1818package com.lambda.graphics.pipeline
1919
2020import com.lambda.graphics.buffer.Buffer.Companion.createPipelineBuffer
21+ import com.lambda.graphics.buffer.DynamicByteBuffer
2122import com.lambda.graphics.buffer.DynamicByteBuffer.Companion.dynamicByteBuffer
2223import com.lambda.graphics.gl.kibibyte
2324import org.lwjgl.system.MemoryUtil.memCopy
24- import java.nio.ByteBuffer
25+ import sun.misc.Unsafe
2526
2627/* *
2728 * Represents a persistent dynamic coherent buffer for fast opengl rendering purposes
2829 */
2930class PersistentBuffer (
30- target : Int , stride : Int
31+ target : Int , stride : Int , initialSize : Int = 1 .kibibyte
3132) {
3233 /* *
3334 * Resizable byte buffer that stores all data used last frame
3435 */
35- val byteBuffer = dynamicByteBuffer(stride * 1 .kibibyte )
36+ val byteBuffer = dynamicByteBuffer(stride * initialSize )
3637
3738 /* *
3839 * Data that has passed through the buffer within previous frame
3940 */
4041 private val snapshot = dynamicByteBuffer(1 )
41- private var cacheSize = 0
42+ private var snapshotData = 0L
4243
4344 /* *
4445 * Represents a gpu-side buffer
4546 */
46- private val glBuffer = createPipelineBuffer(target)
47+ val glBuffer = createPipelineBuffer(target)
4748 private var glSize = 0
4849
4950 var uploadOffset = 0
@@ -58,19 +59,12 @@ class PersistentBuffer(
5859
5960 glBuffer.allocate(byteBuffer.data)
6061 snapshot.realloc(byteBuffer.capacity)
61- cacheSize = 0
62+ snapshotData = 0
6263 return
64+ }
6365
64- /* TODO:
65- Cache data in range min(snapshot.capacity, byteBuffer.bytesPut)
66- and force upload after byteBuffer.bytesPut
67- */
68- } else if (cacheSize > 0 && snapshot.capacity >= byteBuffer.bytesPut) {
69- // TODO: precise compare-mapping to minimize uploaded data
70- // Split data by chunks of modified regions and upload them only
71- // Might be useful in cases when position updates but uv/color/etc doesn't
72- // Might be not...
73- if (memcmp(snapshot.data, byteBuffer.data, uploadOffset, dataCount.toInt())) return
66+ if (snapshotData > 0 && snapshot.capacity >= byteBuffer.bytesPut) {
67+ if (memcmp(snapshot, byteBuffer, uploadOffset, dataCount.toInt())) return
7468 }
7569
7670 glBuffer.update(uploadOffset.toLong(), dataCount, dataStart)
@@ -82,7 +76,7 @@ class PersistentBuffer(
8276
8377 fun sync () {
8478 memCopy(byteBuffer.pointer, snapshot.pointer, byteBuffer.bytesPut)
85- cacheSize = byteBuffer.bytesPut.toInt()
79+ snapshotData = byteBuffer.bytesPut
8680
8781 byteBuffer.resetPosition()
8882 uploadOffset = 0
@@ -92,17 +86,26 @@ class PersistentBuffer(
9286 snapshot.resetPosition()
9387 byteBuffer.resetPosition()
9488 uploadOffset = 0
95- cacheSize = 0
89+ snapshotData = 0
9690 }
9791
9892 fun use (block : () -> Unit ) = glBuffer.bind { block() }
9993
100- private fun memcmp (a : ByteBuffer , b : ByteBuffer , pointer : Int , size : Int ): Boolean {
101- for (i in pointer.. < (pointer + size)) {
102- if (a[i] != b[i]) {
94+ private fun memcmp (a : DynamicByteBuffer , b : DynamicByteBuffer , position : Int , size : Int ): Boolean {
95+ for (i in position.. < (position + size)) {
96+ if (UNSAFE .getByte(null , a.pointer + i) !=
97+ UNSAFE .getByte(null , b.pointer + i)) {
10398 return false
10499 }
105100 }
106101 return true
107102 }
103+
104+ companion object {
105+ private val UNSAFE = run {
106+ val unsafeField = Unsafe ::class .java.getDeclaredField(" theUnsafe" )
107+ unsafeField.setAccessible(true )
108+ unsafeField.get(null ) as Unsafe
109+ }
110+ }
108111}
0 commit comments