Merge branch 'mesa_7_6_branch'
[mesa.git] / src / mesa / state_tracker / st_cb_texture.c
index 98f109fc6598c8bedef48787c8aa8b6769fa7bb9..3520c986b4761d6a28aa57674e912d2939a6bda7 100644 (file)
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
 #include "pipe/p_inlines.h"
+#include "pipe/p_shader_tokens.h"
 #include "util/u_tile.h"
 #include "util/u_blit.h"
 #include "util/u_surface.h"
+#include "util/u_math.h"
 
 
 #define DBG if (0) printf
@@ -237,18 +239,6 @@ do_memcpy(void *dest, const void *src, size_t n)
 }
 
 
-static int
-logbase2(int n)
-{
-   GLint i = 1, log2 = 0;
-   while (n > i) {
-      i *= 2;
-      log2++;
-   }
-   return log2;
-}
-
-
 /**
  * Return default texture usage bitmask for the given texture format.
  */
@@ -335,14 +325,16 @@ guess_and_alloc_texture(struct st_context *st,
     * pagetable arrangements.
     */
    if ((stObj->base.MinFilter == GL_NEAREST ||
-        stObj->base.MinFilter == GL_LINEAR) &&
+        stObj->base.MinFilter == GL_LINEAR ||
+        stImage->base._BaseFormat == GL_DEPTH_COMPONENT ||
+        stImage->base._BaseFormat == GL_DEPTH_STENCIL_EXT) &&
        stImage->level == firstLevel) {
       lastLevel = firstLevel;
    }
    else {
-      GLuint l2width = logbase2(width);
-      GLuint l2height = logbase2(height);
-      GLuint l2depth = logbase2(depth);
+      GLuint l2width = util_logbase2(width);
+      GLuint l2height = util_logbase2(height);
+      GLuint l2depth = util_logbase2(depth);
       lastLevel = firstLevel + MAX2(MAX2(l2width, l2height), l2depth);
    }
 
@@ -525,12 +517,19 @@ st_TexImage(GLcontext * ctx,
    struct st_texture_image *stImage = st_texture_image(texImage);
    GLint postConvWidth, postConvHeight;
    GLint texelBytes, sizeInBytes;
-   GLuint dstRowStride;
+   GLuint dstRowStride = 0;
    struct gl_pixelstore_attrib unpackNB;
+   enum pipe_transfer_usage transfer_usage = 0;
 
    DBG("%s target %s level %d %dx%dx%d border %d\n", __FUNCTION__,
        _mesa_lookup_enum_by_nr(target), level, width, height, depth, border);
 
+   /* switch to "normal" */
+   if (stObj->surface_based) {
+      _mesa_clear_texture_object(ctx, texObj);
+      stObj->surface_based = GL_FALSE;
+   }
+
    /* gallium does not support texture borders, strip it off */
    if (border) {
       strip_texture_border(border, &width, &height, &depth, unpack, &unpackNB);
@@ -659,8 +658,10 @@ st_TexImage(GLcontext * ctx,
                                           format, type,
                                           pixels, unpack, "glTexImage");
    }
-   if (!pixels)
-      return;
+
+   /* Note: we can't check for pixels==NULL until after we've allocated
+    * memory for the texture.
+    */
 
    /* See if we can do texture compression with a blit/render.
     */
@@ -671,15 +672,24 @@ st_TexImage(GLcontext * ctx,
                                    stImage->pt->format,
                                    stImage->pt->target,
                                    PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)) {
+      if (!pixels)
+         goto done;
+
       if (compress_with_blit(ctx, target, level, 0, 0, 0, width, height, depth,
                              format, type, pixels, unpack, texImage)) {
-         return;
+         goto done;
       }
    }
 
    if (stImage->pt) {
+      if (format == GL_DEPTH_COMPONENT &&
+          pf_is_depth_and_stencil(stImage->pt->format))
+         transfer_usage = PIPE_TRANSFER_READ_WRITE;
+      else
+         transfer_usage = PIPE_TRANSFER_WRITE;
+
       texImage->Data = st_texture_image_map(ctx->st, stImage, 0,
-                                            PIPE_TRANSFER_WRITE, 0, 0,
+                                            transfer_usage, 0, 0,
                                             stImage->base.Width,
                                             stImage->base.Height);
       if(stImage->transfer)
@@ -706,6 +716,9 @@ st_TexImage(GLcontext * ctx,
       return;
    }
 
+   if (!pixels)
+      goto done;
+
    DBG("Upload image %dx%dx%d row_len %x pitch %x\n",
        width, height, depth, width * texelBytes, dstRowStride);
 
@@ -740,7 +753,7 @@ st_TexImage(GLcontext * ctx,
            st_texture_image_unmap(ctx->st, stImage);
             /* map next slice of 3D texture */
            texImage->Data = st_texture_image_map(ctx->st, stImage, i + 1,
-                                                  PIPE_TRANSFER_WRITE, 0, 0,
+                                                  transfer_usage, 0, 0,
                                                   stImage->base.Width,
                                                   stImage->base.Height);
            src += srcImageStride;
@@ -748,16 +761,13 @@ st_TexImage(GLcontext * ctx,
       }
    }
 
+done:
    _mesa_unmap_teximage_pbo(ctx, unpack);
 
    if (stImage->pt && texImage->Data) {
       st_texture_image_unmap(ctx->st, stImage);
       texImage->Data = NULL;
    }
-
-   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
-      ctx->Driver.GenerateMipmap(ctx, target, texObj);
-   }
 }
 
 
@@ -865,7 +875,7 @@ decompress_with_blit(GLcontext * ctx, GLenum target, GLint level,
                                             PIPE_TRANSFER_READ,
                                             0, 0, width, height);
 
-   pixels = _mesa_map_readpix_pbo(ctx, &ctx->Pack, pixels);
+   pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels);
 
    /* copy/pack data into user buffer */
    if (st_equal_formats(stImage->pt->format, format, type)) {
@@ -898,7 +908,7 @@ decompress_with_blit(GLcontext * ctx, GLenum target, GLint level,
       }
    }
 
-   _mesa_unmap_readpix_pbo(ctx, &ctx->Pack);
+   _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
 
    /* destroy the temp / dest surface */
    util_destroy_rgba_surface(dst_texture, dst_surface);
@@ -940,8 +950,9 @@ st_get_tex_image(GLcontext * ctx, GLenum target, GLint level,
       /* Image is stored in hardware format in a buffer managed by the
        * kernel.  Need to explicitly map and unmap it.
        */
+      unsigned face = _mesa_tex_target_to_face(target);
 
-      st_teximage_flush_before_map(ctx->st, stImage->pt, 0, level,
+      st_teximage_flush_before_map(ctx->st, stImage->pt, face, level,
                                   PIPE_TRANSFER_READ);
 
       texImage->Data = st_texture_image_map(ctx->st, stImage, 0,
@@ -1038,6 +1049,8 @@ st_TexSubimage(GLcontext *ctx, GLint dims, GLenum target, GLint level,
       _mesa_image_image_stride(packing, width, height, format, type);
    GLint i;
    const GLubyte *src;
+   /* init to silence warning only: */
+   enum pipe_transfer_usage transfer_usage = PIPE_TRANSFER_WRITE;
 
    DBG("%s target %s level %d offset %d,%d %dx%d\n", __FUNCTION__,
        _mesa_lookup_enum_by_nr(target),
@@ -1061,7 +1074,7 @@ st_TexSubimage(GLcontext *ctx, GLint dims, GLenum target, GLint level,
                              xoffset, yoffset, zoffset,
                              width, height, depth,
                              format, type, pixels, packing, texImage)) {
-         return;
+         goto done;
       }
    }
 
@@ -1069,17 +1082,25 @@ st_TexSubimage(GLcontext *ctx, GLint dims, GLenum target, GLint level,
     * from uploading the buffer under us.
     */
    if (stImage->pt) {
-      st_teximage_flush_before_map(ctx->st, stImage->pt, 0, level,
-                                  PIPE_TRANSFER_WRITE);
+      unsigned face = _mesa_tex_target_to_face(target);
+
+      if (format == GL_DEPTH_COMPONENT &&
+          pf_is_depth_and_stencil(stImage->pt->format))
+         transfer_usage = PIPE_TRANSFER_READ_WRITE;
+      else
+         transfer_usage = PIPE_TRANSFER_WRITE;
+
+      st_teximage_flush_before_map(ctx->st, stImage->pt, face, level,
+                                  transfer_usage);
       texImage->Data = st_texture_image_map(ctx->st, stImage, zoffset, 
-                                            PIPE_TRANSFER_WRITE,
+                                            transfer_usage,
                                             xoffset, yoffset,
                                             width, height);
    }
 
    if (!texImage->Data) {
       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
-      return;
+      goto done;
    }
 
    src = (const GLubyte *) pixels;
@@ -1103,17 +1124,14 @@ st_TexSubimage(GLcontext *ctx, GLint dims, GLenum target, GLint level,
          /* map next slice of 3D texture */
         texImage->Data = st_texture_image_map(ctx->st, stImage,
                                                zoffset + i + 1,
-                                               PIPE_TRANSFER_WRITE,
+                                               transfer_usage,
                                                xoffset, yoffset,
                                                width, height);
         src += srcImageStride;
       }
    }
 
-   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
-      ctx->Driver.GenerateMipmap(ctx, target, texObj);
-   }
-
+done:
    _mesa_unmap_teximage_pbo(ctx, packing);
 
    if (stImage->pt) {
@@ -1167,6 +1185,90 @@ st_TexSubImage1D(GLcontext *ctx, GLenum target, GLint level,
 }
 
 
+static void
+st_CompressedTexSubImage1D(GLcontext *ctx, GLenum target, GLint level,
+                           GLint xoffset, GLsizei width,
+                           GLenum format,
+                           GLsizei imageSize, const GLvoid *data,
+                           struct gl_texture_object *texObj,
+                           struct gl_texture_image *texImage)
+{
+   assert(0);
+}
+
+
+static void
+st_CompressedTexSubImage2D(GLcontext *ctx, GLenum target, GLint level,
+                           GLint xoffset, GLint yoffset,
+                           GLsizei width, GLint height,
+                           GLenum format,
+                           GLsizei imageSize, const GLvoid *data,
+                           struct gl_texture_object *texObj,
+                           struct gl_texture_image *texImage)
+{
+   struct st_texture_image *stImage = st_texture_image(texImage);
+   struct pipe_format_block block;
+   int srcBlockStride;
+   int dstBlockStride;
+   int y;
+
+   if (stImage->pt) {
+      unsigned face = _mesa_tex_target_to_face(target);
+
+      st_teximage_flush_before_map(ctx->st, stImage->pt, face, level,
+                                  PIPE_TRANSFER_WRITE);
+      texImage->Data = st_texture_image_map(ctx->st, stImage, 0, 
+                                            PIPE_TRANSFER_WRITE,
+                                            xoffset, yoffset,
+                                            width, height);
+      
+      block = stImage->pt->block;
+      srcBlockStride = pf_get_stride(&block, width);
+      dstBlockStride = stImage->transfer->stride;
+   } else {
+      assert(stImage->pt);
+      /* TODO find good values for block and strides */
+      /* TODO also adjust texImage->data for yoffset/xoffset */
+      return;
+   }
+
+   if (!texImage->Data) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexSubImage");
+      return;
+   }
+
+   assert(xoffset % block.width == 0);
+   assert(yoffset % block.height == 0);
+   assert(width % block.width == 0);
+   assert(height % block.height == 0);
+
+   for (y = 0; y < height; y += block.height) {
+      /* don't need to adjust for xoffset and yoffset as st_texture_image_map does that */
+      const char *src = (const char*)data + srcBlockStride * pf_get_nblocksy(&block, y);
+      char *dst = (char*)texImage->Data + dstBlockStride * pf_get_nblocksy(&block, y);
+      memcpy(dst, src, pf_get_stride(&block, width));
+   }
+
+   if (stImage->pt) {
+      st_texture_image_unmap(ctx->st, stImage);
+      texImage->Data = NULL;
+   }
+}
+
+
+static void
+st_CompressedTexSubImage3D(GLcontext *ctx, GLenum target, GLint level,
+                           GLint xoffset, GLint yoffset, GLint zoffset,
+                           GLsizei width, GLint height, GLint depth,
+                           GLenum format,
+                           GLsizei imageSize, const GLvoid *data,
+                           struct gl_texture_object *texObj,
+                           struct gl_texture_image *texImage)
+{
+   assert(0);
+}
+
+
 
 /**
  * Do a CopyTexSubImage operation using a read transfer from the source,
@@ -1188,6 +1290,7 @@ fallback_copy_texsubimage(GLcontext *ctx, GLenum target, GLint level,
    struct pipe_screen *screen = pipe->screen;
    struct pipe_transfer *src_trans;
    GLvoid *texDest;
+   enum pipe_transfer_usage transfer_usage;
 
    assert(width <= MAX_WIDTH);
 
@@ -1202,10 +1305,16 @@ fallback_copy_texsubimage(GLcontext *ctx, GLenum target, GLint level,
                                               srcX, srcY,
                                               width, height);
 
+   if (baseFormat == GL_DEPTH_COMPONENT &&
+       pf_is_depth_and_stencil(stImage->pt->format))
+      transfer_usage = PIPE_TRANSFER_READ_WRITE;
+   else
+      transfer_usage = PIPE_TRANSFER_WRITE;
+
    st_teximage_flush_before_map(ctx->st, stImage->pt, 0, 0,
-                               PIPE_TRANSFER_WRITE);
+                               transfer_usage);
 
-   texDest = st_texture_image_map(ctx->st, stImage, 0, PIPE_TRANSFER_WRITE,
+   texDest = st_texture_image_map(ctx->st, stImage, 0, transfer_usage,
                                   destX, destY, width, height);
 
    if (baseFormat == GL_DEPTH_COMPONENT ||
@@ -1285,6 +1394,36 @@ fallback_copy_texsubimage(GLcontext *ctx, GLenum target, GLint level,
 }
 
 
+static unsigned
+compatible_src_dst_formats(const struct gl_renderbuffer *src,
+                           const struct gl_texture_image *dst)
+{
+   const GLenum srcFormat = src->_BaseFormat;
+   const GLenum dstLogicalFormat = dst->_BaseFormat;
+
+   if (srcFormat == dstLogicalFormat) {
+      /* This is the same as matching_base_formats, which should
+       * always pass, as it did previously.
+       */
+      return TGSI_WRITEMASK_XYZW;
+   }
+   else if (srcFormat == GL_RGBA &&
+            dstLogicalFormat == GL_RGB) {
+      /* Add a single special case to cope with RGBA->RGB transfers,
+       * setting A to 1.0 to cope with situations where the RGB
+       * destination is actually stored as RGBA.
+       */
+      return TGSI_WRITEMASK_XYZ; /* A ==> 1.0 */
+   }
+   else {
+      /* Otherwise fail.
+       */
+      return 0;
+   }
+}
+
+
+
 /**
  * Do a CopyTex[Sub]Image1/2/3D() using a hardware (blit) path if possible.
  * Note that the region to copy has already been clipped so we know we
@@ -1314,6 +1453,12 @@ st_copy_texsubimage(GLcontext *ctx,
    enum pipe_format dest_format, src_format;
    GLboolean use_fallback = GL_TRUE;
    GLboolean matching_base_formats;
+   GLuint format_writemask;
+   struct pipe_surface *dest_surface = NULL;
+   GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
+
+   /* any rendering in progress must flushed before we grab the fb image */
+   st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
 
    /* make sure finalize_textures has been called? 
     */
@@ -1337,6 +1482,34 @@ st_copy_texsubimage(GLcontext *ctx,
       return;
    }
 
+   if (srcX < 0) {
+      width -= -srcX;
+      destX += -srcX;
+      srcX = 0;
+   }
+
+   if (srcY < 0) {
+      height -= -srcY;
+      destY += -srcY;
+      srcY = 0;
+   }
+
+   if (destX < 0) {
+      width -= -destX;
+      srcX += -destX;
+      destX = 0;
+   }
+
+   if (destY < 0) {
+      height -= -destY;
+      srcY += -destY;
+      destY = 0;
+   }
+
+   if (width < 0 || height < 0)
+      return;
+
+
    assert(strb);
    assert(strb->surface);
    assert(stImage->pt);
@@ -1353,13 +1526,14 @@ st_copy_texsubimage(GLcontext *ctx,
     * textured-quad paths.
     */
    matching_base_formats = (strb->Base._BaseFormat == texImage->_BaseFormat);
+   format_writemask = compatible_src_dst_formats(&strb->Base, texImage);
 
-   if (matching_base_formats && ctx->_ImageTransferState == 0x0) {
-      /* try potential hardware path */
-      struct pipe_surface *dest_surface = NULL;
-      boolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
+   if (ctx->_ImageTransferState == 0x0) {
 
-      if (src_format == dest_format && !do_flip) {
+      if (matching_base_formats && 
+          src_format == dest_format &&
+          !do_flip) 
+      {
          /* use surface_copy() / blit */
 
          dest_surface = screen->get_tex_surface(screen, stImage->pt,
@@ -1379,7 +1553,8 @@ st_copy_texsubimage(GLcontext *ctx,
                             width, height);
          use_fallback = GL_FALSE;
       }
-      else if (screen->is_format_supported(screen, src_format,
+      else if (format_writemask &&
+               screen->is_format_supported(screen, src_format,
                                            PIPE_TEXTURE_2D, 
                                            PIPE_TEXTURE_USAGE_SAMPLER,
                                            0) &&
@@ -1403,14 +1578,15 @@ st_copy_texsubimage(GLcontext *ctx,
             srcY0 = srcY;
             srcY1 = srcY0 + height;
          }
-         util_blit_pixels(ctx->st->blit,
-                          strb->surface,
-                          srcX, srcY0,
-                          srcX + width, srcY1,
-                          dest_surface,
-                          destX, destY,
-                          destX + width, destY + height,
-                          0.0, PIPE_TEX_MIPFILTER_NEAREST);
+         util_blit_pixels_writemask(ctx->st->blit,
+                                    strb->surface,
+                                    srcX, srcY0,
+                                    srcX + width, srcY1,
+                                    dest_surface,
+                                    destX, destY,
+                                    destX + width, destY + height,
+                                    0.0, PIPE_TEX_MIPFILTER_NEAREST,
+                                    format_writemask);
          use_fallback = GL_FALSE;
       }
 
@@ -1425,10 +1601,6 @@ st_copy_texsubimage(GLcontext *ctx,
                                 destX, destY, destZ,
                                 srcX, srcY, width, height);
    }
-
-   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
-      ctx->Driver.GenerateMipmap(ctx, target, texObj);
-   }
 }
 
 
@@ -1785,6 +1957,9 @@ st_init_texture_functions(struct dd_function_table *functions)
    functions->TexSubImage1D = st_TexSubImage1D;
    functions->TexSubImage2D = st_TexSubImage2D;
    functions->TexSubImage3D = st_TexSubImage3D;
+   functions->CompressedTexSubImage1D = st_CompressedTexSubImage1D;
+   functions->CompressedTexSubImage2D = st_CompressedTexSubImage2D;
+   functions->CompressedTexSubImage3D = st_CompressedTexSubImage3D;
    functions->CopyTexImage1D = st_CopyTexImage1D;
    functions->CopyTexImage2D = st_CopyTexImage2D;
    functions->CopyTexSubImage1D = st_CopyTexSubImage1D;