Vulkan: Fix case where uniforms could be overwritten

If a draw caused a command buffer submission, the current uniform storage
should not be used for the new command buffer.
This commit is contained in:
Stenzek 2016-11-30 22:31:41 +10:00
parent 4c11735bd5
commit 3adeacb78d
3 changed files with 19 additions and 13 deletions

View File

@ -467,26 +467,21 @@ void StateTracker::UpdatePixelShaderConstants()
void StateTracker::UploadAllConstants()
{
// We are free to re-use parts of the buffer now since we're uploading all constants.
size_t ub_alignment = g_vulkan_context->GetUniformBufferAlignment();
size_t pixel_constants_offset = 0;
size_t vertex_constants_offset =
Util::AlignValue(pixel_constants_offset + sizeof(PixelShaderConstants),
g_vulkan_context->GetUniformBufferAlignment());
Util::AlignValue(pixel_constants_offset + sizeof(PixelShaderConstants), ub_alignment);
size_t geometry_constants_offset =
Util::AlignValue(vertex_constants_offset + sizeof(VertexShaderConstants),
g_vulkan_context->GetUniformBufferAlignment());
size_t total_allocation_size = geometry_constants_offset + sizeof(GeometryShaderConstants);
Util::AlignValue(vertex_constants_offset + sizeof(VertexShaderConstants), ub_alignment);
size_t allocation_size = geometry_constants_offset + sizeof(GeometryShaderConstants);
// Allocate everything at once.
if (!m_uniform_stream_buffer->ReserveMemory(
total_allocation_size, g_vulkan_context->GetUniformBufferAlignment(), true, true, false))
if (!m_uniform_stream_buffer->ReserveMemory(allocation_size, ub_alignment, true, true, false))
{
// If this fails, wait until the GPU has caught up.
// The only places that call constant updates are safe to have state restored.
WARN_LOG(VIDEO, "Executing command list while waiting for space in uniform buffer");
WARN_LOG(VIDEO, "Executing command buffer while waiting for space in uniform buffer");
Util::ExecuteCurrentCommandsAndRestoreState(false);
if (!m_uniform_stream_buffer->ReserveMemory(total_allocation_size,
g_vulkan_context->GetUniformBufferAlignment(), true,
true, false))
if (!m_uniform_stream_buffer->ReserveMemory(allocation_size, ub_alignment, true, true, false))
{
PanicAlert("Failed to allocate space for constants in streaming buffer");
return;
@ -528,7 +523,7 @@ void StateTracker::UploadAllConstants()
&GeometryShaderManager::constants, sizeof(GeometryShaderConstants));
// Finally, flush buffer memory after copying
m_uniform_stream_buffer->CommitMemory(total_allocation_size);
m_uniform_stream_buffer->CommitMemory(allocation_size);
// Clear dirty flags
VertexShaderManager::dirty = false;
@ -616,6 +611,13 @@ void StateTracker::InvalidateDescriptorSets()
m_dirty_flags &= ~DIRTY_FLAG_PS_SSBO;
}
void StateTracker::InvalidateConstants()
{
VertexShaderManager::dirty = true;
GeometryShaderManager::dirty = true;
PixelShaderManager::dirty = true;
}
void StateTracker::SetPendingRebind()
{
m_dirty_flags |= DIRTY_FLAG_DYNAMIC_OFFSETS | DIRTY_FLAG_DESCRIPTOR_SET_BINDING |

View File

@ -76,6 +76,9 @@ public:
// now be in a different pool for the new command buffer.
void InvalidateDescriptorSets();
// Same with the uniforms, as the current storage will belong to the previous command buffer.
void InvalidateConstants();
// Set dirty flags on everything to force re-bind at next draw time.
void SetPendingRebind();

View File

@ -200,6 +200,7 @@ void ExecuteCurrentCommandsAndRestoreState(bool execute_off_thread, bool wait_fo
StateTracker::GetInstance()->EndRenderPass();
g_command_buffer_mgr->ExecuteCommandBuffer(execute_off_thread, wait_for_completion);
StateTracker::GetInstance()->InvalidateDescriptorSets();
StateTracker::GetInstance()->InvalidateConstants();
StateTracker::GetInstance()->SetPendingRebind();
}