SDL: GPU: Avoid calling SDL_GetWindowSizeInPixels when possible (#11139)

From da5a1585cdb940de06b4538f97d06f5ee106c971 Mon Sep 17 00:00:00 2001
From: Evan Hemsley <[EMAIL REDACTED]>
Date: Wed, 9 Oct 2024 18:59:07 -0700
Subject: [PATCH] GPU: Avoid calling SDL_GetWindowSizeInPixels when possible
 (#11139)

---
 src/gpu/d3d11/SDL_gpu_d3d11.c   | 33 +++++++++++----------
 src/gpu/d3d12/SDL_gpu_d3d12.c   | 33 ++++++++++-----------
 src/gpu/vulkan/SDL_gpu_vulkan.c | 51 ++++++++++++++++++++++-----------
 3 files changed, 65 insertions(+), 52 deletions(-)

diff --git a/src/gpu/d3d11/SDL_gpu_d3d11.c b/src/gpu/d3d11/SDL_gpu_d3d11.c
index 9dd593b3d92f7..838251c10617d 100644
--- a/src/gpu/d3d11/SDL_gpu_d3d11.c
+++ b/src/gpu/d3d11/SDL_gpu_d3d11.c
@@ -5269,9 +5269,8 @@ static bool D3D11_INTERNAL_CreateSwapchain(
         return false;
     }
 
-    int w, h;
-    SDL_SyncWindow(windowData->window);
-    SDL_GetWindowSizeInPixels(windowData->window, &w, &h);
+    res = IDXGISwapChain_GetDesc(swapchain, &swapchainDesc);
+    CHECK_D3D11_ERROR_AND_RETURN("Failed to get swapchain descriptor!", false);
 
     // Initialize dummy container, width/height will be filled out in AcquireSwapchainTexture
     SDL_zerop(&windowData->textureContainer);
@@ -5288,14 +5287,14 @@ static bool D3D11_INTERNAL_CreateSwapchain(
     windowData->textureContainer.header.info.num_levels = 1;
     windowData->textureContainer.header.info.sample_count = SDL_GPU_SAMPLECOUNT_1;
     windowData->textureContainer.header.info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
-    windowData->textureContainer.header.info.width = w;
-    windowData->textureContainer.header.info.height = h;
+    windowData->textureContainer.header.info.width = swapchainDesc.BufferDesc.Width;
+    windowData->textureContainer.header.info.height = swapchainDesc.BufferDesc.Height;
 
     windowData->texture.container = &windowData->textureContainer;
     windowData->texture.containerIndex = 0;
 
-    windowData->width = w;
-    windowData->height = h;
+    windowData->width = swapchainDesc.BufferDesc.Width;
+    windowData->height = swapchainDesc.BufferDesc.Height;
     return true;
 }
 
@@ -5310,16 +5309,12 @@ static bool D3D11_INTERNAL_ResizeSwapchain(
     SDL_free(windowData->texture.subresources[0].colorTargetViews);
     SDL_free(windowData->texture.subresources);
 
-    int w, h;
-    SDL_SyncWindow(windowData->window);
-    SDL_GetWindowSizeInPixels(windowData->window, &w, &h);
-
     // Resize the swapchain
     HRESULT res = IDXGISwapChain_ResizeBuffers(
         windowData->swapchain,
         0, // Keep buffer count the same
-        w,
-        h,
+        0, // Use client window width
+        0, // Use client window height
         DXGI_FORMAT_UNKNOWN, // Keep the old format
         renderer->supportsTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
     CHECK_D3D11_ERROR_AND_RETURN("Could not resize swapchain buffers", false);
@@ -5332,10 +5327,14 @@ static bool D3D11_INTERNAL_ResizeSwapchain(
         (windowData->swapchainComposition == SDL_GPU_SWAPCHAINCOMPOSITION_SDR_LINEAR) ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : windowData->swapchainFormat,
         &windowData->texture);
 
-    windowData->textureContainer.header.info.width = w;
-    windowData->textureContainer.header.info.height = h;
-    windowData->width = w;
-    windowData->height = h;
+    DXGI_SWAP_CHAIN_DESC swapchainDesc;
+    res = IDXGISwapChain_GetDesc(windowData->swapchain, &swapchainDesc);
+    CHECK_D3D11_ERROR_AND_RETURN("Failed to get swapchain descriptor!", false);
+
+    windowData->textureContainer.header.info.width = swapchainDesc.BufferDesc.Width;
+    windowData->textureContainer.header.info.height = swapchainDesc.BufferDesc.Height;
+    windowData->width = swapchainDesc.BufferDesc.Width;
+    windowData->height = swapchainDesc.BufferDesc.Height;
     windowData->needsSwapchainRecreate = !result;
     return result;
 }
diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c
index 2e9ccf74e6fd3..dde8d7179a6e4 100644
--- a/src/gpu/d3d12/SDL_gpu_d3d12.c
+++ b/src/gpu/d3d12/SDL_gpu_d3d12.c
@@ -6347,19 +6347,12 @@ static bool D3D12_INTERNAL_ResizeSwapchain(
         SDL_free(windowData->textureContainers[i].textures);
     }
 
-    int w, h;
-    SDL_SyncWindow(windowData->window);
-    SDL_GetWindowSizeInPixels(
-        windowData->window,
-        &w,
-        &h);
-
     // Resize the swapchain
     HRESULT res = IDXGISwapChain_ResizeBuffers(
         windowData->swapchain,
         0, // Keep buffer count the same
-        w,
-        h,
+        0, // use client window width
+        0, // use client window height
         DXGI_FORMAT_UNKNOWN, // Keep the old format
         renderer->supportsTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
     CHECK_D3D12_ERROR_AND_RETURN("Could not resize swapchain buffers", false)
@@ -6376,8 +6369,12 @@ static bool D3D12_INTERNAL_ResizeSwapchain(
         }
     }
 
-    windowData->width = w;
-    windowData->height = h;
+    DXGI_SWAP_CHAIN_DESC1 swapchainDesc;
+    IDXGISwapChain3_GetDesc1(windowData->swapchain, &swapchainDesc);
+    CHECK_D3D12_ERROR_AND_RETURN("Failed to retrieve swapchain descriptor!", false)
+
+    windowData->width = swapchainDesc.Width;
+    windowData->height = swapchainDesc.Height;
     windowData->needsSwapchainRecreate = false;
     return true;
 }
@@ -6429,12 +6426,9 @@ static bool D3D12_INTERNAL_CreateSwapchain(
 
     swapchainFormat = SwapchainCompositionToTextureFormat[swapchainComposition];
 
-    int w, h;
-    SDL_GetWindowSizeInPixels(windowData->window, &w, &h);
-
     // Initialize the swapchain buffer descriptor
-    swapchainDesc.Width = 0;
-    swapchainDesc.Height = 0;
+    swapchainDesc.Width = 0;  // use client window width
+    swapchainDesc.Height = 0; // use client window height
     swapchainDesc.Format = swapchainFormat;
     swapchainDesc.SampleDesc.Count = 1;
     swapchainDesc.SampleDesc.Quality = 0;
@@ -6521,14 +6515,17 @@ static bool D3D12_INTERNAL_CreateSwapchain(
         IDXGIFactory1_Release(pParent);
     }
 
+    IDXGISwapChain3_GetDesc1(swapchain3, &swapchainDesc);
+    CHECK_D3D12_ERROR_AND_RETURN("Failed to retrieve swapchain descriptor!", false)
+
     // Initialize the swapchain data
     windowData->swapchain = swapchain3;
     windowData->present_mode = presentMode;
     windowData->swapchainComposition = swapchainComposition;
     windowData->swapchainColorSpace = SwapchainCompositionToColorSpace[swapchainComposition];
     windowData->frameCounter = 0;
-    windowData->width = w;
-    windowData->height = h;
+    windowData->width = swapchainDesc.Width;
+    windowData->height = swapchainDesc.Height;
 
     // Precache blit pipelines for the swapchain format
     for (Uint32 i = 0; i < 5; i += 1) {
diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c
index f5daf28f29c1c..8ff9aad1ed7c3 100644
--- a/src/gpu/vulkan/SDL_gpu_vulkan.c
+++ b/src/gpu/vulkan/SDL_gpu_vulkan.c
@@ -714,6 +714,8 @@ typedef struct WindowData
     SDL_GPUSwapchainComposition swapchainComposition;
     SDL_GPUPresentMode presentMode;
     bool needsSwapchainRecreate;
+    Uint32 swapchainCreateWidth;
+    Uint32 swapchainCreateHeight;
 
     // Window surface
     VkSurfaceKHR surface;
@@ -4425,14 +4427,13 @@ static Uint32 VULKAN_INTERNAL_CreateSwapchain(
     VkSemaphoreCreateInfo semaphoreCreateInfo;
     SwapchainSupportDetails swapchainSupportDetails;
     bool hasValidSwapchainComposition, hasValidPresentMode;
-    Sint32 drawableWidth, drawableHeight;
     Uint32 i;
-    SDL_VideoDevice *_this = SDL_GetVideoDevice();
-
-    SDL_assert(_this && _this->Vulkan_CreateSurface);
 
     windowData->frameCounter = 0;
 
+    SDL_VideoDevice *_this = SDL_GetVideoDevice();
+    SDL_assert(_this && _this->Vulkan_CreateSurface);
+
     // Each swapchain must have its own surface.
     if (!_this->Vulkan_CreateSurface(
             _this,
@@ -4535,16 +4536,20 @@ static Uint32 VULKAN_INTERNAL_CreateSwapchain(
         return VULKAN_INTERNAL_TRY_AGAIN;
     }
 
-    // Sync now to be sure that our swapchain size is correct
-    SDL_SyncWindow(windowData->window);
-    SDL_GetWindowSizeInPixels(
-        windowData->window,
-        &drawableWidth,
-        &drawableHeight);
-
     windowData->imageCount = MAX_FRAMES_IN_FLIGHT;
-    windowData->width = drawableWidth;
-    windowData->height = drawableHeight;
+
+#ifdef SDL_PLATFORM_APPLE
+    windowData->width = swapchainSupportDetails.capabilities.currentExtent.width;
+    windowData->height = swapchainSupportDetails.capabilities.currentExtent.height;
+#else
+    windowData->width = SDL_clamp(
+        windowData->swapchainCreateWidth,
+        swapchainSupportDetails.capabilities.minImageExtent.width,
+        swapchainSupportDetails.capabilities.maxImageExtent.width);
+    windowData->height = SDL_clamp(windowData->swapchainCreateHeight,
+        swapchainSupportDetails.capabilities.minImageExtent.height,
+        swapchainSupportDetails.capabilities.maxImageExtent.height);
+#endif
 
     if (swapchainSupportDetails.capabilities.maxImageCount > 0 &&
         windowData->imageCount > swapchainSupportDetails.capabilities.maxImageCount) {
@@ -4572,8 +4577,8 @@ static Uint32 VULKAN_INTERNAL_CreateSwapchain(
     swapchainCreateInfo.minImageCount = windowData->imageCount;
     swapchainCreateInfo.imageFormat = windowData->format;
     swapchainCreateInfo.imageColorSpace = windowData->colorSpace;
-    swapchainCreateInfo.imageExtent.width = drawableWidth;
-    swapchainCreateInfo.imageExtent.height = drawableHeight;
+    swapchainCreateInfo.imageExtent.width = windowData->width;
+    swapchainCreateInfo.imageExtent.height = windowData->height;
     swapchainCreateInfo.imageArrayLayers = 1;
     swapchainCreateInfo.imageUsage =
         VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
@@ -4647,8 +4652,8 @@ static Uint32 VULKAN_INTERNAL_CreateSwapchain(
         // Initialize dummy container
         SDL_zero(windowData->textureContainers[i]);
         windowData->textureContainers[i].canBeCycled = false;
-        windowData->textureContainers[i].header.info.width = drawableWidth;
-        windowData->textureContainers[i].header.info.height = drawableHeight;
+        windowData->textureContainers[i].header.info.width = windowData->width;
+        windowData->textureContainers[i].header.info.height = windowData->height;
         windowData->textureContainers[i].header.info.layer_count_or_depth = 1;
         windowData->textureContainers[i].header.info.format = SwapchainCompositionToSDLFormat(
             windowData->swapchainComposition,
@@ -9411,6 +9416,8 @@ static bool VULKAN_INTERNAL_OnWindowResize(void *userdata, SDL_Event *e)
     if (e->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED && e->window.windowID == SDL_GetWindowID(w)) {
         data = VULKAN_INTERNAL_FetchWindowData(w);
         data->needsSwapchainRecreate = true;
+        data->swapchainCreateWidth = e->window.data1;
+        data->swapchainCreateHeight = e->window.data2;
     }
 
     return true;
@@ -9509,6 +9516,16 @@ static bool VULKAN_ClaimWindow(
         windowData->presentMode = SDL_GPU_PRESENTMODE_VSYNC;
         windowData->swapchainComposition = SDL_GPU_SWAPCHAINCOMPOSITION_SDR;
 
+        // On non-Apple platforms the swapchain capability currentExtent can be different from the window,
+        // so we have to query the window size.
+#ifndef SDL_PLATFORM_APPLE
+        int w, h;
+        SDL_SyncWindow(window);
+        SDL_GetWindowSizeInPixels(window, &w, &h);
+        windowData->swapchainCreateWidth = w;
+        windowData->swapchainCreateHeight = h;
+#endif
+
         Uint32 createSwapchainResult = VULKAN_INTERNAL_CreateSwapchain(renderer, windowData);
         if (createSwapchainResult == 1) {
             SDL_SetPointerProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA, windowData);