VideoBackends / VideoCommon: add new uniform buffer object for custom shader materials (slot 3, geometry shader buffer moves to slot 4 if available)

This commit is contained in:
iwubcode 2023-09-19 19:29:38 -05:00
parent 92accc3ef7
commit b6d321bfb1
16 changed files with 214 additions and 83 deletions

View File

@ -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)

View File

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

View File

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

View File

@ -68,6 +68,9 @@ private:
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;

View File

@ -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<const DXPipeline*>(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)

View File

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

View File

@ -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<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;
@ -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<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.
@ -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);

View File

@ -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(&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.
@ -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);
}

View File

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

View File

@ -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<u32>(
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);

View File

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

View File

@ -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<VkDescriptorSetLayoutBinding, 3> standard_ubo_bindings{{
static const std::array<VkDescriptorSetLayoutBinding, 4> 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<VkDescriptorSetLayoutBinding, 3> ubo_bindings = standard_ubo_bindings;
std::array<VkDescriptorSetLayoutBinding, 4> ubo_bindings = standard_ubo_bindings;
std::array<VkDescriptorSetLayoutCreateInfo, NUM_DESCRIPTOR_SET_LAYOUTS> create_infos{{
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,

View File

@ -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<u32>(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<u32>(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<u32>(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<u32>(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<u32>(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);

View File

@ -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");

View File

@ -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"

View File

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