OpenGL中內存和顯存之間的拷貝操作

1. 從內存至顯存
1.1 對Buffer object的操作,比較簡單:

glGenBuffers(NumBuffers, Buffers);
glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

1.2 對Texture的操作,要注意根據內存中數據的存放格式,設置正確的format和type。這是容易導致紋理填充失敗的原因之一。
其次,通過glPixelStore設置的GL_UNPACK_XXX的參數也會影響到填充操作。
spec:
If target is GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE or one of the GL_TEXTURE_CUBE_MAP targets, data is read from data as a sequence of signed or unsigned bytes, shorts, or longs, or single-precision floating-point values, depending on type. These values are grouped into sets of one, two, three, or four values, depending on format, to form elements. Each data byte is treated as eight 1-bit elements, with bit ordering determined by GL_UNPACK_LSB_FIRST (see glPixelStore).
void glTexImage2D(     GLenum target,
      GLint level,
      GLint internalformat,  // Texture的顏色格式
      GLsizei width,
      GLsizei height,
      GLint border,
      GLenum format,     // 內存數據data的顏色格式
      GLenum type,       // 內存數據data的排放格式
      const void * data);

char *data = ...;  // CPU memory
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
GLenum err1 = glGetError();
// data的數據內容爲【R(1 byte), G(1 byte), B(1 byte), A(1 byte)】, 【R(1 byte), G(1 byte), B(1 byte), A(1 byte)】...
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
GLenum err2 = glGetError();
// check err1 and err2
glBindTexture(GL_TEXTURE_2D, 0);

在指定正確format和type後,如果依然填充失敗,可以檢查如下參數:

glGetIntegerv(GL_UNPACK_SWAP_BYTES, &old_unpack_swap_bytes);
glGetIntegerv(GL_UNPACK_LSB_FIRST, &old_unpack_lsb_first);
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &old_unpack_row_length);
glGetIntegerv(GL_UNPACK_IMAGE_HEIGHT, &old_unpack_image_height);
glGetIntegerv(GL_UNPACK_SKIP_ROWS, &old_unpack_skip_rows);
glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &old_unpack_skip_pixels);
glGetIntegerv(GL_UNPACK_SKIP_IMAGES, &old_unpack_skip_images);
glGetIntegerv(GL_UNPACK_ALIGNMENT, &old_unpack_alignment);
// 參考如下設置
glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
glPixelStorei(GL_UNPACK_LSB_FIRST, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// call glTexImage2D or glTexSubImage2D
// 恢復設置
glPixelStorei(GL_UNPACK_SWAP_BYTES, old_unpack_swap_bytes);
glPixelStorei(GL_UNPACK_LSB_FIRST, old_unpack_lsb_first);
glPixelStorei(GL_UNPACK_ROW_LENGTH, old_unpack_row_length);
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, old_unpack_image_height);
glPixelStorei(GL_UNPACK_SKIP_ROWS, old_unpack_skip_rows);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, old_unpack_skip_pixels);
glPixelStorei(GL_UNPACK_SKIP_IMAGES, old_unpack_skip_images);
glPixelStorei(GL_UNPACK_ALIGNMENT, old_unpack_alignment);

2. 從顯存到內存
典型的,從FBO中讀取渲染完成的畫面至內存。這裏也需要注意glPixelStore設置的參數會影響到是否成功讀取。

glPixelStorei(GL_PACK_ALIGNMENT, 1);  /* default is 4 */
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);

char *data = malloc(...);  // CPU memory
GLenum lastBuffer;
glGetIntegerv(GL_READ_BUFFER, &lastBuffer);
// 如果已經通過glBindFramebuffer(GL_READ_FRAMEBUFFER, ...)指定了讀取源,則不需要再通過glReadBuffer指定
glReadBuffer(GL_FRONT_LEFT);
glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, data);
glReadBuffer(lastBuffer);

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章