<div dir="ltr">On 10 January 2013 12:01, Ian Romanick <span dir="ltr"><<a href="mailto:idr@freedesktop.org" target="_blank">idr@freedesktop.org</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">On 01/08/2013 02:27 PM, Paul Berry wrote:<br>
</div><div><div class="h5"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
In most cases, the width, height, and depth of the physical surface<br>
used by the driver to implement a texture or renderbuffer is equal to<br>
the logical width, height, and depth exposed to the client through<br>
functions such as glTexImage3D().  However, there are two exceptions:<br>
cube maps (which have a physical depth of 6 but a logical depth of 1)<br>
and multisampled renderbuffers (which have larger physical dimensions<br>
than logical dimensions to allow multiple samples per pixel).<br>
<br>
Previous to this patch, we accounted for the difference between<br>
physical and logical surface dimensions at inconsistent places in the<br>
call graph (multisampling was accounted for in<br>
intel_miptree_create_for_<u></u>renderbuffer(), and cubemaps were accounted<br>
for in intel_miptree_create_internal(<u></u>)).  As a result, it wasn't<br>
always clear, when calling a miptree creation function, whether<br>
physical or logical dimensions were needed.  Also, we weren't<br>
consistent about storing logical dimensions in the intel_mipmap_tree<br>
structure (we only did so in the<br>
intel_miptree_create_for_<u></u>renderbuffer() code path, and we did not<br>
store depth).<br>
<br>
This patch refactors things so that intel_miptree_create_internal(<u></u>) is<br>
responsible for converting logical to physical dimensions and for<br>
storing both the physical and logical dimensions in the<br>
intel_mipmap_tree structure.  As a result, all miptree creation<br>
functions interpret their arguments as logical dimensions, and both<br>
physical and logical dimensions are always available to functions that<br>
work with intel_mipmap_trees.<br>
<br>
In addition, it renames the fields in intel_mipmap_tree used to store<br>
the dimensions, so that it is clear from the name whether physical or<br>
logical dimensions are being referred to.<br>
<br>
This should fix the following bugs:<br>
<br>
- When creating a separate stencil surface for a depthstencil cubemap,<br>
   we would erroneously try to convert the depth from 1 to 6 twice,<br>
   resulting in an assertion failure.<br>
<br>
- When creating an MCS buffer for compressed multisampling, we used<br>
   physical dimensions instead of logical dimensions, resulting in<br>
   wasted memory.<br>
<br>
In addition, this should considerably simplify the implementation of<br>
ARB_texture_multisample, because it moves the code to compute the<br>
physical size of multisampled surfaces out of renderbuffer-only code.<br>
---<br>
  src/mesa/drivers/dri/i915/<u></u>i915_tex_layout.c     |  36 ++---<br>
  src/mesa/drivers/dri/i965/brw_<u></u>tex_layout.c      |  20 +--<br>
  src/mesa/drivers/dri/intel/<u></u>intel_fbo.c          |   1 -<br>
  src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.c  | 191 +++++++++++-------------<br>
  src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.h  |  28 ++--<br>
  src/mesa/drivers/dri/intel/<u></u>intel_tex_image.c    |   1 -<br>
  src/mesa/drivers/dri/intel/<u></u>intel_tex_layout.c   |  18 +--<br>
  src/mesa/drivers/dri/intel/<u></u>intel_tex_validate.c |   1 -<br>
  8 files changed, 143 insertions(+), 153 deletions(-)<br>
<br>
diff --git a/src/mesa/drivers/dri/i915/<u></u>i915_tex_layout.c b/src/mesa/drivers/dri/i915/<u></u>i915_tex_layout.c<br>
index 1e3cfad..90911a6 100644<br>
--- a/src/mesa/drivers/dri/i915/<u></u>i915_tex_layout.c<br>
+++ b/src/mesa/drivers/dri/i915/<u></u>i915_tex_layout.c<br>
@@ -114,9 +114,9 @@ static GLint bottom_offsets[6] = {<br>
  static void<br>
  i915_miptree_layout_cube(<u></u>struct intel_mipmap_tree * mt)<br>
  {<br>
-   const GLuint dim = mt->width0;<br>
+   const GLuint dim = mt->physical_width0;<br>
     GLuint face;<br>
-   GLuint lvlWidth = mt->width0, lvlHeight = mt->height0;<br>
+   GLuint lvlWidth = mt->physical_width0, lvlHeight = mt->physical_height0;<br>
     GLint level;<br>
<br>
     assert(lvlWidth == lvlHeight); /* cubemap images are square */<br>
@@ -156,14 +156,14 @@ i915_miptree_layout_cube(<u></u>struct intel_mipmap_tree * mt)<br>
  static void<br>
  i915_miptree_layout_3d(struct intel_mipmap_tree * mt)<br>
  {<br>
-   GLuint width = mt->width0;<br>
-   GLuint height = mt->height0;<br>
-   GLuint depth = mt->depth0;<br>
+   GLuint width = mt->physical_width0;<br>
+   GLuint height = mt->physical_height0;<br>
+   GLuint depth = mt->physical_depth0;<br>
     GLuint stack_height = 0;<br>
     GLint level;<br>
<br>
     /* Calculate the size of a single slice. */<br>
-   mt->total_width = mt->width0;<br>
+   mt->total_width = mt->physical_width0;<br>
<br>
     /* XXX: hardware expects/requires 9 levels at minimum. */<br>
     for (level = mt->first_level; level <= MAX2(8, mt->last_level); level++) {<br>
@@ -178,7 +178,7 @@ i915_miptree_layout_3d(struct intel_mipmap_tree * mt)<br>
     }<br>
<br>
     /* Fixup depth image_offsets: */<br>
-   depth = mt->depth0;<br>
+   depth = mt->physical_depth0;<br>
     for (level = mt->first_level; level <= mt->last_level; level++) {<br>
        GLuint i;<br>
        for (i = 0; i < depth; i++) {<br>
@@ -193,18 +193,18 @@ i915_miptree_layout_3d(struct intel_mipmap_tree * mt)<br>
      * remarkable how wasteful of memory the i915 texture layouts<br>
      * are.  They are largely fixed in the i945.<br>
      */<br>
-   mt->total_height = stack_height * mt->depth0;<br>
+   mt->total_height = stack_height * mt->physical_depth0;<br>
  }<br>
<br>
  static void<br>
  i915_miptree_layout_2d(struct intel_mipmap_tree * mt)<br>
  {<br>
-   GLuint width = mt->width0;<br>
-   GLuint height = mt->height0;<br>
+   GLuint width = mt->physical_width0;<br>
+   GLuint height = mt->physical_height0;<br>
     GLuint img_height;<br>
     GLint level;<br>
<br>
-   mt->total_width = mt->width0;<br>
+   mt->total_width = mt->physical_width0;<br>
     mt->total_height = 0;<br>
<br>
     for (level = mt->first_level; level <= mt->last_level; level++) {<br>
@@ -312,9 +312,9 @@ i915_miptree_layout(struct intel_mipmap_tree * mt)<br>
  static void<br>
  i945_miptree_layout_cube(<u></u>struct intel_mipmap_tree * mt)<br>
  {<br>
-   const GLuint dim = mt->width0;<br>
+   const GLuint dim = mt->physical_width0;<br>
     GLuint face;<br>
-   GLuint lvlWidth = mt->width0, lvlHeight = mt->height0;<br>
+   GLuint lvlWidth = mt->physical_width0, lvlHeight = mt->physical_height0;<br>
     GLint level;<br>
<br>
     assert(lvlWidth == lvlHeight); /* cubemap images are square */<br>
@@ -402,17 +402,17 @@ i945_miptree_layout_cube(<u></u>struct intel_mipmap_tree * mt)<br>
  static void<br>
  i945_miptree_layout_3d(struct intel_mipmap_tree * mt)<br>
  {<br>
-   GLuint width = mt->width0;<br>
-   GLuint height = mt->height0;<br>
-   GLuint depth = mt->depth0;<br>
+   GLuint width = mt->physical_width0;<br>
+   GLuint height = mt->physical_height0;<br>
+   GLuint depth = mt->physical_depth0;<br>
     GLuint pack_x_pitch, pack_x_nr;<br>
     GLuint pack_y_pitch;<br>
     GLuint level;<br>
<br>
-   mt->total_width = mt->width0;<br>
+   mt->total_width = mt->physical_width0;<br>
     mt->total_height = 0;<br>
<br>
-   pack_y_pitch = MAX2(mt->height0, 2);<br>
+   pack_y_pitch = MAX2(mt->physical_height0, 2);<br>
     pack_x_pitch = mt->total_width;<br>
     pack_x_nr = 1;<br>
<br>
diff --git a/src/mesa/drivers/dri/i965/<u></u>brw_tex_layout.c b/src/mesa/drivers/dri/i965/<u></u>brw_tex_layout.c<br>
index b661570..1428396 100644<br>
--- a/src/mesa/drivers/dri/i965/<u></u>brw_tex_layout.c<br>
+++ b/src/mesa/drivers/dri/i965/<u></u>brw_tex_layout.c<br>
@@ -47,8 +47,8 @@ brw_miptree_layout_texture_<u></u>array(struct intel_context *intel,<br>
     GLuint qpitch = 0;<br>
     int h0, h1, q;<br>
<br>
-   h0 = ALIGN(mt->height0, mt->align_h);<br>
-   h1 = ALIGN(minify(mt->height0), mt->align_h);<br>
+   h0 = ALIGN(mt->physical_height0, mt->align_h);<br>
+   h1 = ALIGN(minify(mt->physical_<u></u>height0), mt->align_h);<br>
     if (mt->array_spacing_lod0)<br>
        qpitch = h0;<br>
     else<br>
@@ -59,11 +59,11 @@ brw_miptree_layout_texture_<u></u>array(struct intel_context *intel,<br>
     i945_miptree_layout_2d(mt);<br>
<br>
     for (level = mt->first_level; level <= mt->last_level; level++) {<br>
-      for (q = 0; q < mt->depth0; q++) {<br>
+      for (q = 0; q < mt->physical_depth0; q++) {<br>
         intel_miptree_set_image_<u></u>offset(mt, level, q, 0, q * qpitch);<br>
        }<br>
     }<br>
-   mt->total_height = qpitch * mt->depth0;<br>
+   mt->total_height = qpitch * mt->physical_depth0;<br>
  }<br>
<br>
  void<br>
@@ -84,13 +84,13 @@ brw_miptree_layout(struct intel_context *intel, struct intel_mipmap_tree *mt)<br>
         brw_miptree_layout_texture_<u></u>array(intel, mt);<br>
         break;<br>
        }<br>
-      assert(mt->depth0 == 6);<br>
+      assert(mt->physical_depth0 == 6);<br>
        /* FALLTHROUGH */<br>
<br>
     case GL_TEXTURE_3D: {<br>
-      GLuint width  = mt->width0;<br>
-      GLuint height = mt->height0;<br>
-      GLuint depth = mt->depth0;<br>
+      GLuint width  = mt->physical_width0;<br>
+      GLuint height = mt->physical_height0;<br>
+      GLuint depth = mt->physical_depth0;<br>
        GLuint pack_x_pitch, pack_x_nr;<br>
        GLuint pack_y_pitch;<br>
        GLuint level;<br>
@@ -101,8 +101,8 @@ brw_miptree_layout(struct intel_context *intel, struct intel_mipmap_tree *mt)<br>
            mt->total_width = ALIGN(width, mt->align_w);<br>
            pack_y_pitch = (height + 3) / 4;<br>
        } else {<br>
-        mt->total_width = mt->width0;<br>
-        pack_y_pitch = ALIGN(mt->height0, mt->align_h);<br>
+        mt->total_width = mt->physical_width0;<br>
+        pack_y_pitch = ALIGN(mt->physical_height0, mt->align_h);<br>
        }<br>
<br>
        pack_x_pitch = width;<br>
diff --git a/src/mesa/drivers/dri/intel/<u></u>intel_fbo.c b/src/mesa/drivers/dri/intel/<u></u>intel_fbo.c<br>
index 0597015..034fa8a 100644<br>
--- a/src/mesa/drivers/dri/intel/<u></u>intel_fbo.c<br>
+++ b/src/mesa/drivers/dri/intel/<u></u>intel_fbo.c<br>
@@ -939,7 +939,6 @@ intel_renderbuffer_move_to_<u></u>temp(struct intel_context *intel,<br>
                                   width, height, depth,<br>
                                   true,<br>
                                   irb->mt->num_samples,<br>
-                                 irb->mt->msaa_layout,<br>
                                   false /* force_y_tiling */);<br>
<br>
     intel_miptree_copy_teximage(<u></u>intel, intel_image, new_mt);<br>
diff --git a/src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.c b/src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.c<br>
index 12b77b6..7542219 100644<br>
--- a/src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.c<br>
+++ b/src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.c<br>
@@ -122,8 +122,7 @@ intel_miptree_create_internal(<u></u>struct intel_context *intel,<br>
                              GLuint height0,<br>
                              GLuint depth0,<br>
                              bool for_region,<br>
-                              GLuint num_samples,<br>
-                              enum intel_msaa_layout msaa_layout)<br>
+                              GLuint num_samples)<br>
  {<br>
     struct intel_mipmap_tree *mt = calloc(sizeof(*mt), 1);<br>
     int compress_byte = 0;<br>
@@ -140,18 +139,78 @@ intel_miptree_create_internal(<u></u>struct intel_context *intel,<br>
     mt->format = format;<br>
     mt->first_level = first_level;<br>
     mt->last_level = last_level;<br>
-   mt->width0 = width0;<br>
-   mt->height0 = height0;<br>
+   mt->logical_width0 = width0;<br>
+   mt->logical_height0 = height0;<br>
+   mt->logical_depth0 = depth0;<br>
     mt->cpp = compress_byte ? compress_byte : _mesa_get_format_bytes(mt-><u></u>format);<br>
     mt->num_samples = num_samples;<br>
     mt->compressed = compress_byte ? 1 : 0;<br>
-   mt->msaa_layout = msaa_layout;<br>
+   mt->msaa_layout = INTEL_MSAA_LAYOUT_NONE;<br>
     mt->refcount = 1;<br>
<br>
+   if (num_samples > 1) {<br>
+      /* Adjust width/height/depth for MSAA */<br>
+      mt->msaa_layout = compute_msaa_layout(intel, format);<br>
+      if (mt->msaa_layout == INTEL_MSAA_LAYOUT_IMS) {<br>
+         /* In the Sandy Bridge PRM, volume 4, part 1, page 31, it says:<br>
+          *<br>
+          *     "Any of the other messages (sample*, LOD, load4) used with a<br>
+          *      (4x) multisampled surface will in-effect sample a surface with<br>
+          *      double the height and width as that indicated in the surface<br>
+          *      state. Each pixel position on the original-sized surface is<br>
+          *      replaced with a 2x2 of samples with the following arrangement:<br>
+          *<br>
+          *         sample 0 sample 2<br>
+          *         sample 1 sample 3"<br>
+          *<br>
+          * Thus, when sampling from a multisampled texture, it behaves as<br>
+          * though the layout in memory for (x,y,sample) is:<br>
+          *<br>
+          *      (0,0,0) (0,0,2)   (1,0,0) (1,0,2)<br>
+          *      (0,0,1) (0,0,3)   (1,0,1) (1,0,3)<br>
+          *<br>
+          *      (0,1,0) (0,1,2)   (1,1,0) (1,1,2)<br>
+          *      (0,1,1) (0,1,3)   (1,1,1) (1,1,3)<br>
+          *<br>
+          * However, the actual layout of multisampled data in memory is:<br>
+          *<br>
+          *      (0,0,0) (1,0,0)   (0,0,1) (1,0,1)<br>
+          *      (0,1,0) (1,1,0)   (0,1,1) (1,1,1)<br>
+          *<br>
+          *      (0,0,2) (1,0,2)   (0,0,3) (1,0,3)<br>
+          *      (0,1,2) (1,1,2)   (0,1,3) (1,1,3)<br>
+          *<br>
+          * This pattern repeats for each 2x2 pixel block.<br>
+          *<br>
+          * As a result, when calculating the size of our 4-sample buffer for<br>
+          * an odd width or height, we have to align before scaling up because<br>
+          * sample 3 is in that bottom right 2x2 block.<br>
+          */<br>
+         switch (num_samples) {<br>
+         case 4:<br>
+            width0 = ALIGN(width0, 2) * 2;<br>
+            height0 = ALIGN(height0, 2) * 2;<br>
+            break;<br>
+         case 8:<br>
+            width0 = ALIGN(width0, 2) * 4;<br>
+            height0 = ALIGN(height0, 2) * 2;<br>
+            break;<br>
+         default:<br>
+            /* num_samples should already have been quantized to 0, 1, 4, or<br>
+             * 8.<br>
+             */<br>
+            assert(false);<br>
+         }<br>
+      } else {<br>
+         /* Non-interleaved */<br>
+         depth0 *= num_samples;<br>
+      }<br>
+   }<br>
+<br>
     /* array_spacing_lod0 is only used for non-IMS MSAA surfaces.  TODO: can we<br>
      * use it elsewhere?<br>
      */<br>
-   switch (msaa_layout) {<br>
+   switch (mt->msaa_layout) {<br>
     case INTEL_MSAA_LAYOUT_NONE:<br>
     case INTEL_MSAA_LAYOUT_IMS:<br>
        mt->array_spacing_lod0 = false;<br>
@@ -164,30 +223,28 @@ intel_miptree_create_internal(<u></u>struct intel_context *intel,<br>
<br>
     if (target == GL_TEXTURE_CUBE_MAP) {<br>
        assert(depth0 == 1);<br>
-      mt->depth0 = 6;<br>
-   } else {<br>
-      mt->depth0 = depth0;<br>
+      depth0 = 6;<br>
</blockquote>
<br></div></div>
This is basically converting depth0 from logical to physical.  We had discussed that this could cause problems with future cubemap arrays.  I may not be following the code completely, but does this potential future problem still loom?<div class="HOEnZb">
<div class="h5"><br></div></div></blockquote><div><br></div><div>I think we're ok w.r.t. cubemap arrays.  Once we get around to supporting them, all we should have to do is remove the "assert(depth0 == 1)" line and replace "depth0 = 6" with "depth0 *= 6".<br>
<br></div><div>I was tempted to just go ahead and do that in this patch, but I decided that for now keeping the assertion around is a nice way to verify that we don't accidentally feed physical dimsensions to intel_miptree_create_internal when logical dimensions are intended.<br>
</div></div></div></div>