Skip to content

Commit 756016d

Browse files
authored
Merge pull request #7 from silenium-dev/fix/black-frames-on-resize
fix: black frames on resize
2 parents c98c138 + 9a08494 commit 756016d

File tree

7 files changed

+65
-41
lines changed

7 files changed

+65
-41
lines changed

src/main/java/dev/silenium/compose/gl/fbo/FBOFifo.kt renamed to src/main/java/dev/silenium/compose/gl/fbo/FBOFifoSwapChain.kt

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import java.util.concurrent.ArrayBlockingQueue
55
import java.util.concurrent.locks.ReentrantLock
66
import kotlin.concurrent.withLock
77

8-
class FBOFifo(capacity: Int, private val fboCreator: (IntSize) -> FBOPool.FBO) : IFBOPresentMode {
8+
class FBOFifoSwapChain(capacity: Int, override val fboCreator: (IntSize) -> FBOPool.FBO) : FBOSwapChain() {
9+
override var size: IntSize = IntSize.Zero
10+
private set
911
private val displayLock = ReentrantLock()
1012
private var toDisplay: FBOPool.FBO? = null
1113
private val renderQueue = ArrayBlockingQueue<FBOPool.FBO>(capacity)
@@ -14,21 +16,30 @@ class FBOFifo(capacity: Int, private val fboCreator: (IntSize) -> FBOPool.FBO) :
1416
override fun display(block: (FBOPool.FBO) -> Unit) = displayLock.withLock {
1517
toDisplay?.let(block)
1618
if (!displayQueue.isEmpty()) {
17-
toDisplay?.let(renderQueue::offer)
19+
toDisplay?.let{
20+
if (it.size != size) it.destroy()
21+
else renderQueue.offer(it)
22+
}
1823
toDisplay = displayQueue.poll()
1924
}
2025
}
2126

2227
override suspend fun <R> render(block: suspend (FBOPool.FBO) -> R): R? {
2328
val fbo = renderQueue.poll() ?: return null
2429
val result = block(fbo)
30+
if (fbo.size != size) {
31+
fbo.destroy()
32+
return null
33+
}
2534
displayQueue.offer(fbo)
2635
return result
2736
}
2837

2938
override fun resize(size: IntSize) {
30-
destroyFBOs()
31-
fillRenderQueue { fboCreator(size) }
39+
this.size = size
40+
renderQueue.onEach { it.destroy() }.clear()
41+
displayQueue.onEach { it.destroy() }.clear()
42+
renderQueue.fillRenderQueue(fboCreator, size)
3243
}
3344

3445
override fun destroyFBOs() {
@@ -39,10 +50,4 @@ class FBOFifo(capacity: Int, private val fboCreator: (IntSize) -> FBOPool.FBO) :
3950
toDisplay = null
4051
}
4152
}
42-
43-
private fun fillRenderQueue(generator: () -> FBOPool.FBO) {
44-
while (renderQueue.remainingCapacity() > 0) {
45-
renderQueue.offer(generator())
46-
}
47-
}
4853
}

src/main/java/dev/silenium/compose/gl/fbo/FBOMailbox.kt renamed to src/main/java/dev/silenium/compose/gl/fbo/FBOMailboxSwapChain.kt

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import java.util.concurrent.ArrayBlockingQueue
55
import java.util.concurrent.locks.ReentrantLock
66
import kotlin.concurrent.withLock
77

8-
class FBOMailbox(capacity: Int, private val fboCreator: (IntSize) -> FBOPool.FBO) : IFBOPresentMode {
8+
class FBOMailboxSwapChain(capacity: Int, override val fboCreator: (IntSize) -> FBOPool.FBO) : FBOSwapChain() {
9+
override var size: IntSize = IntSize.Zero
10+
private set
911
private val displayLock = ReentrantLock()
1012
private val waitingLock = ReentrantLock()
1113
private var waitingFBO: FBOPool.FBO? = null
@@ -15,7 +17,12 @@ class FBOMailbox(capacity: Int, private val fboCreator: (IntSize) -> FBOPool.FBO
1517
override fun display(block: (FBOPool.FBO) -> Unit) = displayLock.withLock {
1618
toDisplay?.let(block)
1719
waitingLock.withLock {
18-
if (waitingFBO == null) return
20+
val waiting = waitingFBO ?: return
21+
if (waiting.size != size) {
22+
waiting.destroy()
23+
waitingFBO = null
24+
return
25+
}
1926
toDisplay = waitingFBO
2027
waitingFBO = null
2128
}
@@ -24,8 +31,15 @@ class FBOMailbox(capacity: Int, private val fboCreator: (IntSize) -> FBOPool.FBO
2431
override suspend fun <R> render(block: suspend (FBOPool.FBO) -> R): R? {
2532
val fbo = renderQueue.poll() ?: return null
2633
val result = block(fbo)
34+
if (fbo.size != size) {
35+
fbo.destroy()
36+
return null
37+
}
2738
displayLock.withLock {
28-
toDisplay?.let(renderQueue::offer)
39+
toDisplay?.let {
40+
if (it.size != size) it.destroy()
41+
else renderQueue.offer(it)
42+
}
2943
toDisplay = fbo
3044
}
3145
if (displayLock.tryLock()) {
@@ -38,8 +52,9 @@ class FBOMailbox(capacity: Int, private val fboCreator: (IntSize) -> FBOPool.FBO
3852
}
3953

4054
override fun resize(size: IntSize) {
41-
destroyFBOs()
42-
fillRenderQueue { fboCreator(size) }
55+
this.size = size
56+
renderQueue.onEach { it.destroy() }.clear()
57+
renderQueue.fillRenderQueue(fboCreator, size)
4358
}
4459

4560
override fun destroyFBOs() {
@@ -53,10 +68,4 @@ class FBOMailbox(capacity: Int, private val fboCreator: (IntSize) -> FBOPool.FBO
5368
waitingFBO = null
5469
}
5570
}
56-
57-
private fun fillRenderQueue(generator: () -> FBOPool.FBO) {
58-
while (renderQueue.remainingCapacity() > 0) {
59-
renderQueue.offer(generator())
60-
}
61-
}
6271
}

src/main/java/dev/silenium/compose/gl/fbo/FBOPool.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class FBOPool(
1818
private val render: EGLContext,
1919
private val display: EGLContext,
2020
var size: IntSize,
21-
swapChainFactory: (Int, (IntSize) -> FBO) -> IFBOPresentMode,
21+
swapChainFactory: (Int, (IntSize) -> FBO) -> FBOSwapChain,
2222
swapChainSize: Int = 10,
2323
) {
2424
data class FBO(
@@ -49,7 +49,7 @@ class FBOPool(
4949
}
5050
}
5151

52-
private val swapChain: IFBOPresentMode = swapChainFactory(swapChainSize, ::createFBO)
52+
private val swapChain: FBOSwapChain = swapChainFactory(swapChainSize, ::createFBO)
5353

5454
private enum class ContextType {
5555
RENDER,
@@ -153,11 +153,11 @@ class FBOPool(
153153
* @return wait time for the next frame
154154
*/
155155
suspend fun render(deltaTime: Duration, block: suspend GLDrawScope.() -> Unit): Duration? =
156-
swapChain.render { fbo ->
157-
ensureContext(ContextType.RENDER) {
158-
if (fbo.size != size) ensureContext(ContextType.RENDER) {
159-
swapChain.resize(size)
160-
}
156+
ensureContext(ContextType.RENDER) {
157+
if (swapChain.size != size) {
158+
swapChain.resize(size)
159+
}
160+
swapChain.render { fbo ->
161161
fbo.bind()
162162
val drawScope = GLDrawScopeImpl(fbo, deltaTime)
163163
drawScope.block()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package dev.silenium.compose.gl.fbo
2+
3+
import androidx.compose.ui.unit.IntSize
4+
import java.util.concurrent.ArrayBlockingQueue
5+
6+
abstract class FBOSwapChain {
7+
abstract val size: IntSize
8+
protected abstract val fboCreator: (IntSize) -> FBOPool.FBO
9+
abstract fun display(block: (FBOPool.FBO) -> Unit)
10+
abstract suspend fun <R> render(block: suspend (FBOPool.FBO) -> R): R?
11+
abstract fun resize(size: IntSize)
12+
abstract fun destroyFBOs()
13+
}
14+
15+
fun ArrayBlockingQueue<FBOPool.FBO>.fillRenderQueue(fboCreator: (IntSize) -> FBOPool.FBO, size: IntSize) {
16+
while (remainingCapacity() > 0) {
17+
offer(fboCreator(size))
18+
}
19+
}

src/main/java/dev/silenium/compose/gl/fbo/IFBOPresentMode.kt

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/main/java/dev/silenium/compose/gl/surface/GLSurfaceView.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,19 +72,19 @@ class GLSurfaceView internal constructor(
7272
private val presentMode: PresentMode = PresentMode.MAILBOX,
7373
private val swapChainSize: Int = 10,
7474
) {
75-
enum class PresentMode(internal val impl: (Int, (IntSize) -> FBOPool.FBO) -> IFBOPresentMode) {
75+
enum class PresentMode(internal val impl: (Int, (IntSize) -> FBOPool.FBO) -> FBOSwapChain) {
7676
/**
7777
* Renders the latest frame and discards all the previous frames.
7878
* Results in the lowest latency.
7979
*/
80-
MAILBOX(::FBOMailbox),
80+
MAILBOX(::FBOMailboxSwapChain),
8181

8282
/**
8383
* Renders all the frames in the order they were produced.
8484
* Results in a higher latency, but smoother animations.
8585
* Limits the framerate to the display refresh rate.
8686
*/
87-
FIFO(::FBOFifo),
87+
FIFO(::FBOFifoSwapChain),
8888
}
8989

9090
private var directContext: DirectContext? = null

src/test/kotlin/Main.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ fun ApplicationScope.App() {
4242
GLSurfaceView(
4343
state = state,
4444
modifier = Modifier.aspectRatio(1f).fillMaxSize(),
45+
presentMode = GLSurfaceView.PresentMode.MAILBOX,
4546
) {
4647
glClearColor(color.red, color.green, color.blue, color.alpha)
4748
// glClearColor(1.0f, 0.2f, 0.6f, 0.5f)

0 commit comments

Comments
 (0)