st/mesa: fix guessing the base level size
[mesa.git] / src / mesa / state_tracker / st_cb_texture.c
index 9d1b7f672f5dc6917844119563986db0600097b6..9619dd290ed5ec01b788d56d040f19784d77d38b 100644 (file)
@@ -73,22 +73,38 @@ gl_target_to_pipe(GLenum target)
 {
    switch (target) {
    case GL_TEXTURE_1D:
+   case GL_PROXY_TEXTURE_1D:
       return PIPE_TEXTURE_1D;
    case GL_TEXTURE_2D:
+   case GL_PROXY_TEXTURE_2D:
    case GL_TEXTURE_EXTERNAL_OES:
       return PIPE_TEXTURE_2D;
    case GL_TEXTURE_RECTANGLE_NV:
+   case GL_PROXY_TEXTURE_RECTANGLE_NV:
       return PIPE_TEXTURE_RECT;
    case GL_TEXTURE_3D:
+   case GL_PROXY_TEXTURE_3D:
       return PIPE_TEXTURE_3D;
    case GL_TEXTURE_CUBE_MAP_ARB:
+   case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
       return PIPE_TEXTURE_CUBE;
    case GL_TEXTURE_1D_ARRAY_EXT:
+   case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
       return PIPE_TEXTURE_1D_ARRAY;
    case GL_TEXTURE_2D_ARRAY_EXT:
+   case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
       return PIPE_TEXTURE_2D_ARRAY;
    case GL_TEXTURE_BUFFER:
       return PIPE_BUFFER;
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+      return PIPE_TEXTURE_CUBE_ARRAY;
    default:
       assert(0);
       return 0;
@@ -237,36 +253,6 @@ default_bindings(struct st_context *st, enum pipe_format format)
 }
 
 
-/** Return number of image dimensions (1, 2 or 3) for a texture target. */
-static GLuint
-get_texture_dims(GLenum target)
-{
-   switch (target) {
-   case GL_TEXTURE_1D:
-   case GL_TEXTURE_1D_ARRAY_EXT:
-   case GL_TEXTURE_BUFFER:
-      return 1;
-   case GL_TEXTURE_2D:
-   case GL_TEXTURE_CUBE_MAP_ARB:
-   case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
-   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
-   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
-   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
-   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
-   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
-   case GL_TEXTURE_RECTANGLE_NV:
-   case GL_TEXTURE_2D_ARRAY_EXT:
-   case GL_TEXTURE_EXTERNAL_OES:
-      return 2;
-   case GL_TEXTURE_3D:
-      return 3;
-   default:
-      assert(0 && "invalid texture target in get_texture_dims()");
-      return 1;
-   }
-}
-
-
 /**
  * Given the size of a mipmap image, try to compute the size of the level=0
  * mipmap image.
@@ -281,32 +267,57 @@ guess_base_level_size(GLenum target,
                       GLuint width, GLuint height, GLuint depth, GLuint level,
                       GLuint *width0, GLuint *height0, GLuint *depth0)
 { 
-   const GLuint dims = get_texture_dims(target);
-
    assert(width >= 1);
    assert(height >= 1);
    assert(depth >= 1);
 
    if (level > 0) {
-      /* Depending on the image's size, we can't always make a guess here */
-      if ((dims >= 1 && width == 1) ||
-          (dims >= 2 && height == 1) ||
-          (dims >= 3 && depth == 1)) {
-         /* we can't determine the image size at level=0 */
-         return GL_FALSE;
-      }
+      /* Guess the size of the base level.
+       * Depending on the image's size, we can't always make a guess here.
+       */
+      switch (target) {
+      case GL_TEXTURE_1D:
+      case GL_TEXTURE_1D_ARRAY:
+         width <<= level;
+         break;
+
+      case GL_TEXTURE_2D:
+      case GL_TEXTURE_2D_ARRAY:
+         /* We can't make a good guess here, because the base level dimensions
+          * can be non-square.
+          */
+         if (width == 1 || height == 1) {
+            return GL_FALSE;
+         }
+         width <<= level;
+         height <<= level;
+         break;
+
+      case GL_TEXTURE_CUBE_MAP:
+      case GL_TEXTURE_CUBE_MAP_ARRAY:
+         width <<= level;
+         height <<= level;
+         break;
+
+      case GL_TEXTURE_3D:
+         /* We can't make a good guess here, because the base level dimensions
+          * can be non-cube.
+          */
+         if (width == 1 || height == 1 || depth == 1) {
+            return GL_FALSE;
+         }
+         width <<= level;
+         height <<= level;
+         depth <<= level;
+         break;
 
-      /* grow the image size until we hit level = 0 */
-      while (level > 0) {
-         if (width > 1)
-            width <<= 1;
-         if (height > 1)
-            height <<= 1;
-         if (depth > 1)
-            depth <<= 1;
-         level--;
+      case GL_TEXTURE_RECTANGLE:
+         break;
+
+      default:
+         assert(0);
       }
-   }      
+   }
 
    *width0 = width;
    *height0 = height;
@@ -362,6 +373,8 @@ guess_and_alloc_texture(struct st_context *st,
     */
    if ((stObj->base.Sampler.MinFilter == GL_NEAREST ||
         stObj->base.Sampler.MinFilter == GL_LINEAR ||
+        (stObj->base.BaseLevel == 0 &&
+         stObj->base.MaxLevel == 0) ||
         stImage->base._BaseFormat == GL_DEPTH_COMPONENT ||
         stImage->base._BaseFormat == GL_DEPTH_STENCIL_EXT) &&
        !stObj->base.GenerateMipmap &&
@@ -415,20 +428,18 @@ guess_and_alloc_texture(struct st_context *st,
  */
 static GLboolean
 st_AllocTextureImageBuffer(struct gl_context *ctx,
-                           struct gl_texture_image *texImage,
-                           gl_format format, GLsizei width,
-                           GLsizei height, GLsizei depth)
+                           struct gl_texture_image *texImage)
 {
    struct st_context *st = st_context(ctx);
    struct st_texture_image *stImage = st_texture_image(texImage);
    struct st_texture_object *stObj = st_texture_object(texImage->TexObject);
    const GLuint level = texImage->Level;
+   GLuint width = texImage->Width;
+   GLuint height = texImage->Height;
+   GLuint depth = texImage->Depth;
 
    DBG("%s\n", __FUNCTION__);
 
-   assert(width > 0);
-   assert(height > 0);
-   assert(depth > 0);
    assert(!stImage->TexData);
    assert(!stImage->pt); /* xxx this might be wrong */
 
@@ -500,8 +511,6 @@ st_AllocTextureImageBuffer(struct gl_context *ctx,
  */
 static void
 prep_teximage(struct gl_context *ctx, struct gl_texture_image *texImage,
-              GLint internalFormat,
-              GLint width, GLint height, GLint depth, GLint border,
               GLenum format, GLenum type)
 {
    struct gl_texture_object *texObj = texImage->TexObject;
@@ -518,11 +527,13 @@ prep_teximage(struct gl_context *ctx, struct gl_texture_image *texImage,
 
       /* oops, need to init this image again */
       texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
-                                              internalFormat, format, type);
+                                              texImage->InternalFormat, format,
+                                              type);
 
       _mesa_init_teximage_fields(ctx, texImage,
-                                 width, height, depth, border,
-                                 internalFormat, texFormat);
+                                 texImage->Width, texImage->Height,
+                                 texImage->Depth, texImage->Border,
+                                 texImage->InternalFormat, texFormat);
 
       stObj->surface_based = GL_FALSE;
    }
@@ -532,29 +543,21 @@ prep_teximage(struct gl_context *ctx, struct gl_texture_image *texImage,
 static void
 st_TexImage(struct gl_context * ctx, GLuint dims,
             struct gl_texture_image *texImage,
-            GLint internalFormat,
-            GLint width, GLint height, GLint depth, GLint border,
             GLenum format, GLenum type, const void *pixels,
             const struct gl_pixelstore_attrib *unpack)
 {
-   prep_teximage(ctx, texImage, internalFormat, width, height, depth, border,
-                 format, type);
-   _mesa_store_teximage(ctx, dims, texImage, internalFormat, width, height, depth,
-                        border, format, type, pixels, unpack);
+   prep_teximage(ctx, texImage, format, type);
+   _mesa_store_teximage(ctx, dims, texImage, format, type, pixels, unpack);
 }
 
 
 static void
 st_CompressedTexImage(struct gl_context *ctx, GLuint dims,
                       struct gl_texture_image *texImage,
-                      GLint internalFormat,
-                      GLint width, GLint height, GLint border, GLint depth,
                       GLsizei imageSize, const GLvoid *data)
 {
-   prep_teximage(ctx, texImage, internalFormat, width, height, depth, border,
-                 GL_NONE, GL_NONE);
-   _mesa_store_compressed_teximage(ctx, dims, texImage, internalFormat, width,
-                                   height, depth, border, imageSize, data);
+   prep_teximage(ctx, texImage, GL_NONE, GL_NONE);
+   _mesa_store_compressed_teximage(ctx, dims, texImage, imageSize, data);
 }
 
 
@@ -572,76 +575,58 @@ decompress_with_blit(struct gl_context * ctx,
    struct pipe_context *pipe = st->pipe;
    struct st_texture_image *stImage = st_texture_image(texImage);
    struct st_texture_object *stObj = st_texture_object(texImage->TexObject);
-   struct pipe_sampler_view *src_view;
    const GLuint width = texImage->Width;
    const GLuint height = texImage->Height;
-   struct pipe_surface *dst_surface;
    struct pipe_resource *dst_texture;
+   struct pipe_blit_info blit;
+   unsigned bind = (PIPE_BIND_RENDER_TARGET | PIPE_BIND_TRANSFER_READ);
    struct pipe_transfer *tex_xfer;
-   unsigned bind = (PIPE_BIND_RENDER_TARGET | /* util_blit may choose to render */
-                   PIPE_BIND_TRANSFER_READ);
+   ubyte *map;
 
    /* create temp / dest surface */
-   if (!util_create_rgba_surface(pipe, width, height, bind,
-                                 &dst_texture, &dst_surface)) {
-      _mesa_problem(ctx, "util_create_rgba_surface() failed "
+   if (!util_create_rgba_texture(pipe, width, height, bind,
+                                 &dst_texture)) {
+      _mesa_problem(ctx, "util_create_rgba_texture() failed "
                     "in decompress_with_blit()");
       return;
    }
 
-   /* Disable conditional rendering. */
-   if (st->render_condition) {
-      pipe->render_condition(pipe, NULL, 0);
-   }
-
-   /* Create sampler view that limits fetches to the source mipmap level */
-   {
-      struct pipe_sampler_view sv_temp;
-
-      u_sampler_view_default_template(&sv_temp, stObj->pt, stObj->pt->format);
-
-      sv_temp.u.tex.first_level =
-      sv_temp.u.tex.last_level = texImage->Level;
-
-      src_view = pipe->create_sampler_view(pipe, stObj->pt, &sv_temp);
-      if (!src_view) {
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
-         return;
-      }
-   }
+   blit.src.resource = stObj->pt;
+   blit.src.level = texImage->Level;
+   blit.src.format = util_format_linear(stObj->pt->format);
+   blit.dst.resource = dst_texture;
+   blit.dst.level = 0;
+   blit.dst.format = dst_texture->format;
+   blit.src.box.x = blit.dst.box.x = 0;
+   blit.src.box.y = blit.dst.box.y = 0;
+   blit.src.box.z = 0; /* XXX compressed array textures? */
+   blit.dst.box.z = 0;
+   blit.src.box.width = blit.dst.box.width = width;
+   blit.src.box.height = blit.dst.box.height = height;
+   blit.src.box.depth = blit.dst.box.depth = 1;
+   blit.mask = PIPE_MASK_RGBA;
+   blit.filter = PIPE_TEX_FILTER_NEAREST;
+   blit.scissor_enable = FALSE;
 
    /* blit/render/decompress */
-   util_blit_pixels_tex(st->blit,
-                        src_view,      /* pipe_resource (src) */
-                        0, 0,             /* src x0, y0 */
-                        width, height,    /* src x1, y1 */
-                        dst_surface,      /* pipe_surface (dst) */
-                        0, 0,             /* dst x0, y0 */
-                        width, height,    /* dst x1, y1 */
-                        0.0,              /* z */
-                        PIPE_TEX_MIPFILTER_NEAREST);
-
-   /* Restore conditional rendering state. */
-   if (st->render_condition) {
-      pipe->render_condition(pipe, st->render_condition,
-                             st->condition_mode);
-   }
-
-   /* map the dst_surface so we can read from it */
-   tex_xfer = pipe_get_transfer(pipe,
-                                dst_texture, 0, 0,
-                                PIPE_TRANSFER_READ,
-                                0, 0, width, height);
+   st->pipe->blit(st->pipe, &blit);
 
    pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels);
 
+   map = pipe_transfer_map(pipe, dst_texture, 0, 0,
+                           PIPE_TRANSFER_READ,
+                           0, 0, width, height, &tex_xfer);
+   if (!map) {
+      goto end;
+   }
+
    /* copy/pack data into user buffer */
    if (_mesa_format_matches_format_and_type(stImage->base.TexFormat,
                                             format, type,
                                             ctx->Pack.SwapBytes)) {
       /* memcpy */
       const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format);
-      ubyte *map = pipe_transfer_map(pipe, tex_xfer);
+      /* map the dst_surface so we can read from it */
       GLuint row;
       for (row = 0; row < height; row++) {
          GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width,
@@ -657,7 +642,7 @@ decompress_with_blit(struct gl_context * ctx,
       enum pipe_format pformat = util_format_linear(dst_texture->format);
       GLfloat *rgba;
 
-      rgba = (GLfloat *) malloc(width * 4 * sizeof(GLfloat));
+      rgba = malloc(width * 4 * sizeof(GLfloat));
       if (!rgba) {
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
          goto end;
@@ -672,7 +657,7 @@ decompress_with_blit(struct gl_context * ctx,
             debug_printf("%s: fallback format translation\n", __FUNCTION__);
 
          /* get float[4] rgba row from surface */
-         pipe_get_tile_rgba_format(pipe, tex_xfer, 0, row, width, 1,
+         pipe_get_tile_rgba_format(tex_xfer, map, 0, row, width, 1,
                                    pformat, rgba);
 
          _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format,
@@ -683,14 +668,11 @@ decompress_with_blit(struct gl_context * ctx,
    }
 
 end:
-   _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
-
-   pipe->transfer_destroy(pipe, tex_xfer);
-
-   /* destroy the temp / dest surface */
-   util_destroy_rgba_surface(dst_texture, dst_surface);
+   if (map)
+      pipe_transfer_unmap(pipe, tex_xfer);
 
-   pipe_sampler_view_release(pipe, &src_view);
+   _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
+   pipe_resource_reference(&dst_texture, NULL);
 }
 
 
@@ -740,6 +722,7 @@ fallback_copy_texsubimage(struct gl_context *ctx,
    struct pipe_transfer *src_trans;
    GLvoid *texDest;
    enum pipe_transfer_usage transfer_usage;
+   void *map;
 
    if (ST_DEBUG & DEBUG_FALLBACK)
       debug_printf("%s: fallback processing\n", __FUNCTION__);
@@ -748,13 +731,13 @@ fallback_copy_texsubimage(struct gl_context *ctx,
       srcY = strb->Base.Height - srcY - height;
    }
 
-   src_trans = pipe_get_transfer(pipe,
-                                 strb->texture,
-                                 strb->rtt_level,
-                                 strb->rtt_face + strb->rtt_slice,
-                                 PIPE_TRANSFER_READ,
-                                 srcX, srcY,
-                                 width, height);
+   map = pipe_transfer_map(pipe,
+                           strb->texture,
+                           strb->rtt_level,
+                           strb->rtt_face + strb->rtt_slice,
+                           PIPE_TRANSFER_READ,
+                           srcX, srcY,
+                           width, height, &src_trans);
 
    if ((baseFormat == GL_DEPTH_COMPONENT ||
         baseFormat == GL_DEPTH_STENCIL) &&
@@ -784,16 +767,17 @@ fallback_copy_texsubimage(struct gl_context *ctx,
          yStep = 1;
       }
 
-      data = (uint *) malloc(width * sizeof(uint));
+      data = malloc(width * sizeof(uint));
 
       if (data) {
          /* To avoid a large temp memory allocation, do copy row by row */
          for (row = 0; row < height; row++, srcY += yStep) {
-            pipe_get_tile_z(pipe, src_trans, 0, srcY, width, 1, data);
+            pipe_get_tile_z(src_trans, map, 0, srcY, width, 1, data);
             if (scaleOrBias) {
                _mesa_scale_and_bias_depth_uint(ctx, width, data);
             }
-            pipe_put_tile_z(pipe, stImage->transfer, 0, row, width, 1, data);
+            pipe_put_tile_z(stImage->transfer, texDest, 0, row, width, 1,
+                            data);
          }
       }
       else {
@@ -805,7 +789,7 @@ fallback_copy_texsubimage(struct gl_context *ctx,
    else {
       /* RGBA format */
       GLfloat *tempSrc =
-         (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
+         malloc(width * height * 4 * sizeof(GLfloat));
 
       if (tempSrc && texDest) {
          const GLint dims = 2;
@@ -821,7 +805,7 @@ fallback_copy_texsubimage(struct gl_context *ctx,
          /* XXX this usually involves a lot of int/float conversion.
           * try to avoid that someday.
           */
-         pipe_get_tile_rgba_format(pipe, src_trans, 0, 0, width, height,
+         pipe_get_tile_rgba_format(src_trans, map, 0, 0, width, height,
                                    util_format_linear(strb->texture->format),
                                    tempSrc);
 
@@ -844,12 +828,11 @@ fallback_copy_texsubimage(struct gl_context *ctx,
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
       }
 
-      if (tempSrc)
-         free(tempSrc);
+      free(tempSrc);
    }
 
    st_texture_image_unmap(st, stImage);
-   pipe->transfer_destroy(pipe, src_trans);
+   pipe->transfer_unmap(pipe, src_trans);
 }
 
 
@@ -936,14 +919,13 @@ st_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
 {
    struct st_texture_image *stImage = st_texture_image(texImage);
    const GLenum texBaseFormat = texImage->_BaseFormat;
-   struct gl_framebuffer *fb = ctx->ReadBuffer;
-   struct st_renderbuffer *strb;
+   struct st_renderbuffer *strb = st_renderbuffer(rb);
    struct st_context *st = st_context(ctx);
    struct pipe_context *pipe = st->pipe;
    struct pipe_screen *screen = pipe->screen;
    enum pipe_format dest_format, src_format;
    GLboolean matching_base_formats;
-   GLuint format_writemask, sample_count;
+   GLuint color_writemask, zs_writemask, sample_count;
    struct pipe_surface *dest_surface = NULL;
    GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
    struct pipe_surface surf_tmpl;
@@ -954,16 +936,6 @@ st_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
     */
    if (0) st_validate_state(st);
 
-   /* determine if copying depth or color data */
-   if (texBaseFormat == GL_DEPTH_COMPONENT ||
-       texBaseFormat == GL_DEPTH_STENCIL) {
-      strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer);
-   }
-   else {
-      /* texBaseFormat == GL_RGB, GL_RGBA, GL_ALPHA, etc */
-      strb = st_renderbuffer(fb->_ColorReadBuffer);
-   }
-
    if (!strb || !strb->surface || !stImage->pt) {
       debug_printf("%s: null strb or stImage\n", __FUNCTION__);
       return;
@@ -998,19 +970,37 @@ st_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
       goto fallback;
    }
 
+   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
+      /* 1D arrays might be thought of as 2D images but the actual layout
+       * might not be that way.  At some points, we convert OpenGL's 1D
+       * array 'height' into gallium 'layers' and that prevents the blit
+       * utility code from doing the right thing.  Simpy use the memcpy-based
+       * fallback.
+       */
+      goto fallback;
+   }
+
    if (matching_base_formats &&
        src_format == dest_format &&
        !do_flip) {
       /* use surface_copy() / blit */
       struct pipe_box src_box;
+      unsigned dstLevel;
+
       u_box_2d_zslice(srcX, srcY, strb->surface->u.tex.first_layer,
                       width, height, &src_box);
 
+      /* If stImage->pt is an independent image (not a pointer into a full
+       * mipmap) stImage->pt.last_level will be zero and we need to use that
+       * as the dest level.
+       */
+      dstLevel = MIN2(stImage->base.Level, stImage->pt->last_level);
+
       /* for resource_copy_region(), y=0=top, always */
       pipe->resource_copy_region(pipe,
                                  /* dest */
                                  stImage->pt,
-                                 stImage->base.Level,
+                                 dstLevel,
                                  destX, destY, destZ + stImage->base.Face,
                                  /* src */
                                  strb->texture,
@@ -1024,15 +1014,17 @@ st_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
    }
 
    if (texBaseFormat == GL_DEPTH_COMPONENT) {
-      format_writemask = TGSI_WRITEMASK_XYZW;
+      color_writemask = 0;
+      zs_writemask = BLIT_WRITEMASK_Z;
       dst_usage = PIPE_BIND_DEPTH_STENCIL;
    }
    else {
-      format_writemask = compatible_src_dst_formats(ctx, &strb->Base, texImage);
+      color_writemask = compatible_src_dst_formats(ctx, &strb->Base, texImage);
+      zs_writemask = 0;
       dst_usage = PIPE_BIND_RENDER_TARGET;
    }
 
-   if (!format_writemask ||
+   if ((!color_writemask && !zs_writemask) ||
        !screen->is_format_supported(screen, src_format,
                                     PIPE_TEXTURE_2D, sample_count,
                                     PIPE_BIND_SAMPLER_VIEW) ||
@@ -1065,17 +1057,17 @@ st_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
 
    dest_surface = pipe->create_surface(pipe, stImage->pt,
                                        &surf_tmpl);
-   util_blit_pixels_writemask(st->blit,
-                              strb->texture,
-                              strb->surface->u.tex.level,
-                              srcX, srcY0,
-                              srcX + width, srcY1,
-                              strb->surface->u.tex.first_layer,
-                              dest_surface,
-                              destX, destY,
-                              destX + width, destY + height,
-                              0.0, PIPE_TEX_MIPFILTER_NEAREST,
-                              format_writemask);
+   util_blit_pixels(st->blit,
+                    strb->texture,
+                    strb->surface->u.tex.level,
+                    srcX, srcY0,
+                    srcX + width, srcY1,
+                    strb->surface->u.tex.first_layer,
+                    dest_surface,
+                    destX, destY,
+                    destX + width, destY + height,
+                    0.0, PIPE_TEX_MIPFILTER_NEAREST,
+                    color_writemask, zs_writemask);
    pipe_surface_reference(&dest_surface, NULL);
 
    /* Restore conditional rendering state. */
@@ -1119,11 +1111,19 @@ copy_image_data_to_texture(struct st_context *st,
       /* Copy potentially with the blitter:
        */
       GLuint src_level;
-      if (stImage->pt != stObj->pt)
+      if (stImage->pt->last_level == 0)
          src_level = 0;
       else
          src_level = stImage->base.Level;
 
+      assert(src_level <= stImage->pt->last_level);
+      assert(u_minify(stImage->pt->width0, src_level) == stImage->base.Width);
+      assert(stImage->pt->target == PIPE_TEXTURE_1D_ARRAY ||
+             u_minify(stImage->pt->height0, src_level) == stImage->base.Height);
+      assert(stImage->pt->target == PIPE_TEXTURE_2D_ARRAY ||
+             stImage->pt->target == PIPE_TEXTURE_CUBE_ARRAY ||
+             u_minify(stImage->pt->depth0, src_level) == stImage->base.Depth);
+
       st_texture_image_copy(st->pipe,
                             stObj->pt, dstLevel,  /* dest texture, level */
                             stImage->pt, src_level, /* src texture, level */
@@ -1298,7 +1298,7 @@ st_AllocTextureStorage(struct gl_context *ctx,
                        GLsizei levels, GLsizei width,
                        GLsizei height, GLsizei depth)
 {
-   const GLuint numFaces = (texObj->Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
+   const GLuint numFaces = _mesa_num_tex_faces(texObj->Target);
    struct st_context *st = st_context(ctx);
    struct st_texture_object *stObj = st_texture_object(texObj);
    GLuint ptWidth, ptHeight, ptDepth, ptLayers, bindings;
@@ -1347,6 +1347,57 @@ st_AllocTextureStorage(struct gl_context *ctx,
 }
 
 
+static GLboolean
+st_TestProxyTexImage(struct gl_context *ctx, GLenum target,
+                     GLint level, gl_format format,
+                     GLint width, GLint height,
+                     GLint depth, GLint border)
+{
+   struct st_context *st = st_context(ctx);
+   struct pipe_context *pipe = st->pipe;
+
+   if (width == 0 || height == 0 || depth == 0) {
+      /* zero-sized images are legal, and always fit! */
+      return GL_TRUE;
+   }
+
+   if (pipe->screen->can_create_resource) {
+      /* Ask the gallium driver if the texture is too large */
+      struct gl_texture_object *texObj =
+         _mesa_get_current_tex_object(ctx, target);
+      struct pipe_resource pt;
+
+      /* Setup the pipe_resource object
+       */
+      memset(&pt, 0, sizeof(pt));
+
+      pt.target = gl_target_to_pipe(target);
+      pt.format = st_mesa_format_to_pipe_format(format);
+
+      st_gl_texture_dims_to_pipe_dims(target,
+                                      width, height, depth,
+                                      &pt.width0, &pt.height0,
+                                      &pt.depth0, &pt.array_size);
+
+      if (level == 0 && (texObj->Sampler.MinFilter == GL_LINEAR ||
+                         texObj->Sampler.MinFilter == GL_NEAREST)) {
+         /* assume just one mipmap level */
+         pt.last_level = 0;
+      }
+      else {
+         /* assume a full set of mipmaps */
+         pt.last_level = _mesa_logbase2(MAX3(width, height, depth));
+      }
+
+      return pipe->screen->can_create_resource(pipe->screen, &pt);
+   }
+   else {
+      /* Use core Mesa fallback */
+      return _mesa_test_proxy_teximage(ctx, target, level, format,
+                                       width, height, depth, border);
+   }
+}
+
 
 void
 st_init_texture_functions(struct dd_function_table *functions)
@@ -1374,7 +1425,7 @@ st_init_texture_functions(struct dd_function_table *functions)
    functions->UnmapTextureImage = st_UnmapTextureImage;
 
    /* XXX Temporary until we can query pipe's texture sizes */
-   functions->TestProxyTexImage = _mesa_test_proxy_teximage;
+   functions->TestProxyTexImage = st_TestProxyTexImage;
 
    functions->AllocTextureStorage = st_AllocTextureStorage;
 }