diff --git a/tests/d3d12.c b/tests/d3d12.c index ae8c0afa..d19b4b94 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -41,6 +41,8 @@ typedef int HRESULT; #endif +#include + #define COBJMACROS #define INITGUID #include "vkd3d_test.h" @@ -1161,7 +1163,7 @@ static void test_cpu_signal_fence(void) /* Basic tests with single event. */ event1 = create_event(); - ok(!!event1, "create_event failed.\n"); + ok(!!event1, "Failed to create event.\n"); ret = wait_event(event1, 0); ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); @@ -1253,7 +1255,7 @@ static void test_cpu_signal_fence(void) ok(value == 0, "Got unexpected value %lu.\n", (unsigned long)value); event2 = create_event(); - ok(!!event2, "create_event failed.\n"); + ok(!!event2, "Failed to create event.\n"); ret = wait_event(event1, 0); ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); @@ -1388,6 +1390,255 @@ static void test_cpu_signal_fence(void) ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount); } +static void test_gpu_signal_fence(void) +{ + D3D12_COMMAND_QUEUE_DESC command_queue_desc; + ID3D12CommandQueue *queue; + HANDLE event1, event2; + ID3D12Device *device; + unsigned int i, ret; + ID3D12Fence *fence; + ULONG refcount; + UINT64 value; + HRESULT hr; + + if (!(device = create_device())) + { + skip("Failed to create device.\n"); + return; + } + + command_queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + command_queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; + command_queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + command_queue_desc.NodeMask = 0; + hr = ID3D12Device_CreateCommandQueue(device, &command_queue_desc, + &IID_ID3D12CommandQueue, (void **)&queue); + ok(SUCCEEDED(hr), "CreateCommandQueue failed, hr %#x.\n", hr); + + hr = ID3D12Device_CreateFence(device, 0, D3D12_FENCE_FLAG_NONE, + &IID_ID3D12Fence, (void **)&fence); + ok(SUCCEEDED(hr), "CreateFence failed, hr %#x.\n", hr); + + /* XXX: It seems that when a queue is idle a fence is signalled immediately + * in D3D12. Vulkan implementations don't signal a fence immediately so + * libvkd3d doesn't as well. In order to make this test reliable + * wait_queue_idle() is inserted after every ID3D12CommandQueue_Signal(). */ + hr = ID3D12CommandQueue_Signal(queue, fence, 10); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + value = ID3D12Fence_GetCompletedValue(fence); + ok(value == 10, "Got unexpected value %"PRIu64".\n", value); + + hr = ID3D12CommandQueue_Signal(queue, fence, 0); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + value = ID3D12Fence_GetCompletedValue(fence); + ok(value == 0, "Got unexpected value %"PRIu64".\n", value); + + /* Basic tests with single event. */ + event1 = create_event(); + ok(!!event1, "Failed to create event.\n"); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + hr = ID3D12Fence_SetEventOnCompletion(fence, 5, event1); + ok(SUCCEEDED(hr), "SetEventOnCompletion failed, hr %#x.\n", hr); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + hr = ID3D12CommandQueue_Signal(queue, fence, 5); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_OBJECT_0, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + hr = ID3D12Fence_SetEventOnCompletion(fence, 6, event1); + ok(SUCCEEDED(hr), "SetEventOnCompletion failed, hr %#x.\n", hr); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + hr = ID3D12CommandQueue_Signal(queue, fence, 7); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_OBJECT_0, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + hr = ID3D12CommandQueue_Signal(queue, fence, 10); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + /* Attach one event to multiple values. */ + hr = ID3D12CommandQueue_Signal(queue, fence, 0); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + hr = ID3D12Fence_SetEventOnCompletion(fence, 3, event1); + ok(SUCCEEDED(hr), "SetEventOnCompletion failed, hr %#x.\n", hr); + hr = ID3D12Fence_SetEventOnCompletion(fence, 5, event1); + ok(SUCCEEDED(hr), "SetEventOnCompletion failed, hr %#x.\n", hr); + hr = ID3D12Fence_SetEventOnCompletion(fence, 9, event1); + ok(SUCCEEDED(hr), "SetEventOnCompletion failed, hr %#x.\n", hr); + hr = ID3D12Fence_SetEventOnCompletion(fence, 12, event1); + ok(SUCCEEDED(hr), "SetEventOnCompletion failed, hr %#x.\n", hr); + hr = ID3D12Fence_SetEventOnCompletion(fence, 12, event1); + ok(SUCCEEDED(hr), "SetEventOnCompletion failed, hr %#x.\n", hr); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + for (i = 1; i < 13; ++i) + { + hr = ID3D12CommandQueue_Signal(queue, fence, i); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + if (i == 3 || i == 5 || i == 9 || i == 12) + { + ret = wait_event(event1, 0); + ok(ret == WAIT_OBJECT_0, "Got unexpected return value %#x for %u.\n", ret, i); + } + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x for %u.\n", ret, i); + } + + /* Tests with 2 events. */ + hr = ID3D12CommandQueue_Signal(queue, fence, 0); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + value = ID3D12Fence_GetCompletedValue(fence); + ok(value == 0, "Got unexpected value %"PRIu64".\n", value); + + event2 = create_event(); + ok(!!event2, "Failed to create event.\n"); + + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + hr = ID3D12Fence_SetEventOnCompletion(fence, 100, event1); + ok(SUCCEEDED(hr), "SetEventOnCompletion failed, hr %#x.\n", hr); + hr = ID3D12Fence_SetEventOnCompletion(fence, ~(UINT64)0, event2); + ok(SUCCEEDED(hr), "SetEventOnCompletion failed, hr %#x.\n", hr); + + hr = ID3D12CommandQueue_Signal(queue, fence, 50); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + hr = ID3D12CommandQueue_Signal(queue, fence, 99); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + hr = ID3D12CommandQueue_Signal(queue, fence, 100); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_OBJECT_0, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + hr = ID3D12CommandQueue_Signal(queue, fence, 101); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + hr = ID3D12CommandQueue_Signal(queue, fence, 0); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + hr = ID3D12CommandQueue_Signal(queue, fence, 100); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + hr = ID3D12CommandQueue_Signal(queue, fence, ~(UINT64)0); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_OBJECT_0, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + hr = ID3D12CommandQueue_Signal(queue, fence, ~(UINT64)0); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + hr = ID3D12CommandQueue_Signal(queue, fence, 0); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + /* Attach two events to the same value. */ + hr = ID3D12CommandQueue_Signal(queue, fence, 0); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + hr = ID3D12Fence_SetEventOnCompletion(fence, 1, event1); + ok(SUCCEEDED(hr), "SetEventOnCompletion failed, hr %#x.\n", hr); + hr = ID3D12Fence_SetEventOnCompletion(fence, 1, event2); + ok(SUCCEEDED(hr), "SetEventOnCompletion failed, hr %#x.\n", hr); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + hr = ID3D12CommandQueue_Signal(queue, fence, 3); + ok(SUCCEEDED(hr), "Signal failed, hr %#x.\n", hr); + wait_queue_idle(device, queue); + ret = wait_event(event1, 0); + ok(ret == WAIT_OBJECT_0, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_OBJECT_0, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event1, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + ret = wait_event(event2, 0); + ok(ret == WAIT_TIMEOUT, "Got unexpected return value %#x.\n", ret); + + wait_queue_idle(device, queue); + + destroy_event(event1); + destroy_event(event2); + + ID3D12Fence_Release(fence); + ID3D12CommandQueue_Release(queue); + refcount = ID3D12Device_Release(device); + ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount); +} + static void test_clear_render_target_view(void) { static const float green[] = { 0.0f, 1.0f, 0.0f, 1.0f }; @@ -1525,5 +1776,6 @@ START_TEST(d3d12) test_create_fence(); test_reset_command_allocator(); test_cpu_signal_fence(); + test_gpu_signal_fence(); test_clear_render_target_view(); }