intel: use driReadDrawable in do_copy_texsubimage()
[mesa.git] / src / mesa / state_tracker / st_cb_drawpixels.c
index f9f139ff0737c948ec9e6aacae3a281345d1a533..c655690603865613aed7d789a8d1c41a7bd25b67 100644 (file)
 #include "st_format.h"
 #include "st_mesa_to_tgsi.h"
 #include "st_texture.h"
+#include "st_inlines.h"
+
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
 #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"
 
@@ -144,6 +147,8 @@ combined_drawpix_fragment_program(GLcontext *ctx)
       st->pixel_xfer.xfer_prog_sn = st->pixel_xfer.program->serialNo;
       st->pixel_xfer.user_prog_sn = st->fp->serialNo;
       st->pixel_xfer.combined_prog_sn = stfp->serialNo;
+      /* can't reference new program directly, already have a reference on it */
+      st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL);
       st->pixel_xfer.combined_prog = stfp;
    }
 
@@ -309,6 +314,8 @@ _mesa_base_format(GLenum format)
    switch (format) {
    case GL_DEPTH_COMPONENT:
       return GL_DEPTH_COMPONENT;
+   case GL_DEPTH_STENCIL:
+      return GL_DEPTH_STENCIL;
    case GL_STENCIL_INDEX:
       return GL_STENCIL_INDEX;
    default:
@@ -335,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);
 
@@ -345,15 +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, 0,
+   /* 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;
    }
 
@@ -367,9 +395,9 @@ make_texture(struct st_context *st,
       /* we'll do pixel transfer in a fragment shader */
       ctx->_ImageTransferState = 0x0;
 
-      transfer = screen->get_tex_transfer(screen, pt, 0, 0, 0,
-                                          PIPE_TRANSFER_WRITE, 0, 0,
-                                          width, height);
+      transfer = st_no_flush_get_tex_transfer(st, pt, 0, 0, 0,
+                                             PIPE_TRANSFER_WRITE, 0, 0,
+                                             width, height);
 
       /* map texture transfer */
       dest = screen->transfer_map(screen, transfer);
@@ -400,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;
 }
@@ -415,7 +443,7 @@ 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;
@@ -430,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 */
@@ -489,7 +518,7 @@ draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
       /* allocate/load buffer object with vertex data */
       buf = pipe_buffer_create(pipe->screen, 32, PIPE_BUFFER_USAGE_VERTEX,
                                sizeof(verts));
-      pipe_buffer_write(pipe->screen, buf, 0, sizeof(verts), verts);
+      st_no_flush_pipe_buffer_write(st, buf, 0, sizeof(verts), verts);
 
       util_draw_vertex_buffer(pipe, buf, 0,
                               PIPE_PRIM_QUADS,
@@ -569,15 +598,15 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
 
    /* viewport state: viewport matching window dims */
    {
-      const float width = (float) ctx->DrawBuffer->Width;
-      const float height = (float) ctx->DrawBuffer->Height;
+      const float w = (float) ctx->DrawBuffer->Width;
+      const float h = (float) ctx->DrawBuffer->Height;
       struct pipe_viewport_state vp;
-      vp.scale[0] =  0.5f * width;
-      vp.scale[1] = -0.5f * height;
+      vp.scale[0] =  0.5f * w;
+      vp.scale[1] = -0.5f * h;
       vp.scale[2] = 1.0f;
       vp.scale[3] = 1.0f;
-      vp.translate[0] = 0.5f * width;
-      vp.translate[1] = 0.5f * height;
+      vp.translate[0] = 0.5f * w;
+      vp.translate[1] = 0.5f * h;
       vp.translate[2] = 0.0f;
       vp.translate[3] = 0.0f;
       cso_set_viewport(cso, &vp);
@@ -603,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);
@@ -617,7 +648,7 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
 
 static void
 draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
-                    GLsizei width, GLsizei height, GLenum type,
+                    GLsizei width, GLsizei height, GLenum format, GLenum type,
                     const struct gl_pixelstore_attrib *unpack,
                     const GLvoid *pixels)
 {
@@ -625,21 +656,34 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
    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;
    ubyte *stmap;
 
-   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
-
    strb = st_renderbuffer(ctx->DrawBuffer->
                           Attachment[BUFFER_STENCIL].Renderbuffer);
-   pt = screen->get_tex_transfer(screen, strb->texture, 0, 0, 0,
-                                 PIPE_TRANSFER_WRITE, x, y,
-                                 width, height);
+
+   if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
+      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,
+                                      usage, x, y,
+                                      width, height);
 
    stmap = screen->transfer_map(screen, pt);
 
+   pixels = _mesa_map_pbo_source(ctx, unpack, pixels);
+   assert(pixels);
+
    /* if width > MAX_WIDTH, have to process image in chunks */
    skipPixels = 0;
    while (skipPixels < width) {
@@ -647,53 +691,79 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
       const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
       GLint row;
       for (row = 0; row < height; row++) {
-         GLint spanY = row;
-         GLubyte values[MAX_WIDTH];
+         GLubyte sValues[MAX_WIDTH];
+         GLuint zValues[MAX_WIDTH];
          GLenum destType = GL_UNSIGNED_BYTE;
          const GLvoid *source = _mesa_image_address2d(unpack, pixels,
                                                       width, height,
-                                                      GL_COLOR_INDEX, type,
+                                                      format, type,
                                                       row, skipPixels);
-         _mesa_unpack_stencil_span(ctx, spanWidth, destType, values,
+         _mesa_unpack_stencil_span(ctx, spanWidth, destType, sValues,
                                    type, source, unpack,
                                    ctx->_ImageTransferState);
+
+         if (format == GL_DEPTH_STENCIL) {
+            _mesa_unpack_depth_span(ctx, spanWidth, GL_UNSIGNED_INT, zValues,
+                                    (1 << 24) - 1, type, source, unpack);
+         }
+
          if (zoom) {
-            /*
-            _swrast_write_zoomed_stencil_span(ctx, 0, 0, spanWidth,
-                                              spanX, spanY, values);
-            */
+            _mesa_problem(ctx, "Gallium glDrawPixels(GL_STENCIL) with "
+                          "zoom not complete");
          }
-         else {
+
+         {
+            GLint spanY;
+
             if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
-               spanY = height - spanY - 1;
+               spanY = height - row - 1;
+            }
+            else {
+               spanY = row;
             }
 
+            /* now pack the stencil (and Z) values in the dest format */
             switch (pt->format) {
             case PIPE_FORMAT_S8_UNORM:
                {
                   ubyte *dest = stmap + spanY * pt->stride + spanX;
-                  memcpy(dest, values, spanWidth);
+                  assert(usage == PIPE_TRANSFER_WRITE);
+                  memcpy(dest, sValues, spanWidth);
                }
                break;
             case PIPE_FORMAT_S8Z24_UNORM:
-               {
+               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);
+                  }
+               }
+               else {
                   uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
                   GLint k;
+                  assert(usage == PIPE_TRANSFER_READ_WRITE);
                   for (k = 0; k < spanWidth; k++) {
-                     uint p = dest[k];
-                     p = (p & 0xffffff) | (values[k] << 24);
-                     dest[k] = p;
+                     dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24);
                   }
                }
                break;
             case PIPE_FORMAT_Z24S8_UNORM:
-               {
+               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++) {
-                     uint p = dest[k];
-                     p = (p & 0xffffff00) | (values[k] & 0xff);
-                     dest[k] = p;
+                     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);
                   }
                }
                break;
@@ -705,6 +775,8 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
       skipPixels += spanWidth;
    }
 
+   _mesa_unmap_pbo_source(ctx, unpack);
+
    /* unmap the stencil buffer */
    screen->transfer_unmap(screen, pt);
    screen->tex_transfer_destroy(pt);
@@ -723,16 +795,17 @@ st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
    struct st_vertex_program *stvp;
    struct st_context *st = ctx->st;
    struct pipe_surface *ps;
-   GLuint bufferFormat;
    const GLfloat *color;
 
-   if (format == GL_STENCIL_INDEX) {
-      draw_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels);
+   if (format == GL_STENCIL_INDEX ||
+       format == GL_DEPTH_STENCIL) {
+      draw_stencil_pixels(ctx, x, y, width, height, format, type,
+                          unpack, pixels);
       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);
 
@@ -742,11 +815,6 @@ st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
       stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE);
       color = ctx->Current.RasterColor;
    }
-   else if (format == GL_STENCIL_INDEX) {
-      ps = st->state.framebuffer.zsbuf;
-      /* XXX special case - can't use texture map */
-      color = NULL;
-   }
    else {
       ps = st->state.framebuffer.cbufs[0];
       stfp = combined_drawpix_fragment_program(ctx);
@@ -754,8 +822,6 @@ st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
       color = NULL;
    }
 
-   bufferFormat = ps->format;
-
    /* draw with textured quad */
    {
       struct pipe_texture *pt
@@ -767,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 );
 }
 
 
@@ -780,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;
@@ -792,16 +857,27 @@ copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
    }
 
    /* this will do stencil pixel transfer ops */
-   st_read_stencil_pixels(ctx, srcx, srcy, width, height, GL_UNSIGNED_BYTE,
+   st_read_stencil_pixels(ctx, srcx, srcy, width, height,
+                          GL_STENCIL_INDEX, GL_UNSIGNED_BYTE,
                           &ctx->DefaultPacking, buffer);
 
-   ptDraw = screen->get_tex_transfer(screen, rbDraw->texture, 0, 0, 0,
-                                     PIPE_TRANSFER_WRITE, dstx, dsty,
-                                     width, height);
+   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,
+                                          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);
 
@@ -826,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++;
@@ -836,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++;
@@ -843,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:
@@ -872,12 +951,40 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
    struct pipe_texture *pt;
    GLfloat *color;
    enum pipe_format srcFormat, texFormat;
+   int ptw, pth;
 
-   /* make sure rendering has completed */
    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);
@@ -919,15 +1026,45 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
       }
    }
 
+   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(ctx->st, PIPE_TEXTURE_2D, texFormat, 0,
-                          width, height, 1, 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 */
@@ -947,13 +1084,19 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
    else {
       /* CPU-based fallback/conversion */
       struct pipe_transfer *ptRead =
-         screen->get_tex_transfer(screen, rbRead->texture, 0, 0, 0,
-                                  PIPE_TRANSFER_READ, srcx, srcy, width,
-                                  height);
-
-      struct pipe_transfer *ptTex =
-         screen->get_tex_transfer(screen, pt, 0, 0, 0, PIPE_TRANSFER_WRITE,
-                                  0, 0, width, height);
+         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;
+
+      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() */