GPUDevice: Improve pipeline error reporting

This commit is contained in:
Stenzek 2024-07-22 15:35:28 +10:00
parent deed0c9713
commit ba6b65401d
No known key found for this signature in database
24 changed files with 227 additions and 163 deletions

View file

@ -74,7 +74,7 @@ public:
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language, std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
std::string_view source, const char* entry_point, std::string_view source, const char* entry_point,
DynamicHeapArray<u8>* out_binary, Error* error) override; DynamicHeapArray<u8>* out_binary, Error* error) override;
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override; std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) override;
void PushDebugGroup(const char* name) override; void PushDebugGroup(const char* name) override;
void PopDebugGroup() override; void PopDebugGroup() override;
@ -144,10 +144,10 @@ private:
bool IsRenderTargetBound(const GPUTexture* tex) const; bool IsRenderTargetBound(const GPUTexture* tex) const;
ComPtr<ID3D11RasterizerState> GetRasterizationState(const GPUPipeline::RasterizationState& rs); ComPtr<ID3D11RasterizerState> GetRasterizationState(const GPUPipeline::RasterizationState& rs, Error* error);
ComPtr<ID3D11DepthStencilState> GetDepthState(const GPUPipeline::DepthState& ds); ComPtr<ID3D11DepthStencilState> GetDepthState(const GPUPipeline::DepthState& ds, Error* error);
ComPtr<ID3D11BlendState> GetBlendState(const GPUPipeline::BlendState& bs); ComPtr<ID3D11BlendState> GetBlendState(const GPUPipeline::BlendState& bs, Error* error);
ComPtr<ID3D11InputLayout> GetInputLayout(const GPUPipeline::InputLayout& il, const D3D11Shader* vs); ComPtr<ID3D11InputLayout> GetInputLayout(const GPUPipeline::InputLayout& il, const D3D11Shader* vs, Error* error);
bool CreateTimestampQueries(); bool CreateTimestampQueries();
void DestroyTimestampQueries(); void DestroyTimestampQueries();

View file

@ -6,15 +6,12 @@
#include "d3d_common.h" #include "d3d_common.h"
#include "common/error.h" #include "common/error.h"
#include "common/log.h"
#include "fmt/format.h" #include "fmt/format.h"
#include <array> #include <array>
#include <malloc.h> #include <malloc.h>
Log_SetChannel(D3D11Device);
D3D11Shader::D3D11Shader(GPUShaderStage stage, Microsoft::WRL::ComPtr<ID3D11DeviceChild> shader, D3D11Shader::D3D11Shader(GPUShaderStage stage, Microsoft::WRL::ComPtr<ID3D11DeviceChild> shader,
std::vector<u8> bytecode) std::vector<u8> bytecode)
: GPUShader(stage), m_shader(std::move(shader)), m_bytecode(std::move(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 // can't label this directly
} }
D3D11Device::ComPtr<ID3D11RasterizerState> D3D11Device::GetRasterizationState(const GPUPipeline::RasterizationState& rs) D3D11Device::ComPtr<ID3D11RasterizerState> D3D11Device::GetRasterizationState(const GPUPipeline::RasterizationState& rs,
Error* error)
{ {
ComPtr<ID3D11RasterizerState> drs; ComPtr<ID3D11RasterizerState> drs;
@ -165,13 +163,14 @@ D3D11Device::ComPtr<ID3D11RasterizerState> D3D11Device::GetRasterizationState(co
HRESULT hr = m_device->CreateRasterizerState(&desc, drs.GetAddressOf()); HRESULT hr = m_device->CreateRasterizerState(&desc, drs.GetAddressOf());
if (FAILED(hr)) [[unlikely]] if (FAILED(hr)) [[unlikely]]
ERROR_LOG("Failed to create depth state with {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "CreateRasterizerState() failed: ", hr);
else
m_rasterization_states.emplace(rs.key, drs);
m_rasterization_states.emplace(rs.key, drs);
return drs; return drs;
} }
D3D11Device::ComPtr<ID3D11DepthStencilState> D3D11Device::GetDepthState(const GPUPipeline::DepthState& ds) D3D11Device::ComPtr<ID3D11DepthStencilState> D3D11Device::GetDepthState(const GPUPipeline::DepthState& ds, Error* error)
{ {
ComPtr<ID3D11DepthStencilState> dds; ComPtr<ID3D11DepthStencilState> dds;
@ -200,13 +199,14 @@ D3D11Device::ComPtr<ID3D11DepthStencilState> D3D11Device::GetDepthState(const GP
HRESULT hr = m_device->CreateDepthStencilState(&desc, dds.GetAddressOf()); HRESULT hr = m_device->CreateDepthStencilState(&desc, dds.GetAddressOf());
if (FAILED(hr)) [[unlikely]] if (FAILED(hr)) [[unlikely]]
ERROR_LOG("Failed to create depth state with {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "CreateDepthStencilState() failed: ", hr);
else
m_depth_states.emplace(ds.key, dds);
m_depth_states.emplace(ds.key, dds);
return dds; return dds;
} }
D3D11Device::ComPtr<ID3D11BlendState> D3D11Device::GetBlendState(const GPUPipeline::BlendState& bs) D3D11Device::ComPtr<ID3D11BlendState> D3D11Device::GetBlendState(const GPUPipeline::BlendState& bs, Error* error)
{ {
ComPtr<ID3D11BlendState> dbs; ComPtr<ID3D11BlendState> dbs;
@ -258,14 +258,15 @@ D3D11Device::ComPtr<ID3D11BlendState> D3D11Device::GetBlendState(const GPUPipeli
HRESULT hr = m_device->CreateBlendState(&blend_desc, dbs.GetAddressOf()); HRESULT hr = m_device->CreateBlendState(&blend_desc, dbs.GetAddressOf());
if (FAILED(hr)) [[unlikely]] if (FAILED(hr)) [[unlikely]]
ERROR_LOG("Failed to create blend state with {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "CreateBlendState() failed: ", hr);
else
m_blend_states.emplace(bs.key, dbs);
m_blend_states.emplace(bs.key, dbs);
return dbs; return dbs;
} }
D3D11Device::ComPtr<ID3D11InputLayout> D3D11Device::GetInputLayout(const GPUPipeline::InputLayout& il, D3D11Device::ComPtr<ID3D11InputLayout> D3D11Device::GetInputLayout(const GPUPipeline::InputLayout& il,
const D3D11Shader* vs) const D3D11Shader* vs, Error* error)
{ {
ComPtr<ID3D11InputLayout> dil; ComPtr<ID3D11InputLayout> dil;
const auto it = m_input_layouts.find(il); const auto it = m_input_layouts.find(il);
@ -310,17 +311,18 @@ D3D11Device::ComPtr<ID3D11InputLayout> D3D11Device::GetInputLayout(const GPUPipe
HRESULT hr = m_device->CreateInputLayout(elems, static_cast<UINT>(il.vertex_attributes.size()), HRESULT hr = m_device->CreateInputLayout(elems, static_cast<UINT>(il.vertex_attributes.size()),
vs->GetBytecode().data(), vs->GetBytecode().size(), dil.GetAddressOf()); vs->GetBytecode().data(), vs->GetBytecode().size(), dil.GetAddressOf());
if (FAILED(hr)) [[unlikely]] if (FAILED(hr)) [[unlikely]]
ERROR_LOG("Failed to create input layout with {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "CreateInputLayout() failed: ", hr);
else
m_input_layouts.emplace(il, dil);
m_input_layouts.emplace(il, dil);
return dil; return dil;
} }
std::unique_ptr<GPUPipeline> D3D11Device::CreatePipeline(const GPUPipeline::GraphicsConfig& config) std::unique_ptr<GPUPipeline> D3D11Device::CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error)
{ {
ComPtr<ID3D11RasterizerState> rs = GetRasterizationState(config.rasterization); ComPtr<ID3D11RasterizerState> rs = GetRasterizationState(config.rasterization, error);
ComPtr<ID3D11DepthStencilState> ds = GetDepthState(config.depth); ComPtr<ID3D11DepthStencilState> ds = GetDepthState(config.depth, error);
ComPtr<ID3D11BlendState> bs = GetBlendState(config.blend); ComPtr<ID3D11BlendState> bs = GetBlendState(config.blend, error);
if (!rs || !ds || !bs) if (!rs || !ds || !bs)
return {}; return {};
@ -328,7 +330,7 @@ std::unique_ptr<GPUPipeline> D3D11Device::CreatePipeline(const GPUPipeline::Grap
u32 vertex_stride = 0; u32 vertex_stride = 0;
if (!config.input_layout.vertex_attributes.empty()) if (!config.input_layout.vertex_attributes.empty())
{ {
il = GetInputLayout(config.input_layout, static_cast<const D3D11Shader*>(config.vertex_shader)); il = GetInputLayout(config.input_layout, static_cast<const D3D11Shader*>(config.vertex_shader), error);
vertex_stride = config.input_layout.vertex_stride; vertex_stride = config.input_layout.vertex_stride;
if (!il) if (!il)
return {}; return {};

View file

@ -5,14 +5,12 @@
#include "d3d12_device.h" #include "d3d12_device.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/log.h" #include "common/error.h"
#include "common/string_util.h" #include "common/string_util.h"
#include <cstdarg> #include <cstdarg>
#include <limits> #include <limits>
Log_SetChannel(D3D12Device);
D3D12::GraphicsPipelineBuilder::GraphicsPipelineBuilder() D3D12::GraphicsPipelineBuilder::GraphicsPipelineBuilder()
{ {
Clear(); Clear();
@ -27,14 +25,14 @@ void D3D12::GraphicsPipelineBuilder::Clear()
m_desc.SampleDesc.Count = 1; m_desc.SampleDesc.Count = 1;
} }
Microsoft::WRL::ComPtr<ID3D12PipelineState> D3D12::GraphicsPipelineBuilder::Create(ID3D12Device* device, Microsoft::WRL::ComPtr<ID3D12PipelineState> D3D12::GraphicsPipelineBuilder::Create(ID3D12Device* device, Error* error,
bool clear /*= true*/) bool clear)
{ {
Microsoft::WRL::ComPtr<ID3D12PipelineState> ps; Microsoft::WRL::ComPtr<ID3D12PipelineState> ps;
HRESULT hr = device->CreateGraphicsPipelineState(&m_desc, IID_PPV_ARGS(ps.GetAddressOf())); HRESULT hr = device->CreateGraphicsPipelineState(&m_desc, IID_PPV_ARGS(ps.GetAddressOf()));
if (FAILED(hr)) if (FAILED(hr))
{ {
ERROR_LOG("CreateGraphicsPipelineState() failed: {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "CreateGraphicsPipelineState() failed: ", hr);
return {}; return {};
} }
@ -218,14 +216,14 @@ void D3D12::ComputePipelineBuilder::Clear()
std::memset(&m_desc, 0, sizeof(m_desc)); std::memset(&m_desc, 0, sizeof(m_desc));
} }
Microsoft::WRL::ComPtr<ID3D12PipelineState> D3D12::ComputePipelineBuilder::Create(ID3D12Device* device, Microsoft::WRL::ComPtr<ID3D12PipelineState> D3D12::ComputePipelineBuilder::Create(ID3D12Device* device, Error* error,
bool clear /*= true*/) bool clear)
{ {
Microsoft::WRL::ComPtr<ID3D12PipelineState> ps; Microsoft::WRL::ComPtr<ID3D12PipelineState> ps;
HRESULT hr = device->CreateComputePipelineState(&m_desc, IID_PPV_ARGS(ps.GetAddressOf())); HRESULT hr = device->CreateComputePipelineState(&m_desc, IID_PPV_ARGS(ps.GetAddressOf()));
if (FAILED(hr)) [[unlikely]] if (FAILED(hr)) [[unlikely]]
{ {
ERROR_LOG("CreateComputePipelineState() failed: {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "CreateComputePipelineState() failed: ", hr);
return {}; return {};
} }
@ -260,9 +258,9 @@ void D3D12::RootSignatureBuilder::Clear()
m_num_descriptor_ranges = 0; m_num_descriptor_ranges = 0;
} }
Microsoft::WRL::ComPtr<ID3D12RootSignature> D3D12::RootSignatureBuilder::Create(bool clear /*= true*/) Microsoft::WRL::ComPtr<ID3D12RootSignature> D3D12::RootSignatureBuilder::Create(Error* error, bool clear)
{ {
Microsoft::WRL::ComPtr<ID3D12RootSignature> rs = D3D12Device::GetInstance().CreateRootSignature(&m_desc); Microsoft::WRL::ComPtr<ID3D12RootSignature> rs = D3D12Device::GetInstance().CreateRootSignature(&m_desc, error);
if (!rs) if (!rs)
return {}; return {};

View file

@ -11,6 +11,8 @@
#include <string_view> #include <string_view>
#include <wrl/client.h> #include <wrl/client.h>
class Error;
namespace D3D12 { namespace D3D12 {
class RootSignatureBuilder class RootSignatureBuilder
{ {
@ -25,7 +27,7 @@ public:
void Clear(); void Clear();
Microsoft::WRL::ComPtr<ID3D12RootSignature> Create(bool clear = true); Microsoft::WRL::ComPtr<ID3D12RootSignature> Create(Error* error, bool clear);
void SetInputAssemblerFlag(); void SetInputAssemblerFlag();
@ -58,7 +60,7 @@ public:
void Clear(); void Clear();
Microsoft::WRL::ComPtr<ID3D12PipelineState> Create(ID3D12Device* device, bool clear = true); Microsoft::WRL::ComPtr<ID3D12PipelineState> Create(ID3D12Device* device, Error* error, bool clear);
void SetRootSignature(ID3D12RootSignature* rs); void SetRootSignature(ID3D12RootSignature* rs);
@ -115,7 +117,7 @@ public:
void Clear(); void Clear();
Microsoft::WRL::ComPtr<ID3D12PipelineState> Create(ID3D12Device* device, bool clear = true); Microsoft::WRL::ComPtr<ID3D12PipelineState> Create(ID3D12Device* device, Error* error, bool clear);
void SetRootSignature(ID3D12RootSignature* rs); void SetRootSignature(ID3D12RootSignature* rs);

View file

@ -1,18 +1,16 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "d3d12_descriptor_heap_manager.h" #include "d3d12_descriptor_heap_manager.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/log.h" #include "common/error.h"
Log_SetChannel(D3D12Device);
D3D12DescriptorHeapManager::D3D12DescriptorHeapManager() = default; D3D12DescriptorHeapManager::D3D12DescriptorHeapManager() = default;
D3D12DescriptorHeapManager::~D3D12DescriptorHeapManager() = default; D3D12DescriptorHeapManager::~D3D12DescriptorHeapManager() = default;
bool D3D12DescriptorHeapManager::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors, 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 = { D3D12_DESCRIPTOR_HEAP_DESC desc = {
type, static_cast<UINT>(num_descriptors), type, static_cast<UINT>(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())); HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(m_descriptor_heap.ReleaseAndGetAddressOf()));
if (FAILED(hr)) [[unlikely]] if (FAILED(hr)) [[unlikely]]
{ {
ERROR_LOG("CreateDescriptorHeap() failed: {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "CreateDescriptorHeap() failed: ", hr);
return false; return false;
} }
@ -110,14 +108,14 @@ void D3D12DescriptorHeapManager::Free(D3D12DescriptorHandle* handle)
D3D12DescriptorAllocator::D3D12DescriptorAllocator() = default; D3D12DescriptorAllocator::D3D12DescriptorAllocator() = default;
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<UINT>(num_descriptors), const D3D12_DESCRIPTOR_HEAP_DESC desc = {type, static_cast<UINT>(num_descriptors),
D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, 0u}; D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, 0u};
const HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(m_descriptor_heap.ReleaseAndGetAddressOf())); const HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(m_descriptor_heap.ReleaseAndGetAddressOf()));
if (FAILED(hr)) if (FAILED(hr))
{ {
ERROR_LOG("CreateDescriptorHeap() failed: {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "CreateDescriptorHeap() failed: ", hr);
return false; return false;
} }

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once #pragma once
@ -14,6 +14,8 @@
#include <vector> #include <vector>
#include <wrl/client.h> #include <wrl/client.h>
class Error;
// This class provides an abstraction for D3D12 descriptor heaps. // This class provides an abstraction for D3D12 descriptor heaps.
struct D3D12DescriptorHandle final struct D3D12DescriptorHandle final
{ {
@ -55,7 +57,8 @@ public:
ID3D12DescriptorHeap* GetDescriptorHeap() const { return m_descriptor_heap.Get(); } ID3D12DescriptorHeap* GetDescriptorHeap() const { return m_descriptor_heap.Get(); }
u32 GetDescriptorIncrementSize() const { return m_descriptor_increment_size; } 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(); void Destroy();
bool Allocate(D3D12DescriptorHandle* handle); bool Allocate(D3D12DescriptorHandle* handle);
@ -85,7 +88,7 @@ public:
ALWAYS_INLINE ID3D12DescriptorHeap* GetDescriptorHeap() const { return m_descriptor_heap.Get(); } ALWAYS_INLINE ID3D12DescriptorHeap* GetDescriptorHeap() const { return m_descriptor_heap.Get(); }
ALWAYS_INLINE u32 GetDescriptorIncrementSize() const { return m_descriptor_increment_size; } 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(); void Destroy();
bool Allocate(u32 num_handles, D3D12DescriptorHandle* out_base_handle); bool Allocate(u32 num_handles, D3D12DescriptorHandle* out_base_handle);
@ -130,7 +133,7 @@ public:
using D3D12DescriptorAllocator::GetDescriptorHeap; using D3D12DescriptorAllocator::GetDescriptorHeap;
using D3D12DescriptorAllocator::GetDescriptorIncrementSize; using D3D12DescriptorAllocator::GetDescriptorIncrementSize;
bool Create(ID3D12Device* device, u32 num_descriptors); bool Create(ID3D12Device* device, u32 num_descriptors, Error* error);
void Destroy(); void Destroy();
bool LookupSingle(ID3D12Device* device, D3D12DescriptorHandle* gpu_handle, const D3D12DescriptorHandle& cpu_handle); bool LookupSingle(ID3D12Device* device, D3D12DescriptorHandle* gpu_handle, const D3D12DescriptorHandle& cpu_handle);
@ -153,9 +156,9 @@ template<u32 NumSamplers>
D3D12GroupedSamplerAllocator<NumSamplers>::~D3D12GroupedSamplerAllocator() = default; D3D12GroupedSamplerAllocator<NumSamplers>::~D3D12GroupedSamplerAllocator() = default;
template<u32 NumSamplers> template<u32 NumSamplers>
bool D3D12GroupedSamplerAllocator<NumSamplers>::Create(ID3D12Device* device, u32 num_descriptors) bool D3D12GroupedSamplerAllocator<NumSamplers>::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<u32 NumSamplers> template<u32 NumSamplers>

View file

@ -81,7 +81,7 @@ D3D12Device::~D3D12Device()
Assert(s_pipeline_cache_data.empty()); Assert(s_pipeline_cache_data.empty());
} }
D3D12Device::ComPtr<ID3DBlob> D3D12Device::SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc) D3D12Device::ComPtr<ID3DBlob> D3D12Device::SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error)
{ {
ComPtr<ID3DBlob> blob; ComPtr<ID3DBlob> blob;
ComPtr<ID3DBlob> error_blob; ComPtr<ID3DBlob> error_blob;
@ -89,7 +89,7 @@ D3D12Device::ComPtr<ID3DBlob> D3D12Device::SerializeRootSignature(const D3D12_RO
D3D12SerializeRootSignature(desc, D3D_ROOT_SIGNATURE_VERSION_1, blob.GetAddressOf(), error_blob.GetAddressOf()); D3D12SerializeRootSignature(desc, D3D_ROOT_SIGNATURE_VERSION_1, blob.GetAddressOf(), error_blob.GetAddressOf());
if (FAILED(hr)) [[unlikely]] if (FAILED(hr)) [[unlikely]]
{ {
ERROR_LOG("D3D12SerializeRootSignature() failed: {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "D3D12SerializeRootSignature() failed: ", hr);
if (error_blob) if (error_blob)
ERROR_LOG(static_cast<const char*>(error_blob->GetBufferPointer())); ERROR_LOG(static_cast<const char*>(error_blob->GetBufferPointer()));
@ -99,9 +99,10 @@ D3D12Device::ComPtr<ID3DBlob> D3D12Device::SerializeRootSignature(const D3D12_RO
return blob; return blob;
} }
D3D12Device::ComPtr<ID3D12RootSignature> D3D12Device::CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc) D3D12Device::ComPtr<ID3D12RootSignature> D3D12Device::CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc,
Error* error)
{ {
ComPtr<ID3DBlob> blob = SerializeRootSignature(desc); ComPtr<ID3DBlob> blob = SerializeRootSignature(desc, error);
if (!blob) if (!blob)
return {}; return {};
@ -110,7 +111,7 @@ D3D12Device::ComPtr<ID3D12RootSignature> D3D12Device::CreateRootSignature(const
m_device->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(rs.GetAddressOf())); m_device->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(rs.GetAddressOf()));
if (FAILED(hr)) [[unlikely]] if (FAILED(hr)) [[unlikely]]
{ {
ERROR_LOG("CreateRootSignature() failed: {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "CreateRootSignature() failed: ", hr);
return {}; return {};
} }
@ -228,23 +229,14 @@ bool D3D12Device::CreateDevice(std::string_view adapter, bool threaded_presentat
SetFeatures(disabled_features); SetFeatures(disabled_features);
if (!CreateCommandLists() || !CreateDescriptorHeaps()) if (!CreateCommandLists(error) || !CreateDescriptorHeaps(error))
{
Error::SetStringView(error, "Failed to create command lists/descriptor heaps.");
return false; return false;
}
if (!m_window_info.IsSurfaceless() && !CreateSwapChain()) if (!m_window_info.IsSurfaceless() && !CreateSwapChain(error))
{
Error::SetStringView(error, "Failed to create swap chain.");
return false; return false;
}
if (!CreateRootSignatures() || !CreateBuffers()) if (!CreateRootSignatures(error) || !CreateBuffers(error))
{
Error::SetStringView(error, "Failed to create root signature/buffers.");
return false; return false;
}
CreateTimestampQuery(); CreateTimestampQuery();
return true; return true;
@ -349,7 +341,7 @@ bool D3D12Device::GetPipelineCacheData(DynamicHeapArray<u8>* data)
return true; return true;
} }
bool D3D12Device::CreateCommandLists() bool D3D12Device::CreateCommandLists(Error* error)
{ {
for (u32 i = 0; i < NUM_COMMAND_LISTS; i++) for (u32 i = 0; i < NUM_COMMAND_LISTS; i++)
{ {
@ -362,7 +354,7 @@ bool D3D12Device::CreateCommandLists()
IID_PPV_ARGS(res.command_allocators[j].GetAddressOf())); IID_PPV_ARGS(res.command_allocators[j].GetAddressOf()));
if (FAILED(hr)) if (FAILED(hr))
{ {
ERROR_LOG("CreateCommandAllocator() failed: {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "CreateCommandAllocator() failed: ", hr);
return false; return false;
} }
@ -370,7 +362,7 @@ bool D3D12Device::CreateCommandLists()
IID_PPV_ARGS(res.command_lists[j].GetAddressOf())); IID_PPV_ARGS(res.command_lists[j].GetAddressOf()));
if (FAILED(hr)) if (FAILED(hr))
{ {
ERROR_LOG("CreateCommandList() failed: {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "CreateCommandList() failed: ", hr);
return false; return false;
} }
@ -378,21 +370,21 @@ bool D3D12Device::CreateCommandLists()
hr = res.command_lists[j]->Close(); hr = res.command_lists[j]->Close();
if (FAILED(hr)) if (FAILED(hr))
{ {
ERROR_LOG("Close() failed: {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "Close() for new command list failed: ", hr);
return false; return false;
} }
} }
if (!res.descriptor_allocator.Create(m_device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 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; 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; 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, if (!m_descriptor_heap_manager.Create(m_device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
MAX_PERSISTENT_DESCRIPTORS, false) || MAX_PERSISTENT_DESCRIPTORS, false, error) ||
!m_rtv_heap_manager.Create(m_device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, MAX_PERSISTENT_RTVS, false) || !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) || !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, !m_sampler_heap_manager.Create(m_device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, MAX_PERSISTENT_SAMPLERS, false,
false)) error))
{ {
return false; return false;
} }
@ -490,7 +482,7 @@ bool D3D12Device::CreateDescriptorHeaps()
if (!m_descriptor_heap_manager.Allocate(&m_null_srv_descriptor)) 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; return false;
} }
@ -774,10 +766,13 @@ u32 D3D12Device::GetSwapChainBufferCount() const
return (m_vsync_mode == GPUVSyncMode::Mailbox) ? 3 : 2; return (m_vsync_mode == GPUVSyncMode::Mailbox) ? 3 : 2;
} }
bool D3D12Device::CreateSwapChain() bool D3D12Device::CreateSwapChain(Error* error)
{ {
if (m_window_info.type != WindowInfo::Type::Win32) if (m_window_info.type != WindowInfo::Type::Win32)
{
Error::SetStringView(error, "D3D12 expects a Win32 window.");
return false; return false;
}
const D3DCommon::DXGIFormatMapping& fm = D3DCommon::GetFormatMapping(s_swap_chain_format); 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); 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, hr = m_dxgi_factory->CreateSwapChainForHwnd(m_command_queue.Get(), window_hwnd, &swap_chain_desc, nullptr, nullptr,
m_swap_chain.ReleaseAndGetAddressOf()); 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); hr = m_dxgi_factory->MakeWindowAssociation(window_hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
if (FAILED(hr)) if (FAILED(hr))
WARNING_LOG("MakeWindowAssociation() to disable ALT+ENTER failed"); WARNING_LOG("MakeWindowAssociation() to disable ALT+ENTER failed");
if (!CreateSwapChainRTV()) if (!CreateSwapChainRTV(error))
{ {
DestroySwapChain(); DestroySwapChain();
return false; return false;
@ -870,12 +870,15 @@ bool D3D12Device::CreateSwapChain()
return true; return true;
} }
bool D3D12Device::CreateSwapChainRTV() bool D3D12Device::CreateSwapChainRTV(Error* error)
{ {
DXGI_SWAP_CHAIN_DESC swap_chain_desc; DXGI_SWAP_CHAIN_DESC swap_chain_desc;
HRESULT hr = m_swap_chain->GetDesc(&swap_chain_desc); HRESULT hr = m_swap_chain->GetDesc(&swap_chain_desc);
if (FAILED(hr)) if (FAILED(hr))
{
Error::SetHResult(error, "GetDesc() for swap chain failed: ", hr);
return false; return false;
}
const D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {swap_chain_desc.BufferDesc.Format, D3D12_RTV_DIMENSION_TEXTURE2D, {}}; 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())); hr = m_swap_chain->GetBuffer(i, IID_PPV_ARGS(backbuffer.GetAddressOf()));
if (FAILED(hr)) if (FAILED(hr))
{ {
ERROR_LOG("GetBuffer for RTV failed: 0x{:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "GetBuffer for RTV failed: ", hr);
DestroySwapChainRTVs(); DestroySwapChainRTVs();
return false; return false;
} }
@ -895,7 +898,7 @@ bool D3D12Device::CreateSwapChainRTV()
D3D12DescriptorHandle rtv; D3D12DescriptorHandle rtv;
if (!m_rtv_heap_manager.Allocate(&rtv)) if (!m_rtv_heap_manager.Allocate(&rtv))
{ {
ERROR_LOG("Failed to allocate RTV handle"); Error::SetStringView(error, "Failed to allocate RTV handle.");
DestroySwapChainRTVs(); DestroySwapChainRTVs();
return false; return false;
} }
@ -985,9 +988,10 @@ bool D3D12Device::UpdateWindow()
if (m_window_info.IsSurfaceless()) if (m_window_info.IsSurfaceless())
return true; 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; return false;
} }
@ -1015,8 +1019,12 @@ void D3D12Device::ResizeWindow(s32 new_window_width, s32 new_window_height, floa
if (FAILED(hr)) if (FAILED(hr))
ERROR_LOG("ResizeBuffers() failed: 0x{:08X}", static_cast<unsigned>(hr)); ERROR_LOG("ResizeBuffers() failed: 0x{:08X}", static_cast<unsigned>(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"); Panic("Failed to recreate swap chain RTV after resize");
}
} }
void D3D12Device::DestroySurface() void D3D12Device::DestroySurface()
@ -1083,8 +1091,13 @@ void D3D12Device::SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle)
if (GetSwapChainBufferCount() != old_buffer_count) if (GetSwapChainBufferCount() != old_buffer_count)
{ {
DestroySwapChain(); 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."); Panic("Failed to recreate swap chain after vsync change.");
}
} }
} }
@ -1382,27 +1395,27 @@ void D3D12Device::InvalidateRenderTarget(GPUTexture* t)
EndRenderPass(); 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"); ERROR_LOG("Failed to allocate vertex buffer");
return false; 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"); ERROR_LOG("Failed to allocate index buffer");
return false; 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"); ERROR_LOG("Failed to allocate uniform buffer");
return false; 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"); ERROR_LOG("Failed to allocate texture upload buffer");
return false; return false;
@ -1509,7 +1522,7 @@ void D3D12Device::UnmapUniformBuffer(u32 size)
m_dirty_flags |= DIRTY_FLAG_CONSTANT_BUFFER; m_dirty_flags |= DIRTY_FLAG_CONSTANT_BUFFER;
} }
bool D3D12Device::CreateRootSignatures() bool D3D12Device::CreateRootSignatures(Error* error)
{ {
D3D12::RootSignatureBuilder rsb; 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_SRV, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 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); rsb.AddCBVParameter(0, D3D12_SHADER_VISIBILITY_ALL);
if (!(rs = rsb.Create())) if (!(rs = rsb.Create(error, true)))
return false; return false;
D3D12::SetObjectName(rs.Get(), "Single Texture + UBO Pipeline Layout"); 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_SRV, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 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); 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; return false;
D3D12::SetObjectName(rs.Get(), "Single Texture Pipeline Layout"); D3D12::SetObjectName(rs.Get(), "Single Texture Pipeline Layout");
} }
@ -1543,7 +1556,7 @@ bool D3D12Device::CreateRootSignatures()
rsb.SetInputAssemblerFlag(); rsb.SetInputAssemblerFlag();
rsb.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL); 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); 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; return false;
D3D12::SetObjectName(rs.Get(), "Single Texture Buffer + UBO Pipeline Layout"); 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_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.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, MAX_TEXTURE_SAMPLERS, D3D12_SHADER_VISIBILITY_PIXEL);
rsb.AddCBVParameter(0, D3D12_SHADER_VISIBILITY_ALL); rsb.AddCBVParameter(0, D3D12_SHADER_VISIBILITY_ALL);
if (!(rs = rsb.Create())) if (!(rs = rsb.Create(error, true)))
return false; return false;
D3D12::SetObjectName(rs.Get(), "Multi Texture + UBO Pipeline Layout"); 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_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.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); 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; return false;
D3D12::SetObjectName(rs.Get(), "Multi Texture Pipeline Layout"); D3D12::SetObjectName(rs.Get(), "Multi Texture Pipeline Layout");
} }

View file

@ -95,7 +95,7 @@ public:
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language, std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
std::string_view source, const char* entry_point, std::string_view source, const char* entry_point,
DynamicHeapArray<u8>* out_binary, Error* error) override; DynamicHeapArray<u8>* out_binary, Error* error) override;
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override; std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) override;
void PushDebugGroup(const char* name) override; void PushDebugGroup(const char* name) override;
void PopDebugGroup() override; void PopDebugGroup() override;
@ -155,8 +155,8 @@ public:
ID3D12GraphicsCommandList4* GetInitCommandList(); ID3D12GraphicsCommandList4* GetInitCommandList();
// Root signature access. // Root signature access.
ComPtr<ID3DBlob> SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc); ComPtr<ID3DBlob> SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error);
ComPtr<ID3D12RootSignature> CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc); ComPtr<ID3D12RootSignature> CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc, Error* error);
/// Fence value for current command list. /// Fence value for current command list.
u64 GetCurrentFenceValue() const { return m_current_fence_value; } u64 GetCurrentFenceValue() const { return m_current_fence_value; }
@ -223,18 +223,18 @@ private:
void SetFeatures(FeatureMask disabled_features); void SetFeatures(FeatureMask disabled_features);
u32 GetSwapChainBufferCount() const; u32 GetSwapChainBufferCount() const;
bool CreateSwapChain(); bool CreateSwapChain(Error* error);
bool CreateSwapChainRTV(); bool CreateSwapChainRTV(Error* error);
void DestroySwapChainRTVs(); void DestroySwapChainRTVs();
void DestroySwapChain(); void DestroySwapChain();
bool CreateCommandLists(); bool CreateCommandLists(Error* error);
void DestroyCommandLists(); void DestroyCommandLists();
bool CreateRootSignatures(); bool CreateRootSignatures(Error* error);
void DestroyRootSignatures(); void DestroyRootSignatures();
bool CreateBuffers(); bool CreateBuffers(Error* error);
void DestroyBuffers(); void DestroyBuffers();
bool CreateDescriptorHeaps(); bool CreateDescriptorHeaps(Error* error);
void DestroyDescriptorHeaps(); void DestroyDescriptorHeaps();
bool CreateTimestampQuery(); bool CreateTimestampQuery();
void DestroyTimestampQuery(); void DestroyTimestampQuery();

View file

@ -106,7 +106,7 @@ std::string D3D12Pipeline::GetPipelineName(const GraphicsConfig& config)
return SHA1Digest::DigestToString(digest); return SHA1Digest::DigestToString(digest);
} }
std::unique_ptr<GPUPipeline> D3D12Device::CreatePipeline(const GPUPipeline::GraphicsConfig& config) std::unique_ptr<GPUPipeline> D3D12Device::CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error)
{ {
static constexpr std::array<D3D12_PRIMITIVE_TOPOLOGY, static_cast<u32>(GPUPipeline::Primitive::MaxCount)> primitives = static constexpr std::array<D3D12_PRIMITIVE_TOPOLOGY, static_cast<u32>(GPUPipeline::Primitive::MaxCount)> primitives =
{{ {{
@ -242,7 +242,7 @@ std::unique_ptr<GPUPipeline> D3D12Device::CreatePipeline(const GPUPipeline::Grap
ERROR_LOG("LoadGraphicsPipeline() failed with HRESULT {:08X}", static_cast<unsigned>(hr)); ERROR_LOG("LoadGraphicsPipeline() failed with HRESULT {:08X}", static_cast<unsigned>(hr));
// Need to create it normally. // 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. // Store if it wasn't an OOM or something else.
if (pipeline && hr == E_INVALIDARG) if (pipeline && hr == E_INVALIDARG)
@ -255,7 +255,7 @@ std::unique_ptr<GPUPipeline> D3D12Device::CreatePipeline(const GPUPipeline::Grap
} }
else else
{ {
pipeline = gpb.Create(m_device.Get(), false); pipeline = gpb.Create(m_device.Get(), error, false);
} }
if (!pipeline) if (!pipeline)

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "d3d12_stream_buffer.h" #include "d3d12_stream_buffer.h"
@ -6,6 +6,7 @@
#include "common/align.h" #include "common/align.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/error.h"
#include "common/log.h" #include "common/log.h"
#include "D3D12MemAlloc.h" #include "D3D12MemAlloc.h"
@ -21,7 +22,7 @@ D3D12StreamBuffer::~D3D12StreamBuffer()
Destroy(); Destroy();
} }
bool D3D12StreamBuffer::Create(u32 size) bool D3D12StreamBuffer::Create(u32 size, Error* error)
{ {
const D3D12_RESOURCE_DESC resource_desc = { 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, 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())); IID_PPV_ARGS(buffer.GetAddressOf()));
if (FAILED(hr)) [[unlikely]] if (FAILED(hr)) [[unlikely]]
{ {
ERROR_LOG("CreateResource() failed: {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "CreateResource() for stream buffer failed: ", hr);
return false; return false;
} }
@ -47,7 +48,7 @@ bool D3D12StreamBuffer::Create(u32 size)
hr = buffer->Map(0, &read_range, reinterpret_cast<void**>(&host_pointer)); hr = buffer->Map(0, &read_range, reinterpret_cast<void**>(&host_pointer));
if (FAILED(hr)) [[unlikely]] if (FAILED(hr)) [[unlikely]]
{ {
ERROR_LOG("Map() failed: {:08X}", static_cast<unsigned>(hr)); Error::SetHResult(error, "Map() for stream buffer failed: ", hr);
return false; return false;
} }

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once #pragma once
@ -11,6 +11,8 @@
#include <utility> #include <utility>
#include <wrl/client.h> #include <wrl/client.h>
class Error;
namespace D3D12MA { namespace D3D12MA {
class Allocation; class Allocation;
} }
@ -21,7 +23,7 @@ public:
D3D12StreamBuffer(); D3D12StreamBuffer();
~D3D12StreamBuffer(); ~D3D12StreamBuffer();
bool Create(u32 size); bool Create(u32 size, Error* error);
ALWAYS_INLINE bool IsValid() const { return static_cast<bool>(m_buffer); } ALWAYS_INLINE bool IsValid() const { return static_cast<bool>(m_buffer); }
ALWAYS_INLINE ID3D12Resource* GetBuffer() const { return m_buffer.Get(); } ALWAYS_INLINE ID3D12Resource* GetBuffer() const { return m_buffer.Get(); }

View file

@ -9,6 +9,7 @@
#include "common/align.h" #include "common/align.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/bitutils.h" #include "common/bitutils.h"
#include "common/error.h"
#include "common/log.h" #include "common/log.h"
#include "common/string_util.h" #include "common/string_util.h"
@ -763,10 +764,14 @@ bool D3D12TextureBuffer::Create(D3D12Device& dev)
DXGI_FORMAT_R16_UINT, // R16UI 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; return false;
}
if (!dev.GetDescriptorHeapManager().Allocate(&m_descriptor)) if (!dev.GetDescriptorHeapManager().Allocate(&m_descriptor)) [[unlikely]]
return {}; return {};
D3D12_SHADER_RESOURCE_VIEW_DESC desc = {format_mapping[static_cast<u8>(m_format)], D3D12_SHADER_RESOURCE_VIEW_DESC desc = {format_mapping[static_cast<u8>(m_format)],

View file

@ -533,7 +533,10 @@ bool GPUDevice::CreateResources(Error* error)
std::unique_ptr<GPUShader> imgui_fs = std::unique_ptr<GPUShader> imgui_fs =
CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(), shadergen.GenerateImGuiFragmentShader(), error); CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(), shadergen.GenerateImGuiFragmentShader(), error);
if (!imgui_vs || !imgui_fs) if (!imgui_vs || !imgui_fs)
{
Error::AddPrefix(error, "Failed to compile ImGui shaders: ");
return false; return false;
}
GL_OBJECT_NAME(imgui_vs, "ImGui Vertex Shader"); GL_OBJECT_NAME(imgui_vs, "ImGui Vertex Shader");
GL_OBJECT_NAME(imgui_fs, "ImGui Fragment Shader"); GL_OBJECT_NAME(imgui_fs, "ImGui Fragment Shader");
@ -563,10 +566,10 @@ bool GPUDevice::CreateResources(Error* error)
plconfig.geometry_shader = nullptr; plconfig.geometry_shader = nullptr;
plconfig.fragment_shader = imgui_fs.get(); plconfig.fragment_shader = imgui_fs.get();
m_imgui_pipeline = CreatePipeline(plconfig); m_imgui_pipeline = CreatePipeline(plconfig, error);
if (!m_imgui_pipeline) if (!m_imgui_pipeline)
{ {
Error::SetStringView(error, "Failed to compile ImGui pipeline."); Error::AddPrefix(error, "Failed to compile ImGui pipeline: ");
return false; return false;
} }
GL_OBJECT_NAME(m_imgui_pipeline, "ImGui Pipeline"); GL_OBJECT_NAME(m_imgui_pipeline, "ImGui Pipeline");

View file

@ -650,7 +650,8 @@ public:
/// Shader abstraction. /// Shader abstraction.
std::unique_ptr<GPUShader> CreateShader(GPUShaderStage stage, GPUShaderLanguage language, std::string_view source, std::unique_ptr<GPUShader> CreateShader(GPUShaderStage stage, GPUShaderLanguage language, std::string_view source,
Error* error = nullptr, const char* entry_point = "main"); Error* error = nullptr, const char* entry_point = "main");
virtual std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) = 0; virtual std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config,
Error* error = nullptr) = 0;
/// Debug messaging. /// Debug messaging.
virtual void PushDebugGroup(const char* name) = 0; virtual void PushDebugGroup(const char* name) = 0;

View file

@ -235,7 +235,7 @@ public:
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language, std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
std::string_view source, const char* entry_point, std::string_view source, const char* entry_point,
DynamicHeapArray<u8>* out_binary, Error* error) override; DynamicHeapArray<u8>* out_binary, Error* error) override;
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override; std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) override;
void PushDebugGroup(const char* name) override; void PushDebugGroup(const char* name) override;
void PopDebugGroup() override; void PopDebugGroup() override;

View file

@ -76,6 +76,11 @@ static void LogNSError(NSError* error, std::string_view message)
Log::FastWrite("MetalDevice", LOGLEVEL_ERROR, " NSError Description: {}", [error.description UTF8String]); 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<u32>(error.code), [error.description UTF8String]);
}
static GPUTexture::Format GetTextureFormatForMTLFormat(MTLPixelFormat fmt) static GPUTexture::Format GetTextureFormatForMTLFormat(MTLPixelFormat fmt)
{ {
for (u32 i = 0; i < static_cast<u32>(GPUTexture::Format::MaxCount); i++) for (u32 i = 0; i < static_cast<u32>(GPUTexture::Format::MaxCount); i++)
@ -719,7 +724,7 @@ id<MTLDepthStencilState> MetalDevice::GetDepthState(const GPUPipeline::DepthStat
} }
} }
std::unique_ptr<GPUPipeline> MetalDevice::CreatePipeline(const GPUPipeline::GraphicsConfig& config) std::unique_ptr<GPUPipeline> MetalDevice::CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error)
{ {
@autoreleasepool @autoreleasepool
{ {
@ -857,11 +862,12 @@ std::unique_ptr<GPUPipeline> MetalDevice::CreatePipeline(const GPUPipeline::Grap
if (config.layout == GPUPipeline::Layout::SingleTextureBufferAndPushConstants) if (config.layout == GPUPipeline::Layout::SingleTextureBufferAndPushConstants)
desc.fragmentBuffers[1].mutability = MTLMutabilityImmutable; desc.fragmentBuffers[1].mutability = MTLMutabilityImmutable;
NSError* error = nullptr; NSError* nserror = nullptr;
id<MTLRenderPipelineState> pipeline = [m_device newRenderPipelineStateWithDescriptor:desc error:&error]; id<MTLRenderPipelineState> pipeline = [m_device newRenderPipelineStateWithDescriptor:desc error:&nserror];
if (pipeline == nil) 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 {}; return {};
} }

View file

@ -10,6 +10,7 @@
#include "common/align.h" #include "common/align.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/error.h"
#include "common/log.h" #include "common/log.h"
#include "common/string_util.h" #include "common/string_util.h"
@ -50,6 +51,11 @@ bool OpenGLDevice::ShouldUsePBOsForDownloads()
return !GetInstance().m_disable_pbo && !GetInstance().m_disable_async_download; 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<unsigned>(glerr));
}
RenderAPI OpenGLDevice::GetRenderAPI() const RenderAPI OpenGLDevice::GetRenderAPI() const
{ {
return m_gl_context->IsGLES() ? RenderAPI::OpenGLES : RenderAPI::OpenGL; return m_gl_context->IsGLES() ? RenderAPI::OpenGLES : RenderAPI::OpenGL;

View file

@ -13,6 +13,7 @@
#include <cstdio> #include <cstdio>
#include <memory> #include <memory>
#include <string_view>
#include <tuple> #include <tuple>
class OpenGLPipeline; class OpenGLPipeline;
@ -37,6 +38,7 @@ public:
ALWAYS_INLINE static bool IsGLES() { return GetInstance().m_gl_context->IsGLES(); } ALWAYS_INLINE static bool IsGLES() { return GetInstance().m_gl_context->IsGLES(); }
static void BindUpdateTextureUnit(); static void BindUpdateTextureUnit();
static bool ShouldUsePBOsForDownloads(); static bool ShouldUsePBOsForDownloads();
static void SetErrorObject(Error* errptr, std::string_view prefix, GLenum glerr);
RenderAPI GetRenderAPI() const override; RenderAPI GetRenderAPI() const override;
@ -75,7 +77,7 @@ public:
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language, std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
std::string_view source, const char* entry_point, std::string_view source, const char* entry_point,
DynamicHeapArray<u8>* out_binary, Error* error) override; DynamicHeapArray<u8>* out_binary, Error* error) override;
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override; std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) override;
void PushDebugGroup(const char* name) override; void PushDebugGroup(const char* name) override;
void PopDebugGroup() override; void PopDebugGroup() override;
@ -113,13 +115,13 @@ public:
void CommitRTClearInFB(OpenGLTexture* tex, u32 idx); void CommitRTClearInFB(OpenGLTexture* tex, u32 idx);
void CommitDSClearInFB(OpenGLTexture* tex); void CommitDSClearInFB(OpenGLTexture* tex);
GLuint LookupProgramCache(const OpenGLPipeline::ProgramCacheKey& key, const GPUPipeline::GraphicsConfig& plconfig); GLuint LookupProgramCache(const OpenGLPipeline::ProgramCacheKey& key, const GPUPipeline::GraphicsConfig& plconfig, Error* error);
GLuint CompileProgram(const GPUPipeline::GraphicsConfig& plconfig); GLuint CompileProgram(const GPUPipeline::GraphicsConfig& plconfig, Error* error);
void PostLinkProgram(const GPUPipeline::GraphicsConfig& plconfig, GLuint program_id); void PostLinkProgram(const GPUPipeline::GraphicsConfig& plconfig, GLuint program_id);
void UnrefProgram(const OpenGLPipeline::ProgramCacheKey& key); void UnrefProgram(const OpenGLPipeline::ProgramCacheKey& key);
OpenGLPipeline::VertexArrayCache::const_iterator LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key); OpenGLPipeline::VertexArrayCache::const_iterator LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key, Error* error);
GLuint CreateVAO(std::span<const GPUPipeline::VertexAttribute> attributes, u32 stride); GLuint CreateVAO(std::span<const GPUPipeline::VertexAttribute> attributes, u32 stride, Error* error);
void UnrefVAO(const OpenGLPipeline::VertexArrayCacheKey& key); void UnrefVAO(const OpenGLPipeline::VertexArrayCacheKey& key);
void SetActiveTexture(u32 slot); void SetActiveTexture(u32 slot);

View file

@ -98,10 +98,18 @@ void OpenGLShader::SetDebugName(std::string_view name)
#endif #endif
} }
bool OpenGLShader::Compile() bool OpenGLShader::Compile(Error* error)
{ {
if (m_compile_tried) 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; m_compile_tried = true;
@ -111,6 +119,7 @@ bool OpenGLShader::Compile()
if (GLenum err = glGetError(); err != GL_NO_ERROR) if (GLenum err = glGetError(); err != GL_NO_ERROR)
{ {
ERROR_LOG("glCreateShader() failed: {}", err); ERROR_LOG("glCreateShader() failed: {}", err);
OpenGLDevice::SetErrorObject(error, "glCreateShader() failed: ", err);
return false; return false;
} }
@ -138,6 +147,7 @@ bool OpenGLShader::Compile()
else else
{ {
ERROR_LOG("Shader failed to compile:\n{}", info_log); 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); GPUDevice::DumpBadShader(m_source, info_log);
glDeleteShader(shader); glDeleteShader(shader);
return false; return false;
@ -268,7 +278,7 @@ OpenGLPipeline::ProgramCacheKey OpenGLPipeline::GetProgramCacheKey(const Graphic
} }
GLuint OpenGLDevice::LookupProgramCache(const OpenGLPipeline::ProgramCacheKey& key, GLuint OpenGLDevice::LookupProgramCache(const OpenGLPipeline::ProgramCacheKey& key,
const GPUPipeline::GraphicsConfig& plconfig) const GPUPipeline::GraphicsConfig& plconfig, Error* error)
{ {
auto it = m_program_cache.find(key); auto it = m_program_cache.find(key);
if (it != m_program_cache.end() && it->second.program_id == 0 && it->second.file_uncompressed_size > 0) 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; return it->second.program_id;
} }
const GLuint program_id = CompileProgram(plconfig); const GLuint program_id = CompileProgram(plconfig, error);
if (program_id == 0) if (program_id == 0)
{ {
// Compile failed, don't add to map, it just gets confusing. // 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; 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<OpenGLShader*>(plconfig.vertex_shader); OpenGLShader* vertex_shader = static_cast<OpenGLShader*>(plconfig.vertex_shader);
OpenGLShader* fragment_shader = static_cast<OpenGLShader*>(plconfig.fragment_shader); OpenGLShader* fragment_shader = static_cast<OpenGLShader*>(plconfig.fragment_shader);
OpenGLShader* geometry_shader = static_cast<OpenGLShader*>(plconfig.geometry_shader); OpenGLShader* geometry_shader = static_cast<OpenGLShader*>(plconfig.geometry_shader);
if (!vertex_shader || !fragment_shader || !vertex_shader->Compile() || !fragment_shader->Compile() || if (!vertex_shader || !fragment_shader || !vertex_shader->Compile(error) || !fragment_shader->Compile(error) ||
(geometry_shader && !geometry_shader->Compile())) [[unlikely]] (geometry_shader && !geometry_shader->Compile(error))) [[unlikely]]
{ {
ERROR_LOG("Failed to compile shaders.");
return 0; return 0;
} }
glGetError(); glGetError();
const GLuint program_id = glCreateProgram(); 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; return 0;
} }
@ -412,6 +421,7 @@ GLuint OpenGLDevice::CompileProgram(const GPUPipeline::GraphicsConfig& plconfig)
} }
ERROR_LOG("Program failed to link:\n{}", info_log); ERROR_LOG("Program failed to link:\n{}", info_log);
Error::SetStringFmt(error, "Program failed to link:\n{}", info_log);
glDeleteProgram(program_id); glDeleteProgram(program_id);
return 0; return 0;
} }
@ -468,7 +478,7 @@ void OpenGLDevice::UnrefProgram(const OpenGLPipeline::ProgramCacheKey& key)
} }
OpenGLPipeline::VertexArrayCache::const_iterator 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); OpenGLPipeline::VertexArrayCache::iterator it = m_vao_cache.find(key);
if (it != m_vao_cache.end()) if (it != m_vao_cache.end())
@ -480,7 +490,7 @@ OpenGLDevice::LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key)
OpenGLPipeline::VertexArrayCacheItem item; OpenGLPipeline::VertexArrayCacheItem item;
item.vao_id = item.vao_id =
CreateVAO(std::span<const GPUPipeline::VertexAttribute>(key.vertex_attributes, key.num_vertex_attributes), CreateVAO(std::span<const GPUPipeline::VertexAttribute>(key.vertex_attributes, key.num_vertex_attributes),
key.vertex_attribute_stride); key.vertex_attribute_stride, error);
if (item.vao_id == 0) if (item.vao_id == 0)
return m_vao_cache.cend(); return m_vao_cache.cend();
@ -488,7 +498,7 @@ OpenGLDevice::LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key)
return m_vao_cache.emplace(key, item).first; return m_vao_cache.emplace(key, item).first;
} }
GLuint OpenGLDevice::CreateVAO(std::span<const GPUPipeline::VertexAttribute> attributes, u32 stride) GLuint OpenGLDevice::CreateVAO(std::span<const GPUPipeline::VertexAttribute> attributes, u32 stride, Error* error)
{ {
glGetError(); glGetError();
GLuint vao; GLuint vao;
@ -496,6 +506,7 @@ GLuint OpenGLDevice::CreateVAO(std::span<const GPUPipeline::VertexAttribute> att
if (const GLenum err = glGetError(); err != GL_NO_ERROR) if (const GLenum err = glGetError(); err != GL_NO_ERROR)
{ {
ERROR_LOG("Failed to create vertex array object: {}", err); ERROR_LOG("Failed to create vertex array object: {}", err);
SetErrorObject(error, "glGenVertexArrays() failed: ", err);
return 0; return 0;
} }
@ -582,15 +593,15 @@ void OpenGLPipeline::SetDebugName(std::string_view name)
#endif #endif
} }
std::unique_ptr<GPUPipeline> OpenGLDevice::CreatePipeline(const GPUPipeline::GraphicsConfig& config) std::unique_ptr<GPUPipeline> OpenGLDevice::CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error)
{ {
const OpenGLPipeline::ProgramCacheKey pkey = OpenGLPipeline::GetProgramCacheKey(config); 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) if (program_id == 0)
return {}; 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()) if (vao == m_vao_cache.cend())
{ {
UnrefProgram(pkey); UnrefProgram(pkey);

View file

@ -18,7 +18,7 @@ public:
void SetDebugName(std::string_view name) override; void SetDebugName(std::string_view name) override;
bool Compile(); bool Compile(Error* error);
ALWAYS_INLINE GLuint GetGLId() const { return m_id.value(); } ALWAYS_INLINE GLuint GetGLId() const { return m_id.value(); }
ALWAYS_INLINE const GPUShaderCache::CacheIndexKey& GetKey() const { return m_key; } ALWAYS_INLINE const GPUShaderCache::CacheIndexKey& GetKey() const { return m_key; }

View file

@ -1,9 +1,10 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "vulkan_builders.h" #include "vulkan_builders.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/error.h"
#include "common/log.h" #include "common/log.h"
#include <limits> #include <limits>
@ -109,6 +110,11 @@ void Vulkan::LogVulkanResult(const char* func_name, VkResult res, std::string_vi
VkResultToString(res)); VkResultToString(res));
} }
void Vulkan::SetErrorObject(Error* errptr, std::string_view prefix, VkResult res)
{
Error::SetStringFmt(errptr, "{} (0x{:08X}: {})", prefix, static_cast<unsigned>(res), VkResultToString(res));
}
Vulkan::DescriptorSetLayoutBuilder::DescriptorSetLayoutBuilder() Vulkan::DescriptorSetLayoutBuilder::DescriptorSetLayoutBuilder()
{ {
Clear(); Clear();
@ -277,14 +283,15 @@ void Vulkan::GraphicsPipelineBuilder::Clear()
SetMultisamples(VK_SAMPLE_COUNT_1_BIT); SetMultisamples(VK_SAMPLE_COUNT_1_BIT);
} }
VkPipeline Vulkan::GraphicsPipelineBuilder::Create(VkDevice device, VkPipelineCache pipeline_cache, VkPipeline Vulkan::GraphicsPipelineBuilder::Create(VkDevice device, VkPipelineCache pipeline_cache, bool clear,
bool clear /* = true */) Error* error)
{ {
VkPipeline pipeline; VkPipeline pipeline;
VkResult res = vkCreateGraphicsPipelines(device, pipeline_cache, 1, &m_ci, nullptr, &pipeline); VkResult res = vkCreateGraphicsPipelines(device, pipeline_cache, 1, &m_ci, nullptr, &pipeline);
if (res != VK_SUCCESS) if (res != VK_SUCCESS)
{ {
LOG_VULKAN_ERROR(res, "vkCreateGraphicsPipelines() failed: "); LOG_VULKAN_ERROR(res, "vkCreateGraphicsPipelines() failed: ");
SetErrorObject(error, "vkCreateGraphicsPipelines() failed: ", res);
return VK_NULL_HANDLE; return VK_NULL_HANDLE;
} }

View file

@ -12,6 +12,8 @@
#include <array> #include <array>
#include <string_view> #include <string_view>
class Error;
#if defined(_DEBUG) && !defined(CPU_ARCH_ARM32) && !defined(CPU_ARCH_X86) #if defined(_DEBUG) && !defined(CPU_ARCH_ARM32) && !defined(CPU_ARCH_X86)
#define ENABLE_VULKAN_DEBUG_OBJECTS 1 #define ENABLE_VULKAN_DEBUG_OBJECTS 1
#endif #endif
@ -24,6 +26,7 @@ void AddPointerToChain(void* head, const void* ptr);
const char* VkResultToString(VkResult res); const char* VkResultToString(VkResult res);
void LogVulkanResult(const char* func_name, VkResult res, std::string_view msg); void LogVulkanResult(const char* func_name, VkResult res, std::string_view msg);
void SetErrorObject(Error* errptr, std::string_view prefix, VkResult res);
class DescriptorSetLayoutBuilder class DescriptorSetLayoutBuilder
{ {
@ -89,7 +92,7 @@ public:
void Clear(); 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 SetShaderStage(VkShaderStageFlagBits stage, VkShaderModule module, const char* entry_point);
void SetVertexShader(VkShaderModule module) { SetShaderStage(VK_SHADER_STAGE_VERTEX_BIT, module, "main"); } void SetVertexShader(VkShaderModule module) { SetShaderStage(VK_SHADER_STAGE_VERTEX_BIT, module, "main"); }

View file

@ -104,11 +104,12 @@ public:
void ClearDepth(GPUTexture* t, float d) override; void ClearDepth(GPUTexture* t, float d) override;
void InvalidateRenderTarget(GPUTexture* t) override; void InvalidateRenderTarget(GPUTexture* t) override;
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data, Error* error) override; std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
Error* error) override;
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language, std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
std::string_view source, const char* entry_point, std::string_view source, const char* entry_point,
DynamicHeapArray<u8>* out_binary, Error* error) override; DynamicHeapArray<u8>* out_binary, Error* error) override;
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override; std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error) override;
void PushDebugGroup(const char* name) override; void PushDebugGroup(const char* name) override;
void PopDebugGroup() override; void PopDebugGroup() override;

View file

@ -88,7 +88,7 @@ void VulkanPipeline::SetDebugName(std::string_view name)
Vulkan::SetObjectName(VulkanDevice::GetInstance().GetVulkanDevice(), m_pipeline, name); Vulkan::SetObjectName(VulkanDevice::GetInstance().GetVulkanDevice(), m_pipeline, name);
} }
std::unique_ptr<GPUPipeline> VulkanDevice::CreatePipeline(const GPUPipeline::GraphicsConfig& config) std::unique_ptr<GPUPipeline> VulkanDevice::CreatePipeline(const GPUPipeline::GraphicsConfig& config, Error* error)
{ {
static constexpr std::array<std::pair<VkPrimitiveTopology, u32>, static_cast<u32>(GPUPipeline::Primitive::MaxCount)> static constexpr std::array<std::pair<VkPrimitiveTopology, u32>, static_cast<u32>(GPUPipeline::Primitive::MaxCount)>
primitives = {{ primitives = {{
@ -243,7 +243,7 @@ std::unique_ptr<GPUPipeline> VulkanDevice::CreatePipeline(const GPUPipeline::Gra
gpb.SetRenderPass(render_pass, 0); 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) if (!pipeline)
return {}; return {};