GPU: recreate swapchain on window pixel size change event (#10985)

This commit is contained in:
Evan Hemsley
2024-09-28 18:09:56 -07:00
committed by GitHub
parent 66f6b40c92
commit fc242abbd2
4 changed files with 136 additions and 139 deletions
+1 -1
View File
@@ -3263,7 +3263,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WindowSupportsGPUPresentMode(
* Claims a window, creating a swapchain structure for it.
*
* This must be called before SDL_AcquireGPUSwapchainTexture is called using
* the window.
* the window. You should only call this function from the thread that created the window.
*
* The swapchain will be created with SDL_GPU_SWAPCHAINCOMPOSITION_SDR and
* SDL_GPU_PRESENTMODE_VSYNC. If you want to have different swapchain
+40 -29
View File
@@ -482,6 +482,7 @@ typedef struct D3D11WindowData
DXGI_COLOR_SPACE_TYPE swapchainColorSpace;
SDL_GPUFence *inFlightFences[MAX_FRAMES_IN_FLIGHT];
Uint32 frameCounter;
bool needsSwapchainRecreate;
} D3D11WindowData;
typedef struct D3D11Shader
@@ -5021,6 +5022,18 @@ static D3D11WindowData *D3D11_INTERNAL_FetchWindowData(
return (D3D11WindowData *)SDL_GetPointerProperty(properties, WINDOW_PROPERTY_DATA, NULL);
}
static bool D3D11_INTERNAL_OnWindowResize(void *userdata, SDL_Event *e)
{
SDL_Window *w = (SDL_Window *)userdata;
D3D11WindowData *data;
if (e->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED && e->window.windowID == SDL_GetWindowID(w)) {
data = D3D11_INTERNAL_FetchWindowData(w);
data->needsSwapchainRecreate = true;
}
return true;
}
static bool D3D11_INTERNAL_InitializeSwapchainTexture(
D3D11Renderer *renderer,
IDXGISwapChain *swapchain,
@@ -5089,7 +5102,6 @@ static bool D3D11_INTERNAL_CreateSwapchain(
SDL_GPUPresentMode presentMode)
{
HWND dxgiHandle;
int width, height;
Uint32 i;
DXGI_SWAP_CHAIN_DESC swapchainDesc;
DXGI_FORMAT swapchainFormat;
@@ -5105,9 +5117,6 @@ static bool D3D11_INTERNAL_CreateSwapchain(
dxgiHandle = (HWND)windowData->window;
#endif
// Get the window size
SDL_GetWindowSize(windowData->window, &width, &height);
swapchainFormat = SwapchainCompositionToTextureFormat[swapchainComposition];
// Initialize the swapchain buffer descriptor
@@ -5216,6 +5225,10 @@ static bool D3D11_INTERNAL_CreateSwapchain(
return false;
}
int w, h;
SDL_SyncWindow(windowData->window);
SDL_GetWindowSizeInPixels(windowData->window, &w, &h);
// Initialize dummy container, width/height will be filled out in AcquireSwapchainTexture
SDL_zerop(&windowData->textureContainer);
windowData->textureContainer.textures = SDL_calloc(1, sizeof(D3D11Texture *));
@@ -5231,6 +5244,8 @@ 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->texture.container = &windowData->textureContainer;
windowData->texture.containerIndex = 0;
@@ -5240,32 +5255,41 @@ static bool D3D11_INTERNAL_CreateSwapchain(
static bool D3D11_INTERNAL_ResizeSwapchain(
D3D11Renderer *renderer,
D3D11WindowData *windowData,
Sint32 width,
Sint32 height)
D3D11WindowData *windowData)
{
D3D11_Wait((SDL_GPURenderer *)renderer);
// Release the old RTV
ID3D11RenderTargetView_Release(windowData->texture.subresources[0].colorTargetViews[0]);
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
width,
height,
w,
h,
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);
// Create the texture object for the swapchain
return D3D11_INTERNAL_InitializeSwapchainTexture(
bool result = D3D11_INTERNAL_InitializeSwapchainTexture(
renderer,
windowData->swapchain,
windowData->swapchainFormat,
(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->needsSwapchainRecreate = !result;
return result;
}
static bool D3D11_SupportsSwapchainComposition(
@@ -5350,14 +5374,13 @@ static bool D3D11_ClaimWindow(
D3D11WindowData *windowData = D3D11_INTERNAL_FetchWindowData(window);
if (windowData == NULL) {
windowData = (D3D11WindowData *)SDL_malloc(sizeof(D3D11WindowData));
windowData = (D3D11WindowData *)SDL_calloc(1, sizeof(D3D11WindowData));
windowData->window = window;
if (D3D11_INTERNAL_CreateSwapchain(renderer, windowData, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_VSYNC)) {
SDL_SetPointerProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA, windowData);
SDL_LockMutex(renderer->windowLock);
if (renderer->claimedWindowCount >= renderer->claimedWindowCapacity) {
renderer->claimedWindowCapacity *= 2;
renderer->claimedWindows = SDL_realloc(
@@ -5366,9 +5389,10 @@ static bool D3D11_ClaimWindow(
}
renderer->claimedWindows[renderer->claimedWindowCount] = windowData;
renderer->claimedWindowCount += 1;
SDL_UnlockMutex(renderer->windowLock);
SDL_AddEventWatch(D3D11_INTERNAL_OnWindowResize, window);
return true;
} else {
SDL_free(windowData);
@@ -5439,6 +5463,7 @@ static void D3D11_ReleaseWindow(
SDL_free(windowData);
SDL_ClearProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA);
SDL_RemoveEventWatch(D3D11_INTERNAL_OnWindowResize, window);
}
static bool D3D11_AcquireSwapchainTexture(
@@ -5449,8 +5474,6 @@ static bool D3D11_AcquireSwapchainTexture(
D3D11CommandBuffer *d3d11CommandBuffer = (D3D11CommandBuffer *)commandBuffer;
D3D11Renderer *renderer = (D3D11Renderer *)d3d11CommandBuffer->renderer;
D3D11WindowData *windowData;
DXGI_SWAP_CHAIN_DESC swapchainDesc;
int windowW, windowH;
HRESULT res;
*swapchainTexture = NULL;
@@ -5460,16 +5483,8 @@ static bool D3D11_AcquireSwapchainTexture(
SET_STRING_ERROR_AND_RETURN("Cannot acquire a swapchain texture from an unclaimed window!", false)
}
// Check for window size changes and resize the swapchain if needed.
IDXGISwapChain_GetDesc(windowData->swapchain, &swapchainDesc);
SDL_GetWindowSize(window, &windowW, &windowH);
if ((UINT)windowW != swapchainDesc.BufferDesc.Width || (UINT)windowH != swapchainDesc.BufferDesc.Height) {
if (!D3D11_INTERNAL_ResizeSwapchain(
renderer,
windowData,
windowW,
windowH)) {
if (windowData->needsSwapchainRecreate) {
if (!D3D11_INTERNAL_ResizeSwapchain(renderer, windowData)) {
return false;
}
}
@@ -5511,10 +5526,6 @@ static bool D3D11_AcquireSwapchainTexture(
(void **)&windowData->texture.handle);
CHECK_D3D11_ERROR_AND_RETURN("Could not acquire swapchain!", false);
// Update the texture container dimensions
windowData->textureContainer.header.info.width = windowW;
windowData->textureContainer.header.info.height = windowH;
// Set up presentation
if (d3d11CommandBuffer->windowDataCount == d3d11CommandBuffer->windowDataCapacity) {
d3d11CommandBuffer->windowDataCapacity += 1;
File diff suppressed because it is too large Load Diff
+12 -31
View File
@@ -1159,6 +1159,7 @@ struct VulkanRenderer
SDL_Mutex *acquireUniformBufferLock;
SDL_Mutex *renderPassFetchLock;
SDL_Mutex *framebufferFetchLock;
SDL_Mutex *windowLock;
Uint8 defragInProgress;
@@ -4493,35 +4494,6 @@ static bool VULKAN_INTERNAL_CreateSwapchain(
&drawableWidth,
&drawableHeight);
if (drawableWidth < (Sint32)swapchainSupportDetails.capabilities.minImageExtent.width ||
drawableWidth > (Sint32)swapchainSupportDetails.capabilities.maxImageExtent.width ||
drawableHeight < (Sint32)swapchainSupportDetails.capabilities.minImageExtent.height ||
drawableHeight > (Sint32)swapchainSupportDetails.capabilities.maxImageExtent.height) {
if (swapchainSupportDetails.capabilities.currentExtent.width != SDL_MAX_UINT32) {
drawableWidth = VULKAN_INTERNAL_clamp(
drawableWidth,
(Sint32)swapchainSupportDetails.capabilities.minImageExtent.width,
(Sint32)swapchainSupportDetails.capabilities.maxImageExtent.width);
drawableHeight = VULKAN_INTERNAL_clamp(
drawableHeight,
(Sint32)swapchainSupportDetails.capabilities.minImageExtent.height,
(Sint32)swapchainSupportDetails.capabilities.maxImageExtent.height);
} else {
renderer->vkDestroySurfaceKHR(
renderer->instance,
swapchainData->surface,
NULL);
if (swapchainSupportDetails.formatsLength > 0) {
SDL_free(swapchainSupportDetails.formats);
}
if (swapchainSupportDetails.presentModesLength > 0) {
SDL_free(swapchainSupportDetails.presentModes);
}
SDL_free(swapchainData);
SET_STRING_ERROR_AND_RETURN("No fallback swapchain size available!", false);
}
}
swapchainData->imageCount = MAX_FRAMES_IN_FLIGHT;
if (swapchainSupportDetails.capabilities.maxImageCount > 0 &&
@@ -4833,6 +4805,7 @@ static void VULKAN_DestroyDevice(
SDL_DestroyMutex(renderer->acquireUniformBufferLock);
SDL_DestroyMutex(renderer->renderPassFetchLock);
SDL_DestroyMutex(renderer->framebufferFetchLock);
SDL_DestroyMutex(renderer->windowLock);
renderer->vkDestroyDevice(renderer->logicalDevice, NULL);
renderer->vkDestroyInstance(renderer->instance, NULL);
@@ -9356,7 +9329,7 @@ static bool VULKAN_INTERNAL_OnWindowResize(void *userdata, SDL_Event *e)
{
SDL_Window *w = (SDL_Window *)userdata;
WindowData *data;
if (e->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) {
if (e->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED && e->window.windowID == SDL_GetWindowID(w)) {
data = VULKAN_INTERNAL_FetchWindowData(w);
data->needsSwapchainRecreate = true;
}
@@ -9460,6 +9433,7 @@ static bool VULKAN_ClaimWindow(
if (VULKAN_INTERNAL_CreateSwapchain(renderer, windowData)) {
SDL_SetPointerProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA, windowData);
SDL_LockMutex(renderer->windowLock);
if (renderer->claimedWindowCount >= renderer->claimedWindowCapacity) {
renderer->claimedWindowCapacity *= 2;
renderer->claimedWindows = SDL_realloc(
@@ -9469,6 +9443,7 @@ static bool VULKAN_ClaimWindow(
renderer->claimedWindows[renderer->claimedWindowCount] = windowData;
renderer->claimedWindowCount += 1;
SDL_UnlockMutex(renderer->windowLock);
SDL_AddEventWatch(VULKAN_INTERNAL_OnWindowResize, window);
@@ -9511,6 +9486,7 @@ static void VULKAN_ReleaseWindow(
windowData);
}
SDL_LockMutex(renderer->windowLock);
for (i = 0; i < renderer->claimedWindowCount; i += 1) {
if (renderer->claimedWindows[i]->window == window) {
renderer->claimedWindows[i] = renderer->claimedWindows[renderer->claimedWindowCount - 1];
@@ -9518,6 +9494,7 @@ static void VULKAN_ReleaseWindow(
break;
}
}
SDL_UnlockMutex(renderer->windowLock);
SDL_free(windowData);
@@ -9619,7 +9596,10 @@ static bool VULKAN_AcquireSwapchainTexture(
// If window data marked as needing swapchain recreate, try to recreate
if (windowData->needsSwapchainRecreate) {
VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData);
if (!VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData)) {
return false;
}
swapchainData = windowData->swapchainData;
if (swapchainData == NULL) {
@@ -11340,6 +11320,7 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
renderer->acquireUniformBufferLock = SDL_CreateMutex();
renderer->renderPassFetchLock = SDL_CreateMutex();
renderer->framebufferFetchLock = SDL_CreateMutex();
renderer->windowLock = SDL_CreateMutex();
/*
* Create submitted command buffer list