Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
skiko
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
liuqiang
skiko
Commits
53f70be8
Unverified
Commit
53f70be8
authored
May 17, 2023
by
Elijah Semyonov
Committed by
GitHub
May 17, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Fix for losing presented drawables on JVM Mac OS (#708)" (#710)
This reverts commit
85aef666
.
parent
85aef666
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
93 additions
and
312 deletions
+93
-312
MetalRedrawer.kt
...Main/kotlin/org/jetbrains/skiko/redrawer/MetalRedrawer.kt
+4
-11
AWTMetalLayer.h
skiko/src/awtMain/objectiveC/macos/AWTMetalLayer.h
+0
-17
AWTMetalLayer.mm
skiko/src/awtMain/objectiveC/macos/AWTMetalLayer.mm
+0
-17
MetalContextHandler.mm
skiko/src/awtMain/objectiveC/macos/MetalContextHandler.mm
+2
-9
MetalDevice.h
skiko/src/awtMain/objectiveC/macos/MetalDevice.h
+8
-21
MetalDevice.mm
skiko/src/awtMain/objectiveC/macos/MetalDevice.mm
+0
-150
MetalRedrawer.mm
skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm
+72
-11
SkiaLayerTest.kt
...o/src/awtTest/kotlin/org/jetbrains/skiko/SkiaLayerTest.kt
+3
-69
UiTest.kt
skiko/src/awtTest/kotlin/org/jetbrains/skiko/util/UiTest.kt
+2
-3
FrameDispatcher.kt
.../commonMain/kotlin/org/jetbrains/skiko/FrameDispatcher.kt
+2
-4
No files found.
skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/MetalRedrawer.kt
View file @
53f70be8
...
@@ -73,6 +73,8 @@ internal class MetalRedrawer(
...
@@ -73,6 +73,8 @@ internal class MetalRedrawer(
override
val
renderInfo
:
String
get
()
=
contextHandler
.
rendererInfo
()
override
val
renderInfo
:
String
get
()
=
contextHandler
.
rendererInfo
()
private
val
windowHandle
=
layer
.
windowHandle
private
val
frameDispatcher
=
FrameDispatcher
(
MainUIDispatcher
)
{
private
val
frameDispatcher
=
FrameDispatcher
(
MainUIDispatcher
)
{
if
(
layer
.
isShowing
)
{
if
(
layer
.
isShowing
)
{
update
(
System
.
nanoTime
())
update
(
System
.
nanoTime
())
...
@@ -84,10 +86,6 @@ internal class MetalRedrawer(
...
@@ -84,10 +86,6 @@ internal class MetalRedrawer(
onContextInit
()
onContextInit
()
}
}
fun
drawSync
()
{
frameDispatcher
.
scheduleFrame
()
}
override
fun
dispose
()
=
synchronized
(
drawLock
)
{
override
fun
dispose
()
=
synchronized
(
drawLock
)
{
frameDispatcher
.
cancel
()
frameDispatcher
.
cancel
()
contextHandler
.
dispose
()
contextHandler
.
dispose
()
...
@@ -135,13 +133,10 @@ internal class MetalRedrawer(
...
@@ -135,13 +133,10 @@ internal class MetalRedrawer(
// When window is not visible - it doesn't make sense to redraw fast to avoid battery drain.
// When window is not visible - it doesn't make sense to redraw fast to avoid battery drain.
// In theory, we could be more precise, and just suspend rendering in
// In theory, we could be more precise, and just suspend rendering in
// `NSWindowDidChangeOcclusionStateNotification`, but current approach seems to work as well in practise.
// `NSWindowDidChangeOcclusionStateNotification`, but current approach seems to work as well in practise.
if
(
isOccluded
())
if
(
isOccluded
(
windowHandle
))
delay
(
300
)
delay
(
300
)
}
}
/**
* Avoid calling this method on main thread, it will sleep before next vsync happens if invoked multiple times.
*/
private
fun
performDraw
()
=
synchronized
(
drawLock
)
{
private
fun
performDraw
()
=
synchronized
(
drawLock
)
{
if
(!
isDisposed
)
{
if
(!
isDisposed
)
{
val
handle
=
startRendering
()
val
handle
=
startRendering
()
...
@@ -171,8 +166,6 @@ internal class MetalRedrawer(
...
@@ -171,8 +166,6 @@ internal class MetalRedrawer(
setLayerVisible
(
device
.
ptr
,
isVisible
)
setLayerVisible
(
device
.
ptr
,
isVisible
)
}
}
private
fun
isOccluded
()
=
isOccluded
(
device
.
ptr
)
private
external
fun
chooseAdapter
(
adapterPriority
:
Int
):
Long
private
external
fun
chooseAdapter
(
adapterPriority
:
Int
):
Long
private
external
fun
createMetalDevice
(
window
:
Long
,
transparency
:
Boolean
,
adapter
:
Long
,
platformInfo
:
Long
):
Long
private
external
fun
createMetalDevice
(
window
:
Long
,
transparency
:
Boolean
,
adapter
:
Long
,
platformInfo
:
Long
):
Long
private
external
fun
disposeDevice
(
device
:
Long
)
private
external
fun
disposeDevice
(
device
:
Long
)
...
@@ -180,7 +173,7 @@ internal class MetalRedrawer(
...
@@ -180,7 +173,7 @@ internal class MetalRedrawer(
private
external
fun
setLayerVisible
(
device
:
Long
,
isVisible
:
Boolean
)
private
external
fun
setLayerVisible
(
device
:
Long
,
isVisible
:
Boolean
)
private
external
fun
setContentScale
(
device
:
Long
,
contentScale
:
Float
)
private
external
fun
setContentScale
(
device
:
Long
,
contentScale
:
Float
)
private
external
fun
setVSyncEnabled
(
device
:
Long
,
enabled
:
Boolean
)
private
external
fun
setVSyncEnabled
(
device
:
Long
,
enabled
:
Boolean
)
private
external
fun
isOccluded
(
device
:
Long
):
Boolean
private
external
fun
isOccluded
(
window
:
Long
):
Boolean
private
external
fun
getAdapterName
(
adapter
:
Long
):
String
private
external
fun
getAdapterName
(
adapter
:
Long
):
String
private
external
fun
getAdapterMemorySize
(
adapter
:
Long
):
Long
private
external
fun
getAdapterMemorySize
(
adapter
:
Long
):
Long
private
external
fun
startRendering
():
Long
private
external
fun
startRendering
():
Long
...
...
skiko/src/awtMain/objectiveC/macos/AWTMetalLayer.h
deleted
100644 → 0
View file @
85aef666
#ifdef SK_METAL
#ifndef SK_AWT_METAL_LAYER_H
#define SK_AWT_METAL_LAYER_H
#import <QuartzCore/CAMetalLayer.h>
#import <jni.h>
@interface
AWTMetalLayer
:
CAMetalLayer
@property
jobject
javaRef
;
@end
#endif // SK_AWT_METAL_LAYER_H
#endif // SK_METAL
\ No newline at end of file
skiko/src/awtMain/objectiveC/macos/AWTMetalLayer.mm
deleted
100644 → 0
View file @
85aef666
#import "AWTMetalLayer.h"
@implementation AWTMetalLayer
- (id)init {
self = [super init];
if (self) {
[self removeAllAnimations];
[self setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)];
[self setNeedsDisplayOnBoundsChange: YES];
}
return self;
}
@end
skiko/src/awtMain/objectiveC/macos/MetalContextHandler.mm
View file @
53f70be8
...
@@ -3,6 +3,8 @@
...
@@ -3,6 +3,8 @@
#import <jawt.h>
#import <jawt.h>
#import <jawt_md.h>
#import <jawt_md.h>
#import <QuartzCore/CAMetalLayer.h>
#import <Metal/Metal.h>
#import <GrDirectContext.h>
#import <GrDirectContext.h>
#import <mtl/GrMtlBackendContext.h>
#import <mtl/GrMtlBackendContext.h>
#import <mtl/GrMtlTypes.h>
#import <mtl/GrMtlTypes.h>
...
@@ -11,7 +13,6 @@
...
@@ -11,7 +13,6 @@
extern "C"
extern "C"
{
{
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_context_MetalContextHandler_makeMetalContext(
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_context_MetalContextHandler_makeMetalContext(
JNIEnv* env, jobject contextHandler, jlong devicePtr)
JNIEnv* env, jobject contextHandler, jlong devicePtr)
{
{
...
@@ -29,15 +30,10 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_context_MetalContextHandler_mak
...
@@ -29,15 +30,10 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_context_MetalContextHandler_mak
{
{
@autoreleasepool {
@autoreleasepool {
MetalDevice *device = (__bridge MetalDevice *) (void *) devicePtr;
MetalDevice *device = (__bridge MetalDevice *) (void *) devicePtr;
[device recreateDisplayLinkIfNeeded];
[device waitUntilVsync];
[device waitForQueueSlot];
GrBackendRenderTarget* renderTarget = NULL;
GrBackendRenderTarget* renderTarget = NULL;
id<CAMetalDrawable> currentDrawable = [device.layer nextDrawable];
id<CAMetalDrawable> currentDrawable = [device.layer nextDrawable];
if (!currentDrawable) {
if (!currentDrawable) {
[device freeQueueSlot];
return NULL;
return NULL;
}
}
device.drawableHandle = currentDrawable;
device.drawableHandle = currentDrawable;
...
@@ -60,9 +56,6 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_context_MetalContextHandler_fini
...
@@ -60,9 +56,6 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_context_MetalContextHandler_fini
id<MTLCommandBuffer> commandBuffer = [device.queue commandBuffer];
id<MTLCommandBuffer> commandBuffer = [device.queue commandBuffer];
commandBuffer.label = @"Present";
commandBuffer.label = @"Present";
[commandBuffer presentDrawable:currentDrawable];
[commandBuffer presentDrawable:currentDrawable];
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
[device freeQueueSlot];
}];
[commandBuffer commit];
[commandBuffer commit];
device.drawableHandle = nil;
device.drawableHandle = nil;
}
}
...
...
skiko/src/awtMain/objectiveC/macos/MetalDevice.h
View file @
53f70be8
#ifdef SK_METAL
#ifdef SK_METAL
#ifndef SK_METAL_DEVICE_H
@interface
AWTMetalLayer
:
CAMetalLayer
#define SK_METAL_DEVICE_H
#import <QuartzCore/QuartzCore.h>
@property
jobject
javaRef
;
#import <AppKit/AppKit.h>
#import <Metal/Metal.h>
#import "AWTMetalLayer.h"
@end
@interface
MetalDevice
:
NSObject
@interface
MetalDevice
:
NSObject
@property
(
weak
)
CALayer
*
container
;
@property
(
weak
)
CALayer
*
container
;
@property
(
strong
)
NSWindow
*
window
;
@property
(
retain
,
strong
)
AWTMetalLayer
*
layer
;
@property
(
strong
)
AWTMetalLayer
*
layer
;
@property
(
retain
,
strong
)
id
<
MTLDevice
>
adapter
;
@property
(
strong
)
id
<
MTLDevice
>
adapter
;
@property
(
retain
,
strong
)
id
<
MTLCommandQueue
>
queue
;
@property
(
strong
)
id
<
MTLCommandQueue
>
queue
;
@property
(
retain
,
strong
)
id
<
CAMetalDrawable
>
drawableHandle
;
@property
(
strong
)
id
<
CAMetalDrawable
>
drawableHandle
;
-
(
instancetype
)
initWithContainer
:(
CALayer
*
)
container
adapter
:(
id
<
MTLDevice
>
)
adapter
window
:(
NSWindow
*
)
window
;
-
(
void
)
recreateDisplayLinkIfNeeded
;
-
(
void
)
handleDisplayLinkFired
;
-
(
void
)
waitUntilVsync
;
-
(
void
)
waitForQueueSlot
;
-
(
void
)
freeQueueSlot
;
@end
@end
#endif // SK_AWT_METAL_DEVICE_H
#endif
\ No newline at end of file
#endif // SK_METAL
\ No newline at end of file
skiko/src/awtMain/objectiveC/macos/MetalDevice.mm
deleted
100644 → 0
View file @
85aef666
#import "MetalDevice.h"
#import <stdatomic.h>
static CVReturn MetalDeviceDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) {
MetalDevice *device = (__bridge MetalDevice *)displayLinkContext;
[device handleDisplayLinkFired];
return kCVReturnSuccess;
}
@implementation MetalDevice {
NSScreen *_displayLinkScreen;
CVDisplayLinkRef _displayLink;
dispatch_semaphore_t _presentingBuffersExhaustionSemaphore;
NSConditionLock *_vsyncConditionLock;
volatile atomic_bool _displayLinkOk;
}
- (instancetype)initWithContainer:(CALayer *)container adapter:(id<MTLDevice>)adapter window:(NSWindow *)window {
self = [super init];
if (self) {
self.container = container;
self.adapter = adapter;
self.queue = [adapter newCommandQueue];
self.window = window;
self.layer = [AWTMetalLayer new];
_displayLinkScreen = nil;
[container removeAllAnimations];
[container setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)];
[container setNeedsDisplayOnBoundsChange: YES];
self.layer.device = adapter;
self.layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
self.layer.contentsGravity = kCAGravityTopLeft;
CGFloat transparent[] = { 0.0f, 0.0f, 0.0f, 0.0f };
self.layer.backgroundColor = CGColorCreate(CGColorSpaceCreateDeviceRGB(), transparent);
self.layer.opaque = NO;
[container addSublayer: self.layer];
_presentingBuffersExhaustionSemaphore = dispatch_semaphore_create(3);
_vsyncConditionLock = [[NSConditionLock alloc] initWithCondition: 1];
atomic_store(&_displayLinkOk, true);
}
return self;
}
- (void)dealloc {
[self invalidateDisplayLink];
}
- (void)handleDisplayLinkSetupFailure {
atomic_store(&_displayLinkOk, false);
/// Next line is here to tackle edge case where displayLink reconstruction failed
/// but someone is already waiting at `waitUntilVsync`
/// It's quite improbable scenario anyway
[self handleDisplayLinkFired];
}
- (void)recreateDisplayLinkIfNeeded {
if ([self.window.screen isEqualTo: _displayLinkScreen]) {
return;
}
[self invalidateDisplayLink];
_displayLinkScreen = self.window.screen;
NSDictionary* screenDescription = [_displayLinkScreen deviceDescription];
NSNumber* screenID = [screenDescription objectForKey:@"NSScreenNumber"];
/// TODO: create fallback for any possible failure
CVReturn result;
CVDisplayLinkRef displayLink;
result = CVDisplayLinkCreateWithCGDisplay([screenID unsignedIntValue], &displayLink);
if (result != kCVReturnSuccess) {
[self handleDisplayLinkSetupFailure];
return;
}
result = CVDisplayLinkSetOutputCallback(displayLink, &MetalDeviceDisplayLinkCallback, (__bridge void *)(self));
if (result != kCVReturnSuccess) {
[self handleDisplayLinkSetupFailure];
return;
}
_displayLink = displayLink;
result = CVDisplayLinkStart(displayLink);
if (result != kCVReturnSuccess) {
[self handleDisplayLinkSetupFailure];
return;
}
atomic_store(&_displayLinkOk, true);
NSLog(@"DisplayLink launched for screen with ID: %@", screenID);
}
- (void)handleDisplayLinkFired {
[_vsyncConditionLock lock];
[_vsyncConditionLock unlockWithCondition:1];
}
- (void)waitUntilVsync {
bool displayLinkOk = atomic_load(&_displayLinkOk);
/// If display link construction was corrupted, don't perform any waiting
if (!displayLinkOk) {
return;
}
[_vsyncConditionLock lockWhenCondition:1];
[_vsyncConditionLock unlockWithCondition:0];
}
- (void)waitForQueueSlot {
/// In case we receive more encoded command buffers, than gpu can handle (GPU bottleneck),
/// we need to throttle it down and start a new frame only when one currently run is finished
///
/// see call place of `freeQueueSlot`
dispatch_semaphore_wait(_presentingBuffersExhaustionSemaphore, DISPATCH_TIME_FOREVER);
}
- (void)freeQueueSlot {
dispatch_semaphore_signal(_presentingBuffersExhaustionSemaphore);
}
- (void)invalidateDisplayLink {
if (_displayLink) {
CVDisplayLinkStop(_displayLink);
CVDisplayLinkRelease(_displayLink);
_displayLink = nil;
}
}
@end
skiko/src/awtMain/objectiveC/macos/MetalRedrawer.mm
View file @
53f70be8
...
@@ -3,6 +3,11 @@
...
@@ -3,6 +3,11 @@
#import <jawt.h>
#import <jawt.h>
#import <jawt_md.h>
#import <jawt_md.h>
#import <Cocoa/Cocoa.h>
#import <QuartzCore/QuartzCore.h>
#import <Metal/Metal.h>
#import <QuartzCore/CAMetalLayer.h>
#import <GrBackendSurface.h>
#import <GrBackendSurface.h>
#import <GrDirectContext.h>
#import <GrDirectContext.h>
#import <mtl/GrMtlBackendContext.h>
#import <mtl/GrMtlBackendContext.h>
...
@@ -18,11 +23,47 @@
...
@@ -18,11 +23,47 @@
#define AdpapterPriorityIntegrated 1
#define AdpapterPriorityIntegrated 1
#define AdpapterPriorityDiscrete 2
#define AdpapterPriorityDiscrete 2
@implementation AWTMetalLayer
- (id)init
{
self = [super init];
assert(self != NULL);
[self removeAllAnimations];
[self setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)];
[self setNeedsDisplayOnBoundsChange: YES];
return self;
}
@end
@implementation MetalDevice
- (id) init
{
self = [super init];
if (self)
{
self.layer = nil;
self.adapter = nil;
self.queue = nil;
self.drawableHandle = nil;
}
return self;
}
@end
extern "C"
extern "C"
{
{
void *
objc_autoreleasePoolPush(void);
extern "C" void*
objc_autoreleasePoolPush(void);
void objc_autoreleasePoolPop(void
*);
extern "C" void objc_autoreleasePoolPop(void
*);
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_startRendering(
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_startRendering(
JNIEnv * env, jobject redrawer)
JNIEnv * env, jobject redrawer)
...
@@ -31,9 +72,9 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_startRen
...
@@ -31,9 +72,9 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_startRen
}
}
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_endRendering(
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_endRendering(
JNIEnv *env, jobject redrawer, jlong handle)
JNIEnv *
env, jobject redrawer, jlong handle)
{
{
objc_autoreleasePoolPop((void
*)handle);
objc_autoreleasePoolPop((void*)handle);
}
}
BOOL isUsingIntegratedGPU() {
BOOL isUsingIntegratedGPU() {
...
@@ -107,17 +148,38 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_createMe
...
@@ -107,17 +148,38 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_createMe
{
{
@autoreleasepool {
@autoreleasepool {
id<MTLDevice> adapter = (__bridge_transfer id<MTLDevice>) (void *) adapterPtr;
id<MTLDevice> adapter = (__bridge_transfer id<MTLDevice>) (void *) adapterPtr;
MetalDevice *device = [MetalDevice new];
NSObject<JAWT_SurfaceLayers>* dsi_mac = (__bridge NSObject<JAWT_SurfaceLayers> *) (void*) platformInfoPtr;
NSObject<JAWT_SurfaceLayers>* dsi_mac = (__bridge NSObject<JAWT_SurfaceLayers> *) (void*) platformInfoPtr;
NSWindow *window = (__bridge NSWindow *) (void *) windowPtr;
CALayer *container = [dsi_mac windowLayer];
CALayer *container = [dsi_mac windowLayer];
[container removeAllAnimations];
[container setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)];
[container setNeedsDisplayOnBoundsChange: YES];
AWTMetalLayer *layer = [AWTMetalLayer new];
[container addSublayer: layer];
layer.javaRef = env->NewGlobalRef(redrawer);
id<MTLCommandQueue> fQueue = [adapter newCommandQueue];
MetalDevice *device = [[MetalDevice alloc] initWithContainer:container adapter:adapter window:window];
device.container = container;
device.layer = layer;
device.adapter = adapter;
device.queue = fQueue;
device.layer.javaRef = env->NewGlobalRef(redrawer);
device.layer.device = device.adapter;
device.layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
device.layer.contentsGravity = kCAGravityTopLeft;
CGFloat transparent[] = { 0.0f, 0.0f, 0.0f, 0.0f };
device.layer.backgroundColor = CGColorCreate(CGColorSpaceCreateDeviceRGB(), transparent);
device.layer.opaque = NO;
if (transparency)
if (transparency)
{
{
NSWindow* window = (__bridge NSWindow*) (void *) windowPtr;
window.hasShadow = NO;
window.hasShadow = NO;
}
}
...
@@ -220,11 +282,10 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_getAdapt
...
@@ -220,11 +282,10 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_getAdapt
}
}
JNIEXPORT jboolean JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_isOccluded(
JNIEXPORT jboolean JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_isOccluded(
JNIEnv *env, jobject redrawer, jlong
device
Ptr) {
JNIEnv *env, jobject redrawer, jlong
window
Ptr) {
@autoreleasepool {
@autoreleasepool {
MetalDevice *device = (__bridge MetalDevice *)(void *)devicePtr;
NSWindow* window = (__bridge NSWindow*) (void *) windowPtr;
return ([window occlusionState] & NSWindowOcclusionStateVisible) == 0;
return ([device.window occlusionState] & NSWindowOcclusionStateVisible) == 0;
}
}
}
}
...
...
skiko/src/awtTest/kotlin/org/jetbrains/skiko/SkiaLayerTest.kt
View file @
53f70be8
...
@@ -2,7 +2,6 @@ package org.jetbrains.skiko
...
@@ -2,7 +2,6 @@ package org.jetbrains.skiko
import
kotlinx.coroutines.CompletableDeferred
import
kotlinx.coroutines.CompletableDeferred
import
kotlinx.coroutines.delay
import
kotlinx.coroutines.delay
import
kotlinx.coroutines.launch
import
kotlinx.coroutines.yield
import
kotlinx.coroutines.yield
import
org.jetbrains.skia.Canvas
import
org.jetbrains.skia.Canvas
import
org.jetbrains.skia.FontMgr
import
org.jetbrains.skia.FontMgr
...
@@ -13,7 +12,6 @@ import org.jetbrains.skia.paragraph.ParagraphBuilder
...
@@ -13,7 +12,6 @@ import org.jetbrains.skia.paragraph.ParagraphBuilder
import
org.jetbrains.skia.paragraph.ParagraphStyle
import
org.jetbrains.skia.paragraph.ParagraphStyle
import
org.jetbrains.skia.paragraph.TextStyle
import
org.jetbrains.skia.paragraph.TextStyle
import
org.jetbrains.skiko.context.JvmContextHandler
import
org.jetbrains.skiko.context.JvmContextHandler
import
org.jetbrains.skiko.redrawer.MetalRedrawer
import
org.jetbrains.skiko.redrawer.Redrawer
import
org.jetbrains.skiko.redrawer.Redrawer
import
org.jetbrains.skiko.util.ScreenshotTestRule
import
org.jetbrains.skiko.util.ScreenshotTestRule
import
org.jetbrains.skiko.util.UiTestScope
import
org.jetbrains.skiko.util.UiTestScope
...
@@ -23,11 +21,12 @@ import org.junit.Assert.assertEquals
...
@@ -23,11 +21,12 @@ import org.junit.Assert.assertEquals
import
org.junit.Assume.assumeTrue
import
org.junit.Assume.assumeTrue
import
org.junit.Rule
import
org.junit.Rule
import
org.junit.Test
import
org.junit.Test
import
org.junit.Ignore
import
java.awt.BorderLayout
import
java.awt.BorderLayout
import
java.awt.Color
import
java.awt.Color
import
java.awt.Dimension
import
java.awt.Dimension
import
java.awt.event.*
import
java.awt.event.ComponentAdapter
import
java.awt.event.ComponentEvent
import
java.awt.event.WindowEvent
import
javax.swing.JFrame
import
javax.swing.JFrame
import
javax.swing.JLayeredPane
import
javax.swing.JLayeredPane
import
javax.swing.JPanel
import
javax.swing.JPanel
...
@@ -36,8 +35,6 @@ import javax.swing.WindowConstants
...
@@ -36,8 +35,6 @@ import javax.swing.WindowConstants
import
kotlin.random.Random
import
kotlin.random.Random
import
kotlin.test.assertNotNull
import
kotlin.test.assertNotNull
import
kotlin.test.assertTrue
import
kotlin.test.assertTrue
import
kotlin.time.Duration
import
kotlin.time.ExperimentalTime
@Suppress
(
"BlockingMethodInNonBlockingContext"
,
"SameParameterValue"
)
@Suppress
(
"BlockingMethodInNonBlockingContext"
,
"SameParameterValue"
)
class
SkiaLayerTest
{
class
SkiaLayerTest
{
...
@@ -95,69 +92,6 @@ class SkiaLayerTest {
...
@@ -95,69 +92,6 @@ class SkiaLayerTest {
)
)
}
}
@OptIn
(
ExperimentalTime
::
class
)
@Ignore
@Test
fun
`
frame
is
rendered
immediately
`
()
=
uiTest
{
val
window
=
UiTestWindow
(
properties
=
SkiaLayerProperties
(
isVsyncEnabled
=
true
)
)
val
colors
=
arrayOf
(
Color
.
RED
,
Color
.
GREEN
,
Color
.
BLUE
,
Color
.
YELLOW
)
var
counter1
=
0
var
counter2
=
0
val
paint
=
Paint
()
try
{
window
.
setLocation
(
200
,
200
)
window
.
setSize
(
400
,
600
)
window
.
defaultCloseOperation
=
WindowConstants
.
EXIT_ON_CLOSE
window
.
layer
.
skikoView
=
object
:
SkikoView
{
override
fun
onRender
(
canvas
:
Canvas
,
width
:
Int
,
height
:
Int
,
nanoTime
:
Long
)
{
val
c1
=
counter1
val
c2
=
counter2
paint
.
color
=
colors
[
c1
.
mod
(
colors
.
size
)].
rgb
canvas
.
drawRect
(
Rect
(
0f
,
0f
,
width
.
toFloat
(),
height
/
2f
),
paint
)
paint
.
color
=
colors
[
c2
.
mod
(
colors
.
size
)].
rgb
canvas
.
drawRect
(
Rect
(
0f
,
height
/
2f
,
width
.
toFloat
(),
height
.
toFloat
()),
paint
)
}
}
window
.
isVisible
=
true
window
.
addKeyListener
(
object
:
KeyAdapter
()
{
override
fun
keyTyped
(
e
:
KeyEvent
?)
{
launch
{
val
redrawer
=
window
.
layer
.
redrawer
as
MetalRedrawer
redrawer
.
drawSync
()
counter1
+=
1
redrawer
.
drawSync
()
counter2
+=
1
redrawer
.
drawSync
()
}
}
});
window
.
addWindowListener
(
object
:
WindowAdapter
()
{
override
fun
windowActivated
(
e
:
WindowEvent
?)
{
window
.
requestFocus
()
}
})
delay
(
Duration
.
INFINITE
)
}
finally
{
window
.
close
()
}
}
@Test
@Test
fun
`
render
single
window
`
()
=
uiTest
{
fun
`
render
single
window
`
()
=
uiTest
{
val
window
=
UiTestWindow
()
val
window
=
UiTestWindow
()
...
...
skiko/src/awtTest/kotlin/org/jetbrains/skiko/util/UiTest.kt
View file @
53f70be8
...
@@ -10,10 +10,9 @@ import javax.swing.JFrame
...
@@ -10,10 +10,9 @@ import javax.swing.JFrame
internal
fun
uiTest
(
block
:
suspend
UiTestScope
.()
->
Unit
)
{
internal
fun
uiTest
(
block
:
suspend
UiTestScope
.()
->
Unit
)
{
assumeFalse
(
GraphicsEnvironment
.
isHeadless
())
assumeFalse
(
GraphicsEnvironment
.
isHeadless
())
//
assumeTrue(System.getProperty("skiko.test.ui.enabled", "false") == "true")
assumeTrue
(
System
.
getProperty
(
"skiko.test.ui.enabled"
,
"false"
)
==
"true"
)
// val renderApi = System.getProperty("skiko.test.ui.renderApi", "all")
val
renderApi
=
System
.
getProperty
(
"skiko.test.ui.renderApi"
,
"all"
)
val
renderApi
=
"metal"
runBlocking
(
MainUIDispatcher
)
{
runBlocking
(
MainUIDispatcher
)
{
if
(
renderApi
==
"all"
)
{
if
(
renderApi
==
"all"
)
{
...
...
skiko/src/commonMain/kotlin/org/jetbrains/skiko/FrameDispatcher.kt
View file @
53f70be8
...
@@ -13,11 +13,11 @@ import kotlin.coroutines.CoroutineContext
...
@@ -13,11 +13,11 @@ import kotlin.coroutines.CoroutineContext
*/
*/
class
FrameDispatcher
(
class
FrameDispatcher
(
scope
:
CoroutineScope
,
scope
:
CoroutineScope
,
private
val
onFrame
:
suspend
()
->
Unit
,
private
val
onFrame
:
suspend
()
->
Unit
)
{
)
{
constructor
(
constructor
(
context
:
CoroutineContext
,
context
:
CoroutineContext
,
onFrame
:
suspend
()
->
Unit
,
onFrame
:
suspend
()
->
Unit
)
:
this
(
)
:
this
(
CoroutineScope
(
context
),
CoroutineScope
(
context
),
onFrame
onFrame
...
@@ -28,9 +28,7 @@ class FrameDispatcher(
...
@@ -28,9 +28,7 @@ class FrameDispatcher(
private
val
job
=
scope
.
launch
{
private
val
job
=
scope
.
launch
{
while
(
true
)
{
while
(
true
)
{
// Await for draw request
frameChannel
.
receive
()
frameChannel
.
receive
()
frameScheduled
=
false
frameScheduled
=
false
onFrame
()
onFrame
()
// As per `yield()` documentation:
// As per `yield()` documentation:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment