The open source OpenXR runtime
1// Copyright 2022, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief Direct3D 11 tests.
6 * @author Rylie Pavlik <rylie.pavlik@collabora.com>
7 */
8#include "catch_amalgamated.hpp"
9
10#include "aux_d3d_dxgi_formats.hpp"
11
12#include <iostream>
13
14#include <xrt/xrt_config_have.h>
15#include <d3d/d3d_dxgi_helpers.hpp>
16#include <d3d/d3d_d3d11_helpers.hpp>
17#include <d3d/d3d_d3d11_allocator.hpp>
18#include <util/u_win32_com_guard.hpp>
19
20#ifdef XRT_HAVE_VULKAN
21#include "vktest_init_bundle.hpp"
22#include <vk/vk_image_allocator.h>
23#include <util/u_handles.h>
24#include <d3d/d3d_dxgi_formats.h>
25#endif
26
27#include <d3d11_4.h>
28
29using namespace xrt::auxiliary::d3d;
30using namespace xrt::auxiliary::d3d::d3d11;
31using namespace xrt::auxiliary::util;
32
33
34TEST_CASE("dxgi_adapter", "[.][needgpu]")
35{
36 ComGuard comGuard;
37 wil::com_ptr<IDXGIAdapter> adapter;
38
39 CHECK_NOTHROW(adapter = getAdapterByIndex(0, U_LOGGING_TRACE));
40 CHECK(adapter);
41 auto adapter1 = adapter.query<IDXGIAdapter1>();
42 DXGI_ADAPTER_DESC1 desc{};
43 REQUIRE(SUCCEEDED(adapter1->GetDesc1(&desc)));
44
45 xrt_luid_t luid{};
46 memcpy(&luid, &(desc.AdapterLuid), sizeof(luid));
47
48
49 wil::com_ptr<IDXGIAdapter> adapterFromLuid;
50 CHECK_NOTHROW(adapterFromLuid = getAdapterByLUID(luid, U_LOGGING_TRACE));
51 CHECK(adapterFromLuid);
52}
53
54TEST_CASE("d3d11_device", "[.][needgpu]")
55{
56 ComGuard comGuard;
57 wil::com_ptr<IDXGIAdapter> adapter;
58
59 CHECK_NOTHROW(adapter = getAdapterByIndex(0, U_LOGGING_TRACE));
60 CHECK(adapter);
61 wil::com_ptr<ID3D11Device> device;
62 wil::com_ptr<ID3D11DeviceContext> context;
63 CHECK_NOTHROW(std::tie(device, context) = createDevice(adapter, U_LOGGING_TRACE));
64 CHECK(device);
65 CHECK(context);
66}
67
68#ifdef XRT_HAVE_VULKAN
69
70static inline bool
71tryImport(struct vk_bundle *vk, std::vector<HANDLE> const &handles, const struct xrt_swapchain_create_info &xsci)
72{
73
74 INFO("Testing import into Vulkan");
75
76 static constexpr bool use_dedicated_allocation = false;
77 xrt_swapchain_create_info vk_info = xsci;
78 vk_info.format = d3d_dxgi_format_to_vk((DXGI_FORMAT)xsci.format);
79 const auto free_vk_ic = [&](struct vk_image_collection *vkic) {
80 vk_ic_destroy(vk, vkic);
81 delete vkic;
82 };
83
84 std::shared_ptr<vk_image_collection> vkic{new vk_image_collection, free_vk_ic};
85
86 uint32_t image_count = static_cast<uint32_t>(handles.size());
87 // Populate for import
88 std::vector<xrt_image_native> xins;
89 xins.reserve(image_count);
90
91 for (HANDLE handle : handles) {
92 /*!
93 * If shared resources have been allocated without using NT handles we can't use DuplicateHandle
94 *(like u_graphics_buffer_ref does internally) or CloseHandle (which wil::~unique_handle will call).
95 * More info:
96 * https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiresource-getsharedhandle#remarks
97 * When using KMT handles, their validity is tied to the underlying video memory (I guess that means a
98 * ID3D11Texture2D object).
99 */
100 xrt_image_native xin;
101 xin.handle = handle;
102 xin.size = 0;
103 xin.use_dedicated_allocation = use_dedicated_allocation;
104 xin.is_dxgi_handle = true;
105
106 xins.emplace_back(xin);
107 }
108
109 // Import into a vulkan image collection
110 const VkResult ret = vk_ic_from_natives(vk, &vk_info, xins.data(), (uint32_t)xins.size(), vkic.get());
111 VK_CHK_WITH_RET(ret, "vk_ic_from_natives", false);
112
113 return true;
114}
115#else
116
117static inline bool
118tryImport(struct vk_bundle * /* vk */,
119 std::vector<wil::unique_handle> const & /* handles */,
120 const struct xrt_swapchain_create_info & /* xsci */)
121{
122 return true;
123}
124
125#endif
126
127TEST_CASE("d3d11_allocate", "[.][needgpu]")
128{
129 unique_vk_bundle vk = makeVkBundle();
130
131#ifdef XRT_HAVE_VULKAN
132 REQUIRE(vktest_init_bundle(vk.get()));
133#endif
134
135 ComGuard comGuard;
136 wil::com_ptr<ID3D11Device> device;
137 wil::com_ptr<ID3D11DeviceContext> context;
138 std::tie(device, context) = createDevice();
139 auto device5 = device.query<ID3D11Device5>();
140 std::vector<wil::com_ptr<ID3D11Texture2D1>> images;
141 std::vector<HANDLE> handles;
142
143 static constexpr bool kKeyedMutex = true;
144 size_t imageCount = 3;
145
146 xrt_swapchain_create_info xsci{};
147 CAPTURE(xsci.sample_count = 1);
148 CAPTURE(xsci.width = 800);
149 CAPTURE(xsci.height = 600);
150
151 CAPTURE(xsci.mip_count = 1);
152 xsci.face_count = 1;
153 xsci.array_size = 1;
154 SECTION("create images")
155 {
156 auto nameAndFormat = GENERATE(values(namesAndFormats));
157 DYNAMIC_SECTION("Texture format " << nameAndFormat.first)
158 {
159 auto format = nameAndFormat.second;
160 CAPTURE(isDepthStencilFormat(format));
161 xsci.format = format;
162 if (isDepthStencilFormat(format)) {
163 xsci.bits = XRT_SWAPCHAIN_USAGE_DEPTH_STENCIL;
164 } else {
165 xsci.bits = XRT_SWAPCHAIN_USAGE_COLOR;
166 }
167 xsci.bits = (xrt_swapchain_usage_bits)(xsci.bits | XRT_SWAPCHAIN_USAGE_SAMPLED);
168 images.clear();
169 handles.clear();
170 SECTION("invalid array size 0")
171 {
172 CAPTURE(xsci.array_size = 0);
173 REQUIRE(XRT_SUCCESS !=
174 allocateSharedImages(*device5, xsci, imageCount, kKeyedMutex, images, handles));
175 CHECK(images.empty());
176 CHECK(handles.empty());
177 }
178 SECTION("not array")
179 {
180 CAPTURE(xsci.array_size);
181 REQUIRE(XRT_SUCCESS ==
182 allocateSharedImages(*device5, xsci, imageCount, kKeyedMutex, images, handles));
183 CHECK(images.size() == imageCount);
184 CHECK(handles.size() == imageCount);
185 CHECK(tryImport(vk.get(), handles, xsci));
186 }
187 SECTION("array of 2")
188 {
189 CAPTURE(xsci.array_size = 2);
190 REQUIRE(XRT_SUCCESS ==
191 allocateSharedImages(*device5, xsci, imageCount, kKeyedMutex, images, handles));
192 CHECK(images.size() == imageCount);
193 CHECK(handles.size() == imageCount);
194 CHECK(tryImport(vk.get(), handles, xsci));
195 }
196 SECTION("cubemaps not implemented")
197 {
198 CAPTURE(xsci.array_size);
199 CAPTURE(xsci.face_count = 6);
200 REQUIRE(XRT_ERROR_ALLOCATION ==
201 allocateSharedImages(*device5, xsci, imageCount, kKeyedMutex, images, handles));
202 CHECK(images.empty());
203 CHECK(handles.empty());
204 }
205 SECTION("protected content not implemented")
206 {
207 CAPTURE(xsci.array_size);
208 CAPTURE(xsci.create = XRT_SWAPCHAIN_CREATE_PROTECTED_CONTENT);
209 REQUIRE(XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED ==
210 allocateSharedImages(*device5, xsci, imageCount, kKeyedMutex, images, handles));
211 CHECK(images.empty());
212 CHECK(handles.empty());
213 }
214 }
215 }
216}