Handle present request for multiple swapchains

Adds an additional semaphore for every swapchain image to be waited for
before the present engine access an image. During a present request with
multiple swapchains, these semaphores are grouped together and are
signaled after the incoming pWaitSemaphores signal.

Signed-off-by: Iason Paraskevopoulos <iason.paraskevopoulos@arm.com>
Change-Id: I94cabbf5f7d9a45dceef60eec7773b48ccc32078
This commit is contained in:
Iason Paraskevopoulos 2021-10-20 15:27:47 +01:00
parent 02203b8412
commit 17204773df
4 changed files with 104 additions and 4 deletions

View file

@ -120,6 +120,8 @@ struct instance_dispatch_table
REQUIRED(FreeMemory) \
REQUIRED(CreateFence) \
REQUIRED(DestroyFence) \
REQUIRED(CreateSemaphore) \
REQUIRED(DestroySemaphore) \
REQUIRED(ResetFences) \
REQUIRED(WaitForFences) \
REQUIRED(DestroyDevice) \

View file

@ -127,6 +127,54 @@ VKAPI_ATTR VkResult wsi_layer_vkAcquireNextImageKHR(VkDevice device, VkSwapchain
return sc->acquire_next_image(timeout, semaphore, fence, pImageIndex);
}
static VkResult submit_wait_request(VkQueue queue, const VkPresentInfoKHR &present_info,
layer::device_private_data &device_data)
{
util::vector<VkSemaphore> swapchain_semaphores{ util::allocator(device_data.get_allocator(),
VK_SYSTEM_ALLOCATION_SCOPE_COMMAND) };
if (!swapchain_semaphores.try_resize(present_info.swapchainCount))
{
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
for (uint32_t i = 0; i < present_info.swapchainCount; ++i)
{
auto swapchain = reinterpret_cast<wsi::swapchain_base *>(present_info.pSwapchains[i]);
swapchain_semaphores[i] = swapchain->get_image_present_semaphore(present_info.pImageIndices[i]);
}
util::vector<VkPipelineStageFlags> pipeline_stage_flags{ util::allocator::get_generic() };
if (!pipeline_stage_flags.try_resize(present_info.waitSemaphoreCount))
{
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
for (uint32_t i = 0; i < present_info.waitSemaphoreCount; ++i)
{
pipeline_stage_flags[i] = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
}
VkSubmitInfo submit_info = {
VK_STRUCTURE_TYPE_SUBMIT_INFO,
NULL,
present_info.waitSemaphoreCount,
present_info.pWaitSemaphores,
pipeline_stage_flags.data(),
0,
NULL,
static_cast<uint32_t>(swapchain_semaphores.size()),
swapchain_semaphores.data(),
};
VkResult result = device_data.disp.QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
if (result != VK_SUCCESS)
{
return result;
}
return VK_SUCCESS;
}
VKAPI_ATTR VkResult wsi_layer_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo)
{
assert(queue != VK_NULL_HANDLE);
@ -139,6 +187,20 @@ VKAPI_ATTR VkResult wsi_layer_vkQueuePresentKHR(VkQueue queue, const VkPresentIn
return device_data.disp.QueuePresentKHR(queue, pPresentInfo);
}
/* Avoid allocating on the heap when there is only one swapchain. */
VkResult res = VK_SUCCESS;
const VkPresentInfoKHR *present_info = pPresentInfo;
if (pPresentInfo->swapchainCount > 1)
{
res = submit_wait_request(queue, *pPresentInfo, device_data);
if (res != VK_SUCCESS)
{
return res;
}
present_info = nullptr;
}
VkResult ret = VK_SUCCESS;
for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i)
{
@ -147,7 +209,7 @@ VKAPI_ATTR VkResult wsi_layer_vkQueuePresentKHR(VkQueue queue, const VkPresentIn
wsi::swapchain_base *sc = reinterpret_cast<wsi::swapchain_base *>(swapc);
assert(sc != nullptr);
VkResult res = sc->queue_present(queue, pPresentInfo, pPresentInfo->pImageIndices[i]);
res = sc->queue_present(queue, present_info, pPresentInfo->pImageIndices[i]);
if (pPresentInfo->pResults != nullptr)
{

View file

@ -199,7 +199,9 @@ VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *s
/* Init image to invalid values. */
if (!m_swapchain_images.try_resize(swapchain_create_info->minImageCount))
{
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
/* We have allocated images, we can call the platform init function if something needs to be done. */
bool use_presentation_thread = true;
@ -249,6 +251,15 @@ VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *s
{
return result;
}
VkSemaphoreCreateInfo semaphore_info = {};
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
result = m_device_data.disp.CreateSemaphore(m_device, &semaphore_info, get_allocation_callbacks(),
&img.present_semaphore);
if (result != VK_SUCCESS)
{
return result;
}
}
m_device_data.disp.GetDeviceQueue(m_device, 0, 0, &m_queue);
@ -352,6 +363,8 @@ void swapchain_base::teardown()
{
/* Call implementation specific release */
destroy_image(img);
m_device_data.disp.DestroySemaphore(m_device, img.present_semaphore, get_allocation_callbacks());
}
}
@ -481,8 +494,15 @@ VkResult swapchain_base::notify_presentation_engine(uint32_t image_index)
VkResult swapchain_base::queue_present(VkQueue queue, const VkPresentInfoKHR *present_info, const uint32_t image_index)
{
VkResult result = image_set_present_payload(m_swapchain_images[image_index], queue, present_info->pWaitSemaphores,
present_info->waitSemaphoreCount);
const VkSemaphore *wait_semaphores = &m_swapchain_images[image_index].present_semaphore;
uint32_t sem_count = 1;
if (present_info != nullptr)
{
wait_semaphores = present_info->pWaitSemaphores;
sem_count = present_info->waitSemaphoreCount;
}
VkResult result = image_set_present_payload(m_swapchain_images[image_index], queue, wait_semaphores, sem_count);
if (result != VK_SUCCESS)
{
return result;

View file

@ -60,6 +60,7 @@ struct swapchain_image
VkImage image{VK_NULL_HANDLE};
status status{swapchain_image::INVALID};
VkSemaphore present_semaphore{ VK_NULL_HANDLE };
};
/**
@ -124,7 +125,10 @@ public:
*
* @param queue The queue to which the submission will be made to.
*
* @param pPresentInfo Information about the swapchain and image to be presented.
* @param present_info Information about the swapchain and image to be presented.
* If it is nullptr it means that the presentation request will wait on the
* image's \p present_semaphore and not the semaphores that come with
* \p present_info.
*
* @param imageIndex The index of the image to be presented.
*
@ -169,6 +173,18 @@ public:
virtual VkResult bind_swapchain_image(VkDevice &device, const VkBindImageMemoryInfo *bind_image_mem_info,
const VkBindImageMemorySwapchainInfoKHR *bind_sc_info) = 0;
/**
* @brief Get image's present semaphore
*
* @param image_index Image's index
*
* @return the image's present_semaphore
*/
VkSemaphore get_image_present_semaphore(uint32_t image_index)
{
return m_swapchain_images[image_index].present_semaphore;
}
protected:
layer::device_private_data &m_device_data;