Module: Mesa
Branch: gallium-mesa-7.4
Commit: ae22ad765843c19d4c853277416a6d52d9918c83
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=ae22ad765843c19d4c853277416a6d52d9918c83

Author: Alan Hourihane <al...@vmware.com>
Date:   Mon Jun 15 15:59:57 2009 +0100

add patches from bug 21997

---

 src/gallium/auxiliary/util/u_linear.c     |   63 +++++---
 src/gallium/auxiliary/util/u_linear.h     |   11 ++-
 src/gallium/include/pipe/p_defines.h      |   10 ++
 src/gallium/include/pipe/p_screen.h       |   17 ++
 src/gallium/include/pipe/p_state.h        |   22 +++
 src/mesa/state_tracker/st_cb_readpixels.c |  252 ++++++++++++++++++++++++++++-
 6 files changed, 346 insertions(+), 29 deletions(-)

diff --git a/src/gallium/auxiliary/util/u_linear.c 
b/src/gallium/auxiliary/util/u_linear.c
index ff7645a..34a7ff3 100644
--- a/src/gallium/auxiliary/util/u_linear.c
+++ b/src/gallium/auxiliary/util/u_linear.c
@@ -6,23 +6,27 @@ void
 pipe_linear_to_tile(size_t src_stride, void *src_ptr,
                    struct pipe_tile_info *t, void *dst_ptr)
 {
-   unsigned x, y, z;
-   char *ptr;
+   unsigned x, y, offset;
+   char *ptr, *dst;
+   unsigned rows = t->rows, cols = t->cols;
    size_t bytes = t->cols * t->block.size;
 
 
    assert(pipe_linear_check_tile(t));
 
    /* lets write lineary to the tiled buffer */
-   for (y = 0; y < t->tiles_y; y++) {
-      for (x = 0; x < t->tiles_x; x++) {
-        /* this inner loop could be replace with SSE magic */
-        ptr = (char*)src_ptr + src_stride * t->rows * y + bytes * x;
-        for (z = 0; z < t->rows; z++) {
-           memcpy(dst_ptr, ptr, bytes);
-           dst_ptr = (char *)dst_ptr + bytes;
-           ptr += src_stride;
-        }
+   for (x = t->left; x < t->right; x += cols) {
+      cols = t->cols - x % t->cols;
+      if (x + cols > t->right)
+         cols = t->right - x;
+      ptr = (char*)src_ptr + (x - t->left) * t->block.size;
+      offset = x / t->cols * t->tile.size + (x % t->cols) * t->block.size;
+      for (y = t->top; y < t->bottom; y++) {
+         dst = (char*)dst_ptr + offset
+                + y / t->rows * t->stride * t->rows
+                + (y % t->rows) * bytes;
+         memcpy(dst, ptr, cols * t->block.size);
+         ptr += src_stride;
       }
    }
 }
@@ -30,20 +34,24 @@ pipe_linear_to_tile(size_t src_stride, void *src_ptr,
 void pipe_linear_from_tile(struct pipe_tile_info *t, void  *src_ptr,
                           size_t dst_stride, void *dst_ptr)
 {
-   unsigned x, y, z;
-   char *ptr;
+   unsigned x, y, offset;
+   unsigned rows = t->rows, cols = t->cols;
+   char *ptr, *src;
    size_t bytes = t->cols * t->block.size;
 
-   /* lets read lineary from the tiled buffer */
-   for (y = 0; y < t->tiles_y; y++) {
-      for (x = 0; x < t->tiles_x; x++) {
-        /* this inner loop could be replace with SSE magic */
-        ptr = (char*)dst_ptr + dst_stride * t->rows * y + bytes * x;
-        for (z = 0; z < t->rows; z++) {
-           memcpy(ptr, src_ptr, bytes);
-           src_ptr = (char *)src_ptr + bytes;
-           ptr += dst_stride;
-        }
+   /* lets write lineary to the tiled buffer */
+   for (x = t->left; x < t->right; x += cols) {
+      cols = t->cols - x % t->cols;
+      if (x + cols > t->right)
+         cols = t->right - x;
+      ptr = (char*)dst_ptr + (x - t->left) * t->block.size;
+      offset = x / t->cols * t->tile.size + (x % t->cols) * t->block.size;
+      for (y = t->top; y < t->bottom; y++) {
+         src = (char*)src_ptr + offset
+                + y / t->rows * t->stride * t->rows
+                + (y % t->rows) * bytes;
+         memcpy(ptr, src, cols * t->block.size);
+         ptr += dst_stride;
       }
    }
 }
@@ -52,7 +60,9 @@ void
 pipe_linear_fill_info(struct pipe_tile_info *t,
                      struct pipe_format_block *block,
                      unsigned tile_width, unsigned tile_height,
-                     unsigned tiles_x, unsigned tiles_y)
+                     unsigned tiles_x, unsigned tiles_y,
+                     unsigned left, unsigned top,
+                     unsigned right, unsigned bottom)
 {
    t->block = *block;
 
@@ -66,4 +76,9 @@ pipe_linear_fill_info(struct pipe_tile_info *t,
    t->tiles_y = tiles_y;
    t->stride = t->cols * t->tiles_x * t->block.size;
    t->size = t->tiles_x * t->tiles_y * t->tile.size;
+
+   t->left = left;
+   t->top = top;
+   t->right = right;
+   t->bottom = bottom;
 }
diff --git a/src/gallium/auxiliary/util/u_linear.h 
b/src/gallium/auxiliary/util/u_linear.h
index e337cfd..c213d37 100644
--- a/src/gallium/auxiliary/util/u_linear.h
+++ b/src/gallium/auxiliary/util/u_linear.h
@@ -12,6 +12,12 @@ struct pipe_tile_info
    unsigned tiles_x;
    unsigned tiles_y;
 
+   /* The region to be converted */
+   unsigned left;
+   unsigned top;
+   unsigned right;
+   unsigned bottom;
+
    /* size of each tile expressed in blocks */
    unsigned cols;
    unsigned rows;
@@ -37,11 +43,14 @@ void pipe_linear_from_tile(struct pipe_tile_info *t, void  
*src_ptr,
  * @tile_height the height of the tile in pixels
  * @tiles_x number of tiles in x axis
  * @tiles_y number of tiles in y axis
+ * @[left,top,right,bottom] the region to be converted, in pixels
  */
 void pipe_linear_fill_info(struct pipe_tile_info *t,
                           struct pipe_format_block *block,
                           unsigned tile_width, unsigned tile_height,
-                          unsigned tiles_x, unsigned tiles_y);
+                          unsigned tiles_x, unsigned tiles_y,
+                          unsigned left, unsigned top,
+                          unsigned right, unsigned bottom);
 
 static INLINE boolean pipe_linear_check_tile(struct pipe_tile_info *t)
 {
diff --git a/src/gallium/include/pipe/p_defines.h 
b/src/gallium/include/pipe/p_defines.h
index a900ed0..ff60c20 100644
--- a/src/gallium/include/pipe/p_defines.h
+++ b/src/gallium/include/pipe/p_defines.h
@@ -194,6 +194,16 @@ enum pipe_texture_target {
 
 
 /**
+ * Transfer object usage flags
+ */
+enum pipe_transfer_usage {
+   PIPE_TRANSFER_READ,
+   PIPE_TRANSFER_WRITE,
+   PIPE_TRANSFER_READ_WRITE  /**< Read/modify/write */
+};
+
+
+/**
  * Buffer usage flags
  */
 #define PIPE_BUFFER_USAGE_CPU_READ  (1 << 0)
diff --git a/src/gallium/include/pipe/p_screen.h 
b/src/gallium/include/pipe/p_screen.h
index 492667c..f34cff9 100644
--- a/src/gallium/include/pipe/p_screen.h
+++ b/src/gallium/include/pipe/p_screen.h
@@ -40,6 +40,7 @@
 
 #include "pipe/p_compiler.h"
 #include "pipe/p_state.h"
+#include "pipe/p_defines.h"
 
 
 
@@ -129,6 +130,22 @@ struct pipe_screen {
    void (*surface_unmap)( struct pipe_screen *,
                           struct pipe_surface *surface );
    
+   /** Get a transfer object for transferring data to/from a texture */
+   struct pipe_transfer *(*get_tex_transfer)(struct pipe_screen *,
+                                             struct pipe_texture *texture,
+                                             unsigned face, unsigned level,
+                                             unsigned zslice,
+                                             enum pipe_transfer_usage usage,
+                                             unsigned x, unsigned y,
+                                             unsigned w, unsigned h);
+
+   void (*tex_transfer_destroy)(struct pipe_transfer *);
+   
+   void *(*transfer_map)( struct pipe_screen *,
+                          struct pipe_transfer *transfer );
+
+   void (*transfer_unmap)( struct pipe_screen *,
+                           struct pipe_transfer *transfer );
 };
 
 
diff --git a/src/gallium/include/pipe/p_state.h 
b/src/gallium/include/pipe/p_state.h
index 13fa9ba..ac60240 100644
--- a/src/gallium/include/pipe/p_state.h
+++ b/src/gallium/include/pipe/p_state.h
@@ -299,6 +299,28 @@ struct pipe_surface
 
 
 /**
+ * Transfer object.  For data transfer to/from a texture.
+ */
+struct pipe_transfer
+{
+   enum pipe_format format;      /**< PIPE_FORMAT_x */
+   unsigned x;                   /**< x offset from start of texture image */
+   unsigned y;                   /**< y offset from start of texture image */
+   unsigned width;               /**< logical width in pixels */
+   unsigned height;              /**< logical height in pixels */
+   struct pipe_format_block block;
+   unsigned nblocksx;            /**< allocated width in blocks */
+   unsigned nblocksy;            /**< allocated height in blocks */
+   unsigned stride;              /**< stride in bytes between rows of blocks */
+   unsigned usage;               /**< PIPE_TRANSFER_*  */
+
+   struct pipe_texture *texture; /**< texture to transfer to/from  */
+   unsigned face;
+   unsigned level;
+   unsigned zslice;
+};
+
+/**
  * Texture object.
  */
 struct pipe_texture
diff --git a/src/mesa/state_tracker/st_cb_readpixels.c 
b/src/mesa/state_tracker/st_cb_readpixels.c
index 646eaff..f3e60dd 100644
--- a/src/mesa/state_tracker/st_cb_readpixels.c
+++ b/src/mesa/state_tracker/st_cb_readpixels.c
@@ -45,6 +45,7 @@
 #include "st_context.h"
 #include "st_cb_bitmap.h"
 #include "st_cb_readpixels.h"
+#include "st_cb_bufferobjects.h"
 #include "st_cb_fbo.h"
 #include "st_format.h"
 #include "st_public.h"
@@ -167,6 +168,238 @@ st_get_color_read_renderbuffer(GLcontext *ctx)
  * \return GL_TRUE for success, GL_FALSE for failure
  */
 static GLboolean
+st_accelerated_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)
+{
+   struct pipe_context *pipe = ctx->st->pipe;
+   struct pipe_screen *screen = pipe->screen;
+   GLfloat temp[MAX_WIDTH][4];
+   const GLubyte *map;
+   GLubyte *dst;
+   GLint row, col, dy, dstStride;
+   struct gl_pixelstore_attrib clippedPacking = *pack;
+   struct pipe_transfer *trans;
+   struct st_buffer_object *st_obj = st_buffer_object(pack->BufferObj);
+   boolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
+
+   enum combination {
+      A8R8G8B8_UNORM_TO_RGBA_UBYTE,
+      A8R8G8B8_UNORM_TO_RGB_UBYTE,
+      A8R8G8B8_UNORM_TO_BGRA_UINT,
+      A8R8G8B8_UNORM_TO_FLOAT
+   } combo;
+
+   if (ctx->_ImageTransferState)
+      return GL_FALSE;
+
+   if (strb->format != PIPE_FORMAT_A8R8G8B8_UNORM)
+      return GL_FALSE;
+
+   if (format == GL_RGBA &&
+       ((type == GL_UNSIGNED_BYTE) || (type == GL_UNSIGNED_INT_8_8_8_8))) {
+      combo = A8R8G8B8_UNORM_TO_RGBA_UBYTE;
+   }
+   else if (format == GL_RGB && type == GL_UNSIGNED_BYTE) {
+      combo = A8R8G8B8_UNORM_TO_RGB_UBYTE;
+   }
+   else if (format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) {
+      combo = A8R8G8B8_UNORM_TO_BGRA_UINT;
+   }
+   else if (type == GL_FLOAT) {
+      combo = A8R8G8B8_UNORM_TO_FLOAT;
+   }
+   else {
+      return GL_FALSE;
+   }
+
+   /* Try issue a copy to PBO if possible */
+   if (st_obj && (
+       (combo == A8R8G8B8_UNORM_TO_RGBA_UBYTE) ||
+       (combo == A8R8G8B8_UNORM_TO_BGRA_UINT))) {
+      struct pipe_surface *surface = NULL;
+      struct pipe_surface *surf = NULL;
+      struct pipe_texture template;
+      struct pipe_texture *tex;
+      GLuint stride = (width * 4);
+
+      surf = screen->get_tex_surface(screen, strb->texture,  0, 0, 0,
+                                     PIPE_BUFFER_USAGE_GPU_READ);
+      if (!surf) {
+         return GL_FALSE;
+      }
+
+      template.target = PIPE_TEXTURE_2D;
+      template.compressed = 0;
+      template.format = st_choose_format(pipe, GL_RGBA, PIPE_TEXTURE_2D,
+                                         PIPE_TEXTURE_USAGE_RENDER_TARGET);
+      if (template.format != PIPE_FORMAT_NONE) {
+         pipe_surface_reference(&surf, NULL);
+         return GL_FALSE;
+      }
+      pf_get_block(template.format, &template.block);
+      template.width[0] = width;
+      template.height[0] = height;
+      template.depth[0] = 1;
+      template.last_level = 0;
+      template.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
+
+      tex = pipe->screen->texture_blanket( pipe->screen,
+                 &template,
+                 &stride,
+                 st_obj->buffer );
+      if (!tex) {
+         pipe_surface_reference(&surf, NULL);
+         return GL_FALSE;
+      }
+
+      surface = pipe->screen->get_tex_surface( pipe->screen,
+                     tex, 0, 0, 0,
+                     PIPE_BUFFER_USAGE_GPU_WRITE );
+
+      if (!surface) {
+         pipe_texture_reference(&tex, NULL);
+         pipe_surface_reference(&surf, NULL);
+         return GL_FALSE;
+      }
+
+      pipe->surface_copy(pipe,
+                         do_flip,
+                         /* dest */
+                         surface,
+                         0, 0,
+                         /* src */
+                         surf,
+                         x, y,
+                         /* size */
+                         width, height);
+
+      pipe_surface_reference(&surface, NULL);
+      pipe_texture_reference(&tex, NULL);
+      pipe_surface_reference(&surf, NULL);
+
+      return GL_TRUE;
+   }
+
+   if (!screen->get_tex_transfer ||
+       !screen->tex_transfer_destroy ||
+       !screen->transfer_map ||
+       !screen->transfer_unmap) {
+      return GL_FALSE;
+   }
+
+   if (do_flip) {
+      y = strb->texture->height[0] - y - height;
+   }
+
+   trans = screen->get_tex_transfer(screen, strb->texture,
+                 0, 0, 0,
+                 PIPE_TRANSFER_READ, x, y,
+                 width, height);
+   if (!trans) {
+      return GL_FALSE;
+   }
+
+   map = screen->transfer_map(screen, trans);
+   if (!map) {
+      screen->tex_transfer_destroy(trans);
+      return GL_FALSE;
+   }
+
+   if (do_flip) {
+      y = height - 1;
+      dy = -1;
+   }
+   else {
+      y = 0;
+      dy = 1;
+   }
+
+   dest = _mesa_map_readpix_pbo(ctx, &clippedPacking, dest);
+   if (!dest)
+      return GL_FALSE;
+
+   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 * trans->stride;
+         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 * trans->stride;
+         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 * trans->stride;
+         memcpy(dst, src, 4 * width);
+         dst += dstStride;
+         y += dy;
+      }
+      break;
+   case A8R8G8B8_UNORM_TO_FLOAT:
+      if (format == GL_RGBA) {
+         /* write tile(row) directly into user's buffer */
+         for (row = 0; row < height; row++) {
+            const GLubyte *src = map + y * trans->stride;
+            pipe_tile_raw_to_rgba(strb->format, src, width, 1, dst, dstStride);
+            dst += dstStride;
+            y += dy;
+         }
+      }
+      else {
+         for (row = 0; row < height; row++) {
+            const GLubyte *src = map + y * trans->stride;
+            pipe_tile_raw_to_rgba(strb->format, src, width, 1, temp, 
dstStride);
+            _mesa_pack_rgba_span_float(ctx, width, temp, format, type, dst,
+                                       &clippedPacking, 0);
+            dst += dstStride;
+            y += dy;
+         }
+      }
+      break;
+   default:
+      ; /* nothing */
+   }
+
+   _mesa_unmap_readpix_pbo(ctx, &clippedPacking);
+
+   screen->transfer_unmap(screen, trans);
+   screen->tex_transfer_destroy(trans);
+
+   return GL_TRUE;
+}
+
+
+/**
+ * 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,
@@ -313,15 +546,17 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei 
width, GLsizei height,
       return;
    }
 
-   dest = _mesa_map_readpix_pbo(ctx, &clippedPacking, dest);
-   if (!dest)
-      return;
-
    /* make sure rendering has completed */
    st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
 
    if (format == GL_STENCIL_INDEX) {
+      dest = _mesa_map_readpix_pbo(ctx, &clippedPacking, dest);
+      if (!dest)
+         return;
+
       st_read_stencil_pixels(ctx, x, y, width, height, type, pack, dest);
+
+      _mesa_unmap_readpix_pbo(ctx, &clippedPacking);
       return;
    }
    else if (format == GL_DEPTH_COMPONENT) {
@@ -335,6 +570,15 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei 
width, GLsizei height,
    if (!strb)
       return;
 
+   /* try an accelerated readpixels before anything else */
+   if (st_accelerated_readpixels(ctx, strb, x, y, width, height,
+                                 format, type, pack, dest))
+      return;
+
+   dest = _mesa_map_readpix_pbo(ctx, &clippedPacking, dest);
+   if (!dest)
+      return;
+
    /* try a fast-path readpixels before anything else */
    if (st_fast_readpixels(ctx, strb, x, y, width, height,
                           format, type, pack, dest)) {

_______________________________________________
mesa-commit mailing list
mesa-commit@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-commit

Reply via email to