vulkan/overlay: Add a workaround semaphore for application presenting without one

When an application calls vkQueuePresent() on a different queue than
the one we run our drawing on and it doesn't give a semaphore to wait
on, let's insert our own semaphore so that we don't race the
application's drawing.

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Closes: https://gitlab.freedesktop.org/mesa/mesa/issues/2540
Tested-by: Marge Bot <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3893>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3893>
This commit is contained in:
Lionel Landwerlin
2020-02-20 14:29:22 +02:00
parent 5533c41541
commit 1271193932
+53 -19
View File
@@ -125,6 +125,8 @@ struct overlay_draw {
VkCommandBuffer command_buffer;
VkSemaphore cross_engine_semaphore;
VkSemaphore semaphore;
VkFence fence;
@@ -544,6 +546,8 @@ struct overlay_draw *get_overlay_draw(struct swapchain_data *data)
VK_CHECK(device_data->vtable.CreateSemaphore(device_data->device, &sem_info,
NULL, &draw->semaphore));
VK_CHECK(device_data->vtable.CreateSemaphore(device_data->device, &sem_info,
NULL, &draw->cross_engine_semaphore));
list_addtail(&draw->link, &data->draws);
@@ -1349,26 +1353,55 @@ static struct overlay_draw *render_swapchain_display(struct swapchain_data *data
device_data->vtable.EndCommandBuffer(draw->command_buffer);
VkPipelineStageFlags *stages_wait = (VkPipelineStageFlags*) malloc(sizeof(VkPipelineStageFlags) * n_wait_semaphores);
for (unsigned i = 0; i < n_wait_semaphores; i++)
{
// wait in the fragment stage until the swapchain image is ready
stages_wait[i] = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &draw->command_buffer;
submit_info.pWaitDstStageMask = stages_wait;
submit_info.waitSemaphoreCount = n_wait_semaphores;
submit_info.pWaitSemaphores = wait_semaphores;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &draw->semaphore;
/* When presenting on a different queue than where we're drawing the
* overlay *AND* when the application does not provide a semaphore to
* vkQueuePresent, insert our own cross engine synchronization
* semaphore.
*/
if (n_wait_semaphores == 0 && device_data->graphic_queue->queue != present_queue->queue) {
VkPipelineStageFlags stages_wait = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 0;
submit_info.pWaitDstStageMask = &stages_wait;
submit_info.waitSemaphoreCount = 0;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &draw->cross_engine_semaphore;
device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, draw->fence);
free(stages_wait);
device_data->vtable.QueueSubmit(present_queue->queue, 1, &submit_info, VK_NULL_HANDLE);
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 1;
submit_info.pWaitDstStageMask = &stages_wait;
submit_info.pCommandBuffers = &draw->command_buffer;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &draw->cross_engine_semaphore;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &draw->semaphore;
device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, draw->fence);
} else {
VkPipelineStageFlags *stages_wait = (VkPipelineStageFlags*) malloc(sizeof(VkPipelineStageFlags) * n_wait_semaphores);
for (unsigned i = 0; i < n_wait_semaphores; i++)
{
// wait in the fragment stage until the swapchain image is ready
stages_wait[i] = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &draw->command_buffer;
submit_info.pWaitDstStageMask = stages_wait;
submit_info.waitSemaphoreCount = n_wait_semaphores;
submit_info.pWaitSemaphores = wait_semaphores;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &draw->semaphore;
device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, draw->fence);
free(stages_wait);
}
return draw;
}
@@ -1750,6 +1783,7 @@ static void shutdown_swapchain_data(struct swapchain_data *data)
struct device_data *device_data = data->device;
list_for_each_entry_safe(struct overlay_draw, draw, &data->draws, link) {
device_data->vtable.DestroySemaphore(device_data->device, draw->cross_engine_semaphore, NULL);
device_data->vtable.DestroySemaphore(device_data->device, draw->semaphore, NULL);
device_data->vtable.DestroyFence(device_data->device, draw->fence, NULL);
device_data->vtable.DestroyBuffer(device_data->device, draw->vertex_buffer, NULL);