The open source OpenXR runtime
at prediction-2 194 lines 7.1 kB view raw
1// Copyright 2020-2022, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief D3D11 backed image buffer allocator. 6 * @author Rylie Pavlik <rylie.pavlik@collabora.com> 7 * @author Fernando Velazquez Innella <finnella@magicleap.com> 8 * @ingroup aux_d3d 9 */ 10 11#include "d3d_d3d11_allocator.h" 12#include "d3d_d3d11_allocator.hpp" 13 14#include "d3d_d3d11_bits.h" 15#include "d3d_dxgi_formats.h" 16 17#include "util/u_misc.h" 18#include "util/u_logging.h" 19#include "util/u_debug.h" 20#include "util/u_handles.h" 21 22#include "xrt/xrt_windows.h" 23 24#include <Unknwn.h> 25#include <d3d11_3.h> 26#include <wil/com.h> 27#include <wil/result.h> 28 29#include <memory> 30 31#define DEFAULT_CATCH(...) \ 32 catch (wil::ResultException const &e) \ 33 { \ 34 U_LOG_E("Caught exception: %s", e.what()); \ 35 return __VA_ARGS__; \ 36 } \ 37 catch (std::exception const &e) \ 38 { \ 39 U_LOG_E("Caught exception: %s", e.what()); \ 40 return __VA_ARGS__; \ 41 } \ 42 catch (...) \ 43 { \ 44 U_LOG_E("Caught exception"); \ 45 return __VA_ARGS__; \ 46 } 47 48 49DEBUG_GET_ONCE_LOG_OPTION(d3d11_log, "DXGI_LOG", U_LOGGING_WARN) 50#define D3DA_TRACE(...) U_LOG_IFL_T(debug_get_log_option_d3d11_log(), __VA_ARGS__) 51#define D3DA_DEBUG(...) U_LOG_IFL_D(debug_get_log_option_d3d11_log(), __VA_ARGS__) 52#define D3DA_INFO(...) U_LOG_IFL_I(debug_get_log_option_d3d11_log(), __VA_ARGS__) 53#define D3DA_WARN(...) U_LOG_IFL_W(debug_get_log_option_d3d11_log(), __VA_ARGS__) 54#define D3DA_ERROR(...) U_LOG_IFL_E(debug_get_log_option_d3d11_log(), __VA_ARGS__) 55 56namespace xrt::auxiliary::d3d::d3d11 { 57 58HANDLE 59getSharedHandle(const wil::com_ptr<ID3D11Texture2D1> &image) 60{ 61 wil::com_ptr<IDXGIResource1> dxgiRes; 62 HANDLE h; 63 image.query_to(dxgiRes.put()); 64 THROW_IF_FAILED(dxgiRes->GetSharedHandle(&h)); 65 return h; 66} 67 68xrt_result_t 69allocateSharedImages(ID3D11Device5 &device, 70 const xrt_swapchain_create_info &xsci, 71 size_t image_count, 72 bool keyed_mutex, 73 std::vector<wil::com_ptr<ID3D11Texture2D1>> &out_images, 74 std::vector<HANDLE> &out_handles) 75try { 76 if (0 != (xsci.create & XRT_SWAPCHAIN_CREATE_PROTECTED_CONTENT)) { 77 return XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED; 78 } 79 80 if (0 != (xsci.create & XRT_SWAPCHAIN_CREATE_STATIC_IMAGE) && image_count > 1) { 81 D3DA_ERROR("Got XRT_SWAPCHAIN_CREATE_STATIC_IMAGE but an image count greater than 1!"); 82 return XRT_ERROR_ALLOCATION; 83 } 84 if (xsci.array_size == 0) { 85 D3DA_ERROR("Array size must not be 0"); 86 return XRT_ERROR_ALLOCATION; 87 } 88 CD3D11_TEXTURE2D_DESC1 desc{d3d_dxgi_format_to_typeless_dxgi((DXGI_FORMAT)xsci.format), 89 xsci.width, 90 xsci.height, 91 xsci.array_size, 92 xsci.mip_count, 93 d3d_convert_usage_bits_to_d3d11_bind_flags(xsci.bits)}; 94 desc.SampleDesc.Count = xsci.sample_count; 95 96 // Using NT handles for sharing textures has a lot of limitations and issues. 97 // Depth formats are not supported and Vulkan may fail at vkAllocateMemory 98 desc.MiscFlags = keyed_mutex ? D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX : D3D11_RESOURCE_MISC_SHARED; 99 100 if (desc.Format == 0) { 101 D3DA_ERROR("Invalid format %04" PRIx64 "!", (uint64_t)xsci.format); 102 return XRT_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED; 103 } 104 if (xsci.face_count == 6) { 105 desc.ArraySize *= 6; 106 desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; 107 } 108 // Create textures 109 std::vector<wil::com_ptr<ID3D11Texture2D1>> images; 110 for (size_t i = 0; i < image_count; ++i) { 111 wil::com_ptr<ID3D11Texture2D1> tex; 112 if (FAILED(LOG_IF_FAILED(device.CreateTexture2D1(&desc, nullptr, tex.put())))) { 113 return XRT_ERROR_ALLOCATION; 114 } 115 images.emplace_back(std::move(tex)); 116 } 117 118 std::vector<HANDLE> handles; 119 handles.reserve(image_count); 120 for (const auto &tex : images) { 121 handles.emplace_back(getSharedHandle(tex)); 122 } 123 out_images = std::move(images); 124 out_handles = std::move(handles); 125 return XRT_SUCCESS; 126} 127DEFAULT_CATCH(XRT_ERROR_ALLOCATION) 128 129} // namespace xrt::auxiliary::d3d::d3d11 130 131struct d3d11_allocator 132{ 133 struct xrt_image_native_allocator base; 134 wil::com_ptr<ID3D11Device5> device; 135}; 136 137 138static xrt_result_t 139d3d11_images_allocate(struct xrt_image_native_allocator *xina, 140 const struct xrt_swapchain_create_info *xsci, 141 size_t image_count, 142 struct xrt_image_native *out_images) 143{ 144 try { 145 d3d11_allocator *d3da = reinterpret_cast<d3d11_allocator *>(xina); 146 147 std::vector<wil::com_ptr<ID3D11Texture2D1>> images; 148 std::vector<HANDLE> handles; 149 auto result = xrt::auxiliary::d3d::d3d11::allocateSharedImages(*(d3da->device), *xsci, image_count, 150 false, images, handles); 151 152 if (result != XRT_SUCCESS) { 153 return result; 154 } 155 156 for (size_t i = 0; i < image_count; ++i) { 157 out_images[i].handle = handles[i]; 158 out_images[i].is_dxgi_handle = true; 159 } 160 161 return XRT_SUCCESS; 162 } 163 DEFAULT_CATCH(XRT_ERROR_ALLOCATION) 164} 165 166static xrt_result_t 167d3d11_images_free(struct xrt_image_native_allocator *xina, size_t image_count, struct xrt_image_native *images) 168{ 169 for (size_t i = 0; i < image_count; ++i) { 170 if (!images[i].is_dxgi_handle) { 171 u_graphics_buffer_unref(&(images[i].handle)); 172 } 173 } 174 return XRT_SUCCESS; 175} 176 177static void 178d3d11_destroy(struct xrt_image_native_allocator *xina) 179{ 180 d3d11_allocator *d3da = reinterpret_cast<d3d11_allocator *>(xina); 181 delete d3da; 182} 183 184struct xrt_image_native_allocator * 185d3d11_allocator_create(ID3D11Device *device) 186try { 187 auto ret = std::make_unique<d3d11_allocator>(); 188 U_ZERO(&(ret->base)); 189 ret->base.images_allocate = d3d11_images_allocate; 190 ret->base.images_free = d3d11_images_free; 191 ret->base.destroy = d3d11_destroy; 192 return &(ret.release()->base); 193} 194DEFAULT_CATCH(nullptr)