1 /*
2  * Copyright 2016-2018 Józef Kucia for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include "d3d12_crosstest.h"
20 
21 #define recreate_command_list(a, b, c) recreate_command_list_(__LINE__, a, b, c)
recreate_command_list_(unsigned int line,ID3D12Device * device,ID3D12CommandAllocator * allocator,ID3D12GraphicsCommandList ** command_list)22 static void recreate_command_list_(unsigned int line, ID3D12Device *device,
23         ID3D12CommandAllocator *allocator, ID3D12GraphicsCommandList **command_list)
24 {
25     HRESULT hr;
26 
27     hr = ID3D12CommandAllocator_Reset(allocator);
28     ok_(line)(hr == S_OK, "Failed to reset command allocator, hr %#x.\n", hr);
29     ID3D12GraphicsCommandList_Release(*command_list);
30     hr = ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
31             allocator, NULL, &IID_ID3D12GraphicsCommandList, (void **)command_list);
32     ok_(line)(hr == S_OK, "Failed to create command list, hr %#x.\n", hr);
33 }
34 
test_invalid_resource_barriers(void)35 static void test_invalid_resource_barriers(void)
36 {
37     ID3D12Resource *texture, *readback_buffer, *upload_buffer;
38     ID3D12CommandAllocator *command_allocator;
39     ID3D12GraphicsCommandList *command_list;
40     ID3D12CommandQueue *queue;
41     ID3D12Device *device;
42     ULONG refcount;
43     HRESULT hr;
44 
45     if (!(device = create_device()))
46     {
47         skip("Failed to create device.\n");
48         return;
49     }
50 
51     queue = create_command_queue(device, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL);
52 
53     hr = ID3D12Device_CreateCommandAllocator(device, D3D12_COMMAND_LIST_TYPE_DIRECT,
54             &IID_ID3D12CommandAllocator, (void **)&command_allocator);
55     ok(hr == S_OK, "Failed to create command allocator, hr %#x.\n", hr);
56 
57     hr = ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
58             command_allocator, NULL, &IID_ID3D12GraphicsCommandList, (void **)&command_list);
59     ok(hr == S_OK, "Failed to create command list, hr %#x.\n", hr);
60 
61     texture = create_default_texture(device, 32, 32, DXGI_FORMAT_R8G8B8A8_UNORM,
62             D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
63     upload_buffer = create_upload_buffer(device, 32, NULL);
64     readback_buffer = create_readback_buffer(device, 32);
65 
66     /* The following invalid barrier is not detected by the runtime. */
67     transition_resource_state(command_list, texture,
68             D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
69     hr = ID3D12GraphicsCommandList_Close(command_list);
70     ok(hr == S_OK, "Failed to close command list, hr %#x.\n", hr);
71 
72     reset_command_list(command_list, command_allocator);
73 
74     /* The before state does not match with the previous state. */
75     transition_resource_state(command_list, texture,
76             D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_SOURCE);
77     transition_resource_state(command_list, texture,
78             D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
79     hr = ID3D12GraphicsCommandList_Close(command_list);
80     /* The returned error code has changed after a Windows update. */
81     ok(hr == S_OK || hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
82     if (hr == S_OK)
83     {
84         exec_command_list(queue, command_list);
85         wait_queue_idle(device, queue);
86     }
87 
88     recreate_command_list(device, command_allocator, &command_list);
89 
90     /* The before state does not match with the previous state. */
91     transition_resource_state(command_list, texture,
92             D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
93             D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
94     transition_resource_state(command_list, texture,
95             D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
96     hr = ID3D12GraphicsCommandList_Close(command_list);
97     /* The returned error code has changed after a Windows update. */
98     ok(hr == S_OK || hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
99     if (hr == S_OK)
100     {
101         exec_command_list(queue, command_list);
102         wait_queue_idle(device, queue);
103     }
104 
105     recreate_command_list(device, command_allocator, &command_list);
106 
107     /* Exactly one write state or a combination of read-only states are allowed. */
108     transition_resource_state(command_list, texture,
109             D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
110             D3D12_RESOURCE_STATE_UNORDERED_ACCESS | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
111     hr = ID3D12GraphicsCommandList_Close(command_list);
112     ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
113 
114     recreate_command_list(device, command_allocator, &command_list);
115 
116     /* Readback resources cannot transition from D3D12_RESOURCE_STATE_COPY_DEST. */
117     transition_resource_state(command_list, readback_buffer,
118             D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON);
119     hr = ID3D12GraphicsCommandList_Close(command_list);
120     todo ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
121 
122     recreate_command_list(device, command_allocator, &command_list);
123 
124     /* Upload resources cannot transition from D3D12_RESOURCE_STATE_GENERIC_READ. */
125     transition_resource_state(command_list, upload_buffer,
126             D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_COMMON);
127     hr = ID3D12GraphicsCommandList_Close(command_list);
128     todo ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
129 
130     recreate_command_list(device, command_allocator, &command_list);
131 
132     /* NULL resource. */
133     transition_resource_state(command_list, NULL,
134             D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
135     hr = ID3D12GraphicsCommandList_Close(command_list);
136     ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
137 
138     ID3D12CommandAllocator_Release(command_allocator);
139     ID3D12CommandQueue_Release(queue);
140     ID3D12GraphicsCommandList_Release(command_list);
141     ID3D12Resource_Release(readback_buffer);
142     ID3D12Resource_Release(texture);
143     ID3D12Resource_Release(upload_buffer);
144     refcount = ID3D12Device_Release(device);
145     ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount);
146 }
147 
test_invalid_copy_texture_region(void)148 static void test_invalid_copy_texture_region(void)
149 {
150     ID3D12Resource *dst_texture, *src_texture, *dst_buffer, *src_buffer;
151     D3D12_TEXTURE_COPY_LOCATION src_location, dst_location;
152     ID3D12CommandAllocator *command_allocator;
153     ID3D12GraphicsCommandList *command_list;
154     ID3D12Device *device;
155     ULONG refcount;
156     D3D12_BOX box;
157     HRESULT hr;
158 
159     if (!(device = create_device()))
160     {
161         skip("Failed to create device.\n");
162         return;
163     }
164 
165     hr = ID3D12Device_CreateCommandAllocator(device, D3D12_COMMAND_LIST_TYPE_DIRECT,
166             &IID_ID3D12CommandAllocator, (void **)&command_allocator);
167     ok(hr == S_OK, "Failed to create command allocator, hr %#x.\n", hr);
168 
169     hr = ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
170             command_allocator, NULL, &IID_ID3D12GraphicsCommandList, (void **)&command_list);
171     ok(hr == S_OK, "Failed to create command list, hr %#x.\n", hr);
172 
173     src_buffer = create_upload_buffer(device, 0x40000, NULL);
174     dst_buffer = create_default_buffer(device, 0x40000, 0, D3D12_RESOURCE_STATE_COPY_DEST);
175 
176     src_texture = create_default_texture(device, 64, 64,
177             DXGI_FORMAT_BC3_UNORM, 0, D3D12_RESOURCE_STATE_COPY_SOURCE);
178     dst_texture = create_default_texture(device, 64, 64,
179             DXGI_FORMAT_BC3_UNORM, 0, D3D12_RESOURCE_STATE_COPY_DEST);
180 
181     dst_location.pResource = dst_texture;
182     dst_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
183     dst_location.SubresourceIndex = 0;
184 
185     src_location.pResource = src_buffer;
186     src_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
187     src_location.PlacedFootprint.Offset = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
188     src_location.PlacedFootprint.Footprint.Format = DXGI_FORMAT_BC3_UNORM;
189     src_location.PlacedFootprint.Footprint.Width = 64;
190     src_location.PlacedFootprint.Footprint.Height = 63; /* height must be multiple of block size */
191     src_location.PlacedFootprint.Footprint.Depth = 1;
192     src_location.PlacedFootprint.Footprint.RowPitch
193             = 64 / format_block_width(DXGI_FORMAT_BC3_UNORM) * format_size(DXGI_FORMAT_BC3_UNORM);
194 
195     ID3D12GraphicsCommandList_CopyTextureRegion(command_list,
196             &dst_location, 0, 0, 0, &src_location, NULL);
197 
198     hr = ID3D12GraphicsCommandList_Close(command_list);
199     todo ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
200 
201     recreate_command_list(device, command_allocator, &command_list);
202 
203     src_location.PlacedFootprint.Footprint.Width = 4;
204     src_location.PlacedFootprint.Footprint.Height = 4;
205 
206     /* dst y must be multiple of block size */
207     ID3D12GraphicsCommandList_CopyTextureRegion(command_list,
208             &dst_location, 0, 3, 0, &src_location, NULL);
209 
210     hr = ID3D12GraphicsCommandList_Close(command_list);
211     todo ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
212 
213     recreate_command_list(device, command_allocator, &command_list);
214 
215     /* row pitch must be multiple of D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT */
216     src_location.PlacedFootprint.Footprint.RowPitch
217             = 64 / format_block_width(DXGI_FORMAT_BC3_UNORM) * format_size(DXGI_FORMAT_BC3_UNORM) + 1;
218 
219     ID3D12GraphicsCommandList_CopyTextureRegion(command_list,
220             &dst_location, 0, 0, 0, &src_location, NULL);
221 
222     hr = ID3D12GraphicsCommandList_Close(command_list);
223     todo ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
224 
225     recreate_command_list(device, command_allocator, &command_list);
226 
227     dst_location.pResource = dst_buffer;
228     dst_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
229     dst_location.PlacedFootprint.Offset = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
230     dst_location.PlacedFootprint.Footprint.Format = DXGI_FORMAT_BC3_UNORM;
231     dst_location.PlacedFootprint.Footprint.Width = 64;
232     dst_location.PlacedFootprint.Footprint.Height = 64;
233     dst_location.PlacedFootprint.Footprint.Depth = 1;
234     dst_location.PlacedFootprint.Footprint.RowPitch
235             = 64 / format_block_width(DXGI_FORMAT_BC3_UNORM) * format_size(DXGI_FORMAT_BC3_UNORM);
236 
237     src_location.pResource = src_texture;
238     src_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
239     src_location.SubresourceIndex = 0;
240 
241     /* coordinates must be multiple of block size */
242     set_box(&box, 0, 0, 0, 31, 31, 1);
243     ID3D12GraphicsCommandList_CopyTextureRegion(command_list,
244             &dst_location, 0, 0, 0, &src_location, &box);
245 
246     hr = ID3D12GraphicsCommandList_Close(command_list);
247     todo ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
248 
249     recreate_command_list(device, command_allocator, &command_list);
250 
251     ID3D12Resource_Release(src_texture);
252     src_texture = create_default_texture2d(device, 4, 4, 1, 3, DXGI_FORMAT_BC3_UNORM,
253             D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_SOURCE);
254 
255     src_location.pResource = src_texture;
256     src_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
257     src_location.SubresourceIndex = 1;
258 
259     /* coordinates must be multiple of block size even for smallest miplevels */
260     set_box(&box, 0, 0, 0, 2, 2, 1);
261     ID3D12GraphicsCommandList_CopyTextureRegion(command_list,
262             &dst_location, 0, 0, 0, &src_location, &box);
263 
264     hr = ID3D12GraphicsCommandList_Close(command_list);
265     todo ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
266 
267     recreate_command_list(device, command_allocator, &command_list);
268 
269     src_location.SubresourceIndex = 2;
270 
271     /* coordinates must be multiple of block size even for smallest miplevels */
272     set_box(&box, 0, 0, 0, 1, 1, 1);
273     ID3D12GraphicsCommandList_CopyTextureRegion(command_list,
274             &dst_location, 0, 0, 0, &src_location, &box);
275 
276     hr = ID3D12GraphicsCommandList_Close(command_list);
277     todo ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
278 
279     ID3D12CommandAllocator_Release(command_allocator);
280     ID3D12GraphicsCommandList_Release(command_list);
281     ID3D12Resource_Release(dst_buffer);
282     ID3D12Resource_Release(src_buffer);
283     ID3D12Resource_Release(src_texture);
284     ID3D12Resource_Release(dst_texture);
285     refcount = ID3D12Device_Release(device);
286     ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount);
287 }
288 
test_invalid_unordered_access_views(void)289 static void test_invalid_unordered_access_views(void)
290 {
291     D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc;
292     D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle;
293     ID3D12DescriptorHeap *heap;
294     ID3D12Resource *buffer;
295     ID3D12Device *device;
296     ULONG refcount;
297 
298     if (!(device = create_device()))
299     {
300         skip("Failed to create device.\n");
301         return;
302     }
303 
304     heap = create_gpu_descriptor_heap(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 16);
305 
306     buffer = create_default_buffer(device, 64 * sizeof(float),
307             D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
308 
309     cpu_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(heap);
310 
311     /* Buffer views cannot be created for compressed formats. */
312     uav_desc.Format = DXGI_FORMAT_BC1_UNORM;
313     uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
314     uav_desc.Buffer.FirstElement = 0;
315     uav_desc.Buffer.NumElements = 64;
316     uav_desc.Buffer.StructureByteStride = 0;
317     uav_desc.Buffer.CounterOffsetInBytes = 0;
318     uav_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
319     ID3D12Device_CreateUnorderedAccessView(device, buffer, NULL, &uav_desc, cpu_handle);
320 
321     ID3D12DescriptorHeap_Release(heap);
322     ID3D12Resource_Release(buffer);
323     refcount = ID3D12Device_Release(device);
324     ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount);
325 }
326 
START_TEST(d3d12_invalid_usage)327 START_TEST(d3d12_invalid_usage)
328 {
329     parse_args(argc, argv);
330     enable_d3d12_debug_layer(argc, argv);
331     init_adapter_info();
332 
333     run_test(test_invalid_resource_barriers);
334     run_test(test_invalid_copy_texture_region);
335     run_test(test_invalid_unordered_access_views);
336 }
337