The open source OpenXR runtime
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

c/client: Extract some utilities usable by D3D11 and 12

+319 -106
+1
doc/changes/compositor/mr.943.md
··· 5 5 - mr.1326 6 6 - mr.1302 7 7 - mr.1337 8 + - mr.1340 8 9 --- 9 10 10 11 Full support for D3D11 client applications on Windows.
+9 -2
src/xrt/compositor/CMakeLists.txt
··· 58 58 target_sources(comp_client PRIVATE client/comp_egl_client.c client/comp_egl_client.h) 59 59 endif() 60 60 61 + if(XRT_HAVE_D3D11 OR XRT_HAVE_D3D12) 62 + target_link_libraries(comp_client PRIVATE aux_d3d) 63 + endif() 64 + 65 + if(XRT_HAVE_D3D11 OR XRT_HAVE_D3D12) 66 + target_sources(comp_client PRIVATE client/comp_d3d_common.cpp client/comp_d3d_common.hpp) 67 + endif() 68 + 61 69 if(XRT_HAVE_D3D11) 62 70 target_sources( 63 71 comp_client PRIVATE client/comp_d3d11_client.cpp client/comp_d3d11_client.h ··· 65 73 ) 66 74 target_link_libraries(comp_client PRIVATE aux_d3d) 67 75 endif() 76 + 68 77 ## 69 78 # Util library 70 79 # ··· 259 268 endif() 260 269 endif() 261 270 262 - 263 271 ### 264 272 # Null compositor 265 273 # ··· 267 275 if(XRT_FEATURE_COMPOSITOR_NULL) 268 276 add_subdirectory(null) 269 277 endif() 270 - 271 278 272 279 ### 273 280 # Multi client compositor library
+21 -104
src/xrt/compositor/client/comp_d3d11_client.cpp
··· 10 10 11 11 #include "comp_d3d11_client.h" 12 12 13 + #include "comp_d3d_common.hpp" 14 + 13 15 #include "xrt/xrt_compositor.h" 14 16 #include "xrt/xrt_config_os.h" 15 17 #include "xrt/xrt_handles.h" ··· 44 46 45 47 using namespace std::chrono_literals; 46 48 using namespace std::chrono; 49 + 50 + using xrt::compositor::client::unique_swapchain_ref; 47 51 48 52 DEBUG_GET_ONCE_LOG_OPTION(log, "D3D_COMPOSITOR_LOG", U_LOGGING_INFO) 49 53 ··· 85 89 using unique_compositor_semaphore_ref = std::unique_ptr< 86 90 struct xrt_compositor_semaphore, 87 91 xrt::deleters::reference_deleter<struct xrt_compositor_semaphore, xrt_compositor_semaphore_reference>>; 88 - 89 - using unique_swapchain_ref = 90 - std::unique_ptr<struct xrt_swapchain, 91 - xrt::deleters::reference_deleter<struct xrt_swapchain, xrt_swapchain_reference>>; 92 92 93 93 // 0 is special 94 94 static constexpr uint64_t kKeyedMutexKey = 0; ··· 182 182 */ 183 183 struct client_d3d11_swapchain_data 184 184 { 185 + explicit client_d3d11_swapchain_data(enum u_logging_level log_level) : keyed_mutex_collection(log_level) {} 186 + 187 + xrt::compositor::client::KeyedMutexCollection keyed_mutex_collection; 188 + 185 189 //! The shared handles for all our images 186 190 std::vector<wil::unique_handle> handles; 187 191 ··· 190 194 191 195 //! Images associated with client_d3d11_compositor::comp_device 192 196 std::vector<wil::com_ptr<ID3D11Texture2D1>> comp_images; 193 - 194 - //! Keyed mutex per image associated with client_d3d11_compositor::app_device 195 - std::vector<wil::com_ptr<IDXGIKeyedMutex>> app_keyed_mutex_collection; 196 - 197 - std::vector<bool> keyed_mutex_acquired; 198 - 199 - xrt_result_t 200 - waitImage(client_d3d11_swapchain *sc, uint32_t index, uint64_t timeout_ns); 201 - xrt_result_t 202 - releaseImage(client_d3d11_swapchain *sc, uint32_t index); 203 197 }; 204 198 205 199 /*! ··· 267 261 268 262 /* 269 263 * 270 - * Helpers for Swapchain 271 - * 272 - */ 273 - 274 - inline xrt_result_t 275 - client_d3d11_swapchain_data::waitImage(client_d3d11_swapchain *sc, uint32_t index, uint64_t timeout_ns) 276 - { 277 - if (keyed_mutex_acquired[index]) { 278 - 279 - D3D_WARN(sc->c, "Will not acquire the keyed mutex for image %" PRId32 " - it was already acquired!", 280 - index); 281 - return XRT_ERROR_NO_IMAGE_AVAILABLE; 282 - } 283 - 284 - auto hr = app_keyed_mutex_collection[index]->AcquireSync(kKeyedMutexKey, 285 - convertTimeoutToWindowsMilliseconds(timeout_ns)); 286 - if (hr == WAIT_ABANDONED) { 287 - D3D_ERROR(sc->c, 288 - "Could not acquire the keyed mutex for image %" PRId32 289 - " due to it being in an inconsistent state", 290 - index); 291 - return XRT_ERROR_D3D11; 292 - } 293 - if (hr == WAIT_TIMEOUT) { 294 - return XRT_TIMEOUT; 295 - } 296 - if (FAILED(hr)) { 297 - D3D_ERROR(sc->c, "Could not acquire the keyed mutex for image %" PRId32, index); 298 - return XRT_ERROR_D3D11; 299 - } 300 - keyed_mutex_acquired[index] = true; 301 - sc->c->app_context->Flush(); 302 - //! @todo this causes an error in the debug layer 303 - // Discard old contents 304 - // sc->c->app_context->DiscardResource(wil::com_raw_ptr(app_images[index])); 305 - return XRT_SUCCESS; 306 - } 307 - 308 - inline xrt_result_t 309 - client_d3d11_swapchain_data::releaseImage(client_d3d11_swapchain *sc, uint32_t index) 310 - { 311 - if (!keyed_mutex_acquired[index]) { 312 - 313 - D3D_WARN(sc->c, "Will not release the keyed mutex for image %" PRId32 " - it was not acquired!", index); 314 - return XRT_ERROR_D3D11; 315 - } 316 - auto hr = LOG_IF_FAILED(app_keyed_mutex_collection[index]->ReleaseSync(kKeyedMutexKey)); 317 - if (FAILED(hr)) { 318 - D3D_ERROR(sc->c, "Could not release the keyed mutex for image %" PRId32, index); 319 - return XRT_ERROR_D3D11; 320 - } 321 - sc->data->keyed_mutex_acquired[index] = false; 322 - return XRT_SUCCESS; 323 - } 324 - 325 - /* 326 - * 327 264 * Swapchain functions. 328 265 * 329 266 */ ··· 347 284 348 285 if (xret == XRT_SUCCESS) { 349 286 // OK, we got the image in the native compositor, now need the keyed mutex in d3d11. 350 - return sc->data->waitImage(sc, index, timeout_ns); 287 + xret = sc->data->keyed_mutex_collection.waitKeyedMutex(index, timeout_ns); 351 288 } 289 + 290 + //! @todo discard old contents? 352 291 return xret; 353 292 } 354 293 ··· 361 300 xrt_result_t xret = xrt_swapchain_release_image(sc->xsc.get(), index); 362 301 363 302 if (xret == XRT_SUCCESS) { 364 - return sc->data->releaseImage(sc, index); 303 + // Release the keyed mutex 304 + xret = sc->data->keyed_mutex_collection.releaseKeyedMutex(index); 365 305 } 366 306 return xret; 367 307 } ··· 439 379 vkinfo.format = vk_format; 440 380 441 381 std::unique_ptr<struct client_d3d11_swapchain> sc = std::make_unique<struct client_d3d11_swapchain>(); 442 - sc->data = std::make_unique<client_d3d11_swapchain_data>(); 382 + sc->data = std::make_unique<client_d3d11_swapchain_data>(c->log_level); 443 383 auto &data = sc->data; 444 384 xret = xrt::auxiliary::d3d::d3d11::allocateSharedImages(*(c->comp_device), xinfo, image_count, true, 445 385 data->comp_images, data->handles); 446 386 if (xret != XRT_SUCCESS) { 447 387 return xret; 448 388 } 449 - data->keyed_mutex_acquired.resize(image_count); 450 - sc->data->app_keyed_mutex_collection.reserve(image_count); 451 389 data->app_images.reserve(image_count); 452 390 453 391 // Import from the handle for the app. ··· 458 396 // Put the image where the OpenXR state tracker can get it 459 397 sc->base.images[i] = image.get(); 460 398 461 - // Cache the keyed mutex interface too 462 - sc->data->app_keyed_mutex_collection.emplace_back(image.query<IDXGIKeyedMutex>()); 463 - 464 399 // Store the owning pointer for lifetime management 465 400 data->app_images.emplace_back(std::move(image)); 466 401 } 467 402 468 - // Populate for import 469 - std::vector<xrt_image_native> xins; 470 - xins.reserve(data->handles.size()); 471 - // Keep this around until after successful import, then detach all. 472 - std::vector<wil::unique_handle> handlesForImport; 473 - handlesForImport.reserve(data->handles.size()); 474 - 475 - for (const wil::unique_handle &handle : data->handles) { 476 - wil::unique_handle duped{u_graphics_buffer_ref(handle.get())}; 477 - xrt_image_native xin; 478 - xin.handle = duped.get(); 479 - xin.size = 0; 480 - xin.use_dedicated_allocation = false; //! @todo not sure 481 - 482 - handlesForImport.emplace_back(std::move(duped)); 483 - xins.emplace_back(xin); 403 + // Cache the keyed mutex interface 404 + xret = data->keyed_mutex_collection.init(data->app_images); 405 + if (xret != XRT_SUCCESS) { 406 + D3D_ERROR(c, "Error retrieving keyex mutex interfaces"); 407 + return xret; 484 408 } 485 409 486 410 // Import into the native compositor, to create the corresponding swapchain which we wrap. 487 - xrt_swapchain *xsc = nullptr; 488 - xret = xrt_comp_import_swapchain(&(c->xcn->base), &vkinfo, xins.data(), image_count, &xsc); 411 + xret = xrt::compositor::client::importFromHandleDuplicates( 412 + *(c->xcn), data->handles, vkinfo, false /** @todo not sure - dedicated allocation */, sc->xsc); 489 413 if (xret != XRT_SUCCESS) { 490 414 D3D_ERROR(c, "Error importing D3D11 swapchain into native compositor"); 491 415 return xret; 492 416 } 493 - // The imported swapchain took ownership of them now, release them from ownership here. 494 - for (auto &h : handlesForImport) { 495 - h.release(); 496 - } 497 - 498 - // Let unique_ptr manage the lifetime of xsc now 499 - sc->xsc.reset(xsc); 500 417 501 418 sc->base.base.destroy = client_d3d11_swapchain_destroy; 502 419 sc->base.base.acquire_image = client_d3d11_swapchain_acquire_image;
+144
src/xrt/compositor/client/comp_d3d_common.cpp
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief D3D12 client side glue to compositor implementation. 6 + * @author Ryan Pavlik <ryan.pavlik@collabora.com> 7 + * @author Jakob Bornecrantz <jakob@collabora.com> 8 + * @ingroup comp_client 9 + */ 10 + 11 + #include "comp_d3d_common.hpp" 12 + 13 + #include "util/u_logging.h" 14 + #include "util/u_time.h" 15 + 16 + #include <inttypes.h> 17 + 18 + 19 + #define D3D_COMMON_SPEW(log_level, ...) U_LOG_IFL_T(log_level, __VA_ARGS__); 20 + 21 + #define D3D_COMMON_DEBUG(log_level, ...) U_LOG_IFL_D(log_level, __VA_ARGS__); 22 + 23 + #define D3D_COMMON_INFO(log_level, ...) U_LOG_IFL_I(log_level, __VA_ARGS__); 24 + 25 + #define D3D_COMMON_WARN(log_level, ...) U_LOG_IFL_W(log_level, __VA_ARGS__); 26 + 27 + #define D3D_COMMON_ERROR(log_level, ...) U_LOG_IFL_E(log_level, __VA_ARGS__); 28 + 29 + namespace xrt::compositor::client { 30 + 31 + // xrt_result_t 32 + // importFromHandleDuplicates(xrt_compositor_native &xcn, 33 + // std::vector<wil::unique_handle> const &handles, 34 + // const xrt_swapchain_create_info &vkinfo, 35 + // bool use_dedicated_allocation, 36 + // unique_swapchain_ref &out_xsc) 37 + 38 + 39 + static inline DWORD 40 + convertTimeoutToWindowsMilliseconds(uint64_t timeout_ns) 41 + { 42 + return (timeout_ns == XRT_INFINITE_DURATION) ? INFINITE : (DWORD)(timeout_ns / (uint64_t)U_TIME_1MS_IN_NS); 43 + } 44 + 45 + KeyedMutexCollection::KeyedMutexCollection(u_logging_level log_level) noexcept : log_level(log_level) {} 46 + 47 + xrt_result_t 48 + KeyedMutexCollection::init(const std::vector<wil::com_ptr<ID3D11Texture2D1>> &images) noexcept 49 + try { 50 + keyed_mutex_collection.clear(); 51 + keyed_mutex_collection.reserve(images.size()); 52 + for (const auto &image : images) { 53 + keyed_mutex_collection.emplace_back(image.query<IDXGIKeyedMutex>()); 54 + } 55 + 56 + keyed_mutex_acquired.clear(); 57 + keyed_mutex_acquired.resize(keyed_mutex_collection.size()); 58 + return XRT_SUCCESS; 59 + } catch (wil::ResultException const &e) { 60 + U_LOG_E("Error getting keyed mutex collection for swapchain: %s", e.what()); 61 + return XRT_ERROR_D3D; 62 + } catch (std::exception const &e) { 63 + U_LOG_E("Error getting keyed mutex collection for swapchain: %s", e.what()); 64 + return XRT_ERROR_D3D; 65 + } catch (...) { 66 + U_LOG_E("Error getting keyed mutex collection for swapchain"); 67 + return XRT_ERROR_D3D; 68 + } 69 + 70 + xrt_result_t 71 + KeyedMutexCollection::waitKeyedMutex(uint32_t index, uint64_t timeout_ns) noexcept 72 + 73 + try { 74 + 75 + if (keyed_mutex_acquired[index]) { 76 + 77 + D3D_COMMON_WARN(log_level, 78 + "Will not acquire the keyed mutex for image %" PRId32 " - it was already acquired!", 79 + index); 80 + return XRT_ERROR_NO_IMAGE_AVAILABLE; 81 + } 82 + 83 + auto hr = 84 + keyed_mutex_collection[index]->AcquireSync(kKeyedMutexKey, convertTimeoutToWindowsMilliseconds(timeout_ns)); 85 + if (hr == WAIT_ABANDONED) { 86 + D3D_COMMON_ERROR(log_level, 87 + "Could not acquire the keyed mutex for image %" PRId32 88 + " due to it being in an inconsistent state", 89 + index); 90 + return XRT_ERROR_D3D; 91 + } 92 + if (hr == WAIT_TIMEOUT) { 93 + return XRT_TIMEOUT; 94 + } 95 + if (FAILED(hr)) { 96 + D3D_COMMON_ERROR(log_level, "Could not acquire the keyed mutex for image %" PRId32, index); 97 + return XRT_ERROR_D3D; 98 + } 99 + keyed_mutex_acquired[index] = true; 100 + return XRT_SUCCESS; 101 + } catch (wil::ResultException const &e) { 102 + U_LOG_E("Error acquiring keyed mutex for image %" PRId32 ": %s", index, e.what()); 103 + return XRT_ERROR_D3D; 104 + } catch (std::exception const &e) { 105 + U_LOG_E("Error acquiring keyed mutex for image %" PRId32 ": %s", index, e.what()); 106 + return XRT_ERROR_D3D; 107 + } catch (...) { 108 + U_LOG_E("Error acquiring keyed mutex for image %" PRId32, index); 109 + return XRT_ERROR_D3D; 110 + } 111 + 112 + 113 + xrt_result_t 114 + KeyedMutexCollection::releaseKeyedMutex(uint32_t index) noexcept 115 + 116 + try { 117 + 118 + if (!keyed_mutex_acquired[index]) { 119 + 120 + D3D_COMMON_WARN(log_level, 121 + "Will not release the keyed mutex for image %" PRId32 " - it was not acquired!", index); 122 + return XRT_ERROR_D3D; 123 + } 124 + auto hr = LOG_IF_FAILED(keyed_mutex_collection[index]->ReleaseSync(kKeyedMutexKey)); 125 + if (FAILED(hr)) { 126 + D3D_COMMON_ERROR(log_level, "Could not release the keyed mutex for image %" PRId32, index); 127 + return XRT_ERROR_D3D; 128 + } 129 + keyed_mutex_acquired[index] = false; 130 + return XRT_SUCCESS; 131 + 132 + } catch (wil::ResultException const &e) { 133 + U_LOG_E("Error releasing keyed mutex %" PRId32 ": %s", index, e.what()); 134 + return XRT_ERROR_D3D; 135 + } catch (std::exception const &e) { 136 + U_LOG_E("Error releasing keyed mutex %" PRId32 ": %s", index, e.what()); 137 + return XRT_ERROR_D3D; 138 + } catch (...) { 139 + U_LOG_E("Error releasing keyed mutex %" PRId32, index); 140 + return XRT_ERROR_D3D; 141 + } 142 + 143 + 144 + } // namespace xrt::compositor::client
+144
src/xrt/compositor/client/comp_d3d_common.hpp
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Functionality common to D3D11 and D3D12 for client side compositor implementation. 6 + * @author Ryan Pavlik <ryan.pavlik@collabora.com> 7 + * @author Jakob Bornecrantz <jakob@collabora.com> 8 + * @ingroup comp_client 9 + */ 10 + #pragma once 11 + 12 + #include "xrt/xrt_compositor.h" 13 + #include "xrt/xrt_deleters.hpp" 14 + #include "xrt/xrt_results.h" 15 + 16 + #include "util/u_handles.h" 17 + #include "util/u_logging.h" 18 + 19 + #include <wil/com.h> 20 + #include <wil/resource.h> 21 + #include <wil/result_macros.h> 22 + 23 + #include <d3d11_3.h> 24 + 25 + #include <memory> 26 + #include <vector> 27 + #include <stdint.h> 28 + 29 + 30 + namespace xrt::compositor::client { 31 + 32 + using unique_swapchain_ref = 33 + std::unique_ptr<struct xrt_swapchain, 34 + xrt::deleters::reference_deleter<struct xrt_swapchain, xrt_swapchain_reference>>; 35 + 36 + /** 37 + * Import the provided handles into a native compositor, without consuming them. 38 + * 39 + * @param c The native compositor 40 + * @param handles A vector of uniquely-owned handles. These will be duplicated, not consumed, by this import. 41 + * @param vkinfo The swapchain create info, with format as a Vulkan constant 42 + * @param use_dedicated_allocation Passed through to @ref xrt_image_native 43 + * @param[out] out_xsc The swapchain to populate 44 + * @return XRT_SUCCESS if everything went well, otherwise whatever error a call internally returned. 45 + */ 46 + static inline xrt_result_t 47 + importFromHandleDuplicates(xrt_compositor_native &xcn, 48 + std::vector<wil::unique_handle> const &handles, 49 + const struct xrt_swapchain_create_info &vkinfo, 50 + bool use_dedicated_allocation, 51 + unique_swapchain_ref &out_xsc) 52 + { 53 + uint32_t image_count = static_cast<uint32_t>(handles.size()); 54 + // Populate for import 55 + std::vector<xrt_image_native> xins; 56 + xins.reserve(image_count); 57 + 58 + // Keep this around until after successful import, then detach all. 59 + std::vector<wil::unique_handle> handlesForImport; 60 + handlesForImport.reserve(image_count); 61 + 62 + for (const wil::unique_handle &handle : handles) { 63 + wil::unique_handle duped{u_graphics_buffer_ref(handle.get())}; 64 + xrt_image_native xin; 65 + xin.handle = duped.get(); 66 + xin.size = 0; 67 + xin.use_dedicated_allocation = use_dedicated_allocation; 68 + 69 + handlesForImport.emplace_back(std::move(duped)); 70 + xins.emplace_back(xin); 71 + } 72 + 73 + // Import into the native compositor, to create the corresponding swapchain which we wrap. 74 + xrt_swapchain *xsc = nullptr; 75 + xrt_result_t xret = xrt_comp_import_swapchain(&(xcn.base), &vkinfo, xins.data(), image_count, &xsc); 76 + if (xret != XRT_SUCCESS) { 77 + return xret; 78 + } 79 + // Let unique_ptr manage the lifetime of xsc now 80 + out_xsc.reset(xsc); 81 + 82 + // The imported swapchain took ownership of them now, release them from ownership here. 83 + for (auto &h : handlesForImport) { 84 + h.release(); 85 + } 86 + return XRT_SUCCESS; 87 + } 88 + 89 + /** 90 + * A collection of DXGIKeyedMutex objects, one for each swapchain image in a swapchain. 91 + * 92 + */ 93 + class KeyedMutexCollection 94 + { 95 + public: 96 + // 0 is special 97 + static constexpr uint64_t kKeyedMutexKey = 0; 98 + 99 + /** 100 + * @brief Construct a new Keyed Mutex Collection object 101 + * 102 + * @param log_level The compositor log level to use 103 + */ 104 + explicit KeyedMutexCollection(u_logging_level log_level) noexcept; 105 + 106 + /** 107 + * Take the keyed mutex vector before starting to use the images. 108 + * 109 + * @param keyedMutexVector Your vector of objects to move from 110 + */ 111 + xrt_result_t 112 + init(const std::vector<wil::com_ptr<ID3D11Texture2D1>> &images) noexcept; 113 + 114 + /** 115 + * Wait for acquisition of the keyed mutex. 116 + * 117 + * @param index Swapchain image index 118 + * @param timeout_ns Timeout in nanoseconds or XRT_INFINITE_DURATION 119 + * @return xrt_result_t: XRT_SUCCESS, XRT_TIMEOUT, or some error 120 + */ 121 + xrt_result_t 122 + waitKeyedMutex(uint32_t index, uint64_t timeout_ns) noexcept; 123 + 124 + /** 125 + * Release the keyed mutex 126 + * 127 + * @param index Swapchain image index 128 + * @return xrt_result_t 129 + */ 130 + xrt_result_t 131 + releaseKeyedMutex(uint32_t index) noexcept; 132 + 133 + private: 134 + //! Keyed mutex per image associated with client_d3d11_compositor::app_device 135 + std::vector<wil::com_ptr<IDXGIKeyedMutex>> keyed_mutex_collection; 136 + 137 + std::vector<bool> keyed_mutex_acquired; 138 + 139 + //! Logging level. 140 + u_logging_level log_level; 141 + }; 142 + 143 + 144 + } // namespace xrt::compositor::client