i965/gen4: Add support for single layer in alignment workaround
authorTopi Pohjolainen <topi.pohjolainen@intel.com>
Thu, 8 Jun 2017 08:24:51 +0000 (11:24 +0300)
committerTopi Pohjolainen <topi.pohjolainen@intel.com>
Mon, 19 Jun 2017 19:18:53 +0000 (22:18 +0300)
On gen < 6 one doesn't have level or layer specifiers available
for render and depth targets. In order to support rendering to
specific level/layer, driver needs to manually offset the surface
to the desired slice.
There are, however, alignment restrictions to respect as well and
in come cases the only option is to use temporary single slice
surface which driver copies after rendering to the full miptree.

Current alignment workaround introduces new texture images which
are added to the parent texture object. Texture validation later
on copies the additional levels back to the surface that contains
the full mipmap.
This only works for non-arrayed surfaces and driver currently
creates new arrayed images in vain - individual layers within the
newly created are still unaligned the same as before.

This patch drops this mechanism and instead attaches single
temporary slice into the render buffer. This gets immediately
copied back to the mipmapped and/or arrayed surface just after
the render is done.

Sitting on top of earlier series cleaning up the depth buffer
state, this patch additionally fixes the following piglit tests:

    arb_framebuffer_object.fbo-generatemipmap-cubemap.g965m64
    arb_texture_cube_map.copyteximage cube.g965m64
    arb_texture_cube_map.copyteximage cube.ilkm64
    arb_pixel_buffer_object.texsubimage array pbo.g965m64
    ext_framebuffer_object.fbo-cubemap.g965m64
    ext_texture_array.copyteximage 1d_array.g45m64
    ext_texture_array.copyteximage 1d_array.g965m64
    ext_texture_array.copyteximage 1d_array.ilkm64
    ext_texture_array.copyteximage 2d_array.g45m64
    ext_texture_array.copyteximage 2d_array.g965m64
    ext_texture_array.copyteximage 2d_array.ilkm64
    ext_texture_array.fbo-array.g965m64
    ext_texture_array.fbo-generatemipmap-array.g965m64
    ext_texture_array.gen-mipmap.g965m64

Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Signed-off-by: Topi Pohjolainen <topi.pohjolainen@intel.com>
src/mesa/drivers/dri/i965/brw_draw.c
src/mesa/drivers/dri/i965/brw_misc_state.c
src/mesa/drivers/dri/i965/brw_wm_surface_state.c
src/mesa/drivers/dri/i965/intel_fbo.c
src/mesa/drivers/dri/i965/intel_fbo.h
src/mesa/drivers/dri/i965/intel_mipmap_tree.c
src/mesa/drivers/dri/i965/intel_mipmap_tree.h

index 9e0e2423dae1ffaa9ddbc258af48fbf510397163..d1309ac483701d4c714a6cf5b90ed3915f8f1d35 100644 (file)
@@ -408,6 +408,56 @@ brw_postdraw_set_buffers_need_resolve(struct brw_context *brw)
    }
 }
 
+static void
+intel_renderbuffer_move_temp_back(struct brw_context *brw,
+                                  struct intel_renderbuffer *irb)
+{
+   if (irb->align_wa_mt == NULL)
+      return;
+
+   brw_render_cache_set_check_flush(brw, irb->align_wa_mt->bo);
+
+   intel_miptree_copy_slice(brw, irb->align_wa_mt, 0, 0,
+                            irb->mt,
+                            irb->Base.Base.TexImage->Level, irb->mt_layer);
+
+   intel_miptree_reference(&irb->align_wa_mt, NULL);
+
+   /* Finally restore the x,y to correspond to full miptree. */
+   intel_renderbuffer_set_draw_offset(irb);
+
+   /* Make sure render surface state gets re-emitted with updated miptree. */
+   brw->NewGLState |= _NEW_BUFFERS;
+}
+
+static void
+brw_postdraw_reconcile_align_wa_slices(struct brw_context *brw)
+{
+   struct gl_context *ctx = &brw->ctx;
+   struct gl_framebuffer *fb = ctx->DrawBuffer;
+
+   struct intel_renderbuffer *depth_irb =
+      intel_get_renderbuffer(fb, BUFFER_DEPTH);
+   struct intel_renderbuffer *stencil_irb =
+      intel_get_renderbuffer(fb, BUFFER_STENCIL);
+
+   if (depth_irb && depth_irb->align_wa_mt)
+      intel_renderbuffer_move_temp_back(brw, depth_irb);
+
+   if (stencil_irb && stencil_irb->align_wa_mt)
+      intel_renderbuffer_move_temp_back(brw, stencil_irb);
+
+   for (unsigned i = 0; i < fb->_NumColorDrawBuffers; i++) {
+      struct intel_renderbuffer *irb =
+         intel_renderbuffer(fb->_ColorDrawBuffers[i]);
+
+      if (!irb || irb->align_wa_mt == NULL)
+         continue;
+
+      intel_renderbuffer_move_temp_back(brw, irb);
+   }
+}
+
 /* May fail if out of video memory for texture or vbo upload, or on
  * fallback conditions.
  */
@@ -605,6 +655,7 @@ retry:
       intel_batchbuffer_flush(brw);
 
    brw_program_cache_check_size(brw);
+   brw_postdraw_reconcile_align_wa_slices(brw);
    brw_postdraw_set_buffers_need_resolve(brw);
 
    return;
index a1022e9da1755af49e63faeba6bd7243ab8f5b23..d242aa499187c538c1ad7e91c5b0dfa82dcabd36 100644 (file)
@@ -133,7 +133,7 @@ get_stencil_miptree(struct intel_renderbuffer *irb)
       return NULL;
    if (irb->mt->stencil_mt)
       return irb->mt->stencil_mt;
-   return irb->mt;
+   return intel_renderbuffer_get_mt(irb);
 }
 
 static bool
@@ -262,7 +262,7 @@ brw_emit_depthbuffer(struct brw_context *brw)
    /* _NEW_BUFFERS */
    struct intel_renderbuffer *depth_irb = intel_get_renderbuffer(fb, BUFFER_DEPTH);
    struct intel_renderbuffer *stencil_irb = intel_get_renderbuffer(fb, BUFFER_STENCIL);
-   struct intel_mipmap_tree *depth_mt = depth_irb ? depth_irb->mt : NULL;
+   struct intel_mipmap_tree *depth_mt = intel_renderbuffer_get_mt(depth_irb);
    struct intel_mipmap_tree *stencil_mt = get_stencil_miptree(stencil_irb);
    uint32_t tile_x = brw->depthstencil.tile_x;
    uint32_t tile_y = brw->depthstencil.tile_y;
index 00edce42740e4d15c7dd0b2df7845a3a68037931..93efbb16f6f5b687a4d2decc0233d8579b1241f9 100644 (file)
@@ -1009,7 +1009,8 @@ gen4_update_renderbuffer_surface(struct brw_context *brw,
          * miptree and render into that.
          */
         intel_renderbuffer_move_to_temp(brw, irb, false);
-        mt = irb->mt;
+        assert(irb->align_wa_mt);
+        mt = irb->align_wa_mt;
       }
    }
 
index 864ff32a1bbc066b20dafe2cd49424bbb0b1e59b..478e7b88842de99b5e5ddca19b2bfe6ec7774fc2 100644 (file)
@@ -952,11 +952,11 @@ intel_renderbuffer_move_to_temp(struct brw_context *brw,
 
    intel_get_image_dims(rb->TexImage, &width, &height, &depth);
 
-   new_mt = intel_miptree_create(brw, rb->TexImage->TexObject->Target,
+   assert(irb->align_wa_mt == NULL);
+   new_mt = intel_miptree_create(brw, GL_TEXTURE_2D,
                                  intel_image->base.Base.TexFormat,
-                                 intel_image->base.Base.Level,
-                                 intel_image->base.Base.Level,
-                                 width, height, depth,
+                                 0, 0,
+                                 width, height, 1,
                                  irb->mt->num_samples,
                                  layout_flags);
 
@@ -964,11 +964,16 @@ intel_renderbuffer_move_to_temp(struct brw_context *brw,
       intel_miptree_alloc_hiz(brw, new_mt);
    }
 
-   intel_miptree_copy_teximage(brw, intel_image, new_mt, invalidate);
+   if (!invalidate)
+      intel_miptree_copy_slice(brw, intel_image->mt,
+                               intel_image->base.Base.Level, irb->mt_layer,
+                               new_mt, 0, 0);
 
-   intel_miptree_reference(&irb->mt, intel_image->mt);
-   intel_renderbuffer_set_draw_offset(irb);
+   intel_miptree_reference(&irb->align_wa_mt, new_mt);
    intel_miptree_release(&new_mt);
+
+   irb->draw_x = 0;
+   irb->draw_y = 0;
 }
 
 void
index 86811b4225e98f4369fc29a72df70f2139f23a2a..56c8e6b3b20d1ed02b36352a1775bead60dddbda 100644 (file)
@@ -67,6 +67,16 @@ struct intel_renderbuffer
     */
    struct intel_mipmap_tree *singlesample_mt;
 
+   /* Gen < 6 doesn't have layer specifier for render targets or depth. Driver
+    * needs to manually offset surfaces to correct level/layer. There are,
+    * however, alignment restrictions to respect as well and in come cases
+    * the only option is to use temporary single slice surface which driver
+    * copies after rendering to the full miptree.
+    *
+    * See intel_renderbuffer_move_to_temp().
+    */
+   struct intel_mipmap_tree *align_wa_mt;
+
    /**
     * \name Miptree view
     * \{
@@ -136,6 +146,14 @@ intel_renderbuffer(struct gl_renderbuffer *rb)
       return NULL;
 }
 
+static inline struct intel_mipmap_tree *
+intel_renderbuffer_get_mt(struct intel_renderbuffer *irb)
+{
+   if (!irb)
+      return NULL;
+
+   return (irb->align_wa_mt) ? irb->align_wa_mt : irb->mt;
+}
 
 /**
  * \brief Return the framebuffer attachment specified by attIndex.
@@ -188,6 +206,12 @@ intel_renderbuffer_get_tile_offsets(struct intel_renderbuffer *irb,
                                     uint32_t *tile_x,
                                     uint32_t *tile_y)
 {
+   if (irb->align_wa_mt) {
+      *tile_x = 0;
+      *tile_y = 0;
+      return 0;
+   }
+
    return intel_miptree_get_tile_offsets(irb->mt, irb->mt_level, irb->mt_layer,
                                          tile_x, tile_y);
 }
index 3eaf5e58c1e9fbf8690baf596e9135305d89f714..0320cf88adb48800a44f884e0a5fe5bfdb885b6b 100644 (file)
@@ -1309,7 +1309,7 @@ intel_miptree_copy_slice_sw(struct brw_context *brw,
    }
 }
 
-static void
+void
 intel_miptree_copy_slice(struct brw_context *brw,
                          struct intel_mipmap_tree *src_mt,
                          unsigned src_level, unsigned src_layer,
index f7b8e678cd86824f59e0e0f869d9a0bc7dbc01cc..5e457989c28731857721978630c8fe8432349afd 100644 (file)
@@ -813,6 +813,13 @@ void intel_miptree_set_image_offset(struct intel_mipmap_tree *mt,
                                     GLuint level,
                                     GLuint img, GLuint x, GLuint y);
 
+void
+intel_miptree_copy_slice(struct brw_context *brw,
+                         struct intel_mipmap_tree *src_mt,
+                         unsigned src_level, unsigned src_layer,
+                         struct intel_mipmap_tree *dst_mt,
+                         unsigned dst_level, unsigned dst_layer);
+
 void
 intel_miptree_copy_teximage(struct brw_context *brw,
                             struct intel_texture_image *intelImage,