Make window resizing smooth on Windows with Direct3D - #1243
Merged
Conversation
…d gate the Direct3D live-resize on it and SkiaLayer.fillsWindow
…during live resize
Alexander Maryanovsky (m-sasha)
requested review from
Ivan Matkov (MatkovIvan) and
Igor Demin (igordmn)
July 23, 2026 14:36
Contributor
There was a problem hiding this comment.
Pull request overview
Adds an opt-in synchronous rendering path during interactive window live-resize on Windows/Direct3D to reduce “white border” artifacts by rendering inside the native resize loop and gating the normal async EDT-driven rendering while the drag is active.
Changes:
- Introduces a Windows Direct3D live-resize hook (native WndProc subclass) that synchronously renders/presents during WM_NCCALCSIZE / WM_PAINT and disables the normal async render loop while active.
- Adds a Win32 “invoke-and-wait while pumping” helper to safely run EDT work from the toolkit thread during live-resize without deadlocking cross-thread window operations.
- Refactors/aligns live-resize gating across Direct3D and Metal (naming + behavior), and updates test window setup to use
fillsWindow = true.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| skiko/src/jvmMain/kotlin/org/jetbrains/skiko/SkikoProperties.kt | Adds skiko.rendering.windows.direct3DSynchronousLiveResize property toggle and documentation. |
| skiko/src/awtTest/kotlin/org/jetbrains/skiko/util/UiTest.kt | Sets fillsWindow = true for UI test layers (required for live-resize mode). |
| skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm | Refactors native→Java calls into cached helper invokers (Metal live-resize path). |
| skiko/src/awtMain/kotlin/org/jetbrains/skiko/SkiaLayer.awt.kt | Avoids Direct3D “render immediately during reshape” path while synchronous live-resize is active; adds re-entrancy guard in update(). |
| skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/WinApiEdtInvoker.kt | Introduces JVM-side API and runnable shim for pump-wait EDT invocation on Windows. |
| skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/MetalRedrawer.kt | Renames and clarifies live-resize gating flag to match behavior (“handling live resize now”). |
| skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/Direct3DRedrawer.kt | Implements Windows synchronous live-resize lifecycle + gating, installs/uninstalls native hook, and adds composition wait for resize frames. |
| skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/Direct3DContextHandler.kt | Simplifies size-change tracking logic for Direct3D surfaces. |
| skiko/src/awtMain/cpp/windows/winApiEdtInvoker.h | Declares isPumpingEdt() to prevent re-entrant rendering during nested message pumping. |
| skiko/src/awtMain/cpp/windows/winApiEdtInvoker.cc | Implements Win32 message pumping invoke-and-wait to prevent deadlocks during cross-thread EDT operations. |
| skiko/src/awtMain/cpp/windows/directXRedrawer.cc | Adds Direct3D synchronous live-resize WndProc hook + related JNI entrypoints and swapchain scaling support. |
Comments suppressed due to low confidence (1)
skiko/src/awtMain/cpp/windows/winApiEdtInvoker.cc:44
javaNewEdtInvocationTaskdoesn't validateFindClass/NewGlobalRef/GetMethodIDresults before callingNewObject. If any lookup fails (e.g., due to a pending exception),NewObjectmay be invoked with a null class or constructor ID and crash.
jclass local = env->FindClass("org/jetbrains/skiko/redrawer/EdtInvocationTask");
cls = (jclass)env->NewGlobalRef(local);
env->DeleteLocalRef(local);
ctor = env->GetMethodID(cls, "<init>", "(Ljava/lang/Runnable;J)V");
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Igor Demin (igordmn)
approved these changes
Aug 5, 2026
Igor Demin (igordmn)
approved these changes
Aug 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The mechanism here is similar to the Metal fix.
During live resize draw the frame synchronously when receiving the native event. There's no transaction, but with some careful timing and vsync, it works well too.
The normal (async) rendering path is disabled during the live-resize.
The functionality is enabled by the
skiko.rendering.windows.direct3DSynchronousLiveResizesystem property (disabled by default for now)2026-07-21.16-11-33.mp4
Fixes https://youtrack.jetbrains.com/issue/CMP-10423/DirectX-Smooth-window-resize
Test code: