makefiles: Don't use standard libs for programs that specify -nodefaultlibs.
[wine/zf.git] / dlls / d3d12 / tests / d3d12.c
blob0200047fd17513c7824d90e79652e276f159a5c5
1 /*
2 * Copyright 2017 Józef Kucia for CodeWeavers
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.
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.
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
19 #include <assert.h>
20 #include <stdlib.h>
21 #define COBJMACROS
22 #include "initguid.h"
23 #include "d3d12.h"
24 #include "dxgi1_6.h"
25 #include "wine/test.h"
27 static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff)
29 unsigned int diff = x > y ? x - y : y - x;
31 return diff <= max_diff;
34 static BOOL compare_color(DWORD c1, DWORD c2, unsigned int max_diff)
36 return compare_uint(c1 & 0xff, c2 & 0xff, max_diff)
37 && compare_uint((c1 >> 8) & 0xff, (c2 >> 8) & 0xff, max_diff)
38 && compare_uint((c1 >> 16) & 0xff, (c2 >> 16) & 0xff, max_diff)
39 && compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff);
42 static BOOL equal_luid(LUID a, LUID b)
44 return a.LowPart == b.LowPart && a.HighPart == b.HighPart;
47 static unsigned int format_size(DXGI_FORMAT format)
49 switch (format)
51 case DXGI_FORMAT_R8G8B8A8_TYPELESS:
52 case DXGI_FORMAT_R8G8B8A8_UNORM:
53 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
54 case DXGI_FORMAT_B8G8R8A8_UNORM:
55 case DXGI_FORMAT_R10G10B10A2_UNORM:
56 return 4;
57 default:
58 trace("Unhandled format %#x.\n", format);
59 return 1;
63 static size_t align(size_t addr, size_t alignment)
65 return (addr + (alignment - 1)) & ~(alignment - 1);
68 static void set_viewport(D3D12_VIEWPORT *vp, float x, float y,
69 float width, float height, float min_depth, float max_depth)
71 vp->TopLeftX = x;
72 vp->TopLeftY = y;
73 vp->Width = width;
74 vp->Height = height;
75 vp->MinDepth = min_depth;
76 vp->MaxDepth = max_depth;
79 static BOOL use_warp_adapter;
80 static unsigned int use_adapter_idx;
82 static IDXGIAdapter *create_adapter(void)
84 IDXGIFactory4 *factory;
85 IDXGIAdapter *adapter;
86 HRESULT hr;
88 if (!use_warp_adapter && !use_adapter_idx)
89 return NULL;
91 hr = CreateDXGIFactory2(0, &IID_IDXGIFactory4, (void **)&factory);
92 ok(hr == S_OK, "Failed to create factory, hr %#x.\n", hr);
94 adapter = NULL;
95 if (use_warp_adapter)
97 hr = IDXGIFactory4_EnumWarpAdapter(factory, &IID_IDXGIAdapter, (void **)&adapter);
99 else
101 hr = IDXGIFactory4_EnumAdapters(factory, use_adapter_idx, &adapter);
103 IDXGIFactory4_Release(factory);
104 if (FAILED(hr))
105 trace("Failed to get adapter, hr %#x.\n", hr);
106 return adapter;
109 static ID3D12Device *create_device(void)
111 IDXGIAdapter *adapter;
112 ID3D12Device *device;
113 HRESULT hr;
115 adapter = create_adapter();
116 hr = D3D12CreateDevice((IUnknown *)adapter, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, (void **)&device);
117 if (adapter)
118 IDXGIAdapter_Release(adapter);
119 if (FAILED(hr))
120 return NULL;
122 return device;
125 static void print_adapter_info(void)
127 DXGI_ADAPTER_DESC adapter_desc;
128 IDXGIFactory4 *factory;
129 IDXGIAdapter *adapter;
130 ID3D12Device *device;
131 HRESULT hr;
132 LUID luid;
134 if (!(device = create_device()))
135 return;
136 luid = ID3D12Device_GetAdapterLuid(device);
137 ID3D12Device_Release(device);
139 hr = CreateDXGIFactory2(0, &IID_IDXGIFactory4, (void **)&factory);
140 ok(hr == S_OK, "Failed to create factory, hr %#x.\n", hr);
141 hr = IDXGIFactory4_EnumAdapterByLuid(factory, luid, &IID_IDXGIAdapter, (void **)&adapter);
142 todo_wine ok(hr == S_OK, "Failed to enum adapter by LUID, hr %#x.\n", hr);
143 IDXGIFactory4_Release(factory);
145 if (FAILED(hr))
146 return;
148 hr = IDXGIAdapter_GetDesc(adapter, &adapter_desc);
149 ok(hr == S_OK, "Failed to get adapter desc, hr %#x.\n", hr);
150 IDXGIAdapter_Release(adapter);
152 trace("Adapter: %s, %04x:%04x.\n", wine_dbgstr_w(adapter_desc.Description),
153 adapter_desc.VendorId, adapter_desc.DeviceId);
156 static ULONG get_refcount(void *iface)
158 IUnknown *unknown = iface;
159 IUnknown_AddRef(unknown);
160 return IUnknown_Release(unknown);
163 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
164 static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
166 IUnknown *iface = iface_ptr;
167 HRESULT hr, expected_hr;
168 IUnknown *unk;
170 expected_hr = supported ? S_OK : E_NOINTERFACE;
172 hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
173 ok_(__FILE__, line)(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr);
174 if (SUCCEEDED(hr))
175 IUnknown_Release(unk);
178 static HRESULT create_root_signature(ID3D12Device *device, const D3D12_ROOT_SIGNATURE_DESC *desc,
179 ID3D12RootSignature **root_signature)
181 ID3DBlob *blob;
182 HRESULT hr;
184 if (FAILED(hr = D3D12SerializeRootSignature(desc, D3D_ROOT_SIGNATURE_VERSION_1_0, &blob, NULL)))
185 return hr;
187 hr = ID3D12Device_CreateRootSignature(device, 0, ID3D10Blob_GetBufferPointer(blob),
188 ID3D10Blob_GetBufferSize(blob), &IID_ID3D12RootSignature, (void **)root_signature);
189 ID3D10Blob_Release(blob);
190 return hr;
193 static ID3D12RootSignature *create_default_root_signature(ID3D12Device *device)
195 D3D12_ROOT_SIGNATURE_DESC root_signature_desc;
196 ID3D12RootSignature *root_signature = NULL;
197 D3D12_ROOT_PARAMETER root_parameters[1];
198 HRESULT hr;
200 root_parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
201 root_parameters[0].Constants.ShaderRegister = 0;
202 root_parameters[0].Constants.RegisterSpace = 0;
203 root_parameters[0].Constants.Num32BitValues = 4;
204 root_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
206 root_signature_desc.NumParameters = ARRAY_SIZE(root_parameters);
207 root_signature_desc.pParameters = root_parameters;
208 root_signature_desc.NumStaticSamplers = 0;
209 root_signature_desc.pStaticSamplers = NULL;
210 root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;
211 hr = create_root_signature(device, &root_signature_desc, &root_signature);
212 ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr);
214 return root_signature;
217 #define create_pipeline_state(a, b, c, d) create_pipeline_state_(__LINE__, a, b, c, d)
218 static ID3D12PipelineState *create_pipeline_state_(unsigned int line, ID3D12Device *device,
219 ID3D12RootSignature *root_signature, DXGI_FORMAT rt_format, const D3D12_SHADER_BYTECODE *ps)
221 D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeline_state_desc;
222 ID3D12PipelineState *pipeline_state;
223 HRESULT hr;
225 static const DWORD vs_code[] =
227 #if 0
228 void main(uint id : SV_VertexID, out float4 position : SV_Position)
230 float2 coords = float2((id << 1) & 2, id & 2);
231 position = float4(coords * float2(2, -2) + float2(-1, 1), 0, 1);
233 #endif
234 0x43425844, 0xf900d25e, 0x68bfefa7, 0xa63ac0a7, 0xa476af7a, 0x00000001, 0x0000018c, 0x00000003,
235 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
236 0x00000000, 0x00000006, 0x00000001, 0x00000000, 0x00000101, 0x565f5653, 0x65747265, 0x00444978,
237 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003,
238 0x00000000, 0x0000000f, 0x505f5653, 0x7469736f, 0x006e6f69, 0x58454853, 0x000000f0, 0x00010050,
239 0x0000003c, 0x0100086a, 0x04000060, 0x00101012, 0x00000000, 0x00000006, 0x04000067, 0x001020f2,
240 0x00000000, 0x00000001, 0x02000068, 0x00000001, 0x0b00008c, 0x00100012, 0x00000000, 0x00004001,
241 0x00000001, 0x00004001, 0x00000001, 0x0010100a, 0x00000000, 0x00004001, 0x00000000, 0x07000001,
242 0x00100042, 0x00000000, 0x0010100a, 0x00000000, 0x00004001, 0x00000002, 0x05000056, 0x00100032,
243 0x00000000, 0x00100086, 0x00000000, 0x0f000032, 0x00102032, 0x00000000, 0x00100046, 0x00000000,
244 0x00004002, 0x40000000, 0xc0000000, 0x00000000, 0x00000000, 0x00004002, 0xbf800000, 0x3f800000,
245 0x00000000, 0x00000000, 0x08000036, 0x001020c2, 0x00000000, 0x00004002, 0x00000000, 0x00000000,
246 0x00000000, 0x3f800000, 0x0100003e,
248 static const D3D12_SHADER_BYTECODE vs = {vs_code, sizeof(vs_code)};
249 static const DWORD ps_code[] =
251 #if 0
252 void main(const in float4 position : SV_Position, out float4 target : SV_Target0)
254 target = float4(0.0f, 1.0f, 0.0f, 1.0f);
256 #endif
257 0x43425844, 0x8a4a8140, 0x5eba8e0b, 0x714e0791, 0xb4b8eed2, 0x00000001, 0x000000d8, 0x00000003,
258 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
259 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x505f5653, 0x7469736f, 0x006e6f69,
260 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
261 0x00000000, 0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x58454853, 0x0000003c, 0x00000050,
262 0x0000000f, 0x0100086a, 0x03000065, 0x001020f2, 0x00000000, 0x08000036, 0x001020f2, 0x00000000,
263 0x00004002, 0x00000000, 0x3f800000, 0x00000000, 0x3f800000, 0x0100003e,
265 static const D3D12_SHADER_BYTECODE default_ps = {ps_code, sizeof(ps_code)};
267 if (!ps)
268 ps = &default_ps;
270 memset(&pipeline_state_desc, 0, sizeof(pipeline_state_desc));
271 pipeline_state_desc.pRootSignature = root_signature;
272 pipeline_state_desc.VS = vs;
273 pipeline_state_desc.PS = *ps;
274 pipeline_state_desc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
275 pipeline_state_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
276 pipeline_state_desc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK;
277 pipeline_state_desc.SampleMask = ~(UINT)0;
278 pipeline_state_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
279 pipeline_state_desc.NumRenderTargets = 1;
280 pipeline_state_desc.RTVFormats[0] = rt_format;
281 pipeline_state_desc.SampleDesc.Count = 1;
282 hr = ID3D12Device_CreateGraphicsPipelineState(device, &pipeline_state_desc,
283 &IID_ID3D12PipelineState, (void **)&pipeline_state);
284 ok_(__FILE__, line)(hr == S_OK, "Failed to create graphics pipeline state, hr %#x.\n", hr);
286 return pipeline_state;
289 #define create_command_queue(a, b) create_command_queue_(__LINE__, a, b)
290 static ID3D12CommandQueue *create_command_queue_(unsigned int line,
291 ID3D12Device *device, D3D12_COMMAND_LIST_TYPE type)
293 D3D12_COMMAND_QUEUE_DESC command_queue_desc;
294 ID3D12CommandQueue *queue;
295 HRESULT hr;
297 command_queue_desc.Type = type;
298 command_queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
299 command_queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
300 command_queue_desc.NodeMask = 0;
301 hr = ID3D12Device_CreateCommandQueue(device, &command_queue_desc,
302 &IID_ID3D12CommandQueue, (void **)&queue);
303 ok_(__FILE__, line)(hr == S_OK, "Failed to create command queue, hr %#x.\n", hr);
305 return queue;
308 struct test_context_desc
310 BOOL no_render_target;
311 BOOL no_pipeline;
312 const D3D12_SHADER_BYTECODE *ps;
315 #define MAX_FRAME_COUNT 4
317 struct test_context
319 ID3D12Device *device;
321 ID3D12CommandQueue *queue;
322 ID3D12CommandAllocator *allocator[MAX_FRAME_COUNT];
323 ID3D12GraphicsCommandList *list[MAX_FRAME_COUNT];
325 ID3D12DescriptorHeap *rtv_heap;
326 D3D12_CPU_DESCRIPTOR_HANDLE rtv[MAX_FRAME_COUNT];
327 ID3D12Resource *render_target[MAX_FRAME_COUNT];
329 ID3D12RootSignature *root_signature;
330 ID3D12PipelineState *pipeline_state;
332 D3D12_VIEWPORT viewport;
333 RECT scissor_rect;
336 #define reset_command_list(a, b) reset_command_list_(__LINE__, a, b)
337 static void reset_command_list_(unsigned int line, struct test_context *context, unsigned int index)
339 HRESULT hr;
341 assert(index < MAX_FRAME_COUNT);
343 hr = ID3D12CommandAllocator_Reset(context->allocator[index]);
344 ok_(__FILE__, line)(hr == S_OK, "Failed to reset command allocator, hr %#x.\n", hr);
345 hr = ID3D12GraphicsCommandList_Reset(context->list[index], context->allocator[index], NULL);
346 ok_(__FILE__, line)(hr == S_OK, "Failed to reset command list, hr %#x.\n", hr);
349 static void destroy_render_targets(struct test_context *context)
351 unsigned int i;
353 for (i = 0; i < ARRAY_SIZE(context->render_target); ++i)
355 if (context->render_target[i])
357 ID3D12Resource_Release(context->render_target[i]);
358 context->render_target[i] = NULL;
363 #define create_render_target(context) create_render_target_(__LINE__, context)
364 static void create_render_target_(unsigned int line, struct test_context *context)
366 D3D12_HEAP_PROPERTIES heap_properties;
367 D3D12_RESOURCE_DESC resource_desc;
368 D3D12_CLEAR_VALUE clear_value;
369 HRESULT hr;
371 destroy_render_targets(context);
373 memset(&heap_properties, 0, sizeof(heap_properties));
374 heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
376 resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
377 resource_desc.Alignment = 0;
378 resource_desc.Width = 32;
379 resource_desc.Height = 32;
380 resource_desc.DepthOrArraySize = 1;
381 resource_desc.MipLevels = 1;
382 resource_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
383 resource_desc.SampleDesc.Count = 1;
384 resource_desc.SampleDesc.Quality = 0;
385 resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
386 resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
387 clear_value.Format = resource_desc.Format;
388 clear_value.Color[0] = 1.0f;
389 clear_value.Color[1] = 1.0f;
390 clear_value.Color[2] = 1.0f;
391 clear_value.Color[3] = 1.0f;
392 hr = ID3D12Device_CreateCommittedResource(context->device,
393 &heap_properties, D3D12_HEAP_FLAG_NONE, &resource_desc,
394 D3D12_RESOURCE_STATE_RENDER_TARGET, &clear_value,
395 &IID_ID3D12Resource, (void **)&context->render_target[0]);
396 ok_(__FILE__, line)(hr == S_OK, "Failed to create texture, hr %#x.\n", hr);
398 set_viewport(&context->viewport, 0.0f, 0.0f, resource_desc.Width, resource_desc.Height, 0.0f, 1.0f);
399 SetRect(&context->scissor_rect, 0, 0, resource_desc.Width, resource_desc.Height);
401 ID3D12Device_CreateRenderTargetView(context->device, context->render_target[0], NULL, context->rtv[0]);
404 #define init_test_context(a, b) init_test_context_(__LINE__, a, b)
405 static BOOL init_test_context_(unsigned int line, struct test_context *context,
406 const struct test_context_desc *desc)
408 D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc;
409 unsigned int rtv_size;
410 ID3D12Device *device;
411 unsigned int i;
412 HRESULT hr;
414 memset(context, 0, sizeof(*context));
416 if (!(context->device = create_device()))
418 skip_(__FILE__, line)("Failed to create device.\n");
419 return FALSE;
421 device = context->device;
423 context->queue = create_command_queue_(line, device, D3D12_COMMAND_LIST_TYPE_DIRECT);
425 for (i = 0; i < ARRAY_SIZE(context->allocator); ++i)
427 hr = ID3D12Device_CreateCommandAllocator(device, D3D12_COMMAND_LIST_TYPE_DIRECT,
428 &IID_ID3D12CommandAllocator, (void **)&context->allocator[i]);
429 ok_(__FILE__, line)(hr == S_OK, "Failed to create command allocator %u, hr %#x.\n", i, hr);
432 for (i = 0; i < ARRAY_SIZE(context->list); ++i)
434 hr = ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
435 context->allocator[i], NULL, &IID_ID3D12GraphicsCommandList, (void **)&context->list[i]);
436 ok_(__FILE__, line)(hr == S_OK, "Failed to create command list %u, hr %#x.\n", i, hr);
439 if (desc && desc->no_render_target)
440 return TRUE;
442 rtv_heap_desc.NumDescriptors = MAX_FRAME_COUNT;
443 rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
444 rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
445 rtv_heap_desc.NodeMask = 0;
446 hr = ID3D12Device_CreateDescriptorHeap(device, &rtv_heap_desc,
447 &IID_ID3D12DescriptorHeap, (void **)&context->rtv_heap);
448 ok_(__FILE__, line)(hr == S_OK, "Failed to create descriptor heap, hr %#x.\n", hr);
450 rtv_size = ID3D12Device_GetDescriptorHandleIncrementSize(device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
451 for (i = 0; i < ARRAY_SIZE(context->rtv); ++i)
453 context->rtv[i] = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(context->rtv_heap);
454 context->rtv[i].ptr += i * rtv_size;
457 context->root_signature = create_default_root_signature(device);
459 if (desc && desc->no_pipeline)
460 return TRUE;
462 context->pipeline_state = create_pipeline_state_(line, device,
463 context->root_signature, DXGI_FORMAT_B8G8R8A8_UNORM, desc ? desc->ps : NULL);
465 return TRUE;
468 #define destroy_test_context(context) destroy_test_context_(__LINE__, context)
469 static void destroy_test_context_(unsigned int line, struct test_context *context)
471 unsigned int i;
472 ULONG refcount;
474 if (context->pipeline_state)
475 ID3D12PipelineState_Release(context->pipeline_state);
476 if (context->root_signature)
477 ID3D12RootSignature_Release(context->root_signature);
479 if (context->rtv_heap)
480 ID3D12DescriptorHeap_Release(context->rtv_heap);
481 destroy_render_targets(context);
483 for (i = 0; i < ARRAY_SIZE(context->allocator); ++i)
484 ID3D12CommandAllocator_Release(context->allocator[i]);
485 ID3D12CommandQueue_Release(context->queue);
486 for (i = 0; i < ARRAY_SIZE(context->list); ++i)
487 ID3D12GraphicsCommandList_Release(context->list[i]);
489 refcount = ID3D12Device_Release(context->device);
490 ok_(__FILE__, line)(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount);
493 static void exec_command_list(ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *list)
495 ID3D12CommandList *lists[] = {(ID3D12CommandList *)list};
496 ID3D12CommandQueue_ExecuteCommandLists(queue, 1, lists);
499 static HRESULT wait_for_fence(ID3D12Fence *fence, UINT64 value)
501 HANDLE event;
502 HRESULT hr;
503 DWORD ret;
505 if (ID3D12Fence_GetCompletedValue(fence) >= value)
506 return S_OK;
508 if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL)))
509 return E_FAIL;
511 if (FAILED(hr = ID3D12Fence_SetEventOnCompletion(fence, value, event)))
513 CloseHandle(event);
514 return hr;
517 ret = WaitForSingleObject(event, INFINITE);
518 CloseHandle(event);
519 return ret == WAIT_OBJECT_0 ? S_OK : E_FAIL;
522 #define wait_queue_idle(a, b) wait_queue_idle_(__LINE__, a, b)
523 static void wait_queue_idle_(unsigned int line, ID3D12Device *device, ID3D12CommandQueue *queue)
525 ID3D12Fence *fence;
526 HRESULT hr;
528 hr = ID3D12Device_CreateFence(device, 0, D3D12_FENCE_FLAG_NONE,
529 &IID_ID3D12Fence, (void **)&fence);
530 ok_(__FILE__, line)(hr == S_OK, "Failed to create fence, hr %#x.\n", hr);
532 hr = ID3D12CommandQueue_Signal(queue, fence, 1);
533 ok_(__FILE__, line)(hr == S_OK, "Failed to signal fence, hr %#x.\n", hr);
534 hr = wait_for_fence(fence, 1);
535 ok_(__FILE__, line)(hr == S_OK, "Failed to wait for fence, hr %#x.\n", hr);
537 ID3D12Fence_Release(fence);
540 static void transition_sub_resource_state(ID3D12GraphicsCommandList *list, ID3D12Resource *resource,
541 unsigned int sub_resource_idx, D3D12_RESOURCE_STATES state_before, D3D12_RESOURCE_STATES state_after)
543 D3D12_RESOURCE_BARRIER barrier;
545 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
546 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
547 barrier.Transition.pResource = resource;
548 barrier.Transition.Subresource = sub_resource_idx;
549 barrier.Transition.StateBefore = state_before;
550 barrier.Transition.StateAfter = state_after;
552 ID3D12GraphicsCommandList_ResourceBarrier(list, 1, &barrier);
555 #define create_buffer(a, b, c, d, e) create_buffer_(__LINE__, a, b, c, d, e)
556 static ID3D12Resource *create_buffer_(unsigned int line, ID3D12Device *device,
557 D3D12_HEAP_TYPE heap_type, size_t size, D3D12_RESOURCE_FLAGS resource_flags,
558 D3D12_RESOURCE_STATES initial_resource_state)
560 D3D12_HEAP_PROPERTIES heap_properties;
561 D3D12_RESOURCE_DESC resource_desc;
562 ID3D12Resource *buffer;
563 HRESULT hr;
565 memset(&heap_properties, 0, sizeof(heap_properties));
566 heap_properties.Type = heap_type;
568 resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
569 resource_desc.Alignment = 0;
570 resource_desc.Width = size;
571 resource_desc.Height = 1;
572 resource_desc.DepthOrArraySize = 1;
573 resource_desc.MipLevels = 1;
574 resource_desc.Format = DXGI_FORMAT_UNKNOWN;
575 resource_desc.SampleDesc.Count = 1;
576 resource_desc.SampleDesc.Quality = 0;
577 resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
578 resource_desc.Flags = resource_flags;
580 hr = ID3D12Device_CreateCommittedResource(device, &heap_properties,
581 D3D12_HEAP_FLAG_NONE, &resource_desc, initial_resource_state,
582 NULL, &IID_ID3D12Resource, (void **)&buffer);
583 ok_(__FILE__, line)(hr == S_OK, "Failed to create buffer, hr %#x.\n", hr);
584 return buffer;
587 #define create_readback_buffer(a, b) create_readback_buffer_(__LINE__, a, b)
588 static ID3D12Resource *create_readback_buffer_(unsigned int line, ID3D12Device *device,
589 size_t size)
591 return create_buffer_(line, device, D3D12_HEAP_TYPE_READBACK, size,
592 D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST);
595 static HWND create_window(DWORD style)
597 return CreateWindowA("static", "d3d12_test", style, 0, 0, 256, 256, NULL, NULL, NULL, NULL);
600 static IDXGISwapChain3 *create_swapchain(struct test_context *context, ID3D12CommandQueue *queue,
601 HWND window, unsigned int buffer_count, DXGI_FORMAT format, unsigned int width, unsigned int height)
603 IDXGISwapChain1 *swapchain1;
604 DXGI_SWAP_CHAIN_DESC1 desc;
605 IDXGISwapChain3 *swapchain;
606 IDXGIFactory4 *factory;
607 unsigned int i;
608 HRESULT hr;
610 assert(buffer_count <= MAX_FRAME_COUNT);
612 if (context)
613 destroy_render_targets(context);
615 hr = CreateDXGIFactory2(0, &IID_IDXGIFactory4, (void **)&factory);
616 ok(hr == S_OK, "Failed to create factory, hr %#x.\n", hr);
618 desc.Width = width;
619 desc.Height = height;
620 desc.Format = format;
621 desc.Stereo = FALSE;
622 desc.SampleDesc.Count = 1;
623 desc.SampleDesc.Quality = 0;
624 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
625 desc.BufferCount = buffer_count;
626 desc.Scaling = DXGI_SCALING_STRETCH;
627 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
628 desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
629 desc.Flags = 0;
630 hr = IDXGIFactory4_CreateSwapChainForHwnd(factory, (IUnknown *)queue, window, &desc, NULL, NULL, &swapchain1);
631 ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
633 IDXGIFactory4_Release(factory);
635 hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void **)&swapchain);
636 ok(hr == S_OK, "Failed to query IDXGISwapChain3, hr %#x.\n", hr);
637 IDXGISwapChain1_Release(swapchain1);
639 if (context)
641 set_viewport(&context->viewport, 0.0f, 0.0f, width, height, 0.0f, 1.0f);
642 SetRect(&context->scissor_rect, 0, 0, width, height);
644 for (i = 0; i < buffer_count; ++i)
646 hr = IDXGISwapChain3_GetBuffer(swapchain, i, &IID_ID3D12Resource, (void **)&context->render_target[i]);
647 ok(hr == S_OK, "Failed to get swapchain buffer %u, hr %#x.\n", i, hr);
648 ID3D12Device_CreateRenderTargetView(context->device, context->render_target[i], NULL, context->rtv[i]);
652 return swapchain;
655 struct resource_readback
657 unsigned int width;
658 unsigned int height;
659 ID3D12Resource *resource;
660 unsigned int row_pitch;
661 void *data;
664 static void get_texture_readback_with_command_list(ID3D12Resource *texture, unsigned int sub_resource,
665 struct resource_readback *rb, ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list)
667 D3D12_TEXTURE_COPY_LOCATION dst_location, src_location;
668 D3D12_RESOURCE_DESC resource_desc;
669 D3D12_RANGE read_range;
670 unsigned int miplevel;
671 ID3D12Device *device;
672 DXGI_FORMAT format;
673 HRESULT hr;
675 hr = ID3D12Resource_GetDevice(texture, &IID_ID3D12Device, (void **)&device);
676 ok(hr == S_OK, "Failed to get device, hr %#x.\n", hr);
678 resource_desc = ID3D12Resource_GetDesc(texture);
679 ok(resource_desc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER,
680 "Resource %p is not texture.\n", texture);
681 ok(resource_desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D,
682 "Readback not implemented for 3D textures.\n");
684 miplevel = sub_resource % resource_desc.MipLevels;
685 rb->width = max(1, resource_desc.Width >> miplevel);
686 rb->height = max(1, resource_desc.Height >> miplevel);
687 rb->row_pitch = align(rb->width * format_size(resource_desc.Format), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
688 rb->data = NULL;
690 format = resource_desc.Format;
692 rb->resource = create_readback_buffer(device, rb->row_pitch * rb->height);
694 dst_location.pResource = rb->resource;
695 dst_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
696 dst_location.PlacedFootprint.Offset = 0;
697 dst_location.PlacedFootprint.Footprint.Format = format;
698 dst_location.PlacedFootprint.Footprint.Width = rb->width;
699 dst_location.PlacedFootprint.Footprint.Height = rb->height;
700 dst_location.PlacedFootprint.Footprint.Depth = 1;
701 dst_location.PlacedFootprint.Footprint.RowPitch = rb->row_pitch;
703 src_location.pResource = texture;
704 src_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
705 src_location.SubresourceIndex = sub_resource;
707 ID3D12GraphicsCommandList_CopyTextureRegion(command_list, &dst_location, 0, 0, 0, &src_location, NULL);
708 hr = ID3D12GraphicsCommandList_Close(command_list);
709 ok(hr == S_OK, "Failed to close command list, hr %#x.\n", hr);
711 exec_command_list(queue, command_list);
712 wait_queue_idle(device, queue);
713 ID3D12Device_Release(device);
715 read_range.Begin = 0;
716 read_range.End = resource_desc.Width;
717 hr = ID3D12Resource_Map(rb->resource, 0, &read_range, &rb->data);
718 ok(hr == S_OK, "Failed to map readback buffer, hr %#x.\n", hr);
721 static void *get_readback_data(struct resource_readback *rb, unsigned int x, unsigned int y,
722 size_t element_size)
724 return &((BYTE *)rb->data)[rb->row_pitch * y + x * element_size];
727 static unsigned int get_readback_uint(struct resource_readback *rb, unsigned int x, unsigned int y)
729 return *(unsigned int *)get_readback_data(rb, x, y, sizeof(unsigned int));
732 static void release_resource_readback(struct resource_readback *rb)
734 D3D12_RANGE range = {0, 0};
735 ID3D12Resource_Unmap(rb->resource, 0, &range);
736 ID3D12Resource_Release(rb->resource);
739 #define check_readback_data_uint(a, b, c, d) check_readback_data_uint_(__LINE__, a, b, c, d)
740 static void check_readback_data_uint_(unsigned int line, struct resource_readback *rb,
741 const RECT *rect, unsigned int expected, unsigned int max_diff)
743 RECT r = {0, 0, rb->width, rb->height};
744 unsigned int x = 0, y;
745 BOOL all_match = TRUE;
746 unsigned int got = 0;
748 if (rect)
749 r = *rect;
751 for (y = r.top; y < r.bottom; ++y)
753 for (x = r.left; x < r.right; ++x)
755 got = get_readback_uint(rb, x, y);
756 if (!compare_color(got, expected, max_diff))
758 all_match = FALSE;
759 break;
762 if (!all_match)
763 break;
765 ok_(__FILE__, line)(all_match, "Got 0x%08x, expected 0x%08x at (%u, %u).\n", got, expected, x, y);
768 #define check_sub_resource_uint(a, b, c, d, e, f) check_sub_resource_uint_(__LINE__, a, b, c, d, e, f)
769 static void check_sub_resource_uint_(unsigned int line, ID3D12Resource *texture,
770 unsigned int sub_resource_idx, ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list,
771 unsigned int expected, unsigned int max_diff)
773 struct resource_readback rb;
775 get_texture_readback_with_command_list(texture, 0, &rb, queue, command_list);
776 check_readback_data_uint_(line, &rb, NULL, expected, max_diff);
777 release_resource_readback(&rb);
780 static void test_ordinals(void)
782 PFN_D3D12_CREATE_DEVICE pfn_D3D12CreateDevice, pfn_101;
783 HMODULE d3d12;
785 d3d12 = GetModuleHandleA("d3d12.dll");
786 ok(!!d3d12, "Failed to get module handle.\n");
788 pfn_D3D12CreateDevice = (void *)GetProcAddress(d3d12, "D3D12CreateDevice");
789 ok(!!pfn_D3D12CreateDevice, "Failed to get D3D12CreateDevice() proc address.\n");
791 pfn_101 = (void *)GetProcAddress(d3d12, (const char *)101);
792 ok(pfn_101 == pfn_D3D12CreateDevice, "Got %p, expected %p.\n", pfn_101, pfn_D3D12CreateDevice);
795 static void test_interfaces(void)
797 D3D12_COMMAND_QUEUE_DESC desc;
798 ID3D12CommandQueue *queue;
799 ID3D12Device *device;
800 ULONG refcount;
801 HRESULT hr;
803 if (!(device = create_device()))
805 skip("Failed to create device.\n");
806 return;
809 check_interface(device, &IID_ID3D12Object, TRUE);
810 check_interface(device, &IID_ID3D12DeviceChild, FALSE);
811 check_interface(device, &IID_ID3D12Pageable, FALSE);
812 check_interface(device, &IID_ID3D12Device, TRUE);
814 check_interface(device, &IID_IDXGIObject, FALSE);
815 check_interface(device, &IID_IDXGIDeviceSubObject, FALSE);
816 check_interface(device, &IID_IDXGIDevice, FALSE);
817 check_interface(device, &IID_IDXGIDevice1, FALSE);
818 check_interface(device, &IID_IDXGIDevice2, FALSE);
819 check_interface(device, &IID_IDXGIDevice3, FALSE);
820 check_interface(device, &IID_IDXGIDevice4, FALSE);
822 desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
823 desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
824 desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
825 desc.NodeMask = 0;
826 hr = ID3D12Device_CreateCommandQueue(device, &desc, &IID_ID3D12CommandQueue, (void **)&queue);
827 ok(hr == S_OK, "Failed to create command queue, hr %#x.\n", hr);
829 check_interface(queue, &IID_ID3D12Object, TRUE);
830 check_interface(queue, &IID_ID3D12DeviceChild, TRUE);
831 check_interface(queue, &IID_ID3D12Pageable, TRUE);
832 check_interface(queue, &IID_ID3D12CommandQueue, TRUE);
834 check_interface(queue, &IID_IDXGIObject, FALSE);
835 check_interface(queue, &IID_IDXGIDeviceSubObject, FALSE);
836 check_interface(queue, &IID_IDXGIDevice, FALSE);
837 check_interface(queue, &IID_IDXGIDevice1, FALSE);
838 check_interface(queue, &IID_IDXGIDevice2, FALSE);
839 check_interface(queue, &IID_IDXGIDevice3, FALSE);
840 check_interface(queue, &IID_IDXGIDevice4, FALSE);
842 refcount = ID3D12CommandQueue_Release(queue);
843 ok(!refcount, "Command queue has %u references left.\n", refcount);
844 refcount = ID3D12Device_Release(device);
845 ok(!refcount, "Device has %u references left.\n", refcount);
848 static void test_create_device(void)
850 DXGI_ADAPTER_DESC adapter_desc;
851 IDXGISwapChain3 *swapchain;
852 ID3D12CommandQueue *queue;
853 LUID adapter_luid, luid;
854 IDXGIFactory4 *factory;
855 IDXGIAdapter *adapter;
856 ID3D12Device *device;
857 IDXGIOutput *output;
858 ULONG refcount;
859 HWND window;
860 HRESULT hr;
861 RECT rect;
862 BOOL ret;
864 if (!(device = create_device()))
866 skip("Failed to create device.\n");
867 return;
869 refcount = ID3D12Device_Release(device);
870 ok(!refcount, "Device has %u references left.\n", refcount);
872 hr = CreateDXGIFactory2(0, &IID_IDXGIFactory4, (void **)&factory);
873 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
874 hr = IDXGIFactory4_EnumAdapters(factory, 0, &adapter);
875 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
876 IDXGIFactory4_Release(factory);
878 hr = IDXGIAdapter_GetDesc(adapter, &adapter_desc);
879 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
880 adapter_luid = adapter_desc.AdapterLuid;
882 refcount = get_refcount(adapter);
883 ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
884 hr = D3D12CreateDevice((IUnknown *)adapter, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, (void **)&device);
885 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
886 refcount = IDXGIAdapter_Release(adapter);
887 ok(refcount >= 1, "Got unexpected refcount %u.\n", refcount);
888 adapter = NULL;
890 luid = ID3D12Device_GetAdapterLuid(device);
891 ok(equal_luid(luid, adapter_luid), "Got LUID %08x:%08x, expected %08x:%08x.\n",
892 luid.HighPart, luid.LowPart, adapter_luid.HighPart, adapter_luid.LowPart);
894 queue = create_command_queue(device, D3D12_COMMAND_LIST_TYPE_DIRECT);
895 window = create_window(WS_VISIBLE);
896 ret = GetClientRect(window, &rect);
897 ok(ret, "Failed to get client rect.\n");
898 swapchain = create_swapchain(NULL, queue, window, 2, DXGI_FORMAT_B8G8R8A8_UNORM, rect.right, rect.bottom);
900 hr = IDXGISwapChain3_GetContainingOutput(swapchain, &output);
901 if (hr != DXGI_ERROR_UNSUPPORTED)
903 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
904 hr = IDXGIOutput_GetParent(output, &IID_IDXGIAdapter, (void **)&adapter);
905 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
906 IDXGIOutput_Release(output);
908 memset(&adapter_desc, 0, sizeof(adapter_desc));
909 hr = IDXGIAdapter_GetDesc(adapter, &adapter_desc);
910 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
911 IDXGIAdapter_Release(adapter);
913 ok(equal_luid(adapter_desc.AdapterLuid, adapter_luid),
914 "Got LUID %08x:%08x, expected %08x:%08x.\n",
915 adapter_desc.AdapterLuid.HighPart, adapter_desc.AdapterLuid.LowPart,
916 adapter_luid.HighPart, adapter_luid.LowPart);
918 else
920 skip("GetContainingOutput() is not supported.\n");
923 refcount = IDXGISwapChain3_Release(swapchain);
924 ok(!refcount, "Swapchain has %u references left.\n", refcount);
925 DestroyWindow(window);
926 ID3D12CommandQueue_Release(queue);
928 refcount = ID3D12Device_Release(device);
929 ok(!refcount, "Device has %u references left.\n", refcount);
932 static void test_draw(void)
934 static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f};
935 ID3D12GraphicsCommandList *command_list;
936 struct test_context context;
937 ID3D12CommandQueue *queue;
939 if (!init_test_context(&context, NULL))
940 return;
941 command_list = context.list[0];
942 queue = context.queue;
944 create_render_target(&context);
946 ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv[0], white, 0, NULL);
948 ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv[0], FALSE, NULL);
949 ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
950 ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state);
951 ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
952 ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
953 ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
954 ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
956 transition_sub_resource_state(command_list, context.render_target[0], 0,
957 D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
959 check_sub_resource_uint(context.render_target[0], 0, queue, command_list, 0xff00ff00, 0);
961 destroy_test_context(&context);
964 static void test_swapchain_draw(void)
966 static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f};
967 ID3D12GraphicsCommandList *command_list;
968 D3D12_CPU_DESCRIPTOR_HANDLE rtv;
969 struct test_context_desc desc;
970 struct test_context context;
971 ID3D12Resource *backbuffer;
972 IDXGISwapChain3 *swapchain;
973 ID3D12CommandQueue *queue;
974 unsigned int i, index;
975 ID3D12Device *device;
976 ULONG refcount;
977 HWND window;
978 HRESULT hr;
979 RECT rect;
980 BOOL ret;
982 static const DWORD ps_code[] =
984 #if 0
985 float4 color;
987 float4 main() : SV_Target
989 return color;
991 #endif
992 0x43425844, 0x69e703c1, 0xf0db50aa, 0x9af7ae76, 0x623b93f7, 0x00000001, 0x000000bc, 0x00000003,
993 0x0000002c, 0x0000003c, 0x00000070, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
994 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003, 0x00000000,
995 0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x58454853, 0x00000044, 0x00000050, 0x00000011,
996 0x0100086a, 0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x03000065, 0x001020f2, 0x00000000,
997 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x0100003e,
999 static const D3D12_SHADER_BYTECODE ps = {ps_code, sizeof(ps_code)};
1001 static const struct
1003 DXGI_FORMAT format;
1004 float input[4];
1005 unsigned int color;
1007 tests[] =
1009 {DXGI_FORMAT_B8G8R8A8_UNORM, {1.0f, 0.0f, 0.0f, 1.0f}, 0xffff0000},
1010 {DXGI_FORMAT_B8G8R8A8_UNORM, {0.0f, 1.0f, 0.0f, 1.0f}, 0xff00ff00},
1011 {DXGI_FORMAT_R8G8B8A8_UNORM, {1.0f, 0.0f, 0.0f, 1.0f}, 0xff0000ff},
1012 {DXGI_FORMAT_R8G8B8A8_UNORM, {0.0f, 1.0f, 0.0f, 1.0f}, 0xff00ff00},
1013 {DXGI_FORMAT_R10G10B10A2_UNORM, {1.0f, 0.0f, 0.0f, 1.0f}, 0xc00003ff},
1014 {DXGI_FORMAT_R10G10B10A2_UNORM, {0.0f, 1.0f, 0.0f, 1.0f}, 0xc00ffc00},
1017 memset(&desc, 0, sizeof(desc));
1018 desc.no_pipeline = TRUE;
1019 if (!init_test_context(&context, &desc))
1020 return;
1021 device = context.device;
1022 command_list = context.list[0];
1023 queue = context.queue;
1025 window = create_window(WS_VISIBLE);
1026 ret = GetClientRect(window, &rect);
1027 ok(ret, "Failed to get client rect.\n");
1029 for (i = 0; i < ARRAY_SIZE(tests); ++i)
1031 context.pipeline_state = create_pipeline_state(device,
1032 context.root_signature, tests[i].format, &ps);
1034 swapchain = create_swapchain(&context, queue, window, 2, tests[i].format, rect.right, rect.bottom);
1035 index = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain);
1036 backbuffer = context.render_target[index];
1037 rtv = context.rtv[index];
1039 transition_sub_resource_state(command_list, backbuffer, 0,
1040 D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
1042 ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, rtv, white, 0, NULL);
1044 ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &rtv, FALSE, NULL);
1045 ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
1046 ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state);
1047 ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
1048 ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
1049 ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &rect);
1050 ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 0, 4, tests[i].input, 0);
1051 ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
1053 transition_sub_resource_state(command_list, backbuffer, 0,
1054 D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
1055 check_sub_resource_uint(backbuffer, 0, queue, command_list, tests[i].color, 0);
1057 reset_command_list(&context, 0);
1058 transition_sub_resource_state(command_list, backbuffer, 0,
1059 D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_PRESENT);
1060 hr = ID3D12GraphicsCommandList_Close(command_list);
1061 ok(hr == S_OK, "Failed to close command list, hr %#x.\n", hr);
1062 exec_command_list(queue, command_list);
1064 hr = IDXGISwapChain3_Present(swapchain, 0, 0);
1065 ok(hr == S_OK, "Failed to present, hr %#x.\n", hr);
1067 wait_queue_idle(device, queue);
1069 destroy_render_targets(&context);
1070 refcount = IDXGISwapChain3_Release(swapchain);
1071 ok(!refcount, "Swapchain has %u references left.\n", refcount);
1072 ID3D12PipelineState_Release(context.pipeline_state);
1073 context.pipeline_state = NULL;
1075 reset_command_list(&context, 0);
1078 DestroyWindow(window);
1079 destroy_test_context(&context);
1082 static void test_swapchain_refcount(void)
1084 const unsigned int buffer_count = 4;
1085 struct test_context_desc desc;
1086 struct test_context context;
1087 IDXGISwapChain3 *swapchain;
1088 unsigned int i;
1089 ULONG refcount;
1090 HWND window;
1091 HRESULT hr;
1092 RECT rect;
1093 BOOL ret;
1095 memset(&desc, 0, sizeof(desc));
1096 desc.no_pipeline = TRUE;
1097 if (!init_test_context(&context, &desc))
1098 return;
1100 window = create_window(WS_VISIBLE);
1101 ret = GetClientRect(window, &rect);
1102 ok(ret, "Failed to get client rect.\n");
1103 swapchain = create_swapchain(&context, context.queue, window,
1104 buffer_count, DXGI_FORMAT_B8G8R8A8_UNORM, rect.right, rect.bottom);
1106 for (i = 0; i < buffer_count; ++i)
1108 refcount = get_refcount(swapchain);
1109 todo_wine ok(refcount == 2, "Got refcount %u.\n", refcount);
1110 ID3D12Resource_Release(context.render_target[i]);
1111 context.render_target[i] = NULL;
1113 refcount = get_refcount(swapchain);
1114 ok(refcount == 1, "Got refcount %u.\n", refcount);
1116 refcount = IDXGISwapChain3_AddRef(swapchain);
1117 ok(refcount == 2, "Got refcount %u.\n", refcount);
1118 hr = IDXGISwapChain3_GetBuffer(swapchain, 0, &IID_ID3D12Resource, (void **)&context.render_target[0]);
1119 ok(hr == S_OK, "Failed to get swapchain buffer, hr %#x.\n", hr);
1120 refcount = get_refcount(swapchain);
1121 todo_wine ok(refcount == 3, "Got refcount %u.\n", refcount);
1123 refcount = ID3D12Resource_AddRef(context.render_target[0]);
1124 ok(refcount == 2, "Got refcount %u.\n", refcount);
1125 refcount = get_refcount(swapchain);
1126 todo_wine ok(refcount == 3, "Got refcount %u.\n", refcount);
1128 hr = IDXGISwapChain3_GetBuffer(swapchain, 1, &IID_ID3D12Resource, (void **)&context.render_target[1]);
1129 ok(hr == S_OK, "Failed to get swapchain buffer, hr %#x.\n", hr);
1130 refcount = get_refcount(swapchain);
1131 todo_wine ok(refcount == 3, "Got refcount %u.\n", refcount);
1133 ID3D12Resource_Release(context.render_target[0]);
1134 ID3D12Resource_Release(context.render_target[0]);
1135 context.render_target[0] = NULL;
1136 refcount = get_refcount(swapchain);
1137 todo_wine ok(refcount == 3, "Got refcount %u.\n", refcount);
1139 refcount = IDXGISwapChain3_Release(swapchain);
1140 todo_wine ok(refcount == 2, "Got refcount %u.\n", refcount);
1141 ID3D12Resource_Release(context.render_target[1]);
1142 context.render_target[1] = NULL;
1143 refcount = get_refcount(swapchain);
1144 ok(refcount == 1, "Got refcount %u.\n", refcount);
1146 refcount = IDXGISwapChain3_Release(swapchain);
1147 ok(!refcount, "Swapchain has %u references left.\n", refcount);
1148 DestroyWindow(window);
1149 destroy_test_context(&context);
1152 static void test_swapchain_size_mismatch(void)
1154 static const float green[] = {0.0f, 1.0f, 0.0f, 1.0f};
1155 UINT64 frame_fence_value[MAX_FRAME_COUNT] = {0};
1156 ID3D12GraphicsCommandList *command_list;
1157 D3D12_CPU_DESCRIPTOR_HANDLE rtv;
1158 struct test_context_desc desc;
1159 struct test_context context;
1160 ID3D12Resource *backbuffer;
1161 IDXGISwapChain3 *swapchain;
1162 ID3D12CommandQueue *queue;
1163 unsigned int index, i;
1164 ID3D12Device *device;
1165 ID3D12Fence *fence;
1166 UINT64 fence_value;
1167 ULONG refcount;
1168 HWND window;
1169 HRESULT hr;
1170 RECT rect;
1171 BOOL ret;
1173 memset(&desc, 0, sizeof(desc));
1174 desc.no_pipeline = TRUE;
1175 if (!init_test_context(&context, &desc))
1176 return;
1177 device = context.device;
1178 command_list = context.list[0];
1179 queue = context.queue;
1181 window = CreateWindowA("static", "d3d12_test", WS_VISIBLE, 0, 0, 200, 200, NULL, NULL, NULL, NULL);
1182 swapchain = create_swapchain(&context, queue, window, 2, DXGI_FORMAT_B8G8R8A8_UNORM, 400, 400);
1183 index = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain);
1184 backbuffer = context.render_target[index];
1185 rtv = context.rtv[index];
1187 transition_sub_resource_state(command_list, backbuffer, 0,
1188 D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
1189 ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, rtv, green, 0, NULL);
1190 transition_sub_resource_state(command_list, backbuffer, 0,
1191 D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
1192 check_sub_resource_uint(backbuffer, 0, queue, command_list, 0xff00ff00, 0);
1194 reset_command_list(&context, 0);
1195 transition_sub_resource_state(command_list, backbuffer, 0,
1196 D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_PRESENT);
1197 hr = ID3D12GraphicsCommandList_Close(command_list);
1198 ok(hr == S_OK, "Failed to close command list, hr %#x.\n", hr);
1199 exec_command_list(queue, command_list);
1201 hr = IDXGISwapChain3_Present(swapchain, 1, 0);
1202 ok(hr == S_OK, "Failed to present, hr %#x.\n", hr);
1204 wait_queue_idle(device, queue);
1205 reset_command_list(&context, 0);
1207 destroy_render_targets(&context);
1208 refcount = IDXGISwapChain3_Release(swapchain);
1209 ok(!refcount, "Swapchain has %u references left.\n", refcount);
1210 DestroyWindow(window);
1212 window = create_window(WS_VISIBLE);
1213 ret = GetClientRect(window, &rect);
1214 ok(ret, "Failed to get client rect.\n");
1215 swapchain = create_swapchain(&context, queue, window, 4, DXGI_FORMAT_B8G8R8A8_UNORM, rect.right, rect.bottom);
1217 hr = ID3D12Device_CreateFence(device, 0, D3D12_FENCE_FLAG_NONE, &IID_ID3D12Fence, (void **)&fence);
1218 ok(hr == S_OK, "Failed to create fence, hr %#x.\n", hr);
1220 for (i = 0; i < ARRAY_SIZE(context.list); ++i)
1222 hr = ID3D12GraphicsCommandList_Close(context.list[i]);
1223 ok(hr == S_OK, "Failed to close command list %u, hr %#x.\n", i, hr);
1226 fence_value = 1;
1227 for (i = 0; i < 20; ++i)
1229 index = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain);
1231 hr = wait_for_fence(fence, frame_fence_value[index]);
1232 ok(hr == S_OK, "Failed to wait for fence, hr %#x.\n", hr);
1234 reset_command_list(&context, index);
1235 backbuffer = context.render_target[index];
1236 command_list = context.list[index];
1237 rtv = context.rtv[index];
1239 transition_sub_resource_state(command_list, backbuffer, 0,
1240 D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
1241 ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, rtv, green, 0, NULL);
1242 transition_sub_resource_state(command_list, backbuffer, 0,
1243 D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
1244 hr = ID3D12GraphicsCommandList_Close(command_list);
1245 ok(hr == S_OK, "Failed to close command list, hr %#x.\n", hr);
1246 exec_command_list(queue, command_list);
1248 hr = IDXGISwapChain3_Present(swapchain, 1, 0);
1249 ok(hr == S_OK, "Failed to present, hr %#x.\n", hr);
1251 if (i == 6)
1253 wait_queue_idle(device, queue);
1254 MoveWindow(window, 0, 0, 100, 100, TRUE);
1257 frame_fence_value[index] = fence_value;
1258 hr = ID3D12CommandQueue_Signal(queue, fence, fence_value);
1259 ok(hr == S_OK, "Failed to signal fence, hr %#x.\n", hr);
1260 ++fence_value;
1263 wait_queue_idle(device, queue);
1265 ID3D12Fence_Release(fence);
1266 destroy_render_targets(&context);
1267 refcount = IDXGISwapChain3_Release(swapchain);
1268 ok(!refcount, "Swapchain has %u references left.\n", refcount);
1269 DestroyWindow(window);
1270 destroy_test_context(&context);
1273 static void test_swapchain_backbuffer_index(void)
1275 static const float green[] = {0.0f, 1.0f, 0.0f, 1.0f};
1276 UINT64 frame_fence_value[MAX_FRAME_COUNT] = {0};
1277 ID3D12GraphicsCommandList *command_list;
1278 unsigned int expected_index, index, i;
1279 const unsigned int buffer_count = 2;
1280 D3D12_CPU_DESCRIPTOR_HANDLE rtv;
1281 struct test_context_desc desc;
1282 struct test_context context;
1283 ID3D12Resource *backbuffer;
1284 unsigned int sync_interval;
1285 IDXGISwapChain3 *swapchain;
1286 ID3D12CommandQueue *queue;
1287 ID3D12Device *device;
1288 ID3D12Fence *fence;
1289 UINT64 fence_value;
1290 ULONG refcount;
1291 HWND window;
1292 HRESULT hr;
1293 RECT rect;
1294 BOOL ret;
1296 memset(&desc, 0, sizeof(desc));
1297 desc.no_pipeline = TRUE;
1298 if (!init_test_context(&context, &desc))
1299 return;
1300 device = context.device;
1301 queue = context.queue;
1303 window = create_window(WS_VISIBLE);
1304 ret = GetClientRect(window, &rect);
1305 ok(ret, "Failed to get client rect.\n");
1306 swapchain = create_swapchain(&context, queue, window,
1307 buffer_count, DXGI_FORMAT_B8G8R8A8_UNORM, rect.right, rect.bottom);
1309 hr = ID3D12Device_CreateFence(device, 0, D3D12_FENCE_FLAG_NONE, &IID_ID3D12Fence, (void **)&fence);
1310 ok(hr == S_OK, "Failed to create fence, hr %#x.\n", hr);
1312 for (i = 0; i < ARRAY_SIZE(context.list); ++i)
1314 hr = ID3D12GraphicsCommandList_Close(context.list[i]);
1315 ok(hr == S_OK, "Failed to close command list %u, hr %#x.\n", i, hr);
1318 index = 1;
1319 fence_value = 1;
1320 for (i = 0; i < 20; ++i)
1322 expected_index = (index + 1) % buffer_count;
1323 index = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain);
1324 ok(index == expected_index, "Test %u: Got index %u, expected %u.\n", i, index, expected_index);
1326 hr = wait_for_fence(fence, frame_fence_value[index]);
1327 ok(hr == S_OK, "Failed to wait for fence, hr %#x.\n", hr);
1329 reset_command_list(&context, index);
1330 backbuffer = context.render_target[index];
1331 command_list = context.list[index];
1332 rtv = context.rtv[index];
1334 transition_sub_resource_state(command_list, backbuffer, 0,
1335 D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
1336 ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, rtv, green, 0, NULL);
1337 transition_sub_resource_state(command_list, backbuffer, 0,
1338 D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
1339 hr = ID3D12GraphicsCommandList_Close(command_list);
1340 ok(hr == S_OK, "Failed to close command list, hr %#x.\n", hr);
1341 exec_command_list(queue, command_list);
1343 if (i <= 4 || (8 <= i && i <= 14))
1344 sync_interval = 1;
1345 else
1346 sync_interval = 0;
1348 hr = IDXGISwapChain3_Present(swapchain, sync_interval, 0);
1349 ok(hr == S_OK, "Failed to present, hr %#x.\n", hr);
1351 frame_fence_value[index] = fence_value;
1352 hr = ID3D12CommandQueue_Signal(queue, fence, fence_value);
1353 ok(hr == S_OK, "Failed to signal fence, hr %#x.\n", hr);
1354 ++fence_value;
1357 wait_queue_idle(device, queue);
1359 ID3D12Fence_Release(fence);
1360 destroy_render_targets(&context);
1361 refcount = IDXGISwapChain3_Release(swapchain);
1362 ok(!refcount, "Swapchain has %u references left.\n", refcount);
1363 DestroyWindow(window);
1364 destroy_test_context(&context);
1367 static void test_desktop_window(void)
1369 DXGI_SWAP_CHAIN_DESC1 swapchain_desc;
1370 struct test_context_desc desc;
1371 struct test_context context;
1372 IDXGISwapChain1 *swapchain;
1373 IDXGIFactory4 *factory;
1374 IUnknown *queue;
1375 HWND window;
1376 HRESULT hr;
1377 RECT rect;
1378 BOOL ret;
1380 memset(&desc, 0, sizeof(desc));
1381 desc.no_render_target = TRUE;
1382 if (!init_test_context(&context, NULL))
1383 return;
1384 queue = (IUnknown *)context.queue;
1386 window = GetDesktopWindow();
1387 ret = GetClientRect(window, &rect);
1388 ok(ret, "Failed to get client rect.\n");
1390 hr = CreateDXGIFactory2(0, &IID_IDXGIFactory4, (void **)&factory);
1391 ok(hr == S_OK, "Failed to create factory, hr %#x.\n", hr);
1393 swapchain_desc.Width = 640;
1394 swapchain_desc.Height = 480;
1395 swapchain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1396 swapchain_desc.Stereo = FALSE;
1397 swapchain_desc.SampleDesc.Count = 1;
1398 swapchain_desc.SampleDesc.Quality = 0;
1399 swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
1400 swapchain_desc.BufferCount = 2;
1401 swapchain_desc.Scaling = DXGI_SCALING_STRETCH;
1402 swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
1403 swapchain_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
1404 swapchain_desc.Flags = 0;
1405 hr = IDXGIFactory4_CreateSwapChainForHwnd(factory, queue, window, &swapchain_desc, NULL, NULL, &swapchain);
1406 ok(hr == E_ACCESSDENIED, "Got unexpected hr %#x.\n", hr);
1408 swapchain_desc.Width = rect.right;
1409 swapchain_desc.Height = rect.bottom;
1410 hr = IDXGIFactory4_CreateSwapChainForHwnd(factory, queue, window, &swapchain_desc, NULL, NULL, &swapchain);
1411 ok(hr == E_ACCESSDENIED, "Got unexpected hr %#x.\n", hr);
1413 IDXGIFactory4_Release(factory);
1414 destroy_test_context(&context);
1417 START_TEST(d3d12)
1419 BOOL enable_debug_layer = FALSE;
1420 unsigned int argc, i;
1421 ID3D12Debug *debug;
1422 char **argv;
1424 argc = winetest_get_mainargs(&argv);
1425 for (i = 2; i < argc; ++i)
1427 if (!strcmp(argv[i], "--validate"))
1428 enable_debug_layer = TRUE;
1429 else if (!strcmp(argv[i], "--warp"))
1430 use_warp_adapter = TRUE;
1431 else if (!strcmp(argv[i], "--adapter") && i + 1 < argc)
1432 use_adapter_idx = atoi(argv[++i]);
1435 if (enable_debug_layer && SUCCEEDED(D3D12GetDebugInterface(&IID_ID3D12Debug, (void **)&debug)))
1437 ID3D12Debug_EnableDebugLayer(debug);
1438 ID3D12Debug_Release(debug);
1441 print_adapter_info();
1443 test_ordinals();
1444 test_interfaces();
1445 test_create_device();
1446 test_draw();
1447 test_swapchain_draw();
1448 test_swapchain_refcount();
1449 test_swapchain_size_mismatch();
1450 test_swapchain_backbuffer_index();
1451 test_desktop_window();