mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JBR-6696: hardened MTLGC_DestroyMTLGraphicsConfig to ensure any aync callbacks are performed before deallocation, added CVDisplayLink checks + skip delayed callbacks, added traces and refactored code + improved drawable lifecycle + hardened appkit main thread usage + instrumentation to debug latency + fixed ThreadUtilities to observe all performOnMainThread usages + enable apple MainThreadChecker in DEBUG builds + fixed few MainThread violations (PrinterView init) (WIP)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -288,6 +288,73 @@ JLI_NotifyAWTLoaded()
|
||||
|
||||
static int (*main_fptr)(int argc, char **argv) = NULL;
|
||||
|
||||
|
||||
void useMainThreadChecker() {
|
||||
BOOL hasEnvMTC = (getenv("JAVA_AWT_MTC") != NULL);
|
||||
|
||||
/* always enable MTC in debug builds */
|
||||
#ifndef DEBUG
|
||||
/* check if MTC is enabled on product releases (env variable 'JAVA_AWT_MTC' is set) */
|
||||
if (!hasEnvMTC) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* See MTC config from https://bryce.co/main-thread-checker-configuration/
|
||||
*/
|
||||
|
||||
setenv("MTC_VERBOSE", "0", 1);
|
||||
setenv("MTC_LOG_REPORTS_TO_OS_LOG", "0", 1);
|
||||
setenv("MTC_CALL_BREAKPOINT_SYMBOL", "0", 1);
|
||||
|
||||
// enable MTC_CRASH_ON_REPORT for testing (jtreg...):
|
||||
#ifdef DEBUG
|
||||
setenv("MTC_CRASH_ON_REPORT", "1", 1);
|
||||
#else
|
||||
/* check if the env variable 'JAVA_AWT_MTC_CRASH' is set */
|
||||
if (getenv("JAVA_AWT_MTC_CRASH") != NULL) {
|
||||
setenv("MTC_CRASH_ON_REPORT", "1", 1);
|
||||
} else {
|
||||
setenv("MTC_CRASH_ON_REPORT", "0", 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* keep repeated violations */
|
||||
setenv("MTC_MAX_HIT_COUNT", "99999", 1);
|
||||
|
||||
// disables Ignore flags to get more information:
|
||||
setenv("MTC_IGNORE_DUPS_BY_THREAD_PC", "0", 1);
|
||||
setenv("MTC_IGNORE_INLINE_CALLS", "0", 1);
|
||||
|
||||
setenv("MTC_IGNORE_DEALLOC", "1", 1);
|
||||
setenv("MTC_IGNORE_RETAIN_RELEASE", "1", 1);
|
||||
|
||||
if (0) {
|
||||
// Report also violations within apple frameworks (DEV ONLY):
|
||||
setenv("MTC_SUPPRESS_SYSTEM_REPORTS", "0", 1);
|
||||
} else {
|
||||
// disabling internals violations:
|
||||
setenv("MTC_SUPPRESS_SYSTEM_REPORTS", "1", 1);
|
||||
}
|
||||
|
||||
if (0) {
|
||||
// dump selector stats at exit (DEV ONLY):
|
||||
setenv("MTC_PRINT_SELECTOR_STATS", "1", 1);
|
||||
}
|
||||
|
||||
// TODO: get DL_PATH from env vars (no hard-coded path):
|
||||
void *result = dlopen("/Applications/Xcode.app/Contents/Developer/usr/lib/libMainThreadChecker.dylib",
|
||||
RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE | RTLD_FIRST
|
||||
);
|
||||
if (hasEnvMTC) {
|
||||
if (result == NULL) {
|
||||
printf("useMainThreadChecker: Failed loading libMainThreadChecker...\n");
|
||||
} else {
|
||||
printf("useMainThreadChecker: Loaded libMainThreadChecker...\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unwrap the arguments and re-run main()
|
||||
*/
|
||||
@@ -334,6 +401,7 @@ static void MacOSXStartup(int argc, char *argv[]) {
|
||||
// Thread already started?
|
||||
static jboolean started = false;
|
||||
if (started) {
|
||||
useMainThreadChecker();
|
||||
return;
|
||||
}
|
||||
started = true;
|
||||
|
||||
@@ -2108,7 +2108,6 @@ JNI_COCOA_ENTER(env);
|
||||
jobject platformWindow = (*env)->NewWeakGlobalRef(env, obj);
|
||||
NSView *contentView = OBJC(contentViewPtr);
|
||||
NSRect frameRect = NSMakeRect(x, y, w, h);
|
||||
AWTWindow *owner = [OBJC(ownerPtr) delegate];
|
||||
|
||||
BOOL isIgnoreMouseEvents = NO;
|
||||
GET_CPLATFORM_WINDOW_CLASS_RETURN(0);
|
||||
@@ -2121,6 +2120,7 @@ JNI_COCOA_ENTER(env);
|
||||
(*env)->DeleteLocalRef(env, awtWindow);
|
||||
}
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
AWTWindow *owner = [OBJC(ownerPtr) delegate];
|
||||
|
||||
window = [[AWTWindow alloc] initWithPlatformWindow:platformWindow
|
||||
ownerWindow:owner
|
||||
@@ -2534,8 +2534,8 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowTi
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
NSWindow *nsWindow = OBJC(windowPtr);
|
||||
[nsWindow performSelectorOnMainThread:@selector(setTitle:)
|
||||
withObject:JavaStringToNSString(env, jtitle)
|
||||
[ThreadUtilities performOnMainThread:@selector(setTitle:) on:nsWindow
|
||||
withObject:JavaStringToNSString(env, jtitle)
|
||||
waitUntilDone:NO];
|
||||
|
||||
JNI_COCOA_EXIT(env);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -293,7 +293,6 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
|
||||
NSString *url = [[openURLEvent paramDescriptorForKeyword:keyDirectObject] stringValue];
|
||||
|
||||
//fprintf(stderr,"jm_handleOpenURL\n");
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jstring jURL = NSStringToJavaString(env, url);
|
||||
GET_APPEVENTHANDLER_CLASS();
|
||||
@@ -337,7 +336,6 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
return;
|
||||
}
|
||||
|
||||
//fprintf(stderr,"jm_handleOpenFile\n");
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
|
||||
// if these files were opened from a Spotlight query, try to get the search text from the current AppleEvent
|
||||
@@ -364,7 +362,6 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
if (!fHandlesDocumentTypes) return NSPrintingCancelled;
|
||||
|
||||
//fprintf(stderr,"jm_handlePrintFile\n");
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject jFileNamesArray = [self _createFilePathArrayFrom:fileNames withEnv:env];
|
||||
GET_APPEVENTHANDLER_CLASS_RETURN(NSPrintingCancelled);
|
||||
@@ -381,7 +378,6 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
+ (void)_notifyJava:(jint)notificationType {
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
|
||||
//fprintf(stderr,"jm_handleOpenApplication\n");
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
GET_APPEVENTHANDLER_CLASS();
|
||||
DECLARE_STATIC_METHOD(jm_handleNativeNotification, sjc_AppEventHandler, "handleNativeNotification", "(I)V");
|
||||
@@ -401,7 +397,7 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
|
||||
// Open app handler, registered in -init
|
||||
+ (void)_willFinishLaunching {
|
||||
[self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_OPEN_APP];
|
||||
[ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_OPEN_APP];
|
||||
}
|
||||
|
||||
// ReOpen app handler
|
||||
@@ -430,47 +426,47 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
}
|
||||
|
||||
+ (void)_systemWillPowerOff {
|
||||
[self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SHUTDOWN];
|
||||
[ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SHUTDOWN];
|
||||
}
|
||||
|
||||
+ (void)_appDidActivate {
|
||||
[self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_ACTIVE_APP_GAINED];
|
||||
[ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_ACTIVE_APP_GAINED];
|
||||
}
|
||||
|
||||
+ (void)_appDidDeactivate {
|
||||
[self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_ACTIVE_APP_LOST];
|
||||
[ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_ACTIVE_APP_LOST];
|
||||
}
|
||||
|
||||
+ (void)_appDidHide {
|
||||
[self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_APP_HIDDEN];
|
||||
[ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_APP_HIDDEN];
|
||||
}
|
||||
|
||||
+ (void)_appDidUnhide {
|
||||
[self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_APP_SHOWN];
|
||||
[ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_APP_SHOWN];
|
||||
}
|
||||
|
||||
+ (void)_sessionDidActivate {
|
||||
[self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_USER_SESSION_ACTIVE];
|
||||
[ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_USER_SESSION_ACTIVE];
|
||||
}
|
||||
|
||||
+ (void)_sessionDidDeactivate {
|
||||
[self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_USER_SESSION_INACTIVE];
|
||||
[ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_USER_SESSION_INACTIVE];
|
||||
}
|
||||
|
||||
+ (void)_screenDidSleep {
|
||||
[self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SCREEN_SLEEP];
|
||||
[ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SCREEN_SLEEP];
|
||||
}
|
||||
|
||||
+ (void)_screenDidWake {
|
||||
[self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SCREEN_WAKE];
|
||||
[ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SCREEN_WAKE];
|
||||
}
|
||||
|
||||
+ (void)_systemDidSleep {
|
||||
[self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SYSTEM_SLEEP];
|
||||
[ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SYSTEM_SLEEP];
|
||||
}
|
||||
|
||||
+ (void)_systemDidWake {
|
||||
[self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SYSTEM_WAKE];
|
||||
[ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SYSTEM_WAKE];
|
||||
}
|
||||
|
||||
+ (void)_registerForNotification:(NSNumber *)notificationTypeNum {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -593,7 +593,7 @@ static BOOL sNeedsEnter;
|
||||
{
|
||||
AWT_ASSERT_NOT_APPKIT_THREAD;
|
||||
|
||||
[self performSelectorOnMainThread:@selector(doDrag) withObject:nil waitUntilDone:YES];
|
||||
[ThreadUtilities performOnMainThread:@selector(doDrag) on:self withObject:nil waitUntilDone:YES];
|
||||
}
|
||||
|
||||
/******************************** BEGIN NSDraggingSource Interface ********************************/
|
||||
|
||||
@@ -660,8 +660,14 @@ JNI_COCOA_ENTER(env);
|
||||
jobject pageFormatArea = (*env)->CallObjectMethod(env, jthis, jm_getPageFormatArea, page); // AWT_THREADING Safe (!appKit)
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
PrinterView* printerView = [[PrinterView alloc] initWithFrame:JavaToNSRect(env, pageFormatArea) withEnv:env withPrinterJob:jthis];
|
||||
[printerView setFirstPage:firstPage lastPage:lastPage];
|
||||
NSRect rect = JavaToNSRect(env, pageFormatArea);
|
||||
|
||||
__block PrinterView *printerView = nil;
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^() {
|
||||
printerView = [[PrinterView alloc] initWithFrame:rect withEnv:env withPrinterJob:jthis];
|
||||
[printerView setFirstPage:firstPage lastPage:lastPage];
|
||||
}];
|
||||
|
||||
GET_NSPRINTINFO_METHOD_RETURN(NO)
|
||||
NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr((*env)->CallLongMethod(env, jthis, sjm_getNSPrintInfo)); // AWT_THREADING Safe (known object)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -109,6 +109,8 @@
|
||||
- (id)initWithDevice:(jint)displayID shadersLib:(NSString*)shadersLib;
|
||||
- (void)dealloc;
|
||||
|
||||
- (void)handleDisplayLink: (BOOL)enabled source:(const char*)src;
|
||||
|
||||
/**
|
||||
* Resets the current clip state (disables both scissor and depth tests).
|
||||
*/
|
||||
@@ -245,6 +247,7 @@
|
||||
- (void)commitCommandBuffer:(BOOL)waitUntilCompleted display:(BOOL)updateDisplay;
|
||||
- (void)startRedraw:(MTLLayer*)layer;
|
||||
- (void)stopRedraw:(MTLLayer*)layer;
|
||||
- (void)haltRedraw;
|
||||
@end
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -39,6 +39,10 @@
|
||||
// scenarios with multiple subsequent updates.
|
||||
#define KEEP_ALIVE_COUNT 4
|
||||
|
||||
// Min interval between 2 display link callbacks (Main thread may be blocked)
|
||||
// ~ 1ms (shorter than best monitor frame rate = 1000 hz)
|
||||
#define KEEP_ALIVE_MIN_INTERVAL 1.0 / 1000.0
|
||||
|
||||
// Amount of blit operations per update to make sure that everything is
|
||||
// rendered into the window drawable. It does not slow things down as we
|
||||
// use separate command queue for blitting.
|
||||
@@ -48,6 +52,15 @@ extern jboolean MTLSD_InitMTLWindow(JNIEnv *env, MTLSDOps *mtlsdo);
|
||||
extern BOOL isDisplaySyncEnabled();
|
||||
extern BOOL MTLLayer_isExtraRedrawEnabled();
|
||||
|
||||
#define CHECK_CVLINK(op, cmd) \
|
||||
{ \
|
||||
CVReturn ret = (CVReturn) (cmd); \
|
||||
if (ret != kCVReturnSuccess) { \
|
||||
J2dTraceImpl(J2D_TRACE_ERROR, JNI_TRUE, "CVDisplayLink[%s] Error: %d", \
|
||||
op, ret); \
|
||||
} \
|
||||
}
|
||||
|
||||
static struct TxtVertex verts[PGRAM_VERTEX_COUNT] = {
|
||||
{{-1.0, 1.0}, {0.0, 0.0}},
|
||||
{{1.0, 1.0}, {1.0, 0.0}},
|
||||
@@ -122,6 +135,7 @@ MTLTransform* tempTransform = nil;
|
||||
CVDisplayLinkRef _displayLink;
|
||||
NSMutableSet* _layers;
|
||||
int _displayLinkCount;
|
||||
CFTimeInterval _lastRedrawTime;
|
||||
|
||||
MTLComposite * _composite;
|
||||
MTLPaint * _paint;
|
||||
@@ -145,6 +159,8 @@ MTLTransform* tempTransform = nil;
|
||||
extern void initSamplers(id<MTLDevice> device);
|
||||
|
||||
- (id)initWithDevice:(jint)displayID shadersLib:(NSString*)shadersLib {
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
// Initialize ourselves
|
||||
self = [super init];
|
||||
if (self) {
|
||||
// Initialization code here.
|
||||
@@ -161,6 +177,8 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
return nil;
|
||||
}
|
||||
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "initWithDevice: created MTLContext[%p]", self);
|
||||
|
||||
texturePool = [[MTLTexturePool alloc] initWithDevice:device];
|
||||
|
||||
vertexBuffer = [device newBufferWithBytes:verts
|
||||
@@ -184,11 +202,35 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
blitCommandQueue = [device newCommandQueue];
|
||||
|
||||
_tempTransform = [[MTLTransform alloc] init];
|
||||
|
||||
_displayLinkCount = 0;
|
||||
_lastRedrawTime = 0.0;
|
||||
|
||||
if (isDisplaySyncEnabled()) {
|
||||
_layers = [[NSMutableSet alloc] init];
|
||||
_displayLinkCount = 0;
|
||||
CVDisplayLinkCreateWithCGDisplay(displayID, &_displayLink);
|
||||
CVDisplayLinkSetOutputCallback(_displayLink, &mtlDisplayLinkCallback, (__bridge void *) self);
|
||||
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLContext_CVDisplayLinkCreateWithCGDisplay: "
|
||||
"ctx=%p displayID=%d", self, displayID);
|
||||
|
||||
CHECK_CVLINK("CreateWithCGDisplay",
|
||||
CVDisplayLinkCreateWithCGDisplay(displayID, &_displayLink)
|
||||
);
|
||||
if (_displayLink == nil) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"MTLContext.initWithDevice(): Failed to initialize CVDisplayLink.");
|
||||
return nil;
|
||||
} else {
|
||||
// LBO: should retain ?
|
||||
/* CVDisplayLinkRetain(_displayLink); */
|
||||
|
||||
CHECK_CVLINK("SetOutputCallback",
|
||||
CVDisplayLinkSetOutputCallback(_displayLink,
|
||||
&mtlDisplayLinkCallback,
|
||||
(__bridge void *) self)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
_displayLink = nil;
|
||||
}
|
||||
_glyphCacheLCD = [[MTLGlyphCache alloc] initWithContext:self];
|
||||
_glyphCacheAA = [[MTLGlyphCache alloc] initWithContext:self];
|
||||
@@ -196,9 +238,39 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)handleDisplayLink: (BOOL)enabled source:(const char*)src {
|
||||
/* should be called by APPKIT_THREAD except from dealloc: */
|
||||
// AWT_ASSERT_APPKIT_THREAD
|
||||
if (_displayLink == nil) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLContext_handleDisplayLink[%s]: "
|
||||
"ctx=%p - displayLink = nil", src, self);
|
||||
} else {
|
||||
if (enabled) {
|
||||
if (!CVDisplayLinkIsRunning(_displayLink)) {
|
||||
CHECK_CVLINK("Start", CVDisplayLinkStart(_displayLink));
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLContext_CVDisplayLinkStart[%s]: "
|
||||
"ctx=%p", src, self);
|
||||
}
|
||||
} else {
|
||||
if (CVDisplayLinkIsRunning(_displayLink)) {
|
||||
CHECK_CVLINK("Stop", CVDisplayLinkStop(_displayLink));
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLContext_CVDisplayLinkStop[%s]: "
|
||||
"ctx=%p", src, self);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.dealloc");
|
||||
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLContext.dealloc: MTLContext[%p]", self);
|
||||
|
||||
if (_displayLink != nil) {
|
||||
AWT_DEBUG_LOG(@"CVDisplayLink still running in dealloc.");
|
||||
[self haltRedraw];
|
||||
}
|
||||
|
||||
// TODO : Check that texturePool is completely released.
|
||||
// texturePool content is released in MTLCommandBufferWrapper.onComplete()
|
||||
//self.texturePool = nil;
|
||||
@@ -255,15 +327,6 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
_layers = nil;
|
||||
}
|
||||
|
||||
if (_displayLink != NULL) {
|
||||
if (CVDisplayLinkIsRunning(_displayLink)) {
|
||||
CVDisplayLinkStop(_displayLink);
|
||||
J2dTraceLn1(J2D_TRACE_VERBOSE, "MTLContext_CVDisplayLinkStop: ctx=%p", self);
|
||||
}
|
||||
CVDisplayLinkRelease(_displayLink);
|
||||
_displayLink = NULL;
|
||||
}
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -564,6 +627,20 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
|
||||
- (void) redraw {
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
/*
|
||||
* Avoid repeated invocations by UIKit Main Thread
|
||||
* if blocked while many mtlDisplayLinkCallback() are dispatched
|
||||
*/
|
||||
const CFTimeInterval now = CACurrentMediaTime();
|
||||
const CFTimeInterval elapsed = (_lastRedrawTime != 0.0) ? (now - _lastRedrawTime) : 0.0;
|
||||
|
||||
if ((elapsed != 0.0) && (elapsed <= KEEP_ALIVE_MIN_INTERVAL)) {
|
||||
J2dTraceLn2(J2D_TRACE_VERBOSE, "[%.3lf] MTLContext_redraw: elapsed: %.3lf ms => SKIP",
|
||||
now, 1000.0 * elapsed);
|
||||
return;
|
||||
}
|
||||
_lastRedrawTime = now;
|
||||
// Process layers:
|
||||
for (MTLLayer *layer in _layers) {
|
||||
[layer setNeedsDisplay];
|
||||
}
|
||||
@@ -573,10 +650,7 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
if (_layers.count > 0) {
|
||||
[_layers removeAllObjects];
|
||||
}
|
||||
if (CVDisplayLinkIsRunning(_displayLink)) {
|
||||
CVDisplayLinkStop(_displayLink);
|
||||
J2dTraceLn1(J2D_TRACE_VERBOSE, "MTLContext_CVDisplayLinkStop: ctx=%p", self);
|
||||
}
|
||||
[self handleDisplayLink:NO source:"redraw"];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,7 +659,7 @@ CVReturn mtlDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp*
|
||||
J2dTraceLn1(J2D_TRACE_VERBOSE, "MTLContext_mtlDisplayLinkCallback: ctx=%p", displayLinkContext);
|
||||
@autoreleasepool {
|
||||
MTLContext *ctx = (__bridge MTLContext *)displayLinkContext;
|
||||
[ctx performSelectorOnMainThread:@selector(redraw) withObject:nil waitUntilDone:NO];
|
||||
[ThreadUtilities performOnMainThread:@selector(redraw) on:ctx withObject:nil waitUntilDone:NO];
|
||||
}
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
@@ -600,10 +674,7 @@ CVReturn mtlDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp*
|
||||
// Request for redraw before starting display link to avoid rendering problem on M2 processor
|
||||
[layer setNeedsDisplay];
|
||||
}
|
||||
if (_displayLink != NULL && !CVDisplayLinkIsRunning(_displayLink)) {
|
||||
CVDisplayLinkStart(_displayLink);
|
||||
J2dTraceLn1(J2D_TRACE_VERBOSE, "MTLContext_CVDisplayLinkStart: ctx=%p", self);
|
||||
}
|
||||
[self handleDisplayLink:YES source:"startRedraw"];
|
||||
}
|
||||
|
||||
- (void)stopRedraw:(MTLLayer*) layer {
|
||||
@@ -614,13 +685,29 @@ CVReturn mtlDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp*
|
||||
[_layers removeObject:layer];
|
||||
layer.redrawCount = 0;
|
||||
}
|
||||
if (_layers.count == 0 && _displayLinkCount == 0) {
|
||||
if (CVDisplayLinkIsRunning(_displayLink)) {
|
||||
CVDisplayLinkStop(_displayLink);
|
||||
J2dTraceLn1(J2D_TRACE_VERBOSE, "MTLContext_CVDisplayLinkStop: ctx=%p", self);
|
||||
}
|
||||
if ((_layers.count == 0) && (_displayLinkCount == 0)) {
|
||||
[self handleDisplayLink:NO source:"stopRedraw"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)haltRedraw {
|
||||
/* should be called by APPKIT_THREAD except from dealloc: */
|
||||
// AWT_ASSERT_APPKIT_THREAD
|
||||
if (_displayLink != nil) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "MTLContext_haltRedraw: ctx=%p", self);
|
||||
if (_layers.count > 0) {
|
||||
for (MTLLayer *layer in _layers) {
|
||||
layer.redrawCount = 0;
|
||||
}
|
||||
[_layers removeAllObjects];
|
||||
}
|
||||
_displayLinkCount = 0;
|
||||
[self handleDisplayLink:NO source:"haltRedraw"];
|
||||
|
||||
CVDisplayLinkRelease(_displayLink);
|
||||
_displayLink = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -70,6 +70,7 @@ JNIEXPORT jlong JNICALL
|
||||
Java_sun_java2d_metal_MTLGraphicsConfig_getMTLConfigInfo
|
||||
(JNIEnv *env, jclass mtlgc, jint displayID, jstring mtlShadersLib)
|
||||
{
|
||||
__block MTLContext* mtlc = nil;
|
||||
__block MTLGraphicsConfigInfo* mtlinfo = nil;
|
||||
|
||||
JNI_COCOA_ENTER(env);
|
||||
@@ -78,7 +79,7 @@ JNI_COCOA_ENTER(env);
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^() {
|
||||
|
||||
MTLContext* mtlc = [[MTLContext alloc] initWithDevice:displayID
|
||||
mtlc = [[MTLContext alloc] initWithDevice:displayID
|
||||
shadersLib:path];
|
||||
if (mtlc != 0L) {
|
||||
// create the MTLGraphicsConfigInfo record for this context
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -40,6 +40,7 @@
|
||||
@property (readwrite, assign) int topInset;
|
||||
@property (readwrite, assign) int leftInset;
|
||||
@property (readwrite, atomic) int redrawCount;
|
||||
@property (readwrite, atomic) CFTimeInterval lastPresentedTime;
|
||||
@property (readwrite, atomic) NSTimeInterval avgBlitFrameTime;
|
||||
|
||||
- (id) initWithJavaLayer:(jobject)layer;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -35,6 +35,10 @@
|
||||
#define MAX_DRAWABLE 3
|
||||
#define LAST_DRAWABLE (MAX_DRAWABLE - 1)
|
||||
|
||||
#define TRACE_DISPLAY 1
|
||||
#define TRACE_DRAWABLE_LATENCY 0
|
||||
|
||||
const BOOL USE_CATRANSACTION = NO;
|
||||
const NSTimeInterval DF_BLIT_FRAME_TIME=1.0/120.0;
|
||||
|
||||
BOOL isDisplaySyncEnabled() {
|
||||
@@ -113,7 +117,9 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
return (BOOL)redrawEnabled;
|
||||
}
|
||||
|
||||
@implementation MTLLayer
|
||||
@implementation MTLLayer {
|
||||
NSLock* _lock;
|
||||
}
|
||||
|
||||
- (id) initWithJavaLayer:(jobject)layer
|
||||
{
|
||||
@@ -122,6 +128,8 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
self = [super init];
|
||||
if (self == nil) return self;
|
||||
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "initWithJavaLayer: created MTLLayer[%p]", self);
|
||||
|
||||
self.javaLayer = layer;
|
||||
|
||||
self.contentsGravity = kCAGravityTopLeft;
|
||||
@@ -149,14 +157,17 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
self.nextDrawableCount = 0;
|
||||
self.opaque = YES;
|
||||
self.redrawCount = 0;
|
||||
self.lastPresentedTime = 0.0;
|
||||
self.avgBlitFrameTime = DF_BLIT_FRAME_TIME;
|
||||
|
||||
if (@available(macOS 10.13, *)) {
|
||||
self.displaySyncEnabled = isDisplaySyncEnabled();
|
||||
}
|
||||
if (@available(macOS 10.13.2, *)) {
|
||||
self.maximumDrawableCount = MAX_DRAWABLE;
|
||||
}
|
||||
self.presentsWithTransaction = NO;
|
||||
self.avgBlitFrameTime = DF_BLIT_FRAME_TIME;
|
||||
self.presentsWithTransaction = (USE_CATRANSACTION && isDisplaySyncEnabled());
|
||||
_lock = [[NSLock alloc] init];
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -171,91 +182,217 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.nextDrawableCount >= LAST_DRAWABLE) {
|
||||
if (!isDisplaySyncEnabled()) {
|
||||
[self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform blit:
|
||||
[self stopRedraw:NO];
|
||||
|
||||
@autoreleasepool {
|
||||
if (((*self.buffer).width == 0) || ((*self.buffer).height == 0)) {
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: cannot create drawable of size 0");
|
||||
return;
|
||||
}
|
||||
// MTLDrawable pool barrier:
|
||||
BOOL skipDrawable = YES;
|
||||
|
||||
NSUInteger src_x = self.leftInset * self.contentsScale;
|
||||
NSUInteger src_y = self.topInset * self.contentsScale;
|
||||
NSUInteger src_w = (*self.buffer).width - src_x;
|
||||
NSUInteger src_h = (*self.buffer).height - src_y;
|
||||
|
||||
if (src_h <= 0 || src_w <= 0) {
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: Invalid src width or height.");
|
||||
return;
|
||||
}
|
||||
|
||||
id<MTLCommandBuffer> commandBuf = [self.ctx createBlitCommandBuffer];
|
||||
if (commandBuf == nil) {
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: commandBuf is null");
|
||||
return;
|
||||
}
|
||||
id<CAMetalDrawable> mtlDrawable = [self nextDrawable];
|
||||
if (mtlDrawable == nil) {
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: nextDrawable is null)");
|
||||
return;
|
||||
}
|
||||
// increment used drawables:
|
||||
self.nextDrawableCount++;
|
||||
id <MTLBlitCommandEncoder> blitEncoder = [commandBuf blitCommandEncoder];
|
||||
|
||||
[blitEncoder
|
||||
copyFromTexture:(isDisplaySyncEnabled()) ? (*self.buffer) : (*self.outBuffer)
|
||||
sourceSlice:0 sourceLevel:0
|
||||
sourceOrigin:MTLOriginMake(src_x, src_y, 0)
|
||||
sourceSize:MTLSizeMake(src_w, src_h, 1)
|
||||
toTexture:mtlDrawable.texture destinationSlice:0 destinationLevel:0
|
||||
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||
[blitEncoder endEncoding];
|
||||
|
||||
if (isDisplaySyncEnabled()) {
|
||||
[commandBuf presentDrawable:mtlDrawable];
|
||||
} else {
|
||||
if (@available(macOS 10.15.4, *)) {
|
||||
[commandBuf presentDrawable:mtlDrawable afterMinimumDuration:self.avgBlitFrameTime];
|
||||
} else {
|
||||
[commandBuf presentDrawable:mtlDrawable];
|
||||
[_lock lock];
|
||||
@try {
|
||||
if (self.nextDrawableCount < LAST_DRAWABLE) {
|
||||
// increment used drawables to act as the CPU fence:
|
||||
self.nextDrawableCount++;
|
||||
skipDrawable = NO;
|
||||
}
|
||||
} @finally {
|
||||
[_lock unlock];
|
||||
}
|
||||
|
||||
[self retain];
|
||||
[commandBuf addCompletedHandler:^(id <MTLCommandBuffer> commandbuf) {
|
||||
// free drawable:
|
||||
self.nextDrawableCount--;
|
||||
if (skipDrawable) {
|
||||
if (TRACE_DISPLAY) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "[%.6lf] MTLLayer_blitTexture: skip drawable [skip blit] nextDrawableCount = %d",
|
||||
CACurrentMediaTime(), self.nextDrawableCount);
|
||||
}
|
||||
[self startRedraw];
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform blit:
|
||||
|
||||
// Decrement redrawCount:
|
||||
[self stopRedraw:NO];
|
||||
|
||||
// try-finally block to ensure releasing the CPU fence (abort blit):
|
||||
BOOL releaseFence = YES;
|
||||
@try {
|
||||
if (((*self.buffer).width == 0) || ((*self.buffer).height == 0)) {
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: cannot create drawable of size 0");
|
||||
return;
|
||||
}
|
||||
|
||||
NSUInteger src_x = self.leftInset * self.contentsScale;
|
||||
NSUInteger src_y = self.topInset * self.contentsScale;
|
||||
NSUInteger src_w = (*self.buffer).width - src_x;
|
||||
NSUInteger src_h = (*self.buffer).height - src_y;
|
||||
|
||||
if (src_h <= 0 || src_w <= 0) {
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: Invalid src width or height.");
|
||||
return;
|
||||
}
|
||||
|
||||
id<MTLCommandBuffer> commandBuf = [self.ctx createBlitCommandBuffer];
|
||||
if (commandBuf == nil) {
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: commandBuf is null");
|
||||
return;
|
||||
}
|
||||
|
||||
const CFTimeInterval beforeNextDrawableTime = (TRACE_DRAWABLE_LATENCY) ? CACurrentMediaTime() : 0.0;
|
||||
|
||||
const id<CAMetalDrawable> mtlDrawable = [self nextDrawable];
|
||||
|
||||
const CFTimeInterval nextDrawableTime = (TRACE_DISPLAY || TRACE_DRAWABLE_LATENCY) ? CACurrentMediaTime() : 0.0;
|
||||
|
||||
if (mtlDrawable == nil) {
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: nextDrawable is null)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (TRACE_DRAWABLE_LATENCY) {
|
||||
const CFTimeInterval nextDrawableLatency = (nextDrawableTime - beforeNextDrawableTime);
|
||||
J2dRlsTraceLn5(J2D_TRACE_VERBOSE,
|
||||
"[%.6lf] MTLLayer_blitTexture: layer=%p nextDrawable = drawable(%d) - nextDrawableCount = %d - nextDrawableLatency = %.3lf ms",
|
||||
CACurrentMediaTime(), self, [mtlDrawable drawableID], self.nextDrawableCount,
|
||||
1000.0 * nextDrawableLatency);
|
||||
}
|
||||
|
||||
// Keep Fence from now:
|
||||
releaseFence = NO;
|
||||
|
||||
MTLDrawablePresentedHandler presentedHandler = nil;
|
||||
|
||||
if (@available(macOS 10.15.4, *)) {
|
||||
if (!isDisplaySyncEnabled()) {
|
||||
// Exponential smoothing on elapsed time:
|
||||
const NSTimeInterval gpuTime = commandbuf.GPUEndTime - commandbuf.GPUStartTime;
|
||||
const NSTimeInterval a = 0.25;
|
||||
self.avgBlitFrameTime = gpuTime * a + self.avgBlitFrameTime * (1.0 - a);
|
||||
[self retain];
|
||||
|
||||
presentedHandler = ^(id <MTLDrawable> drawable) {
|
||||
// note: called anyway even if drawable.present() not called!
|
||||
// free drawable only once presented:
|
||||
[self freeDrawableCount];
|
||||
|
||||
const CFTimeInterval presentedTime = drawable.presentedTime;
|
||||
|
||||
if (presentedTime != 0.0) {
|
||||
if (TRACE_DISPLAY) {
|
||||
const CFTimeInterval now = CACurrentMediaTime();
|
||||
const CFTimeInterval presentedOffset = (now - presentedTime);
|
||||
const CFTimeInterval presentedHandlerLatency = (now - nextDrawableTime);
|
||||
const CFTimeInterval frameInterval = (self.lastPresentedTime != 0.0) ? (presentedTime - self.lastPresentedTime) : -1.0;
|
||||
|
||||
J2dRlsTraceLn5(J2D_TRACE_VERBOSE,
|
||||
"[%.6lf] MTLLayer_blitTexture: PresentedHandler: drawable(%d) presented"
|
||||
" - presentedHandlerLatency = %.3lf ms (offset: %.3lf ms) frameInterval = %.3lf ms",
|
||||
CACurrentMediaTime(), drawable.drawableID,
|
||||
1000.0 * presentedHandlerLatency, 1000.0 * presentedOffset,
|
||||
1000.0 * frameInterval
|
||||
);
|
||||
}
|
||||
self.lastPresentedTime = presentedTime;
|
||||
} else {
|
||||
if (TRACE_DISPLAY) {
|
||||
const CFTimeInterval now = CACurrentMediaTime();
|
||||
const CFTimeInterval presentedHandlerLatency = (now - nextDrawableTime);
|
||||
|
||||
J2dRlsTraceLn3(J2D_TRACE_VERBOSE,
|
||||
"[%.6lf] MTLLayer_blitTexture: PresentedHandler: drawable(%d) skipped"
|
||||
" - presentedHandlerLatency = %.3lf ms",
|
||||
CACurrentMediaTime(), drawable.drawableID, 1000.0 * presentedHandlerLatency
|
||||
);
|
||||
}
|
||||
}
|
||||
[self release];
|
||||
};
|
||||
}
|
||||
|
||||
id <MTLBlitCommandEncoder> blitEncoder = [commandBuf blitCommandEncoder];
|
||||
|
||||
[blitEncoder
|
||||
copyFromTexture:(isDisplaySyncEnabled()) ? (*self.buffer) : (*self.outBuffer)
|
||||
sourceSlice:0 sourceLevel:0
|
||||
sourceOrigin:MTLOriginMake(src_x, src_y, 0)
|
||||
sourceSize:MTLSizeMake(src_w, src_h, 1)
|
||||
toTexture:mtlDrawable.texture destinationSlice:0 destinationLevel:0
|
||||
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||
[blitEncoder endEncoding];
|
||||
|
||||
if (!isDisplaySyncEnabled()) {
|
||||
if (presentedHandler != nil) {
|
||||
[mtlDrawable addPresentedHandler:presentedHandler];
|
||||
}
|
||||
if (@available(macOS 10.15.4, *)) {
|
||||
[commandBuf presentDrawable:mtlDrawable afterMinimumDuration:self.avgBlitFrameTime];
|
||||
} else {
|
||||
[commandBuf presentDrawable:mtlDrawable];
|
||||
}
|
||||
}
|
||||
[self release];
|
||||
}];
|
||||
|
||||
[commandBuf commit];
|
||||
[self retain];
|
||||
[mtlDrawable retain];
|
||||
|
||||
[commandBuf addCompletedHandler:^(id <MTLCommandBuffer> commandbuf) {
|
||||
if (isDisplaySyncEnabled()) {
|
||||
if (TRACE_DISPLAY) {
|
||||
J2dRlsTraceLn3(J2D_TRACE_INFO,
|
||||
"[%.6lf] MTLLayer.blitTexture: CompletedHandler: layer[%p] present drawable(%d)",
|
||||
CACurrentMediaTime(), self, mtlDrawable.drawableID);
|
||||
}
|
||||
// present drawable:
|
||||
if (presentedHandler != nil) {
|
||||
[mtlDrawable addPresentedHandler:presentedHandler];
|
||||
}
|
||||
[ThreadUtilities performOnMainThread:@selector(present) on:mtlDrawable withObject:nil waitUntilDone:NO];
|
||||
}
|
||||
if (presentedHandler == nil) {
|
||||
// free drawable:
|
||||
[self freeDrawableCount];
|
||||
}
|
||||
if (!isDisplaySyncEnabled()) {
|
||||
if (@available(macOS 10.15.4, *)) {
|
||||
const NSTimeInterval gpuTime = commandBuf.GPUEndTime - commandBuf.GPUStartTime;
|
||||
const NSTimeInterval a = 0.25;
|
||||
self.avgBlitFrameTime = gpuTime * a + self.avgBlitFrameTime * (1.0 - a);
|
||||
}
|
||||
}
|
||||
[mtlDrawable release];
|
||||
[self release];
|
||||
}];
|
||||
|
||||
[commandBuf commit];
|
||||
|
||||
} @finally {
|
||||
// try-finally block to ensure releasing the CPU fence:
|
||||
if (releaseFence) {
|
||||
// free drawable:
|
||||
[self freeDrawableCount];
|
||||
|
||||
if (isDisplaySyncEnabled()) {
|
||||
// Increment redrawCount:
|
||||
[self startRedraw];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) freeDrawableCount {
|
||||
[_lock lock];
|
||||
@try {
|
||||
--self.nextDrawableCount;
|
||||
} @finally {
|
||||
[_lock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLLayer.dealloc: MTLLayer[%p]", self);
|
||||
|
||||
// LBO: dangerous as async ?
|
||||
[self stopRedraw:YES];
|
||||
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
(*env)->DeleteWeakGlobalRef(env, self.javaLayer);
|
||||
self.javaLayer = nil;
|
||||
[self stopRedraw:YES];
|
||||
self.buffer = NULL;
|
||||
self.ctx = NULL;
|
||||
[_lock release];
|
||||
_lock = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -286,6 +423,7 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
if (isDisplaySyncEnabled()) {
|
||||
if (self.redrawCount == 0) {
|
||||
if (0) J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLLayer_startRedrawIfNeeded: layer = %p redrawCount = %d", self, self.redrawCount);
|
||||
[self.ctx startRedraw:self];
|
||||
}
|
||||
}
|
||||
@@ -294,10 +432,14 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
- (void)startRedraw {
|
||||
if (isDisplaySyncEnabled()) {
|
||||
if (self.ctx != nil) {
|
||||
[self.ctx performSelectorOnMainThread:@selector(startRedraw:) withObject:self waitUntilDone:NO];
|
||||
[ThreadUtilities performOnMainThreadNowOrLater:^(){
|
||||
[self.ctx startRedraw:self];
|
||||
}];
|
||||
}
|
||||
} else {
|
||||
[self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
|
||||
[ThreadUtilities performOnMainThreadNowOrLater:^(){
|
||||
[self setNeedsDisplay];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,7 +449,9 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
self.redrawCount = 0;
|
||||
}
|
||||
if (self.ctx != nil) {
|
||||
[self.ctx performSelectorOnMainThread:@selector(stopRedraw:) withObject:self waitUntilDone:NO];
|
||||
[ThreadUtilities performOnMainThreadNowOrLater:^(){
|
||||
[self.ctx stopRedraw:self];
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -344,7 +488,7 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
|
||||
[cbwrapper release];
|
||||
if (updateDisplay && isDisplaySyncEnabled()) {
|
||||
// Ensure layer will be redrawn asap to display new content:
|
||||
[self performSelectorOnMainThread:@selector(startRedrawIfNeeded) withObject:nil waitUntilDone:NO];
|
||||
[ThreadUtilities performOnMainThread:@selector(startRedrawIfNeeded) on:self withObject:nil waitUntilDone:NO];
|
||||
}
|
||||
[self release];
|
||||
}];
|
||||
@@ -382,12 +526,15 @@ JNI_COCOA_ENTER(env);
|
||||
|
||||
jobject javaLayer = (*env)->NewWeakGlobalRef(env, obj);
|
||||
|
||||
// Wait and ensure main thread creates the MTLLayer instance now:
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
|
||||
layer = [[MTLLayer alloc] initWithJavaLayer: javaLayer];
|
||||
}];
|
||||
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLLayer_nativeCreateLayer: created MTLLayer[%p]", layer);
|
||||
|
||||
JNI_COCOA_EXIT(env);
|
||||
|
||||
return ptr_to_jlong(layer);
|
||||
@@ -419,6 +566,7 @@ Java_sun_java2d_metal_MTLLayer_validate
|
||||
layer.drawableSize =
|
||||
CGSizeMake((*layer.buffer).width,
|
||||
(*layer.buffer).height);
|
||||
|
||||
if (isDisplaySyncEnabled()) {
|
||||
[layer startRedraw];
|
||||
} else {
|
||||
@@ -436,11 +584,14 @@ Java_sun_java2d_metal_MTLLayer_nativeSetScale
|
||||
{
|
||||
JNI_COCOA_ENTER(env);
|
||||
MTLLayer *layer = jlong_to_ptr(layerPtr);
|
||||
|
||||
// We always call all setXX methods asynchronously, exception is only in
|
||||
// this method where we need to change native texture size and layer's scale
|
||||
// in one call on appkit, otherwise we'll get window's contents blinking,
|
||||
// during screen-2-screen moving.
|
||||
[ThreadUtilities performOnMainThreadWaiting:[NSThread isMainThread] block:^(){
|
||||
// Ensure main thread changes the MTLLayer instance later:
|
||||
[ThreadUtilities performOnMainThreadNowOrLater:^(){
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLLayer_nativeSetScale: layer = %p scale = %.3lf", layer, scale);
|
||||
layer.contentsScale = scale;
|
||||
}];
|
||||
JNI_COCOA_EXIT(env);
|
||||
@@ -451,19 +602,26 @@ Java_sun_java2d_metal_MTLLayer_nativeSetInsets
|
||||
(JNIEnv *env, jclass cls, jlong layerPtr, jint top, jint left)
|
||||
{
|
||||
MTLLayer *layer = jlong_to_ptr(layerPtr);
|
||||
layer.topInset = top;
|
||||
layer.leftInset = left;
|
||||
|
||||
[ThreadUtilities performOnMainThreadNowOrLater:^() {
|
||||
J2dRlsTraceLn3(J2D_TRACE_VERBOSE, "MTLLayer_nativeSetInsets: layer = %p top = %d left = %d", layer, top, left);
|
||||
layer.topInset = top;
|
||||
layer.leftInset = left;
|
||||
}];
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_metal_MTLLayer_blitTexture
|
||||
(JNIEnv *env, jclass cls, jlong layerPtr)
|
||||
{
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer_blitTexture");
|
||||
JNI_COCOA_ENTER(env);
|
||||
MTLLayer *layer = jlong_to_ptr(layerPtr);
|
||||
|
||||
J2dTraceLn1(J2D_TRACE_VERBOSE, "MTLLayer_blitTexture: layer = %p", layer);
|
||||
|
||||
MTLContext * ctx = layer.ctx;
|
||||
if (layer == nil || ctx == nil) {
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer_blit : Layer or Context is null");
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "MTLLayer_blitTexture : Layer or Context is null");
|
||||
if (layer != nil) {
|
||||
[layer stopRedraw:YES];
|
||||
}
|
||||
@@ -471,6 +629,7 @@ Java_sun_java2d_metal_MTLLayer_blitTexture
|
||||
}
|
||||
|
||||
[layer blitTexture];
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
@@ -478,11 +637,12 @@ Java_sun_java2d_metal_MTLLayer_nativeSetOpaque
|
||||
(JNIEnv *env, jclass cls, jlong layerPtr, jboolean opaque)
|
||||
{
|
||||
JNI_COCOA_ENTER(env);
|
||||
MTLLayer *layer = jlong_to_ptr(layerPtr);
|
||||
|
||||
MTLLayer *mtlLayer = OBJC(layerPtr);
|
||||
// Ensure main thread changes the MTLLayer instance later:
|
||||
[ThreadUtilities performOnMainThreadWaiting:NO block:^(){
|
||||
[mtlLayer setOpaque:(opaque == JNI_TRUE)];
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLLayer_nativeSetOpaque: layer = %p opaque = %d", layer, opaque);
|
||||
[layer setOpaque:(opaque == JNI_TRUE)];
|
||||
}];
|
||||
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -38,6 +38,11 @@
|
||||
#include "MTLTextRenderer.h"
|
||||
#import "ThreadUtilities.h"
|
||||
|
||||
#define CHECK_MAIN_THREAD_LATENCY 1
|
||||
|
||||
// ~ 2ms is high for main thread:
|
||||
#define LATENCY_HIGH_THRESHOLD 2.0
|
||||
|
||||
/**
|
||||
* References to the "current" context and destination surface.
|
||||
*/
|
||||
@@ -48,6 +53,22 @@ jint mtlPreviousOp = MTL_OP_INIT;
|
||||
extern BOOL isDisplaySyncEnabled();
|
||||
extern void MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo);
|
||||
|
||||
void checkMainThreadLatency() {
|
||||
const CFTimeInterval start = CACurrentMediaTime();
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:NO block:^(){
|
||||
const CFTimeInterval now = CACurrentMediaTime();
|
||||
const CFTimeInterval elapsedMs = 1000.0 * (now - start);
|
||||
|
||||
if ((elapsedMs != 0.0) && (elapsedMs >= LATENCY_HIGH_THRESHOLD)) {
|
||||
J2dRlsTraceLn3(J2D_TRACE_VERBOSE, "[%.3lf] checkMainThreadLatency: MainThread latency: %.3lf ms (> %.3lf ms)",
|
||||
now, elapsedMs, LATENCY_HIGH_THRESHOLD);
|
||||
return;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
void MTLRenderQueue_CheckPreviousOp(jint op) {
|
||||
|
||||
if (mtlPreviousOp == op) {
|
||||
@@ -651,10 +672,24 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
|
||||
CHECK_PREVIOUS_OP(MTL_OP_OTHER);
|
||||
jlong pConfigInfo = NEXT_LONG(b);
|
||||
CONTINUE_IF_NULL(mtlc);
|
||||
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "RQ: DISPOSE_CONFIG: start MTLContext[%p] -----", mtlc);
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
[mtlc haltRedraw];
|
||||
}];
|
||||
[mtlc commitCommandBuffer:YES display:NO];
|
||||
|
||||
// free resources:
|
||||
if (mtlPreviousOp == MTL_OP_MASK_OP) {
|
||||
MTLVertexCache_DisableMaskCache(mtlc);
|
||||
}
|
||||
[mtlc.glyphCacheAA free];
|
||||
[mtlc.glyphCacheLCD free];
|
||||
|
||||
MTLGC_DestroyMTLGraphicsConfig(pConfigInfo);
|
||||
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "RQ: DISPOSE_CONFIG: end MTLContext[%p] -----", mtlc);
|
||||
mtlc = NULL;
|
||||
break;
|
||||
}
|
||||
@@ -880,7 +915,7 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
|
||||
"MTLRenderQueue_flushBuffer: invalid opcode=%d", opcode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // buffer processing
|
||||
|
||||
if (mtlc != NULL) {
|
||||
if (mtlPreviousOp == MTL_OP_MASK_OP) {
|
||||
@@ -894,6 +929,10 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
|
||||
}
|
||||
}
|
||||
RESET_PREVIOUS_OP();
|
||||
|
||||
#if CHECK_MAIN_THREAD_LATENCY == 1
|
||||
checkMainThreadLatency();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -225,7 +225,9 @@ Java_sun_java2d_opengl_CGLLayer_nativeSetScale
|
||||
// this method where we need to change native texture size and layer's scale
|
||||
// in one call on appkit, otherwise we'll get window's contents blinking,
|
||||
// during screen-2-screen moving.
|
||||
[ThreadUtilities performOnMainThreadWaiting:[NSThread isMainThread] block:^(){
|
||||
// Ensure main thread changes the MTLLayer instance later:
|
||||
[ThreadUtilities performOnMainThreadNowOrLater:^(){
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "CGLLayer_nativeSetScale: layer = %p scale = %.3lf", layer, scale);
|
||||
layer.contentsScale = scale;
|
||||
}];
|
||||
JNI_COCOA_EXIT(env);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -139,9 +139,14 @@ __attribute__((visibility("default")))
|
||||
+ (void)detachCurrentThread;
|
||||
+ (void)setAppkitThreadGroup:(jobject)group;
|
||||
|
||||
+ (NSString*)getCaller;
|
||||
|
||||
+ (void)performOnMainThreadNowOrLater:(void (^)())block;
|
||||
|
||||
+ (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block;
|
||||
+ (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait;
|
||||
+ (NSString*)javaRunLoopMode;
|
||||
|
||||
@end
|
||||
|
||||
JNIEXPORT void OSXAPP_SetJavaVM(JavaVM *vm);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -25,10 +25,23 @@
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <objc/message.h>
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
#import "ThreadUtilities.h"
|
||||
|
||||
|
||||
/*
|
||||
* Enable the MainThread task monitor to detect slow tasks that may cause high latencies or delays
|
||||
*/
|
||||
#define CHECK_MAIN_THREAD 0
|
||||
#define TRACE_MAIN_THREAD 0
|
||||
|
||||
// ~ 2ms is already high for main thread:
|
||||
#define LATENCY_HIGH_THRESHOLD 2.0
|
||||
|
||||
#define DECORATE_MAIN_THREAD (TRACE_MAIN_THREAD || CHECK_MAIN_THREAD)
|
||||
|
||||
|
||||
// The following must be named "jvm", as there are extern references to it in AWT
|
||||
JavaVM *jvm = NULL;
|
||||
static JNIEnv *appKitEnv = NULL;
|
||||
@@ -110,32 +123,109 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
Block_release(blockCopy);
|
||||
}
|
||||
|
||||
+ (void)performOnMainThreadNowOrLater:(void (^)())block {
|
||||
if ([NSThread isMainThread]) {
|
||||
block();
|
||||
} else {
|
||||
[self performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Block_copy(block) waitUntilDone:NO];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block {
|
||||
if ([NSThread isMainThread] && wait == YES) {
|
||||
if ([NSThread isMainThread] && wait) {
|
||||
block();
|
||||
} else {
|
||||
[self performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Block_copy(block) waitUntilDone:wait];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait {
|
||||
if ([NSThread isMainThread] && wait == YES) {
|
||||
[target performSelector:aSelector withObject:arg];
|
||||
} else {
|
||||
if (wait && isEventDispatchThread()) {
|
||||
void (^blockCopy)(void) = Block_copy(^(){
|
||||
setBlockingEventDispatchThread(YES);
|
||||
@try {
|
||||
[target performSelector:aSelector withObject:arg];
|
||||
} @finally {
|
||||
setBlockingEventDispatchThread(NO);
|
||||
}
|
||||
});
|
||||
[self performSelectorOnMainThread:@selector(invokeBlockCopy:) withObject:blockCopy waitUntilDone:YES modes:javaModes];
|
||||
} else {
|
||||
[target performSelectorOnMainThread:aSelector withObject:arg waitUntilDone:wait modes:javaModes];
|
||||
}
|
||||
+ (NSString*)getCaller {
|
||||
#if DECORATE_MAIN_THREAD > 0
|
||||
const NSArray<NSString*> *symbols = NSThread.callStackSymbols;
|
||||
|
||||
for (NSUInteger i = 2, len = [symbols count]; i < len; i++) {
|
||||
NSString* symbol = [symbols objectAtIndex:i];
|
||||
if (![symbol hasPrefix: @"performOnMainThread"]) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait {
|
||||
#if DECORATE_MAIN_THREAD == 0
|
||||
if ([NSThread isMainThread] && wait) {
|
||||
[target performSelector:aSelector withObject:arg];
|
||||
} else if (wait && isEventDispatchThread()) {
|
||||
void (^blockCopy)(void) = Block_copy(^() {
|
||||
setBlockingEventDispatchThread(YES);
|
||||
@try {
|
||||
[target performSelector:aSelector withObject:arg];
|
||||
} @finally {
|
||||
setBlockingEventDispatchThread(NO);
|
||||
}
|
||||
});
|
||||
[self performSelectorOnMainThread:@selector(invokeBlockCopy:) withObject:blockCopy waitUntilDone:YES modes:javaModes];
|
||||
} else {
|
||||
[target performSelectorOnMainThread:aSelector withObject:arg waitUntilDone:wait modes:javaModes];
|
||||
}
|
||||
#else
|
||||
// Perform instrumentation on selector:
|
||||
static mach_timebase_info_data_t* timebase = nil;
|
||||
if (timebase == nil) {
|
||||
timebase = malloc(sizeof (mach_timebase_info_data_t));
|
||||
mach_timebase_info(timebase);
|
||||
}
|
||||
|
||||
const NSString* caller = [self getCaller];
|
||||
BOOL invokeDirect = NO;
|
||||
BOOL blockingEDT;
|
||||
|
||||
if ([NSThread isMainThread] && wait) {
|
||||
invokeDirect = YES;
|
||||
blockingEDT = NO;
|
||||
} else if (wait && isEventDispatchThread()) {
|
||||
blockingEDT = YES;
|
||||
} else {
|
||||
blockingEDT = NO;
|
||||
}
|
||||
const char* operation = (invokeDirect ? "now " : (blockingEDT ? "block" : "later"));
|
||||
|
||||
void (^blockCopy)(void) = Block_copy(^(){
|
||||
const uint64_t start = mach_absolute_time();
|
||||
|
||||
if (TRACE_MAIN_THREAD) {
|
||||
NSLog(@"performOnMainThread(%s)[before block]: [%@]", operation, caller);
|
||||
}
|
||||
|
||||
if (blockingEDT) {
|
||||
setBlockingEventDispatchThread(YES);
|
||||
}
|
||||
@try {
|
||||
[target performSelector:aSelector withObject:arg];
|
||||
} @finally {
|
||||
if (blockingEDT) {
|
||||
setBlockingEventDispatchThread(NO);
|
||||
}
|
||||
|
||||
const double elapsedMs = ((mach_absolute_time() - start) * timebase->numer) / (1000000.0 * timebase->denom);
|
||||
|
||||
if (TRACE_MAIN_THREAD) {
|
||||
NSLog(@"performOnMainThread(%s)[after block - time: %.3lf ms]: [%@]", operation, elapsedMs, caller);
|
||||
}
|
||||
|
||||
if (CHECK_MAIN_THREAD && (elapsedMs >= LATENCY_HIGH_THRESHOLD)) {
|
||||
NSLog(@"performOnMainThread(%s)[time: %.3lf ms]: [%@]", operation, elapsedMs, caller);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (invokeDirect) {
|
||||
[self performSelector:@selector(invokeBlockCopy:) withObject:blockCopy];
|
||||
} else {
|
||||
[self performSelectorOnMainThread:@selector(invokeBlockCopy:) withObject:blockCopy waitUntilDone:wait modes:javaModes];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (NSString*)javaRunLoopMode {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#import "JNIUtilities.h"
|
||||
#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
|
||||
#import <ThreadUtilities.h>
|
||||
|
||||
#import "apple_laf_JRSUIControl.h"
|
||||
#import "apple_laf_JRSUIConstants_DoubleValue.h"
|
||||
@@ -158,9 +159,14 @@ JNIEXPORT jint JNICALL Java_apple_laf_JRSUIControl_syncChanges
|
||||
static inline jint doPaintCGContext(CGContextRef cgRef, jlong controlPtr, jlong oldProperties, jlong newProperties, jdouble x, jdouble y, jdouble w, jdouble h)
|
||||
{
|
||||
JRSUIControlRef control = (JRSUIControlRef)jlong_to_ptr(controlPtr);
|
||||
|
||||
_SyncEncodedProperties(control, oldProperties, newProperties);
|
||||
CGRect bounds = CGRectMake(x, y, w, h);
|
||||
JRSUIControlDraw(gRenderer, control, cgRef, bounds);
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
CGRect bounds = CGRectMake(x, y, w, h);
|
||||
JRSUIControlDraw(gRenderer, control, cgRef, bounds);
|
||||
}];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -248,7 +254,13 @@ JNIEXPORT jint JNICALL Java_apple_laf_JRSUIControl_getNativeHitPart
|
||||
CGRect bounds = CGRectMake(x, y, w, h);
|
||||
CGPoint point = CGPointMake(pointX, pointY);
|
||||
|
||||
return JRSUIControlGetHitPart(gRenderer, control, bounds, point);
|
||||
__block JRSUIPartHit result;
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
result = JRSUIControlGetHitPart(gRenderer, control, bounds, point);
|
||||
}];
|
||||
|
||||
return (jint)result;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -259,7 +271,12 @@ JNIEXPORT jint JNICALL Java_apple_laf_JRSUIControl_getNativeHitPart
|
||||
JNIEXPORT jboolean JNICALL Java_apple_laf_JRSUIUtils_00024ScrollBar_shouldUseScrollToClick
|
||||
(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
return JRSUIControlShouldScrollToClick();
|
||||
__block Boolean result;
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
result = JRSUIControlShouldScrollToClick();
|
||||
}];
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -273,8 +290,12 @@ JNIEXPORT void JNICALL Java_apple_laf_JRSUIControl_getNativePartBounds
|
||||
JRSUIControlRef control = (JRSUIControlRef)jlong_to_ptr(controlPtr);
|
||||
_SyncEncodedProperties(control, oldProperties, newProperties);
|
||||
|
||||
CGRect frame = CGRectMake(x, y, w, h);
|
||||
CGRect partBounds = JRSUIControlGetScrollBarPartBounds(control, frame, part);
|
||||
__block CGRect partBounds;
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
CGRect frame = CGRectMake(x, y, w, h);
|
||||
partBounds = JRSUIControlGetScrollBarPartBounds(control, frame, part);
|
||||
}];
|
||||
|
||||
jdouble *rect = (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL);
|
||||
if (rect != NULL) {
|
||||
@@ -297,6 +318,11 @@ JNIEXPORT jdouble JNICALL Java_apple_laf_JRSUIControl_getNativeScrollBarOffsetCh
|
||||
JRSUIControlRef control = (JRSUIControlRef)jlong_to_ptr(controlPtr);
|
||||
_SyncEncodedProperties(control, oldProperties, newProperties);
|
||||
|
||||
CGRect frame = CGRectMake(x, y, w, h);
|
||||
return (jdouble)JRSUIControlGetScrollBarOffsetFor(control, frame, offset, visibleAmount, extent);
|
||||
__block jdouble result;
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
CGRect frame = CGRectMake(x, y, w, h);
|
||||
result = (jdouble)JRSUIControlGetScrollBarOffsetFor(control, frame, offset, visibleAmount, extent);
|
||||
}];
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -154,6 +154,9 @@ J2dTraceImpl(int level, jboolean cr, const char *string, ...);
|
||||
#define J2dRlsTrace5(level, string, arg1, arg2, arg3, arg4, arg5) { \
|
||||
J2dTraceImpl(level, JNI_FALSE, string, arg1, arg2, arg3, arg4, arg5); \
|
||||
}
|
||||
#define J2dRlsTrace6(level, string, arg1, arg2, arg3, arg4, arg5, arg6) { \
|
||||
J2dTraceImpl(level, JNI_FALSE, string, arg1, arg2, arg3, arg4, arg5, arg6); \
|
||||
}
|
||||
#define J2dRlsTraceLn(level, string) { \
|
||||
J2dTraceImpl(level, JNI_TRUE, string); \
|
||||
}
|
||||
@@ -172,6 +175,9 @@ J2dTraceImpl(int level, jboolean cr, const char *string, ...);
|
||||
#define J2dRlsTraceLn5(level, string, arg1, arg2, arg3, arg4, arg5) { \
|
||||
J2dTraceImpl(level, JNI_TRUE, string, arg1, arg2, arg3, arg4, arg5); \
|
||||
}
|
||||
#define J2dRlsTraceLn6(level, string, arg1, arg2, arg3, arg4, arg5, arg6) { \
|
||||
J2dTraceImpl(level, JNI_TRUE, string, arg1, arg2, arg3, arg4, arg5, arg6); \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user