VK_PRESENT_MODE_FIFO_KHR,
};
+static uint32_t
+wsi_wl_surface_get_min_image_count(const VkSurfacePresentModeEXT *present_mode)
+{
+ if (present_mode && (present_mode->presentMode == VK_PRESENT_MODE_FIFO_KHR ||
+ present_mode->presentMode == VK_PRESENT_MODE_FIFO_RELAXED_KHR)) {
+ /* If we receive a FIFO present mode, only 2 images is required for forward progress.
+ * Performance with 2 images will be questionable, but we only allow it for applications
+ * using the new API, so we don't risk breaking any existing apps this way.
+ * Other ICDs expose 2 images here already. */
+ return 2;
+ } else {
+ /* For true mailbox mode, we need at least 4 images:
+ * 1) One to scan out from
+ * 2) One to have queued for scan-out
+ * 3) One to be currently held by the Wayland compositor
+ * 4) One to render to
+ */
+ return 4;
+ }
+}
+
+static uint32_t
+wsi_wl_surface_get_min_image_count_for_mode_group(const VkSwapchainPresentModesCreateInfoEXT *modes)
+{
+ /* If we don't provide the PresentModeCreateInfo struct, we must be backwards compatible,
+ * and assume that minImageCount is the default one, i.e. 4, which supports both FIFO and MAILBOX. */
+ if (!modes) {
+ return wsi_wl_surface_get_min_image_count(NULL);
+ }
+
+ uint32_t max_required = 0;
+ for (uint32_t i = 0; i < modes->presentModeCount; i++) {
+ const VkSurfacePresentModeEXT mode = {
+ VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT,
+ NULL,
+ modes->pPresentModes[i]
+ };
+ max_required = MAX2(max_required, wsi_wl_surface_get_min_image_count(&mode));
+ }
+
+ return max_required;
+}
+
static VkResult
wsi_wl_surface_get_capabilities(VkIcdSurfaceBase *surface,
struct wsi_device *wsi_device,
+ const VkSurfacePresentModeEXT *present_mode,
VkSurfaceCapabilitiesKHR* caps)
{
- /* For true mailbox mode, we need at least 4 images:
- * 1) One to scan out from
- * 2) One to have queued for scan-out
- * 3) One to be currently held by the Wayland compositor
- * 4) One to render to
- */
- caps->minImageCount = 4;
+ caps->minImageCount = wsi_wl_surface_get_min_image_count(present_mode);
/* There is no real maximum */
caps->maxImageCount = 0;
{
assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);
+ const VkSurfacePresentModeEXT *present_mode = vk_find_struct_const(info_next, SURFACE_PRESENT_MODE_EXT);
+
VkResult result =
- wsi_wl_surface_get_capabilities(surface, wsi_device,
+ wsi_wl_surface_get_capabilities(surface, wsi_device, present_mode,
&caps->surfaceCapabilities);
vk_foreach_struct(ext, caps->pNext) {
break;
}
+ case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT: {
+ /* Unsupported. */
+ VkSurfacePresentScalingCapabilitiesEXT *scaling = (void *)ext;
+ scaling->supportedPresentScaling = 0;
+ scaling->supportedPresentGravityX = 0;
+ scaling->supportedPresentGravityY = 0;
+ scaling->minScaledImageExtent = caps->surfaceCapabilities.minImageExtent;
+ scaling->maxScaledImageExtent = caps->surfaceCapabilities.maxImageExtent;
+ break;
+ }
+
+ case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT: {
+ /* Can easily toggle between FIFO and MAILBOX on Wayland. */
+ assert(present_mode);
+ VkSurfacePresentModeCompatibilityEXT *compat = (void *)ext;
+ if (compat->pPresentModes) {
+ VK_OUTARRAY_MAKE_TYPED(VkPresentModeKHR, modes, compat->pPresentModes, &compat->presentModeCount);
+ /* Must always return queried present mode even when truncating. */
+ vk_outarray_append_typed(VkPresentModeKHR, &modes, mode) {
+ *mode = present_mode->presentMode;
+ }
+ for (unsigned i = 0; i < ARRAY_SIZE(present_modes); i++) {
+ if (present_modes[i] != present_mode->presentMode) {
+ vk_outarray_append_typed(VkPresentModeKHR, &modes, mode) {
+ *mode = present_modes[i];
+ }
+ }
+ }
+ } else {
+ compat->presentModeCount = ARRAY_SIZE(present_modes);
+ }
+ break;
+ }
+
default:
/* Ignored */
break;
}
static VkResult
+wsi_wl_swapchain_release_images(struct wsi_swapchain *wsi_chain,
+ uint32_t count, const uint32_t *indices)
+{
+ struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;
+ for (uint32_t i = 0; i < count; i++) {
+ uint32_t index = indices[i];
+ assert(chain->images[index].busy);
+ chain->images[index].busy = false;
+ }
+ return VK_SUCCESS;
+}
+
+static void
+wsi_wl_swapchain_set_present_mode(struct wsi_swapchain *wsi_chain,
+ VkPresentModeKHR mode)
+{
+ struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;
+ chain->base.present_mode = mode;
+}
+
+static VkResult
wsi_wl_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain,
const VkAcquireNextImageInfoKHR *info,
uint32_t *image_index)
memcpy(image->shm_ptr, image->base.cpu_map,
image->base.row_pitches[0] * chain->extent.height);
}
- if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) {
- while (!chain->fifo_ready) {
- int ret = wl_display_dispatch_queue(wsi_wl_surface->display->wl_display,
- wsi_wl_surface->display->queue);
- if (ret < 0)
- return VK_ERROR_OUT_OF_DATE_KHR;
- }
+
+ /* For EXT_swapchain_maintenance1. We might have transitioned from FIFO to MAILBOX.
+ * In this case we need to let the FIFO request complete, before presenting MAILBOX. */
+ while (!chain->fifo_ready) {
+ int ret = wl_display_dispatch_queue(wsi_wl_surface->display->wl_display,
+ wsi_wl_surface->display->queue);
+ if (ret < 0)
+ return VK_ERROR_OUT_OF_DATE_KHR;
}
assert(image_index < chain->base.image_count);
chain->frame = wl_surface_frame(wsi_wl_surface->surface);
wl_callback_add_listener(chain->frame, &frame_listener, chain);
chain->fifo_ready = false;
+ } else {
+ /* If we present MAILBOX, any subsequent presentation in FIFO can replace this image. */
+ chain->fifo_ready = true;
}
chain->images[image_index].busy = true;
chain->base.get_wsi_image = wsi_wl_swapchain_get_wsi_image;
chain->base.acquire_next_image = wsi_wl_swapchain_acquire_next_image;
chain->base.queue_present = wsi_wl_swapchain_queue_present;
+ chain->base.release_images = wsi_wl_swapchain_release_images;
+ chain->base.set_present_mode = wsi_wl_swapchain_set_present_mode;
chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, pCreateInfo);
chain->base.image_count = num_images;
chain->extent = pCreateInfo->imageExtent;