Skip to content

Commit

Permalink
UIKit interop (#668)
Browse files Browse the repository at this point in the history
  • Loading branch information
dima-avdeev-jb authored Mar 6, 2023
1 parent 9de5457 commit befd7f0
Showing 1 changed file with 33 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
package org.jetbrains.skiko.redrawer

import kotlinx.cinterop.addressOf
import kotlinx.cinterop.autoreleasepool
import kotlinx.cinterop.objcPtr
import kotlinx.cinterop.usePinned
import kotlinx.cinterop.useContents
import kotlinx.cinterop.*
import org.jetbrains.skia.BackendRenderTarget
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.MetalContextHandler
import platform.CoreGraphics.CGColorCreate
import platform.CoreGraphics.CGColorSpaceCreateDeviceRGB
import platform.CoreGraphics.CGContextRef
import platform.CoreGraphics.CGSizeMake
import platform.Foundation.NSRunLoop
import platform.Foundation.NSSelectorFromString
import platform.Metal.MTLCreateSystemDefaultDevice
import platform.Metal.MTLDeviceProtocol
import platform.Metal.MTLPixelFormatBGRA8Unorm
import platform.QuartzCore.CADisplayLink
import platform.QuartzCore.CAMetalDrawableProtocol
import platform.QuartzCore.CAMetalLayer
import platform.QuartzCore.kCAGravityTopLeft
import kotlin.system.getTimeNanos
import platform.CoreGraphics.CGSizeMake
import platform.darwin.NSObject

internal class MetalRedrawer(
private val layer: SkiaLayer
Expand All @@ -33,16 +32,22 @@ internal class MetalRedrawer(
private val queue = device.newCommandQueue()!!
private var currentDrawable: CAMetalDrawableProtocol? = null
private val metalLayer = MetalLayer()

init {
metalLayer.init(this.layer, contextHandler, device)
}

private val frameDispatcher = FrameDispatcher(SkikoDispatchers.Main) {
private val frameListener: NSObject = FrameTickListener {
caDisplayLink.setPaused(true)
if (layer.isShowing()) {
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())

Expand All @@ -53,7 +58,7 @@ internal class MetalRedrawer(

override fun dispose() {
if (!isDisposed) {
frameDispatcher.cancel()
caDisplayLink.invalidate()
contextHandler.dispose()
metalLayer.dispose()
isDisposed = true
Expand All @@ -73,7 +78,7 @@ internal class MetalRedrawer(

override fun needRedraw() {
check(!isDisposed) { "MetalRedrawer is disposed" }
frameDispatcher.scheduleFrame()
caDisplayLink.setPaused(false)
}

override fun redrawImmediately() {
Expand All @@ -83,7 +88,7 @@ internal class MetalRedrawer(

private fun draw() {
// TODO: maybe make flush async as in JVM version.
autoreleasepool {
autoreleasepool { //todo measure performance without autoreleasepool
if (!isDisposed) {
contextHandler.draw()
}
Expand All @@ -108,9 +113,10 @@ internal class MetalLayer : CAMetalLayer {
private lateinit var contextHandler: ContextHandler

@OverrideInit
constructor(): super()
constructor() : super()

@OverrideInit
constructor(layer: Any): super(layer)
constructor(layer: Any) : super(layer)

fun init(
skiaLayer: SkiaLayer,
Expand All @@ -129,7 +135,7 @@ internal class MetalLayer : CAMetalLayer {
this.backgroundColor =
CGColorCreate(CGColorSpaceCreateDeviceRGB(), it.addressOf(0))
}
this.opaque = true
this.opaque = false // For UIKit interop through a "Hole"
skiaLayer.view?.let {
this.frame = it.frame
it.layer.addSublayer(this)
Expand All @@ -146,3 +152,10 @@ internal class MetalLayer : CAMetalLayer {
super.drawInContext(ctx)
}
}

private class FrameTickListener(val onFrameTick: () -> Unit) : NSObject() {
@ObjCAction
fun onDisplayLinkTick() {
onFrameTick()
}
}

0 comments on commit befd7f0

Please sign in to comment.