From b6d321bfb176b8296d9b128d3bb23da5b1a9124c Mon Sep 17 00:00:00 2001 From: iwubcode Date: Tue, 19 Sep 2023 19:29:38 -0500 Subject: [PATCH] VideoBackends / VideoCommon: add new uniform buffer object for custom shader materials (slot 3, geometry shader buffer moves to slot 4 if available) --- Source/Core/VideoBackends/D3D/D3DState.cpp | 12 +++- Source/Core/VideoBackends/D3D/D3DState.h | 9 ++- .../VideoBackends/D3D/D3DVertexManager.cpp | 18 ++++- .../Core/VideoBackends/D3D/D3DVertexManager.h | 3 + Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp | 13 +++- Source/Core/VideoBackends/D3D12/D3D12Gfx.h | 39 ++++++----- .../D3D12/D3D12VertexManager.cpp | 55 ++++++++++++---- .../Core/VideoBackends/D3D12/DX12Context.cpp | 7 +- Source/Core/VideoBackends/D3D12/DX12Context.h | 3 +- .../VideoBackends/OGL/ProgramShaderCache.cpp | 53 ++++++++++----- Source/Core/VideoBackends/Vulkan/Constants.h | 3 +- .../Core/VideoBackends/Vulkan/ObjectCache.cpp | 6 +- .../VideoBackends/Vulkan/VKVertexManager.cpp | 66 +++++++++++++++---- Source/Core/VideoCommon/GeometryShaderGen.cpp | 2 +- Source/Core/VideoCommon/UberShaderVertex.cpp | 4 +- Source/Core/VideoCommon/VertexShaderGen.cpp | 4 +- 16 files changed, 214 insertions(+), 83 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index 0372252b9a..f3aed1c1f2 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -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) diff --git a/Source/Core/VideoBackends/D3D/D3DState.h b/Source/Core/VideoBackends/D3D/D3DState.h index 0893220e71..9b14b00350 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.h +++ b/Source/Core/VideoBackends/D3D/D3DState.h @@ -91,13 +91,16 @@ public: 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) @@ -252,7 +255,7 @@ private: { std::array textures; std::array samplers; - std::array pixelConstants; + std::array pixelConstants; ID3D11Buffer* vertexConstants; ID3D11Buffer* geometryConstants; ID3D11Buffer* vertexBuffer; diff --git a/Source/Core/VideoBackends/D3D/D3DVertexManager.cpp b/Source/Core/VideoBackends/D3D/D3DVertexManager.cpp index 4aa1c40266..5929788b03 100644 --- a/Source/Core/VideoBackends/D3D/D3DVertexManager.cpp +++ b/Source/Core/VideoBackends/D3D/D3DVertexManager.cpp @@ -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(pixel_shader_manager.custom_constants.size())); + } + UpdateConstantBuffer(m_custom_pixel_constant_buffer.Get(), + pixel_shader_manager.custom_constants.data(), + static_cast(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()); } diff --git a/Source/Core/VideoBackends/D3D/D3DVertexManager.h b/Source/Core/VideoBackends/D3D/D3DVertexManager.h index 669d670fed..4bdbf34bb0 100644 --- a/Source/Core/VideoBackends/D3D/D3DVertexManager.h +++ b/Source/Core/VideoBackends/D3D/D3DVertexManager.h @@ -68,6 +68,9 @@ private: ComPtr m_geometry_constant_buffer = nullptr; ComPtr m_pixel_constant_buffer = nullptr; + ComPtr m_custom_pixel_constant_buffer = nullptr; + std::size_t m_last_custom_pixel_buffer_size = 0; + ComPtr m_texel_buffer = nullptr; std::array, NUM_TEXEL_BUFFER_FORMATS> m_texel_buffer_views; u32 m_texel_buffer_offset = 0; diff --git a/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp b/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp index 84bac629ac..08d273859f 100644 --- a/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp +++ b/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp @@ -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) { @@ -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(m_current_pipeline); @@ -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, @@ -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) diff --git a/Source/Core/VideoBackends/D3D12/D3D12Gfx.h b/Source/Core/VideoBackends/D3D12/D3D12Gfx.h index b3426cb95e..9f537e5e09 100644 --- a/Source/Core/VideoBackends/D3D12/D3D12Gfx.h +++ b/Source/Core/VideoBackends/D3D12/D3D12Gfx.h @@ -98,8 +98,6 @@ protected: void OnConfigChanged(u32 bits) override; private: - static const u32 NUM_CONSTANT_BUFFERS = 3; - // Dirty bits enum DirtyStates { @@ -113,27 +111,28 @@ private: 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(); @@ -158,7 +157,7 @@ private: { ID3D12RootSignature* root_signature = nullptr; DXShader* compute_shader = nullptr; - std::array constant_buffers = {}; + std::array constant_buffers = {}; std::array textures = {}; D3D12_CPU_DESCRIPTOR_HANDLE vs_srv = {}; D3D12_CPU_DESCRIPTOR_HANDLE ps_uav = {}; diff --git a/Source/Core/VideoBackends/D3D12/D3D12VertexManager.cpp b/Source/Core/VideoBackends/D3D12/D3D12VertexManager.cpp index 03e88e3867..c0fe195e75 100644 --- a/Source/Core/VideoBackends/D3D12/D3D12VertexManager.cpp +++ b/Source/Core/VideoBackends/D3D12/D3D12VertexManager.cpp @@ -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)); @@ -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(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(std::max({sizeof(PixelShaderConstants), sizeof(VertexShaderConstants), sizeof(GeometryShaderConstants)})); - if (m_uniform_stream_buffer.ReserveMemory(reserve_size, + const u32 custom_constants_size = static_cast(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; @@ -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 = @@ -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(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. @@ -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(); @@ -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); diff --git a/Source/Core/VideoBackends/D3D12/DX12Context.cpp b/Source/Core/VideoBackends/D3D12/DX12Context.cpp index dd8630ac3b..843efc79d4 100644 --- a/Source/Core/VideoBackends/D3D12/DX12Context.cpp +++ b/Source/Core/VideoBackends/D3D12/DX12Context.cpp @@ -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). @@ -367,7 +367,7 @@ bool DXContext::CreateGXRootSignature() SetRootParamTable(¶ms[param_count], &ranges[param_count], D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 3, 1, D3D12_SHADER_VISIBILITY_VERTEX); param_count++; - SetRootParamConstant(¶ms[param_count], 3, 1, D3D12_SHADER_VISIBILITY_VERTEX); + SetRootParamConstant(¶ms[param_count], 4, 1, D3D12_SHADER_VISIBILITY_VERTEX); param_count++; // Since these must be contiguous, pixel lighting goes to bbox if not enabled. @@ -383,6 +383,9 @@ bool DXContext::CreateGXRootSignature() param_count++; } + SetRootParamCBV(¶ms[param_count], 2, D3D12_SHADER_VISIBILITY_PIXEL); + param_count++; + return BuildRootSignature(m_device.Get(), &m_gx_root_signature, params.data(), param_count); } diff --git a/Source/Core/VideoBackends/D3D12/DX12Context.h b/Source/Core/VideoBackends/D3D12/DX12Context.h index ad9ef9fe74..d492e7face 100644 --- a/Source/Core/VideoBackends/D3D12/DX12Context.h +++ b/Source/Core/VideoBackends/D3D12/DX12Context.h @@ -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 diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp index 8c56a40e8c..91794696b9 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp @@ -105,9 +105,9 @@ void SHADER::SetProgramVariables() if (VSBlock_id != -1) glUniformBlockBinding(glprogid, VSBlock_id, 2); if (GSBlock_id != -1) - glUniformBlockBinding(glprogid, GSBlock_id, 3); + glUniformBlockBinding(glprogid, GSBlock_id, 4); if (UBERBlock_id != -1) - glUniformBlockBinding(glprogid, UBERBlock_id, 4); + glUniformBlockBinding(glprogid, UBERBlock_id, 5); // Bind Texture Samplers for (int a = 0; a < 8; ++a) @@ -232,35 +232,54 @@ void ProgramShaderCache::UploadConstants() auto& pixel_shader_manager = system.GetPixelShaderManager(); auto& vertex_shader_manager = system.GetVertexShaderManager(); auto& geometry_shader_manager = system.GetGeometryShaderManager(); - if (pixel_shader_manager.dirty || vertex_shader_manager.dirty || geometry_shader_manager.dirty) + if (pixel_shader_manager.dirty || vertex_shader_manager.dirty || geometry_shader_manager.dirty || + pixel_shader_manager.custom_constants_dirty) { - auto buffer = s_buffer->Map(s_ubo_buffer_size, s_ubo_align); + const u32 custom_constants_size = static_cast( + Common::AlignUp(pixel_shader_manager.custom_constants.size(), s_ubo_align)); + auto buffer = s_buffer->Map(s_ubo_buffer_size + custom_constants_size, s_ubo_align); memcpy(buffer.first, &pixel_shader_manager.constants, sizeof(PixelShaderConstants)); - memcpy(buffer.first + Common::AlignUp(sizeof(PixelShaderConstants), s_ubo_align), - &vertex_shader_manager.constants, sizeof(VertexShaderConstants)); + u64 size = Common::AlignUp(sizeof(PixelShaderConstants), s_ubo_align); - memcpy(buffer.first + Common::AlignUp(sizeof(PixelShaderConstants), s_ubo_align) + - Common::AlignUp(sizeof(VertexShaderConstants), s_ubo_align), - &geometry_shader_manager.constants, sizeof(GeometryShaderConstants)); + memcpy(buffer.first + size, &vertex_shader_manager.constants, sizeof(VertexShaderConstants)); + size += Common::AlignUp(sizeof(VertexShaderConstants), s_ubo_align); + + if (!pixel_shader_manager.custom_constants.empty()) + { + memcpy(buffer.first + size, pixel_shader_manager.custom_constants.data(), + pixel_shader_manager.custom_constants.size()); + size += custom_constants_size; + } + + memcpy(buffer.first + size, &geometry_shader_manager.constants, + sizeof(GeometryShaderConstants)); + + s_buffer->Unmap(s_ubo_buffer_size + custom_constants_size); - s_buffer->Unmap(s_ubo_buffer_size); glBindBufferRange(GL_UNIFORM_BUFFER, 1, s_buffer->m_buffer, buffer.second, sizeof(PixelShaderConstants)); - glBindBufferRange(GL_UNIFORM_BUFFER, 2, s_buffer->m_buffer, - buffer.second + Common::AlignUp(sizeof(PixelShaderConstants), s_ubo_align), + size = Common::AlignUp(sizeof(PixelShaderConstants), s_ubo_align); + glBindBufferRange(GL_UNIFORM_BUFFER, 2, s_buffer->m_buffer, buffer.second + size, sizeof(VertexShaderConstants)); - glBindBufferRange(GL_UNIFORM_BUFFER, 3, s_buffer->m_buffer, - buffer.second + Common::AlignUp(sizeof(PixelShaderConstants), s_ubo_align) + - Common::AlignUp(sizeof(VertexShaderConstants), s_ubo_align), + size += Common::AlignUp(sizeof(VertexShaderConstants), s_ubo_align); + + if (!pixel_shader_manager.custom_constants.empty()) + { + glBindBufferRange(GL_UNIFORM_BUFFER, 3, s_buffer->m_buffer, buffer.second + size, + pixel_shader_manager.custom_constants.size()); + size += Common::AlignUp(pixel_shader_manager.custom_constants.size(), s_ubo_align); + } + glBindBufferRange(GL_UNIFORM_BUFFER, 4, s_buffer->m_buffer, buffer.second + size, sizeof(GeometryShaderConstants)); pixel_shader_manager.dirty = false; vertex_shader_manager.dirty = false; geometry_shader_manager.dirty = false; + pixel_shader_manager.custom_constants_dirty = false; - ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, s_ubo_buffer_size); + ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, s_ubo_buffer_size + custom_constants_size); } } @@ -273,7 +292,7 @@ void ProgramShaderCache::UploadConstants(const void* data, u32 data_size) s_buffer->Unmap(alloc_size); // bind the same sub-buffer to all stages - for (u32 index = 1; index <= 3; index++) + for (u32 index = 1; index <= 4; index++) glBindBufferRange(GL_UNIFORM_BUFFER, index, s_buffer->m_buffer, buffer.second, data_size); ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, data_size); diff --git a/Source/Core/VideoBackends/Vulkan/Constants.h b/Source/Core/VideoBackends/Vulkan/Constants.h index 2bdceefe3b..90271c60bd 100644 --- a/Source/Core/VideoBackends/Vulkan/Constants.h +++ b/Source/Core/VideoBackends/Vulkan/Constants.h @@ -38,7 +38,7 @@ enum DESCRIPTOR_SET_LAYOUT // We use four pipeline layouts: // - Standard -// - Per-stage UBO (VS/GS/PS, VS constants accessible from PS) [set=0, binding=0-2] +// - Per-stage UBO (VS/GS/PS, VS constants accessible from PS) [set=0, binding=0-3] // - 8 combined image samplers (accessible from PS) [set=1, binding=0-7] // - 1 SSBO accessible from PS if supported [set=2, binding=0] // - Uber @@ -70,6 +70,7 @@ enum UNIFORM_BUFFER_DESCRIPTOR_SET_BINDING { UBO_DESCRIPTOR_SET_BINDING_PS, UBO_DESCRIPTOR_SET_BINDING_VS, + UBO_DESCRIPTOR_SET_BINDING_PS_CUST, UBO_DESCRIPTOR_SET_BINDING_GS, NUM_UBO_DESCRIPTOR_SET_BINDINGS }; diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp index d899191614..3a226b7177 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp @@ -110,11 +110,13 @@ bool ObjectCache::CreateDescriptorSetLayouts() { // The geometry shader buffer must be last in this binding set, as we don't include it // if geometry shaders are not supported by the device. See the decrement below. - static const std::array standard_ubo_bindings{{ + static const std::array standard_ubo_bindings{{ {UBO_DESCRIPTOR_SET_BINDING_PS, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {UBO_DESCRIPTOR_SET_BINDING_VS, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT}, + {UBO_DESCRIPTOR_SET_BINDING_PS_CUST, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, + VK_SHADER_STAGE_FRAGMENT_BIT}, {UBO_DESCRIPTOR_SET_BINDING_GS, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_GEOMETRY_BIT}, }}; @@ -170,7 +172,7 @@ bool ObjectCache::CreateDescriptorSetLayouts() {18, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT}, }}; - std::array ubo_bindings = standard_ubo_bindings; + std::array ubo_bindings = standard_ubo_bindings; std::array create_infos{{ {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0, diff --git a/Source/Core/VideoBackends/Vulkan/VKVertexManager.cpp b/Source/Core/VideoBackends/Vulkan/VKVertexManager.cpp index 5069d3e6d0..73c9dfde59 100644 --- a/Source/Core/VideoBackends/Vulkan/VKVertexManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKVertexManager.cpp @@ -243,22 +243,43 @@ void VertexManager::UpdatePixelShaderConstants() auto& system = Core::System::GetInstance(); auto& pixel_shader_manager = system.GetPixelShaderManager(); - if (!pixel_shader_manager.dirty || !ReserveConstantStorage()) + if (!ReserveConstantStorage()) return; - StateTracker::GetInstance()->SetGXUniformBuffer( - UBO_DESCRIPTOR_SET_BINDING_PS, m_uniform_stream_buffer->GetBuffer(), - m_uniform_stream_buffer->GetCurrentOffset(), sizeof(PixelShaderConstants)); - 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) + { + StateTracker::GetInstance()->SetGXUniformBuffer( + UBO_DESCRIPTOR_SET_BINDING_PS, m_uniform_stream_buffer->GetBuffer(), + m_uniform_stream_buffer->GetCurrentOffset(), sizeof(PixelShaderConstants)); + 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) + { + StateTracker::GetInstance()->SetGXUniformBuffer( + UBO_DESCRIPTOR_SET_BINDING_PS_CUST, m_uniform_stream_buffer->GetBuffer(), + m_uniform_stream_buffer->GetCurrentOffset(), + static_cast(pixel_shader_manager.custom_constants.size())); + 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(pixel_shader_manager.custom_constants.size())); + pixel_shader_manager.custom_constants_dirty = false; + } } bool VertexManager::ReserveConstantStorage() { - if (m_uniform_stream_buffer->ReserveMemory(m_uniform_buffer_reserve_size, + auto& system = Core::System::GetInstance(); + auto& pixel_shader_manager = system.GetPixelShaderManager(); + const u32 custom_constants_size = static_cast(pixel_shader_manager.custom_constants.size()); + + if (m_uniform_stream_buffer->ReserveMemory(m_uniform_buffer_reserve_size + custom_constants_size, g_vulkan_context->GetUniformBufferAlignment())) { return true; @@ -276,6 +297,11 @@ bool VertexManager::ReserveConstantStorage() void VertexManager::UploadAllConstants() { + auto& system = Core::System::GetInstance(); + auto& pixel_shader_manager = system.GetPixelShaderManager(); + + const u32 custom_constants_size = static_cast(pixel_shader_manager.custom_constants.size()); + // We are free to re-use parts of the buffer now since we're uploading all constants. const u32 ub_alignment = static_cast(g_vulkan_context->GetUniformBufferAlignment()); const u32 pixel_constants_offset = 0; @@ -283,7 +309,9 @@ void VertexManager::UploadAllConstants() Common::AlignUp(pixel_constants_offset + sizeof(PixelShaderConstants), ub_alignment); const u32 geometry_constants_offset = Common::AlignUp(vertex_constants_offset + sizeof(VertexShaderConstants), ub_alignment); - const u32 allocation_size = geometry_constants_offset + sizeof(GeometryShaderConstants); + const u32 custom_pixel_constants_offset = + Common::AlignUp(geometry_constants_offset + sizeof(GeometryShaderConstants), ub_alignment); + const u32 allocation_size = custom_pixel_constants_offset + custom_constants_size; // Allocate everything at once. // We should only be here if the buffer was full and a command buffer was submitted anyway. @@ -293,8 +321,6 @@ void VertexManager::UploadAllConstants() return; } - auto& system = Core::System::GetInstance(); - auto& pixel_shader_manager = system.GetPixelShaderManager(); auto& vertex_shader_manager = system.GetVertexShaderManager(); auto& geometry_shader_manager = system.GetGeometryShaderManager(); @@ -307,6 +333,14 @@ void VertexManager::UploadAllConstants() UBO_DESCRIPTOR_SET_BINDING_VS, m_uniform_stream_buffer->GetBuffer(), m_uniform_stream_buffer->GetCurrentOffset() + vertex_constants_offset, sizeof(VertexShaderConstants)); + + if (!pixel_shader_manager.custom_constants.empty()) + { + StateTracker::GetInstance()->SetGXUniformBuffer( + UBO_DESCRIPTOR_SET_BINDING_PS_CUST, m_uniform_stream_buffer->GetBuffer(), + m_uniform_stream_buffer->GetCurrentOffset() + custom_pixel_constants_offset, + custom_constants_size); + } StateTracker::GetInstance()->SetGXUniformBuffer( UBO_DESCRIPTOR_SET_BINDING_GS, m_uniform_stream_buffer->GetBuffer(), m_uniform_stream_buffer->GetCurrentOffset() + geometry_constants_offset, @@ -319,6 +353,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); diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index 5b552f9298..c4b6649331 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -93,7 +93,7 @@ ShaderCode GenerateGeometryShaderCode(APIType api_type, const ShaderHostConfig& // uniforms if (api_type == APIType::OpenGL || api_type == APIType::Vulkan) - out.Write("UBO_BINDING(std140, 3) uniform GSBlock {{\n"); + out.Write("UBO_BINDING(std140, 4) uniform GSBlock {{\n"); else out.Write("cbuffer GSBlock {{\n"); diff --git a/Source/Core/VideoCommon/UberShaderVertex.cpp b/Source/Core/VideoCommon/UberShaderVertex.cpp index 6e663a1d02..71fc974ced 100644 --- a/Source/Core/VideoCommon/UberShaderVertex.cpp +++ b/Source/Core/VideoCommon/UberShaderVertex.cpp @@ -52,7 +52,7 @@ ShaderCode GenVertexShader(APIType api_type, const ShaderHostConfig& host_config if (vertex_loader) { - out.Write("UBO_BINDING(std140, 3) uniform GSBlock {{\n"); + out.Write("UBO_BINDING(std140, 4) uniform GSBlock {{\n"); out.Write("{}", s_geometry_shader_uniforms); out.Write("}};\n"); } @@ -84,7 +84,7 @@ SSBO_BINDING(1) readonly restrict buffer Vertices {{ // D3D12 uses a root constant for this uniform, since it changes with every draw. // D3D11 doesn't currently support dynamic vertex loader, and we'll have to figure something // out for it if we want to support it in the future. - out.Write("UBO_BINDING(std140, 4) uniform DX_Constants {{\n" + out.Write("UBO_BINDING(std140, 5) uniform DX_Constants {{\n" " uint base_vertex;\n" "}};\n\n" "uint GetVertexBaseOffset(uint vertex_id) {{\n" diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index ff555b74fe..d2898cb412 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -96,14 +96,14 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho if (uid_data->vs_expand != VSExpand::None) { - out.Write("UBO_BINDING(std140, 3) uniform GSBlock {{\n"); + out.Write("UBO_BINDING(std140, 4) uniform GSBlock {{\n"); out.Write("{}", s_geometry_shader_uniforms); out.Write("}};\n"); if (api_type == APIType::D3D) { // D3D doesn't include the base vertex in SV_VertexID - out.Write("UBO_BINDING(std140, 4) uniform DX_Constants {{\n" + out.Write("UBO_BINDING(std140, 5) uniform DX_Constants {{\n" " uint base_vertex;\n" "}};\n\n"); }