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() void StateTracker::UploadAllConstants()
{ {
// We are free to re-use parts of the buffer now since we're uploading all constants. // 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 pixel_constants_offset = 0;
size_t vertex_constants_offset = size_t vertex_constants_offset =
Util::AlignValue(pixel_constants_offset + sizeof(PixelShaderConstants), Util::AlignValue(pixel_constants_offset + sizeof(PixelShaderConstants), ub_alignment);
g_vulkan_context->GetUniformBufferAlignment());
size_t geometry_constants_offset = size_t geometry_constants_offset =
Util::AlignValue(vertex_constants_offset + sizeof(VertexShaderConstants), Util::AlignValue(vertex_constants_offset + sizeof(VertexShaderConstants), ub_alignment);
g_vulkan_context->GetUniformBufferAlignment()); size_t allocation_size = geometry_constants_offset + sizeof(GeometryShaderConstants);
size_t total_allocation_size = geometry_constants_offset + sizeof(GeometryShaderConstants);
// Allocate everything at once. // Allocate everything at once.
if (!m_uniform_stream_buffer->ReserveMemory( if (!m_uniform_stream_buffer->ReserveMemory(allocation_size, ub_alignment, true, true, false))
total_allocation_size, g_vulkan_context->GetUniformBufferAlignment(), 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. // 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); Util::ExecuteCurrentCommandsAndRestoreState(false);
if (!m_uniform_stream_buffer->ReserveMemory(total_allocation_size, if (!m_uniform_stream_buffer->ReserveMemory(allocation_size, ub_alignment, true, true, false))
g_vulkan_context->GetUniformBufferAlignment(), true,
true, false))
{ {
PanicAlert("Failed to allocate space for constants in streaming buffer"); PanicAlert("Failed to allocate space for constants in streaming buffer");
return; return;
@ -528,7 +523,7 @@ void StateTracker::UploadAllConstants()
&GeometryShaderManager::constants, sizeof(GeometryShaderConstants)); &GeometryShaderManager::constants, sizeof(GeometryShaderConstants));
// Finally, flush buffer memory after copying // Finally, flush buffer memory after copying
m_uniform_stream_buffer->CommitMemory(total_allocation_size); m_uniform_stream_buffer->CommitMemory(allocation_size);
// Clear dirty flags // Clear dirty flags
VertexShaderManager::dirty = false; VertexShaderManager::dirty = false;
@ -616,6 +611,13 @@ void StateTracker::InvalidateDescriptorSets()
m_dirty_flags &= ~DIRTY_FLAG_PS_SSBO; m_dirty_flags &= ~DIRTY_FLAG_PS_SSBO;
} }
void StateTracker::InvalidateConstants()
{
VertexShaderManager::dirty = true;
GeometryShaderManager::dirty = true;
PixelShaderManager::dirty = true;
}
void StateTracker::SetPendingRebind() void StateTracker::SetPendingRebind()
{ {
m_dirty_flags |= DIRTY_FLAG_DYNAMIC_OFFSETS | DIRTY_FLAG_DESCRIPTOR_SET_BINDING | 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. // now be in a different pool for the new command buffer.
void InvalidateDescriptorSets(); 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. // Set dirty flags on everything to force re-bind at next draw time.
void SetPendingRebind(); void SetPendingRebind();

View File

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