diff --git a/Source/Core/VideoBackends/D3D12/D3D12BoundingBox.cpp b/Source/Core/VideoBackends/D3D12/D3D12BoundingBox.cpp index 0713edb80b..75b3f6064a 100644 --- a/Source/Core/VideoBackends/D3D12/D3D12BoundingBox.cpp +++ b/Source/Core/VideoBackends/D3D12/D3D12BoundingBox.cpp @@ -42,7 +42,7 @@ std::vector D3D12BoundingBox::Read(u32 index, u32 length) static constexpr D3D12_RANGE read_range = {0, BUFFER_SIZE}; void* mapped_pointer; HRESULT hr = m_readback_buffer->Map(0, &read_range, &mapped_pointer); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Map bounding box CPU buffer failed"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Map bounding box CPU buffer failed: {}", DX12HRWrap(hr)); if (FAILED(hr)) return values; @@ -103,7 +103,7 @@ bool D3D12BoundingBox::CreateBuffers() HRESULT hr = g_dx_context->GetDevice()->CreateCommittedResource( &gpu_heap_properties, D3D12_HEAP_FLAG_NONE, &buffer_desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, IID_PPV_ARGS(&m_gpu_buffer)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating bounding box GPU buffer failed"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating bounding box GPU buffer failed: {}", DX12HRWrap(hr)); if (FAILED(hr) || !g_dx_context->GetDescriptorHeapManager().Allocate(&m_gpu_descriptor)) return false; @@ -116,7 +116,7 @@ bool D3D12BoundingBox::CreateBuffers() hr = g_dx_context->GetDevice()->CreateCommittedResource( &cpu_heap_properties, D3D12_HEAP_FLAG_NONE, &buffer_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_readback_buffer)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating bounding box CPU buffer failed"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating bounding box CPU buffer failed: {}", DX12HRWrap(hr)); if (FAILED(hr)) return false; diff --git a/Source/Core/VideoBackends/D3D12/D3D12PerfQuery.cpp b/Source/Core/VideoBackends/D3D12/D3D12PerfQuery.cpp index c7e5acac7f..9b69a70ca2 100644 --- a/Source/Core/VideoBackends/D3D12/D3D12PerfQuery.cpp +++ b/Source/Core/VideoBackends/D3D12/D3D12PerfQuery.cpp @@ -23,7 +23,7 @@ bool PerfQuery::Initialize() { constexpr D3D12_QUERY_HEAP_DESC desc = {D3D12_QUERY_HEAP_TYPE_OCCLUSION, PERF_QUERY_BUFFER_SIZE}; HRESULT hr = g_dx_context->GetDevice()->CreateQueryHeap(&desc, IID_PPV_ARGS(&m_query_heap)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create query heap"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create query heap: {}", DX12HRWrap(hr)); if (FAILED(hr)) return false; @@ -41,7 +41,7 @@ bool PerfQuery::Initialize() hr = g_dx_context->GetDevice()->CreateCommittedResource( &heap_properties, D3D12_HEAP_FLAG_NONE, &resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_query_readback_buffer)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create query buffer"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create query buffer: {}", DX12HRWrap(hr)); if (FAILED(hr)) return false; @@ -221,7 +221,7 @@ void PerfQuery::AccumulateQueriesFromBuffer(u32 query_count) (m_query_readback_pos + query_count) * sizeof(PerfQueryDataType)}; u8* mapped_ptr; HRESULT hr = m_query_readback_buffer->Map(0, &read_range, reinterpret_cast(&mapped_ptr)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to map query readback buffer"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to map query readback buffer: {}", DX12HRWrap(hr)); if (FAILED(hr)) return; diff --git a/Source/Core/VideoBackends/D3D12/D3D12StreamBuffer.cpp b/Source/Core/VideoBackends/D3D12/D3D12StreamBuffer.cpp index a5d28d62e9..9e55cebc46 100644 --- a/Source/Core/VideoBackends/D3D12/D3D12StreamBuffer.cpp +++ b/Source/Core/VideoBackends/D3D12/D3D12StreamBuffer.cpp @@ -46,13 +46,14 @@ bool StreamBuffer::AllocateBuffer(u32 size) HRESULT hr = g_dx_context->GetDevice()->CreateCommittedResource( &heap_properties, D3D12_HEAP_FLAG_NONE, &resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_buffer)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to allocate buffer of size {}", size); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to allocate buffer of size {}: {}", size, + DX12HRWrap(hr)); if (FAILED(hr)) return false; static const D3D12_RANGE read_range = {}; hr = m_buffer->Map(0, &read_range, reinterpret_cast(&m_host_pointer)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to map buffer of size {}", size); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to map buffer of size {}: {}", size, DX12HRWrap(hr)); if (FAILED(hr)) return false; diff --git a/Source/Core/VideoBackends/D3D12/D3D12SwapChain.cpp b/Source/Core/VideoBackends/D3D12/D3D12SwapChain.cpp index 45ba0be22e..5ebc8c7d74 100644 --- a/Source/Core/VideoBackends/D3D12/D3D12SwapChain.cpp +++ b/Source/Core/VideoBackends/D3D12/D3D12SwapChain.cpp @@ -34,7 +34,7 @@ bool SwapChain::CreateSwapChainBuffers() { ComPtr resource; HRESULT hr = m_swap_chain->GetBuffer(i, IID_PPV_ARGS(&resource)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to get swap chain buffer {}", i); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to get swap chain buffer {}: {}", i, DX12HRWrap(hr)); BufferResources buffer; buffer.texture = DXTexture::CreateAdopted(resource.Get()); diff --git a/Source/Core/VideoBackends/D3D12/DX12Context.cpp b/Source/Core/VideoBackends/D3D12/DX12Context.cpp index b74785a059..cc6fb72adc 100644 --- a/Source/Core/VideoBackends/D3D12/DX12Context.cpp +++ b/Source/Core/VideoBackends/D3D12/DX12Context.cpp @@ -152,7 +152,7 @@ bool DXContext::CreateDevice(u32 adapter_index, bool enable_debug_layer) HRESULT hr = m_dxgi_factory->EnumAdapters(adapter_index, &adapter); if (FAILED(hr)) { - ERROR_LOG_FMT(VIDEO, "Adapter {} not found, using default", adapter_index); + ERROR_LOG_FMT(VIDEO, "Adapter {} not found, using default: {}", adapter_index, DX12HRWrap(hr)); adapter = nullptr; } @@ -166,14 +166,14 @@ bool DXContext::CreateDevice(u32 adapter_index, bool enable_debug_layer) } else { - ERROR_LOG_FMT(VIDEO, "Debug layer requested but not available."); + ERROR_LOG_FMT(VIDEO, "Debug layer requested but not available: {}", DX12HRWrap(hr)); enable_debug_layer = false; } } // Create the actual device. hr = s_d3d12_create_device(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create D3D12 device"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create D3D12 device: {}", DX12HRWrap(hr)); if (FAILED(hr)) return false; @@ -208,7 +208,7 @@ bool DXContext::CreateCommandQueue() D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, D3D12_COMMAND_QUEUE_FLAG_NONE}; HRESULT hr = m_device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&m_command_queue)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create command queue"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create command queue: {}", DX12HRWrap(hr)); return SUCCEEDED(hr); } @@ -216,7 +216,7 @@ bool DXContext::CreateFence() { HRESULT hr = m_device->CreateFence(m_completed_fence_value, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create fence"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create fence: {}", DX12HRWrap(hr)); if (FAILED(hr)) return false; @@ -303,14 +303,15 @@ static bool BuildRootSignature(ID3D12Device* device, ID3D12RootSignature** sig_p &root_signature_blob, &root_signature_error_blob); if (FAILED(hr)) { - PanicAlertFmt("Failed to serialize root signature: {}", - static_cast(root_signature_error_blob->GetBufferPointer())); + PanicAlertFmt("Failed to serialize root signature: {}\n{}", + static_cast(root_signature_error_blob->GetBufferPointer()), + DX12HRWrap(hr)); return false; } hr = device->CreateRootSignature(0, root_signature_blob->GetBufferPointer(), root_signature_blob->GetBufferSize(), IID_PPV_ARGS(sig_ptr)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create root signature"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create root signature: {}", DX12HRWrap(hr)); return true; } @@ -417,13 +418,13 @@ bool DXContext::CreateCommandLists() CommandListResources& res = m_command_lists[i]; HRESULT hr = m_device->CreateCommandAllocator( D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(res.command_allocator.GetAddressOf())); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create command allocator"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create command allocator: {}", DX12HRWrap(hr)); if (FAILED(hr)) return false; hr = m_device->CreateCommandList(1, D3D12_COMMAND_LIST_TYPE_DIRECT, res.command_allocator.Get(), nullptr, IID_PPV_ARGS(res.command_list.GetAddressOf())); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create command list"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create command list: {}", DX12HRWrap(hr)); if (FAILED(hr)) { return false; @@ -431,7 +432,7 @@ bool DXContext::CreateCommandLists() // Close the command list, since the first thing we do is reset them. hr = res.command_list->Close(); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Closing new command list failed"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Closing new command list failed: {}", DX12HRWrap(hr)); if (FAILED(hr)) return false; @@ -473,7 +474,7 @@ void DXContext::ExecuteCommandList(bool wait_for_completion) // Close and queue command list. HRESULT hr = res.command_list->Close(); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to close command list"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to close command list: {}", DX12HRWrap(hr)); const std::array execute_lists{res.command_list.Get()}; m_command_queue->ExecuteCommandLists(static_cast(execute_lists.size()), execute_lists.data()); @@ -481,7 +482,7 @@ void DXContext::ExecuteCommandList(bool wait_for_completion) // Update fence when GPU has completed. hr = m_command_queue->Signal(m_fence.Get(), m_current_fence_value); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to signal fence"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to signal fence: {}", DX12HRWrap(hr)); MoveToNextCommandList(); if (wait_for_completion) @@ -534,7 +535,7 @@ void DXContext::WaitForFence(u64 fence) { // Fall back to event. HRESULT hr = m_fence->SetEventOnCompletion(fence, m_fence_event); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to set fence event on completion"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to set fence event on completion: {}", DX12HRWrap(hr)); WaitForSingleObject(m_fence_event, INFINITE); m_completed_fence_value = m_fence->GetCompletedValue(); } diff --git a/Source/Core/VideoBackends/D3D12/DX12Context.h b/Source/Core/VideoBackends/D3D12/DX12Context.h index f1f41c953b..1528f436c3 100644 --- a/Source/Core/VideoBackends/D3D12/DX12Context.h +++ b/Source/Core/VideoBackends/D3D12/DX12Context.h @@ -7,6 +7,8 @@ #include #include "Common/CommonTypes.h" +#include "Common/HRWrap.h" + #include "VideoBackends/D3D12/Common.h" #include "VideoBackends/D3D12/D3D12StreamBuffer.h" #include "VideoBackends/D3D12/DescriptorAllocator.h" @@ -187,4 +189,34 @@ private: extern std::unique_ptr g_dx_context; +// Wrapper for HRESULT to be used with fmt. Note that we can't create a fmt::formatter directly +// for HRESULT as HRESULT is simply a typedef on long and not a distinct type. +// Unlike the version in Common, this variant also knows to call GetDeviceRemovedReason if needed. +struct DX12HRWrap +{ + constexpr explicit DX12HRWrap(HRESULT hr) : m_hr(hr) {} + const HRESULT m_hr; +}; + } // namespace DX12 + +template <> +struct fmt::formatter +{ + constexpr auto parse(fmt::format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const DX12::DX12HRWrap& hr, FormatContext& ctx) + { + if (hr.m_hr == DXGI_ERROR_DEVICE_REMOVED && DX12::g_dx_context != nullptr && + DX12::g_dx_context->GetDevice() != nullptr) + { + return fmt::format_to( + ctx.out(), "{}\nDevice removal reason: {}", Common::HRWrap(hr.m_hr), + Common::HRWrap(DX12::g_dx_context->GetDevice()->GetDeviceRemovedReason())); + } + else + { + return fmt::format_to(ctx.out(), "{}", Common::HRWrap(hr.m_hr)); + } + } +}; diff --git a/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp b/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp index aa20f35bd6..52b73e6911 100644 --- a/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp +++ b/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp @@ -210,8 +210,8 @@ std::unique_ptr DXPipeline::Create(const AbstractPipelineConfig& con HRESULT hr = g_dx_context->GetDevice()->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&pso)); if (FAILED(hr)) { - WARN_LOG_FMT(VIDEO, "CreateGraphicsPipelineState() {}failed with HRESULT {:08X}", - cache_data ? "with cache data " : "", hr); + WARN_LOG_FMT(VIDEO, "CreateGraphicsPipelineState() {}failed: {}", + cache_data ? "with cache data " : "", DX12HRWrap(hr)); return nullptr; } @@ -227,7 +227,7 @@ AbstractPipeline::CacheData DXPipeline::GetCacheData() const HRESULT hr = m_pipeline->GetCachedBlob(&blob); if (FAILED(hr)) { - WARN_LOG_FMT(VIDEO, "ID3D12Pipeline::GetCachedBlob() failed with HRESULT {:08X}", hr); + WARN_LOG_FMT(VIDEO, "ID3D12Pipeline::GetCachedBlob() failed: {}", DX12HRWrap(hr)); return {}; } diff --git a/Source/Core/VideoBackends/D3D12/DX12Shader.cpp b/Source/Core/VideoBackends/D3D12/DX12Shader.cpp index 724059a621..61550d2a68 100644 --- a/Source/Core/VideoBackends/D3D12/DX12Shader.cpp +++ b/Source/Core/VideoBackends/D3D12/DX12Shader.cpp @@ -52,7 +52,7 @@ bool DXShader::CreateComputePipeline() HRESULT hr = g_dx_context->GetDevice()->CreateComputePipelineState( &desc, IID_PPV_ARGS(&m_compute_pipeline)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating compute pipeline failed"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating compute pipeline failed: {}", DX12HRWrap(hr)); if (m_compute_pipeline && !m_name.empty()) m_compute_pipeline->SetName(m_name.c_str()); diff --git a/Source/Core/VideoBackends/D3D12/DX12Texture.cpp b/Source/Core/VideoBackends/D3D12/DX12Texture.cpp index d0a0f0d79c..31951b1e95 100644 --- a/Source/Core/VideoBackends/D3D12/DX12Texture.cpp +++ b/Source/Core/VideoBackends/D3D12/DX12Texture.cpp @@ -39,7 +39,7 @@ static ComPtr CreateTextureUploadBuffer(u32 buffer_size) HRESULT hr = g_dx_context->GetDevice()->CreateCommittedResource( &heap_properties, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&resource)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create texture upload buffer"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create texture upload buffer: {}", DX12HRWrap(hr)); return resource; } @@ -116,7 +116,7 @@ std::unique_ptr DXTexture::Create(const TextureConfig& config, std::s HRESULT hr = g_dx_context->GetDevice()->CreateCommittedResource( &heap_properties, D3D12_HEAP_FLAG_NONE, &resource_desc, resource_state, config.IsRenderTarget() ? &optimized_clear_value : nullptr, IID_PPV_ARGS(&resource)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create D3D12 texture resource"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create D3D12 texture resource: {}", DX12HRWrap(hr)); if (FAILED(hr)) return nullptr; @@ -230,9 +230,15 @@ void DXTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* { const D3D12_RANGE read_range = {0, 0}; staging_buffer = CreateTextureUploadBuffer(upload_size); - if (!staging_buffer || FAILED(staging_buffer->Map(0, &read_range, &upload_buffer_ptr))) + if (!staging_buffer) { - PanicAlertFmt("Failed to allocate/map temporary texture upload buffer"); + PanicAlertFmt("Failed to allocate temporary texture upload buffer"); + return; + } + HRESULT hr = staging_buffer->Map(0, &read_range, &upload_buffer_ptr); + if (FAILED(hr)) + { + PanicAlertFmt("Failed to map temporary texture upload buffer: {}", DX12HRWrap(hr)); return; } @@ -598,7 +604,7 @@ bool DXStagingTexture::Map() const D3D12_RANGE read_range = {0u, m_type == StagingTextureType::Upload ? 0u : m_buffer_size}; HRESULT hr = m_resource->Map(0, &read_range, reinterpret_cast(&m_map_pointer)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Map resource failed"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Map resource failed: {}", DX12HRWrap(hr)); if (FAILED(hr)) return false; @@ -663,7 +669,7 @@ std::unique_ptr DXStagingTexture::Create(StagingTextureType ty &heap_properties, D3D12_HEAP_FLAG_NONE, &desc, is_upload ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&resource)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create staging texture resource"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create staging texture resource: {}", DX12HRWrap(hr)); if (FAILED(hr)) return nullptr; diff --git a/Source/Core/VideoBackends/D3D12/DescriptorAllocator.cpp b/Source/Core/VideoBackends/D3D12/DescriptorAllocator.cpp index 989dec905c..bd50b97d87 100644 --- a/Source/Core/VideoBackends/D3D12/DescriptorAllocator.cpp +++ b/Source/Core/VideoBackends/D3D12/DescriptorAllocator.cpp @@ -18,7 +18,8 @@ bool DescriptorAllocator::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYP const D3D12_DESCRIPTOR_HEAP_DESC desc = {type, static_cast(num_descriptors), D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE}; HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&m_descriptor_heap)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating descriptor heap for linear allocator failed"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating descriptor heap for linear allocator failed: {}", + DX12HRWrap(hr)); if (FAILED(hr)) return false; diff --git a/Source/Core/VideoBackends/D3D12/DescriptorHeapManager.cpp b/Source/Core/VideoBackends/D3D12/DescriptorHeapManager.cpp index 265aedaa87..97d0c8ce2e 100644 --- a/Source/Core/VideoBackends/D3D12/DescriptorHeapManager.cpp +++ b/Source/Core/VideoBackends/D3D12/DescriptorHeapManager.cpp @@ -20,7 +20,7 @@ bool DescriptorHeapManager::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_T D3D12_DESCRIPTOR_HEAP_FLAG_NONE}; HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&m_descriptor_heap)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create descriptor heap"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create descriptor heap: {}", DX12HRWrap(hr)); if (FAILED(hr)) return false; @@ -176,7 +176,7 @@ bool SamplerHeapManager::Create(ID3D12Device* device, u32 num_descriptors) { const D3D12_DESCRIPTOR_HEAP_DESC desc = {D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, num_descriptors}; HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&m_descriptor_heap)); - ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create sampler descriptor heap"); + ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create sampler descriptor heap: {}", DX12HRWrap(hr)); if (FAILED(hr)) return false;