From 7f155d76301a5dd15f9270bc1b62d7601c882cc9 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Wed, 8 Jan 2025 16:12:46 +0100 Subject: [PATCH 1/4] Ensure correct thread for native window operations --- .../objectiveC/macos/DisplayLinkThrottler.mm | 9 +++++++- .../awtMain/objectiveC/macos/MetalRedrawer.mm | 23 +++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/skiko/src/awtMain/objectiveC/macos/DisplayLinkThrottler.mm b/skiko/src/awtMain/objectiveC/macos/DisplayLinkThrottler.mm index b23a1ae51..dc10ef287 100644 --- a/skiko/src/awtMain/objectiveC/macos/DisplayLinkThrottler.mm +++ b/skiko/src/awtMain/objectiveC/macos/DisplayLinkThrottler.mm @@ -88,7 +88,14 @@ - (instancetype)initWithWindow:(NSWindow *)window { [weakSelf onScreenDidChange]; }]; - [self onScreenDidChange]; + if (NSThread.currentThread.isMainThread) { + [self onScreenDidChange]; + } else { + // In case of OpenJDK, EDT thread != NSThread main thread + dispatch_async(dispatch_get_main_queue(), ^{ + [self onScreenDidChange]; + }); + } } return self; diff --git a/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm b/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm index 4b4a51194..d90d82e74 100644 --- a/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm +++ b/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm @@ -115,6 +115,24 @@ static jmethodID getOnOcclusionStateChangedMethodID(JNIEnv *env, jobject redrawe return onOcclusionStateChanged; } + +static void setWindowPropertiesUnsafe(NSWindow* window, jboolean transparency) { + if (transparency) { + window.hasShadow = NO; + } +} + +static void setWindowProperties(NSWindow* window, jboolean transparency) { + if (NSThread.currentThread.isMainThread) { + setWindowPropertiesUnsafe(window, transparency); + } else { + // In case of OpenJDK, EDT thread != NSThread main thread + dispatch_sync(dispatch_get_main_queue(), ^{ + setWindowPropertiesUnsafe(window, transparency); + }); + } +} + extern "C" { @@ -161,10 +179,7 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_createMe device.inflightSemaphore = dispatch_semaphore_create(device.layer.maximumDrawableCount); NSWindow* window = (__bridge NSWindow*) (void *) windowPtr; - - if (transparency) { - window.hasShadow = NO; - } + setWindowProperties(window, transparency); jmethodID onOcclusionStateChanged = getOnOcclusionStateChangedMethodID(env, redrawer); device.occlusionObserver = From 87fdd55e46f38bcc4a0b0d3eca52ed032622a3d9 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Fri, 10 Jan 2025 14:19:45 +0100 Subject: [PATCH 2/4] Address feedback --- .../objectiveC/macos/DisplayLinkThrottler.mm | 13 ++++++++++++- skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm | 3 ++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/skiko/src/awtMain/objectiveC/macos/DisplayLinkThrottler.mm b/skiko/src/awtMain/objectiveC/macos/DisplayLinkThrottler.mm index dc10ef287..1df94d776 100644 --- a/skiko/src/awtMain/objectiveC/macos/DisplayLinkThrottler.mm +++ b/skiko/src/awtMain/objectiveC/macos/DisplayLinkThrottler.mm @@ -92,8 +92,19 @@ - (instancetype)initWithWindow:(NSWindow *)window { [self onScreenDidChange]; } else { // In case of OpenJDK, EDT thread != NSThread main thread + // There is one thing we should keep in mind. Postponing creation of vsync throttler will cause that for sometime there won't be any waiting: + // + // ``` + // create window + // (10x) schedule render -> render + // onScreenDidChange + // schedule render -> wait vsync -> render + // ``` + // + // It is probably okay, but possible alternative would be to wait for throttler creation. It is difficult, so we can just keep the current code. + __weak DisplayLinkThrottler *weakSelf = self; dispatch_async(dispatch_get_main_queue(), ^{ - [self onScreenDidChange]; + [weakSelf onScreenDidChange]; }); } } diff --git a/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm b/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm index d90d82e74..8b21d82a2 100644 --- a/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm +++ b/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm @@ -127,8 +127,9 @@ static void setWindowProperties(NSWindow* window, jboolean transparency) { setWindowPropertiesUnsafe(window, transparency); } else { // In case of OpenJDK, EDT thread != NSThread main thread + __weak NSWindow *weakWindow = window; dispatch_sync(dispatch_get_main_queue(), ^{ - setWindowPropertiesUnsafe(window, transparency); + setWindowPropertiesUnsafe(weakWindow, transparency); }); } } From 187afc6891eec675e706ee8e27c74365a010d394 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Fri, 10 Jan 2025 14:42:31 +0100 Subject: [PATCH 3/4] Address feedback: extra null check --- skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm b/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm index 8b21d82a2..184a7d3e3 100644 --- a/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm +++ b/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm @@ -117,6 +117,7 @@ static jmethodID getOnOcclusionStateChangedMethodID(JNIEnv *env, jobject redrawe static void setWindowPropertiesUnsafe(NSWindow* window, jboolean transparency) { + if (window == NULL) return; if (transparency) { window.hasShadow = NO; } From 4656cb82bfbd2ccf994768d7e340b00aeb76b60b Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Mon, 13 Jan 2025 15:43:00 +0100 Subject: [PATCH 4/4] Apply window properties async --- skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm b/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm index 184a7d3e3..5c671e22d 100644 --- a/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm +++ b/skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm @@ -129,7 +129,7 @@ static void setWindowProperties(NSWindow* window, jboolean transparency) { } else { // In case of OpenJDK, EDT thread != NSThread main thread __weak NSWindow *weakWindow = window; - dispatch_sync(dispatch_get_main_queue(), ^{ + dispatch_async(dispatch_get_main_queue(), ^{ setWindowPropertiesUnsafe(weakWindow, transparency); }); }