glReadPixels: 如果你想将渲染的结果保存下来,你可以使用glReadPixels将图像内容从现存读取到内存中,需要注意:仅限于读取Color Buffer,无法读取Depth Buffer和Stencil Buffer,当调用glReadPixels时,可以将Color Buffer中的像素值保存到预分配的内存缓冲区中。
函数定义:
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
x, y: specify the viewport coordinates of the lower-left corner of the pixel rectangle read from the color buffer.
width,height: specify the dimensions of the pixel rectangle read from the color buffer.
format: specifies the pixel format that you would like returned. Three formats are available: GL_RGBA, GL_RGBA_INTEGER, and the value returned by querying GL_IMPLEMENTATION_COLOR_READ_FORMAT, which is an implementation-specific pixel format.
type: specifies the data type of the pixels returned. Five types are available: GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, GL_INT, GL_FLOAT, and the value returned from querying GL_IMPLEMENTATION_COLOR_READ_TYPE, which is an implementation-specific pixel type. pixels: a contiguous array of bytes that contain the values read from the color buffer after glReadPixels returns.
下面分几种情况讲解glReadPixels的使用方式:
1. 从GL_TEXTURE_2D中读取:
当从GL_TEXTURE_2D读取时,因为有可能当前Context并没有FrameBuffer绑定,或者FrameBuffer绑定的并不是我们需要读取的Texture,所以最好的方式是创建一个临时FrameBuffer,在临时的FrameBuffer上绑定要读取的Texture,并在使用临时FrameBuffer之前,查询当前绑定的FrameBuffer,并在读取完成后恢复当前绑定的FrameBuffer。
GLuint Tmp_Framebuffer = 0;
glGenFramebuffers ( 1, &TMP_Framebuffer );
/******* IN Rendering LOOP Begin**************/
GLint defaultFramebuffer = 0;
glGetIntegerv ( GL_FRAMEBUFFER_BINDING, &defaultFramebuffer );
glBindFramebuffer ( GL_FRAMEBUFFER, G_Framebuffer );
// textureId: 要读取的TextureID
glFramebufferTexture2D ( GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
textureId, 0 );
//默认读取GL_COLOR_ATTACHMENT0,此处可以不设置
glReadBuffer ( GL_COLOR_ATTACHMENT0 );
///////////////////////////////////////////////////////////////////
////////////调用glReadPixels读取现存////////////////////////////////
///////////////////////////////////////////////////////////////////
glBindFramebuffer ( GL_FRAMEBUFFER, defaultFramebuffer );
/******* IN Rendering LOOP End **************/
2. 从GL_TEXTURE_2D_ARRAY中读取:
与1中的实现相同,唯一的区别是在临时FrameBuffer绑定GL_TEXTURE_2D_ARRAY的接口有所区别,需要使用glFramebufferTextureLayer( GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 0 );
3. 从帧缓冲区中读取,WindowSurface和PBufferSurface
不需要做特殊操作,直接读取就可以读取eglMakeCurrent时设置的readSurface中的内容。
完整代码如下:
#define FILENAME_MAX 64
#define CAMERA_DUMP_FRM_LOCATION "/sdcard/"
void dumpImage(unsigned char* imagedata,
uint32_t frameid, uint32_t width, uint32_t height, uint32_t bytesPerPixel) {
LOG("20191108: %s,%d E .", __FUNCTION__, __LINE__);
char buf[FILENAME_MAX];
memset(buf, 0, sizeof(buf));
snprintf(buf, sizeof(buf), CAMERA_DUMP_FRM_LOCATION "frame_%dX%d_%d.rgb",
width,height,frameid);
LOG("20191108: %s,%d buf : %s", __FUNCTION__,__LINE__,buf);
int file_fd = open(buf, O_RDWR | O_CREAT, 0644);
uint32_t ImageSize = width*height*bytesPerPixel;
if (file_fd >= 0)
{
ssize_t written_image = write(file_fd, imagedata, ImageSize);
LOG("20191108: %s,%d : written number of %zd bytes to file %s", __FUNCTION__, __LINE__, ImageSize, buf);
close(file_fd);
}
else
{
LOG("20191108: %s,%d : failed to write data to %s", __FUNCTION__, __LINE__, buf);
}
LOG("20191108: %s,%d X .", __FUNCTION__, __LINE__);
}
GLuint G_Framebuffer = 0;
glGenFramebuffers ( 1, &G_Framebuffer );
/********************* IN Rendering LOOP Begin **************************/
//glDrawBuffer(GL_NONE);
//glReadBuffer(GL_NONE);
//glFramebufferTextureLayer(
// GL_READ_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,
// texture,0,0 // Use layer 0 for subsequent operations
//);
GLint defaultFramebuffer = 0;
glGetIntegerv ( GL_FRAMEBUFFER_BINDING, &defaultFramebuffer );
static int frameid = 0;
if((frameid++ % 300) == 0)
{
glBindFramebuffer ( GL_FRAMEBUFFER, G_Framebuffer );
glFramebufferTexture2D ( GL_READ_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
textureId, 0 );
int width = my_GetIntConfig(TEXTURE_WIDTH);
int height = my_GetIntConfig(TEXTURE_HEIGHT);
glReadBuffer ( GL_COLOR_ATTACHMENT0 );
GLint readType, readFormat;
GLubyte *pixels;
glGetIntegerv ( GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType );
glGetIntegerv ( GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat );
unsigned int bytesPerPixel = 0;
switch ( readType )
{
case GL_UNSIGNED_BYTE:
case GL_BYTE:
switch ( readFormat )
{
case GL_RGBA:
bytesPerPixel = 4;
break;
case GL_RGB:
case GL_RGB_INTEGER:
bytesPerPixel = 3;
break;
case GL_RG:
case GL_RG_INTEGER:
case GL_LUMINANCE_ALPHA:
bytesPerPixel = 2;
break;
case GL_RED:
case GL_RED_INTEGER:
case GL_ALPHA:
case GL_LUMINANCE:
bytesPerPixel = 1;
break;
default:
// Undetected format/error
break;
}
break;
case GL_FLOAT:
case GL_UNSIGNED_INT:
case GL_INT:
switch ( readFormat )
{
case GL_RGBA:
case GL_RGBA_INTEGER:
bytesPerPixel = 16;
break;
case GL_RGB:
case GL_RGB_INTEGER:
bytesPerPixel = 12;
break;
case GL_RG:
case GL_RG_INTEGER:
bytesPerPixel = 8;
break;
case GL_RED:
case GL_RED_INTEGER:
case GL_DEPTH_COMPONENT:
bytesPerPixel = 4;
break;
default:
// Undetected format/error
break;
}
break;
case GL_HALF_FLOAT:
case GL_UNSIGNED_SHORT:
case GL_SHORT:
switch ( readFormat )
{
case GL_RGBA:
case GL_RGBA_INTEGER:
bytesPerPixel = 8;
break;
case GL_RGB:
case GL_RGB_INTEGER:
bytesPerPixel = 6;
break;
case GL_RG:
case GL_RG_INTEGER:
bytesPerPixel = 4;
break;
case GL_RED:
case GL_RED_INTEGER:
bytesPerPixel = 2;
break;
default:
// Undetected format/error
break;
}
break;
case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: // GL_DEPTH_STENCIL
bytesPerPixel = 8;
break;
// GL_RGBA, GL_RGBA_INTEGER format
case GL_UNSIGNED_INT_2_10_10_10_REV:
case GL_UNSIGNED_INT_10F_11F_11F_REV: // GL_RGB format
case GL_UNSIGNED_INT_5_9_9_9_REV: // GL_RGB format
case GL_UNSIGNED_INT_24_8: // GL_DEPTH_STENCIL format
bytesPerPixel = 4;
break;
case GL_UNSIGNED_SHORT_4_4_4_4: // GL_RGBA format
case GL_UNSIGNED_SHORT_5_5_5_1: // GL_RGBA format
case GL_UNSIGNED_SHORT_5_6_5: // GL_RGB format
bytesPerPixel = 2;
break;
default:
break;
// Undetected type/error
}
pixels = ( GLubyte* ) malloc( width * height * bytesPerPixel );
glReadPixels ( 0, 0, width, height, readFormat, readType, pixels );
dumpImage(pixels, frameid, width, height, bytesPerPixel);
}
glBindFramebuffer ( GL_FRAMEBUFFER, defaultFramebuffer );
/********************* IN Rendering LOOP End **************************/