REQUIRED(FreeMemory) \
REQUIRED(CreateFence) \
REQUIRED(DestroyFence) \
+ REQUIRED(CreateSemaphore) \
+ REQUIRED(DestroySemaphore) \
REQUIRED(ResetFences) \
REQUIRED(WaitForFences) \
REQUIRED(DestroyDevice) \
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);
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)
{
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)
{
/* 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;
{
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);
{
/* Call implementation specific release */
destroy_image(img);
+
+ m_device_data.disp.DestroySemaphore(m_device, img.present_semaphore, get_allocation_callbacks());
}
}
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;
VkImage image{VK_NULL_HANDLE};
status status{swapchain_image::INVALID};
+ VkSemaphore present_semaphore{ VK_NULL_HANDLE };
};
/**
*
* @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.
*
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;