intel: Add support for LLC-cached reads of X-tiled miptrees using a blit.
authorEric Anholt <eric@anholt.net>
Wed, 30 Nov 2011 15:36:26 +0000 (07:36 -0800)
committerEric Anholt <eric@anholt.net>
Wed, 7 Dec 2011 21:38:53 +0000 (13:38 -0800)
This mimics the MapRenderbuffer code, and should improve the
performance of glGetTexImage().

v2: Fix broken error handling.

src/mesa/drivers/dri/intel/intel_mipmap_tree.c
src/mesa/drivers/dri/intel/intel_mipmap_tree.h

index fe359bfb601cf2fa78f5b73c3b891c7c04ae55f7..160e5cc5e98a17323ab245062006592e38cf2e95 100644 (file)
@@ -686,6 +686,80 @@ intel_miptree_unmap_gtt(struct intel_context *intel,
    intel_region_unmap(intel, mt->region);
 }
 
+static void
+intel_miptree_map_blit(struct intel_context *intel,
+                      struct intel_mipmap_tree *mt,
+                      struct intel_miptree_map *map,
+                      unsigned int level, unsigned int slice)
+{
+   unsigned int image_x, image_y;
+   int x = map->x;
+   int y = map->y;
+   int ret;
+
+   /* The blitter requires the pitch to be aligned to 4. */
+   map->stride = ALIGN(map->w * mt->region->cpp, 4);
+
+   map->bo = drm_intel_bo_alloc(intel->bufmgr, "intel_miptree_map_blit() temp",
+                               map->stride * map->h, 4096);
+   if (!map->bo) {
+      fprintf(stderr, "Failed to allocate blit temporary\n");
+      goto fail;
+   }
+
+   intel_miptree_get_image_offset(mt, level, 0, slice, &image_x, &image_y);
+   x += image_x;
+   y += image_y;
+
+   if (!intelEmitCopyBlit(intel,
+                         mt->region->cpp,
+                         mt->region->pitch, mt->region->bo,
+                         0, mt->region->tiling,
+                         map->stride / mt->region->cpp, map->bo,
+                         0, I915_TILING_NONE,
+                         x, y,
+                         0, 0,
+                         map->w, map->h,
+                         GL_COPY)) {
+      fprintf(stderr, "Failed to blit\n");
+      goto fail;
+   }
+
+   intel_batchbuffer_flush(intel);
+   ret = drm_intel_bo_map(map->bo, (map->mode & GL_MAP_WRITE_BIT) != 0);
+   if (ret) {
+      fprintf(stderr, "Failed to map blit temporary\n");
+      goto fail;
+   }
+
+   map->ptr = map->bo->virtual;
+
+   DBG("%s: %d,%d %dx%d from mt %p (%s) %d,%d = %p/%d\n", __FUNCTION__,
+       map->x, map->y, map->w, map->h,
+       mt, _mesa_get_format_name(mt->format),
+       x, y, map->ptr, map->stride);
+
+   return;
+
+fail:
+   drm_intel_bo_unreference(map->bo);
+   map->ptr = NULL;
+   map->stride = 0;
+}
+
+static void
+intel_miptree_unmap_blit(struct intel_context *intel,
+                        struct intel_mipmap_tree *mt,
+                        struct intel_miptree_map *map,
+                        unsigned int level,
+                        unsigned int slice)
+{
+   assert(!(map->mode & GL_MAP_WRITE_BIT));
+
+   drm_intel_bo_unmap(map->bo);
+   drm_intel_bo_unreference(map->bo);
+}
+
 static void
 intel_miptree_map_s8(struct intel_context *intel,
                     struct intel_mipmap_tree *mt,
@@ -924,6 +998,11 @@ intel_miptree_map(struct intel_context *intel,
       intel_miptree_map_s8(intel, mt, map, level, slice);
    } else if (mt->stencil_mt) {
       intel_miptree_map_depthstencil(intel, mt, map, level, slice);
+   } else if (intel->gen >= 6 &&
+             !(mode & GL_MAP_WRITE_BIT) &&
+             !mt->compressed &&
+             mt->region->tiling == I915_TILING_X) {
+      intel_miptree_map_blit(intel, mt, map, level, slice);
    } else {
       intel_miptree_map_gtt(intel, mt, map, level, slice);
    }
@@ -950,6 +1029,8 @@ intel_miptree_unmap(struct intel_context *intel,
       intel_miptree_unmap_s8(intel, mt, map, level, slice);
    } else if (mt->stencil_mt) {
       intel_miptree_unmap_depthstencil(intel, mt, map, level, slice);
+   } else if (map->bo) {
+      intel_miptree_unmap_blit(intel, mt, map, level, slice);
    } else {
       intel_miptree_unmap_gtt(intel, mt, map, level, slice);
    }
index 50f8b8202283e349daed72ee4139fcd5a0d42a50..aa95f7b9e779c0398532ac04a47f6b323f8cdf05 100644 (file)
@@ -69,6 +69,8 @@ struct intel_miptree_map {
    int x, y, w, h;
    /** Possibly malloced temporary buffer for the mapping. */
    void *buffer;
+   /** Possible pointer to a BO temporary for the mapping. */
+   drm_intel_bo *bo;
    /** Pointer to the start of (map_x, map_y) returned by the mapping. */
    void *ptr;
    /** Stride of the mapping. */