Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #12185 from iwubcode/custom_shader_uniform_backend…
…_support

VideoBackends / VideoCommon: add support for custom shader uniforms to D3D, Vulkan, OGL
  • Loading branch information
AdmiralCurtiss committed Oct 14, 2023
2 parents 5195446 + 713454b commit 2677fd9
Show file tree
Hide file tree
Showing 21 changed files with 237 additions and 86 deletions.
12 changes: 9 additions & 3 deletions Source/Core/VideoBackends/D3D/D3DState.cpp
Expand Up @@ -69,12 +69,18 @@ void StateManager::Apply()
if (dirtyConstants)
{
if (m_current.pixelConstants[0] != m_pending.pixelConstants[0] ||
m_current.pixelConstants[1] != m_pending.pixelConstants[1])
m_current.pixelConstants[1] != m_pending.pixelConstants[1] ||
m_current.pixelConstants[2] != m_pending.pixelConstants[2])
{
D3D::context->PSSetConstantBuffers(0, m_pending.pixelConstants[1] ? 2 : 1,
m_pending.pixelConstants.data());
u32 count = 1;
if (m_pending.pixelConstants[1])
count++;
if (m_pending.pixelConstants[2])
count++;
D3D::context->PSSetConstantBuffers(0, count, m_pending.pixelConstants.data());
m_current.pixelConstants[0] = m_pending.pixelConstants[0];
m_current.pixelConstants[1] = m_pending.pixelConstants[1];
m_current.pixelConstants[2] = m_pending.pixelConstants[2];
}

if (m_current.vertexConstants != m_pending.vertexConstants)
Expand Down
9 changes: 6 additions & 3 deletions Source/Core/VideoBackends/D3D/D3DState.h
Expand Up @@ -91,13 +91,16 @@ class StateManager
m_pending.samplers[index] = sampler;
}

void SetPixelConstants(ID3D11Buffer* buffer0, ID3D11Buffer* buffer1 = nullptr)
void SetPixelConstants(ID3D11Buffer* buffer0, ID3D11Buffer* buffer1 = nullptr,
ID3D11Buffer* buffer2 = nullptr)
{
if (m_current.pixelConstants[0] != buffer0 || m_current.pixelConstants[1] != buffer1)
if (m_current.pixelConstants[0] != buffer0 || m_current.pixelConstants[1] != buffer1 ||
m_current.pixelConstants[2] != buffer2)
m_dirtyFlags.set(DirtyFlag_PixelConstants);

m_pending.pixelConstants[0] = buffer0;
m_pending.pixelConstants[1] = buffer1;
m_pending.pixelConstants[2] = buffer2;
}

void SetVertexConstants(ID3D11Buffer* buffer)
Expand Down Expand Up @@ -252,7 +255,7 @@ class StateManager
{
std::array<ID3D11ShaderResourceView*, VideoCommon::MAX_PIXEL_SHADER_SAMPLERS> textures;
std::array<ID3D11SamplerState*, VideoCommon::MAX_PIXEL_SHADER_SAMPLERS> samplers;
std::array<ID3D11Buffer*, 2> pixelConstants;
std::array<ID3D11Buffer*, 3> pixelConstants;
ID3D11Buffer* vertexConstants;
ID3D11Buffer* geometryConstants;
ID3D11Buffer* vertexBuffer;
Expand Down
18 changes: 17 additions & 1 deletion Source/Core/VideoBackends/D3D/D3DVertexManager.cpp
Expand Up @@ -288,9 +288,25 @@ void VertexManager::UploadUniforms()
pixel_shader_manager.dirty = false;
}

if (pixel_shader_manager.custom_constants_dirty)
{
if (m_last_custom_pixel_buffer_size < pixel_shader_manager.custom_constants.size())
{
m_custom_pixel_constant_buffer =
AllocateConstantBuffer(static_cast<u32>(pixel_shader_manager.custom_constants.size()));
}
UpdateConstantBuffer(m_custom_pixel_constant_buffer.Get(),
pixel_shader_manager.custom_constants.data(),
static_cast<u32>(pixel_shader_manager.custom_constants.size()));
m_last_custom_pixel_buffer_size = pixel_shader_manager.custom_constants.size();
pixel_shader_manager.custom_constants_dirty = false;
}

D3D::stateman->SetPixelConstants(
m_pixel_constant_buffer.Get(),
g_ActiveConfig.bEnablePixelLighting ? m_vertex_constant_buffer.Get() : nullptr);
g_ActiveConfig.bEnablePixelLighting ? m_vertex_constant_buffer.Get() : nullptr,
pixel_shader_manager.custom_constants.empty() ? nullptr :
m_custom_pixel_constant_buffer.Get());
D3D::stateman->SetVertexConstants(m_vertex_constant_buffer.Get());
D3D::stateman->SetGeometryConstants(m_geometry_constant_buffer.Get());
}
Expand Down
3 changes: 3 additions & 0 deletions Source/Core/VideoBackends/D3D/D3DVertexManager.h
Expand Up @@ -68,6 +68,9 @@ class VertexManager : public VertexManagerBase
ComPtr<ID3D11Buffer> m_geometry_constant_buffer = nullptr;
ComPtr<ID3D11Buffer> m_pixel_constant_buffer = nullptr;

ComPtr<ID3D11Buffer> m_custom_pixel_constant_buffer = nullptr;
std::size_t m_last_custom_pixel_buffer_size = 0;

ComPtr<ID3D11Buffer> m_texel_buffer = nullptr;
std::array<ComPtr<ID3D11ShaderResourceView>, NUM_TEXEL_BUFFER_FORMATS> m_texel_buffer_views;
u32 m_texel_buffer_offset = 0;
Expand Down
13 changes: 10 additions & 3 deletions Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp
Expand Up @@ -161,7 +161,7 @@ void Gfx::SetPipeline(const AbstractPipeline* pipeline)
m_dirty_bits |= DirtyState_RootSignature | DirtyState_PS_CBV | DirtyState_VS_CBV |
DirtyState_GS_CBV | DirtyState_SRV_Descriptor |
DirtyState_Sampler_Descriptor | DirtyState_UAV_Descriptor |
DirtyState_VS_SRV_Descriptor;
DirtyState_VS_SRV_Descriptor | DirtyState_PS_CUS_CBV;
}
if (dx_pipeline->UseIntegerRTV() != m_state.using_integer_rtv)
{
Expand Down Expand Up @@ -524,7 +524,7 @@ bool Gfx::ApplyState()
DirtyState_ScissorRect | DirtyState_PS_UAV | DirtyState_PS_CBV | DirtyState_VS_CBV |
DirtyState_GS_CBV | DirtyState_SRV_Descriptor | DirtyState_Sampler_Descriptor |
DirtyState_UAV_Descriptor | DirtyState_VertexBuffer | DirtyState_IndexBuffer |
DirtyState_PrimitiveTopology | DirtyState_VS_SRV_Descriptor);
DirtyState_PrimitiveTopology | DirtyState_VS_SRV_Descriptor | DirtyState_PS_CUS_CBV);

auto* const cmdlist = g_dx_context->GetCommandList();
auto* const pipeline = static_cast<const DXPipeline*>(m_current_pipeline);
Expand Down Expand Up @@ -575,6 +575,13 @@ bool Gfx::ApplyState()
}
}

if (dirty_bits & DirtyState_PS_CUS_CBV)
{
cmdlist->SetGraphicsRootConstantBufferView(
g_ActiveConfig.bBBoxEnable ? ROOT_PARAMETER_PS_CUS_CBV : ROOT_PARAMETER_PS_CBV2,
m_state.constant_buffers[2]);
}

if (dirty_bits & DirtyState_VS_SRV_Descriptor && UsesDynamicVertexLoader(pipeline))
{
cmdlist->SetGraphicsRootDescriptorTable(ROOT_PARAMETER_VS_SRV,
Expand All @@ -584,7 +591,7 @@ bool Gfx::ApplyState()
if (dirty_bits & DirtyState_GS_CBV)
{
cmdlist->SetGraphicsRootConstantBufferView(ROOT_PARAMETER_GS_CBV,
m_state.constant_buffers[2]);
m_state.constant_buffers[3]);
}

if (dirty_bits & DirtyState_UAV_Descriptor && g_ActiveConfig.bBBoxEnable)
Expand Down
39 changes: 19 additions & 20 deletions Source/Core/VideoBackends/D3D12/D3D12Gfx.h
Expand Up @@ -98,8 +98,6 @@ class Gfx final : public ::AbstractGfx
void OnConfigChanged(u32 bits) override;

private:
static const u32 NUM_CONSTANT_BUFFERS = 3;

// Dirty bits
enum DirtyStates
{
Expand All @@ -113,27 +111,28 @@ class Gfx final : public ::AbstractGfx
DirtyState_PS_UAV = (1 << 7),
DirtyState_PS_CBV = (1 << 8),
DirtyState_VS_CBV = (1 << 9),
DirtyState_GS_CBV = (1 << 10),
DirtyState_SRV_Descriptor = (1 << 11),
DirtyState_Sampler_Descriptor = (1 << 12),
DirtyState_UAV_Descriptor = (1 << 13),
DirtyState_VertexBuffer = (1 << 14),
DirtyState_IndexBuffer = (1 << 15),
DirtyState_PrimitiveTopology = (1 << 16),
DirtyState_RootSignature = (1 << 17),
DirtyState_ComputeRootSignature = (1 << 18),
DirtyState_DescriptorHeaps = (1 << 19),
DirtyState_VS_SRV = (1 << 20),
DirtyState_VS_SRV_Descriptor = (1 << 21),
DirtyState_PS_CUS_CBV = (1 << 10),
DirtyState_GS_CBV = (1 << 11),
DirtyState_SRV_Descriptor = (1 << 12),
DirtyState_Sampler_Descriptor = (1 << 13),
DirtyState_UAV_Descriptor = (1 << 14),
DirtyState_VertexBuffer = (1 << 15),
DirtyState_IndexBuffer = (1 << 16),
DirtyState_PrimitiveTopology = (1 << 17),
DirtyState_RootSignature = (1 << 18),
DirtyState_ComputeRootSignature = (1 << 19),
DirtyState_DescriptorHeaps = (1 << 20),
DirtyState_VS_SRV = (1 << 21),
DirtyState_VS_SRV_Descriptor = (1 << 22),

DirtyState_All =
DirtyState_Framebuffer | DirtyState_Pipeline | DirtyState_Textures | DirtyState_Samplers |
DirtyState_Viewport | DirtyState_ScissorRect | DirtyState_ComputeImageTexture |
DirtyState_PS_UAV | DirtyState_PS_CBV | DirtyState_VS_CBV | DirtyState_GS_CBV |
DirtyState_SRV_Descriptor | DirtyState_Sampler_Descriptor | DirtyState_UAV_Descriptor |
DirtyState_VertexBuffer | DirtyState_IndexBuffer | DirtyState_PrimitiveTopology |
DirtyState_RootSignature | DirtyState_ComputeRootSignature | DirtyState_DescriptorHeaps |
DirtyState_VS_SRV | DirtyState_VS_SRV_Descriptor
DirtyState_PS_UAV | DirtyState_PS_CBV | DirtyState_VS_CBV | DirtyState_PS_CUS_CBV |
DirtyState_GS_CBV | DirtyState_SRV_Descriptor | DirtyState_Sampler_Descriptor |
DirtyState_UAV_Descriptor | DirtyState_VertexBuffer | DirtyState_IndexBuffer |
DirtyState_PrimitiveTopology | DirtyState_RootSignature | DirtyState_ComputeRootSignature |
DirtyState_DescriptorHeaps | DirtyState_VS_SRV | DirtyState_VS_SRV_Descriptor
};

void CheckForSwapChainChanges();
Expand All @@ -158,7 +157,7 @@ class Gfx final : public ::AbstractGfx
{
ID3D12RootSignature* root_signature = nullptr;
DXShader* compute_shader = nullptr;
std::array<D3D12_GPU_VIRTUAL_ADDRESS, 3> constant_buffers = {};
std::array<D3D12_GPU_VIRTUAL_ADDRESS, 4> constant_buffers = {};
std::array<D3D12_CPU_DESCRIPTOR_HANDLE, VideoCommon::MAX_PIXEL_SHADER_SAMPLERS> textures = {};
D3D12_CPU_DESCRIPTOR_HANDLE vs_srv = {};
D3D12_CPU_DESCRIPTOR_HANDLE ps_uav = {};
Expand Down
55 changes: 43 additions & 12 deletions Source/Core/VideoBackends/D3D12/D3D12VertexManager.cpp
Expand Up @@ -167,7 +167,7 @@ void VertexManager::UpdateGeometryShaderConstants()
if (!geometry_shader_manager.dirty || !ReserveConstantStorage())
return;

Gfx::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer());
Gfx::GetInstance()->SetConstantBuffer(3, m_uniform_stream_buffer.GetCurrentGPUPointer());
std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer(), &geometry_shader_manager.constants,
sizeof(GeometryShaderConstants));
m_uniform_stream_buffer.CommitMemory(sizeof(GeometryShaderConstants));
Expand All @@ -180,23 +180,41 @@ void VertexManager::UpdatePixelShaderConstants()
auto& system = Core::System::GetInstance();
auto& pixel_shader_manager = system.GetPixelShaderManager();

if (!pixel_shader_manager.dirty || !ReserveConstantStorage())
if (!ReserveConstantStorage())
return;

Gfx::GetInstance()->SetConstantBuffer(0, m_uniform_stream_buffer.GetCurrentGPUPointer());
std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer(), &pixel_shader_manager.constants,
sizeof(PixelShaderConstants));
m_uniform_stream_buffer.CommitMemory(sizeof(PixelShaderConstants));
ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, sizeof(PixelShaderConstants));
pixel_shader_manager.dirty = false;
if (pixel_shader_manager.dirty)
{
Gfx::GetInstance()->SetConstantBuffer(0, m_uniform_stream_buffer.GetCurrentGPUPointer());
std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer(), &pixel_shader_manager.constants,
sizeof(PixelShaderConstants));
m_uniform_stream_buffer.CommitMemory(sizeof(PixelShaderConstants));
ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, sizeof(PixelShaderConstants));
pixel_shader_manager.dirty = false;
}

if (pixel_shader_manager.custom_constants_dirty)
{
Gfx::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer());
std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer(),
pixel_shader_manager.custom_constants.data(),
pixel_shader_manager.custom_constants.size());
m_uniform_stream_buffer.CommitMemory(
static_cast<u32>(pixel_shader_manager.custom_constants.size()));
pixel_shader_manager.custom_constants_dirty = false;
}
}

bool VertexManager::ReserveConstantStorage()
{
auto& system = Core::System::GetInstance();
auto& pixel_shader_manager = system.GetPixelShaderManager();

static constexpr u32 reserve_size =
static_cast<u32>(std::max({sizeof(PixelShaderConstants), sizeof(VertexShaderConstants),
sizeof(GeometryShaderConstants)}));
if (m_uniform_stream_buffer.ReserveMemory(reserve_size,
const u32 custom_constants_size = static_cast<u32>(pixel_shader_manager.custom_constants.size());
if (m_uniform_stream_buffer.ReserveMemory(reserve_size + custom_constants_size,
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT))
{
return true;
Expand All @@ -214,6 +232,9 @@ bool VertexManager::ReserveConstantStorage()

void VertexManager::UploadAllConstants()
{
auto& system = Core::System::GetInstance();
auto& pixel_shader_manager = system.GetPixelShaderManager();

// We are free to re-use parts of the buffer now since we're uploading all constants.
const u32 pixel_constants_offset = 0;
constexpr u32 vertex_constants_offset =
Expand All @@ -222,7 +243,11 @@ void VertexManager::UploadAllConstants()
constexpr u32 geometry_constants_offset =
Common::AlignUp(vertex_constants_offset + sizeof(VertexShaderConstants),
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
const u32 allocation_size = geometry_constants_offset + sizeof(GeometryShaderConstants);
constexpr u32 custom_pixel_constants_offset =
Common::AlignUp(geometry_constants_offset + sizeof(GeometryShaderConstants),
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
const u32 allocation_size = custom_pixel_constants_offset +
static_cast<u32>(pixel_shader_manager.custom_constants.size());

// Allocate everything at once.
// We should only be here if the buffer was full and a command buffer was submitted anyway.
Expand All @@ -239,10 +264,10 @@ void VertexManager::UploadAllConstants()
Gfx::GetInstance()->SetConstantBuffer(1, m_uniform_stream_buffer.GetCurrentGPUPointer() +
vertex_constants_offset);
Gfx::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer() +
custom_pixel_constants_offset);
Gfx::GetInstance()->SetConstantBuffer(3, m_uniform_stream_buffer.GetCurrentGPUPointer() +
geometry_constants_offset);

auto& system = Core::System::GetInstance();
auto& pixel_shader_manager = system.GetPixelShaderManager();
auto& vertex_shader_manager = system.GetVertexShaderManager();
auto& geometry_shader_manager = system.GetGeometryShaderManager();

Expand All @@ -253,6 +278,12 @@ void VertexManager::UploadAllConstants()
&vertex_shader_manager.constants, sizeof(VertexShaderConstants));
std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer() + geometry_constants_offset,
&geometry_shader_manager.constants, sizeof(GeometryShaderConstants));
if (!pixel_shader_manager.custom_constants.empty())
{
std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer() + custom_pixel_constants_offset,
pixel_shader_manager.custom_constants.data(),
pixel_shader_manager.custom_constants.size());
}

// Finally, flush buffer memory after copying
m_uniform_stream_buffer.CommitMemory(allocation_size);
Expand Down
7 changes: 5 additions & 2 deletions Source/Core/VideoBackends/D3D12/DX12Context.cpp
Expand Up @@ -339,7 +339,7 @@ bool DXContext::CreateRootSignatures()
bool DXContext::CreateGXRootSignature()
{
// GX:
// - 3 constant buffers (bindings 0-2), 0/1 visible in PS, 2 visible in VS, 1 visible in GS.
// - 4 constant buffers (bindings 0-3), 0/1/2 visible in PS, 2 visible in VS, 1 visible in GS.
// - VideoCommon::MAX_PIXEL_SHADER_SAMPLERS textures (visible in PS).
// - VideoCommon::MAX_PIXEL_SHADER_SAMPLERS samplers (visible in PS).
// - 1 UAV (visible in PS).
Expand Down Expand Up @@ -367,7 +367,7 @@ bool DXContext::CreateGXRootSignature()
SetRootParamTable(&params[param_count], &ranges[param_count], D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 3,
1, D3D12_SHADER_VISIBILITY_VERTEX);
param_count++;
SetRootParamConstant(&params[param_count], 3, 1, D3D12_SHADER_VISIBILITY_VERTEX);
SetRootParamConstant(&params[param_count], 4, 1, D3D12_SHADER_VISIBILITY_VERTEX);
param_count++;

// Since these must be contiguous, pixel lighting goes to bbox if not enabled.
Expand All @@ -383,6 +383,9 @@ bool DXContext::CreateGXRootSignature()
param_count++;
}

SetRootParamCBV(&params[param_count], 2, D3D12_SHADER_VISIBILITY_PIXEL);
param_count++;

return BuildRootSignature(m_device.Get(), &m_gx_root_signature, params.data(), param_count);
}

Expand Down
3 changes: 2 additions & 1 deletion Source/Core/VideoBackends/D3D12/DX12Context.h
Expand Up @@ -30,7 +30,8 @@ enum ROOT_PARAMETER
ROOT_PARAMETER_VS_SRV,
ROOT_PARAMETER_BASE_VERTEX_CONSTANT,
ROOT_PARAMETER_PS_UAV_OR_CBV2,
ROOT_PARAMETER_PS_CBV2, // ROOT_PARAMETER_PS_UAV_OR_CBV2 if bbox is not enabled
ROOT_PARAMETER_PS_CBV2, // ROOT_PARAMETER_PS_UAV_OR_CBV2 if bbox is not enabled
ROOT_PARAMETER_PS_CUS_CBV, // ROOT_PARAMETER_PS_CBV2 if bbox is not enabled
NUM_ROOT_PARAMETERS
};
// Compute shader root parameters
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/VideoBackends/Metal/MTLUtil.mm
Expand Up @@ -458,7 +458,7 @@ fragment float4 fbfetch_test(float4 in [[color(0), raster_order_group(0)]]) {
static const spirv_cross::MSLResourceBinding resource_bindings[] = {
MakeResourceBinding(spv::ExecutionModelVertex, 0, 0, 1, 0, 0), // vs/ubo
MakeResourceBinding(spv::ExecutionModelVertex, 0, 1, 1, 0, 0), // vs/ubo
MakeResourceBinding(spv::ExecutionModelVertex, 0, 2, 2, 0, 0), // vs/ubo
MakeResourceBinding(spv::ExecutionModelVertex, 0, 3, 2, 0, 0), // vs/ubo
MakeResourceBinding(spv::ExecutionModelVertex, 2, 1, 0, 0, 0), // vs/ssbo
MakeResourceBinding(spv::ExecutionModelFragment, 0, 0, 0, 0, 0), // vs/ubo
MakeResourceBinding(spv::ExecutionModelFragment, 0, 1, 1, 0, 0), // vs/ubo
Expand Down

0 comments on commit 2677fd9

Please sign in to comment.