デフォルトのglReadPixels()はすべての描画コマンドがGLスレッドで実行されるまで待機することがわかりました。しかし、PixelBufferオブジェクトをバインドしてからglReadPixels()を呼び出すと、非同期である必要があり、何も待たないでしょう。 しかし、PBOをバインドしてglReadPixels()を実行すると、しばらくブロックされています。PixelBufferオブジェクトとAndroid(ARCore)ブロッキングのglReadPixel
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 size
GLES30.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);
し、私はピンポンの周りに二つのバッファを使用します:
は、ここで私はPBOを初期化する方法を説明します
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 call
ByteBuffer byteBuffer = (ByteBuffer) GLES30.glMapBufferRange(GLES30.GL_PIXEL_PACK_BUFFER, 0, mPboSize, GLES30.GL_MAP_READ_BIT); //downdload from the GPU to CPU
Bitmap 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;
これは、フレームごとに私のdrawメソッドで呼び出されます。 私の理解では、glReadPixelsはまったく時間を取るべきではありませんが、Google Pixel 2では約25msかかっており、ビットマップの作成にはさらに40msかかります。これは、PBOを使用しないglReadPixelsよりも悪い13 FPSのようにしか達成できません。
コードに紛失や間違いがありますか?
私のケースでは、コールは小さいバッファ(360x640ピクセルなど)に対してのみブロックしていました。より大きなバッファ(例えば、720x1280)の場合、呼び出しは非同期になりました。 GPUによる「最適化」のようなものかもしれません。この動作を無効にする方法が見つかりませんでした。 – coeing