gallium: implement a fast-path for glReadPixels for common cases
This commit is contained in:
@@ -162,6 +162,124 @@ st_get_color_read_renderbuffer(GLcontext *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to do glReadPixels in a fast manner for common cases.
|
||||||
|
* \return GL_TRUE for success, GL_FALSE for failure
|
||||||
|
*/
|
||||||
|
static GLboolean
|
||||||
|
st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb,
|
||||||
|
GLint x, GLint y, GLsizei width, GLsizei height,
|
||||||
|
GLenum format, GLenum type,
|
||||||
|
const struct gl_pixelstore_attrib *pack,
|
||||||
|
GLvoid *dest)
|
||||||
|
{
|
||||||
|
enum combination {
|
||||||
|
A8R8G8B8_UNORM_TO_RGBA_UBYTE,
|
||||||
|
A8R8G8B8_UNORM_TO_RGB_UBYTE,
|
||||||
|
A8R8G8B8_UNORM_TO_BGRA_UINT
|
||||||
|
} combo;
|
||||||
|
|
||||||
|
if (ctx->_ImageTransferState)
|
||||||
|
return GL_FALSE;
|
||||||
|
|
||||||
|
if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM &&
|
||||||
|
format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
|
||||||
|
combo = A8R8G8B8_UNORM_TO_RGBA_UBYTE;
|
||||||
|
}
|
||||||
|
else if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM &&
|
||||||
|
format == GL_RGB && type == GL_UNSIGNED_BYTE) {
|
||||||
|
combo = A8R8G8B8_UNORM_TO_RGB_UBYTE;
|
||||||
|
}
|
||||||
|
else if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM &&
|
||||||
|
format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) {
|
||||||
|
combo = A8R8G8B8_UNORM_TO_BGRA_UINT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return GL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*printf("st_fast_readpixels combo %d\n", (GLint) combo);*/
|
||||||
|
|
||||||
|
{
|
||||||
|
struct pipe_context *pipe = ctx->st->pipe;
|
||||||
|
struct pipe_screen *screen = pipe->screen;
|
||||||
|
struct pipe_surface *surf;
|
||||||
|
const GLubyte *map;
|
||||||
|
GLubyte *dst;
|
||||||
|
GLint row, col, dy, dstStride;
|
||||||
|
|
||||||
|
surf = screen->get_tex_surface(screen, strb->texture, 0, 0, 0,
|
||||||
|
PIPE_BUFFER_USAGE_CPU_READ);
|
||||||
|
if (!surf) {
|
||||||
|
return GL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
map = screen->surface_map(screen, surf, PIPE_BUFFER_USAGE_CPU_READ);
|
||||||
|
if (!map) {
|
||||||
|
pipe_surface_reference(&surf, NULL);
|
||||||
|
return GL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
|
||||||
|
y = surf->height - y - 1;
|
||||||
|
dy = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dy = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = _mesa_image_address2d(pack, dest, width, height,
|
||||||
|
format, type, 0, 0);
|
||||||
|
dstStride = _mesa_image_row_stride(pack, width, format, type);
|
||||||
|
|
||||||
|
switch (combo) {
|
||||||
|
case A8R8G8B8_UNORM_TO_RGBA_UBYTE:
|
||||||
|
for (row = 0; row < height; row++) {
|
||||||
|
const GLubyte *src = map + y * surf->stride + x * 4;
|
||||||
|
for (col = 0; col < width; col++) {
|
||||||
|
GLuint pixel = ((GLuint *) src)[col];
|
||||||
|
dst[col*4+0] = (pixel >> 16) & 0xff;
|
||||||
|
dst[col*4+1] = (pixel >> 8) & 0xff;
|
||||||
|
dst[col*4+2] = (pixel >> 0) & 0xff;
|
||||||
|
dst[col*4+3] = (pixel >> 24) & 0xff;
|
||||||
|
}
|
||||||
|
dst += dstStride;
|
||||||
|
y += dy;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case A8R8G8B8_UNORM_TO_RGB_UBYTE:
|
||||||
|
for (row = 0; row < height; row++) {
|
||||||
|
const GLubyte *src = map + y * surf->stride + x * 4;
|
||||||
|
for (col = 0; col < width; col++) {
|
||||||
|
GLuint pixel = ((GLuint *) src)[col];
|
||||||
|
dst[col*3+0] = (pixel >> 16) & 0xff;
|
||||||
|
dst[col*3+1] = (pixel >> 8) & 0xff;
|
||||||
|
dst[col*3+2] = (pixel >> 0) & 0xff;
|
||||||
|
}
|
||||||
|
dst += dstStride;
|
||||||
|
y += dy;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case A8R8G8B8_UNORM_TO_BGRA_UINT:
|
||||||
|
for (row = 0; row < height; row++) {
|
||||||
|
const GLubyte *src = map + y * surf->stride + x * 4;
|
||||||
|
memcpy(dst, src, 4 * width);
|
||||||
|
dst += dstStride;
|
||||||
|
y += dy;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
; /* nothing */
|
||||||
|
}
|
||||||
|
|
||||||
|
screen->surface_unmap(screen, surf);
|
||||||
|
pipe_surface_reference(&surf, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do glReadPixels by getting rows from the framebuffer surface with
|
* Do glReadPixels by getting rows from the framebuffer surface with
|
||||||
* get_tile(). Convert to requested format/type with Mesa image routines.
|
* get_tile(). Convert to requested format/type with Mesa image routines.
|
||||||
@@ -219,6 +337,14 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
|
|||||||
if (!strb)
|
if (!strb)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* try a fast-path readpixels before anything else */
|
||||||
|
if (st_fast_readpixels(ctx, strb, x, y, width, height,
|
||||||
|
format, type, pack, dest)) {
|
||||||
|
/* success! */
|
||||||
|
_mesa_unmap_readpix_pbo(ctx, &clippedPacking);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (format == GL_RGBA && type == GL_FLOAT) {
|
if (format == GL_RGBA && type == GL_FLOAT) {
|
||||||
/* write tile(row) directly into user's buffer */
|
/* write tile(row) directly into user's buffer */
|
||||||
df = (GLfloat *) _mesa_image_address2d(&clippedPacking, dest, width,
|
df = (GLfloat *) _mesa_image_address2d(&clippedPacking, dest, width,
|
||||||
|
Reference in New Issue
Block a user