Skip to content

Commit

Permalink
tests: Add test for ID3D12DXVKInteropDevice1 cmdbuf sharing
Browse files Browse the repository at this point in the history
Signed-off-by: Liam Middlebrook <lmiddlebrook@nvidia.com>
  • Loading branch information
liam-middlebrook committed Jul 31, 2024
1 parent 404c332 commit 7cdb3d7
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 29 deletions.
64 changes: 35 additions & 29 deletions tests/d3d12_crosstest.h
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,41 @@ static inline void wait_queue_idle_no_event_(unsigned int line, ID3D12Device *de
ID3D12Fence_Release(fence);
}

static PFN_vkGetInstanceProcAddr pfn_vkGetInstanceProcAddr;
static PFN_vkGetDeviceProcAddr pfn_vkGetDeviceProcAddr;
static bool init_vulkan_loader(void)

Check warning on line 375 in tests/d3d12_crosstest.h

View workflow job for this annotation

GitHub Actions / build-set-linux

‘init_vulkan_loader’ defined but not used [-Wunused-function]
{
#ifdef _WIN32
HMODULE hmod;
#else
void *mod;
#endif

if (pfn_vkGetInstanceProcAddr)
return true;

if (pfn_vkGetDeviceProcAddr)
return true;

#ifdef _WIN32
hmod = LoadLibraryA(SONAME_LIBVULKAN);

Check failure on line 390 in tests/d3d12_crosstest.h

View workflow job for this annotation

GitHub Actions / build-set-linux

‘SONAME_LIBVULKAN’ undeclared (first use in this function)
if (!hmod)
return false;

pfn_vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress(hmod, "vkGetInstanceProcAddr");

Check warning on line 394 in tests/d3d12_crosstest.h

View workflow job for this annotation

GitHub Actions / build-set-linux

cast between incompatible function types from ‘FARPROC’ {aka ‘int (__attribute__((stdcall)) *)()’} to ‘void (__attribute__((stdcall)) * (__attribute__((stdcall)) *)(struct VkInstance_T *, const char *))(void)’ [-Wcast-function-type]
pfn_vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)GetProcAddress(hmod, "vkGetDeviceProcAddr");

Check warning on line 395 in tests/d3d12_crosstest.h

View workflow job for this annotation

GitHub Actions / build-set-linux

cast between incompatible function types from ‘FARPROC’ {aka ‘int (__attribute__((stdcall)) *)()’} to ‘void (__attribute__((stdcall)) * (__attribute__((stdcall)) *)(struct VkDevice_T *, const char *))(void)’ [-Wcast-function-type]
#else
mod = dlopen(SONAME_LIBVULKAN, RTLD_LAZY);
if (!mod)
return false;

pfn_vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(mod, "vkGetInstanceProcAddr");
pfn_vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)dlsym(mod, "vkGetDeviceProcAddr");
#endif

return pfn_vkGetInstanceProcAddr != NULL;
}

#if defined(_WIN32) && !defined(VKD3D_FORCE_UTILS_WRAPPER)
static IUnknown *create_warp_adapter(IDXGIFactory4 *factory)
{
Expand Down Expand Up @@ -544,35 +579,6 @@ static inline bool is_vk_device_extension_supported(ID3D12Device *device, const
}
#else

static PFN_vkGetInstanceProcAddr pfn_vkGetInstanceProcAddr;
static bool init_vulkan_loader(void)
{
#ifdef _WIN32
HMODULE hmod;
#else
void *mod;
#endif

if (pfn_vkGetInstanceProcAddr)
return true;

#ifdef _WIN32
hmod = LoadLibraryA(SONAME_LIBVULKAN);
if (!hmod)
return false;

pfn_vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress(hmod, "vkGetInstanceProcAddr");
#else
mod = dlopen(SONAME_LIBVULKAN, RTLD_LAZY);
if (!mod)
return false;

pfn_vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(mod, "vkGetInstanceProcAddr");
#endif

return pfn_vkGetInstanceProcAddr != NULL;
}

static ID3D12Device *create_device(void)
{
ID3D12Device *device;
Expand Down
155 changes: 155 additions & 0 deletions tests/d3d12_dxvk_interop_device.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@

/*
* Copyright 2024 NVIDIA Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/

#define VKD3D_DBG_CHANNEL VKD3D_DBG_CHANNEL_API
#include "d3d12_crosstest.h"

void test_vkd3d_dxvk_cmdbuf_interop(void)
{
PFN_vkCmdUpdateBuffer pfn_vkCmdUpdateBuffer;
ID3D12DXVKInteropDevice1 *interop_device;
ID3D12GraphicsCommandList *command_list;
ID3D12CommandAllocator *allocator;
VkPhysicalDevice vkPhysicalDevice;
struct resource_readback rb;
struct test_context context;
ID3D12CommandQueue *queue;
VkCommandBuffer vkCmdBuf;
VkDeviceAddress offset;
ID3D12Resource *buffer;
ID3D12Device *device;
VkInstance vkInstance;
VkDevice vkDevice;
VkBuffer vkBuffer;
unsigned int value;
HRESULT hr;

static const unsigned int data_values[] = {0xdeadbeef, 0xf00baa, 0xdeadbeef, 0xf00baa};
static const uint32_t update_data[3] = { 0x1020304, 0xc0d0e0f, 0x5060708};

// Initialize pointer to GDPA function
if (!init_vulkan_loader())
return;

if (!init_test_context(&context, NULL))
return;

device = context.device;

if (FAILED(hr = ID3D12Device_QueryInterface(device,
&IID_ID3D12DXVKInteropDevice1, (void **)&interop_device)))
{
skip("ID3D12DXVKInteropDevice1 not implemented.\n");
destroy_test_context(&context);
return;
}

if (FAILED(hr = ID3D12DXVKInteropDevice1_GetVulkanHandles(interop_device,
&vkInstance,
&vkPhysicalDevice,
&vkDevice)))
{
ok(hr == S_OK, "ID3D12DXVKInteropDevice1_GetVulkanHandles failed %#x.\n", hr);
destroy_test_context(&context);
return;
}

pfn_vkCmdUpdateBuffer = (PFN_vkCmdUpdateBuffer)pfn_vkGetDeviceProcAddr(vkDevice, "vkCmdUpdateBuffer");
if (!pfn_vkCmdUpdateBuffer)
{
ok(pfn_vkCmdUpdateBuffer, "vkCmdUpdateBuffer not found.\n");
destroy_test_context(&context);
return;
}

if (FAILED(hr = ID3D12DXVKInteropDevice1_CreateInteropCommandAllocator(interop_device,
D3D12_COMMAND_LIST_TYPE_DIRECT,
&allocator)))
{
ok(hr == S_OK, "ID3D12DXVKInteropDevice1_CreateInteropCommandAllocator failed %#x.\n", hr);
destroy_test_context(&context);
return;
}

if (FAILED(hr = ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
allocator, NULL, &IID_ID3D12GraphicsCommandList, (void **)&command_list)))
{
ok(hr == S_OK, "ID3D12Device_CreateCommandList failed %#x.\n", hr);
destroy_test_context(&context);
return;
}

if (FAILED(ID3D12DXVKInteropDevice1_GetVulkanCmdHandles(interop_device,
(ID3D12CommandList*)command_list,
&vkCmdBuf)))
{
ok(hr == S_OK, "ID3D12DXVKInteropDevice1_GetVulkanCmdHandles failed %#x.\n", hr);
destroy_test_context(&context);
return;
}

queue = context.queue;

// Create a D3D12 Buffer
buffer = create_default_buffer(device,
sizeof(data_values),
D3D12_RESOURCE_FLAG_NONE,
D3D12_RESOURCE_STATE_COPY_DEST);
upload_buffer_data(buffer, 0, sizeof(data_values), data_values, queue, command_list);
reset_command_list(command_list, allocator);


// Export it to VK and use VK functions to manipulate it
ID3D12DXVKInteropDevice1_GetVulkanResourceInfo1(interop_device,
buffer,
(uint64_t*)&vkBuffer,
&offset,
NULL);

// Update in the pattern 0 1 - 2
pfn_vkCmdUpdateBuffer(vkCmdBuf, vkBuffer, 0, sizeof(data_values[0]) * 2, &update_data[0]);
pfn_vkCmdUpdateBuffer(vkCmdBuf, vkBuffer, sizeof(data_values[0]) * 3, sizeof(data_values[0]), &update_data[2]);

// Back to D3D12 logic, close the command list + execute it
hr = ID3D12GraphicsCommandList_Close(command_list);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
exec_command_list(queue, command_list);
wait_queue_idle(device, queue);
reset_command_list(command_list, allocator);


// Validate data
get_buffer_readback_with_command_list(buffer, DXGI_FORMAT_R32_UINT, &rb, queue, command_list);
value = get_readback_uint(&rb, 0, 0, 0);
ok(value == update_data[0], "Got unexpected value %#x, expected %#x.\n", value, update_data[0]);
value = get_readback_uint(&rb, 1, 0, 0);
ok(value == update_data[1], "Got unexpected value %#x, expected %#x.\n", value, update_data[1]);
value = get_readback_uint(&rb, 2, 0, 0);
ok(value == data_values[2], "Got unexpected value %#x, expected %#x.\n", value, data_values[2]);
value = get_readback_uint(&rb, 3, 0, 0);
ok(value == update_data[2], "Got unexpected value %#x, expected %#x.\n", value, update_data[2]);
release_resource_readback(&rb);
reset_command_list(command_list, allocator);

ID3D12Resource_Release(buffer);
ID3D12GraphicsCommandList_Release(command_list);
ID3D12CommandAllocator_Release(allocator);
ID3D12DXVKInteropDevice1_Release(interop_device);
destroy_test_context(&context);
}
1 change: 1 addition & 0 deletions tests/d3d12_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -424,3 +424,4 @@ decl_test(test_sm68_draw_parameters);
decl_test(test_sm68_wave_size_range);
decl_test(test_sm68_sample_cmp_bias_grad);
decl_test(test_planar_video_formats);
decl_test(test_vkd3d_dxvk_cmdbuf_interop);
1 change: 1 addition & 0 deletions tests/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ d3d12_test_utils_lib = static_library('d3d12-test-utils', 'd3d12_test_utils.c',
include_directories : vkd3d_private_includes)

d3d12_test_src = [
'd3d12_dxvk_interop_device.c',
'd3d12_clip_cull_distance.c',
'd3d12_enhanced_barriers.c',
'd3d12_sampler_feedback.c',
Expand Down

0 comments on commit 7cdb3d7

Please sign in to comment.