Merge branch 'mesa_7_6_branch'
[mesa.git] / src / mesa / state_tracker / st_cb_drawpixels.c
index 08dc7c930e281961feefdd3e684d720d9709a58c..99f3ba678bb5a68a5c1e6464f66472a9e3689ff5 100644 (file)
@@ -60,6 +60,7 @@
 #include "pipe/p_inlines.h"
 #include "util/u_tile.h"
 #include "util/u_draw_quad.h"
+#include "util/u_math.h"
 #include "shader/prog_instruction.h"
 #include "cso_cache/cso_context.h"
 
@@ -97,7 +98,7 @@ is_passthrough_program(const struct gl_fragment_program *prog)
 static struct st_fragment_program *
 combined_drawpix_fragment_program(GLcontext *ctx)
 {
-   struct st_context *st = ctx->st;
+   struct st_context *st = st_context(ctx);
    struct st_fragment_program *stfp;
 
    if (st->pixel_xfer.program->serialNo == st->pixel_xfer.xfer_prog_sn
@@ -341,6 +342,7 @@ make_texture(struct st_context *st,
    enum pipe_format pipeFormat;
    GLuint cpp;
    GLenum baseFormat;
+   int ptw, pth;
 
    baseFormat = _mesa_base_format(format);
 
@@ -351,14 +353,35 @@ make_texture(struct st_context *st,
    assert(pipeFormat);
    cpp = st_sizeof_format(pipeFormat);
 
-   pixels = _mesa_map_drawpix_pbo(ctx, unpack, pixels);
+   pixels = _mesa_map_pbo_source(ctx, unpack, pixels);
    if (!pixels)
       return NULL;
 
-   pt = st_texture_create(st, PIPE_TEXTURE_2D, pipeFormat, 0, width, height, 1,
+   /* Need to use POT texture? */
+   ptw = width;
+   pth = height;
+   if (!screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES)) {
+      int l2pt, maxSize;
+
+      l2pt = util_logbase2(width);
+      if (1<<l2pt != width) {
+         ptw = 1<<(l2pt+1);
+      }
+      l2pt = util_logbase2(height);
+      if (1<<l2pt != height) {
+         pth = 1<<(l2pt+1);
+      }
+
+      /* Check against maximum texture size */
+      maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
+      assert(ptw <= maxSize);
+      assert(pth <= maxSize);
+   }
+
+   pt = st_texture_create(st, PIPE_TEXTURE_2D, pipeFormat, 0, ptw, pth, 1,
                           PIPE_TEXTURE_USAGE_SAMPLER);
    if (!pt) {
-      _mesa_unmap_drawpix_pbo(ctx, unpack);
+      _mesa_unmap_pbo_source(ctx, unpack);
       return NULL;
    }
 
@@ -405,7 +428,7 @@ make_texture(struct st_context *st,
       ctx->_ImageTransferState = imageTransferStateSave;
    }
 
-   _mesa_unmap_drawpix_pbo(ctx, unpack);
+   _mesa_unmap_pbo_source(ctx, unpack);
 
    return pt;
 }
@@ -420,10 +443,10 @@ make_texture(struct st_context *st,
 static void
 draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
           GLfloat x1, GLfloat y1, const GLfloat *color,
-          GLboolean invertTex)
+          GLboolean invertTex, GLfloat maxXcoord, GLfloat maxYcoord)
 {
-   struct st_context *st = ctx->st;
-   struct pipe_context *pipe = ctx->st->pipe;
+   struct st_context *st = st_context(ctx);
+   struct pipe_context *pipe = st->pipe;
    GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */
 
    /* setup vertex data */
@@ -435,8 +458,9 @@ draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
       const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f;
       const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f;
       const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f;
-      const GLfloat sLeft = 0.0f, sRight = 1.0f;
-      const GLfloat tTop = invertTex, tBot = 1.0f - tTop;
+      const GLfloat sLeft = 0.0f, sRight = maxXcoord;
+      const GLfloat tTop = invertTex ? maxYcoord : 0.0f;
+      const GLfloat tBot = invertTex ? 0.0f : maxYcoord;
       GLuint tex, i;
 
       /* upper-left */
@@ -516,9 +540,9 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
                    const GLfloat *color,
                    GLboolean invertTex)
 {
-   struct st_context *st = ctx->st;
-   struct pipe_context *pipe = ctx->st->pipe;
-   struct cso_context *cso = ctx->st->cso_context;
+   struct st_context *st = st_context(ctx);
+   struct pipe_context *pipe = st->pipe;
+   struct cso_context *cso = st->cso_context;
    GLfloat x0, y0, x1, y1;
    GLsizei maxSize;
 
@@ -608,7 +632,9 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
    y0 = (GLfloat) y;
    y1 = y + height * ctx->Pixel.ZoomY;
 
-   draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex);
+   draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex,
+            (GLfloat) width / pt->width[0],
+            (GLfloat) height / pt->height[0]);
 
    /* restore state */
    cso_restore_rasterizer(cso);
@@ -626,10 +652,11 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
                     const struct gl_pixelstore_attrib *unpack,
                     const GLvoid *pixels)
 {
-   struct st_context *st = ctx->st;
+   struct st_context *st = st_context(ctx);
    struct pipe_context *pipe = st->pipe;
    struct pipe_screen *screen = pipe->screen;
    struct st_renderbuffer *strb;
+   enum pipe_transfer_usage usage;
    struct pipe_transfer *pt;
    const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
    GLint skipPixels;
@@ -642,13 +669,19 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
       y = ctx->DrawBuffer->Height - y - height;
    }
 
+   if(format != GL_DEPTH_STENCIL && 
+      pf_get_component_bits( strb->format, PIPE_FORMAT_COMP_Z ) != 0)
+      usage = PIPE_TRANSFER_READ_WRITE;
+   else
+      usage = PIPE_TRANSFER_WRITE;
+
    pt = st_cond_flush_get_tex_transfer(st_context(ctx), strb->texture, 0, 0, 0,
-                                      PIPE_TRANSFER_WRITE, x, y,
+                                      usage, x, y,
                                       width, height);
 
    stmap = screen->transfer_map(screen, pt);
 
-   pixels = _mesa_map_drawpix_pbo(ctx, unpack, pixels);
+   pixels = _mesa_map_pbo_source(ctx, unpack, pixels);
    assert(pixels);
 
    /* if width > MAX_WIDTH, have to process image in chunks */
@@ -694,6 +727,7 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
             case PIPE_FORMAT_S8_UNORM:
                {
                   ubyte *dest = stmap + spanY * pt->stride + spanX;
+                  assert(usage == PIPE_TRANSFER_WRITE);
                   memcpy(dest, sValues, spanWidth);
                }
                break;
@@ -701,6 +735,7 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
                if (format == GL_DEPTH_STENCIL) {
                   uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
                   GLint k;
+                  assert(usage == PIPE_TRANSFER_WRITE);
                   for (k = 0; k < spanWidth; k++) {
                      dest[k] = zValues[k] | (sValues[k] << 24);
                   }
@@ -708,6 +743,7 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
                else {
                   uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
                   GLint k;
+                  assert(usage == PIPE_TRANSFER_READ_WRITE);
                   for (k = 0; k < spanWidth; k++) {
                      dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24);
                   }
@@ -717,13 +753,15 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
                if (format == GL_DEPTH_STENCIL) {
                   uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
                   GLint k;
+                  assert(usage == PIPE_TRANSFER_WRITE);
                   for (k = 0; k < spanWidth; k++) {
-                     dest[k] = zValues[k] | (sValues[k] << 24);
+                     dest[k] = (zValues[k] << 8) | (sValues[k] & 0xff);
                   }
                }
                else {
                   uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
                   GLint k;
+                  assert(usage == PIPE_TRANSFER_READ_WRITE);
                   for (k = 0; k < spanWidth; k++) {
                      dest[k] = (dest[k] & 0xffffff00) | (sValues[k] & 0xff);
                   }
@@ -737,7 +775,7 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
       skipPixels += spanWidth;
    }
 
-   _mesa_unmap_drawpix_pbo(ctx, unpack);
+   _mesa_unmap_pbo_source(ctx, unpack);
 
    /* unmap the stencil buffer */
    screen->transfer_unmap(screen, pt);
@@ -755,9 +793,8 @@ st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
 {
    struct st_fragment_program *stfp;
    struct st_vertex_program *stvp;
-   struct st_context *st = ctx->st;
+   struct st_context *st = st_context(ctx);
    struct pipe_surface *ps;
-   GLuint bufferFormat;
    const GLfloat *color;
 
    if (format == GL_STENCIL_INDEX ||
@@ -767,30 +804,28 @@ st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
       return;
    }
 
-   _mesa_set_vp_override( ctx, TRUE );
-   _mesa_update_state( ctx );
+   /* Mesa state should be up to date by now */
+   assert(ctx->NewState == 0x0);
 
    st_validate_state(st);
 
    if (format == GL_DEPTH_COMPONENT) {
       ps = st->state.framebuffer.zsbuf;
-      stfp = make_fragment_shader_z(ctx->st);
-      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
+      stfp = make_fragment_shader_z(st);
+      stvp = st_make_passthrough_vertex_shader(st, GL_TRUE);
       color = ctx->Current.RasterColor;
    }
    else {
       ps = st->state.framebuffer.cbufs[0];
       stfp = combined_drawpix_fragment_program(ctx);
-      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE);
+      stvp = st_make_passthrough_vertex_shader(st, GL_FALSE);
       color = NULL;
    }
 
-   bufferFormat = ps->format;
-
    /* draw with textured quad */
    {
       struct pipe_texture *pt
-         = make_texture(ctx->st, width, height, format, type, unpack, pixels);
+         = make_texture(st, width, height, format, type, unpack, pixels);
       if (pt) {
          draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
                             width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
@@ -798,8 +833,6 @@ st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
          pipe_texture_reference(&pt, NULL);
       }
    }
-
-   _mesa_set_vp_override( ctx, FALSE );
 }
 
 
@@ -811,6 +844,7 @@ copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
 {
    struct st_renderbuffer *rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer);
    struct pipe_screen *screen = ctx->st->pipe->screen;
+   enum pipe_transfer_usage usage;
    struct pipe_transfer *ptDraw;
    ubyte *drawMap;
    ubyte *buffer;
@@ -827,14 +861,23 @@ copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
                           GL_STENCIL_INDEX, GL_UNSIGNED_BYTE,
                           &ctx->DefaultPacking, buffer);
 
+   if(pf_get_component_bits( rbDraw->format, PIPE_FORMAT_COMP_Z ) != 0)
+      usage = PIPE_TRANSFER_READ_WRITE;
+   else
+      usage = PIPE_TRANSFER_WRITE;
+   
+   if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
+      dsty = rbDraw->Base.Height - dsty - height;
+   }
+
    ptDraw = st_cond_flush_get_tex_transfer(st_context(ctx),
                                           rbDraw->texture, 0, 0, 0,
-                                          PIPE_TRANSFER_WRITE, dstx, dsty,
+                                          usage, dstx, dsty,
                                           width, height);
 
    assert(ptDraw->block.width == 1);
    assert(ptDraw->block.height == 1);
-   
+
    /* map the stencil buffer */
    drawMap = screen->transfer_map(screen, ptDraw);
 
@@ -859,6 +902,7 @@ copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
          {
             uint *dst4 = (uint *) dst;
             int j;
+            assert(usage == PIPE_TRANSFER_READ_WRITE);
             for (j = 0; j < width; j++) {
                *dst4 = (*dst4 & 0xffffff) | (src[j] << 24);
                dst4++;
@@ -869,6 +913,7 @@ copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
          {
             uint *dst4 = (uint *) dst;
             int j;
+            assert(usage == PIPE_TRANSFER_READ_WRITE);
             for (j = 0; j < width; j++) {
                *dst4 = (*dst4 & 0xffffff00) | (src[j] & 0xff);
                dst4++;
@@ -876,6 +921,7 @@ copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
          }
          break;
       case PIPE_FORMAT_S8_UNORM:
+         assert(usage == PIPE_TRANSFER_WRITE);
          memcpy(dst, src, width);
          break;
       default:
@@ -896,7 +942,7 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
               GLsizei width, GLsizei height,
               GLint dstx, GLint dsty, GLenum type)
 {
-   struct st_context *st = ctx->st;
+   struct st_context *st = st_context(ctx);
    struct pipe_context *pipe = st->pipe;
    struct pipe_screen *screen = pipe->screen;
    struct st_renderbuffer *rbRead;
@@ -905,11 +951,40 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
    struct pipe_texture *pt;
    GLfloat *color;
    enum pipe_format srcFormat, texFormat;
+   int ptw, pth;
 
    pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
 
    st_validate_state(st);
 
+   if (srcx < 0) {
+      width -= -srcx;
+      dstx += -srcx;
+      srcx = 0;
+   }
+
+   if (srcy < 0) {
+      height -= -srcy;
+      dsty += -srcy;
+      srcy = 0;
+   }
+
+   if (dstx < 0) {
+      width -= -dstx;
+      srcx += -dstx;
+      dstx = 0;
+   }
+
+   if (dsty < 0) {
+      height -= -dsty;
+      srcy += -dsty;
+      dsty = 0;
+   }
+
+   if (width < 0 || height < 0)
+      return;
+
+
    if (type == GL_STENCIL) {
       /* can't use texturing to do stencil */
       copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
@@ -920,14 +995,14 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
       rbRead = st_get_color_read_renderbuffer(ctx);
       color = NULL;
       stfp = combined_drawpix_fragment_program(ctx);
-      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE);
+      stvp = st_make_passthrough_vertex_shader(st, GL_FALSE);
    }
    else {
       assert(type == GL_DEPTH);
       rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
       color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
-      stfp = make_fragment_shader_z(ctx->st);
-      stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
+      stfp = make_fragment_shader_z(st);
+      stvp = st_make_passthrough_vertex_shader(st, GL_TRUE);
    }
 
    srcFormat = rbRead->texture->format;
@@ -951,15 +1026,45 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
       }
    }
 
-   pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, texFormat, 0,
-                          width, height, 1,
+   if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
+      srcy = ctx->DrawBuffer->Height - srcy - height;
+
+      if (srcy < 0) {
+         height -= -srcy;
+         srcy = 0;
+      }
+
+      if (height < 0)
+         return;
+   }
+
+   /* Need to use POT texture? */
+   ptw = width;
+   pth = height;
+   if (!screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES)) {
+      int l2pt, maxSize;
+
+      l2pt = util_logbase2(width);
+      if (1<<l2pt != width) {
+         ptw = 1<<(l2pt+1);
+      }
+      l2pt = util_logbase2(height);
+      if (1<<l2pt != height) {
+         pth = 1<<(l2pt+1);
+      }
+
+      /* Check against maximum texture size */
+      maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
+      assert(ptw <= maxSize);
+      assert(pth <= maxSize);
+   }
+
+   pt = st_texture_create(st, PIPE_TEXTURE_2D, texFormat, 0,
+                          ptw, pth, 1,
                           PIPE_TEXTURE_USAGE_SAMPLER);
    if (!pt)
       return;
 
-   if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
-      srcy = ctx->DrawBuffer->Height - srcy - height;
-   }
 
    if (srcFormat == texFormat) {
       /* copy source framebuffer surface into mipmap/texture */
@@ -982,10 +1087,16 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
          st_cond_flush_get_tex_transfer(st, rbRead->texture, 0, 0, 0,
                                        PIPE_TRANSFER_READ, srcx, srcy, width,
                                        height);
+      struct pipe_transfer *ptTex;
+      enum pipe_transfer_usage transfer_usage;
+
+      if (type == GL_DEPTH && pf_is_depth_and_stencil(pt->format))
+         transfer_usage = PIPE_TRANSFER_READ_WRITE;
+      else
+         transfer_usage = PIPE_TRANSFER_WRITE;
 
-      struct pipe_transfer *ptTex =
-         st_cond_flush_get_tex_transfer(st, pt, 0, 0, 0, PIPE_TRANSFER_WRITE,
-                                       0, 0, width, height);
+      ptTex = st_cond_flush_get_tex_transfer(st, pt, 0, 0, 0, transfer_usage,
+                                             0, 0, width, height);
 
       if (type == GL_COLOR) {
          /* alternate path using get/put_tile() */