mesa: move PBO-related functions into a new file
[mesa.git] / src / mesa / state_tracker / st_cb_readpixels.c
index 10795ee9e4ad307c7fd772aba4ac38f77330e463..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_context *pipe = ctx->st->pipe;
+   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 = pipe->transfer_map(pipe, pt);
+   stmap = pipe_transfer_map(pipe, pt);
 
    /* width should never be > MAX_WIDTH since we did clipping earlier */
    ASSERT(width <= MAX_WIDTH);
@@ -102,7 +107,7 @@ st_read_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
       }
 
       /* get stencil (and Z) values */
-      switch (pt->texture->format) {
+      switch (pt->resource->format) {
       case PIPE_FORMAT_S8_USCALED:
          {
             const ubyte *src = stmap + srcY * pt->stride;
@@ -162,34 +167,21 @@ st_read_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
    }
 
    /* unmap the stencil buffer */
-   pipe->transfer_unmap(pipe, pt);
-   pipe->tex_transfer_destroy(pipe, 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;
 }
@@ -200,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,
@@ -234,7 +226,7 @@ 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_context *pipe = st_context(ctx)->pipe;
       struct pipe_transfer *trans;
       const GLubyte *map;
       GLubyte *dst;
@@ -245,17 +237,17 @@ st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb,
          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 = pipe->transfer_map(pipe, trans);
+      map = pipe_transfer_map(pipe, trans);
       if (!map) {
-         pipe->tex_transfer_destroy(pipe, trans);
+         pipe->transfer_destroy(pipe, trans);
          return GL_FALSE;
       }
 
@@ -317,8 +309,8 @@ st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb,
          ; /* nothing */
       }
 
-      pipe->transfer_unmap(pipe, trans);
-      pipe->tex_transfer_destroy(pipe, trans);
+      pipe_transfer_unmap(pipe, trans);
+      pipe->transfer_destroy(pipe, trans);
    }
 
    return GL_TRUE;
@@ -331,13 +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;
-   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;
@@ -345,13 +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(ctx->st);
+   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)) {
@@ -359,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,
@@ -373,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 */
@@ -390,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,
@@ -408,10 +409,10 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei 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) {
@@ -423,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__);
 
@@ -437,8 +441,8 @@ 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_Z24_UNORM_S8_USCALED ||
-          trans->texture->format == PIPE_FORMAT_Z24X8_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];
@@ -469,8 +473,8 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
             }
          }
       }
-      else if (trans->texture->format == PIPE_FORMAT_S8_USCALED_Z24_UNORM ||
-               trans->texture->format == PIPE_FORMAT_X8Z24_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];
@@ -496,7 +500,7 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
             }
          }
       }
-      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];
@@ -511,7 +515,7 @@ 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];
@@ -530,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(pipe, 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) {
@@ -542,7 +547,9 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
       }
    }
 
-   pipe->tex_transfer_destroy(pipe, trans);
+   free(temp);
+
+   pipe->transfer_destroy(pipe, trans);
 
    _mesa_unmap_pbo_dest(ctx, &clippedPacking);
 }