Commit d56864e2 authored by Igor Demin's avatar Igor Demin

Redrawer. Fix macOs issues

parent 38ae7bf7
...@@ -69,6 +69,7 @@ native crash in SkiaWindowTest "render single window" ...@@ -69,6 +69,7 @@ native crash in SkiaWindowTest "render single window"
} }
init { init {
setLocation(200,200)
setSize(width, height) setSize(width, height)
defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
layer.renderer = object : SkiaRenderer { layer.renderer = object : SkiaRenderer {
...@@ -208,6 +209,7 @@ j org.jetbrains.skiko.redrawer.MacOsRedrawer$drawLayer$1.draw()V+7 ...@@ -208,6 +209,7 @@ j org.jetbrains.skiko.redrawer.MacOsRedrawer$drawLayer$1.draw()V+7
val window = SkiaWindow() val window = SkiaWindow()
try { try {
window.setLocation(200, 200)
window.setSize(400, 400) window.setSize(400, 400)
window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
window.isUndecorated = true window.isUndecorated = true
......
...@@ -51,6 +51,7 @@ class SkiaWindowTest { ...@@ -51,6 +51,7 @@ class SkiaWindowTest {
fun `render single window`() = swingTest { fun `render single window`() = swingTest {
val window = SkiaWindow() val window = SkiaWindow()
try { try {
window.setLocation(200, 200)
window.setSize(400, 200) window.setSize(400, 200)
window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
val renderer = RectRenderer(window.layer, 200, 100, Color.RED) val renderer = RectRenderer(window.layer, 200, 100, Color.RED)
...@@ -74,6 +75,7 @@ class SkiaWindowTest { ...@@ -74,6 +75,7 @@ class SkiaWindowTest {
fun `resize window`() = swingTest { fun `resize window`() = swingTest {
val window = SkiaWindow() val window = SkiaWindow()
try { try {
window.setLocation(200, 200)
window.setSize(40, 20) window.setSize(40, 20)
window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
window.layer.renderer = RectRenderer(window.layer, 20, 10, Color.RED) window.layer.renderer = RectRenderer(window.layer, 20, 10, Color.RED)
...@@ -93,6 +95,7 @@ class SkiaWindowTest { ...@@ -93,6 +95,7 @@ class SkiaWindowTest {
@Test @Test
fun `render three windows`() = swingTest { fun `render three windows`() = swingTest {
fun window(color: Color) = SkiaWindow().apply { fun window(color: Color) = SkiaWindow().apply {
setLocation(200,200)
setSize(400, 200) setSize(400, 200)
defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
layer.renderer = RectRenderer(layer, 200, 100, color) layer.renderer = RectRenderer(layer, 200, 100, color)
...@@ -131,6 +134,7 @@ class SkiaWindowTest { ...@@ -131,6 +134,7 @@ class SkiaWindowTest {
val window = SkiaWindow() val window = SkiaWindow()
try { try {
window.setLocation(200, 200)
window.setSize(40, 20) window.setSize(40, 20)
window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
window.layer.renderer = object : SkiaRenderer { window.layer.renderer = object : SkiaRenderer {
...@@ -161,6 +165,7 @@ class SkiaWindowTest { ...@@ -161,6 +165,7 @@ class SkiaWindowTest {
@Test @Test
fun `open windows stress test`() = swingTest { fun `open windows stress test`() = swingTest {
fun window(isAnimated: Boolean) = SkiaWindow().apply { fun window(isAnimated: Boolean) = SkiaWindow().apply {
setLocation(200,200)
setSize(40, 20) setSize(40, 20)
defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
layer.renderer = if (isAnimated) { layer.renderer = if (isAnimated) {
...@@ -219,6 +224,7 @@ class SkiaWindowTest { ...@@ -219,6 +224,7 @@ class SkiaWindowTest {
val window = SkiaWindow() val window = SkiaWindow()
try { try {
window.setLocation(200, 200)
window.setSize(400, 200) window.setSize(400, 200)
window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
......
...@@ -58,9 +58,14 @@ open class SkiaLayer : HardwareLayer() { ...@@ -58,9 +58,14 @@ open class SkiaLayer : HardwareLayer() {
super.dispose() super.dispose()
} }
override fun setBounds(x: Int, y: Int, width: Int, height: Int) {
super.setBounds(x, y, width, height)
redrawer?.syncSize()
needRedraw()
}
override fun paint(g: Graphics) { override fun paint(g: Graphics) {
super.paint(g) super.paint(g)
// we don't have to call it in setBounds method, because paint will always be called after setBounds
redrawer?.syncSize() redrawer?.syncSize()
needRedraw() needRedraw()
} }
......
...@@ -14,14 +14,14 @@ internal class MacOsRedrawer( ...@@ -14,14 +14,14 @@ internal class MacOsRedrawer(
) : Redrawer { ) : Redrawer {
private val containerLayerPtr = initContainer(layer) private val containerLayerPtr = initContainer(layer)
private val drawLayer = object : AWTGLLayer(containerLayerPtr) { private val drawLayer = object : AWTGLLayer(containerLayerPtr, setNeedsDisplayOnBoundsChange = true) {
override fun draw() = layer.draw() override fun draw() = layer.draw()
} }
// use a separate layer for vsync, because with single layer we cannot asynchronously update layer // use a separate layer for vsync, because with single layer we cannot asynchronously update layer
// `update` is suspend, and runBlocking(Dispatchers.Swing) causes dead lock with AppKit Thread. // `update` is suspend, and runBlocking(Dispatchers.Swing) causes dead lock with AppKit Thread.
// AWT has a method to avoid dead locks but it is internal (sun.lwawt.macosx.LWCToolkit.invokeAndWait) // AWT has a method to avoid dead locks but it is internal (sun.lwawt.macosx.LWCToolkit.invokeAndWait)
private val vsyncLayer = object : AWTGLLayer(containerLayerPtr) { private val vsyncLayer = object : AWTGLLayer(containerLayerPtr, setNeedsDisplayOnBoundsChange = false) {
@Volatile @Volatile
private var needDraw: CompletableDeferred<Unit>? = null private var needDraw: CompletableDeferred<Unit>? = null
...@@ -34,7 +34,7 @@ internal class MacOsRedrawer( ...@@ -34,7 +34,7 @@ internal class MacOsRedrawer(
val opengl = OpenGLApi.instance val opengl = OpenGLApi.instance
opengl.glClearColor(0f, 0f, 0f, 0f) opengl.glClearColor(0f, 0f, 0f, 0f)
opengl.glClear(opengl.GL_COLOR_BUFFER_BIT) opengl.glClear(opengl.GL_COLOR_BUFFER_BIT)
needDraw!!.complete(Unit) needDraw?.complete(Unit)
} }
override fun canDraw(): Boolean { override fun canDraw(): Boolean {
...@@ -83,7 +83,12 @@ internal class MacOsRedrawer( ...@@ -83,7 +83,12 @@ internal class MacOsRedrawer(
val globalPosition = convertPoint(layer, layer.x, layer.y, getRootPane(layer)) val globalPosition = convertPoint(layer, layer.x, layer.y, getRootPane(layer))
setContentScale(containerLayerPtr, layer.contentScale) setContentScale(containerLayerPtr, layer.contentScale)
setContentScale(drawLayer.ptr, layer.contentScale) setContentScale(drawLayer.ptr, layer.contentScale)
drawLayer.setFrame(globalPosition.x, globalPosition.y, layer.width, layer.height) drawLayer.setFrame(
globalPosition.x,
globalPosition.y,
layer.width.coerceAtLeast(0),
layer.height.coerceAtLeast(0)
)
} }
override fun needRedraw() { override fun needRedraw() {
...@@ -91,9 +96,9 @@ internal class MacOsRedrawer( ...@@ -91,9 +96,9 @@ internal class MacOsRedrawer(
} }
} }
private open class AWTGLLayer(private val containerPtr: Long) { private open class AWTGLLayer(private val containerPtr: Long, setNeedsDisplayOnBoundsChange: Boolean) {
@Suppress("LeakingThis") @Suppress("LeakingThis")
val ptr = initAWTGLLayer(containerPtr, this) val ptr = initAWTGLLayer(containerPtr, this, setNeedsDisplayOnBoundsChange)
fun setFrame(x: Int, y: Int, width: Int, height: Int) { fun setFrame(x: Int, y: Int, width: Int, height: Int) {
setFrame(containerPtr, ptr, x.toFloat(), y.toFloat(), width.toFloat(), height.toFloat()) setFrame(containerPtr, ptr, x.toFloat(), y.toFloat(), width.toFloat(), height.toFloat())
...@@ -111,7 +116,7 @@ private open class AWTGLLayer(private val containerPtr: Long) { ...@@ -111,7 +116,7 @@ private open class AWTGLLayer(private val containerPtr: Long) {
// Called in AppKit Thread // Called in AppKit Thread
protected open fun canDraw() = true protected open fun canDraw() = true
// Called in AppKit Thread, shouldn't be called if canDraw returned false // Called in AppKit Thread
protected open fun draw() = Unit protected open fun draw() = Unit
private external fun isAsynchronous(ptr: Long): Boolean private external fun isAsynchronous(ptr: Long): Boolean
...@@ -122,5 +127,5 @@ private open class AWTGLLayer(private val containerPtr: Long) { ...@@ -122,5 +127,5 @@ private open class AWTGLLayer(private val containerPtr: Long) {
private external fun initContainer(layer: HardwareLayer): Long private external fun initContainer(layer: HardwareLayer): Long
private external fun setContentScale(layerNativePtr: Long, contentScale: Float) private external fun setContentScale(layerNativePtr: Long, contentScale: Float)
private external fun initAWTGLLayer(containerPtr: Long, layer: AWTGLLayer): Long private external fun initAWTGLLayer(containerPtr: Long, layer: AWTGLLayer, setNeedsDisplayOnBoundsChange: Boolean): Long
private external fun disposeAWTGLLayer(ptr: Long) private external fun disposeAWTGLLayer(ptr: Long)
...@@ -27,7 +27,6 @@ JavaVM *jvm = NULL; ...@@ -27,7 +27,6 @@ JavaVM *jvm = NULL;
[self removeAllAnimations]; [self removeAllAnimations];
[self setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; [self setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)];
[self setNeedsDisplayOnBoundsChange: YES];
return self; return self;
} }
...@@ -109,12 +108,13 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_MacOsRedrawerKt_setCont ...@@ -109,12 +108,13 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_MacOsRedrawerKt_setCont
layer.contentsScale = contentScale; layer.contentsScale = contentScale;
} }
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MacOsRedrawerKt_initAWTGLLayer(JNIEnv *env, jobject obj, jlong containerPtr, jobject layer) JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MacOsRedrawerKt_initAWTGLLayer(JNIEnv *env, jobject obj, jlong containerPtr, jobject layer, jboolean setNeedsDisplayOnBoundsChange)
{ {
CALayer *container = (CALayer *) containerPtr; CALayer *container = (CALayer *) containerPtr;
AWTGLLayer *glLayer = [AWTGLLayer new]; AWTGLLayer *glLayer = [AWTGLLayer new];
glLayer.javaRef = (*env)->NewGlobalRef(env, layer); glLayer.javaRef = (*env)->NewGlobalRef(env, layer);
[glLayer setNeedsDisplayOnBoundsChange: setNeedsDisplayOnBoundsChange];
[container addSublayer: glLayer]; [container addSublayer: glLayer];
return (jlong) glLayer; return (jlong) glLayer;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment