1

我想在 OpenGL 中截取当前帧的屏幕截图以进行进一步处理,并且我正在尝试通过使用 PBO 异步读取帧缓冲区来提高 glReadPixels 的性能。

我的印象是 GL_PIXEL_PACK_BUFFER 绑定到缓冲区后的 glReadPixels 应该立即返回,但它实际上比不使用 PBO 需要相似甚至更多的时间。

以下是我的代码示例:

// Setup PBO
GLES30.glGenBuffers(nPbo, pboIndex, 0);
for(int i=0;i<nPbo; i++){
    GLES30.glBindBuffer (GL_PIXEL_PACK_BUFFER, pboIndex[i]);
    GLES30.glBufferData(GL_PIXEL_PACK_BUFFER, size, null,GL_STREAM_READ);
}
GLES30.glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);

......

// For each frame, trigger async transfer of framebuffer to PBO.
// Note that I don't even map the PBO to memory yet
GLES30.glBindBuffer (GL_PIXEL_PACK_BUFFER, pboIndex[index]);
// The following is a JNI method to overload glReadPixels in GLES20.glReadPixels,
// to allow passing int offset to the last param in order to use PBO, 
// and slowdown (around 500ms on my device) happens here
GLES3PBOReadPixelsFix.glReadPixelsPBO(0, 0, mWidth, mHeight, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, 0); 
GLES30.glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);

根据这篇文章,速度变慢的原因可能是由于内部格式(可能是 GL_BGRA)和像素传输格式(我的代码中的 GL_RGBA)之间的转换。将传输格式更改为 GL_RGB 会将 glReadPixels 的延迟减少到 100 毫秒左右,但是当我使用 GLES30.glMapBufferRange 映射缓冲区时,输出帧看起来并没有正确渲染。我还在 GLES11Ext 中尝试了 GL_BGRA 格式,但它会导致 glReadPixel 中的 GL_INVALID_OPERATION。

有没有其他方法可以让 Android 上的 glReadPixels 立即返回,以便 PBO 可以提高性能?

4

1 回答 1

0

正如 Reto 所建议的,事实证明这是一个特定于实现的问题。我最初测试的 GPU 是 Adreno 306。当我在三星 Note 4 (Adreno 420) 上测试相同的代码时,它按预期工作。因此,针对此类问题在不同的设备和 GPU 上进行测试总是值得的。

于 2016-12-06T06:11:47.530 回答