diff --git a/src/util/d3d11_device.h b/src/util/d3d11_device.h index b41bf4d54..fd0e044e6 100644 --- a/src/util/d3d11_device.h +++ b/src/util/d3d11_device.h @@ -74,7 +74,7 @@ public: std::unique_ptr CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language, std::string_view source, const char* entry_point, DynamicHeapArray* out_binary, Error* error) override; - std::unique_ptr CreatePipeline(const GPUPipeline::GraphicsConfig& config) override; + std::unique_ptr CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) override; void PushDebugGroup(const char* name) override; void PopDebugGroup() override; @@ -144,10 +144,10 @@ private: bool IsRenderTargetBound(const GPUTexture* tex) const; - ComPtr GetRasterizationState(const GPUPipeline::RasterizationState& rs); - ComPtr GetDepthState(const GPUPipeline::DepthState& ds); - ComPtr GetBlendState(const GPUPipeline::BlendState& bs); - ComPtr GetInputLayout(const GPUPipeline::InputLayout& il, const D3D11Shader* vs); + ComPtr GetRasterizationState(const GPUPipeline::RasterizationState& rs, Error* error); + ComPtr GetDepthState(const GPUPipeline::DepthState& ds, Error* error); + ComPtr GetBlendState(const GPUPipeline::BlendState& bs, Error* error); + ComPtr GetInputLayout(const GPUPipeline::InputLayout& il, const D3D11Shader* vs, Error* error); bool CreateTimestampQueries(); void DestroyTimestampQueries(); diff --git a/src/util/d3d11_pipeline.cpp b/src/util/d3d11_pipeline.cpp index 41eb2897a..2103189b2 100644 --- a/src/util/d3d11_pipeline.cpp +++ b/src/util/d3d11_pipeline.cpp @@ -6,15 +6,12 @@ #include "d3d_common.h" #include "common/error.h" -#include "common/log.h" #include "fmt/format.h" #include #include -Log_SetChannel(D3D11Device); - D3D11Shader::D3D11Shader(GPUShaderStage stage, Microsoft::WRL::ComPtr shader, std::vector bytecode) : GPUShader(stage), m_shader(std::move(shader)), m_bytecode(std::move(bytecode)) @@ -140,7 +137,8 @@ void D3D11Pipeline::SetDebugName(std::string_view name) // can't label this directly } -D3D11Device::ComPtr D3D11Device::GetRasterizationState(const GPUPipeline::RasterizationState& rs) +D3D11Device::ComPtr D3D11Device::GetRasterizationState(const GPUPipeline::RasterizationState& rs, + Error* error) { ComPtr drs; @@ -165,13 +163,14 @@ D3D11Device::ComPtr D3D11Device::GetRasterizationState(co HRESULT hr = m_device->CreateRasterizerState(&desc, drs.GetAddressOf()); if (FAILED(hr)) [[unlikely]] - ERROR_LOG("Failed to create depth state with {:08X}", static_cast(hr)); + Error::SetHResult(error, "CreateRasterizerState() failed: ", hr); + else + m_rasterization_states.emplace(rs.key, drs); - m_rasterization_states.emplace(rs.key, drs); return drs; } -D3D11Device::ComPtr D3D11Device::GetDepthState(const GPUPipeline::DepthState& ds) +D3D11Device::ComPtr D3D11Device::GetDepthState(const GPUPipeline::DepthState& ds, Error* error) { ComPtr dds; @@ -200,13 +199,14 @@ D3D11Device::ComPtr D3D11Device::GetDepthState(const GP HRESULT hr = m_device->CreateDepthStencilState(&desc, dds.GetAddressOf()); if (FAILED(hr)) [[unlikely]] - ERROR_LOG("Failed to create depth state with {:08X}", static_cast(hr)); + Error::SetHResult(error, "CreateDepthStencilState() failed: ", hr); + else + m_depth_states.emplace(ds.key, dds); - m_depth_states.emplace(ds.key, dds); return dds; } -D3D11Device::ComPtr D3D11Device::GetBlendState(const GPUPipeline::BlendState& bs) +D3D11Device::ComPtr D3D11Device::GetBlendState(const GPUPipeline::BlendState& bs, Error* error) { ComPtr dbs; @@ -258,14 +258,15 @@ D3D11Device::ComPtr D3D11Device::GetBlendState(const GPUPipeli HRESULT hr = m_device->CreateBlendState(&blend_desc, dbs.GetAddressOf()); if (FAILED(hr)) [[unlikely]] - ERROR_LOG("Failed to create blend state with {:08X}", static_cast(hr)); + Error::SetHResult(error, "CreateBlendState() failed: ", hr); + else + m_blend_states.emplace(bs.key, dbs); - m_blend_states.emplace(bs.key, dbs); return dbs; } D3D11Device::ComPtr D3D11Device::GetInputLayout(const GPUPipeline::InputLayout& il, - const D3D11Shader* vs) + const D3D11Shader* vs, Error* error) { ComPtr dil; const auto it = m_input_layouts.find(il); @@ -310,17 +311,18 @@ D3D11Device::ComPtr D3D11Device::GetInputLayout(const GPUPipe HRESULT hr = m_device->CreateInputLayout(elems, static_cast(il.vertex_attributes.size()), vs->GetBytecode().data(), vs->GetBytecode().size(), dil.GetAddressOf()); if (FAILED(hr)) [[unlikely]] - ERROR_LOG("Failed to create input layout with {:08X}", static_cast(hr)); + Error::SetHResult(error, "CreateInputLayout() failed: ", hr); + else + m_input_layouts.emplace(il, dil); - m_input_layouts.emplace(il, dil); return dil; } -std::unique_ptr D3D11Device::CreatePipeline(const GPUPipeline::GraphicsConfig& config) +std::unique_ptr D3D11Device::CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) { - ComPtr rs = GetRasterizationState(config.rasterization); - ComPtr ds = GetDepthState(config.depth); - ComPtr bs = GetBlendState(config.blend); + ComPtr rs = GetRasterizationState(config.rasterization, error); + ComPtr ds = GetDepthState(config.depth, error); + ComPtr bs = GetBlendState(config.blend, error); if (!rs || !ds || !bs) return {}; @@ -328,7 +330,7 @@ std::unique_ptr D3D11Device::CreatePipeline(const GPUPipeline::Grap u32 vertex_stride = 0; if (!config.input_layout.vertex_attributes.empty()) { - il = GetInputLayout(config.input_layout, static_cast(config.vertex_shader)); + il = GetInputLayout(config.input_layout, static_cast(config.vertex_shader), error); vertex_stride = config.input_layout.vertex_stride; if (!il) return {}; diff --git a/src/util/d3d12_builders.cpp b/src/util/d3d12_builders.cpp index e57f72eb6..3e093a8ae 100644 --- a/src/util/d3d12_builders.cpp +++ b/src/util/d3d12_builders.cpp @@ -5,14 +5,12 @@ #include "d3d12_device.h" #include "common/assert.h" -#include "common/log.h" +#include "common/error.h" #include "common/string_util.h" #include #include -Log_SetChannel(D3D12Device); - D3D12::GraphicsPipelineBuilder::GraphicsPipelineBuilder() { Clear(); @@ -27,14 +25,14 @@ void D3D12::GraphicsPipelineBuilder::Clear() m_desc.SampleDesc.Count = 1; } -Microsoft::WRL::ComPtr D3D12::GraphicsPipelineBuilder::Create(ID3D12Device* device, - bool clear /*= true*/) +Microsoft::WRL::ComPtr D3D12::GraphicsPipelineBuilder::Create(ID3D12Device* device, Error* error, + bool clear) { Microsoft::WRL::ComPtr ps; HRESULT hr = device->CreateGraphicsPipelineState(&m_desc, IID_PPV_ARGS(ps.GetAddressOf())); if (FAILED(hr)) { - ERROR_LOG("CreateGraphicsPipelineState() failed: {:08X}", static_cast(hr)); + Error::SetHResult(error, "CreateGraphicsPipelineState() failed: ", hr); return {}; } @@ -218,14 +216,14 @@ void D3D12::ComputePipelineBuilder::Clear() std::memset(&m_desc, 0, sizeof(m_desc)); } -Microsoft::WRL::ComPtr D3D12::ComputePipelineBuilder::Create(ID3D12Device* device, - bool clear /*= true*/) +Microsoft::WRL::ComPtr D3D12::ComputePipelineBuilder::Create(ID3D12Device* device, Error* error, + bool clear) { Microsoft::WRL::ComPtr ps; HRESULT hr = device->CreateComputePipelineState(&m_desc, IID_PPV_ARGS(ps.GetAddressOf())); if (FAILED(hr)) [[unlikely]] { - ERROR_LOG("CreateComputePipelineState() failed: {:08X}", static_cast(hr)); + Error::SetHResult(error, "CreateComputePipelineState() failed: ", hr); return {}; } @@ -260,9 +258,9 @@ void D3D12::RootSignatureBuilder::Clear() m_num_descriptor_ranges = 0; } -Microsoft::WRL::ComPtr D3D12::RootSignatureBuilder::Create(bool clear /*= true*/) +Microsoft::WRL::ComPtr D3D12::RootSignatureBuilder::Create(Error* error, bool clear) { - Microsoft::WRL::ComPtr rs = D3D12Device::GetInstance().CreateRootSignature(&m_desc); + Microsoft::WRL::ComPtr rs = D3D12Device::GetInstance().CreateRootSignature(&m_desc, error); if (!rs) return {}; diff --git a/src/util/d3d12_builders.h b/src/util/d3d12_builders.h index 37c378774..c1785d24a 100644 --- a/src/util/d3d12_builders.h +++ b/src/util/d3d12_builders.h @@ -11,6 +11,8 @@ #include #include +class Error; + namespace D3D12 { class RootSignatureBuilder { @@ -25,7 +27,7 @@ public: void Clear(); - Microsoft::WRL::ComPtr Create(bool clear = true); + Microsoft::WRL::ComPtr Create(Error* error, bool clear); void SetInputAssemblerFlag(); @@ -58,7 +60,7 @@ public: void Clear(); - Microsoft::WRL::ComPtr Create(ID3D12Device* device, bool clear = true); + Microsoft::WRL::ComPtr Create(ID3D12Device* device, Error* error, bool clear); void SetRootSignature(ID3D12RootSignature* rs); @@ -115,7 +117,7 @@ public: void Clear(); - Microsoft::WRL::ComPtr Create(ID3D12Device* device, bool clear = true); + Microsoft::WRL::ComPtr Create(ID3D12Device* device, Error* error, bool clear); void SetRootSignature(ID3D12RootSignature* rs); diff --git a/src/util/d3d12_descriptor_heap_manager.cpp b/src/util/d3d12_descriptor_heap_manager.cpp index b56eab9cc..ae6120512 100644 --- a/src/util/d3d12_descriptor_heap_manager.cpp +++ b/src/util/d3d12_descriptor_heap_manager.cpp @@ -1,18 +1,16 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "d3d12_descriptor_heap_manager.h" #include "common/assert.h" -#include "common/log.h" - -Log_SetChannel(D3D12Device); +#include "common/error.h" D3D12DescriptorHeapManager::D3D12DescriptorHeapManager() = default; D3D12DescriptorHeapManager::~D3D12DescriptorHeapManager() = default; bool D3D12DescriptorHeapManager::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors, - bool shader_visible) + bool shader_visible, Error* error) { D3D12_DESCRIPTOR_HEAP_DESC desc = { type, static_cast(num_descriptors), @@ -21,7 +19,7 @@ bool D3D12DescriptorHeapManager::Create(ID3D12Device* device, D3D12_DESCRIPTOR_H HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(m_descriptor_heap.ReleaseAndGetAddressOf())); if (FAILED(hr)) [[unlikely]] { - ERROR_LOG("CreateDescriptorHeap() failed: {:08X}", static_cast(hr)); + Error::SetHResult(error, "CreateDescriptorHeap() failed: ", hr); return false; } @@ -110,14 +108,14 @@ void D3D12DescriptorHeapManager::Free(D3D12DescriptorHandle* handle) D3D12DescriptorAllocator::D3D12DescriptorAllocator() = default; D3D12DescriptorAllocator::~D3D12DescriptorAllocator() = default; -bool D3D12DescriptorAllocator::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors) +bool D3D12DescriptorAllocator::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors, Error* error) { const D3D12_DESCRIPTOR_HEAP_DESC desc = {type, static_cast(num_descriptors), D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, 0u}; const HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(m_descriptor_heap.ReleaseAndGetAddressOf())); if (FAILED(hr)) { - ERROR_LOG("CreateDescriptorHeap() failed: {:08X}", static_cast(hr)); + Error::SetHResult(error, "CreateDescriptorHeap() failed: ", hr); return false; } diff --git a/src/util/d3d12_descriptor_heap_manager.h b/src/util/d3d12_descriptor_heap_manager.h index 28e54d09c..62cff543e 100644 --- a/src/util/d3d12_descriptor_heap_manager.h +++ b/src/util/d3d12_descriptor_heap_manager.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once @@ -14,6 +14,8 @@ #include #include +class Error; + // This class provides an abstraction for D3D12 descriptor heaps. struct D3D12DescriptorHandle final { @@ -55,7 +57,8 @@ public: ID3D12DescriptorHeap* GetDescriptorHeap() const { return m_descriptor_heap.Get(); } u32 GetDescriptorIncrementSize() const { return m_descriptor_increment_size; } - bool Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors, bool shader_visible); + bool Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors, bool shader_visible, + Error* error); void Destroy(); bool Allocate(D3D12DescriptorHandle* handle); @@ -85,7 +88,7 @@ public: ALWAYS_INLINE ID3D12DescriptorHeap* GetDescriptorHeap() const { return m_descriptor_heap.Get(); } ALWAYS_INLINE u32 GetDescriptorIncrementSize() const { return m_descriptor_increment_size; } - bool Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors); + bool Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors, Error* error); void Destroy(); bool Allocate(u32 num_handles, D3D12DescriptorHandle* out_base_handle); @@ -130,7 +133,7 @@ public: using D3D12DescriptorAllocator::GetDescriptorHeap; using D3D12DescriptorAllocator::GetDescriptorIncrementSize; - bool Create(ID3D12Device* device, u32 num_descriptors); + bool Create(ID3D12Device* device, u32 num_descriptors, Error* error); void Destroy(); bool LookupSingle(ID3D12Device* device, D3D12DescriptorHandle* gpu_handle, const D3D12DescriptorHandle& cpu_handle); @@ -153,9 +156,9 @@ template D3D12GroupedSamplerAllocator::~D3D12GroupedSamplerAllocator() = default; template -bool D3D12GroupedSamplerAllocator::Create(ID3D12Device* device, u32 num_descriptors) +bool D3D12GroupedSamplerAllocator::Create(ID3D12Device* device, u32 num_descriptors, Error* error) { - return D3D12DescriptorAllocator::Create(device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, num_descriptors); + return D3D12DescriptorAllocator::Create(device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, num_descriptors, error); } template diff --git a/src/util/d3d12_device.cpp b/src/util/d3d12_device.cpp index 59ace80e5..2ac35d497 100644 --- a/src/util/d3d12_device.cpp +++ b/src/util/d3d12_device.cpp @@ -81,7 +81,7 @@ D3D12Device::~D3D12Device() Assert(s_pipeline_cache_data.empty()); } -D3D12Device::ComPtr D3D12Device::SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc) +D3D12Device::ComPtr D3D12Device::SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error) { ComPtr blob; ComPtr error_blob; @@ -89,7 +89,7 @@ D3D12Device::ComPtr D3D12Device::SerializeRootSignature(const D3D12_RO D3D12SerializeRootSignature(desc, D3D_ROOT_SIGNATURE_VERSION_1, blob.GetAddressOf(), error_blob.GetAddressOf()); if (FAILED(hr)) [[unlikely]] { - ERROR_LOG("D3D12SerializeRootSignature() failed: {:08X}", static_cast(hr)); + Error::SetHResult(error, "D3D12SerializeRootSignature() failed: ", hr); if (error_blob) ERROR_LOG(static_cast(error_blob->GetBufferPointer())); @@ -99,9 +99,10 @@ D3D12Device::ComPtr D3D12Device::SerializeRootSignature(const D3D12_RO return blob; } -D3D12Device::ComPtr D3D12Device::CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc) +D3D12Device::ComPtr D3D12Device::CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, + Error* error) { - ComPtr blob = SerializeRootSignature(desc); + ComPtr blob = SerializeRootSignature(desc, error); if (!blob) return {}; @@ -110,7 +111,7 @@ D3D12Device::ComPtr D3D12Device::CreateRootSignature(const m_device->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(rs.GetAddressOf())); if (FAILED(hr)) [[unlikely]] { - ERROR_LOG("CreateRootSignature() failed: {:08X}", static_cast(hr)); + Error::SetHResult(error, "CreateRootSignature() failed: ", hr); return {}; } @@ -228,23 +229,14 @@ bool D3D12Device::CreateDevice(std::string_view adapter, bool threaded_presentat SetFeatures(disabled_features); - if (!CreateCommandLists() || !CreateDescriptorHeaps()) - { - Error::SetStringView(error, "Failed to create command lists/descriptor heaps."); + if (!CreateCommandLists(error) || !CreateDescriptorHeaps(error)) return false; - } - if (!m_window_info.IsSurfaceless() && !CreateSwapChain()) - { - Error::SetStringView(error, "Failed to create swap chain."); + if (!m_window_info.IsSurfaceless() && !CreateSwapChain(error)) return false; - } - if (!CreateRootSignatures() || !CreateBuffers()) - { - Error::SetStringView(error, "Failed to create root signature/buffers."); + if (!CreateRootSignatures(error) || !CreateBuffers(error)) return false; - } CreateTimestampQuery(); return true; @@ -349,7 +341,7 @@ bool D3D12Device::GetPipelineCacheData(DynamicHeapArray* data) return true; } -bool D3D12Device::CreateCommandLists() +bool D3D12Device::CreateCommandLists(Error* error) { for (u32 i = 0; i < NUM_COMMAND_LISTS; i++) { @@ -362,7 +354,7 @@ bool D3D12Device::CreateCommandLists() IID_PPV_ARGS(res.command_allocators[j].GetAddressOf())); if (FAILED(hr)) { - ERROR_LOG("CreateCommandAllocator() failed: {:08X}", static_cast(hr)); + Error::SetHResult(error, "CreateCommandAllocator() failed: ", hr); return false; } @@ -370,7 +362,7 @@ bool D3D12Device::CreateCommandLists() IID_PPV_ARGS(res.command_lists[j].GetAddressOf())); if (FAILED(hr)) { - ERROR_LOG("CreateCommandList() failed: {:08X}", static_cast(hr)); + Error::SetHResult(error, "CreateCommandList() failed: ", hr); return false; } @@ -378,21 +370,21 @@ bool D3D12Device::CreateCommandLists() hr = res.command_lists[j]->Close(); if (FAILED(hr)) { - ERROR_LOG("Close() failed: {:08X}", static_cast(hr)); + Error::SetHResult(error, "Close() for new command list failed: ", hr); return false; } } if (!res.descriptor_allocator.Create(m_device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, - MAX_DESCRIPTORS_PER_FRAME)) + MAX_DESCRIPTORS_PER_FRAME, error)) { - ERROR_LOG("Failed to create per frame descriptor allocator"); + Error::AddPrefix(error, "Failed to create per frame descriptor allocator: "); return false; } - if (!res.sampler_allocator.Create(m_device.Get(), MAX_SAMPLERS_PER_FRAME)) + if (!res.sampler_allocator.Create(m_device.Get(), MAX_SAMPLERS_PER_FRAME, error)) { - ERROR_LOG("Failed to create per frame sampler allocator"); + Error::AddPrefix(error, "Failed to create per frame sampler allocator: "); return false; } } @@ -472,14 +464,14 @@ void D3D12Device::DestroyCommandLists() } } -bool D3D12Device::CreateDescriptorHeaps() +bool D3D12Device::CreateDescriptorHeaps(Error* error) { if (!m_descriptor_heap_manager.Create(m_device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, - MAX_PERSISTENT_DESCRIPTORS, false) || - !m_rtv_heap_manager.Create(m_device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, MAX_PERSISTENT_RTVS, false) || - !m_dsv_heap_manager.Create(m_device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_DSV, MAX_PERSISTENT_DSVS, false) || - !m_sampler_heap_manager.Create(m_device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, MAX_PERSISTENT_SAMPLERS, - false)) + MAX_PERSISTENT_DESCRIPTORS, false, error) || + !m_rtv_heap_manager.Create(m_device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, MAX_PERSISTENT_RTVS, false, error) || + !m_dsv_heap_manager.Create(m_device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_DSV, MAX_PERSISTENT_DSVS, false, error) || + !m_sampler_heap_manager.Create(m_device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, MAX_PERSISTENT_SAMPLERS, false, + error)) { return false; } @@ -490,7 +482,7 @@ bool D3D12Device::CreateDescriptorHeaps() if (!m_descriptor_heap_manager.Allocate(&m_null_srv_descriptor)) { - ERROR_LOG("Failed to allocate null descriptor"); + Error::SetStringView(error, "Failed to allocate null SRV descriptor"); return false; } @@ -774,10 +766,13 @@ u32 D3D12Device::GetSwapChainBufferCount() const return (m_vsync_mode == GPUVSyncMode::Mailbox) ? 3 : 2; } -bool D3D12Device::CreateSwapChain() +bool D3D12Device::CreateSwapChain(Error* error) { if (m_window_info.type != WindowInfo::Type::Win32) + { + Error::SetStringView(error, "D3D12 expects a Win32 window."); return false; + } const D3DCommon::DXGIFormatMapping& fm = D3DCommon::GetFormatMapping(s_swap_chain_format); @@ -853,13 +848,18 @@ bool D3D12Device::CreateSwapChain() VERBOSE_LOG("Creating a {}x{} windowed swap chain", swap_chain_desc.Width, swap_chain_desc.Height); hr = m_dxgi_factory->CreateSwapChainForHwnd(m_command_queue.Get(), window_hwnd, &swap_chain_desc, nullptr, nullptr, m_swap_chain.ReleaseAndGetAddressOf()); + if (FAILED(hr)) + { + Error::SetHResult(error, "CreateSwapChainForHwnd() failed: ", hr); + return false; + } } hr = m_dxgi_factory->MakeWindowAssociation(window_hwnd, DXGI_MWA_NO_WINDOW_CHANGES); if (FAILED(hr)) WARNING_LOG("MakeWindowAssociation() to disable ALT+ENTER failed"); - if (!CreateSwapChainRTV()) + if (!CreateSwapChainRTV(error)) { DestroySwapChain(); return false; @@ -870,12 +870,15 @@ bool D3D12Device::CreateSwapChain() return true; } -bool D3D12Device::CreateSwapChainRTV() +bool D3D12Device::CreateSwapChainRTV(Error* error) { DXGI_SWAP_CHAIN_DESC swap_chain_desc; HRESULT hr = m_swap_chain->GetDesc(&swap_chain_desc); if (FAILED(hr)) + { + Error::SetHResult(error, "GetDesc() for swap chain failed: ", hr); return false; + } const D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {swap_chain_desc.BufferDesc.Format, D3D12_RTV_DIMENSION_TEXTURE2D, {}}; @@ -885,7 +888,7 @@ bool D3D12Device::CreateSwapChainRTV() hr = m_swap_chain->GetBuffer(i, IID_PPV_ARGS(backbuffer.GetAddressOf())); if (FAILED(hr)) { - ERROR_LOG("GetBuffer for RTV failed: 0x{:08X}", static_cast(hr)); + Error::SetHResult(error, "GetBuffer for RTV failed: ", hr); DestroySwapChainRTVs(); return false; } @@ -895,7 +898,7 @@ bool D3D12Device::CreateSwapChainRTV() D3D12DescriptorHandle rtv; if (!m_rtv_heap_manager.Allocate(&rtv)) { - ERROR_LOG("Failed to allocate RTV handle"); + Error::SetStringView(error, "Failed to allocate RTV handle."); DestroySwapChainRTVs(); return false; } @@ -985,9 +988,10 @@ bool D3D12Device::UpdateWindow() if (m_window_info.IsSurfaceless()) return true; - if (!CreateSwapChain()) + Error error; + if (!CreateSwapChain(&error)) { - ERROR_LOG("Failed to create swap chain on updated window"); + ERROR_LOG("Failed to create swap chain on updated window: {}", error.GetDescription()); return false; } @@ -1015,8 +1019,12 @@ void D3D12Device::ResizeWindow(s32 new_window_width, s32 new_window_height, floa if (FAILED(hr)) ERROR_LOG("ResizeBuffers() failed: 0x{:08X}", static_cast(hr)); - if (!CreateSwapChainRTV()) + Error error; + if (!CreateSwapChainRTV(&error)) + { + ERROR_LOG("Failed to recreate swap chain RTV after resize", error.GetDescription()); Panic("Failed to recreate swap chain RTV after resize"); + } } void D3D12Device::DestroySurface() @@ -1083,8 +1091,13 @@ void D3D12Device::SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle) if (GetSwapChainBufferCount() != old_buffer_count) { DestroySwapChain(); - if (!CreateSwapChain()) + + Error error; + if (!CreateSwapChain(&error)) + { + ERROR_LOG("Failed to recreate swap chain after vsync change: {}", error.GetDescription()); Panic("Failed to recreate swap chain after vsync change."); + } } } @@ -1382,27 +1395,27 @@ void D3D12Device::InvalidateRenderTarget(GPUTexture* t) EndRenderPass(); } -bool D3D12Device::CreateBuffers() +bool D3D12Device::CreateBuffers(Error* error) { - if (!m_vertex_buffer.Create(VERTEX_BUFFER_SIZE)) + if (!m_vertex_buffer.Create(VERTEX_BUFFER_SIZE, error)) { ERROR_LOG("Failed to allocate vertex buffer"); return false; } - if (!m_index_buffer.Create(INDEX_BUFFER_SIZE)) + if (!m_index_buffer.Create(INDEX_BUFFER_SIZE, error)) { ERROR_LOG("Failed to allocate index buffer"); return false; } - if (!m_uniform_buffer.Create(VERTEX_UNIFORM_BUFFER_SIZE)) + if (!m_uniform_buffer.Create(VERTEX_UNIFORM_BUFFER_SIZE, error)) { ERROR_LOG("Failed to allocate uniform buffer"); return false; } - if (!m_texture_upload_buffer.Create(TEXTURE_BUFFER_SIZE)) + if (!m_texture_upload_buffer.Create(TEXTURE_BUFFER_SIZE, error)) { ERROR_LOG("Failed to allocate texture upload buffer"); return false; @@ -1509,7 +1522,7 @@ void D3D12Device::UnmapUniformBuffer(u32 size) m_dirty_flags |= DIRTY_FLAG_CONSTANT_BUFFER; } -bool D3D12Device::CreateRootSignatures() +bool D3D12Device::CreateRootSignatures(Error* error) { D3D12::RootSignatureBuilder rsb; @@ -1520,7 +1533,7 @@ bool D3D12Device::CreateRootSignatures() rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL); rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL); rsb.AddCBVParameter(0, D3D12_SHADER_VISIBILITY_ALL); - if (!(rs = rsb.Create())) + if (!(rs = rsb.Create(error, true))) return false; D3D12::SetObjectName(rs.Get(), "Single Texture + UBO Pipeline Layout"); } @@ -1532,7 +1545,7 @@ bool D3D12Device::CreateRootSignatures() rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL); rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL); rsb.Add32BitConstants(0, UNIFORM_PUSH_CONSTANTS_SIZE / sizeof(u32), D3D12_SHADER_VISIBILITY_ALL); - if (!(rs = rsb.Create())) + if (!(rs = rsb.Create(error, true))) return false; D3D12::SetObjectName(rs.Get(), "Single Texture Pipeline Layout"); } @@ -1543,7 +1556,7 @@ bool D3D12Device::CreateRootSignatures() rsb.SetInputAssemblerFlag(); rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL); rsb.Add32BitConstants(0, UNIFORM_PUSH_CONSTANTS_SIZE / sizeof(u32), D3D12_SHADER_VISIBILITY_ALL); - if (!(rs = rsb.Create())) + if (!(rs = rsb.Create(error, true))) return false; D3D12::SetObjectName(rs.Get(), "Single Texture Buffer + UBO Pipeline Layout"); } @@ -1555,7 +1568,7 @@ bool D3D12Device::CreateRootSignatures() rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, MAX_TEXTURE_SAMPLERS, D3D12_SHADER_VISIBILITY_PIXEL); rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, MAX_TEXTURE_SAMPLERS, D3D12_SHADER_VISIBILITY_PIXEL); rsb.AddCBVParameter(0, D3D12_SHADER_VISIBILITY_ALL); - if (!(rs = rsb.Create())) + if (!(rs = rsb.Create(error, true))) return false; D3D12::SetObjectName(rs.Get(), "Multi Texture + UBO Pipeline Layout"); } @@ -1567,7 +1580,7 @@ bool D3D12Device::CreateRootSignatures() rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, MAX_TEXTURE_SAMPLERS, D3D12_SHADER_VISIBILITY_PIXEL); rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, MAX_TEXTURE_SAMPLERS, D3D12_SHADER_VISIBILITY_PIXEL); rsb.Add32BitConstants(0, UNIFORM_PUSH_CONSTANTS_SIZE / sizeof(u32), D3D12_SHADER_VISIBILITY_ALL); - if (!(rs = rsb.Create())) + if (!(rs = rsb.Create(error, true))) return false; D3D12::SetObjectName(rs.Get(), "Multi Texture Pipeline Layout"); } diff --git a/src/util/d3d12_device.h b/src/util/d3d12_device.h index 3f833d631..22927a134 100644 --- a/src/util/d3d12_device.h +++ b/src/util/d3d12_device.h @@ -95,7 +95,7 @@ public: std::unique_ptr CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language, std::string_view source, const char* entry_point, DynamicHeapArray* out_binary, Error* error) override; - std::unique_ptr CreatePipeline(const GPUPipeline::GraphicsConfig& config) override; + std::unique_ptr CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) override; void PushDebugGroup(const char* name) override; void PopDebugGroup() override; @@ -155,8 +155,8 @@ public: ID3D12GraphicsCommandList4* GetInitCommandList(); // Root signature access. - ComPtr SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc); - ComPtr CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc); + ComPtr SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error); + ComPtr CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error); /// Fence value for current command list. u64 GetCurrentFenceValue() const { return m_current_fence_value; } @@ -223,18 +223,18 @@ private: void SetFeatures(FeatureMask disabled_features); u32 GetSwapChainBufferCount() const; - bool CreateSwapChain(); - bool CreateSwapChainRTV(); + bool CreateSwapChain(Error* error); + bool CreateSwapChainRTV(Error* error); void DestroySwapChainRTVs(); void DestroySwapChain(); - bool CreateCommandLists(); + bool CreateCommandLists(Error* error); void DestroyCommandLists(); - bool CreateRootSignatures(); + bool CreateRootSignatures(Error* error); void DestroyRootSignatures(); - bool CreateBuffers(); + bool CreateBuffers(Error* error); void DestroyBuffers(); - bool CreateDescriptorHeaps(); + bool CreateDescriptorHeaps(Error* error); void DestroyDescriptorHeaps(); bool CreateTimestampQuery(); void DestroyTimestampQuery(); diff --git a/src/util/d3d12_pipeline.cpp b/src/util/d3d12_pipeline.cpp index 15a96c3e1..0cd394110 100644 --- a/src/util/d3d12_pipeline.cpp +++ b/src/util/d3d12_pipeline.cpp @@ -106,7 +106,7 @@ std::string D3D12Pipeline::GetPipelineName(const GraphicsConfig& config) return SHA1Digest::DigestToString(digest); } -std::unique_ptr D3D12Device::CreatePipeline(const GPUPipeline::GraphicsConfig& config) +std::unique_ptr D3D12Device::CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) { static constexpr std::array(GPUPipeline::Primitive::MaxCount)> primitives = {{ @@ -242,7 +242,7 @@ std::unique_ptr D3D12Device::CreatePipeline(const GPUPipeline::Grap ERROR_LOG("LoadGraphicsPipeline() failed with HRESULT {:08X}", static_cast(hr)); // Need to create it normally. - pipeline = gpb.Create(m_device.Get(), false); + pipeline = gpb.Create(m_device.Get(), error, false); // Store if it wasn't an OOM or something else. if (pipeline && hr == E_INVALIDARG) @@ -255,7 +255,7 @@ std::unique_ptr D3D12Device::CreatePipeline(const GPUPipeline::Grap } else { - pipeline = gpb.Create(m_device.Get(), false); + pipeline = gpb.Create(m_device.Get(), error, false); } if (!pipeline) diff --git a/src/util/d3d12_stream_buffer.cpp b/src/util/d3d12_stream_buffer.cpp index 42b8ac26a..478782ba9 100644 --- a/src/util/d3d12_stream_buffer.cpp +++ b/src/util/d3d12_stream_buffer.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "d3d12_stream_buffer.h" @@ -6,6 +6,7 @@ #include "common/align.h" #include "common/assert.h" +#include "common/error.h" #include "common/log.h" #include "D3D12MemAlloc.h" @@ -21,7 +22,7 @@ D3D12StreamBuffer::~D3D12StreamBuffer() Destroy(); } -bool D3D12StreamBuffer::Create(u32 size) +bool D3D12StreamBuffer::Create(u32 size, Error* error) { const D3D12_RESOURCE_DESC resource_desc = { D3D12_RESOURCE_DIMENSION_BUFFER, 0, size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, @@ -38,7 +39,7 @@ bool D3D12StreamBuffer::Create(u32 size) IID_PPV_ARGS(buffer.GetAddressOf())); if (FAILED(hr)) [[unlikely]] { - ERROR_LOG("CreateResource() failed: {:08X}", static_cast(hr)); + Error::SetHResult(error, "CreateResource() for stream buffer failed: ", hr); return false; } @@ -47,7 +48,7 @@ bool D3D12StreamBuffer::Create(u32 size) hr = buffer->Map(0, &read_range, reinterpret_cast(&host_pointer)); if (FAILED(hr)) [[unlikely]] { - ERROR_LOG("Map() failed: {:08X}", static_cast(hr)); + Error::SetHResult(error, "Map() for stream buffer failed: ", hr); return false; } diff --git a/src/util/d3d12_stream_buffer.h b/src/util/d3d12_stream_buffer.h index 314cb746c..cb652bf04 100644 --- a/src/util/d3d12_stream_buffer.h +++ b/src/util/d3d12_stream_buffer.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once @@ -11,6 +11,8 @@ #include #include +class Error; + namespace D3D12MA { class Allocation; } @@ -21,7 +23,7 @@ public: D3D12StreamBuffer(); ~D3D12StreamBuffer(); - bool Create(u32 size); + bool Create(u32 size, Error* error); ALWAYS_INLINE bool IsValid() const { return static_cast(m_buffer); } ALWAYS_INLINE ID3D12Resource* GetBuffer() const { return m_buffer.Get(); } diff --git a/src/util/d3d12_texture.cpp b/src/util/d3d12_texture.cpp index 5679d1427..8dce4cee8 100644 --- a/src/util/d3d12_texture.cpp +++ b/src/util/d3d12_texture.cpp @@ -9,6 +9,7 @@ #include "common/align.h" #include "common/assert.h" #include "common/bitutils.h" +#include "common/error.h" #include "common/log.h" #include "common/string_util.h" @@ -763,10 +764,14 @@ bool D3D12TextureBuffer::Create(D3D12Device& dev) DXGI_FORMAT_R16_UINT, // R16UI }}; - if (!m_buffer.Create(GetSizeInBytes())) + Error error; + if (!m_buffer.Create(GetSizeInBytes(), &error)) [[unlikely]] + { + ERROR_LOG("Failed to create stream buffer: {}", error.GetDescription()); return false; + } - if (!dev.GetDescriptorHeapManager().Allocate(&m_descriptor)) + if (!dev.GetDescriptorHeapManager().Allocate(&m_descriptor)) [[unlikely]] return {}; D3D12_SHADER_RESOURCE_VIEW_DESC desc = {format_mapping[static_cast(m_format)], diff --git a/src/util/gpu_device.cpp b/src/util/gpu_device.cpp index 7c59318af..31c4805ef 100644 --- a/src/util/gpu_device.cpp +++ b/src/util/gpu_device.cpp @@ -533,7 +533,10 @@ bool GPUDevice::CreateResources(Error* error) std::unique_ptr imgui_fs = CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(), shadergen.GenerateImGuiFragmentShader(), error); if (!imgui_vs || !imgui_fs) + { + Error::AddPrefix(error, "Failed to compile ImGui shaders: "); return false; + } GL_OBJECT_NAME(imgui_vs, "ImGui Vertex Shader"); GL_OBJECT_NAME(imgui_fs, "ImGui Fragment Shader"); @@ -563,10 +566,10 @@ bool GPUDevice::CreateResources(Error* error) plconfig.geometry_shader = nullptr; plconfig.fragment_shader = imgui_fs.get(); - m_imgui_pipeline = CreatePipeline(plconfig); + m_imgui_pipeline = CreatePipeline(plconfig, error); if (!m_imgui_pipeline) { - Error::SetStringView(error, "Failed to compile ImGui pipeline."); + Error::AddPrefix(error, "Failed to compile ImGui pipeline: "); return false; } GL_OBJECT_NAME(m_imgui_pipeline, "ImGui Pipeline"); diff --git a/src/util/gpu_device.h b/src/util/gpu_device.h index 8f624fc37..b93e985ee 100644 --- a/src/util/gpu_device.h +++ b/src/util/gpu_device.h @@ -650,7 +650,8 @@ public: /// Shader abstraction. std::unique_ptr CreateShader(GPUShaderStage stage, GPUShaderLanguage language, std::string_view source, Error* error = nullptr, const char* entry_point = "main"); - virtual std::unique_ptr CreatePipeline(const GPUPipeline::GraphicsConfig& config) = 0; + virtual std::unique_ptr CreatePipeline(const GPUPipeline::GraphicsConfig& config, + Error* error = nullptr) = 0; /// Debug messaging. virtual void PushDebugGroup(const char* name) = 0; diff --git a/src/util/metal_device.h b/src/util/metal_device.h index fe3b570a9..e384267ea 100644 --- a/src/util/metal_device.h +++ b/src/util/metal_device.h @@ -235,7 +235,7 @@ public: std::unique_ptr CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language, std::string_view source, const char* entry_point, DynamicHeapArray* out_binary, Error* error) override; - std::unique_ptr CreatePipeline(const GPUPipeline::GraphicsConfig& config) override; + std::unique_ptr CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) override; void PushDebugGroup(const char* name) override; void PopDebugGroup() override; diff --git a/src/util/metal_device.mm b/src/util/metal_device.mm index 9d4c65eab..8ecc59f54 100644 --- a/src/util/metal_device.mm +++ b/src/util/metal_device.mm @@ -76,6 +76,11 @@ static void LogNSError(NSError* error, std::string_view message) Log::FastWrite("MetalDevice", LOGLEVEL_ERROR, " NSError Description: {}", [error.description UTF8String]); } +static void NSErrorToErrorObject(Error* errptr, std::string_view message, NSError* error) +{ + Error::SetStringFmt(errptr, "{}NSError Code {}: {}", message, static_cast(error.code), [error.description UTF8String]); +} + static GPUTexture::Format GetTextureFormatForMTLFormat(MTLPixelFormat fmt) { for (u32 i = 0; i < static_cast(GPUTexture::Format::MaxCount); i++) @@ -719,7 +724,7 @@ id MetalDevice::GetDepthState(const GPUPipeline::DepthStat } } -std::unique_ptr MetalDevice::CreatePipeline(const GPUPipeline::GraphicsConfig& config) +std::unique_ptr MetalDevice::CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) { @autoreleasepool { @@ -857,11 +862,12 @@ std::unique_ptr MetalDevice::CreatePipeline(const GPUPipeline::Grap if (config.layout == GPUPipeline::Layout::SingleTextureBufferAndPushConstants) desc.fragmentBuffers[1].mutability = MTLMutabilityImmutable; - NSError* error = nullptr; - id pipeline = [m_device newRenderPipelineStateWithDescriptor:desc error:&error]; + NSError* nserror = nullptr; + id pipeline = [m_device newRenderPipelineStateWithDescriptor:desc error:&nserror]; if (pipeline == nil) { - LogNSError(error, "Failed to create render pipeline state"); + LogNSError(nserror, "Failed to create render pipeline state"); + NSErrorToErrorObject(error, "newRenderPipelineStateWithDescriptor failed: ", nserror); return {}; } diff --git a/src/util/opengl_device.cpp b/src/util/opengl_device.cpp index d68dc8dfd..5947baf58 100644 --- a/src/util/opengl_device.cpp +++ b/src/util/opengl_device.cpp @@ -10,6 +10,7 @@ #include "common/align.h" #include "common/assert.h" +#include "common/error.h" #include "common/log.h" #include "common/string_util.h" @@ -50,6 +51,11 @@ bool OpenGLDevice::ShouldUsePBOsForDownloads() return !GetInstance().m_disable_pbo && !GetInstance().m_disable_async_download; } +void OpenGLDevice::SetErrorObject(Error* errptr, std::string_view prefix, GLenum glerr) +{ + Error::SetStringFmt(errptr, "{}GL Error 0x{:04X}", prefix, static_cast(glerr)); +} + RenderAPI OpenGLDevice::GetRenderAPI() const { return m_gl_context->IsGLES() ? RenderAPI::OpenGLES : RenderAPI::OpenGL; diff --git a/src/util/opengl_device.h b/src/util/opengl_device.h index b7ed363b6..04d1b2ed0 100644 --- a/src/util/opengl_device.h +++ b/src/util/opengl_device.h @@ -13,6 +13,7 @@ #include #include +#include #include class OpenGLPipeline; @@ -37,6 +38,7 @@ public: ALWAYS_INLINE static bool IsGLES() { return GetInstance().m_gl_context->IsGLES(); } static void BindUpdateTextureUnit(); static bool ShouldUsePBOsForDownloads(); + static void SetErrorObject(Error* errptr, std::string_view prefix, GLenum glerr); RenderAPI GetRenderAPI() const override; @@ -75,7 +77,7 @@ public: std::unique_ptr CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language, std::string_view source, const char* entry_point, DynamicHeapArray* out_binary, Error* error) override; - std::unique_ptr CreatePipeline(const GPUPipeline::GraphicsConfig& config) override; + std::unique_ptr CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) override; void PushDebugGroup(const char* name) override; void PopDebugGroup() override; @@ -113,13 +115,13 @@ public: void CommitRTClearInFB(OpenGLTexture* tex, u32 idx); void CommitDSClearInFB(OpenGLTexture* tex); - GLuint LookupProgramCache(const OpenGLPipeline::ProgramCacheKey& key, const GPUPipeline::GraphicsConfig& plconfig); - GLuint CompileProgram(const GPUPipeline::GraphicsConfig& plconfig); + GLuint LookupProgramCache(const OpenGLPipeline::ProgramCacheKey& key, const GPUPipeline::GraphicsConfig& plconfig, Error* error); + GLuint CompileProgram(const GPUPipeline::GraphicsConfig& plconfig, Error* error); void PostLinkProgram(const GPUPipeline::GraphicsConfig& plconfig, GLuint program_id); void UnrefProgram(const OpenGLPipeline::ProgramCacheKey& key); - OpenGLPipeline::VertexArrayCache::const_iterator LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key); - GLuint CreateVAO(std::span attributes, u32 stride); + OpenGLPipeline::VertexArrayCache::const_iterator LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key, Error* error); + GLuint CreateVAO(std::span attributes, u32 stride, Error* error); void UnrefVAO(const OpenGLPipeline::VertexArrayCacheKey& key); void SetActiveTexture(u32 slot); diff --git a/src/util/opengl_pipeline.cpp b/src/util/opengl_pipeline.cpp index 086f9cb3f..4e3b65db4 100644 --- a/src/util/opengl_pipeline.cpp +++ b/src/util/opengl_pipeline.cpp @@ -98,10 +98,18 @@ void OpenGLShader::SetDebugName(std::string_view name) #endif } -bool OpenGLShader::Compile() +bool OpenGLShader::Compile(Error* error) { if (m_compile_tried) - return m_id.has_value(); + { + if (!m_id.has_value()) [[unlikely]] + { + Error::SetStringView(error, "Shader previously failed to compile."); + return false; + } + + return true; + } m_compile_tried = true; @@ -111,6 +119,7 @@ bool OpenGLShader::Compile() if (GLenum err = glGetError(); err != GL_NO_ERROR) { ERROR_LOG("glCreateShader() failed: {}", err); + OpenGLDevice::SetErrorObject(error, "glCreateShader() failed: ", err); return false; } @@ -138,6 +147,7 @@ bool OpenGLShader::Compile() else { ERROR_LOG("Shader failed to compile:\n{}", info_log); + Error::SetStringFmt(error, "Shader failed to compile:\n{}", info_log); GPUDevice::DumpBadShader(m_source, info_log); glDeleteShader(shader); return false; @@ -268,7 +278,7 @@ OpenGLPipeline::ProgramCacheKey OpenGLPipeline::GetProgramCacheKey(const Graphic } GLuint OpenGLDevice::LookupProgramCache(const OpenGLPipeline::ProgramCacheKey& key, - const GPUPipeline::GraphicsConfig& plconfig) + const GPUPipeline::GraphicsConfig& plconfig, Error* error) { auto it = m_program_cache.find(key); if (it != m_program_cache.end() && it->second.program_id == 0 && it->second.file_uncompressed_size > 0) @@ -291,7 +301,7 @@ GLuint OpenGLDevice::LookupProgramCache(const OpenGLPipeline::ProgramCacheKey& k return it->second.program_id; } - const GLuint program_id = CompileProgram(plconfig); + const GLuint program_id = CompileProgram(plconfig, error); if (program_id == 0) { // Compile failed, don't add to map, it just gets confusing. @@ -312,23 +322,22 @@ GLuint OpenGLDevice::LookupProgramCache(const OpenGLPipeline::ProgramCacheKey& k return item.program_id; } -GLuint OpenGLDevice::CompileProgram(const GPUPipeline::GraphicsConfig& plconfig) +GLuint OpenGLDevice::CompileProgram(const GPUPipeline::GraphicsConfig& plconfig, Error* error) { OpenGLShader* vertex_shader = static_cast(plconfig.vertex_shader); OpenGLShader* fragment_shader = static_cast(plconfig.fragment_shader); OpenGLShader* geometry_shader = static_cast(plconfig.geometry_shader); - if (!vertex_shader || !fragment_shader || !vertex_shader->Compile() || !fragment_shader->Compile() || - (geometry_shader && !geometry_shader->Compile())) [[unlikely]] + if (!vertex_shader || !fragment_shader || !vertex_shader->Compile(error) || !fragment_shader->Compile(error) || + (geometry_shader && !geometry_shader->Compile(error))) [[unlikely]] { - ERROR_LOG("Failed to compile shaders."); return 0; } glGetError(); const GLuint program_id = glCreateProgram(); - if (glGetError() != GL_NO_ERROR) [[unlikely]] + if (const GLenum err = glGetError(); err != GL_NO_ERROR) [[unlikely]] { - ERROR_LOG("Failed to create program object."); + SetErrorObject(error, "glCreateProgram() failed: ", err); return 0; } @@ -412,6 +421,7 @@ GLuint OpenGLDevice::CompileProgram(const GPUPipeline::GraphicsConfig& plconfig) } ERROR_LOG("Program failed to link:\n{}", info_log); + Error::SetStringFmt(error, "Program failed to link:\n{}", info_log); glDeleteProgram(program_id); return 0; } @@ -468,7 +478,7 @@ void OpenGLDevice::UnrefProgram(const OpenGLPipeline::ProgramCacheKey& key) } OpenGLPipeline::VertexArrayCache::const_iterator -OpenGLDevice::LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key) +OpenGLDevice::LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key, Error* error) { OpenGLPipeline::VertexArrayCache::iterator it = m_vao_cache.find(key); if (it != m_vao_cache.end()) @@ -480,7 +490,7 @@ OpenGLDevice::LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key) OpenGLPipeline::VertexArrayCacheItem item; item.vao_id = CreateVAO(std::span(key.vertex_attributes, key.num_vertex_attributes), - key.vertex_attribute_stride); + key.vertex_attribute_stride, error); if (item.vao_id == 0) return m_vao_cache.cend(); @@ -488,7 +498,7 @@ OpenGLDevice::LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key) return m_vao_cache.emplace(key, item).first; } -GLuint OpenGLDevice::CreateVAO(std::span attributes, u32 stride) +GLuint OpenGLDevice::CreateVAO(std::span attributes, u32 stride, Error* error) { glGetError(); GLuint vao; @@ -496,6 +506,7 @@ GLuint OpenGLDevice::CreateVAO(std::span att if (const GLenum err = glGetError(); err != GL_NO_ERROR) { ERROR_LOG("Failed to create vertex array object: {}", err); + SetErrorObject(error, "glGenVertexArrays() failed: ", err); return 0; } @@ -582,15 +593,15 @@ void OpenGLPipeline::SetDebugName(std::string_view name) #endif } -std::unique_ptr OpenGLDevice::CreatePipeline(const GPUPipeline::GraphicsConfig& config) +std::unique_ptr OpenGLDevice::CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) { const OpenGLPipeline::ProgramCacheKey pkey = OpenGLPipeline::GetProgramCacheKey(config); - const GLuint program_id = LookupProgramCache(pkey, config); + const GLuint program_id = LookupProgramCache(pkey, config, error); if (program_id == 0) return {}; - const OpenGLPipeline::VertexArrayCache::const_iterator vao = LookupVAOCache(pkey.va_key); + const OpenGLPipeline::VertexArrayCache::const_iterator vao = LookupVAOCache(pkey.va_key, error); if (vao == m_vao_cache.cend()) { UnrefProgram(pkey); diff --git a/src/util/opengl_pipeline.h b/src/util/opengl_pipeline.h index 8d8054fbd..8deb64bc4 100644 --- a/src/util/opengl_pipeline.h +++ b/src/util/opengl_pipeline.h @@ -18,7 +18,7 @@ public: void SetDebugName(std::string_view name) override; - bool Compile(); + bool Compile(Error* error); ALWAYS_INLINE GLuint GetGLId() const { return m_id.value(); } ALWAYS_INLINE const GPUShaderCache::CacheIndexKey& GetKey() const { return m_key; } diff --git a/src/util/vulkan_builders.cpp b/src/util/vulkan_builders.cpp index b37677b94..225fe5cda 100644 --- a/src/util/vulkan_builders.cpp +++ b/src/util/vulkan_builders.cpp @@ -1,9 +1,10 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "vulkan_builders.h" #include "common/assert.h" +#include "common/error.h" #include "common/log.h" #include @@ -109,6 +110,11 @@ void Vulkan::LogVulkanResult(const char* func_name, VkResult res, std::string_vi VkResultToString(res)); } +void Vulkan::SetErrorObject(Error* errptr, std::string_view prefix, VkResult res) +{ + Error::SetStringFmt(errptr, "{} (0x{:08X}: {})", prefix, static_cast(res), VkResultToString(res)); +} + Vulkan::DescriptorSetLayoutBuilder::DescriptorSetLayoutBuilder() { Clear(); @@ -277,14 +283,15 @@ void Vulkan::GraphicsPipelineBuilder::Clear() SetMultisamples(VK_SAMPLE_COUNT_1_BIT); } -VkPipeline Vulkan::GraphicsPipelineBuilder::Create(VkDevice device, VkPipelineCache pipeline_cache, - bool clear /* = true */) +VkPipeline Vulkan::GraphicsPipelineBuilder::Create(VkDevice device, VkPipelineCache pipeline_cache, bool clear, + Error* error) { VkPipeline pipeline; VkResult res = vkCreateGraphicsPipelines(device, pipeline_cache, 1, &m_ci, nullptr, &pipeline); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkCreateGraphicsPipelines() failed: "); + SetErrorObject(error, "vkCreateGraphicsPipelines() failed: ", res); return VK_NULL_HANDLE; } diff --git a/src/util/vulkan_builders.h b/src/util/vulkan_builders.h index eddcad4c3..0038859f5 100644 --- a/src/util/vulkan_builders.h +++ b/src/util/vulkan_builders.h @@ -12,6 +12,8 @@ #include #include +class Error; + #if defined(_DEBUG) && !defined(CPU_ARCH_ARM32) && !defined(CPU_ARCH_X86) #define ENABLE_VULKAN_DEBUG_OBJECTS 1 #endif @@ -24,6 +26,7 @@ void AddPointerToChain(void* head, const void* ptr); const char* VkResultToString(VkResult res); void LogVulkanResult(const char* func_name, VkResult res, std::string_view msg); +void SetErrorObject(Error* errptr, std::string_view prefix, VkResult res); class DescriptorSetLayoutBuilder { @@ -89,7 +92,7 @@ public: void Clear(); - VkPipeline Create(VkDevice device, VkPipelineCache pipeline_cache = VK_NULL_HANDLE, bool clear = true); + VkPipeline Create(VkDevice device, VkPipelineCache pipeline_cache, bool clear, Error* error); void SetShaderStage(VkShaderStageFlagBits stage, VkShaderModule module, const char* entry_point); void SetVertexShader(VkShaderModule module) { SetShaderStage(VK_SHADER_STAGE_VERTEX_BIT, module, "main"); } diff --git a/src/util/vulkan_device.h b/src/util/vulkan_device.h index b997dddf6..059c2f8cb 100644 --- a/src/util/vulkan_device.h +++ b/src/util/vulkan_device.h @@ -104,11 +104,12 @@ public: void ClearDepth(GPUTexture* t, float d) override; void InvalidateRenderTarget(GPUTexture* t) override; - std::unique_ptr CreateShaderFromBinary(GPUShaderStage stage, std::span data, Error* error) override; + std::unique_ptr CreateShaderFromBinary(GPUShaderStage stage, std::span data, + Error* error) override; std::unique_ptr CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language, std::string_view source, const char* entry_point, DynamicHeapArray* out_binary, Error* error) override; - std::unique_ptr CreatePipeline(const GPUPipeline::GraphicsConfig& config) override; + std::unique_ptr CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) override; void PushDebugGroup(const char* name) override; void PopDebugGroup() override; diff --git a/src/util/vulkan_pipeline.cpp b/src/util/vulkan_pipeline.cpp index 01e0a0fbe..4a4f1c43c 100644 --- a/src/util/vulkan_pipeline.cpp +++ b/src/util/vulkan_pipeline.cpp @@ -88,7 +88,7 @@ void VulkanPipeline::SetDebugName(std::string_view name) Vulkan::SetObjectName(VulkanDevice::GetInstance().GetVulkanDevice(), m_pipeline, name); } -std::unique_ptr VulkanDevice::CreatePipeline(const GPUPipeline::GraphicsConfig& config) +std::unique_ptr VulkanDevice::CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) { static constexpr std::array, static_cast(GPUPipeline::Primitive::MaxCount)> primitives = {{ @@ -243,7 +243,7 @@ std::unique_ptr VulkanDevice::CreatePipeline(const GPUPipeline::Gra gpb.SetRenderPass(render_pass, 0); } - const VkPipeline pipeline = gpb.Create(m_device, m_pipeline_cache, false); + const VkPipeline pipeline = gpb.Create(m_device, m_pipeline_cache, false, error); if (!pipeline) return {};