Merge branch 'mesa_7_6_branch'
[mesa.git] / src / mesa / drivers / dri / intel / intel_mipmap_tree.c
index bf1c3f03f0e1983e3d09e8bb9e2fe3467e01c094..01e9d4add341584d60ef1ca9179cfc7f34b35024 100644 (file)
 #include "intel_context.h"
 #include "intel_mipmap_tree.h"
 #include "intel_regions.h"
+#include "intel_tex_layout.h"
 #include "intel_chipset.h"
+#ifndef I915
+#include "brw_state.h"
+#endif
 #include "main/enums.h"
 
 #define FILE_DEBUG_FLAG DEBUG_MIPTREE
 
+
 static GLenum
 target_to_target(GLenum target)
 {
@@ -49,6 +54,7 @@ target_to_target(GLenum target)
    }
 }
 
+
 static struct intel_mipmap_tree *
 intel_miptree_create_internal(struct intel_context *intel,
                              GLenum target,
@@ -57,14 +63,16 @@ intel_miptree_create_internal(struct intel_context *intel,
                              GLuint last_level,
                              GLuint width0,
                              GLuint height0,
-                             GLuint depth0, GLuint cpp, GLuint compress_byte)
+                             GLuint depth0, GLuint cpp, GLuint compress_byte,
+                             uint32_t tiling)
 {
    GLboolean ok;
    struct intel_mipmap_tree *mt = calloc(sizeof(*mt), 1);
 
-   DBG("%s target %s format %s level %d..%d\n", __FUNCTION__,
+   DBG("%s target %s format %s level %d..%d <-- %p\n", __FUNCTION__,
        _mesa_lookup_enum_by_nr(target),
-       _mesa_lookup_enum_by_nr(internal_format), first_level, last_level);
+       _mesa_lookup_enum_by_nr(internal_format), 
+       first_level, last_level, mt);
 
    mt->target = target_to_target(target);
    mt->internal_format = internal_format;
@@ -80,36 +88,53 @@ intel_miptree_create_internal(struct intel_context *intel,
 
 #ifdef I915
    if (IS_945(intel->intelScreen->deviceID))
-      ok = i945_miptree_layout(intel, mt);
+      ok = i945_miptree_layout(intel, mt, tiling);
    else
-      ok = i915_miptree_layout(intel, mt);
+      ok = i915_miptree_layout(intel, mt, tiling);
 #else
-   ok = brw_miptree_layout(intel, mt);
+   ok = brw_miptree_layout(intel, mt, tiling);
 #endif
 
    if (!ok) {
       free(mt);
+      DBG("%s not okay - returning NULL\n", __FUNCTION__);
       return NULL;
    }
 
    return mt;
 }
 
+
 struct intel_mipmap_tree *
 intel_miptree_create(struct intel_context *intel,
                     GLenum target,
+                    GLenum base_format,
                     GLenum internal_format,
                     GLuint first_level,
                     GLuint last_level,
                     GLuint width0,
                     GLuint height0,
-                    GLuint depth0, GLuint cpp, GLuint compress_byte)
+                    GLuint depth0, GLuint cpp, GLuint compress_byte,
+                    GLboolean expect_accelerated_upload)
 {
    struct intel_mipmap_tree *mt;
+   uint32_t tiling;
+
+   if (intel->use_texture_tiling && compress_byte == 0 &&
+       intel->intelScreen->kernel_exec_fencing) {
+      if (IS_965(intel->intelScreen->deviceID) &&
+         (base_format == GL_DEPTH_COMPONENT ||
+          base_format == GL_DEPTH_STENCIL_EXT))
+        tiling = I915_TILING_Y;
+      else
+        tiling = I915_TILING_X;
+   } else
+      tiling = I915_TILING_NONE;
 
    mt = intel_miptree_create_internal(intel, target, internal_format,
                                      first_level, last_level, width0,
-                                     height0, depth0, cpp, compress_byte);
+                                     height0, depth0, cpp, compress_byte,
+                                     tiling);
    /*
     * pitch == 0 || height == 0  indicates the null texture
     */
@@ -117,10 +142,12 @@ intel_miptree_create(struct intel_context *intel,
       return NULL;
 
    mt->region = intel_region_alloc(intel,
+                                  tiling,
                                   mt->cpp,
                                   mt->pitch,
                                   mt->total_height,
-                                  mt->pitch);
+                                  mt->pitch,
+                                  expect_accelerated_upload);
 
    if (!mt->region) {
        free(mt);
@@ -130,6 +157,7 @@ intel_miptree_create(struct intel_context *intel,
    return mt;
 }
 
+
 struct intel_mipmap_tree *
 intel_miptree_create_for_region(struct intel_context *intel,
                                GLenum target,
@@ -145,7 +173,8 @@ intel_miptree_create_for_region(struct intel_context *intel,
    mt = intel_miptree_create_internal(intel, target, internal_format,
                                      first_level, last_level,
                                      region->width, region->height, 1,
-                                     region->cpp, compress_byte);
+                                     region->cpp, compress_byte,
+                                     I915_TILING_NONE);
    if (!mt)
       return mt;
 #if 0
@@ -166,7 +195,8 @@ intel_miptree_create_for_region(struct intel_context *intel,
    intel_region_reference(&mt->region, region);
 
    return mt;
- }
+}
+
 
 /**
  * intel_miptree_pitch_align:
@@ -180,9 +210,9 @@ intel_miptree_create_for_region(struct intel_context *intel,
  * Given @pitch, compute a larger value which accounts for
  * any necessary alignment required by the device
  */
-
 int intel_miptree_pitch_align (struct intel_context *intel,
                               struct intel_mipmap_tree *mt,
+                              uint32_t tiling,
                               int pitch)
 {
 #ifdef I915
@@ -203,6 +233,11 @@ int intel_miptree_pitch_align (struct intel_context *intel,
         pitch_align = 4;
       }
 
+      if (tiling == I915_TILING_X)
+        pitch_align = 512;
+      else if (tiling == I915_TILING_Y)
+        pitch_align = 128;
+
       pitch = ALIGN(pitch * mt->cpp, pitch_align);
 
 #ifdef I915
@@ -220,6 +255,7 @@ int intel_miptree_pitch_align (struct intel_context *intel,
    return pitch;
 }
 
+
 void
 intel_miptree_reference(struct intel_mipmap_tree **dst,
                         struct intel_mipmap_tree *src)
@@ -229,6 +265,7 @@ intel_miptree_reference(struct intel_mipmap_tree **dst,
    DBG("%s %p refcount now %d\n", __FUNCTION__, src, src->refcount);
 }
 
+
 void
 intel_miptree_release(struct intel_context *intel,
                       struct intel_mipmap_tree **mt)
@@ -242,6 +279,19 @@ intel_miptree_release(struct intel_context *intel,
 
       DBG("%s deleting %p\n", __FUNCTION__, *mt);
 
+#ifndef I915
+      /* Free up cached binding tables holding a reference on our buffer, to
+       * avoid excessive memory consumption.
+       *
+       * This isn't as aggressive as we could be, as we'd like to do
+       * it from any time we free the last ref on a region.  But intel_region.c
+       * is context-agnostic.  Perhaps our constant state cache should be, as
+       * well.
+       */
+      brw_state_cache_bo_delete(&brw_context(&intel->ctx)->surface_cache,
+                               (*mt)->region->buffer);
+#endif
+
       intel_region_release(&((*mt)->region));
 
       for (i = 0; i < MAX_TEXTURE_LEVELS; i++)
@@ -254,9 +304,8 @@ intel_miptree_release(struct intel_context *intel,
 }
 
 
-
-
-/* Can the image be pulled into a unified mipmap tree.  This mirrors
+/**
+ * Can the image be pulled into a unified mipmap tree?  This mirrors
  * the completeness test in a lot of ways.
  *
  * Not sure whether I want to pass gl_texture_image here.
@@ -326,53 +375,54 @@ intel_miptree_set_level_info(struct intel_mipmap_tree *mt,
 }
 
 
-
 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(struct intel_mipmap_tree *mt,
+                                  GLuint level, GLuint img,
+                                  GLuint x, GLuint y, 
+                                  GLuint offset)
 {
    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;
+   mt->level[level].image_offset[img] = (x + y * mt->pitch) * mt->cpp + offset;
 
    DBG("%s level %d img %d pos %d,%d image_offset %x\n",
        __FUNCTION__, level, img, x, y, mt->level[level].image_offset[img]);
 }
 
 
-/* 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)
+void
+intel_miptree_set_image_offset(struct intel_mipmap_tree *mt,
+                              GLuint level, GLuint img,
+                              GLuint x, GLuint y)
 {
-   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;
+    intel_miptree_set_image_offset_ex(mt, level, img, x, y, 0);
 }
 
 
+/**
+ * Return offset to the start of a 2D slice of a texture (a mipmap level,
+ * cube face, 3D Z slice).
+ * \param mt  the texture object/miptree
+ * \param face  cube map face in [0,5] or zero for non-cube textures
+ * \param level  mipmap level
+ * \param zslice  Z slice of a 3D texture, or zero for non-3D textures
+ */
 GLuint
-intel_miptree_image_offset(struct intel_mipmap_tree *mt,
-                          GLuint face, GLuint level)
+intel_miptree_image_offset(const struct intel_mipmap_tree *mt,
+                           GLuint face, GLuint level, GLuint zslice)
 {
+   GLuint offset = mt->level[level].level_offset;
+
    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;
-}
+      offset += mt->level[level].image_offset[face];
+   else if (mt->target == GL_TEXTURE_3D)
+      offset += mt->level[level].image_offset[zslice];
 
+   return offset;
+}
 
 
 /**
@@ -408,9 +458,10 @@ intel_miptree_image_map(struct intel_context * intel,
    }
 
    return (intel_region_map(intel, mt->region) +
-           intel_miptree_image_offset(mt, face, level));
+           intel_miptree_image_offset(mt, face, level, 0));
 }
 
+
 void
 intel_miptree_image_unmap(struct intel_context *intel,
                           struct intel_mipmap_tree *mt)
@@ -420,8 +471,8 @@ intel_miptree_image_unmap(struct intel_context *intel,
 }
 
 
-
-/* Upload data for a particular image.
+/**
+ * Upload data for a particular image.
  */
 void
 intel_miptree_image_data(struct intel_context *intel,
@@ -432,32 +483,33 @@ intel_miptree_image_data(struct intel_context *intel,
                         GLuint src_row_pitch,
                         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);
+   const GLuint depth = dst->level[level].depth;
    GLuint i;
-   GLuint height = 0;
 
    DBG("%s: %d/%d\n", __FUNCTION__, face, level);
    for (i = 0; i < depth; i++) {
-      height = dst->level[level].height;
-      if(dst->compressed)
+      GLuint dst_offset = intel_miptree_image_offset(dst, face, level, i);
+      GLuint 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 */
+                       dst_offset,
                        0, 0,                             /* dstx, dsty */
                        src,
                        src_row_pitch,
                        0, 0,                             /* source x, y */
                        dst->level[level].width, height); /* width, height */
 
-      src += src_image_pitch * dst->cpp;
+      src = (char *)src + src_image_pitch * dst->cpp;
    }
 }
 
-extern GLuint intel_compressed_alignment(GLenum);
-/* Copy mipmap image between trees
+
+/**
+ * Copy mipmap image between trees
  */
 void
 intel_miptree_image_copy(struct intel_context *intel,
@@ -468,25 +520,42 @@ 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 i;
+   GLboolean success;
 
    if (dst->compressed) {
-       GLuint alignment = intel_compressed_alignment(dst->internal_format);
+       GLuint align_w, align_h;
+
+       intel_get_texture_alignment_unit(dst->internal_format,
+                                        &align_w, &align_h);
        height = (height + 3) / 4;
-       width = ((width + alignment - 1) & ~(alignment - 1));
+       width = ALIGN(width, align_w);
    }
 
    for (i = 0; i < depth; i++) {
-      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);
+      GLuint dst_offset = intel_miptree_image_offset(dst, face, level, i);
+      GLuint src_offset = intel_miptree_image_offset(src, face, level, i);
+
+      success = intel_region_copy(intel,
+                                 dst->region, dst_offset,
+                                 0, 0,
+                                 src->region, src_offset,
+                                 0, 0, 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->cpp,
+                        dst->pitch,
+                        0, 0, width, height,
+                        src_ptr + src_offset,
+                        src->pitch,
+                        0, 0);
+        intel_region_unmap(intel, src->region);
+        intel_region_unmap(intel, dst->region);
+      }
    }
-
 }