diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/SkiaLayer.awt.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/SkiaLayer.awt.kt index cbfeccd90..79d997ff0 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/SkiaLayer.awt.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/SkiaLayer.awt.kt @@ -645,13 +645,22 @@ actual open class SkiaLayer internal constructor( @Suppress("LeakingThis") private val fpsCounter = defaultFPSCounter(this) - internal inline fun inDrawScope(body: () -> Unit) { + private fun createDrawScope() = LayerDrawScope( + pixelGeometry = pixelGeometry, + layerWidth = width, + layerHeight = height, + scale = contentScale + ) + + internal inline fun inDrawScope(body: LayerDrawScope.() -> Unit) { check(isEventDispatchThread()) { "Method should be called from AWT event dispatch thread" } check(!isDisposed) { "SkiaLayer is disposed" } try { fpsCounter?.tick() - body() - } catch (e: CancellationException) { + with(createDrawScope()) { + body() + } + } catch (_: CancellationException) { // ignore } catch (e: RenderException) { if (!isDisposed) { diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/AngleContextHandler.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/AngleContextHandler.kt index e1d6aee18..211fadee7 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/AngleContextHandler.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/AngleContextHandler.kt @@ -2,6 +2,7 @@ package org.jetbrains.skiko.context import org.jetbrains.skia.* import org.jetbrains.skiko.AngleApi +import org.jetbrains.skiko.LayerDrawScope import org.jetbrains.skiko.RenderException import org.jetbrains.skiko.SkiaLayer import org.jetbrains.skiko.redrawer.AngleRedrawer @@ -23,12 +24,11 @@ internal class AngleContextHandler(layer: SkiaLayer) : ContextBasedContextHandle return false } - override fun initCanvas() { + override fun LayerDrawScope.initCanvas() { val context = context ?: return - val scale = layer.contentScale - val w = (layer.width * scale).toInt().coerceAtLeast(0) - val h = (layer.height * scale).toInt().coerceAtLeast(0) + val w = scaledLayerWidth + val h = scaledLayerHeight if (isSizeChanged(w, h) || surface == null) { disposeCanvas() @@ -41,7 +41,7 @@ internal class AngleContextHandler(layer: SkiaLayer) : ContextBasedContextHandle SurfaceOrigin.BOTTOM_LEFT, SurfaceColorFormat.RGBA_8888, ColorSpace.sRGB, - SurfaceProps(pixelGeometry = layer.pixelGeometry) + SurfaceProps(pixelGeometry = pixelGeometry) ) ?: throw RenderException("Cannot create surface") } diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/ContextBasedContextHandler.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/ContextBasedContextHandler.kt index 0453d4f74..b02e75bbc 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/ContextBasedContextHandler.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/ContextBasedContextHandler.kt @@ -6,7 +6,7 @@ import org.jetbrains.skiko.SkiaLayer internal abstract class ContextBasedContextHandler(layer: SkiaLayer, val name: String) : JvmContextHandler(layer) { - abstract protected fun makeContext(): DirectContext + protected abstract fun makeContext(): DirectContext override fun initContext(): Boolean { try { diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/ContextFreeContextHandler.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/ContextFreeContextHandler.kt index 1fe411406..ae4eb7d0d 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/ContextFreeContextHandler.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/ContextFreeContextHandler.kt @@ -3,13 +3,13 @@ package org.jetbrains.skiko.context import org.jetbrains.skiko.SkiaLayer internal abstract class ContextFreeContextHandler(layer: SkiaLayer) : JvmContextHandler(layer) { - private var isInited = false + private var isInitialized = false override fun initContext(): Boolean { - if (!isInited) { - isInited = true + if (!isInitialized) { + isInitialized = true onContextInitialized() } - return isInited + return isInitialized } } \ No newline at end of file diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/Direct3DContextHandler.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/Direct3DContextHandler.kt index fa8c5fa06..82771efa9 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/Direct3DContextHandler.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/Direct3DContextHandler.kt @@ -4,7 +4,7 @@ import org.jetbrains.skia.DirectContext import org.jetbrains.skia.Surface import org.jetbrains.skia.SurfaceProps import org.jetbrains.skia.impl.getPtr -import org.jetbrains.skiko.Logger +import org.jetbrains.skiko.LayerDrawScope import org.jetbrains.skiko.SkiaLayer import org.jetbrains.skiko.redrawer.Direct3DRedrawer import java.lang.ref.Reference @@ -30,15 +30,14 @@ internal class Direct3DContextHandler(layer: SkiaLayer) : ContextBasedContextHan return false } - override fun initCanvas() { + override fun LayerDrawScope.initCanvas() { val context = context ?: return - val scale = layer.contentScale // Direct3D can't work with zero size. // Don't rewrite code to skipping, as we need the whole pipeline in zero case too // (drawing -> flushing -> swapping -> waiting for vsync) - val width = (layer.width * scale).toInt().coerceAtLeast(1) - val height = (layer.height * scale).toInt().coerceAtLeast(1) + val width = scaledLayerWidth.coerceAtLeast(1) + val height = scaledLayerHeight.coerceAtLeast(1) if (isSizeChanged(width, height) || isSurfacesNull()) { disposeCanvas() @@ -46,7 +45,7 @@ internal class Direct3DContextHandler(layer: SkiaLayer) : ContextBasedContextHan val justInitialized = directXRedrawer.changeSize(width, height) try { - val surfaceProps = SurfaceProps(pixelGeometry = layer.pixelGeometry) + val surfaceProps = SurfaceProps(pixelGeometry = pixelGeometry) for (bufferIndex in 0 until bufferCount) { surfaces[bufferIndex] = directXRedrawer.makeSurface( context = getPtr(context), @@ -68,7 +67,7 @@ internal class Direct3DContextHandler(layer: SkiaLayer) : ContextBasedContextHan canvas = surface!!.canvas } - override fun flush() { + override fun flush(scope: LayerDrawScope) { val context = context ?: return val surface = surface ?: return try { diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/DirectSoftwareContextHandler.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/DirectSoftwareContextHandler.kt index 6c4cfd88a..a30cb9ff2 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/DirectSoftwareContextHandler.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/DirectSoftwareContextHandler.kt @@ -1,6 +1,7 @@ package org.jetbrains.skiko.context import org.jetbrains.skia.impl.getPtr +import org.jetbrains.skiko.LayerDrawScope import org.jetbrains.skiko.SkiaLayer import org.jetbrains.skiko.redrawer.AbstractDirectSoftwareRedrawer import java.lang.ref.Reference @@ -20,10 +21,9 @@ internal class DirectSoftwareContextHandler(layer: SkiaLayer) : ContextFreeConte return false } - override fun initCanvas() { - val scale = layer.contentScale - val w = (layer.width * scale).toInt().coerceAtLeast(0) - val h = (layer.height * scale).toInt().coerceAtLeast(0) + override fun LayerDrawScope.initCanvas() { + val w = scaledLayerWidth + val h = scaledLayerHeight if (isSizeChanged(w, h) || surface == null) { disposeCanvas() if (w > 0 && h > 0) { @@ -37,7 +37,7 @@ internal class DirectSoftwareContextHandler(layer: SkiaLayer) : ContextFreeConte } } - override fun flush() { + override fun flush(scope: LayerDrawScope) { val surface = surface if (surface != null) { try { diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/MetalContextHandler.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/MetalContextHandler.kt index e4d19d628..8c46415e0 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/MetalContextHandler.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/MetalContextHandler.kt @@ -1,6 +1,7 @@ package org.jetbrains.skiko.context import org.jetbrains.skia.* +import org.jetbrains.skiko.LayerDrawScope import org.jetbrains.skiko.Logger import org.jetbrains.skiko.MetalAdapter import org.jetbrains.skiko.RenderException @@ -20,12 +21,11 @@ internal class MetalContextHandler( private val device: MetalDevice, private val adapter: MetalAdapter ) : ContextBasedContextHandler(layer, "Metal") { - override fun initCanvas() { + override fun LayerDrawScope.initCanvas() { disposeCanvas() - val scale = layer.contentScale - val width = (layer.backedLayer.width * scale).toInt().coerceAtLeast(0) - val height = (layer.backedLayer.height * scale).toInt().coerceAtLeast(0) + val width = scaledLayerWidth + val height = scaledLayerHeight if (width > 0 && height > 0) { renderTarget = makeRenderTarget(width, height) @@ -36,7 +36,7 @@ internal class MetalContextHandler( SurfaceOrigin.TOP_LEFT, SurfaceColorFormat.BGRA_8888, ColorSpace.sRGB, - SurfaceProps(pixelGeometry = layer.pixelGeometry) + SurfaceProps(pixelGeometry = pixelGeometry) ) ?: throw RenderException("Cannot create surface") canvas = surface!!.canvas @@ -47,8 +47,8 @@ internal class MetalContextHandler( } } - override fun flush() { - super.flush() + override fun flush(scope: LayerDrawScope) { + super.flush(scope) surface?.flushAndSubmit() finishFrame() Logger.debug { "MetalContextHandler finished drawing frame" } diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/OpenGLContextHandler.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/OpenGLContextHandler.kt index c57f959e3..86c95d9eb 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/OpenGLContextHandler.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/OpenGLContextHandler.kt @@ -18,10 +18,9 @@ internal class OpenGLContextHandler(layer: SkiaLayer) : ContextBasedContextHandl return false } - override fun initCanvas() { - val scale = layer.contentScale - val w = (layer.width * scale).toInt().coerceAtLeast(0) - val h = (layer.height * scale).toInt().coerceAtLeast(0) + override fun LayerDrawScope.initCanvas() { + val w = scaledLayerWidth + val h = scaledLayerHeight if (isSizeChanged(w, h) || surface == null) { disposeCanvas() @@ -41,7 +40,7 @@ internal class OpenGLContextHandler(layer: SkiaLayer) : ContextBasedContextHandl SurfaceOrigin.BOTTOM_LEFT, SurfaceColorFormat.RGBA_8888, ColorSpace.sRGB, - SurfaceProps(pixelGeometry = layer.pixelGeometry) + SurfaceProps(pixelGeometry = pixelGeometry) ) ?: throw RenderException("Cannot create surface") } diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/SoftwareContextHandler.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/SoftwareContextHandler.kt index f74c1c89d..21e271de0 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/SoftwareContextHandler.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/context/SoftwareContextHandler.kt @@ -1,6 +1,7 @@ package org.jetbrains.skiko.context import org.jetbrains.skia.* +import org.jetbrains.skiko.LayerDrawScope import org.jetbrains.skiko.OS import org.jetbrains.skiko.SkiaLayer import org.jetbrains.skiko.hostOs @@ -22,25 +23,22 @@ internal class SoftwareContextHandler(layer: SkiaLayer) : ContextFreeContextHand var imageData: ByteArray? = null var raster: WritableRaster? = null - override fun initCanvas() { + override fun LayerDrawScope.initCanvas() { disposeCanvas() - val scale = layer.contentScale - val w = (layer.width * scale).toInt().coerceAtLeast(0) - val h = (layer.height * scale).toInt().coerceAtLeast(0) + val w = scaledLayerWidth + val h = scaledLayerHeight if (storage.width != w || storage.height != h) { storage.allocPixelsFlags(ImageInfo.makeS32(w, h, ColorAlphaType.PREMUL), false) } - canvas = Canvas(storage, SurfaceProps(pixelGeometry = layer.pixelGeometry)) + canvas = Canvas(storage, SurfaceProps(pixelGeometry = pixelGeometry)) } - override fun flush() { - val scale = layer.contentScale - val w = (layer.width * scale).toInt().coerceAtLeast(0) - val h = (layer.height * scale).toInt().coerceAtLeast(0) - + override fun flush(scope: LayerDrawScope) { + val w = scope.scaledLayerWidth + val h = scope.scaledLayerHeight val bytes = storage.readPixels(storage.imageInfo, (w * 4), 0, 0) if (bytes != null) { diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/AWTRedrawer.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/AWTRedrawer.kt index a8a91fb09..dc4e2d36d 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/AWTRedrawer.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/AWTRedrawer.kt @@ -54,7 +54,7 @@ internal abstract class AWTRedrawer( layer.update(nanoTime) } - protected inline fun inDrawScope(body: () -> Unit) { + protected inline fun inDrawScope(body: LayerDrawScope.() -> Unit) { requireNotNull(deviceAnalytics) { "deviceAnalytics is not null. Call onDeviceChosen after choosing the drawing device" } if (!isDisposed) { val isFirstFrame = !isFirstFrameRendered diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/AbstractDirectSoftwareRedrawer.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/AbstractDirectSoftwareRedrawer.kt index 75767b770..c40ad5332 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/AbstractDirectSoftwareRedrawer.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/AbstractDirectSoftwareRedrawer.kt @@ -33,7 +33,7 @@ internal abstract class AbstractDirectSoftwareRedrawer( frameDispatcher.scheduleFrame() } - protected open fun draw() = inDrawScope(contextHandler::draw) + protected open fun draw() = inDrawScope { contextHandler.draw() } override fun renderImmediately() { update() diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/AngleRedrawer.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/AngleRedrawer.kt index 4dc8064ce..a96e84064 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/AngleRedrawer.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/AngleRedrawer.kt @@ -89,7 +89,9 @@ internal class AngleRedrawer( return } makeCurrent(device) - contextHandler.draw() + layer.inDrawScope { + contextHandler.draw() + } swapBuffers(device, withVsync) } diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/Direct3DRedrawer.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/Direct3DRedrawer.kt index 5024012e3..7de1f29cb 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/Direct3DRedrawer.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/Direct3DRedrawer.kt @@ -86,7 +86,7 @@ internal class Direct3DRedrawer( } } - private fun drawAndSwap(withVsync: Boolean) = synchronized(drawLock) { + private fun LayerDrawScope.drawAndSwap(withVsync: Boolean) = synchronized(drawLock) { if (isDisposed) { return } diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/LinuxOpenGLRedrawer.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/LinuxOpenGLRedrawer.kt index 895cc7163..b05cecea3 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/LinuxOpenGLRedrawer.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/LinuxOpenGLRedrawer.kt @@ -97,7 +97,7 @@ internal class LinuxOpenGLRedrawer( } private fun draw() { - inDrawScope(contextHandler::draw) + inDrawScope { contextHandler.draw() } } companion object { diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/MetalRedrawer.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/MetalRedrawer.kt index 918007126..c09c08f61 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/MetalRedrawer.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/MetalRedrawer.kt @@ -144,7 +144,7 @@ internal class MetalRedrawer( windowOcclusionStateChannel.trySend(isOccluded) } - private fun performDraw() = synchronized(drawLock) { + private fun LayerDrawScope.performDraw() = synchronized(drawLock) { if (!isDisposed) { autoreleasepool { contextHandler.draw() diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/SoftwareRedrawer.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/SoftwareRedrawer.kt index 38c1815a7..d54ef6bee 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/SoftwareRedrawer.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/SoftwareRedrawer.kt @@ -27,7 +27,7 @@ internal class SoftwareRedrawer( if (layer.isShowing) { update() - inDrawScope(contextHandler::draw) + inDrawScope { contextHandler.draw() } } } diff --git a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/WindowsOpenGLRedrawer.kt b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/WindowsOpenGLRedrawer.kt index 063dc3d2f..dbc2a7bce 100644 --- a/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/WindowsOpenGLRedrawer.kt +++ b/skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/WindowsOpenGLRedrawer.kt @@ -78,7 +78,7 @@ internal class WindowsOpenGLRedrawer( } private fun draw() { - inDrawScope(contextHandler::draw) + inDrawScope { contextHandler.draw() } } private fun makeCurrent() = makeCurrent(device, context) diff --git a/skiko/src/awtTest/kotlin/org/jetbrains/skiko/SkiaLayerTest.kt b/skiko/src/awtTest/kotlin/org/jetbrains/skiko/SkiaLayerTest.kt index 9500e28a2..2cf6fb66d 100644 --- a/skiko/src/awtTest/kotlin/org/jetbrains/skiko/SkiaLayerTest.kt +++ b/skiko/src/awtTest/kotlin/org/jetbrains/skiko/SkiaLayerTest.kt @@ -578,9 +578,9 @@ class SkiaLayerTest { object : BaseTestRedrawer(layer) { private val contextHandler = object : JvmContextHandler(layer) { override fun initContext() = false - override fun initCanvas() = Unit + override fun LayerDrawScope.initCanvas() = Unit } - override fun renderImmediately() = layer.inDrawScope(contextHandler::draw) + override fun renderImmediately() = layer.inDrawScope { contextHandler.draw() } } } } diff --git a/skiko/src/commonMain/kotlin/org/jetbrains/skiko/SkiaLayer.kt b/skiko/src/commonMain/kotlin/org/jetbrains/skiko/SkiaLayer.kt index 272faf22c..4008c9e8c 100644 --- a/skiko/src/commonMain/kotlin/org/jetbrains/skiko/SkiaLayer.kt +++ b/skiko/src/commonMain/kotlin/org/jetbrains/skiko/SkiaLayer.kt @@ -3,6 +3,7 @@ package org.jetbrains.skiko import org.jetbrains.skia.Canvas import org.jetbrains.skia.Picture import org.jetbrains.skia.PixelGeometry +import org.jetbrains.skiko.context.ContextHandler /** * Generic layer for Skiko rendering. @@ -70,6 +71,35 @@ expect open class SkiaLayer { internal fun draw(canvas: Canvas) } - internal class PictureHolder(val instance: Picture, val width: Int, val height: Int) +internal class LayerDrawScope( + val pixelGeometry: PixelGeometry, + val scaledLayerWidth: Int, + val scaledLayerHeight: Int, +) { + constructor( + pixelGeometry: PixelGeometry, + layerWidth: Int, + layerHeight: Int, + scale: Float + ): this( + pixelGeometry = pixelGeometry, + scaledLayerWidth = (layerWidth * scale).toInt().coerceAtLeast(0), + scaledLayerHeight = (layerHeight * scale).toInt().coerceAtLeast(0) + ) + constructor( + pixelGeometry: PixelGeometry, + layerWidth: Double, + layerHeight: Double, + scale: Float + ): this( + pixelGeometry = pixelGeometry, + scaledLayerWidth = (layerWidth * scale).toInt().coerceAtLeast(0), + scaledLayerHeight = (layerHeight * scale).toInt().coerceAtLeast(0) + ) + + internal fun ContextHandler.draw() { + this@LayerDrawScope.draw() + } +} \ No newline at end of file diff --git a/skiko/src/commonMain/kotlin/org/jetbrains/skiko/context/ContextHandler.kt b/skiko/src/commonMain/kotlin/org/jetbrains/skiko/context/ContextHandler.kt index 79c87453d..43d20c155 100644 --- a/skiko/src/commonMain/kotlin/org/jetbrains/skiko/context/ContextHandler.kt +++ b/skiko/src/commonMain/kotlin/org/jetbrains/skiko/context/ContextHandler.kt @@ -13,9 +13,9 @@ internal abstract class ContextHandler( protected var canvas: Canvas? = null protected abstract fun initContext(): Boolean - protected abstract fun initCanvas() + protected abstract fun LayerDrawScope.initCanvas() - protected open fun flush() { + protected open fun flush(scope: LayerDrawScope) { context?.flush() } @@ -35,7 +35,7 @@ internal abstract class ContextHandler( } // throws RenderException if initialization of graphic context was not successful - fun draw() { + fun LayerDrawScope.draw() { if (!initContext()) { throw RenderException("Cannot init graphic context") } @@ -44,6 +44,7 @@ internal abstract class ContextHandler( clear(Color.TRANSPARENT) drawContent() } - flush() + flush(this) } -} \ No newline at end of file +} + diff --git a/skiko/src/macosMain/kotlin/org/jetbrains/skiko/SkiaLayer.macos.kt b/skiko/src/macosMain/kotlin/org/jetbrains/skiko/SkiaLayer.macos.kt index 498b81236..09d47d784 100644 --- a/skiko/src/macosMain/kotlin/org/jetbrains/skiko/SkiaLayer.macos.kt +++ b/skiko/src/macosMain/kotlin/org/jetbrains/skiko/SkiaLayer.macos.kt @@ -168,4 +168,17 @@ actual open class SkiaLayer { actual val pixelGeometry: PixelGeometry get() = PixelGeometry.UNKNOWN + + private fun createDrawScope() = LayerDrawScope( + pixelGeometry = pixelGeometry, + layerWidth = nsView.frame.useContents { size.width }, + layerHeight = nsView.frame.useContents { size.height }, + scale = contentScale + ) + + internal fun inDrawScope(block: LayerDrawScope.() -> Unit) { + with(createDrawScope()) { + block() + } + } } diff --git a/skiko/src/macosMain/kotlin/org/jetbrains/skiko/context/MetalContextHandler.macos.kt b/skiko/src/macosMain/kotlin/org/jetbrains/skiko/context/MetalContextHandler.macos.kt index e4c37e960..4a54d11f9 100644 --- a/skiko/src/macosMain/kotlin/org/jetbrains/skiko/context/MetalContextHandler.macos.kt +++ b/skiko/src/macosMain/kotlin/org/jetbrains/skiko/context/MetalContextHandler.macos.kt @@ -1,13 +1,13 @@ package org.jetbrains.skiko.context -import kotlinx.cinterop.useContents import org.jetbrains.skia.* +import org.jetbrains.skiko.LayerDrawScope import org.jetbrains.skiko.RenderException import org.jetbrains.skiko.SkiaLayer import org.jetbrains.skiko.redrawer.MacOsMetalRedrawer /** - * Metal ContextHandler implementation for MacOs. + * Metal ContextHandler implementation for macOS. */ internal class MacOsMetalContextHandler(layer: SkiaLayer) : ContextHandler(layer, layer::draw) { private val metalRedrawer: MacOsMetalRedrawer @@ -25,12 +25,11 @@ internal class MacOsMetalContextHandler(layer: SkiaLayer) : ContextHandler(layer return true } - override fun initCanvas() { + override fun LayerDrawScope.initCanvas() { disposeCanvas() - val scale = layer.contentScale - val w = (layer.nsView.frame.useContents { size.width } * scale).toInt().coerceAtLeast(0) - val h = (layer.nsView.frame.useContents { size.height } * scale).toInt().coerceAtLeast(0) + val w = scaledLayerWidth + val h = scaledLayerHeight if (w > 0 && h > 0) { renderTarget = metalRedrawer.makeRenderTarget(w, h) @@ -52,9 +51,9 @@ internal class MacOsMetalContextHandler(layer: SkiaLayer) : ContextHandler(layer } } - override fun flush() { + override fun flush(scope: LayerDrawScope) { // TODO: maybe make flush async as in JVM version. - super.flush() + super.flush(scope) surface?.flushAndSubmit() metalRedrawer.finishFrame() } diff --git a/skiko/src/macosMain/kotlin/org/jetbrains/skiko/context/OpenGLContextHandler.macos.kt b/skiko/src/macosMain/kotlin/org/jetbrains/skiko/context/OpenGLContextHandler.macos.kt index bcf02f13f..c37527701 100644 --- a/skiko/src/macosMain/kotlin/org/jetbrains/skiko/context/OpenGLContextHandler.macos.kt +++ b/skiko/src/macosMain/kotlin/org/jetbrains/skiko/context/OpenGLContextHandler.macos.kt @@ -3,6 +3,7 @@ package org.jetbrains.skiko.context import kotlinx.cinterop.* import org.jetbrains.skia.* import org.jetbrains.skiko.GraphicsApi +import org.jetbrains.skiko.LayerDrawScope import org.jetbrains.skiko.RenderException import org.jetbrains.skiko.SkiaLayer import platform.OpenGL.GL_DRAW_FRAMEBUFFER_BINDING @@ -10,7 +11,8 @@ import platform.OpenGL.glGetIntegerv import platform.OpenGLCommon.GLenum /** - * OpenGL context handler for MacOs (native). + * OpenGL context handler for macOS (native). + * * Not used anymore, unless corresponding [GraphicsApi] is hardcoded in [SkiaLayer]. * See [MacOsMetalContextHandler] instead. */ @@ -20,7 +22,7 @@ internal class MacOSOpenGLContextHandler(layer: SkiaLayer) : ContextHandler(laye if (context == null) { context = DirectContext.makeGL() } - } catch (e: Exception) { + } catch (_: Exception) { println("Failed to create Skia OpenGL context!") return false } @@ -29,11 +31,11 @@ internal class MacOSOpenGLContextHandler(layer: SkiaLayer) : ContextHandler(laye @ExperimentalUnsignedTypes private fun openglGetIntegerv(pname: GLenum): UInt { - var result: UInt = 0U + var result = 0U memScoped { val data = alloc() - glGetIntegerv(pname, data.ptr); - result = data.value.toUInt(); + glGetIntegerv(pname, data.ptr) + result = data.value.toUInt() } return result } @@ -49,10 +51,9 @@ internal class MacOSOpenGLContextHandler(layer: SkiaLayer) : ContextHandler(laye return false } - override fun initCanvas() { - val scale = layer.contentScale - val w = (layer.nsView.frame.useContents { size.width } * scale).toInt().coerceAtLeast(0) - val h = (layer.nsView.frame.useContents { size.height } * scale).toInt().coerceAtLeast(0) + override fun LayerDrawScope.initCanvas() { + val w = scaledLayerWidth + val h = scaledLayerHeight if (isSizeChanged(w, h)) { val fbId = openglGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING.toUInt()) renderTarget = BackendRenderTarget.makeGL( diff --git a/skiko/src/macosMain/kotlin/org/jetbrains/skiko/redrawer/MetalRedrawer.macos.kt b/skiko/src/macosMain/kotlin/org/jetbrains/skiko/redrawer/MetalRedrawer.macos.kt index 4d682aea7..2bfbe7110 100644 --- a/skiko/src/macosMain/kotlin/org/jetbrains/skiko/redrawer/MetalRedrawer.macos.kt +++ b/skiko/src/macosMain/kotlin/org/jetbrains/skiko/redrawer/MetalRedrawer.macos.kt @@ -157,7 +157,9 @@ internal class MacOsMetalRedrawer( update() } if (!isDisposed) { // Redrawer may be disposed in user code, during `update` - contextHandler.draw() + skiaLayer.inDrawScope { + contextHandler.draw() + } } } } @@ -166,7 +168,9 @@ internal class MacOsMetalRedrawer( autoreleasepool { if (!isDisposed) { update() - contextHandler.draw() + skiaLayer.inDrawScope { + contextHandler.draw() + } } } @@ -233,6 +237,8 @@ internal class MetalLayer : CAMetalLayer { override fun drawInContext(ctx: CGContextRef?) { skiaLayer.update(currentNanoTime()) - contextHandler.draw() + skiaLayer.inDrawScope { + contextHandler.draw() + } } } diff --git a/skiko/src/macosMain/kotlin/org/jetbrains/skiko/redrawer/OpenGLRedrawer.macos.kt b/skiko/src/macosMain/kotlin/org/jetbrains/skiko/redrawer/OpenGLRedrawer.macos.kt index 44f8d09fb..477264e8a 100644 --- a/skiko/src/macosMain/kotlin/org/jetbrains/skiko/redrawer/OpenGLRedrawer.macos.kt +++ b/skiko/src/macosMain/kotlin/org/jetbrains/skiko/redrawer/OpenGLRedrawer.macos.kt @@ -133,7 +133,9 @@ internal class MacosGLLayer : CAOpenGLLayer { CGLSetCurrentContext(ctx) try { skiaLayer.update(currentNanoTime()) - contextHandler.draw() + skiaLayer.inDrawScope { + contextHandler.draw() + } } catch (e: Throwable) { e.printStackTrace() throw e