You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android平台OpenGL ES 3.1中SSBO的float数据读写问题求助

Retrieving Data from an OpenGL ES 3.1 SSBO After Compute Shader Execution

Nice work getting the SSBO set up and your compute shader running! To pull the processed data back to the CPU, you’ve got two solid options in OpenGL ES 3.1—let me walk you through both with Kotlin code that matches your existing setup.

First, a crucial pre-step: make sure the GPU has finished running your compute shader before trying to read data. OpenGL operations are asynchronous, so add this line right after dispatching your compute shader to block the CPU until all GPU work is done:

GLES31.glFinish()

Method 1: Use glGetBufferSubData (No Memory Mapping)

This approach copies SSBO data directly into a pre-allocated CPU buffer, which is straightforward and avoids dealing with memory pointers.

// 1. Bind your SSBO (skip if it's already bound)
GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, this.storageShaderBufferObject[0])

// 2. Create a CPU buffer to hold the retrieved data
val size = this.meshSizeX * this.meshSizeY
val retrievedData = FloatArray(size)
val byteBuffer = ByteBuffer.allocateDirect(retrievedData.size * 4)
    .order(ByteOrder.nativeOrder())
    .asFloatBuffer()

// 3. Copy data from the SSBO to the CPU buffer
GLES31.glGetBufferSubData(
    GLES31.GL_SHADER_STORAGE_BUFFER,
    0,  // Start reading from the beginning of the SSBO
    retrievedData.size * 4,  // Total bytes to read
    byteBuffer
)

// 4. Transfer data from the ByteBuffer to your FloatArray
byteBuffer.position(0)
byteBuffer.get(retrievedData)

// Now you can use retrievedData!
for (i in retrievedData.indices) {
    println("Index $i value: ${retrievedData[i]}")
}

Method 2: Use glMapBuffer + glUnmapBuffer (Memory Mapping)

This method maps the GPU’s SSBO memory directly to a CPU-accessible pointer, which can be more efficient for large datasets. Here’s how to implement it:

// 1. Bind your SSBO
GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, this.storageShaderBufferObject[0])

// 2. Map the SSBO to CPU memory (use GL_READ_ONLY since we're only reading)
val mappedBuffer = GLES31.glMapBuffer(
    GLES31.GL_SHADER_STORAGE_BUFFER,
    GLES31.GL_READ_ONLY
)

if (mappedBuffer != null) {
    // 3. Convert the mapped pointer to a FloatBuffer
    val floatBuffer = mappedBuffer.order(ByteOrder.nativeOrder()).asFloatBuffer()
    
    // 4. Copy data to a FloatArray (or use the buffer directly)
    val size = this.meshSizeX * this.meshSizeY
    val retrievedData = FloatArray(size)
    floatBuffer.get(retrievedData)
    
    // 5. Unmap the buffer to release the GPU memory mapping
    val unmapSuccess = GLES31.glUnmapBuffer(GLES31.GL_SHADER_STORAGE_BUFFER)
    if (!unmapSuccess) {
        println("Warning: Unmapping failed—data might be invalid!")
    }
    
    // Use your retrieved data here
    for (i in retrievedData.indices) {
        println("Index $i value: ${retrievedData[i]}")
    }
} else {
    println("Error: Failed to map SSBO to CPU memory!")
}

Quick Notes:

  • Buffer Usage: Your choice of GL_STATIC_COPY for the SSBO is perfect here—it’s designed for data that goes from CPU to GPU, gets modified by the GPU, then comes back to the CPU.
  • Workgroup Check: Double-check your compute shader’s offset logic: uint offset = gl_GlobalInvocationID.x * gWidth + gl_GlobalInvocationID.y; Make sure your dispatch call (glDispatchCompute(...)) uses values that cover all your mesh elements. For a local size of 8x8, you’d use glDispatchCompute((meshSizeX +7)/8, (meshSizeY +7)/8, 1) to avoid missing any indices.

内容的提问来源于stack exchange,提问作者M. Miguel-Brebion

火山引擎 最新活动