st_cb_readpixels.c File Reference

Include dependency graph for st_cb_readpixels.c:

Go to the source code of this file.

Functions

void st_read_stencil_pixels (GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, const struct gl_pixelstore_attrib *packing, GLvoid *pixels)
 glReadPixels interface to pipe
struct st_renderbufferst_get_color_read_renderbuffer (GLcontext *ctx)
 Return renderbuffer to use for reading color pixels for glRead/CopyPixel commands.
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)
 Try to do glReadPixels in a fast manner for common cases.
static void st_readpixels (GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *pack, GLvoid *dest)
 Do glReadPixels by getting rows from the framebuffer surface with get_tile().
void st_init_readpixels_functions (struct dd_function_table *functions)


Function Documentation

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 
) [static]

Try to do glReadPixels in a fast manner for common cases.

Returns:
GL_TRUE for success, GL_FALSE for failure

Definition at line 170 of file st_cb_readpixels.c.

References st_renderbuffer::format, pipe_screen::get_tex_surface, pipe_surface::height, PIPE_BUFFER_USAGE_CPU_READ, PIPE_FORMAT_A8R8G8B8_UNORM, pipe_surface_reference(), pipe_context::screen, st_fb_orientation(), pipe_surface::stride, pipe_screen::surface_map, pipe_screen::surface_unmap, st_renderbuffer::texture, and Y_0_TOP.

00175 {
00176    enum combination {
00177       A8R8G8B8_UNORM_TO_RGBA_UBYTE,
00178       A8R8G8B8_UNORM_TO_RGB_UBYTE,
00179       A8R8G8B8_UNORM_TO_BGRA_UINT
00180    } combo;
00181 
00182    if (ctx->_ImageTransferState)
00183       return GL_FALSE;
00184 
00185    if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM &&
00186        format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
00187       combo = A8R8G8B8_UNORM_TO_RGBA_UBYTE;
00188    }
00189    else if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM &&
00190             format == GL_RGB && type == GL_UNSIGNED_BYTE) {
00191       combo = A8R8G8B8_UNORM_TO_RGB_UBYTE;
00192    }
00193    else if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM &&
00194             format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) {
00195       combo = A8R8G8B8_UNORM_TO_BGRA_UINT;
00196    }
00197    else {
00198       return GL_FALSE;
00199    }
00200 
00201    /*printf("st_fast_readpixels combo %d\n", (GLint) combo);*/
00202 
00203    {
00204       struct pipe_context *pipe = ctx->st->pipe;
00205       struct pipe_screen *screen = pipe->screen;
00206       struct pipe_surface *surf;
00207       const GLubyte *map;
00208       GLubyte *dst;
00209       GLint row, col, dy, dstStride;
00210 
00211       surf = screen->get_tex_surface(screen, strb->texture,  0, 0, 0,
00212                                      PIPE_BUFFER_USAGE_CPU_READ);
00213       if (!surf) {
00214          return GL_FALSE;
00215       }
00216 
00217       map = screen->surface_map(screen, surf, PIPE_BUFFER_USAGE_CPU_READ);
00218       if (!map) {
00219          pipe_surface_reference(&surf, NULL);
00220          return GL_FALSE;
00221       }
00222 
00223       if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
00224          y = surf->height - y - 1;
00225          dy = -1;
00226       }
00227       else {
00228          dy = 1;
00229       }
00230 
00231       dst = _mesa_image_address2d(pack, dest, width, height,
00232                                   format, type, 0, 0);
00233       dstStride = _mesa_image_row_stride(pack, width, format, type);
00234 
00235       switch (combo) {
00236       case A8R8G8B8_UNORM_TO_RGBA_UBYTE:
00237          for (row = 0; row < height; row++) {
00238             const GLubyte *src = map + y * surf->stride + x * 4;
00239             for (col = 0; col < width; col++) {
00240                GLuint pixel = ((GLuint *) src)[col];
00241                dst[col*4+0] = (pixel >> 16) & 0xff;
00242                dst[col*4+1] = (pixel >>  8) & 0xff;
00243                dst[col*4+2] = (pixel >>  0) & 0xff;
00244                dst[col*4+3] = (pixel >> 24) & 0xff;
00245             }
00246             dst += dstStride;
00247             y += dy;
00248          }
00249          break;
00250       case A8R8G8B8_UNORM_TO_RGB_UBYTE:
00251          for (row = 0; row < height; row++) {
00252             const GLubyte *src = map + y * surf->stride + x * 4;
00253             for (col = 0; col < width; col++) {
00254                GLuint pixel = ((GLuint *) src)[col];
00255                dst[col*3+0] = (pixel >> 16) & 0xff;
00256                dst[col*3+1] = (pixel >>  8) & 0xff;
00257                dst[col*3+2] = (pixel >>  0) & 0xff;
00258             }
00259             dst += dstStride;
00260             y += dy;
00261          }
00262          break;
00263       case A8R8G8B8_UNORM_TO_BGRA_UINT:
00264          for (row = 0; row < height; row++) {
00265             const GLubyte *src = map + y * surf->stride + x * 4;
00266             memcpy(dst, src, 4 * width);
00267             dst += dstStride;
00268             y += dy;
00269          }
00270          break;
00271       default:
00272          ; /* nothing */
00273       }
00274 
00275       screen->surface_unmap(screen, surf);
00276       pipe_surface_reference(&surf, NULL);
00277    }
00278 
00279    return GL_TRUE;
00280 }

struct st_renderbuffer* st_get_color_read_renderbuffer ( GLcontext *  ctx  )  [read]

Return renderbuffer to use for reading color pixels for glRead/CopyPixel commands.

Special care is needed for the front buffer.

Definition at line 143 of file st_cb_readpixels.c.

References FRONT_STATUS_COPY_OF_BACK, and st_renderbuffer().

00144 {
00145    struct gl_framebuffer *fb = ctx->ReadBuffer;
00146    struct st_renderbuffer *strb =
00147       st_renderbuffer(fb->_ColorReadBuffer);
00148    struct st_renderbuffer *front = 
00149       st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
00150 
00151    if (strb == front
00152        && ctx->st->frontbuffer_status == FRONT_STATUS_COPY_OF_BACK) {
00153       /* reading from front color buffer, which is a logical copy of the
00154        * back color buffer.
00155        */
00156       struct st_renderbuffer *back = 
00157          st_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
00158       strb = back;
00159    }
00160 
00161    return strb;
00162 }

void st_init_readpixels_functions ( struct dd_function_table *  functions  ) 

Definition at line 461 of file st_cb_readpixels.c.

References st_readpixels().

00462 {
00463    functions->ReadPixels = st_readpixels;
00464 }

void st_read_stencil_pixels ( GLcontext *  ctx,
GLint  x,
GLint  y,
GLsizei  width,
GLsizei  height,
GLenum  type,
const struct gl_pixelstore_attrib *  packing,
GLvoid *  pixels 
)

glReadPixels interface to pipe

Author:
Brian Paul Special case for reading stencil buffer. For color/depth we use get_tile(). For stencil, map the stencil buffer.

Definition at line 58 of file st_cb_readpixels.c.

References assert, ASSERT, pipe_surface::format, pipe_screen::get_tex_surface, MAX_WIDTH, PIPE_BUFFER_USAGE_CPU_READ, PIPE_FORMAT_S8_UNORM, PIPE_FORMAT_S8Z24_UNORM, PIPE_FORMAT_Z24S8_UNORM, pipe_surface_reference(), st_fb_orientation(), st_renderbuffer(), pipe_surface::stride, pipe_screen::surface_map, pipe_screen::surface_unmap, st_renderbuffer::texture, and Y_0_TOP.

00062 {
00063    struct gl_framebuffer *fb = ctx->ReadBuffer;
00064    struct pipe_screen *screen = ctx->st->pipe->screen;
00065    struct st_renderbuffer *strb = st_renderbuffer(fb->_StencilBuffer);
00066    struct pipe_surface *ps;
00067    ubyte *stmap;
00068    GLint j;
00069 
00070    /* Create a CPU-READ surface/view into the renderbuffer's texture */
00071    ps = screen->get_tex_surface(screen, strb->texture,  0, 0, 0,
00072                                 PIPE_BUFFER_USAGE_CPU_READ);
00073 
00074    /* map the stencil buffer */
00075    stmap = screen->surface_map(screen, ps, PIPE_BUFFER_USAGE_CPU_READ);
00076 
00077    /* width should never be > MAX_WIDTH since we did clipping earlier */
00078    ASSERT(width <= MAX_WIDTH);
00079 
00080    /* process image row by row */
00081    for (j = 0; j < height; j++, y++) {
00082       GLvoid *dest;
00083       GLstencil values[MAX_WIDTH];
00084       GLint srcY;
00085 
00086       if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
00087          srcY = ctx->DrawBuffer->Height - y - 1;
00088       }
00089       else {
00090          srcY = y;
00091       }
00092 
00093       /* get stencil values */
00094       switch (ps->format) {
00095       case PIPE_FORMAT_S8_UNORM:
00096          {
00097             const ubyte *src = stmap + srcY * ps->stride + x;
00098             memcpy(values, src, width);
00099          }
00100          break;
00101       case PIPE_FORMAT_S8Z24_UNORM:
00102          {
00103             const uint *src = (uint *) (stmap + srcY * ps->stride + x*4);
00104             GLint k;
00105             for (k = 0; k < width; k++) {
00106                values[k] = src[k] >> 24;
00107             }
00108          }
00109          break;
00110       case PIPE_FORMAT_Z24S8_UNORM:
00111          {
00112             const uint *src = (uint *) (stmap + srcY * ps->stride + x*4);
00113             GLint k;
00114             for (k = 0; k < width; k++) {
00115                values[k] = src[k] & 0xff;
00116             }
00117          }
00118          break;
00119       default:
00120          assert(0);
00121       }
00122 
00123       /* store */
00124       dest = _mesa_image_address2d(packing, pixels, width, height,
00125                                    GL_STENCIL_INDEX, type, j, 0);
00126 
00127       _mesa_pack_stencil_span(ctx, width, type, dest, values, packing);
00128    }
00129 
00130 
00131    /* unmap the stencil buffer */
00132    screen->surface_unmap(screen, ps);
00133    pipe_surface_reference(&ps, NULL);
00134 }

static void st_readpixels ( GLcontext *  ctx,
GLint  x,
GLint  y,
GLsizei  width,
GLsizei  height,
GLenum  format,
GLenum  type,
const struct gl_pixelstore_attrib *  pack,
GLvoid *  dest 
) [static]

Do glReadPixels by getting rows from the framebuffer surface with get_tile().

Convert to requested format/type with Mesa image routines. Image transfer ops are done in software too.

Definition at line 289 of file st_cb_readpixels.c.

References assert, st_renderbuffer::Base, pipe_surface::format, pipe_screen::get_tex_surface, MAX_WIDTH, PIPE_BUFFER_USAGE_CPU_READ, PIPE_FLUSH_RENDER_CACHE, PIPE_FORMAT_S8Z24_UNORM, PIPE_FORMAT_X8Z24_UNORM, PIPE_FORMAT_Z16_UNORM, PIPE_FORMAT_Z32_UNORM, pipe_get_tile_raw(), pipe_get_tile_rgba(), pipe_surface_reference(), pipe_context::screen, st_fast_readpixels(), st_fb_orientation(), st_flush(), st_get_color_read_renderbuffer(), st_read_stencil_pixels(), st_renderbuffer(), st_renderbuffer::texture, and Y_0_TOP.

00293 {
00294    struct pipe_context *pipe = ctx->st->pipe;
00295    struct pipe_screen *screen = pipe->screen;
00296    GLfloat temp[MAX_WIDTH][4];
00297    const GLbitfield transferOps = ctx->_ImageTransferState;
00298    GLsizei i, j;
00299    GLint yStep, dfStride;
00300    GLfloat *df;
00301    struct st_renderbuffer *strb;
00302    struct gl_pixelstore_attrib clippedPacking = *pack;
00303    struct pipe_surface *surf;
00304 
00305    assert(ctx->ReadBuffer->Width > 0);
00306 
00307    /* XXX convolution not done yet */
00308    assert((transferOps & IMAGE_CONVOLUTION_BIT) == 0);
00309 
00310    /* Do all needed clipping here, so that we can forget about it later */
00311    if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
00312       /* The ReadPixels surface is totally outside the window bounds */
00313       return;
00314    }
00315 
00316    dest = _mesa_map_readpix_pbo(ctx, &clippedPacking, dest);
00317    if (!dest)
00318       return;
00319 
00320    /* make sure rendering has completed */
00321    st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
00322 
00323    if (format == GL_STENCIL_INDEX) {
00324       st_read_stencil_pixels(ctx, x, y, width, height, type, pack, dest);
00325       return;
00326    }
00327    else if (format == GL_DEPTH_COMPONENT) {
00328       strb = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
00329    }
00330    else {
00331       /* Read color buffer */
00332       strb = st_get_color_read_renderbuffer(ctx);
00333    }
00334 
00335    if (!strb)
00336       return;
00337 
00338    /* try a fast-path readpixels before anything else */
00339    if (st_fast_readpixels(ctx, strb, x, y, width, height,
00340                           format, type, pack, dest)) {
00341       /* success! */
00342       _mesa_unmap_readpix_pbo(ctx, &clippedPacking);
00343       return;
00344    }
00345 
00346    if (format == GL_RGBA && type == GL_FLOAT) {
00347       /* write tile(row) directly into user's buffer */
00348       df = (GLfloat *) _mesa_image_address2d(&clippedPacking, dest, width,
00349                                              height, format, type, 0, 0);
00350       dfStride = width * 4;
00351    }
00352    else {
00353       /* write tile(row) into temp row buffer */
00354       df = (GLfloat *) temp;
00355       dfStride = 0;
00356    }
00357 
00358    /* determine bottom-to-top vs. top-to-bottom order */
00359    if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
00360       y = strb->Base.Height - 1 - y;
00361       yStep = -1;
00362    }
00363    else {
00364       yStep = 1;
00365    }
00366 
00367    /* Create a CPU-READ surface/view into the renderbuffer's texture */
00368    surf = screen->get_tex_surface(screen, strb->texture,  0, 0, 0,
00369                                   PIPE_BUFFER_USAGE_CPU_READ);
00370 
00371    /*
00372     * Copy pixels from pipe_surface to user memory
00373     */
00374    {
00375       /* dest of first pixel in client memory */
00376       GLubyte *dst = _mesa_image_address2d(&clippedPacking, dest, width,
00377                                            height, format, type, 0, 0);
00378       /* dest row stride */
00379       const GLint dstStride = _mesa_image_row_stride(&clippedPacking, width,
00380                                                      format, type);
00381 
00382       if (surf->format == PIPE_FORMAT_S8Z24_UNORM ||
00383           surf->format == PIPE_FORMAT_X8Z24_UNORM) {
00384          if (format == GL_DEPTH_COMPONENT) {
00385             for (i = 0; i < height; i++) {
00386                GLuint ztemp[MAX_WIDTH];
00387                GLfloat zfloat[MAX_WIDTH];
00388                const double scale = 1.0 / ((1 << 24) - 1);
00389                pipe_get_tile_raw(surf, x, y, width, 1, ztemp, 0);
00390                y += yStep;
00391                for (j = 0; j < width; j++) {
00392                   zfloat[j] = (float) (scale * (ztemp[j] & 0xffffff));
00393                }
00394                _mesa_pack_depth_span(ctx, width, dst, type,
00395                                      zfloat, &clippedPacking);
00396                dst += dstStride;
00397             }
00398          }
00399          else {
00400             /* untested, but simple: */
00401             assert(format == GL_DEPTH_STENCIL_EXT);
00402             for (i = 0; i < height; i++) {
00403                pipe_get_tile_raw(surf, x, y, width, 1, dst, 0);
00404                y += yStep;
00405                dst += dstStride;
00406             }
00407          }
00408       }
00409       else if (surf->format == PIPE_FORMAT_Z16_UNORM) {
00410          for (i = 0; i < height; i++) {
00411             GLushort ztemp[MAX_WIDTH];
00412             GLfloat zfloat[MAX_WIDTH];
00413             const double scale = 1.0 / 0xffff;
00414             pipe_get_tile_raw(surf, x, y, width, 1, ztemp, 0);
00415             y += yStep;
00416             for (j = 0; j < width; j++) {
00417                zfloat[j] = (float) (scale * ztemp[j]);
00418             }
00419             _mesa_pack_depth_span(ctx, width, dst, type,
00420                                   zfloat, &clippedPacking);
00421             dst += dstStride;
00422          }
00423       }
00424       else if (surf->format == PIPE_FORMAT_Z32_UNORM) {
00425          for (i = 0; i < height; i++) {
00426             GLuint ztemp[MAX_WIDTH];
00427             GLfloat zfloat[MAX_WIDTH];
00428             const double scale = 1.0 / 0xffffffff;
00429             pipe_get_tile_raw(surf, x, y, width, 1, ztemp, 0);
00430             y += yStep;
00431             for (j = 0; j < width; j++) {
00432                zfloat[j] = (float) (scale * ztemp[j]);
00433             }
00434             _mesa_pack_depth_span(ctx, width, dst, type,
00435                                   zfloat, &clippedPacking);
00436             dst += dstStride;
00437          }
00438       }
00439       else {
00440          /* RGBA format */
00441          /* Do a row at a time to flip image data vertically */
00442          for (i = 0; i < height; i++) {
00443             pipe_get_tile_rgba(surf, x, y, width, 1, df);
00444             y += yStep;
00445             df += dfStride;
00446             if (!dfStride) {
00447                _mesa_pack_rgba_span_float(ctx, width, temp, format, type, dst,
00448                                           &clippedPacking, transferOps);
00449                dst += dstStride;
00450             }
00451          }
00452       }
00453    }
00454 
00455    pipe_surface_reference(&surf, NULL);
00456 
00457    _mesa_unmap_readpix_pbo(ctx, &clippedPacking);
00458 }


Generated on Tue Sep 29 06:25:53 2009 for Gallium3D by  doxygen 1.5.4