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::string_view source, const char* entry_point,
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 PopDebugGroup() override;
@ -144,10 +144,10 @@ private:
bool IsRenderTargetBound(const GPUTexture* tex) const;
ComPtr<ID3D11RasterizerState> GetRasterizationState(const GPUPipeline::RasterizationState& rs);
ComPtr<ID3D11DepthStencilState> GetDepthState(const GPUPipeline::DepthState& ds);
ComPtr<ID3D11BlendState> GetBlendState(const GPUPipeline::BlendState& bs);
ComPtr<ID3D11InputLayout> GetInputLayout(const GPUPipeline::InputLayout& il, const D3D11Shader* vs);
ComPtr<ID3D11RasterizerState> GetRasterizationState(const GPUPipeline::RasterizationState& rs, Error* error);
ComPtr<ID3D11DepthStencilState> GetDepthState(const GPUPipeline::DepthState& ds, Error* error);
ComPtr<ID3D11BlendState> GetBlendState(const GPUPipeline::BlendState& bs, Error* error);
ComPtr<ID3D11InputLayout> GetInputLayout(const GPUPipeline::InputLayout& il, const D3D11Shader* vs, Error* error);
bool CreateTimestampQueries();
void DestroyTimestampQueries();

View file

@ -6,15 +6,12 @@
#include "d3d_common.h"
#include "common/error.h"
#include "common/log.h"
#include "fmt/format.h"
#include <array>
#include <malloc.h>
Log_SetChannel(D3D11Device);
D3D11Shader::D3D11Shader(GPUShaderStage stage, Microsoft::WRL::ComPtr<ID3D11DeviceChild> shader,
std::vector<u8> 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<ID3D11RasterizerState> D3D11Device::GetRasterizationState(const GPUPipeline::RasterizationState& rs)
D3D11Device::ComPtr<ID3D11RasterizerState> D3D11Device::GetRasterizationState(const GPUPipeline::RasterizationState& rs,
Error* error)
{
ComPtr<ID3D11RasterizerState> drs;
@ -165,13 +163,14 @@ D3D11Device::ComPtr<ID3D11RasterizerState> 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<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;
}
D3D11Device::ComPtr<ID3D11DepthStencilState> D3D11Device::GetDepthState(const GPUPipeline::DepthState& ds)
D3D11Device::ComPtr<ID3D11DepthStencilState> D3D11Device::GetDepthState(const GPUPipeline::DepthState& ds, Error* error)
{
ComPtr<ID3D11DepthStencilState> dds;
@ -200,13 +199,14 @@ D3D11Device::ComPtr<ID3D11DepthStencilState> 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<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;
}
D3D11Device::ComPtr<ID3D11BlendState> D3D11Device::GetBlendState(const GPUPipeline::BlendState& bs)
D3D11Device::ComPtr<ID3D11BlendState> D3D11Device::GetBlendState(const GPUPipeline::BlendState& bs, Error* error)
{
ComPtr<ID3D11BlendState> dbs;
@ -258,14 +258,15 @@ D3D11Device::ComPtr<ID3D11BlendState> 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<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;
}
D3D11Device::ComPtr<ID3D11InputLayout> D3D11Device::GetInputLayout(const GPUPipeline::InputLayout& il,
const D3D11Shader* vs)
const D3D11Shader* vs, Error* error)
{
ComPtr<ID3D11InputLayout> dil;
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()),
vs->GetBytecode().data(), vs->GetBytecode().size(), dil.GetAddressOf());
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;
}
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<ID3D11DepthStencilState> ds = GetDepthState(config.depth);
ComPtr<ID3D11BlendState> bs = GetBlendState(config.blend);
ComPtr<ID3D11RasterizerState> rs = GetRasterizationState(config.rasterization, error);
ComPtr<ID3D11DepthStencilState> ds = GetDepthState(config.depth, error);
ComPtr<ID3D11BlendState> bs = GetBlendState(config.blend, error);
if (!rs || !ds || !bs)
return {};
@ -328,7 +330,7 @@ std::unique_ptr<GPUPipeline> D3D11Device::CreatePipeline(const GPUPipeline::Grap
u32 vertex_stride = 0;
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;
if (!il)
return {};

View file

@ -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 <cstdarg>
#include <limits>
Log_SetChannel(D3D12Device);
D3D12::GraphicsPipelineBuilder::GraphicsPipelineBuilder()
{
Clear();
@ -27,14 +25,14 @@ void D3D12::GraphicsPipelineBuilder::Clear()
m_desc.SampleDesc.Count = 1;
}
Microsoft::WRL::ComPtr<ID3D12PipelineState> D3D12::GraphicsPipelineBuilder::Create(ID3D12Device* device,
bool clear /*= true*/)
Microsoft::WRL::ComPtr<ID3D12PipelineState> D3D12::GraphicsPipelineBuilder::Create(ID3D12Device* device, Error* error,
bool clear)
{
Microsoft::WRL::ComPtr<ID3D12PipelineState> ps;
HRESULT hr = device->CreateGraphicsPipelineState(&m_desc, IID_PPV_ARGS(ps.GetAddressOf()));
if (FAILED(hr))
{
ERROR_LOG("CreateGraphicsPipelineState() failed: {:08X}", static_cast<unsigned>(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<ID3D12PipelineState> D3D12::ComputePipelineBuilder::Create(ID3D12Device* device,
bool clear /*= true*/)
Microsoft::WRL::ComPtr<ID3D12PipelineState> D3D12::ComputePipelineBuilder::Create(ID3D12Device* device, Error* error,
bool clear)
{
Microsoft::WRL::ComPtr<ID3D12PipelineState> ps;
HRESULT hr = device->CreateComputePipelineState(&m_desc, IID_PPV_ARGS(ps.GetAddressOf()));
if (FAILED(hr)) [[unlikely]]
{
ERROR_LOG("CreateComputePipelineState() failed: {:08X}", static_cast<unsigned>(hr));
Error::SetHResult(error, "CreateComputePipelineState() failed: ", hr);
return {};
}
@ -260,9 +258,9 @@ void D3D12::RootSignatureBuilder::Clear()
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)
return {};

View file

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

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)
#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<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()));
if (FAILED(hr)) [[unlikely]]
{
ERROR_LOG("CreateDescriptorHeap() failed: {:08X}", static_cast<unsigned>(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<UINT>(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<unsigned>(hr));
Error::SetHResult(error, "CreateDescriptorHeap() failed: ", hr);
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)
#pragma once
@ -14,6 +14,8 @@
#include <vector>
#include <wrl/client.h>
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<u32 NumSamplers>
D3D12GroupedSamplerAllocator<NumSamplers>::~D3D12GroupedSamplerAllocator() = default;
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>

View file

@ -81,7 +81,7 @@ D3D12Device::~D3D12Device()
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> 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());
if (FAILED(hr)) [[unlikely]]
{
ERROR_LOG("D3D12SerializeRootSignature() failed: {:08X}", static_cast<unsigned>(hr));
Error::SetHResult(error, "D3D12SerializeRootSignature() failed: ", hr);
if (error_blob)
ERROR_LOG(static_cast<const char*>(error_blob->GetBufferPointer()));
@ -99,9 +99,10 @@ D3D12Device::ComPtr<ID3DBlob> D3D12Device::SerializeRootSignature(const D3D12_RO
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)
return {};
@ -110,7 +111,7 @@ D3D12Device::ComPtr<ID3D12RootSignature> 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<unsigned>(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<u8>* 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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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<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");
}
}
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");
}

View file

@ -95,7 +95,7 @@ public:
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
std::string_view source, const char* entry_point,
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 PopDebugGroup() override;
@ -155,8 +155,8 @@ public:
ID3D12GraphicsCommandList4* GetInitCommandList();
// Root signature access.
ComPtr<ID3DBlob> SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc);
ComPtr<ID3D12RootSignature> CreateRootSignature(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, 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();

View file

@ -106,7 +106,7 @@ std::string D3D12Pipeline::GetPipelineName(const GraphicsConfig& config)
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 =
{{
@ -242,7 +242,7 @@ std::unique_ptr<GPUPipeline> D3D12Device::CreatePipeline(const GPUPipeline::Grap
ERROR_LOG("LoadGraphicsPipeline() failed with HRESULT {:08X}", static_cast<unsigned>(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<GPUPipeline> D3D12Device::CreatePipeline(const GPUPipeline::Grap
}
else
{
pipeline = gpb.Create(m_device.Get(), false);
pipeline = gpb.Create(m_device.Get(), error, false);
}
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)
#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<unsigned>(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<void**>(&host_pointer));
if (FAILED(hr)) [[unlikely]]
{
ERROR_LOG("Map() failed: {:08X}", static_cast<unsigned>(hr));
Error::SetHResult(error, "Map() for stream buffer failed: ", hr);
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)
#pragma once
@ -11,6 +11,8 @@
#include <utility>
#include <wrl/client.h>
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<bool>(m_buffer); }
ALWAYS_INLINE ID3D12Resource* GetBuffer() const { return m_buffer.Get(); }

View file

@ -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<u8>(m_format)],

View file

@ -533,7 +533,10 @@ bool GPUDevice::CreateResources(Error* error)
std::unique_ptr<GPUShader> 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");

View file

@ -650,7 +650,8 @@ public:
/// Shader abstraction.
std::unique_ptr<GPUShader> CreateShader(GPUShaderStage stage, GPUShaderLanguage language, std::string_view source,
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.
virtual void PushDebugGroup(const char* name) = 0;

View file

@ -235,7 +235,7 @@ public:
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
std::string_view source, const char* entry_point,
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 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]);
}
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)
{
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
{
@ -857,11 +862,12 @@ std::unique_ptr<GPUPipeline> MetalDevice::CreatePipeline(const GPUPipeline::Grap
if (config.layout == GPUPipeline::Layout::SingleTextureBufferAndPushConstants)
desc.fragmentBuffers[1].mutability = MTLMutabilityImmutable;
NSError* error = nullptr;
id<MTLRenderPipelineState> pipeline = [m_device newRenderPipelineStateWithDescriptor:desc error:&error];
NSError* nserror = nullptr;
id<MTLRenderPipelineState> 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 {};
}

View file

@ -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<unsigned>(glerr));
}
RenderAPI OpenGLDevice::GetRenderAPI() const
{
return m_gl_context->IsGLES() ? RenderAPI::OpenGLES : RenderAPI::OpenGL;

View file

@ -13,6 +13,7 @@
#include <cstdio>
#include <memory>
#include <string_view>
#include <tuple>
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<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
std::string_view source, const char* entry_point,
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 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<const GPUPipeline::VertexAttribute> attributes, u32 stride);
OpenGLPipeline::VertexArrayCache::const_iterator LookupVAOCache(const OpenGLPipeline::VertexArrayCacheKey& key, Error* error);
GLuint CreateVAO(std::span<const GPUPipeline::VertexAttribute> attributes, u32 stride, Error* error);
void UnrefVAO(const OpenGLPipeline::VertexArrayCacheKey& key);
void SetActiveTexture(u32 slot);

View file

@ -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<OpenGLShader*>(plconfig.vertex_shader);
OpenGLShader* fragment_shader = static_cast<OpenGLShader*>(plconfig.fragment_shader);
OpenGLShader* geometry_shader = static_cast<OpenGLShader*>(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<const GPUPipeline::VertexAttribute>(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<const GPUPipeline::VertexAttribute> attributes, u32 stride)
GLuint OpenGLDevice::CreateVAO(std::span<const GPUPipeline::VertexAttribute> attributes, u32 stride, Error* error)
{
glGetError();
GLuint vao;
@ -496,6 +506,7 @@ GLuint OpenGLDevice::CreateVAO(std::span<const GPUPipeline::VertexAttribute> 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<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 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);

View file

@ -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; }

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)
#include "vulkan_builders.h"
#include "common/assert.h"
#include "common/error.h"
#include "common/log.h"
#include <limits>
@ -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<unsigned>(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;
}

View file

@ -12,6 +12,8 @@
#include <array>
#include <string_view>
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"); }

View file

@ -104,11 +104,12 @@ public:
void ClearDepth(GPUTexture* t, float d) 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::string_view source, const char* entry_point,
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 PopDebugGroup() override;

View file

@ -88,7 +88,7 @@ void VulkanPipeline::SetDebugName(std::string_view 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)>
primitives = {{
@ -243,7 +243,7 @@ std::unique_ptr<GPUPipeline> 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 {};