使用Android OpenGL ES 3.0 PBO替代glReadPixels()

5

我希望通过使用PBO(对于支持GLES 3的设备)来提高glReadPixels()的性能,但是在这段代码中遇到了问题:

final ByteBuffer pboByteBuffer = ByteBuffer.allocateDirect(4 * mWidth * mHeight);
pboByteBuffer.order(ByteOrder.nativeOrder());

//set framebuffer to read from
GLES30.glReadBuffer(GLES30.GL_BACK);

// bind pbo
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, mPboHandleContainer[0]);

// read pixels(should be instant)
GLES30.glReadPixels(0, 0, mWidth, mHeight, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, pboByteBuffer);

// map pbo to bb
ByteBuffer byteBuffer =
        ((ByteBuffer) GLES30.glMapBufferRange(GLES30.GL_PIXEL_PACK_BUFFER, 0, 4 * mWidth * mHeight,
                                              GLES30.GL_MAP_READ_BIT)).order(ByteOrder.nativeOrder());

// unmap pbo
GLES30.glUnmapBuffer(GLES30.GL_PIXEL_PACK_BUFFER);

// unbind pbo
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, 0);

目前它无法通过glReadPixels()方法。我找到了这个这个,但是我不能发送零因为它需要一个IntBuffer参数。我非常感谢任何关于这个问题的建议。

更新:似乎不可能仅使用Java API完成此任务。所以我使用ndk添加了一个调用具有正确最后参数(int offset)的glReadPixels()函数的功能。现在我的所有GL调用都没有产生错误。

这是我的jni c代码:

#include <jni.h>

#include <GLES3/gl3.h>

#ifdef __cplusplus
extern "C" {
    JNIEXPORT void JNICALL Java_somepackage_GLES3PBOReadPixelsFix_glReadPixelsPBO(JNIEnv * env, jobject obj, jint x, jint y, jint width, jint height, jint format, jint type, jint offsetPBO);
};
#endif

JNIEXPORT void JNICALL Java_somepackage_GLES3PBOReadPixelsFix_glReadPixelsPBO(JNIEnv * env, jobject obj, jint x, jint y, jint width, jint height, jint format, jint type, jint offsetPBO)
{
    glReadPixels(x, y, width, height, format, type, offsetPBO);
}

现在的问题是glReadPixels()调用所需时间比不使用PBOs的时间更长,因此目前没有性能提升。我将探究原因,并在找到内容后进行更新。 更新2 我之前忘记更新了,但实际上问题是我正在使用pbuffer表面,这就是为什么我没有获得性能提升的原因。我比较了该选项和不使用pbuffer表面的选项,性能提升非常巨大。
因此,在离屏渲染并使用glReadPixels时,值得使用pbuffer表面。

1
奇怪。看起来在Android中使用PBOs进行glReadPixels()的Java入口点丢失了。如果确实是这样,那么这不是Android中第一次发生这种情况。使用本地代码总是一个解决方案。话虽如此,如果您立即等待结果,则使用PBO可能不会对您有太大帮助。整个想法是glReadPixels()调用不会阻塞。如果您随后立即阻塞,那么这将没有什么好处。 - Reto Koradi
@RetoKoradi 感谢您的反馈!对我来说,使用本地代码仍然不是一个选择。而真正重要的是,我的代码块所花费的时间与简单的glReadPixels()调用相比如何。 - Sam
我在Android上遇到了使用PBO没有看到性能提升的相同问题。您可以详细解释一下如何在Android上不使用pbuffer表面以启用快速和异步的glReadPixels到PBO吗?谢谢。 - Ziju Feng
1个回答

2
在glReadPixels之后立即映射PBO缓冲区总是会降低性能。当您请求映射时,GPU仍在工作。因此,glMapBufferRange等待GPU完成读取像素到PBO。如果您在glReadPixels之后继续渲染,并在一些帧之后执行映射,则可以获得性能提升。
更多信息请参见:http://www.songho.ca/opengl/gl_pbo.html的“Mapping PBO”部分。

更新了我的答案。我看了那篇文章和许多其他文章,但当时不幸的是我没有意识到发生了什么。 - Sam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接