Unverified Commit 0c89dfa7 authored by Elijah Semyonov's avatar Elijah Semyonov Committed by GitHub

Add overcommitment prevention mechanism (iOS) (#755)

parent dda594ad
...@@ -17,7 +17,7 @@ import platform.Metal.MTLDeviceProtocol ...@@ -17,7 +17,7 @@ import platform.Metal.MTLDeviceProtocol
import platform.Metal.MTLPixelFormatBGRA8Unorm import platform.Metal.MTLPixelFormatBGRA8Unorm
import platform.QuartzCore.* import platform.QuartzCore.*
import platform.UIKit.window import platform.UIKit.window
import platform.darwin.NSObject import platform.darwin.*
private enum class DrawSchedulingState { private enum class DrawSchedulingState {
AVAILABLE_ON_NEXT_FRAME, AVAILABLE_ON_NEXT_FRAME,
...@@ -37,6 +37,9 @@ internal class MetalRedrawer( ...@@ -37,6 +37,9 @@ internal class MetalRedrawer(
private var currentDrawable: CAMetalDrawableProtocol? = null private var currentDrawable: CAMetalDrawableProtocol? = null
private val metalLayer = MetalLayer() private val metalLayer = MetalLayer()
// Semaphore for preventing command buffers count more than swapchain size to be scheduled/executed at the same time
private val inflightSemaphore = dispatch_semaphore_create(metalLayer.maximumDrawableCount.toLong())
/* /*
* Initial value is [DrawSchedulingState.AVAILABLE_ON_NEXT_FRAME] because voluntarily dispatching a frame * Initial value is [DrawSchedulingState.AVAILABLE_ON_NEXT_FRAME] because voluntarily dispatching a frame
* disregarding CADisplayLink timing (which is not accessible while it's paused) can cause frame drifting in worst * disregarding CADisplayLink timing (which is not accessible while it's paused) can cause frame drifting in worst
...@@ -105,6 +108,9 @@ internal class MetalRedrawer( ...@@ -105,6 +108,9 @@ internal class MetalRedrawer(
fun makeContext() = DirectContext.makeMetal(device.objcPtr(), queue.objcPtr()) fun makeContext() = DirectContext.makeMetal(device.objcPtr(), queue.objcPtr())
fun makeRenderTarget(width: Int, height: Int): BackendRenderTarget { fun makeRenderTarget(width: Int, height: Int): BackendRenderTarget {
// If more than swapchain size count of command buffers are inflight
// wait until one finishes work
dispatch_semaphore_wait(inflightSemaphore, DISPATCH_TIME_FOREVER)
currentDrawable = metalLayer.nextDrawable()!! currentDrawable = metalLayer.nextDrawable()!!
return BackendRenderTarget.makeMetal(width, height, currentDrawable!!.texture.objcPtr()) return BackendRenderTarget.makeMetal(width, height, currentDrawable!!.texture.objcPtr())
} }
...@@ -190,6 +196,10 @@ internal class MetalRedrawer( ...@@ -190,6 +196,10 @@ internal class MetalRedrawer(
val commandBuffer = queue.commandBuffer()!! val commandBuffer = queue.commandBuffer()!!
commandBuffer.label = "Present" commandBuffer.label = "Present"
commandBuffer.presentDrawable(it) commandBuffer.presentDrawable(it)
commandBuffer.addCompletedHandler {
// Signal work finish, allow a new command buffer to be scheduled
dispatch_semaphore_signal(inflightSemaphore)
}
commandBuffer.commit() commandBuffer.commit()
currentDrawable = null currentDrawable = null
} }
......
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