The open source OpenXR runtime
at prediction-2 236 lines 9.2 kB view raw
1// Copyright 2020-2024, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief D3D12 backed image buffer allocator. 6 * @author Rylie Pavlik <rylie.pavlik@collabora.com> 7 * @author Fernando Velazquez Innella <finnella@magicleap.com> 8 * @author Korcan Hussein <korcan.hussein@collabora.com> 9 * @ingroup aux_d3d 10 */ 11 12#include "d3d_d3d12_allocator.h" 13#include "d3d_d3d12_allocator.hpp" 14 15#include "d3d_d3d12_bits.h" 16#include "d3d_dxgi_formats.h" 17 18#include "util/u_misc.h" 19#include "util/u_logging.h" 20#include "util/u_debug.h" 21#include "util/u_handles.h" 22 23#include "xrt/xrt_windows.h" 24 25#include <Unknwn.h> 26#include <d3d12.h> 27#include <wil/com.h> 28#include <wil/result.h> 29 30#include <memory> 31 32#define DEFAULT_CATCH(...) \ 33 catch (wil::ResultException const &e) \ 34 { \ 35 U_LOG_E("Caught exception: %s", e.what()); \ 36 return __VA_ARGS__; \ 37 } \ 38 catch (std::exception const &e) \ 39 { \ 40 U_LOG_E("Caught exception: %s", e.what()); \ 41 return __VA_ARGS__; \ 42 } \ 43 catch (...) \ 44 { \ 45 U_LOG_E("Caught exception"); \ 46 return __VA_ARGS__; \ 47 } 48 49 50DEBUG_GET_ONCE_LOG_OPTION(d3d12_log, "D3D12_LOG", U_LOGGING_WARN) 51#define D3DA_TRACE(...) U_LOG_IFL_T(debug_get_log_option_d3d12_log(), __VA_ARGS__) 52#define D3DA_DEBUG(...) U_LOG_IFL_D(debug_get_log_option_d3d12_log(), __VA_ARGS__) 53#define D3DA_INFO(...) U_LOG_IFL_I(debug_get_log_option_d3d12_log(), __VA_ARGS__) 54#define D3DA_WARN(...) U_LOG_IFL_W(debug_get_log_option_d3d12_log(), __VA_ARGS__) 55#define D3DA_ERROR(...) U_LOG_IFL_E(debug_get_log_option_d3d12_log(), __VA_ARGS__) 56 57namespace xrt::auxiliary::d3d::d3d12 { 58 59static wil::unique_handle 60createSharedHandle(ID3D12Device &device, const wil::com_ptr<ID3D12Resource> &image) 61{ 62 wil::unique_handle h; 63 THROW_IF_FAILED(device.CreateSharedHandle( // 64 image.get(), // pObject 65 nullptr, // pAttributes 66 GENERIC_ALL, // Access 67 nullptr, // Name 68 h.put())); // pHandle 69 return h; 70} 71 72 73xrt_result_t 74allocateSharedImages(ID3D12Device &device, 75 const xrt_swapchain_create_info &xsci, 76 size_t image_count, 77 std::vector<wil::com_ptr<ID3D12Resource>> &out_images, 78 std::vector<wil::unique_handle> &out_handles, 79 std::uint64_t &out_image_mem_size) 80try { 81 if (0 != (xsci.create & XRT_SWAPCHAIN_CREATE_PROTECTED_CONTENT)) { 82 return XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED; 83 } 84 85 if (0 != (xsci.create & XRT_SWAPCHAIN_CREATE_STATIC_IMAGE) && image_count > 1) { 86 D3DA_ERROR("Got XRT_SWAPCHAIN_CREATE_STATIC_IMAGE but an image count greater than 1!"); 87 return XRT_ERROR_ALLOCATION; 88 } 89 if (xsci.array_size == 0) { 90 D3DA_ERROR("Array size must not be 0"); 91 return XRT_ERROR_ALLOCATION; 92 } 93 94 // TODO: See if this is still necessary 95 DXGI_FORMAT typeless_format = d3d_dxgi_format_to_typeless_dxgi((DXGI_FORMAT)xsci.format); 96 if (typeless_format == 0) { 97 D3DA_ERROR("Invalid format %04" PRIx64 "!", (uint64_t)xsci.format); 98 return XRT_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED; 99 } 100 101 DXGI_SAMPLE_DESC sample_desc{ 102 xsci.sample_count, // Count 103 0, // Quality 104 }; 105 106 // Note: 107 // To use a cross-adapter heap the following flag must be passed: 108 // resource_flags |= D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER; 109 // Additionally, only copy operations are allowed with the resource. 110 D3D12_RESOURCE_FLAGS resource_flags = d3d_convert_usage_bits_to_d3d12_resource_flags(xsci.bits); 111 112 D3D12_RESOURCE_DESC desc{ 113 D3D12_RESOURCE_DIMENSION_TEXTURE2D, // Dimension 114 0, // Alignment 115 xsci.width, // Width 116 xsci.height, // Height 117 (UINT16)xsci.array_size, // DepthOrArraySize 118 (UINT16)xsci.mip_count, // MipLevels 119 typeless_format, // Format 120 sample_desc, // SampleDesc 121 D3D12_TEXTURE_LAYOUT_UNKNOWN, // Layout 122 resource_flags // Flags; 123 }; 124 125 // Cubemap 126 if (xsci.face_count == 6) { 127 desc.DepthOrArraySize *= 6; 128 } 129 130 // Create resources and let the driver manage memory 131 std::vector<wil::com_ptr<ID3D12Resource>> images; 132 D3D12_HEAP_PROPERTIES heap{}; 133 heap.Type = D3D12_HEAP_TYPE_DEFAULT; 134 D3D12_HEAP_FLAGS heap_flags = D3D12_HEAP_FLAG_SHARED; 135 D3D12_RESOURCE_STATES initial_resource_state = d3d_convert_usage_bits_to_d3d12_app_resource_state(xsci.bits); 136 137 for (size_t i = 0; i < image_count; ++i) { 138 wil::com_ptr<ID3D12Resource> tex; 139 HRESULT res = device.CreateCommittedResource( // 140 &heap, // pHeapProperties 141 heap_flags, // HeapFlags 142 &desc, // pDesc 143 initial_resource_state, // InitialResourceState 144 nullptr, // pOptimizedClearValue 145 IID_PPV_ARGS(tex.put())); // riidResource, ppvResource 146 147 if (FAILED(LOG_IF_FAILED(res))) { 148 return XRT_ERROR_ALLOCATION; 149 } 150 images.emplace_back(std::move(tex)); 151 } 152 153 std::vector<wil::unique_handle> handles; 154 handles.reserve(image_count); 155 for (const auto &tex : images) { 156 handles.emplace_back(createSharedHandle(device, tex)); 157 } 158 out_images = std::move(images); 159 out_handles = std::move(handles); 160 const D3D12_RESOURCE_ALLOCATION_INFO alloc_info = device.GetResourceAllocationInfo(0, 1, &desc); 161 out_image_mem_size = alloc_info.SizeInBytes; 162 return XRT_SUCCESS; 163} 164DEFAULT_CATCH(XRT_ERROR_ALLOCATION) 165 166} // namespace xrt::auxiliary::d3d::d3d12 167 168struct d3d12_allocator 169{ 170 struct xrt_image_native_allocator base; 171 wil::com_ptr<ID3D12Device> device; 172}; 173 174 175static xrt_result_t 176d3d12_images_allocate(struct xrt_image_native_allocator *xina, 177 const struct xrt_swapchain_create_info *xsci, 178 size_t image_count, 179 struct xrt_image_native *out_images) 180{ 181 try { 182 d3d12_allocator *d3da = reinterpret_cast<d3d12_allocator *>(xina); 183 184 std::uint64_t image_mem_size = 0; 185 std::vector<wil::com_ptr<ID3D12Resource>> images; 186 std::vector<wil::unique_handle> handles; 187 auto result = xrt::auxiliary::d3d::d3d12::allocateSharedImages( // 188 *(d3da->device), // device 189 *xsci, // xsci 190 image_count, // image_count 191 images, // out_images 192 handles, // out_handles 193 image_mem_size); // out_image_mem_size (in bytes) 194 195 if (result != XRT_SUCCESS) { 196 return result; 197 } 198 199 for (size_t i = 0; i < image_count; ++i) { 200 out_images[i].handle = handles[i].release(); 201 out_images[i].is_dxgi_handle = false; 202 out_images[i].size = image_mem_size; 203 } 204 205 return XRT_SUCCESS; 206 } 207 DEFAULT_CATCH(XRT_ERROR_ALLOCATION) 208} 209 210static xrt_result_t 211d3d12_images_free(struct xrt_image_native_allocator *xina, size_t image_count, struct xrt_image_native *images) 212{ 213 for (size_t i = 0; i < image_count; ++i) { 214 u_graphics_buffer_unref(&(images[i].handle)); 215 } 216 return XRT_SUCCESS; 217} 218 219static void 220d3d12_destroy(struct xrt_image_native_allocator *xina) 221{ 222 d3d12_allocator *d3da = reinterpret_cast<d3d12_allocator *>(xina); 223 delete d3da; 224} 225 226struct xrt_image_native_allocator * 227d3d12_allocator_create(ID3D11Device *device) 228try { 229 auto ret = std::make_unique<d3d12_allocator>(); 230 U_ZERO(&(ret->base)); 231 ret->base.images_allocate = d3d12_images_allocate; 232 ret->base.images_free = d3d12_images_free; 233 ret->base.destroy = d3d12_destroy; 234 return &(ret.release()->base); 235} 236DEFAULT_CATCH(nullptr)