mesa: move PBO-related functions into a new file
[mesa.git] / src / mesa / state_tracker / st_cb_readpixels.c
index 6b1fdf3ecd0704cda99250ca4025802d20315cdf..f8da2a4d158ef356c8de0b7b270200440abe91a3 100644 (file)
 #include "main/bufferobj.h"
 #include "main/context.h"
 #include "main/image.h"
+#include "main/pack.h"
+#include "main/pbo.h"
 
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
+#include "util/u_format.h"
 #include "util/u_inlines.h"
 #include "util/u_tile.h"
 
 #include "st_debug.h"
 #include "st_context.h"
+#include "st_atom.h"
+#include "st_cb_bitmap.h"
 #include "st_cb_readpixels.h"
 #include "st_cb_fbo.h"
-#include "st_public.h"
-#include "st_texture.h"
-#include "st_inlines.h"
 
 /**
  * Special case for reading stencil buffer.
  * For color/depth we use get_tile().  For stencil, map the stencil buffer.
  */
 void
-st_read_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
+st_read_stencil_pixels(struct gl_context *ctx, GLint x, GLint y,
                        GLsizei width, GLsizei height,
                        GLenum format, GLenum type,
                        const struct gl_pixelstore_attrib *packing,
                        GLvoid *pixels)
 {
    struct gl_framebuffer *fb = ctx->ReadBuffer;
-   struct pipe_screen *screen = ctx->st->pipe->screen;
+   struct pipe_context *pipe = st_context(ctx)->pipe;
    struct st_renderbuffer *strb = st_renderbuffer(fb->_StencilBuffer);
    struct pipe_transfer *pt;
    ubyte *stmap;
    GLint j;
 
+   if (strb->Base.Wrapped) {
+      strb = st_renderbuffer(strb->Base.Wrapped);
+   }
+
    if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
       y = ctx->DrawBuffer->Height - y - height;
    }
 
    /* Create a read transfer from the renderbuffer's texture */
 
-   pt = st_cond_flush_get_tex_transfer(st_context(ctx), strb->texture,
-                                      0, 0, 0,
-                                      PIPE_TRANSFER_READ, x, y,
-                                      width, height);
+   pt = pipe_get_transfer(pipe, strb->texture,
+                          0, 0,
+                          PIPE_TRANSFER_READ,
+                          x, y, width, height);
 
    /* map the stencil buffer */
-   stmap = screen->transfer_map(screen, pt);
+   stmap = pipe_transfer_map(pipe, pt);
 
    /* width should never be > MAX_WIDTH since we did clipping earlier */
    ASSERT(width <= MAX_WIDTH);
@@ -101,14 +107,14 @@ st_read_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
       }
 
       /* get stencil (and Z) values */
-      switch (pt->texture->format) {
-      case PIPE_FORMAT_S8_UNORM:
+      switch (pt->resource->format) {
+      case PIPE_FORMAT_S8_USCALED:
          {
             const ubyte *src = stmap + srcY * pt->stride;
             memcpy(sValues, src, width);
          }
          break;
-      case PIPE_FORMAT_S8Z24_UNORM:
+      case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
          if (format == GL_DEPTH_STENCIL) {
             const uint *src = (uint *) (stmap + srcY * pt->stride);
             const GLfloat scale = 1.0f / (0xffffff);
@@ -126,7 +132,7 @@ st_read_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
             }
          }
          break;
-      case PIPE_FORMAT_Z24S8_UNORM:
+      case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
          if (format == GL_DEPTH_STENCIL) {
             const uint *src = (uint *) (stmap + srcY * pt->stride);
             const GLfloat scale = 1.0f / (0xffffff);
@@ -161,34 +167,21 @@ st_read_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
    }
 
    /* unmap the stencil buffer */
-   screen->transfer_unmap(screen, pt);
-   screen->tex_transfer_destroy(pt);
+   pipe_transfer_unmap(pipe, pt);
+   pipe->transfer_destroy(pipe, pt);
 }
 
 
 /**
  * Return renderbuffer to use for reading color pixels for glRead/CopyPixel
  * commands.
- * Special care is needed for the front buffer.
  */
 struct st_renderbuffer *
-st_get_color_read_renderbuffer(GLcontext *ctx)
+st_get_color_read_renderbuffer(struct gl_context *ctx)
 {
    struct gl_framebuffer *fb = ctx->ReadBuffer;
    struct st_renderbuffer *strb =
       st_renderbuffer(fb->_ColorReadBuffer);
-   struct st_renderbuffer *front = 
-      st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
-
-   if (strb == front
-       && ctx->st->frontbuffer_status == FRONT_STATUS_COPY_OF_BACK) {
-      /* reading from front color buffer, which is a logical copy of the
-       * back color buffer.
-       */
-      struct st_renderbuffer *back = 
-         st_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
-      strb = back;
-   }
 
    return strb;
 }
@@ -199,7 +192,7 @@ st_get_color_read_renderbuffer(GLcontext *ctx)
  * \return GL_TRUE for success, GL_FALSE for failure
  */
 static GLboolean
-st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb,
+st_fast_readpixels(struct gl_context *ctx, struct st_renderbuffer *strb,
                    GLint x, GLint y, GLsizei width, GLsizei height,
                    GLenum format, GLenum type,
                    const struct gl_pixelstore_attrib *pack,
@@ -214,15 +207,15 @@ st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb,
    if (ctx->_ImageTransferState)
       return GL_FALSE;
 
-   if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM &&
+   if (strb->format == PIPE_FORMAT_B8G8R8A8_UNORM &&
        format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
       combo = A8R8G8B8_UNORM_TO_RGBA_UBYTE;
    }
-   else if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM &&
+   else if (strb->format == PIPE_FORMAT_B8G8R8A8_UNORM &&
             format == GL_RGB && type == GL_UNSIGNED_BYTE) {
       combo = A8R8G8B8_UNORM_TO_RGB_UBYTE;
    }
-   else if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM &&
+   else if (strb->format == PIPE_FORMAT_B8G8R8A8_UNORM &&
             format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) {
       combo = A8R8G8B8_UNORM_TO_BGRA_UINT;
    }
@@ -233,36 +226,41 @@ st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb,
    /*printf("st_fast_readpixels combo %d\n", (GLint) combo);*/
 
    {
-      struct pipe_context *pipe = ctx->st->pipe;
-      struct pipe_screen *screen = pipe->screen;
+      struct pipe_context *pipe = st_context(ctx)->pipe;
       struct pipe_transfer *trans;
       const GLubyte *map;
       GLubyte *dst;
       GLint row, col, dy, dstStride;
 
       if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
+         /* convert GL Y to Gallium Y */
          y = strb->texture->height0 - y - height;
       }
 
-      trans = st_cond_flush_get_tex_transfer(st_context(ctx), strb->texture,
-                                            0, 0, 0,
-                                            PIPE_TRANSFER_READ, x, y,
-                                            width, height);
+      trans = pipe_get_transfer(pipe, strb->texture,
+                                0, 0,
+                                PIPE_TRANSFER_READ,
+                                x, y, width, height);
       if (!trans) {
          return GL_FALSE;
       }
 
-      map = screen->transfer_map(screen, trans);
+      map = pipe_transfer_map(pipe, trans);
       if (!map) {
-         screen->tex_transfer_destroy(trans);
+         pipe->transfer_destroy(pipe, trans);
          return GL_FALSE;
       }
 
+      /* We always write to the user/dest buffer from low addr to high addr
+       * but the read order depends on renderbuffer orientation
+       */
       if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
+         /* read source rows from bottom to top */
          y = height - 1;
          dy = -1;
       }
       else {
+         /* read source rows from top to bottom */
          y = 0;
          dy = 1;
       }
@@ -311,8 +309,8 @@ st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb,
          ; /* nothing */
       }
 
-      screen->transfer_unmap(screen, trans);
-      screen->tex_transfer_destroy(trans);
+      pipe_transfer_unmap(pipe, trans);
+      pipe->transfer_destroy(pipe, trans);
    }
 
    return GL_TRUE;
@@ -325,14 +323,14 @@ st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb,
  * Image transfer ops are done in software too.
  */
 static void
-st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
+st_readpixels(struct gl_context *ctx, 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];
+   struct st_context *st = st_context(ctx);
+   struct pipe_context *pipe = st->pipe;
+   GLfloat (*temp)[4];
    const GLbitfield transferOps = ctx->_ImageTransferState;
    GLsizei i, j;
    GLint yStep, dfStride;
@@ -340,11 +338,11 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
    struct st_renderbuffer *strb;
    struct gl_pixelstore_attrib clippedPacking = *pack;
    struct pipe_transfer *trans;
+   enum pipe_format pformat;
 
    assert(ctx->ReadBuffer->Width > 0);
 
-   /* XXX convolution not done yet */
-   assert((transferOps & IMAGE_CONVOLUTION_BIT) == 0);
+   st_validate_state(st);
 
    /* Do all needed clipping here, so that we can forget about it later */
    if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
@@ -352,12 +350,12 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
       return;
    }
 
+   st_flush_bitmap_cache(st);
+
    dest = _mesa_map_pbo_dest(ctx, &clippedPacking, dest);
    if (!dest)
       return;
 
-   st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
-
    if (format == GL_STENCIL_INDEX ||
        format == GL_DEPTH_STENCIL) {
       st_read_stencil_pixels(ctx, x, y, width, height,
@@ -366,6 +364,9 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
    }
    else if (format == GL_DEPTH_COMPONENT) {
       strb = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
+      if (strb->Base.Wrapped) {
+         strb = st_renderbuffer(strb->Base.Wrapped);
+      }
    }
    else {
       /* Read color buffer */
@@ -383,6 +384,13 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
       return;
    }
 
+   /* allocate temp pixel row buffer */
+   temp = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
+   if (!temp) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
+      return;
+   }
+
    if (format == GL_RGBA && type == GL_FLOAT) {
       /* write tile(row) directly into user's buffer */
       df = (GLfloat *) _mesa_image_address2d(&clippedPacking, dest, width,
@@ -396,14 +404,15 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
    }
 
    if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
+      /* convert GL Y to Gallium Y */
       y = strb->Base.Height - y - height;
    }
 
    /* Create a read transfer from the renderbuffer's texture */
-   trans = st_cond_flush_get_tex_transfer(st_context(ctx), strb->texture,
-                                         0, 0, 0,
-                                         PIPE_TRANSFER_READ, x, y,
-                                         width, height);
+   trans = pipe_get_transfer(pipe, strb->texture,
+                             0, 0,
+                             PIPE_TRANSFER_READ,
+                             x, y, width, height);
 
    /* determine bottom-to-top vs. top-to-bottom order */
    if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
@@ -415,6 +424,9 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
       yStep = 1;
    }
 
+   /* possibly convert sRGB format to linear RGB format */
+   pformat = util_format_linear(trans->resource->format);
+
    if (ST_DEBUG & DEBUG_FALLBACK)
       debug_printf("%s: fallback processing\n", __FUNCTION__);
 
@@ -429,14 +441,14 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
       const GLint dstStride = _mesa_image_row_stride(&clippedPacking, width,
                                                      format, type);
 
-      if (trans->texture->format == PIPE_FORMAT_S8Z24_UNORM ||
-          trans->texture->format == PIPE_FORMAT_X8Z24_UNORM) {
+      if (pformat == PIPE_FORMAT_Z24_UNORM_S8_USCALED ||
+          pformat == PIPE_FORMAT_Z24X8_UNORM) {
          if (format == GL_DEPTH_COMPONENT) {
             for (i = 0; i < height; i++) {
                GLuint ztemp[MAX_WIDTH];
                GLfloat zfloat[MAX_WIDTH];
                const double scale = 1.0 / ((1 << 24) - 1);
-               pipe_get_tile_raw(trans, 0, y, width, 1, ztemp, 0);
+               pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
                y += yStep;
                for (j = 0; j < width; j++) {
                   zfloat[j] = (float) (scale * (ztemp[j] & 0xffffff));
@@ -451,7 +463,7 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
             assert(format == GL_DEPTH_STENCIL_EXT);
             for (i = 0; i < height; i++) {
                GLuint *zshort = (GLuint *)dst;
-               pipe_get_tile_raw(trans, 0, y, width, 1, dst, 0);
+               pipe_get_tile_raw(pipe, trans, 0, y, width, 1, dst, 0);
                y += yStep;
                /* Reverse into 24/8 */
                for (j = 0; j < width; j++) {
@@ -461,14 +473,14 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
             }
          }
       }
-      else if (trans->texture->format == PIPE_FORMAT_Z24S8_UNORM ||
-               trans->texture->format == PIPE_FORMAT_Z24X8_UNORM) {
+      else if (pformat == PIPE_FORMAT_S8_USCALED_Z24_UNORM ||
+               pformat == PIPE_FORMAT_X8Z24_UNORM) {
          if (format == GL_DEPTH_COMPONENT) {
             for (i = 0; i < height; i++) {
                GLuint ztemp[MAX_WIDTH];
                GLfloat zfloat[MAX_WIDTH];
                const double scale = 1.0 / ((1 << 24) - 1);
-               pipe_get_tile_raw(trans, 0, y, width, 1, ztemp, 0);
+               pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
                y += yStep;
                for (j = 0; j < width; j++) {
                   zfloat[j] = (float) (scale * ((ztemp[j] >> 8) & 0xffffff));
@@ -482,18 +494,18 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
             /* XXX: unreachable code -- should be before st_read_stencil_pixels */
             assert(format == GL_DEPTH_STENCIL_EXT);
             for (i = 0; i < height; i++) {
-               pipe_get_tile_raw(trans, 0, y, width, 1, dst, 0);
+               pipe_get_tile_raw(pipe, trans, 0, y, width, 1, dst, 0);
                y += yStep;
                dst += dstStride;
             }
          }
       }
-      else if (trans->texture->format == PIPE_FORMAT_Z16_UNORM) {
+      else if (pformat == PIPE_FORMAT_Z16_UNORM) {
          for (i = 0; i < height; i++) {
             GLushort ztemp[MAX_WIDTH];
             GLfloat zfloat[MAX_WIDTH];
             const double scale = 1.0 / 0xffff;
-            pipe_get_tile_raw(trans, 0, y, width, 1, ztemp, 0);
+            pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
             y += yStep;
             for (j = 0; j < width; j++) {
                zfloat[j] = (float) (scale * ztemp[j]);
@@ -503,12 +515,12 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
             dst += dstStride;
          }
       }
-      else if (trans->texture->format == PIPE_FORMAT_Z32_UNORM) {
+      else if (pformat == PIPE_FORMAT_Z32_UNORM) {
          for (i = 0; i < height; i++) {
             GLuint ztemp[MAX_WIDTH];
             GLfloat zfloat[MAX_WIDTH];
             const double scale = 1.0 / 0xffffffff;
-            pipe_get_tile_raw(trans, 0, y, width, 1, ztemp, 0);
+            pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
             y += yStep;
             for (j = 0; j < width; j++) {
                zfloat[j] = (float) (scale * ztemp[j]);
@@ -522,7 +534,8 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
          /* RGBA format */
          /* Do a row at a time to flip image data vertically */
          for (i = 0; i < height; i++) {
-            pipe_get_tile_rgba(trans, 0, y, width, 1, df);
+            pipe_get_tile_rgba_format(pipe, trans, 0, y, width, 1,
+                                      pformat, df);
             y += yStep;
             df += dfStride;
             if (!dfStride) {
@@ -534,7 +547,9 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
       }
    }
 
-   screen->tex_transfer_destroy(trans);
+   free(temp);
+
+   pipe->transfer_destroy(pipe, trans);
 
    _mesa_unmap_pbo_dest(ctx, &clippedPacking);
 }