Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 6 commits into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/SDL3/SDL_gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
69 changes: 40 additions & 29 deletions src/gpu/d3d11/SDL_gpu_d3d11.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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 *));
Expand All @@ -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;
Expand All @@ -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);
thatcosmonaut marked this conversation as resolved.
Show resolved Hide resolved
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(
Expand Down Expand Up @@ -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(
Expand All @@ -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);
Expand Down Expand Up @@ -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(
Expand All @@ -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;
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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;
Expand Down
Loading
Loading