intel: Keep track of x,y offsets in miptrees and use them for blitting.
authorEric Anholt <eric@anholt.net>
Thu, 9 Jul 2009 16:32:21 +0000 (09:32 -0700)
committerEric Anholt <eric@anholt.net>
Fri, 23 Oct 2009 21:12:24 +0000 (14:12 -0700)
By just using offsets, we confused the hardware's tiling calculations,
resulting in failures in miptree validation and blit clears.

Fixes piglit fbo-clearmipmap.

Bug #23552. (automatic mipmap generation)

src/mesa/drivers/dri/i965/brw_tex_layout.c
src/mesa/drivers/dri/intel/intel_blit.c
src/mesa/drivers/dri/intel/intel_fbo.c
src/mesa/drivers/dri/intel/intel_mipmap_tree.c
src/mesa/drivers/dri/intel/intel_mipmap_tree.h
src/mesa/drivers/dri/intel/intel_regions.h
src/mesa/drivers/dri/intel/intel_tex_copy.c
src/mesa/drivers/dri/intel/intel_tex_image.c

index 5986cbffade3ee81180863ec6388dd7d95228dc1..e59e52ed8612da84da15c1d99b3e34198d8531c1 100644 (file)
@@ -86,10 +86,10 @@ GLboolean brw_miptree_layout(struct intel_context *intel,
           mt->pitch = intel_miptree_pitch_align(intel, mt, tiling, mt->pitch);
 
           if (mt->compressed) {
-              qpitch = (y_pitch + ALIGN(minify(y_pitch), align_h) + 11 * align_h) / 4 * mt->pitch * mt->cpp;
+              qpitch = (y_pitch + ALIGN(minify(y_pitch), align_h) + 11 * align_h) / 4;
               mt->total_height = (y_pitch + ALIGN(minify(y_pitch), align_h) + 11 * align_h) / 4 * 6;
           } else {
-              qpitch = (y_pitch + ALIGN(minify(y_pitch), align_h) + 11 * align_h) * mt->pitch * mt->cpp;
+              qpitch = (y_pitch + ALIGN(minify(y_pitch), align_h) + 11 * align_h);
               mt->total_height = (y_pitch + ALIGN(minify(y_pitch), align_h) + 11 * align_h) * 6;
           }
 
@@ -102,7 +102,8 @@ GLboolean brw_miptree_layout(struct intel_context *intel,
                                            height, 1);
 
               for (q = 0; q < nr_images; q++)
-                  intel_miptree_set_image_offset_ex(mt, level, q, x, y, q * qpitch);
+                  intel_miptree_set_image_offset(mt, level, q,
+                                                x, y + q * qpitch);
 
               if (mt->compressed)
                   img_height = MAX2(1, height/4);
index 0c5be4c79892d632360a4b8aaf91e5ba53a8cc0b..ec4a5b492aecb621921b50d45e9600bc29abbbd2 100644 (file)
@@ -441,6 +441,10 @@ intelClearWithBlit(GLcontext *ctx, GLbitfield mask)
                   intel_region_buffer(intel, irb->region,
                                       all ? INTEL_WRITE_FULL :
                                       INTEL_WRITE_PART);
+              int x1 = b.x1 + irb->region->draw_x;
+              int y1 = b.y1 + irb->region->draw_y;
+              int x2 = b.x2 + irb->region->draw_x;
+              int y2 = b.y2 + irb->region->draw_y;
 
                GLuint clearVal;
                GLint pitch, cpp;
@@ -449,11 +453,10 @@ intelClearWithBlit(GLcontext *ctx, GLbitfield mask)
                pitch = irb->region->pitch;
                cpp = irb->region->cpp;
 
-               DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
+               DBG("%s dst:buf(%p)/%d %d,%d sz:%dx%d\n",
                    __FUNCTION__,
                    irb->region->buffer, (pitch * cpp),
-                   irb->region->draw_offset,
-                   b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1);
+                   x1, y1, x2 - x1, y2 - y1);
 
               BR13 = 0xf0 << 16;
               CMD = XY_COLOR_BLT_CMD;
@@ -526,17 +529,17 @@ intelClearWithBlit(GLcontext *ctx, GLbitfield mask)
                   buf, irb->Base.Name);
                 */
 
-               assert(b.x1 < b.x2);
-               assert(b.y1 < b.y2);
+               assert(x1 < x2);
+               assert(y1 < y2);
 
                BEGIN_BATCH(6, REFERENCES_CLIPRECTS);
                OUT_BATCH(CMD);
                OUT_BATCH(BR13);
-               OUT_BATCH((b.y1 << 16) | b.x1);
-               OUT_BATCH((b.y2 << 16) | b.x2);
+               OUT_BATCH((y1 << 16) | x1);
+               OUT_BATCH((y2 << 16) | x2);
                OUT_RELOC(write_buffer,
                         I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
-                         irb->region->draw_offset);
+                         0);
                OUT_BATCH(clearVal);
                ADVANCE_BATCH();
                clearMask &= ~bufBit;    /* turn off bit, for faster loop exit */
index 804c03484013138d40edde161ed59271472e719e..cf007d5b62bf2f7554f106f2267f48e75072759d 100644 (file)
@@ -571,7 +571,7 @@ intel_render_texture(GLcontext * ctx,
       = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
    struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer);
    struct intel_texture_image *intel_image;
-   GLuint imageOffset;
+   GLuint dst_x, dst_y;
 
    (void) fb;
 
@@ -618,18 +618,16 @@ intel_render_texture(GLcontext * ctx,
    }
 
    /* compute offset of the particular 2D image within the texture region */
-   imageOffset = intel_miptree_image_offset(intel_image->mt,
-                                            att->CubeMapFace,
-                                            att->TextureLevel);
-
-   if (att->Texture->Target == GL_TEXTURE_3D) {
-      const GLuint *offsets = intel_miptree_depth_offsets(intel_image->mt,
-                                                          att->TextureLevel);
-      imageOffset += offsets[att->Zoffset];
-   }
-
-   /* store that offset in the region */
-   intel_image->mt->region->draw_offset = imageOffset;
+   intel_miptree_get_image_offset(intel_image->mt,
+                                 att->TextureLevel,
+                                 att->CubeMapFace,
+                                 att->Zoffset,
+                                 &dst_x, &dst_y);
+
+   intel_image->mt->region->draw_offset = (dst_y * intel_image->mt->pitch +
+                                          dst_x) * intel_image->mt->cpp;
+   intel_image->mt->region->draw_x = dst_x;
+   intel_image->mt->region->draw_y = dst_y;
 
    /* update drawing region, etc */
    intel_draw_buffer(ctx, fb);
index 4f5101a312870ff7df302238d0feca45a8035d88..0589d82db2524a5b5a228cf125db4ddd7b0f2593 100644 (file)
@@ -287,9 +287,10 @@ intel_miptree_release(struct intel_context *intel,
 
       intel_region_release(&((*mt)->region));
 
-      for (i = 0; i < MAX_TEXTURE_LEVELS; i++)
-         if ((*mt)->level[i].image_offset)
-            free((*mt)->level[i].image_offset);
+      for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
+        free((*mt)->level[i].x_offset);
+        free((*mt)->level[i].y_offset);
+      }
 
       free(*mt);
    }
@@ -350,82 +351,58 @@ intel_miptree_set_level_info(struct intel_mipmap_tree *mt,
    mt->level[level].height = h;
    mt->level[level].depth = d;
    mt->level[level].level_offset = (x + y * mt->pitch) * mt->cpp;
+   mt->level[level].level_x = x;
+   mt->level[level].level_y = y;
    mt->level[level].nr_images = nr_images;
 
    DBG("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
        level, w, h, d, x, y, mt->level[level].level_offset);
 
-   /* Not sure when this would happen, but anyway: 
-    */
-   if (mt->level[level].image_offset) {
-      free(mt->level[level].image_offset);
-      mt->level[level].image_offset = NULL;
-   }
-
    assert(nr_images);
+   assert(!mt->level[level].x_offset);
 
-   mt->level[level].image_offset = malloc(nr_images * sizeof(GLuint));
-   mt->level[level].image_offset[0] = 0;
+   mt->level[level].x_offset = malloc(nr_images * sizeof(GLuint));
+   mt->level[level].x_offset[0] = mt->level[level].level_x;
+   mt->level[level].y_offset = malloc(nr_images * sizeof(GLuint));
+   mt->level[level].y_offset[0] = mt->level[level].level_y;
 }
 
 
 void
-intel_miptree_set_image_offset_ex(struct intel_mipmap_tree *mt,
-                                  GLuint level, GLuint img,
-                                  GLuint x, GLuint y, 
-                                  GLuint offset)
+intel_miptree_set_image_offset(struct intel_mipmap_tree *mt,
+                              GLuint level, GLuint img,
+                              GLuint x, GLuint y)
 {
    if (img == 0 && level == 0)
       assert(x == 0 && y == 0);
 
    assert(img < mt->level[level].nr_images);
 
-   mt->level[level].image_offset[img] = (x + y * mt->pitch) * mt->cpp + offset;
+   mt->level[level].x_offset[img] = mt->level[level].level_x + x;
+   mt->level[level].y_offset[img] = mt->level[level].level_y + y;
 
-   DBG("%s level %d img %d pos %d,%d image_offset %x\n",
-       __FUNCTION__, level, img, x, y, mt->level[level].image_offset[img]);
+   DBG("%s level %d img %d pos %d,%d\n",
+       __FUNCTION__, level, img,
+       mt->level[level].x_offset[img], mt->level[level].y_offset[img]);
 }
 
 void
-intel_miptree_set_image_offset(struct intel_mipmap_tree *mt,
-                              GLuint level, GLuint img,
-                              GLuint x, GLuint y)
-{
-    intel_miptree_set_image_offset_ex(mt, level, img, x, y, 0);
-}
-
-
-/* Although we use the image_offset[] array to store relative offsets
- * to cube faces, Mesa doesn't know anything about this and expects
- * each cube face to be treated as a separate image.
- *
- * These functions present that view to mesa:
- */
-const GLuint *
-intel_miptree_depth_offsets(struct intel_mipmap_tree *mt, GLuint level)
-{
-   static const GLuint zero = 0;
-
-   if (mt->target != GL_TEXTURE_3D || mt->level[level].nr_images == 1)
-      return &zero;
-   else
-      return mt->level[level].image_offset;
-}
-
-
-GLuint
-intel_miptree_image_offset(struct intel_mipmap_tree *mt,
-                          GLuint face, GLuint level)
+intel_miptree_get_image_offset(struct intel_mipmap_tree *mt,
+                              GLuint level, GLuint face, GLuint depth,
+                              GLuint *x, GLuint *y)
 {
-   if (mt->target == GL_TEXTURE_CUBE_MAP_ARB)
-      return (mt->level[level].level_offset +
-             mt->level[level].image_offset[face]);
-   else
-      return mt->level[level].level_offset;
+   if (mt->target == GL_TEXTURE_CUBE_MAP_ARB) {
+      *x = mt->level[level].x_offset[face];
+      *y = mt->level[level].y_offset[face];
+   } else if (mt->target == GL_TEXTURE_3D) {
+      *x = mt->level[level].x_offset[depth];
+      *y = mt->level[level].y_offset[depth];
+   } else {
+      *x = mt->level[level].x_offset[0];
+      *y = mt->level[level].y_offset[0];
+   }
 }
 
-
-
 /**
  * Map a teximage in a mipmap tree.
  * \param row_stride  returns row stride in bytes
@@ -441,6 +418,7 @@ intel_miptree_image_map(struct intel_context * intel,
                         GLuint level,
                         GLuint * row_stride, GLuint * image_offsets)
 {
+   GLuint x, y;
    DBG("%s \n", __FUNCTION__);
 
    if (row_stride)
@@ -449,17 +427,23 @@ intel_miptree_image_map(struct intel_context * intel,
    if (mt->target == GL_TEXTURE_3D) {
       int i;
 
-      for (i = 0; i < mt->level[level].depth; i++)
-        image_offsets[i] = mt->level[level].image_offset[i] / mt->cpp;
+      for (i = 0; i < mt->level[level].depth; i++) {
+
+        intel_miptree_get_image_offset(mt, level, face, i,
+                                       &x, &y);
+        image_offsets[i] = x + y * mt->pitch;
+      }
+
+      return intel_region_map(intel, mt->region);
    } else {
       assert(mt->level[level].depth == 1);
-      assert(mt->target == GL_TEXTURE_CUBE_MAP ||
-            mt->level[level].image_offset[0] == 0);
+      intel_miptree_get_image_offset(mt, level, face, 0,
+                                    &x, &y);
       image_offsets[0] = 0;
-   }
 
-   return (intel_region_map(intel, mt->region) +
-           intel_miptree_image_offset(mt, face, level));
+      return intel_region_map(intel, mt->region) +
+        (x + y * mt->pitch) * mt->cpp;
+   }
 }
 
 void
@@ -484,20 +468,19 @@ intel_miptree_image_data(struct intel_context *intel,
                         GLuint src_image_pitch)
 {
    GLuint depth = dst->level[level].depth;
-   GLuint dst_offset = intel_miptree_image_offset(dst, face, level);
-   const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level);
    GLuint i;
-   GLuint height = 0;
 
    DBG("%s: %d/%d\n", __FUNCTION__, face, level);
    for (i = 0; i < depth; i++) {
+      GLuint dst_x, dst_y, height;
+
+      intel_miptree_get_image_offset(dst, level, face, i, &dst_x, &dst_y);
+
       height = dst->level[level].height;
       if(dst->compressed)
         height = (height + 3) / 4;
       intel_region_data(intel,
-                       dst->region,
-                       dst_offset + dst_depth_offset[i], /* dst_offset */
-                       0, 0,                             /* dstx, dsty */
+                       dst->region, 0, dst_x, dst_y,
                        src,
                        src_row_pitch,
                        0, 0,                             /* source x, y */
@@ -519,10 +502,7 @@ intel_miptree_image_copy(struct intel_context *intel,
    GLuint width = src->level[level].width;
    GLuint height = src->level[level].height;
    GLuint depth = src->level[level].depth;
-   GLuint dst_offset = intel_miptree_image_offset(dst, face, level);
-   GLuint src_offset = intel_miptree_image_offset(src, face, level);
-   const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level);
-   const GLuint *src_depth_offset = intel_miptree_depth_offsets(src, level);
+   GLuint src_x, src_y, dst_x, dst_y;
    GLuint i;
    GLboolean success;
 
@@ -535,22 +515,23 @@ intel_miptree_image_copy(struct intel_context *intel,
    }
 
    for (i = 0; i < depth; i++) {
+      intel_miptree_get_image_offset(src, level, face, i, &src_x, &src_y);
+      intel_miptree_get_image_offset(dst, level, face, i, &dst_x, &dst_y);
       success = intel_region_copy(intel,
-                                 dst->region, dst_offset + dst_depth_offset[i],
-                                 0, 0,
-                                 src->region, src_offset + src_depth_offset[i],
-                                 0, 0, width, height, GL_COPY);
+                                 dst->region, 0, dst_x, dst_y,
+                                 src->region, 0, src_x, src_y, width, height,
+                                 GL_COPY);
       if (!success) {
         GLubyte *src_ptr, *dst_ptr;
 
         src_ptr = intel_region_map(intel, src->region);
         dst_ptr = intel_region_map(intel, dst->region);
 
-        _mesa_copy_rect(dst_ptr + dst_offset + dst_depth_offset[i],
+        _mesa_copy_rect(dst_ptr + dst->cpp * (dst_x + dst_y * dst->pitch),
                         dst->cpp,
                         dst->pitch,
                         0, 0, width, height,
-                        src_ptr + src_offset + src_depth_offset[i],
+                        src_ptr + src->cpp * (src_x + src_y * src->pitch),
                         src->pitch,
                         0, 0);
         intel_region_unmap(intel, src->region);
index c890b2a0d047488747dc2db7aaaaa36a02da5ec8..3bce54daa15988d4dfad30104126803d778b6bca 100644 (file)
@@ -70,6 +70,10 @@ struct intel_mipmap_level
     * always zero in that case.
     */
    GLuint level_offset;
+   /** Offset to this miptree level, used in computing x_offset. */
+   GLuint level_x;
+   /** Offset to this miptree level, used in computing y_offset. */
+   GLuint level_y;
    GLuint width;
    GLuint height;
    /** Depth of the mipmap at this level: 1 for 1D/2D/CUBE, n for 3D. */
@@ -86,7 +90,7 @@ struct intel_mipmap_level
     * compute the offsets of depth/cube images within a mipmap level,
     * so have to store them as a lookup table.
     */
-   GLuint *image_offset;
+   GLuint *x_offset, *y_offset;
 };
 
 struct intel_mipmap_tree
@@ -176,19 +180,10 @@ GLubyte *intel_miptree_image_map(struct intel_context *intel,
 void intel_miptree_image_unmap(struct intel_context *intel,
                                struct intel_mipmap_tree *mt);
 
-
-/* Return the linear offset of an image relative to the start of the
- * tree:
- */
-GLuint intel_miptree_image_offset(struct intel_mipmap_tree *mt,
-                                  GLuint face, GLuint level);
-
-/* Return pointers to each 2d slice within an image.  Indexed by depth
- * value.
- */
-const GLuint *intel_miptree_depth_offsets(struct intel_mipmap_tree *mt,
-                                          GLuint level);
-
+void
+intel_miptree_get_image_offset(struct intel_mipmap_tree *mt,
+                              GLuint level, GLuint face, GLuint depth,
+                              GLuint *x, GLuint *y);
 
 void intel_miptree_set_level_info(struct intel_mipmap_tree *mt,
                                   GLuint level,
@@ -196,16 +191,10 @@ void intel_miptree_set_level_info(struct intel_mipmap_tree *mt,
                                   GLuint x, GLuint y,
                                   GLuint w, GLuint h, GLuint d);
 
-void intel_miptree_set_image_offset_ex(struct intel_mipmap_tree *mt,
-                                       GLuint level,
-                                       GLuint img, GLuint x, GLuint y,
-                                       GLuint offset);
-
 void intel_miptree_set_image_offset(struct intel_mipmap_tree *mt,
                                     GLuint level,
                                     GLuint img, GLuint x, GLuint y);
 
-
 /* Upload an image into a tree
  */
 void intel_miptree_image_data(struct intel_context *intel,
index 0d379bdc6e273c2483c3cb279fb668fbcefbfe6d..535fcd7be0b2041bd5ac4a8d21f29b659765b300 100644 (file)
@@ -62,6 +62,8 @@ struct intel_region
    GLuint map_refcount;  /**< Reference count for mapping */
 
    GLuint draw_offset; /**< Offset of drawing address within the region */
+   GLuint draw_x, draw_y; /**< Offset of drawing within the region */
+
    uint32_t tiling; /**< Which tiling mode the region is in */
    uint32_t bit_6_swizzle; /**< GEM flag for address swizzling requirement */
    drmAddress classic_map; /**< drmMap of the region when not in GEM mode */
index b241c116251cba1a3dc08cfe097e83f9247a64e9..9d58b11b14ffec747c2296e173dd826f83ae847b 100644 (file)
@@ -115,20 +115,22 @@ do_copy_texsubimage(struct intel_context *intel,
       drm_intel_bo *dst_bo = intel_region_buffer(intel,
                                                 intelImage->mt->region,
                                                 INTEL_WRITE_PART);
-      GLuint image_offset = intel_miptree_image_offset(intelImage->mt,
-                                                       intelImage->face,
-                                                       intelImage->level);
       const GLint orig_x = x;
       const GLint orig_y = y;
+      GLuint image_x, image_y;
       GLshort src_pitch;
 
+      intel_miptree_get_image_offset(intelImage->mt,
+                                    intelImage->level,
+                                    intelImage->face,
+                                    0,
+                                    &image_x, &image_y);
       /* Update dst for clipped src.  Need to also clip the source rect. */
       dstx += x - orig_x;
       dsty += y - orig_y;
 
       /* Can't blit to tiled buffers with non-tile-aligned offset. */
-      if (intelImage->mt->region->tiling != I915_TILING_NONE &&
-         (image_offset & 4095) != 0) {
+      if (intelImage->mt->region->tiling == I915_TILING_Y) {
         UNLOCK_HARDWARE(intel);
         return GL_FALSE;
       }
@@ -160,9 +162,10 @@ do_copy_texsubimage(struct intel_context *intel,
                             src->tiling,
                             intelImage->mt->pitch,
                             dst_bo,
-                            image_offset,
+                            0,
                             intelImage->mt->region->tiling,
-                            x, y, dstx, dsty, width, height,
+                            x, y, image_x + dstx, image_y + dsty,
+                            width, height,
                             GL_COPY)) {
         UNLOCK_HARDWARE(intel);
         return GL_FALSE;
index c5f52208376e98a8ad2d5bc04ef1a4cb9bc86631..2e0945c36574651f3744d549ec69bcb6752ee3ea 100644 (file)
@@ -204,7 +204,7 @@ try_pbo_upload(struct intel_context *intel,
 {
    struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj);
    GLuint src_offset, src_stride;
-   GLuint dst_offset, dst_stride;
+   GLuint dst_x, dst_y, dst_stride;
 
    if (unpack->BufferObj->Name == 0 ||
        intel->ctx._ImageTransferState ||
@@ -221,9 +221,9 @@ try_pbo_upload(struct intel_context *intel,
    else
       src_stride = width;
 
-   dst_offset = intel_miptree_image_offset(intelImage->mt,
-                                           intelImage->face,
-                                           intelImage->level);
+   intel_miptree_get_image_offset(intelImage->mt, intelImage->level,
+                                 intelImage->face, 0,
+                                 &dst_x, &dst_y);
 
    dst_stride = intelImage->mt->pitch;
 
@@ -239,8 +239,8 @@ try_pbo_upload(struct intel_context *intel,
       if (!intelEmitCopyBlit(intel,
                             intelImage->mt->cpp,
                             src_stride, src_buffer, src_offset, GL_FALSE,
-                            dst_stride, dst_buffer, dst_offset, GL_FALSE,
-                            0, 0, 0, 0, width, height,
+                            dst_stride, dst_buffer, 0, GL_FALSE,
+                            0, 0, dst_x, dst_y, width, height,
                             GL_COPY)) {
         UNLOCK_HARDWARE(intel);
         return GL_FALSE;
@@ -262,7 +262,7 @@ try_pbo_zcopy(struct intel_context *intel,
 {
    struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj);
    GLuint src_offset, src_stride;
-   GLuint dst_offset, dst_stride;
+   GLuint dst_x, dst_y, dst_stride;
 
    if (unpack->BufferObj->Name == 0 ||
        intel->ctx._ImageTransferState ||
@@ -279,13 +279,14 @@ try_pbo_zcopy(struct intel_context *intel,
    else
       src_stride = width;
 
-   dst_offset = intel_miptree_image_offset(intelImage->mt,
-                                           intelImage->face,
-                                           intelImage->level);
+   intel_miptree_get_image_offset(intelImage->mt, intelImage->level,
+                                 intelImage->face, 0,
+                                 &dst_x, &dst_y);
 
    dst_stride = intelImage->mt->pitch;
 
-   if (src_stride != dst_stride || dst_offset != 0 || src_offset != 0) {
+   if (src_stride != dst_stride || dst_x != 0 || dst_y != 0 ||
+       src_offset != 0) {
       DBG("%s: failure 2\n", __FUNCTION__);
       return GL_FALSE;
    }