From 2168e0b93ce57a63fc09188b76c7d653e70de70a Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 16 May 2022 14:16:24 -0500 Subject: [PATCH] tests: D3D11 and Vulkan client compositor tests --- tests/CMakeLists.txt | 10 +- tests/tests_aux_d3d.cpp | 5 +- tests/tests_comp_client_d3d11.cpp | 91 +++++++++++++ tests/tests_comp_client_vulkan.cpp | 205 +++++++++++++++++++++++++++++ 4 files changed, 306 insertions(+), 5 deletions(-) create mode 100644 tests/tests_comp_client_d3d11.cpp create mode 100644 tests/tests_comp_client_vulkan.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7308cc670..9b14a58a1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -24,7 +24,10 @@ set(tests tests_worker ) if(XRT_HAVE_D3D11) - list(APPEND tests tests_aux_d3d) + list(APPEND tests tests_aux_d3d tests_comp_client_d3d11) +endif() +if(XRT_HAVE_VULKAN) + list(APPEND tests tests_comp_client_vulkan) endif() foreach(testname ${tests}) @@ -46,4 +49,9 @@ target_link_libraries(tests_rational PRIVATE aux_math) if(XRT_HAVE_D3D11) target_link_libraries(tests_aux_d3d PRIVATE aux_d3d) + target_link_libraries(tests_comp_client_d3d11 PRIVATE comp_client comp_mock) +endif() + +if(XRT_HAVE_VULKAN) + target_link_libraries(tests_comp_client_vulkan PRIVATE comp_client comp_mock comp_util aux_vk) endif() diff --git a/tests/tests_aux_d3d.cpp b/tests/tests_aux_d3d.cpp index 0336b9e61..e61246139 100644 --- a/tests/tests_aux_d3d.cpp +++ b/tests/tests_aux_d3d.cpp @@ -82,12 +82,9 @@ isDepthStencilFormat(DXGI_FORMAT format) TEST_CASE("d3d11_allocate", "[.][needgpu]") { ComGuard comGuard; - wil::com_ptr adapter; - - CHECK_NOTHROW(adapter = getAdapterByIndex(0, U_LOGGING_TRACE)); wil::com_ptr device; wil::com_ptr context; - CHECK_NOTHROW(std::tie(device, context) = createD3D11Device(adapter, U_LOGGING_TRACE)); + std::tie(device, context) = createD3D11Device(); auto device5 = device.query(); std::vector> images; std::vector handles; diff --git a/tests/tests_comp_client_d3d11.cpp b/tests/tests_comp_client_d3d11.cpp new file mode 100644 index 000000000..570c51618 --- /dev/null +++ b/tests/tests_comp_client_d3d11.cpp @@ -0,0 +1,91 @@ +// Copyright 2022, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Direct3D 11 tests. + * @author Ryan Pavlik + */ + + +#include "mock/mock_compositor.h" +#include "client/comp_d3d11_client.h" + +#include "catch/catch.hpp" +#include "util/u_handles.h" + +#include +#include +#include + +#include + + +using namespace xrt::auxiliary::d3d; +using namespace xrt::auxiliary::util; + +TEST_CASE("client_compositor", "[.][needgpu]") +{ + xrt_compositor_native *xcn = mock_create_native_compositor(); + struct mock_compositor *mc = mock_compositor(&(xcn->base)); + + ComGuard comGuard; + + wil::com_ptr device; + wil::com_ptr context; + std::tie(device, context) = createD3D11Device(); + struct xrt_compositor_d3d11 *xcd3d = client_d3d11_compositor_create(xcn, device.get()); + struct xrt_compositor *xc = &xcd3d->base; + + SECTION("Swapchain create and import") + { + struct Data + { + bool nativeCreateCalled = false; + + bool nativeImportCalled = false; + } data; + mc->userdata = &data; + mc->compositor_hooks.create_swapchain = + [](struct mock_compositor *mc, struct mock_compositor_swapchain *mcsc, + const struct xrt_swapchain_create_info *info, struct xrt_swapchain **out_xsc) { + auto *data = static_cast(mc->userdata); + data->nativeCreateCalled = true; + return XRT_SUCCESS; + }; + mc->compositor_hooks.import_swapchain = + [](struct mock_compositor *mc, struct mock_compositor_swapchain *mcsc, + const struct xrt_swapchain_create_info *info, struct xrt_image_native *native_images, + uint32_t image_count, struct xrt_swapchain **out_xscc) { + auto *data = static_cast(mc->userdata); + data->nativeImportCalled = true; + // need to release the native handles to avoid leaks + for (uint32_t i = 0; i < image_count; ++i) { + u_graphics_buffer_unref(&native_images[i].handle); + } + return XRT_SUCCESS; + }; + xrt_swapchain_create_info xsci{}; + xsci.format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + xsci.bits = (xrt_swapchain_usage_bits)(XRT_SWAPCHAIN_USAGE_COLOR | XRT_SWAPCHAIN_USAGE_SAMPLED); + xsci.sample_count = 1; + xsci.width = 800; + xsci.height = 600; + xsci.face_count = 1; + xsci.array_size = 1; + xsci.mip_count = 1; + SECTION("Swapchain Create") + { + struct xrt_swapchain *xsc = nullptr; + // This will fail because the mock compositor doesn't actually import, but it will get far + // enough to trigger our hook and update the flag. + xrt_comp_create_swapchain(xc, &xsci, &xsc); + // D3D always imports into the native compositor + CHECK(data.nativeImportCalled); + CHECK_FALSE(data.nativeCreateCalled); + xrt_swapchain_reference(&xsc, nullptr); + } + } + + xrt_comp_destroy(&xc); + xrt_comp_native_destroy(&xcn); +} diff --git a/tests/tests_comp_client_vulkan.cpp b/tests/tests_comp_client_vulkan.cpp new file mode 100644 index 000000000..4ff40a1ae --- /dev/null +++ b/tests/tests_comp_client_vulkan.cpp @@ -0,0 +1,205 @@ +// Copyright 2022, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Basic Vulkan compositor tests. + * @author Ryan Pavlik + */ + + +#include "mock/mock_compositor.h" +#include "client/comp_vk_client.h" +#include "xrt/xrt_results.h" +#include + +#undef Always +#undef None + +#include "catch/catch.hpp" +#include "util/comp_vulkan.h" +#include "util/u_logging.h" +#include "util/u_string_list.h" +#include "vk/vk_helpers.h" +#include "xrt/xrt_compositor.h" + +#include +#include + +namespace { +struct Deleter +{ + void + operator()(struct xrt_compositor_native *xcn) const + { + xrt_comp_native_destroy(&xcn); + } +}; +} // namespace + +using unique_native_compositor = std::unique_ptr; +// clang-format off +#define COMP_INSTANCE_EXTENSIONS_COMMON \ + VK_EXT_DEBUG_REPORT_EXTENSION_NAME, \ + VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, \ + VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, \ + VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, \ + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, \ + VK_KHR_SURFACE_EXTENSION_NAME +// clang-format on + +static const char *instance_extensions_common[] = { + COMP_INSTANCE_EXTENSIONS_COMMON, +}; +static const char *required_device_extensions[] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, // + VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, // + VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME, // + VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, // + VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, // + VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, // + +// Platform version of "external_memory" +#if defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_FD) + VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, + +#elif defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER) + VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME, + +#elif defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_WIN32_HANDLE) + VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, + +#else +#error "Need port!" +#endif + +// Platform version of "external_fence" and "external_semaphore" +#if defined(XRT_GRAPHICS_SYNC_HANDLE_IS_FD) // Optional + +#elif defined(XRT_GRAPHICS_SYNC_HANDLE_IS_WIN32_HANDLE) + VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, + VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME, + +#else +#error "Need port!" +#endif +}; + +struct StringListDeleter +{ + void + operator()(u_string_list *usl) const + { + u_string_list_destroy(&usl); + } +}; + +using unique_string_list = std::unique_ptr; +struct CompDeleter +{ + void + operator()(struct xrt_compositor *xc) const + { + xrt_comp_destroy(&xc); + } + + void + operator()(struct xrt_compositor_vk *xcvk) const + { + xrt_compositor *xc = &xcvk->base; + xrt_comp_destroy(&xc); + } +}; + +using unique_compositor_vulkan = std::unique_ptr; + +TEST_CASE("client_compositor", "[.][needgpu]") +{ + xrt_compositor_native *xcn = mock_create_native_compositor(); + struct mock_compositor *mc = mock_compositor(&(xcn->base)); + + // every backend needs at least the common extensions + unique_string_list required_instance_ext_list{ + u_string_list_create_from_array(instance_extensions_common, ARRAY_SIZE(instance_extensions_common))}; + + unique_string_list optional_instance_ext_list{u_string_list_create()}; + + unique_string_list required_device_extension_list{ + u_string_list_create_from_array(required_device_extensions, ARRAY_SIZE(required_device_extensions))}; + + unique_string_list optional_device_extension_list{u_string_list_create()}; + + comp_vulkan_arguments args{VK_MAKE_VERSION(1, 0, 0), + vkGetInstanceProcAddr, + required_instance_ext_list.get(), + optional_instance_ext_list.get(), + required_device_extension_list.get(), + optional_device_extension_list.get(), + U_LOGGING_TRACE, + false /* only_compute_queue */, + true /*timeline_semaphore*/, + -1, + -1}; + vk_bundle vk_bundle_storage{}; + vk_bundle *vk = &vk_bundle_storage; + comp_vulkan_results results{}; + REQUIRE(comp_vulkan_init_bundle(vk, &args, &results)); + struct xrt_compositor_vk *xcvk = xrt_gfx_vk_provider_create( // + xcn, // + vk->instance, // + vkGetInstanceProcAddr, // + vk->physical_device, // + vk->device, +#if defined(XRT_GRAPHICS_SYNC_HANDLE_IS_FD) // + vk->external.fence_sync_fd, // + vk->external.binary_semaphore_sync_fd, // + vk->external.timeline_semaphore_sync_fd, // +#elif defined(XRT_GRAPHICS_SYNC_HANDLE_IS_WIN32_HANDLE) + vk->external.fence_win32_handle, // + vk->external.binary_semaphore_win32_handle, // + vk->external.timeline_semaphore_win32_handle, // +#else +#error "Need port for fence sync handles checkers" +#endif + vk->queue_family_index, // + vk->queue_index); + struct xrt_compositor *xc = &xcvk->base; + + SECTION("CreateSwapchain calls native create") + { + bool nativeCreateCalled = false; + mc->userdata = &nativeCreateCalled; + mc->compositor_hooks.create_swapchain = + [](struct mock_compositor *mc, struct mock_compositor_swapchain *mcsc, + const struct xrt_swapchain_create_info *info, struct xrt_swapchain **out_xsc) { + *static_cast(mc->userdata) = true; + return XRT_SUCCESS; + }; + xrt_swapchain_create_info xsci{}; + xsci.format = VK_FORMAT_B8G8R8A8_SRGB; + xsci.bits = (xrt_swapchain_usage_bits)(XRT_SWAPCHAIN_USAGE_COLOR | XRT_SWAPCHAIN_USAGE_SAMPLED); + xsci.sample_count = 1; + xsci.width = 800; + xsci.height = 600; + xsci.face_count = 1; + xsci.array_size = 1; + xsci.mip_count = 1; + + struct xrt_swapchain *xsc = nullptr; + // This will fail because the mock compositor doesn't actually create images for Vulkan to import, but + // it will get far enough to trigger our hook and update the flag. + xrt_comp_create_swapchain(xc, &xsci, &xsc); + CHECK(nativeCreateCalled); + xrt_swapchain_reference(&xsc, nullptr); + } + + xrt_comp_destroy(&xc); + + if (vk->cmd_pool != VK_NULL_HANDLE) { + vk->vkDeviceWaitIdle(vk->device); + vk->vkDestroyCommandPool(vk->device, vk->cmd_pool, NULL); + vk->cmd_pool = VK_NULL_HANDLE; + } + vk_deinit_mutex(vk); + + xrt_comp_native_destroy(&xcn); +}