From 5cc8a3953c7986bec781d7c1f8a014195ca4bf6b Mon Sep 17 00:00:00 2001 From: assiduous Date: Thu, 23 Apr 2020 20:55:17 -0700 Subject: Added surface pretransform parameter to swap chain desc (API 240057) --- .../include/SwapChainVkImpl.hpp | 9 ++- .../include/VulkanTypeConversions.hpp | 12 ++-- .../GraphicsEngineVulkan/src/SwapChainVkImpl.cpp | 64 +++++++++++++++++++--- .../src/VulkanTypeConversions.cpp | 49 +++++++++++++++++ 4 files changed, 121 insertions(+), 13 deletions(-) (limited to 'Graphics/GraphicsEngineVulkan') diff --git a/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.hpp index 289dbe55..6bfc15ea 100644 --- a/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.hpp @@ -58,7 +58,7 @@ public: virtual void DILIGENT_CALL_TYPE Present(Uint32 SyncInterval) override final; /// Implementation of ISwapChain::Resize() in Vulkan backend. - virtual void DILIGENT_CALL_TYPE Resize(Uint32 NewWidth, Uint32 NewHeight) override final; + virtual void DILIGENT_CALL_TYPE Resize(Uint32 NewWidth, Uint32 NewHeight, SURFACE_TRANSFORM NewPreTransform) override final; /// Implementation of ISwapChain::SetFullscreenMode() in Vulkan backend. virtual void DILIGENT_CALL_TYPE SetFullscreenMode(const DisplayModeAttribs& DisplayMode) override final; @@ -92,6 +92,13 @@ private: VkSwapchainKHR m_VkSwapChain = VK_NULL_HANDLE; VkFormat m_VkColorFormat = VK_FORMAT_UNDEFINED; +#if PLATFORM_ANDROID + // Surface extent corresponding to identity transform. We have to store this value, + // because on Android vkGetPhysicalDeviceSurfaceCapabilitiesKHR is not reliable and + // starts reporting incorrect dimensions after few rotations. + VkExtent2D m_SurfaceIdentityExtent = {}; +#endif + std::vector> m_ImageAcquiredSemaphores; std::vector> m_DrawCompleteSemaphores; std::vector m_ImageAcquiredFences; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp index 1f752700..15420ead 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp @@ -32,6 +32,7 @@ #include #include "GraphicsTypes.h" +#include "InputLayout.h" namespace Diligent { @@ -41,14 +42,14 @@ TEXTURE_FORMAT VkFormatToTexFormat(VkFormat VkFmt); VkFormat TypeToVkFormat(VALUE_TYPE ValType, Uint32 NumComponents, Bool bIsNormalized); -VkPipelineRasterizationStateCreateInfo RasterizerStateDesc_To_VkRasterizationStateCI(const RasterizerStateDesc& RasterizerDesc); -VkPipelineDepthStencilStateCreateInfo DepthStencilStateDesc_To_VkDepthStencilStateCI(const DepthStencilStateDesc& DepthStencilDesc); +VkPipelineRasterizationStateCreateInfo RasterizerStateDesc_To_VkRasterizationStateCI(const struct RasterizerStateDesc& RasterizerDesc); +VkPipelineDepthStencilStateCreateInfo DepthStencilStateDesc_To_VkDepthStencilStateCI(const struct DepthStencilStateDesc& DepthStencilDesc); -void BlendStateDesc_To_VkBlendStateCI(const BlendStateDesc& BSDesc, +void BlendStateDesc_To_VkBlendStateCI(const struct BlendStateDesc& BSDesc, VkPipelineColorBlendStateCreateInfo& ColorBlendStateCI, std::vector& ColorBlendAttachments); -void InputLayoutDesc_To_VkVertexInputStateCI(const InputLayoutDesc& LayoutDesc, +void InputLayoutDesc_To_VkVertexInputStateCI(const struct InputLayoutDesc& LayoutDesc, VkPipelineVertexInputStateCreateInfo& VertexInputStateCI, std::array& BindingDescriptions, std::array& AttributeDescription); @@ -69,4 +70,7 @@ VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag); RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlags AccessFlags); RESOURCE_STATE VkImageLayoutToResourceState(VkImageLayout Layout); +SURFACE_TRANSFORM VkSurfaceTransformFlagToSurfaceTransform(VkSurfaceTransformFlagBitsKHR vkTransformFlag); +VkSurfaceTransformFlagBitsKHR SurfaceTransformToVkSurfaceTransformFlag(SURFACE_TRANSFORM SrfTransform); + } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp index da2f9b98..69c8d5cc 100644 --- a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp @@ -207,6 +207,35 @@ void SwapChainVkImpl::CreateVulkanSwapChain() CHECK_VK_ERROR_AND_THROW(err, "Failed to query surface present modes"); VERIFY_EXPR(presentModeCount == presentModes.size()); + + VkSurfaceTransformFlagBitsKHR vkPreTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + if (m_DesiredPreTransform != SURFACE_TRANSFORM_OPTIMAL) + { + vkPreTransform = SurfaceTransformToVkSurfaceTransformFlag(m_DesiredPreTransform); + if ((surfCapabilities.supportedTransforms & vkPreTransform) != 0) + { + m_SwapChainDesc.PreTransform = m_DesiredPreTransform; + } + else + { + LOG_WARNING_MESSAGE(GetSurfaceTransformString(m_DesiredPreTransform), + " is not supported by the presentation engine. Optimal surface transform will be used instead." + " Query the swap chain description to get the actual surface transform."); + m_DesiredPreTransform = SURFACE_TRANSFORM_OPTIMAL; + } + } + + if (m_DesiredPreTransform == SURFACE_TRANSFORM_OPTIMAL) + { + // Use current surface transform to avoid extra cost of presenting the image. + // If preTransform does not match the currentTransform value returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR, + // the presentation engine will transform the image content as part of the presentation operation. + // https://android-developers.googleblog.com/2020/02/handling-device-orientation-efficiently.html + // https://community.arm.com/developer/tools-software/graphics/b/blog/posts/appropriate-use-of-surface-rotation + vkPreTransform = surfCapabilities.currentTransform; + m_SwapChainDesc.PreTransform = VkSurfaceTransformFlagToSurfaceTransform(vkPreTransform); + } + VkExtent2D swapchainExtent = {}; // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF. if (surfCapabilities.currentExtent.width == 0xFFFFFFFF && m_SwapChainDesc.Width != 0 && m_SwapChainDesc.Height != 0) @@ -221,6 +250,30 @@ void SwapChainVkImpl::CreateVulkanSwapChain() // If the surface size is defined, the swap chain size must match swapchainExtent = surfCapabilities.currentExtent; } + +#if PLATFORM_ANDROID + // On Android, vkGetPhysicalDeviceSurfaceCapabilitiesKHR is not reliable and starts reporting incorrect + // dimensions after few rotations. To alleviate the problem, we store the surface extent corresponding to + // identity rotation. + // https://android-developers.googleblog.com/2020/02/handling-device-orientation-efficiently.html + if (m_SurfaceIdentityExtent.width == 0 || m_SurfaceIdentityExtent.height == 0) + { + m_SurfaceIdentityExtent = surfCapabilities.currentExtent; + constexpr auto Rotate90TransformFlags = + VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | + VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR | + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR | + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR; + if ((surfCapabilities.currentTransform & Rotate90TransformFlags) != 0) + std::swap(m_SurfaceIdentityExtent.width, m_SurfaceIdentityExtent.height); + } + + if (m_DesiredPreTransform == SURFACE_TRANSFORM_OPTIMAL) + { + swapchainExtent = m_SurfaceIdentityExtent; + } +#endif + swapchainExtent.width = std::max(swapchainExtent.width, 1u); swapchainExtent.height = std::max(swapchainExtent.height, 1u); m_SwapChainDesc.Width = swapchainExtent.width; @@ -273,11 +326,6 @@ void SwapChainVkImpl::CreateVulkanSwapChain() } uint32_t desiredNumberOfSwapChainImages = m_SwapChainDesc.BufferCount; - VkSurfaceTransformFlagBitsKHR preTransform = - (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? - VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : - surfCapabilities.currentTransform; - // Find a supported composite alpha mode - one of these is guaranteed to be set VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = // @@ -308,7 +356,7 @@ void SwapChainVkImpl::CreateVulkanSwapChain() swapchain_ci.imageFormat = m_VkColorFormat; swapchain_ci.imageExtent.width = swapchainExtent.width; swapchain_ci.imageExtent.height = swapchainExtent.height; - swapchain_ci.preTransform = preTransform; + swapchain_ci.preTransform = vkPreTransform; swapchain_ci.compositeAlpha = compositeAlpha; swapchain_ci.imageArrayLayers = 1; swapchain_ci.presentMode = swapchainPresentMode; @@ -705,9 +753,9 @@ void SwapChainVkImpl::RecreateVulkanSwapchain(DeviceContextVkImpl* pImmediateCtx InitBuffersAndViews(); } -void SwapChainVkImpl::Resize(Uint32 NewWidth, Uint32 NewHeight) +void SwapChainVkImpl::Resize(Uint32 NewWidth, Uint32 NewHeight, SURFACE_TRANSFORM NewPreTransform) { - if (TSwapChainBase::Resize(NewWidth, NewHeight)) + if (TSwapChainBase::Resize(NewWidth, NewHeight, NewPreTransform)) { auto pDeviceContext = m_wpDeviceContext.Lock(); VERIFY(pDeviceContext, "Immediate context has been released"); diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp index 26a2fcf5..d5e4f48b 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp @@ -31,6 +31,7 @@ #include "VulkanTypeConversions.hpp" #include "PlatformMisc.hpp" +#include "Align.hpp" namespace Diligent { @@ -1372,4 +1373,52 @@ RESOURCE_STATE VkImageLayoutToResourceState(VkImageLayout Layout) } } +SURFACE_TRANSFORM VkSurfaceTransformFlagToSurfaceTransform(VkSurfaceTransformFlagBitsKHR vkTransformFlag) +{ + VERIFY(IsPowerOfTwo(static_cast(vkTransformFlag)), "Only single transform bit is expected"); + + // clang-format off + switch (vkTransformFlag) + { + case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: return SURFACE_TRANSFORM_IDENTITY; + case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: return SURFACE_TRANSFORM_ROTATE_90; + case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: return SURFACE_TRANSFORM_ROTATE_180; + case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: return SURFACE_TRANSFORM_ROTATE_270; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR: return SURFACE_TRANSFORM_HORIZONTAL_MIRROR; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR: return SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR: return SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR: return SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270; + + default: + UNEXPECTED("Unexpected surface transform"); + return SURFACE_TRANSFORM_IDENTITY; + } + // clang-format on +} + +VkSurfaceTransformFlagBitsKHR SurfaceTransformToVkSurfaceTransformFlag(SURFACE_TRANSFORM SrfTransform) +{ + // clang-format off + switch (SrfTransform) + { + case SURFACE_TRANSFORM_OPTIMAL: + UNEXPECTED("Optimal transform does not have corresponding Vulkan flag"); + return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + + case SURFACE_TRANSFORM_IDENTITY: return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + case SURFACE_TRANSFORM_ROTATE_90: return VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR; + case SURFACE_TRANSFORM_ROTATE_180: return VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR; + case SURFACE_TRANSFORM_ROTATE_270: return VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; + case SURFACE_TRANSFORM_HORIZONTAL_MIRROR: return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR; + case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90: return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR; + case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180: return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR; + case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270: return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR; + + default: + UNEXPECTED("Unexpected surface transform"); + return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + } + // clang-format on +} + } // namespace Diligent -- cgit v1.2.3