From 4f160d69a64bd5c7d444d333c744b167d0d347a0 Mon Sep 17 00:00:00 2001
From: Dan Ginsburg <[EMAIL REDACTED]>
Date: Fri, 25 Oct 2024 16:35:07 -0400
Subject: [PATCH] Closes #10318 - implement Android prerotation in the Vulkan
renderer
---
src/render/vulkan/SDL_render_vulkan.c | 88 +++++++++++++++++++++++++--
1 file changed, 82 insertions(+), 6 deletions(-)
diff --git a/src/render/vulkan/SDL_render_vulkan.c b/src/render/vulkan/SDL_render_vulkan.c
index d99bf8cbed038..2ccad3e080baa 100644
--- a/src/render/vulkan/SDL_render_vulkan.c
+++ b/src/render/vulkan/SDL_render_vulkan.c
@@ -361,6 +361,7 @@ typedef struct
uint32_t swapchainDesiredImageCount;
VkSurfaceFormatKHR surfaceFormat;
VkExtent2D swapchainSize;
+ VkSurfaceTransformFlagBitsKHR swapChainPreTransform;
uint32_t swapchainImageCount;
VkImage *swapchainImages;
VkImageView *swapchainImageViews;
@@ -477,6 +478,8 @@ static bool VULKAN_FindMemoryTypeIndex(VULKAN_RenderData *rendererData, uint32_t
static VkResult VULKAN_CreateWindowSizeDependentResources(SDL_Renderer *renderer);
static VkDescriptorPool VULKAN_AllocateDescriptorPool(VULKAN_RenderData *rendererData);
static VkResult VULKAN_CreateDescriptorSetAndPipelineLayout(VULKAN_RenderData *rendererData, VkSampler samplerYcbcr, VkDescriptorSetLayout *descriptorSetLayoutOut, VkPipelineLayout *pipelineLayoutOut);
+static VkSurfaceTransformFlagBitsKHR VULKAN_GetRotationForCurrentRenderTarget(VULKAN_RenderData *rendererData);
+static bool VULKAN_IsDisplayRotated90Degrees(VkSurfaceTransformFlagBitsKHR rotation);
static void VULKAN_DestroyAll(SDL_Renderer *renderer)
{
@@ -923,6 +926,7 @@ static void VULKAN_BeginRenderPass(VULKAN_RenderData *rendererData, VkAttachment
width = rendererData->textureRenderTarget->width;
height = rendererData->textureRenderTarget->height;
}
+
switch (loadOp) {
case VK_ATTACHMENT_LOAD_OP_CLEAR:
rendererData->currentRenderPass = rendererData->textureRenderTarget ?
@@ -2212,6 +2216,15 @@ static VkResult VULKAN_CreateSwapChain(SDL_Renderer *renderer, int w, int h)
rendererData->surfaceCapabilities.minImageExtent.height,
rendererData->surfaceCapabilities.maxImageExtent.height);
+ // Handle rotation
+ rendererData->swapChainPreTransform = rendererData->surfaceCapabilities.currentTransform;
+ if (rendererData->swapChainPreTransform == VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR ||
+ rendererData->swapChainPreTransform == VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
+ uint32_t tempWidth = rendererData->swapchainSize.width;
+ rendererData->swapchainSize.width = rendererData->swapchainSize.height;
+ rendererData->swapchainSize.height = tempWidth;
+ }
+
if (rendererData->swapchainSize.width == 0 && rendererData->swapchainSize.height == 0) {
// Don't recreate the swapchain if size is (0,0), just fail and continue attempting creation
return VK_ERROR_OUT_OF_DATE_KHR;
@@ -2275,7 +2288,7 @@ static VkResult VULKAN_CreateSwapChain(SDL_Renderer *renderer, int w, int h)
swapchainCreateInfo.imageArrayLayers = 1;
swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
- swapchainCreateInfo.preTransform = rendererData->surfaceCapabilities.currentTransform;
+ swapchainCreateInfo.preTransform = rendererData->swapChainPreTransform;
swapchainCreateInfo.compositeAlpha = (renderer->window->flags & SDL_WINDOW_TRANSPARENT) ? (VkCompositeAlphaFlagBitsKHR)0 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
swapchainCreateInfo.presentMode = presentMode;
swapchainCreateInfo.clipped = VK_TRUE;
@@ -3249,12 +3262,34 @@ static bool VULKAN_UpdateVertexBuffer(SDL_Renderer *renderer,
return true;
}
+static VkSurfaceTransformFlagBitsKHR VULKAN_GetRotationForCurrentRenderTarget(VULKAN_RenderData *rendererData)
+{
+ if (rendererData->textureRenderTarget) {
+ return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+ } else {
+ return rendererData->swapChainPreTransform;
+ }
+}
+
+static bool VULKAN_IsDisplayRotated90Degrees(VkSurfaceTransformFlagBitsKHR rotation)
+{
+ switch (rotation) {
+ case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
+ case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
+ return true;
+ default:
+ return false;
+ }
+}
+
static bool VULKAN_UpdateViewport(SDL_Renderer *renderer)
{
VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal;
const SDL_Rect *viewport = &rendererData->currentViewport;
Float4X4 projection;
Float4X4 view;
+ VkSurfaceTransformFlagBitsKHR rotation = VULKAN_GetRotationForCurrentRenderTarget(rendererData);
+ bool swapDimensions;
if (viewport->w == 0 || viewport->h == 0) {
/* If the viewport is empty, assume that it is because
@@ -3265,7 +3300,22 @@ static bool VULKAN_UpdateViewport(SDL_Renderer *renderer)
return false;
}
- projection = MatrixIdentity();
+ switch (rotation) {
+ case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
+ projection = MatrixRotationZ(SDL_PI_F * 0.5f);
+ break;
+ case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
+ projection = MatrixRotationZ(SDL_PI_F);
+ break;
+ case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
+ projection = MatrixRotationZ(-SDL_PI_F * 0.5f);
+ break;
+ case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
+ default:
+ projection = MatrixIdentity();
+ break;
+
+ }
// Update the view matrix
SDL_zero(view);
@@ -3281,10 +3331,20 @@ static bool VULKAN_UpdateViewport(SDL_Renderer *renderer)
projection);
VkViewport vkViewport;
- vkViewport.x = viewport->x;
- vkViewport.y = viewport->y;
- vkViewport.width = viewport->w;
- vkViewport.height = viewport->h;
+
+ swapDimensions = VULKAN_IsDisplayRotated90Degrees(rotation);
+ if (swapDimensions) {
+ vkViewport.x = viewport->y;
+ vkViewport.y = viewport->x;
+ vkViewport.width = viewport->h;
+ vkViewport.height = viewport->w;
+ }
+ else {
+ vkViewport.x = viewport->x;
+ vkViewport.y = viewport->y;
+ vkViewport.width = viewport->w;
+ vkViewport.height = viewport->h;
+ }
vkViewport.minDepth = 0.0f;
vkViewport.maxDepth = 1.0f;
vkCmdSetViewport(rendererData->currentCommandBuffer, 0, 1, &vkViewport);
@@ -3297,6 +3357,8 @@ static bool VULKAN_UpdateClipRect(SDL_Renderer *renderer)
{
VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal;
const SDL_Rect *viewport = &rendererData->currentViewport;
+ VkSurfaceTransformFlagBitsKHR rotation = VULKAN_GetRotationForCurrentRenderTarget(rendererData);
+ bool swapDimensions = VULKAN_IsDisplayRotated90Degrees(rotation);
VkRect2D scissor;
if (rendererData->currentCliprectEnabled) {
@@ -3310,6 +3372,13 @@ static bool VULKAN_UpdateClipRect(SDL_Renderer *renderer)
scissor.extent.width = viewport->w;
scissor.extent.height = viewport->h;
}
+ if (swapDimensions) {
+ VkRect2D scissorTemp = scissor;
+ scissor.offset.x = scissorTemp.offset.y;
+ scissor.offset.y = scissorTemp.offset.x;
+ scissor.extent.width = scissorTemp.extent.height;
+ scissor.extent.height = scissorTemp.extent.width;
+ }
vkCmdSetScissor(rendererData->currentCommandBuffer, 0, 1, &scissor);
rendererData->cliprectDirty = false;
@@ -3769,6 +3838,7 @@ static void VULKAN_InvalidateCachedState(SDL_Renderer *renderer)
static bool VULKAN_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
{
VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal;
+ VkSurfaceTransformFlagBitsKHR currentRotation = VULKAN_GetRotationForCurrentRenderTarget(rendererData);
VULKAN_DrawStateCache stateCache;
SDL_memset(&stateCache, 0, sizeof(stateCache));
@@ -3776,6 +3846,12 @@ static bool VULKAN_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cm
return SDL_SetError("Device lost and couldn't be recovered");
}
+ if(rendererData->currentViewportRotation != currentRotation) {
+ rendererData->currentViewportRotation = currentRotation;
+ rendererData->viewportDirty = true;
+ rendererData->cliprectDirty = true;
+ }
+
if (rendererData->recreateSwapchain) {
if (VULKAN_UpdateForWindowSizeChange(renderer) != VK_SUCCESS) {
return false;