從GPU讀取資料到系統記憶體的三種方式
方法一:glReadPixels
首先建立一個fbo,繫結fbo後,attach上需要操作的texture,再進行讀取。
if(fbo == 0)
{
glGenFramebuffers(1, &fbo);
}
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, dataPointer);
方法二: glGetTexImg
也是比較簡單,bind需要讀取的texture後,就可以直接呼叫glGetTexImg進行讀取
glBindTexture(GL_TEXTURE_2D, textureID);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, dataPointer);
glBindTexture(GL_TEXTURE_2D, 0);
方法三:使用pbo
使用pbo是最複雜的,但是比前兩種要快。只使用一個pbo的話,也就是同步,比glReadpixel快那麼一點點,但是如果使用多個pbo進行非同步讀取,呵呵,那就快了幾百倍了。
首先初始化的時候,可生成兩個pbo
GLuint pbo[2];
//creates PBOs to hold the data, this allocates memory for them too
glGenBuffers(2, pbo);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[0]);
glBufferData(GL_PIXEL_PACK_BUFFER, height* width, 0, GL_STREAM_READ);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[1]);
glBufferData(GL_PIXEL_PACK_BUFFER, height* width, 0, GL_STREAM_READ);
//unbind buffers for now
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
然後建立fbo
if(fbo == 0)
{
glGenFramebuffers(1, &fbo);
}
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0);
接下來就是fbo的非同步處理了
writeIndex = (writeIndex + 1) % 2;
readIndex = (readIndex + 1) % 2;
//bind FBO to read pixels. This buffer is being compied from GPU to CPU memory
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[writeIndex]);
//copy from framebuffer to FBO asynchronously. it will be ready in the Next Frame
glReadPixels(0,0 ,width, height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
//now read other FBO which should be already in CPU memory
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[readIndex]);
//map buffer so we can access it
cpixel = (unsigned char *)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
if (cpixel)
{
// ok we have the data now avaliable and could process it or copy it somewhere
// ...
// unmap the buffer again
memcpy(dataPointer,cpixel,height * width);
//cpixel = nullptr;
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
}
//back to conventional pixel operation
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
三種方法介紹完了,其實還有很多其他的寫法。第一次分享,嘻嘻~
轉載請註明出處,謝謝!