// Copyright 2022-2023 The Khronos Group Inc. // // SPDX-License-Identifier: CC-BY-4.0 = VK_EXT_surface_maintenance1 :toc: left :refpage: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/ :sectnums: This proposal investigates and addresses a number of practical issues with the `VK_KHR_surface` specification. == Problem Statement The following is a list of issues considered in this proposal: * Min and max image count as reported in `VkSurfaceCapabilitiesKHR` depend on present mode. * The scaling behavior of the surface is undefined when the swapchain and the surface dimensions do not match. * Switching between some present modes technically should not require recreating the swapchain === Image Count Query Per Present Mode The implementation may require a different number of images, as reported in `VkSurfaceCapabilitiesKHR::minImageCount` and `VkSurfaceCapabilitiesKHR::maxImageCount` depending on the desired present mode. However, there is currently no way to specify the present mode when calling `vkGetPhysicalDeviceSurfaceCapabilitiesKHR`. === Undefined Scaling Behavior Currently, a few of the surface extensions (such as `VK_KHR_xcb_surface` and `VK_KHR_win32_surface`) require the swapchain's extents to match the surface's. A mismatch between the swapchain and the surface dimensions, as the window is resized, would result in `VK_ERROR_OUT_OF_DATE_KHR`, which can be undesirable behavior. On other surfaces where scaling happens, it is undefined how the image is scaled. The image may stretch, scale with fixed aspect ratio, snap to a corner or be centered. === Switching Present Modes Certain present modes are compatible, such that a swapchain operating under one mode can be easily switched to another. In such a case, recreating the swapchain is undesirable. See the proposal for `VK_EXT_swapchain_maintenance1` for details. == Solution Space === Image Count Query Per Present Mode This issue can be rectified by providing the desired present mode when querying surface capabilities. === Undefined Scaling Behavior This issue can be resolved by the application querying and opting in to a specific supported scaling behavior. Potential behaviors are: * Stretch the swapchain image to the dimensions of the surface * Stretch the swapchain image while maintaining the aspect ratio to fit within the surface * No scaling applied, and swapchain pixels are mapped one-to-one to the surface When the resulting image does not cover the entire surface, additional behavior can be specified for each of the X and Y axes: * Gravitate to left/top * Gravitate to right/bottom * Center This extension allows the supported behavior to be queried, while `VK_EXT_swapchain_maintenance1` would be used to select the desired behavior at swapchain creation time. === Switching Present Modes To support the `VK_EXT_swapchain_maintenance1` extension and allow creating swapchains that may change present modes, it should be possible to query the set of compatible present modes for this purpose. This can be done by providing one present mode and querying the list of compatible present modes from the surface. == Proposal Introduced by this API are: === Image Count Query Per Present Mode To query the min and max image counts for a specific present mode, chain the following to `VkPhysicalDeviceSurfaceInfo2KHR` when calling `vkGetPhysicalDeviceSurfaceCapabilities2KHR`: [source,c] ---- typedef struct VkSurfacePresentModeEXT { VkStructureType sType; void* pNext; VkPresentModeKHR presentMode; } VkSurfacePresentModeEXT; ---- The returned values in `VkSurfaceCapabilitiesKHR::minImageCount` and `VkSurfaceCapabilitiesKHR::maxImageCount` would then be specific to the given present mode. === Undefined Scaling Behavior To query supported scaling behavior, chain `VkSurfacePresentModeEXT` to `VkPhysicalDeviceSurfaceInfo2KHR` and chain the following to `VkSurfaceCapabilities2KHR`: [source,c] ---- typedef struct VkSurfacePresentScalingCapabilitiesEXT { VkStructureType sType; void* pNext; VkPresentScalingFlagsEXT supportedPresentScaling; VkPresentGravityFlagsEXT supportedPresentGravityX; VkPresentGravityFlagsEXT supportedPresentGravityY; VkExtent2D minScaledImageExtent; VkExtent2D maxScaledImageExtent; } VkSurfacePresentScalingCapabilitiesEXT; ---- Where `VkPresentScalingFlagsEXT` is defined as: [source,c] ---- typedef enum VkPresentScalingFlagBitsEXT { VK_PRESENT_SCALING_ONE_TO_ONE_BIT_EXT = 0x00000001, VK_PRESENT_SCALING_ASPECT_RATIO_STRETCH_BIT_EXT = 0x00000002, VK_PRESENT_SCALING_STRETCH_BIT_EXT = 0x00000004, } VkPresentScalingFlagBitsEXT; typedef VkFlags VkPresentScalingFlagsEXT; ---- And `VkPresentGravityFlagsEXT` is defined as: [source,c] ---- typedef enum VkPresentGravityFlagBitsEXT { VK_PRESENT_GRAVITY_MIN_BIT_EXT = 0x00000001, VK_PRESENT_GRAVITY_MAX_BIT_EXT = 0x00000002, VK_PRESENT_GRAVITY_CENTERED_BIT_EXT = 0x00000004, } VkPresentGravityFlagBitsEXT; typedef VkFlags VkPresentGravityFlagsEXT; ---- Note that scaling may not be supported for certain present modes. The `VK_EXT_swapchain_maintenance1` extension must be used to create a swapchain with a supported behavior. Swapchains created with scaling enabled, must use image extents that are bounded by `minScaledImageExtent` and `maxScaledImageExtent`. === Switching Present Modes To query the list of compatible present modes with a given present mode for the purposes of mode switching, chain `VkSurfacePresentModeEXT` to `VkPhysicalDeviceSurfaceInfo2KHR` and chain the following to `VkSurfaceCapabilities2KHR`: [source,c] ---- typedef struct VkSurfacePresentModeCompatibilityEXT { VkStructureType sType; void* pNext; uint32_t presentModeCount; VkPresentMode* pPresentModes; } VkSurfacePresentModeCompatibilityEXT; ---- The implementation will return the count of compatible present modes in `presentModeCount`, and if provided, the list of them in `pPresentModes`. == Issues