diff --git a/src/main.cpp b/src/main.cpp index eb723a8..0278d10 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1527,6 +1527,20 @@ int main(int argc, char* argv[]) if (event->window.windowID != SDL_GetWindowID(ctx->window)) return true; + // Never nest NewFrame() inside an already-open frame — Windows min/max/restore buttons + // (renderBorderlessControls) push SDL window events synchronously from inside app.render(). (C146) + ImGuiContext* gctx = ImGui::GetCurrentContext(); + if (!gctx || gctx->WithinFrameScope) return true; + + // Dedupe the RESIZED + PIXEL_SIZE_CHANGED pair: both report the same final pixel size, so render + // once. SDL_GetWindowSizeInPixels is a consistent key across both event types (their data1/data2 + // differ — points vs pixels — and cannot be compared directly). + int pw = 0, ph = 0; + SDL_GetWindowSizeInPixels(ctx->window, &pw, &ph); + static int lastW = 0, lastH = 0; + if (pw == lastW && ph == lastH) return true; + lastW = pw; lastH = ph; + // Avoid re-entrancy static bool in_resize_render = false; if (in_resize_render) return true; diff --git a/src/platform/dx11_context.cpp b/src/platform/dx11_context.cpp index 822527c..e562b56 100644 --- a/src/platform/dx11_context.cpp +++ b/src/platform/dx11_context.cpp @@ -252,16 +252,6 @@ void DX11Context::resize(int width, int height) (void)height; if (!swapChain_ || !deviceContext_) return; - cleanupRenderTarget(); - - // Unbind the render target from the pipeline — ResizeBuffers requires - // ALL outstanding references to back-buffer resources to be released. - // Without this, ResizeBuffers fails with DXGI_ERROR_INVALID_CALL when - // growing the window (shrinking appears fine because the old larger - // buffer simply gets cropped by DWM). - deviceContext_->OMSetRenderTargets(0, nullptr, nullptr); - deviceContext_->Flush(); - // For composition swap chains (CreateSwapChainForComposition), // passing 0,0 means "keep current size" — NOT auto-detect from HWND. // We must pass the actual pixel dimensions from GetClientRect. @@ -272,7 +262,22 @@ void DX11Context::resize(int width, int height) w = static_cast(rc.right - rc.left); h = static_cast(rc.bottom - rc.top); } - if (w == 0 || h == 0) return; + if (w == 0 || h == 0) return; // minimized / zero-area: keep the current RTV, do nothing + + // Already this size with a live RTV: nothing to do (skips the destroy/recreate churn). + DXGI_SWAP_CHAIN_DESC1 d; + if (SUCCEEDED(swapChain_->GetDesc1(&d)) && d.Width == w && d.Height == h && renderTargetView_) + return; + + cleanupRenderTarget(); + + // Unbind the render target from the pipeline — ResizeBuffers requires + // ALL outstanding references to back-buffer resources to be released. + // Without this, ResizeBuffers fails with DXGI_ERROR_INVALID_CALL when + // growing the window (shrinking appears fine because the old larger + // buffer simply gets cropped by DWM). + deviceContext_->OMSetRenderTargets(0, nullptr, nullptr); + deviceContext_->Flush(); HRESULT hr = swapChain_->ResizeBuffers(0, w, h, DXGI_FORMAT_UNKNOWN, 0); if (FAILED(hr)) {