i965: Mark that depth buffer needs depth resolve after drawing
[mesa.git] / src / mesa / drivers / dri / intel / intel_mipmap_tree.c
index 8f10101a233285acbaae35393fc51e37954ab039..b4f6bb31897b4a084ad2bc2d401476e609ecc74d 100644 (file)
  * 
  **************************************************************************/
 
+#include "intel_batchbuffer.h"
 #include "intel_context.h"
 #include "intel_mipmap_tree.h"
 #include "intel_regions.h"
+#include "intel_resolve_map.h"
+#include "intel_span.h"
 #include "intel_tex_layout.h"
 #include "intel_tex.h"
 #include "intel_blit.h"
+
 #include "main/enums.h"
 #include "main/formats.h"
+#include "main/image.h"
 #include "main/teximage.h"
 
 #define FILE_DEBUG_FLAG DEBUG_MIPTREE
 
-
 static GLenum
 target_to_target(GLenum target)
 {
@@ -54,7 +58,6 @@ target_to_target(GLenum target)
    }
 }
 
-
 static struct intel_mipmap_tree *
 intel_miptree_create_internal(struct intel_context *intel,
                              GLenum target,
@@ -82,11 +85,27 @@ intel_miptree_create_internal(struct intel_context *intel,
    mt->last_level = last_level;
    mt->width0 = width0;
    mt->height0 = height0;
-   mt->depth0 = depth0;
    mt->cpp = compress_byte ? compress_byte : _mesa_get_format_bytes(mt->format);
    mt->compressed = compress_byte ? 1 : 0;
    mt->refcount = 1; 
 
+   if (target == GL_TEXTURE_CUBE_MAP) {
+      assert(depth0 == 1);
+      mt->depth0 = 6;
+   } else {
+      mt->depth0 = depth0;
+   }
+
+   if (format == MESA_FORMAT_S8) {
+      /* The stencil buffer has quirky pitch requirements.  From Vol 2a,
+       * 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface Pitch":
+       *    The pitch must be set to 2x the value computed based on width, as
+       *    the stencil buffer is stored with two rows interleaved.
+       */
+      assert(intel->has_separate_stencil);
+      mt->cpp = 2;
+   }
+
 #ifdef I915
    (void) intel;
    if (intel->is_945)
@@ -97,6 +116,23 @@ intel_miptree_create_internal(struct intel_context *intel,
    brw_miptree_layout(intel, mt);
 #endif
 
+   if (intel->must_use_separate_stencil &&
+       _mesa_is_depthstencil_format(_mesa_get_format_base_format(format))) {
+      mt->stencil_mt = intel_miptree_create(intel,
+                                            mt->target,
+                                            MESA_FORMAT_S8,
+                                            mt->first_level,
+                                            mt->last_level,
+                                            mt->width0,
+                                            mt->height0,
+                                            mt->depth0,
+                                            true);
+      if (!mt->stencil_mt) {
+        intel_miptree_release(&mt);
+        return NULL;
+      }
+   }
+
    return mt;
 }
 
@@ -121,6 +157,8 @@ intel_miptree_create(struct intel_context *intel,
          (base_format == GL_DEPTH_COMPONENT ||
           base_format == GL_DEPTH_STENCIL_EXT))
         tiling = I915_TILING_Y;
+      else if (format == MESA_FORMAT_S8)
+        tiling = I915_TILING_NONE;
       else if (width0 >= 64)
         tiling = I915_TILING_X;
    }
@@ -223,7 +261,9 @@ intel_miptree_release(struct intel_mipmap_tree **mt)
       DBG("%s deleting %p\n", __FUNCTION__, *mt);
 
       intel_region_release(&((*mt)->region));
-      intel_region_release(&((*mt)->hiz_region));
+      intel_miptree_release(&(*mt)->stencil_mt);
+      intel_miptree_release(&(*mt)->hiz_mt);
+      intel_resolve_map_clear(&(*mt)->hiz_map);
 
       for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
         free((*mt)->level[i].slice);
@@ -287,7 +327,6 @@ intel_miptree_match_image(struct intel_mipmap_tree *mt,
 void
 intel_miptree_set_level_info(struct intel_mipmap_tree *mt,
                             GLuint level,
-                            GLuint nr_images,
                             GLuint x, GLuint y,
                             GLuint w, GLuint h, GLuint d)
 {
@@ -296,15 +335,13 @@ intel_miptree_set_level_info(struct intel_mipmap_tree *mt,
    mt->level[level].depth = d;
    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\n", __FUNCTION__,
        level, w, h, d, x, y);
 
-   assert(nr_images);
    assert(mt->level[level].slice == NULL);
 
-   mt->level[level].slice = malloc(nr_images * sizeof(*mt->level[0].slice));
+   mt->level[level].slice = malloc(d * sizeof(*mt->level[0].slice));
    mt->level[level].slice[0].x_offset = mt->level[level].level_x;
    mt->level[level].slice[0].y_offset = mt->level[level].level_y;
 }
@@ -318,7 +355,7 @@ intel_miptree_set_image_offset(struct intel_mipmap_tree *mt,
    if (img == 0 && level == 0)
       assert(x == 0 && y == 0);
 
-   assert(img < mt->level[level].nr_images);
+   assert(img < mt->level[level].depth);
 
    mt->level[level].slice[img].x_offset = mt->level[level].level_x + x;
    mt->level[level].slice[img].y_offset = mt->level[level].level_y + y;
@@ -330,28 +367,33 @@ intel_miptree_set_image_offset(struct intel_mipmap_tree *mt,
 }
 
 
+/**
+ * For cube map textures, either the \c face parameter can be used, of course,
+ * or the cube face can be interpreted as a depth layer and the \c layer
+ * parameter used.
+ */
 void
 intel_miptree_get_image_offset(struct intel_mipmap_tree *mt,
-                              GLuint level, GLuint face, GLuint depth,
+                              GLuint level, GLuint face, GLuint layer,
                               GLuint *x, GLuint *y)
 {
-   switch (mt->target) {
-   case GL_TEXTURE_CUBE_MAP_ARB:
-      *x = mt->level[level].slice[face].x_offset;
-      *y = mt->level[level].slice[face].y_offset;
-      break;
-   case GL_TEXTURE_3D:
-   case GL_TEXTURE_2D_ARRAY_EXT:
-   case GL_TEXTURE_1D_ARRAY_EXT:
-      assert(depth < mt->level[level].nr_images);
-      *x = mt->level[level].slice[depth].x_offset;
-      *y = mt->level[level].slice[depth].y_offset;
-      break;
-   default:
-      *x = mt->level[level].slice[0].x_offset;
-      *y = mt->level[level].slice[0].y_offset;
-      break;
+   int slice;
+
+   if (face > 0) {
+      assert(mt->target == GL_TEXTURE_CUBE_MAP);
+      assert(face < 6);
+      assert(layer == 0);
+      slice = face;
+   } else {
+      /* This branch may be taken even if the texture target is a cube map. In
+       * that case, the caller chose to interpret each cube face as a layer.
+       */
+      assert(face == 0);
+      slice = layer;
    }
+
+   *x = mt->level[level].slice[slice].x_offset;
+   *y = mt->level[level].slice[slice].y_offset;
 }
 
 static void
@@ -415,6 +457,12 @@ intel_miptree_copy_slice(struct intel_context *intel,
       intel_region_unmap(intel, dst_mt->region);
       intel_region_unmap(intel, src_mt->region);
    }
+
+   if (src_mt->stencil_mt) {
+      intel_miptree_copy_slice(intel,
+                               dst_mt->stencil_mt, src_mt->stencil_mt,
+                               level, face, depth);
+   }
 }
 
 /**
@@ -429,7 +477,7 @@ intel_miptree_copy_teximage(struct intel_context *intel,
    struct intel_mipmap_tree *src_mt = intelImage->mt;
    int level = intelImage->base.Base.Level;
    int face = intelImage->base.Base.Face;
-   GLuint depth = src_mt->level[level].depth;
+   GLuint depth = intelImage->base.Base.Depth;
 
    for (int slice = 0; slice < depth; slice++) {
       intel_miptree_copy_slice(intel, dst_mt, src_mt, level, face, slice);
@@ -438,3 +486,228 @@ intel_miptree_copy_teximage(struct intel_context *intel,
    intel_miptree_reference(&intelImage->mt, dst_mt);
 }
 
+/**
+ * \param scatter Scatter if true. Gather if false.
+ *
+ * \see intel_miptree_s8z24_scatter()
+ * \see intel_miptree_s8z24_gather()
+ */
+static void
+intel_miptree_s8z24_scattergather(struct intel_context *intel,
+                                  struct intel_mipmap_tree *mt,
+                                  uint32_t level,
+                                  uint32_t layer,
+                                  bool scatter)
+{
+   /* Check function inputs. */
+   assert(level >= mt->first_level);
+   assert(level <= mt->last_level);
+   assert(layer < mt->level[level].depth);
+
+   /* Label everything and its bit layout, just to make the code easier to
+    * read.
+    */
+   struct intel_mipmap_tree  *s8_mt    = mt->stencil_mt;
+   struct intel_mipmap_level *s8_level = &s8_mt->level[level];
+   struct intel_mipmap_slice *s8_slice = &s8_mt->level[level].slice[layer];
+
+   struct intel_mipmap_tree  *s8z24_mt    = mt;
+   struct intel_mipmap_level *s8z24_level = &s8z24_mt->level[level];
+   struct intel_mipmap_slice *s8z24_slice = &s8z24_mt->level[level].slice[layer];
+
+   /* Check that both miptree levels have the same dimensions. */
+   assert(s8_level->width  == s8z24_level->width);
+   assert(s8_level->height == s8z24_level->height);
+   assert(s8_level->depth  == s8z24_level->depth);
+
+   /* Map the buffers. */
+   if (drm_intel_bo_references(intel->batch.bo, s8_mt->region->bo) ||
+       drm_intel_bo_references(intel->batch.bo, s8z24_mt->region->bo)) {
+      intel_batchbuffer_flush(intel);
+   }
+   drm_intel_gem_bo_map_gtt(s8_mt->region->bo);
+   drm_intel_gem_bo_map_gtt(s8z24_mt->region->bo);
+
+   /* Define the invariant values outside the for loop, because I don't trust
+    * GCC to do it for us.
+    */
+   uint8_t *s8_map = s8_mt->region->bo->virtual
+                  + s8_slice->x_offset
+                  + s8_slice->y_offset;
+
+   uint8_t *s8z24_map = s8z24_mt->region->bo->virtual
+                     + s8z24_slice->x_offset
+                     + s8z24_slice->y_offset;
+
+   ptrdiff_t s8z24_stride = s8z24_mt->region->pitch * s8z24_mt->region->cpp;
+
+   uint32_t w = s8_level->width;
+   uint32_t h = s8_level->height;
+
+   for (uint32_t y = 0; y < h; ++y) {
+      for (uint32_t x = 0; x < w; ++x) {
+        ptrdiff_t s8_offset = intel_offset_S8(s8_mt->region->pitch, x, y);
+        ptrdiff_t s8z24_offset = y * s8z24_stride
+                               + x * 4
+                               + 3;
+        if (scatter) {
+           s8_map[s8_offset] = s8z24_map[s8z24_offset];
+        } else {
+           s8z24_map[s8z24_offset] = s8_map[s8_offset];
+        }
+      }
+   }
+
+   drm_intel_gem_bo_unmap_gtt(s8_mt->region->bo);
+   drm_intel_gem_bo_unmap_gtt(s8z24_mt->region->bo);
+}
+
+void
+intel_miptree_s8z24_scatter(struct intel_context *intel,
+                            struct intel_mipmap_tree *mt,
+                            uint32_t level,
+                            uint32_t layer)
+{
+   intel_miptree_s8z24_scattergather(intel, mt, level, layer, true);
+}
+
+void
+intel_miptree_s8z24_gather(struct intel_context *intel,
+                           struct intel_mipmap_tree *mt,
+                           uint32_t level,
+                           uint32_t layer)
+{
+   intel_miptree_s8z24_scattergather(intel, mt, level, layer, false);
+}
+
+bool
+intel_miptree_alloc_hiz(struct intel_context *intel,
+                       struct intel_mipmap_tree *mt)
+{
+   assert(mt->hiz_mt == NULL);
+   mt->hiz_mt = intel_miptree_create(intel,
+                                     mt->target,
+                                     MESA_FORMAT_X8_Z24,
+                                     mt->first_level,
+                                     mt->last_level,
+                                     mt->width0,
+                                     mt->height0,
+                                     mt->depth0,
+                                     true);
+   return mt->hiz_mt != NULL;
+}
+
+void
+intel_miptree_slice_set_needs_hiz_resolve(struct intel_mipmap_tree *mt,
+                                         uint32_t level,
+                                         uint32_t layer)
+{
+   intel_miptree_check_level_layer(mt, level, layer);
+
+   if (!mt->hiz_mt)
+      return;
+
+   intel_resolve_map_set(&mt->hiz_map,
+                        level, layer, INTEL_NEED_HIZ_RESOLVE);
+}
+
+
+void
+intel_miptree_slice_set_needs_depth_resolve(struct intel_mipmap_tree *mt,
+                                            uint32_t level,
+                                            uint32_t layer)
+{
+   intel_miptree_check_level_layer(mt, level, layer);
+
+   if (!mt->hiz_mt)
+      return;
+
+   intel_resolve_map_set(&mt->hiz_map,
+                        level, layer, INTEL_NEED_DEPTH_RESOLVE);
+}
+
+typedef void (*resolve_func_t)(struct intel_context *intel,
+                              struct intel_mipmap_tree *mt,
+                              uint32_t level,
+                              uint32_t layer);
+
+static bool
+intel_miptree_slice_resolve(struct intel_context *intel,
+                           struct intel_mipmap_tree *mt,
+                           uint32_t level,
+                           uint32_t layer,
+                           enum intel_need_resolve need,
+                           resolve_func_t func)
+{
+   intel_miptree_check_level_layer(mt, level, layer);
+
+   struct intel_resolve_map *item =
+        intel_resolve_map_get(&mt->hiz_map, level, layer);
+
+   if (!item || item->need != need)
+      return false;
+
+   func(intel, mt, level, layer);
+   intel_resolve_map_remove(item);
+   return true;
+}
+
+bool
+intel_miptree_slice_resolve_hiz(struct intel_context *intel,
+                               struct intel_mipmap_tree *mt,
+                               uint32_t level,
+                               uint32_t layer)
+{
+   return intel_miptree_slice_resolve(intel, mt, level, layer,
+                                     INTEL_NEED_HIZ_RESOLVE,
+                                     intel->vtbl.resolve_hiz_slice);
+}
+
+bool
+intel_miptree_slice_resolve_depth(struct intel_context *intel,
+                                 struct intel_mipmap_tree *mt,
+                                 uint32_t level,
+                                 uint32_t layer)
+{
+   return intel_miptree_slice_resolve(intel, mt, level, layer,
+                                     INTEL_NEED_DEPTH_RESOLVE,
+                                     intel->vtbl.resolve_depth_slice);
+}
+
+static bool
+intel_miptree_all_slices_resolve(struct intel_context *intel,
+                                struct intel_mipmap_tree *mt,
+                                enum intel_need_resolve need,
+                                resolve_func_t func)
+{
+   bool did_resolve = false;
+   struct intel_resolve_map *i;
+
+   for (i = mt->hiz_map.next; i; i = i->next) {
+      if (i->need != need)
+        continue;
+      func(intel, mt, i->level, i->layer);
+      intel_resolve_map_remove(i);
+      did_resolve = true;
+   }
+
+   return did_resolve;
+}
+
+bool
+intel_miptree_all_slices_resolve_hiz(struct intel_context *intel,
+                                    struct intel_mipmap_tree *mt)
+{
+   return intel_miptree_all_slices_resolve(intel, mt,
+                                          INTEL_NEED_HIZ_RESOLVE,
+                                          intel->vtbl.resolve_hiz_slice);
+}
+
+bool
+intel_miptree_all_slices_resolve_depth(struct intel_context *intel,
+                                      struct intel_mipmap_tree *mt)
+{
+   return intel_miptree_all_slices_resolve(intel, mt,
+                                          INTEL_NEED_DEPTH_RESOLVE,
+                                          intel->vtbl.resolve_depth_slice);
+}