Unverified Commit befd7f0b authored by dima.avdeev's avatar dima.avdeev Committed by GitHub

UIKit interop (#668)

parent 9de54574
package org.jetbrains.skiko.redrawer package org.jetbrains.skiko.redrawer
import kotlinx.cinterop.addressOf import kotlinx.cinterop.*
import kotlinx.cinterop.autoreleasepool
import kotlinx.cinterop.objcPtr
import kotlinx.cinterop.usePinned
import kotlinx.cinterop.useContents
import org.jetbrains.skia.BackendRenderTarget import org.jetbrains.skia.BackendRenderTarget
import org.jetbrains.skia.DirectContext import org.jetbrains.skia.DirectContext
import org.jetbrains.skiko.* import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.context.ContextHandler import org.jetbrains.skiko.context.ContextHandler
import org.jetbrains.skiko.context.MetalContextHandler import org.jetbrains.skiko.context.MetalContextHandler
import platform.CoreGraphics.CGColorCreate import platform.CoreGraphics.CGColorCreate
import platform.CoreGraphics.CGColorSpaceCreateDeviceRGB import platform.CoreGraphics.CGColorSpaceCreateDeviceRGB
import platform.CoreGraphics.CGContextRef import platform.CoreGraphics.CGContextRef
import platform.CoreGraphics.CGSizeMake
import platform.Foundation.NSRunLoop
import platform.Foundation.NSSelectorFromString
import platform.Metal.MTLCreateSystemDefaultDevice import platform.Metal.MTLCreateSystemDefaultDevice
import platform.Metal.MTLDeviceProtocol import platform.Metal.MTLDeviceProtocol
import platform.Metal.MTLPixelFormatBGRA8Unorm import platform.Metal.MTLPixelFormatBGRA8Unorm
import platform.QuartzCore.CADisplayLink
import platform.QuartzCore.CAMetalDrawableProtocol import platform.QuartzCore.CAMetalDrawableProtocol
import platform.QuartzCore.CAMetalLayer import platform.QuartzCore.CAMetalLayer
import platform.QuartzCore.kCAGravityTopLeft import platform.QuartzCore.kCAGravityTopLeft
import kotlin.system.getTimeNanos import platform.darwin.NSObject
import platform.CoreGraphics.CGSizeMake
internal class MetalRedrawer( internal class MetalRedrawer(
private val layer: SkiaLayer private val layer: SkiaLayer
...@@ -33,16 +32,22 @@ internal class MetalRedrawer( ...@@ -33,16 +32,22 @@ internal class MetalRedrawer(
private val queue = device.newCommandQueue()!! private val queue = device.newCommandQueue()!!
private var currentDrawable: CAMetalDrawableProtocol? = null private var currentDrawable: CAMetalDrawableProtocol? = null
private val metalLayer = MetalLayer() private val metalLayer = MetalLayer()
private val frameListener: NSObject = FrameTickListener {
init { caDisplayLink.setPaused(true)
metalLayer.init(this.layer, contextHandler, device)
}
private val frameDispatcher = FrameDispatcher(SkikoDispatchers.Main) {
if (layer.isShowing()) { if (layer.isShowing()) {
draw() draw()
} }
} }
private val caDisplayLink = CADisplayLink.displayLinkWithTarget(
target = frameListener,
selector = NSSelectorFromString(FrameTickListener::onDisplayLinkTick.name)
)
init {
metalLayer.init(this.layer, contextHandler, device)
caDisplayLink.setPaused(true)
caDisplayLink.addToRunLoop(NSRunLoop.mainRunLoop, NSRunLoop.mainRunLoop.currentMode)
}
fun makeContext() = DirectContext.makeMetal(device.objcPtr(), queue.objcPtr()) fun makeContext() = DirectContext.makeMetal(device.objcPtr(), queue.objcPtr())
...@@ -53,7 +58,7 @@ internal class MetalRedrawer( ...@@ -53,7 +58,7 @@ internal class MetalRedrawer(
override fun dispose() { override fun dispose() {
if (!isDisposed) { if (!isDisposed) {
frameDispatcher.cancel() caDisplayLink.invalidate()
contextHandler.dispose() contextHandler.dispose()
metalLayer.dispose() metalLayer.dispose()
isDisposed = true isDisposed = true
...@@ -73,7 +78,7 @@ internal class MetalRedrawer( ...@@ -73,7 +78,7 @@ internal class MetalRedrawer(
override fun needRedraw() { override fun needRedraw() {
check(!isDisposed) { "MetalRedrawer is disposed" } check(!isDisposed) { "MetalRedrawer is disposed" }
frameDispatcher.scheduleFrame() caDisplayLink.setPaused(false)
} }
override fun redrawImmediately() { override fun redrawImmediately() {
...@@ -83,7 +88,7 @@ internal class MetalRedrawer( ...@@ -83,7 +88,7 @@ internal class MetalRedrawer(
private fun draw() { private fun draw() {
// TODO: maybe make flush async as in JVM version. // TODO: maybe make flush async as in JVM version.
autoreleasepool { autoreleasepool { //todo measure performance without autoreleasepool
if (!isDisposed) { if (!isDisposed) {
contextHandler.draw() contextHandler.draw()
} }
...@@ -108,9 +113,10 @@ internal class MetalLayer : CAMetalLayer { ...@@ -108,9 +113,10 @@ internal class MetalLayer : CAMetalLayer {
private lateinit var contextHandler: ContextHandler private lateinit var contextHandler: ContextHandler
@OverrideInit @OverrideInit
constructor(): super() constructor() : super()
@OverrideInit @OverrideInit
constructor(layer: Any): super(layer) constructor(layer: Any) : super(layer)
fun init( fun init(
skiaLayer: SkiaLayer, skiaLayer: SkiaLayer,
...@@ -129,7 +135,7 @@ internal class MetalLayer : CAMetalLayer { ...@@ -129,7 +135,7 @@ internal class MetalLayer : CAMetalLayer {
this.backgroundColor = this.backgroundColor =
CGColorCreate(CGColorSpaceCreateDeviceRGB(), it.addressOf(0)) CGColorCreate(CGColorSpaceCreateDeviceRGB(), it.addressOf(0))
} }
this.opaque = true this.opaque = false // For UIKit interop through a "Hole"
skiaLayer.view?.let { skiaLayer.view?.let {
this.frame = it.frame this.frame = it.frame
it.layer.addSublayer(this) it.layer.addSublayer(this)
...@@ -146,3 +152,10 @@ internal class MetalLayer : CAMetalLayer { ...@@ -146,3 +152,10 @@ internal class MetalLayer : CAMetalLayer {
super.drawInContext(ctx) super.drawInContext(ctx)
} }
} }
private class FrameTickListener(val onFrameTick: () -> Unit) : NSObject() {
@ObjCAction
fun onDisplayLinkTick() {
onFrameTick()
}
}
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