Unverified Commit a662a791 authored by Elijah Semyonov's avatar Elijah Semyonov Committed by GitHub

Remove synchronous draw reentry logic inside needRedraw completely (#773)

parent 68677fd5
...@@ -259,8 +259,6 @@ class SkikoUIView : UIView, UIKeyInputProtocol, UITextInputProtocol { ...@@ -259,8 +259,6 @@ class SkikoUIView : UIView, UIKeyInputProtocol, UITextInputProtocol {
platform = event platform = event
) )
) )
// If invalidation doesn't happen while onPointerEvent is processed, it's too late to schedule any work for this frame.
skiaLayer?.redrawer?.preventDrawDispatchDuringCurrentFrame()
} }
private val UITouch.isPressed get() = private val UITouch.isPressed get() =
......
...@@ -16,15 +16,8 @@ import platform.Metal.MTLCreateSystemDefaultDevice ...@@ -16,15 +16,8 @@ import platform.Metal.MTLCreateSystemDefaultDevice
import platform.Metal.MTLDeviceProtocol import platform.Metal.MTLDeviceProtocol
import platform.Metal.MTLPixelFormatBGRA8Unorm import platform.Metal.MTLPixelFormatBGRA8Unorm
import platform.QuartzCore.* import platform.QuartzCore.*
import platform.UIKit.window
import platform.darwin.* import platform.darwin.*
private enum class DrawSchedulingState {
AVAILABLE_ON_NEXT_FRAME,
AVAILABLE_ON_CURRENT_FRAME,
SCHEDULED_ON_NEXT_FRAME
}
internal class MetalRedrawer( internal class MetalRedrawer(
private val layer: SkiaLayer private val layer: SkiaLayer
) : Redrawer { ) : Redrawer {
...@@ -41,24 +34,9 @@ internal class MetalRedrawer( ...@@ -41,24 +34,9 @@ internal class MetalRedrawer(
private val inflightSemaphore = dispatch_semaphore_create(metalLayer.maximumDrawableCount.toLong()) private val inflightSemaphore = dispatch_semaphore_create(metalLayer.maximumDrawableCount.toLong())
/* /*
* Initial value is [DrawSchedulingState.AVAILABLE_ON_NEXT_FRAME] because voluntarily dispatching a frame * Indicates that scene is invalidated and next display link callback will draw
* disregarding CADisplayLink timing (which is not accessible while it's paused) can cause frame drifting in worst
* cases adding one frame latency due to presentation mechanism, if followed by steady draw dispatch
* (which is often the case).
* TODO: look closer to what happens after blank frames leave it in AVAILABLE_ON_CURRENT_FRAME. Touch driven events sequence negate that problem.
*/ */
private var drawSchedulingState = DrawSchedulingState.AVAILABLE_ON_NEXT_FRAME private var hasScheduledDrawOnNextVSync = false
/**
* UITouch events are dispatched right before next CADisplayLink callback by iOS.
* It's too late to encode any work for this frame after this happens.
* Any work dispatched before the next CADisplayLink callback should be scheduled after that callback.
*/
fun preventDrawDispatchDuringCurrentFrame() {
if (drawSchedulingState == DrawSchedulingState.AVAILABLE_ON_CURRENT_FRAME) {
drawSchedulingState = DrawSchedulingState.AVAILABLE_ON_NEXT_FRAME
}
}
/** /**
* Needs scheduling displayLink for forcing UITouch events to come at the fastest possible cadence. * Needs scheduling displayLink for forcing UITouch events to come at the fastest possible cadence.
...@@ -74,22 +52,12 @@ internal class MetalRedrawer( ...@@ -74,22 +52,12 @@ internal class MetalRedrawer(
} }
private val frameListener: NSObject = FrameTickListener { private val frameListener: NSObject = FrameTickListener {
when (drawSchedulingState) { if (hasScheduledDrawOnNextVSync) {
DrawSchedulingState.AVAILABLE_ON_NEXT_FRAME -> { hasScheduledDrawOnNextVSync = false
drawSchedulingState = DrawSchedulingState.AVAILABLE_ON_CURRENT_FRAME
}
DrawSchedulingState.SCHEDULED_ON_NEXT_FRAME -> {
drawSchedulingState = DrawSchedulingState.AVAILABLE_ON_NEXT_FRAME
drawIfLayerIsShowing() drawIfLayerIsShowing()
} }
DrawSchedulingState.AVAILABLE_ON_CURRENT_FRAME -> {
// still available, do nothing
}
}
if (!needsProactiveDisplayLink) { if (!needsProactiveDisplayLink) {
caDisplayLink.setPaused(true) caDisplayLink.setPaused(true)
} }
...@@ -142,37 +110,15 @@ internal class MetalRedrawer( ...@@ -142,37 +110,15 @@ internal class MetalRedrawer(
override fun needRedraw() { override fun needRedraw() {
check(!isDisposed) { "MetalRedrawer is disposed" } check(!isDisposed) { "MetalRedrawer is disposed" }
drawImmediatelyIfPossible() hasScheduledDrawOnNextVSync = true
if (drawSchedulingState == DrawSchedulingState.SCHEDULED_ON_NEXT_FRAME) { // If caDisplayLink is proactive (touches tracking), this does nothing (already unpaused)
caDisplayLink.setPaused(false) caDisplayLink.setPaused(false)
} }
}
override fun redrawImmediately() { override fun redrawImmediately() {
check(!isDisposed) { "MetalRedrawer is disposed" } // TODO: separate iOS MetalRedrawer from Redrawer, it's a false abstraction, iOS only uses MetalRedrawer explicitly
draw() throw UnsupportedOperationException("This should never be called on iOS")
}
/*
* Dispatch redraw immediately during current frame if possible and updates [drawSchedulingState] to relevant value
*/
private fun drawImmediatelyIfPossible() {
when (drawSchedulingState) {
DrawSchedulingState.AVAILABLE_ON_NEXT_FRAME -> {
drawSchedulingState = DrawSchedulingState.SCHEDULED_ON_NEXT_FRAME
}
DrawSchedulingState.AVAILABLE_ON_CURRENT_FRAME -> {
drawSchedulingState = DrawSchedulingState.AVAILABLE_ON_NEXT_FRAME
drawIfLayerIsShowing()
}
DrawSchedulingState.SCHEDULED_ON_NEXT_FRAME -> {
// already scheduled, do nothing
}
}
} }
private fun drawIfLayerIsShowing() { private fun drawIfLayerIsShowing() {
......
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