st_cb_readpixels.c

Go to the documentation of this file.
00001 /**************************************************************************
00002  * 
00003  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
00004  * All Rights Reserved.
00005  * 
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * copy of this software and associated documentation files (the
00008  * "Software"), to deal in the Software without restriction, including
00009  * without limitation the rights to use, copy, modify, merge, publish,
00010  * distribute, sub license, and/or sell copies of the Software, and to
00011  * permit persons to whom the Software is furnished to do so, subject to
00012  * the following conditions:
00013  * 
00014  * The above copyright notice and this permission notice (including the
00015  * next paragraph) shall be included in all copies or substantial portions
00016  * of the Software.
00017  * 
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
00021  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
00022  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
00023  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
00024  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025  * 
00026  **************************************************************************/
00027 
00028 
00036 #include "main/imports.h"
00037 #include "main/bufferobj.h"
00038 #include "main/context.h"
00039 #include "main/image.h"
00040 
00041 #include "pipe/p_context.h"
00042 #include "pipe/p_defines.h"
00043 #include "pipe/p_inlines.h"
00044 #include "util/u_tile.h"
00045 #include "st_context.h"
00046 #include "st_cb_bitmap.h"
00047 #include "st_cb_readpixels.h"
00048 #include "st_cb_fbo.h"
00049 #include "st_format.h"
00050 #include "st_public.h"
00051 
00052 
00057 void
00058 st_read_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
00059                        GLsizei width, GLsizei height, GLenum type,
00060                        const struct gl_pixelstore_attrib *packing,
00061                        GLvoid *pixels)
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 }
00135 
00136 
00142 struct st_renderbuffer *
00143 st_get_color_read_renderbuffer(GLcontext *ctx)
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 }
00163 
00164 
00169 static GLboolean
00170 st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb,
00171                    GLint x, GLint y, GLsizei width, GLsizei height,
00172                    GLenum format, GLenum type,
00173                    const struct gl_pixelstore_attrib *pack,
00174                    GLvoid *dest)
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 }
00281 
00282 
00288 static void
00289 st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
00290               GLenum format, GLenum type,
00291               const struct gl_pixelstore_attrib *pack,
00292               GLvoid *dest)
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 }
00459 
00460 
00461 void st_init_readpixels_functions(struct dd_function_table *functions)
00462 {
00463    functions->ReadPixels = st_readpixels;
00464 }

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