Skip to content

Commit 12e2045

Browse files
committed
better pbo
1 parent 68b24da commit 12e2045

File tree

1 file changed

+54
-19
lines changed

1 file changed

+54
-19
lines changed

common/src/main/kotlin/com/lambda/graphics/buffer/pbo/PixelBuffer.kt

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package com.lambda.graphics.buffer.pbo
22

3+
import com.lambda.Lambda.LOG
34
import com.lambda.graphics.buffer.BufferUsage
5+
import org.lwjgl.opengl.GL
46
import org.lwjgl.opengl.GL45C.*
5-
import org.lwjgl.opengl.GREMEDYStringMarker
67
import java.nio.ByteBuffer
78

89
class PixelBuffer(
@@ -17,24 +18,51 @@ class PixelBuffer(
1718

1819
private val queryId = glGenQueries() // Used to measure the time taken to upload data to the PBO
1920
val uploadTime get() = IntArray(1).also { glGetQueryObjectiv(queryId, GL_QUERY_RESULT, it) }[0]
21+
var transferRate = 0L // The transfer rate in bytes per second
22+
private set
23+
24+
var pboSupported = false
25+
private set
2026

2127
fun mapTexture(id: Int, buffer: ByteBuffer) =
2228
upload(buffer) {
2329
// Bind the texture
2430
glBindTexture(GL_TEXTURE_2D, id)
2531

26-
// Perform the actual data transfer to the GPU
27-
glTextureSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0)
32+
if (buffers > 0 && pboSupported) {
33+
// Bind the next PBO to update pixel values
34+
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[writeIdx])
35+
36+
// Perform the actual data transfer to the GPU
37+
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0)
38+
}
39+
else {
40+
// Perform the actual data transfer to the GPU
41+
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer)
42+
}
2843
}
2944

3045
fun upload(data: ByteBuffer, process: () -> Unit) =
3146
recordTransfer {
32-
uploadIdx = (writeIdx + 1) % buffers
47+
if (buffers >= 2)
48+
uploadIdx = (writeIdx + 1) % buffers
3349

34-
GREMEDYStringMarker.glStringMarkerGREMEDY("Data transfer to buffer")
50+
// Copy the pixel values from the PBO to the texture
51+
process()
3552

36-
// Bind the next PBO to update pixel values
37-
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[writeIdx])
53+
if (!pboSupported) return@recordTransfer
54+
55+
// Bind the current PBO for writing
56+
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[uploadIdx])
57+
58+
// Note that glMapBuffer() causes sync issue.
59+
// If GPU is working with this buffer, glMapBuffer() will wait(stall)
60+
// until GPU to finish its job. To avoid waiting (idle), you can call
61+
// first glBufferData() with NULL pointer before glMapBuffer().
62+
// If you do that, the previous data in PBO will be discarded and
63+
// glMapBuffer() returns a new allocated pointer immediately
64+
// even if GPU is still working with the previous data.
65+
glBufferData(GL_PIXEL_UNPACK_BUFFER, width * height * 4L, bufferUsage.gl)
3866

3967
// Map the buffer into the memory
4068
val bufferData = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY)
@@ -43,17 +71,7 @@ class PixelBuffer(
4371

4472
// Release the buffer
4573
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER)
46-
} else {
47-
println("Failed to map the PBO")
48-
}
49-
50-
// Bind the current PBO for writing
51-
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[uploadIdx])
52-
53-
GREMEDYStringMarker.glStringMarkerGREMEDY("Data transfer to GPU")
54-
55-
// Copy the pixel values from the PBO to the texture
56-
process()
74+
} else throw IllegalStateException("Failed to map the buffer")
5775

5876
// Unbind the PBO
5977
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0)
@@ -63,6 +81,11 @@ class PixelBuffer(
6381
}
6482

6583
private fun recordTransfer(block: () -> Unit) {
84+
if (!pboSupported) {
85+
block()
86+
return
87+
}
88+
6689
// Start the timer
6790
glBeginQuery(GL_TIME_ELAPSED, queryId)
6891

@@ -71,6 +94,12 @@ class PixelBuffer(
7194

7295
// Stop the timer
7396
glEndQuery(GL_TIME_ELAPSED)
97+
98+
// Calculate the transfer rate
99+
val time = uploadTime
100+
if (time > 0) {
101+
transferRate = (width * height * 4L * 1_000_000_000) / time
102+
}
74103
}
75104

76105
// Called when no references to the object exist
@@ -80,7 +109,13 @@ class PixelBuffer(
80109
}
81110

82111
init {
83-
if (buffers < 1) throw IllegalArgumentException("Buffers must be greater than or equal to 1")
112+
// Check if the PBO is supported
113+
GL.getCapabilities().let { pboSupported = it.OpenGL30 || it.GL_ARB_pixel_buffer_object }
114+
115+
if (!pboSupported && buffers > 0)
116+
LOG.warn("Client tried to utilize PBOs, but they are not supported on the machine, falling back to direct buffer upload")
117+
118+
if (buffers < 0) throw IllegalArgumentException("Buffers must be greater than or equal to 0")
84119

85120
// Generate the PBOs
86121
glGenBuffers(pboIds)

0 commit comments

Comments
 (0)