PixelBuffer对象和Android上的glReadPixel(ARCore)阻塞

出门莫恨无人随,书中车马多如簇。这篇文章主要讲述PixelBuffer对象和Android上的glReadPixel(ARCore)阻塞相关的知识,希望能为你提供帮助。
我知道默认的glReadPixels()会等到GL线程上执行所有绘图命令。但是当你绑定一个PixelBuffer对象然后调用glReadPixels()时,它应该是异步的,不会等待任何事情。但是当我绑定PBO并执行glReadPixels()时,它会阻塞一段时间。
以下是我初始化PBO的方法:

mPboIds = IntBuffer.allocate(2); GLES30.glGenBuffers(2, mPboIds); GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, mPboIds.get(0)); GLES30.glBufferData(GLES30.GL_PIXEL_PACK_BUFFER, mPboSize, null, GLES30.GL_STATIC_READ); //allocates only memory space given data sizeGLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, mPboIds.get(1)); GLES30.glBufferData(GLES30.GL_PIXEL_PACK_BUFFER, mPboSize, null, GLES30.GL_STATIC_READ); GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, 0);

然后我用两个缓冲区来打乒乓:
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, mPboIds.get(mPboIndex)); //1st PBO JNIWrapper.glReadPixels(0, 0, mRowStride / mPixelStride, (int)height, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE); //read pixel from the screen and write to 1st buffer(native C++ code)//don't load anything in the first frame if (mInitRecord) { GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, 0); //reverse the index mPboIndex = (mPboIndex + 1) % 2; mPboNewIndex = (mPboNewIndex + 1) % 2; mInitRecord = false; return; }GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, mPboIds.get(mPboNewIndex)); //2nd PBO //glMapBufferRange returns pointer to the buffer object //this is the same thing as calling glReadPixel() without a bound PBO //The key point is that we can pipeline this callByteBuffer byteBuffer = (ByteBuffer) GLES30.glMapBufferRange(GLES30.GL_PIXEL_PACK_BUFFER, 0, mPboSize, GLES30.GL_MAP_READ_BIT); //downdload from the GPU to CPUBitmap bitmap = Bitmap.createBitmap((int)mScreenWidth,(int)mScreenHeight, Bitmap.Config.ARGB_8888); bitmap.copyPixelsFromBuffer(byteBuffer); GLES30.glUnmapBuffer(GLES30.GL_PIXEL_PACK_BUFFER); GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, 0); //reverse the index mPboIndex = (mPboIndex + 1) % 2; mPboNewIndex = (mPboNewIndex + 1) % 2;

每帧都会在我的绘图方法中调用它。根据我的理解,glReadPixels不应该花费任何时间,但它需要大约25ms(在Google Pixel 2上)并且创建位图需要另外40ms。这只能达到13 FPS,比没有PBO的glReadPixels差。
我的代码中是否有任何遗漏或错误的内容?
答案编辑,因为你指出我的原始假设是不正确的(初始PboIndex == PboNextIndex)。希望有所帮助,这里是我刚刚在本机上编写的C ++代码,使用GLES 3通过JNI从android调用。它似乎工作而不是阻止glReadPixels(...)。请注意,只有一个glPboIndex变量:
glBindBuffer(GL_PIXEL_PACK_BUFFER, glPboIds[glPboIndex]); glReadPixels(0, 0, frameWidth_, frameHeight_, GL_RGBA, GL_UNSIGNED_BYTE, 0); glPboReady[glPboIndex] = true; glPboIndex = (glPboIndex + 1) % 2; if (glPboReady[glPboIndex]) { glBindBuffer(GL_PIXEL_PACK_BUFFER, glPboIds[glPboIndex]); GLubyte* rgbaBytes = (GLubyte*)glMapBufferRange( GL_PIXEL_PACK_BUFFER, 0, frameByteCount_, GL_MAP_READ_BIT); if (rgbaBytes) { size_t minYuvByteCount = frameWidth_ * frameHeight_ * 3 / 2; // 12 bits/pixel if (videoFrameBufferSize_ < minYuvByteCount) { return; // !!! not logging error inside render loop } convertToVideoYuv420NV21FromRgbaInverted( videoFrameBufferAddress_, rgbaBytes, frameWidth_, frameHeight_); } glUnmapBuffer(GL_PIXEL_PACK_BUFFER); glPboReady[glPboIndex] = false; } glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);

...
以前毫无根据的假设:
【PixelBuffer对象和Android上的glReadPixel(ARCore)阻塞】您的问题没有显示设置mPboIndex和mPboNewIndex的初始值的代码,但是如果将它们设置为相同的初始值(例如0),那么它们将在每个循环中具有匹配的值,这将导致映射相同的PBO刚读过。在该假设/真实场景中,即使正在使用2个PBO,它们也不会在glReadPixels和glMapBufferRange之间交替,然后它们将阻塞,直到GPU完成数据传输。我建议这种改变以确保公益组织交替:
mPboNewIndex = mPboIndex; mPboIndex = (mPboNewIndex + 1) % 2;


    推荐阅读