|
1 | 1 | package dev.silenium.compose.gl.fbo |
2 | 2 |
|
3 | 3 | import androidx.compose.ui.unit.IntSize |
4 | | -import java.util.concurrent.ArrayBlockingQueue |
5 | | -import java.util.concurrent.locks.ReentrantLock |
6 | | -import kotlin.concurrent.withLock |
| 4 | +import java.util.concurrent.ConcurrentLinkedQueue |
| 5 | +import java.util.concurrent.atomic.AtomicReference |
7 | 6 |
|
8 | | -class FBOFifoSwapChain(capacity: Int, override val fboCreator: (IntSize) -> FBO) : FBOSwapChain() { |
| 7 | +class FBOFifoSwapChain(private val capacity: Int, override val fboCreator: (IntSize) -> FBO) : FBOSwapChain() { |
9 | 8 | override var size: IntSize = IntSize.Zero |
10 | 9 | private set |
11 | | - private val displayLock = ReentrantLock() |
12 | | - private var current: FBO? = null |
13 | | - private val renderQueue = ArrayBlockingQueue<FBO>(capacity) |
14 | | - private val displayQueue = ArrayBlockingQueue<FBO>(capacity) |
| 10 | + private var fbos = AtomicReference<Array<FBO>?>(null) |
| 11 | + private var current: Int = -1 |
| 12 | + private val displayQueue = ConcurrentLinkedQueue<Int>() |
| 13 | + private val renderQueue = ConcurrentLinkedQueue<Int>() |
15 | 14 |
|
16 | | - override fun <R> display(block: (FBO) -> R) = displayLock.withLock { |
17 | | - val result = current?.let(block) |
18 | | - if (!displayQueue.isEmpty()) { |
19 | | - current?.let { |
20 | | - if (it.size != size) it.destroy() |
21 | | - else renderQueue.offer(it) |
22 | | - } |
23 | | - current = displayQueue.poll() |
| 15 | + override fun <R> display(block: (FBO) -> R): R? { |
| 16 | + val next = displayQueue.poll() |
| 17 | + if (next != null && next != -1) { |
| 18 | + renderQueue.add(current) |
| 19 | + current = next |
24 | 20 | } |
25 | | - return@withLock result |
| 21 | + if (current == -1) return null |
| 22 | + val fbo = fbos.get()?.get(current) ?: return null |
| 23 | + val result = block(fbo) |
| 24 | + return result |
26 | 25 | } |
27 | 26 |
|
28 | 27 | override fun <R> render(block: (FBO) -> R): R? { |
29 | | - val fbo = renderQueue.poll() ?: return null |
30 | | - if (fbo.size != size) { |
31 | | - fbo.destroy() |
32 | | - return null |
| 28 | + val next = renderQueue.poll() ?: return null |
| 29 | + val nextFbos = fbos.updateAndGet { |
| 30 | + if (it?.get(next)?.size != size) { |
| 31 | + it?.get(next)?.destroy() |
| 32 | + it?.set(next, fboCreator(size)) |
| 33 | + } |
| 34 | + it |
33 | 35 | } |
34 | 36 | try { |
35 | | - val result = block(fbo) |
36 | | - displayQueue.offer(fbo) |
| 37 | + val nextFbo = nextFbos?.get(next) ?: return null |
| 38 | + val result = block(nextFbo) |
| 39 | + current = next |
37 | 40 | return result |
38 | 41 | } catch (e: Throwable) { |
39 | | - renderQueue.add(fbo) |
40 | 42 | throw e |
41 | 43 | } |
42 | 44 | } |
43 | 45 |
|
44 | 46 | override fun resize(size: IntSize) { |
45 | 47 | this.size = size |
46 | | - renderQueue.onEach { it.destroy() }.clear() |
47 | | - displayQueue.onEach { it.destroy() }.clear() |
48 | | - renderQueue.fillRenderQueue(fboCreator, size) |
| 48 | + renderQueue.clear() |
| 49 | + displayQueue.clear() |
| 50 | + fbos.get()?.forEachIndexed { index, fbo -> |
| 51 | + if (fbo.size != size && index != current) { |
| 52 | + fbo.destroy() |
| 53 | + } |
| 54 | + } |
| 55 | + val currentFbo = fbos.get()?.getOrNull(current) |
| 56 | + fbos.set(Array(capacity) { |
| 57 | + if (it == current) currentFbo ?: fboCreator(size) |
| 58 | + else fboCreator(size) |
| 59 | + }.also { |
| 60 | + renderQueue.addAll(it.indices - current) |
| 61 | + }) |
49 | 62 | } |
50 | 63 |
|
51 | 64 | override fun destroyFBOs() { |
52 | | - renderQueue.onEach { it.destroy() }.clear() |
53 | | - displayQueue.onEach { it.destroy() }.clear() |
54 | | - displayLock.withLock { |
55 | | - current?.destroy() |
56 | | - current = null |
| 65 | + renderQueue.clear() |
| 66 | + displayQueue.clear() |
| 67 | + current = -1 |
| 68 | + fbos.updateAndGet { |
| 69 | + it?.forEach(FBO::destroy) |
| 70 | + null |
57 | 71 | } |
58 | 72 | } |
59 | 73 | } |
0 commit comments