<div dir="ltr">On 4 November 2013 14:24, Paul Berry <span dir="ltr"><<a href="mailto:stereotype441@gmail.com" target="_blank">stereotype441@gmail.com</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">i965/gen7 hardware doesn't perform alpha blending correctly when<br>
compressed (CMS) multisampled buffers are in use.  Therefore, we need<br>
to detect when alpha blending is used on a compressed multisampled<br>
buffer, and convert the buffer to uncompressed (UMS) layout.<br>
<br>
Once a given buffer has been converted from CMS to UMS, we leave it in<br>
UMS mode forever after, because (a) the conversion is expensive, and<br>
(b) it seems likely that if alpha blending is performed on a buffer<br>
once, it will probably be performed again on subsequent frames.<br>
<br>
Fixes glitches in GTA San Andreas under Wine.<br>
<br>
Bugzilla: <a href="https://bugs.freedesktop.org/show_bug.cgi?id=53077" target="_blank">https://bugs.freedesktop.org/show_bug.cgi?id=53077</a><br></blockquote><div><br></div><div>NAK this patch.  I found the true source of the problem: multisampled buffers need to use a vertical alignment of 4.  We were using a vertical alignment of 2.<br>
<br></div><div>I'll follow up with a proper fix ASAP.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
---<br>
 src/mesa/drivers/dri/i965/brw_blorp.h        |  14 ++++<br>
 src/mesa/drivers/dri/i965/brw_blorp_blit.cpp |  51 +++++++++++++<br>
 src/mesa/drivers/dri/i965/brw_context.h      |   1 +<br>
 src/mesa/drivers/dri/i965/brw_draw.c         |   5 +-<br>
 src/mesa/drivers/dri/i965/brw_misc_state.c   | 104 +++++++++++++++++++++++++++<br>
 src/mesa/drivers/dri/i965/gen6_cc.c          |   2 +<br>
 src/mesa/drivers/dri/i965/gen7_blorp.cpp     |   2 +-<br>
 7 files changed, 176 insertions(+), 3 deletions(-)<br>
<br>
diff --git a/src/mesa/drivers/dri/i965/brw_blorp.h b/src/mesa/drivers/dri/i965/brw_blorp.h<br>
index 07ab805..bbc610d 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_blorp.h<br>
+++ b/src/mesa/drivers/dri/i965/brw_blorp.h<br>
@@ -54,6 +54,9 @@ void<br>
 brw_blorp_resolve_color(struct brw_context *brw,<br>
                         struct intel_mipmap_tree *mt);<br>
<br>
+void<br>
+brw_blorp_cms_to_ums(struct brw_context *brw, struct intel_mipmap_tree *mt);<br>
+<br>
 #ifdef __cplusplus<br>
 } /* end extern "C" */<br>
<br>
@@ -356,6 +359,17 @@ public:<br>
    virtual uint32_t get_wm_prog(struct brw_context *brw,<br>
                                 brw_blorp_prog_data **prog_data) const;<br>
<br>
+   /**<br>
+    * Force the destination to use uncompressed multisampling<br>
+    * (INTEL_MSAA_LAYOUT_UMS) instead of compressed multisampling.  This is<br>
+    * used when we are converting a framebuffer from an uncompressed to a<br>
+    * compressed layout.<br>
+    */<br>
+   void force_dst_to_ums()<br>
+   {<br>
+      this->dst.msaa_layout = INTEL_MSAA_LAYOUT_UMS;<br>
+   }<br>
+<br>
 private:<br>
    brw_blorp_blit_prog_key wm_prog_key;<br>
 };<br>
diff --git a/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp b/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp<br>
index 7e436f7..6d558d8 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp<br>
+++ b/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp<br>
@@ -167,6 +167,57 @@ brw_blorp_blit_miptrees(struct brw_context *brw,<br>
    intel_miptree_slice_set_needs_hiz_resolve(dst_mt, dst_level, dst_layer);<br>
 }<br>
<br>
+<br>
+/**<br>
+ * Convert a multisampled framebuffer from compressed layout<br>
+ * (INTEL_MSAA_LAYOUT_CMS) to uncompressed layout (INTEL_MSAA_LAYOUT_UMS).<br>
+ *<br>
+ * The conversion happens in place--no extra buffer needs to be allocated.<br>
+ */<br>
+void<br>
+brw_blorp_cms_to_ums(struct brw_context *brw, struct intel_mipmap_tree *mt)<br>
+{<br>
+   assert(mt->msaa_layout == INTEL_MSAA_LAYOUT_CMS);<br>
+<br>
+   /* Multisampled buffers aren't mipmapped, so the code below only has to fix<br>
+    * up miplevel 0.<br>
+    */<br>
+   assert(mt->first_level == 0 && mt->last_level == 0);<br>
+<br>
+   /* Cubemaps can't be multisampled, so the code below doesn't have to<br>
+    * correct by a factor of 6 when counting layers.<br>
+    */<br>
+   assert(mt->target != GL_TEXTURE_CUBE_MAP);<br>
+<br>
+   for (unsigned layer = 0; layer < mt->logical_depth0; layer++) {<br>
+      /* Note: normally blitting from one miptree to itself is undefined if<br>
+       * the source and destination rectangles overlap, because (a) the 3D<br>
+       * pipeline doesn't make any guarantee as to what order the pixels are<br>
+       * processed in, and (b) the source and destination rectangles are<br>
+       * accessed through different (non-coherent) caches.  However, in this<br>
+       * case it's ok, since the source and destination rectangles are<br>
+       * identical, so (a) order doesn't matter because every pixel is copied<br>
+       * to itself, and (b) cache coherency isn't a problem because every<br>
+       * pixel is read exactly once and then written exactly once.<br>
+       */<br>
+      brw_blorp_blit_params params(brw,<br>
+                                   mt, 0, layer,<br>
+                                   mt, 0, layer,<br>
+                                   0, 0,<br>
+                                   mt->logical_width0, mt->logical_height0,<br>
+                                   0, 0,<br>
+                                   mt->logical_width0, mt->logical_height0,<br>
+                                   GL_NEAREST, false, false);<br>
+      params.force_dst_to_ums();<br>
+      brw_blorp_exec(brw, &params);<br>
+   }<br>
+<br>
+   intel_miptree_release(&mt->mcs_mt);<br>
+   mt->msaa_layout = INTEL_MSAA_LAYOUT_UMS;<br>
+   mt->mcs_state = INTEL_MCS_STATE_NONE;<br>
+}<br>
+<br>
+<br>
 static void<br>
 do_blorp_blit(struct brw_context *brw, GLbitfield buffer_bit,<br>
               struct intel_renderbuffer *src_irb,<br>
diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h<br>
index 7aacf4f..85cb567 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_context.h<br>
+++ b/src/mesa/drivers/dri/i965/brw_context.h<br>
@@ -1466,6 +1466,7 @@ void brw_get_depthstencil_tile_masks(struct intel_mipmap_tree *depth_mt,<br>
                                      uint32_t *out_tile_mask_y);<br>
 void brw_workaround_depthstencil_alignment(struct brw_context *brw,<br>
                                            GLbitfield clear_mask);<br>
+void brw_workaround_cms_blending(struct brw_context *brw);<br>
<br>
 /* brw_object_purgeable.c */<br>
 void brw_init_object_purgeable_functions(struct dd_function_table *functions);<br>
diff --git a/src/mesa/drivers/dri/i965/brw_draw.c b/src/mesa/drivers/dri/i965/brw_draw.c<br>
index 0acd089..50c0ddc 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_draw.c<br>
+++ b/src/mesa/drivers/dri/i965/brw_draw.c<br>
@@ -355,10 +355,11 @@ static bool brw_try_draw_prims( struct gl_context *ctx,<br>
<br>
    intel_prepare_render(brw);<br>
<br>
-   /* This workaround has to happen outside of brw_upload_state() because it<br>
-    * may flush the batchbuffer for a blit, affecting the state flags.<br>
+   /* These workarounds have to happen outside of brw_upload_state() because<br>
+    * they may flush the batchbuffer for a blit, affecting the state flags.<br>
     */<br>
    brw_workaround_depthstencil_alignment(brw, 0);<br>
+   brw_workaround_cms_blending(brw);<br>
<br>
    /* Resolves must occur after updating renderbuffers, updating context state,<br>
     * and finalizing textures but before setting up any hardware state for<br>
diff --git a/src/mesa/drivers/dri/i965/brw_misc_state.c b/src/mesa/drivers/dri/i965/brw_misc_state.c<br>
index 70b0dbd..95836fa 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_misc_state.c<br>
+++ b/src/mesa/drivers/dri/i965/brw_misc_state.c<br>
@@ -36,6 +36,7 @@<br>
 #include "intel_mipmap_tree.h"<br>
 #include "intel_regions.h"<br>
<br>
+#include "brw_blorp.h"<br>
 #include "brw_context.h"<br>
 #include "brw_state.h"<br>
 #include "brw_defines.h"<br>
@@ -1081,3 +1082,106 @@ const struct brw_tracked_state brw_state_base_address = {<br>
    },<br>
    .emit = upload_state_base_address<br>
 };<br>
+<br>
+<br>
+/**<br>
+ * Return true if the color buffer indicated by \c b needs the CMS blending<br>
+ * workaround applied to it.<br>
+ *<br>
+ * When the CMS MSAA layout is in use, the hardware's pixel backend always<br>
+ * seems to write new color values into the buffer correctly, but it doesn't<br>
+ * always read old values from the buffer correctly.  Therefore, whenever the<br>
+ * blending/logic-op mode causes the final value of covered samples to depend<br>
+ * on the old values of those samples, we need to do a workaround.<br>
+ */<br>
+static inline bool<br>
+cms_blending_workaround_needed(struct brw_context *brw, int b)<br>
+{<br>
+   struct gl_context *ctx = &brw->ctx;<br>
+   struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[b];<br>
+   struct intel_renderbuffer *irb = intel_renderbuffer(rb);<br>
+   if (irb->mt->msaa_layout != INTEL_MSAA_LAYOUT_CMS)<br>
+      return false;<br>
+<br>
+   /* _NEW_COLOR */<br>
+   if (ctx->Color.ColorLogicOpEnabled) {<br>
+      switch (ctx->Color.LogicOp) {<br>
+      case GL_CLEAR:<br>
+      case GL_COPY:<br>
+      case GL_COPY_INVERTED:<br>
+      case GL_SET:<br>
+         /* In these modes, the final sample value depends only on the<br>
+          * "source" value from the shader; they don't depend on the<br>
+          * destination sample value.<br>
+          */<br>
+         return false;<br>
+      default:<br>
+         return true;<br>
+      }<br>
+   }<br>
+<br>
+   if (!(ctx->Color.BlendEnabled & (1 << b)))<br>
+      return false;<br>
+<br>
+   GLenum eqRGB = ctx->Color.Blend[b].EquationRGB;<br>
+   if (eqRGB == GL_MIN || eqRGB == GL_MAX)<br>
+      return true;<br>
+   switch (ctx->Color.Blend[b].DstRGB) {<br>
+   case GL_ZERO:<br>
+      break;<br>
+   case GL_ONE_MINUS_DST_ALPHA:<br>
+      /* If the buffer is missing an alpha channel, alpha is effectively<br>
+       * always 1.0, so GL_ONE_MINUS_DST_ALPHA mode reduces to GL_ZERO mode.<br>
+       */<br>
+      return _mesa_base_format_has_channel(rb->_BaseFormat,<br>
+                                           GL_TEXTURE_ALPHA_TYPE);<br>
+   default:<br>
+      return true;<br>
+   }<br>
+<br>
+   if (_mesa_base_format_has_channel(rb->_BaseFormat, GL_TEXTURE_ALPHA_TYPE)) {<br>
+      GLenum eqA = ctx->Color.Blend[b].EquationA;<br>
+      if (eqA == GL_MIN || eqA == GL_MAX)<br>
+         return true;<br>
+      if (ctx->Color.Blend[b].DstA != GL_ZERO)<br>
+         return true;<br>
+   }<br>
+<br>
+   return false;<br>
+}<br>
+<br>
+<br>
+/**<br>
+ * When the CMS MSAA layout is in use, the hardware's pixel backend always<br>
+ * seems to write new color values into the buffer correctly, but it doesn't<br>
+ * always read old values from the buffer correctly.<br>
+ *<br>
+ * Therefore, if we're rendering in a way that causes the pixel backend to<br>
+ * read color values from the buffer, we need to first convert from the CMS to<br>
+ * the UMS layout.<br>
+ */<br>
+void<br>
+brw_workaround_cms_blending(struct brw_context *brw)<br>
+{<br>
+   struct gl_context *ctx = &brw->ctx;<br>
+<br>
+   if (!(brw->NewGLState & (_NEW_BUFFERS | _NEW_COLOR)))<br>
+      return;<br>
+<br>
+   /* Prior to Gen7, compressed multisampling wasn't supported.  Hopefully<br>
+    * this bug is fixed in Gen8.<br>
+    */<br>
+   if (brw->gen != 7)<br>
+      return;<br>
+<br>
+   /* _NEW_BUFFERS */<br>
+   int nr_draw_buffers = ctx->DrawBuffer->_NumColorDrawBuffers;<br>
+   for (int b = 0; b < nr_draw_buffers; b++) {<br>
+      if (!cms_blending_workaround_needed(brw, b))<br>
+         continue;<br>
+<br>
+      struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[b];<br>
+      struct intel_renderbuffer *irb = intel_renderbuffer(rb);<br>
+      brw_blorp_cms_to_ums(brw, irb->mt);<br>
+   }<br>
+}<br>
diff --git a/src/mesa/drivers/dri/i965/gen6_cc.c b/src/mesa/drivers/dri/i965/gen6_cc.c<br>
index 45c926c..f1222a3 100644<br>
--- a/src/mesa/drivers/dri/i965/gen6_cc.c<br>
+++ b/src/mesa/drivers/dri/i965/gen6_cc.c<br>
@@ -30,11 +30,13 @@<br>
 #include "brw_defines.h"<br>
 #include "brw_util.h"<br>
 #include "intel_batchbuffer.h"<br>
+#include "intel_fbo.h"<br>
 #include "main/macros.h"<br>
 #include "main/enums.h"<br>
 #include "main/glformats.h"<br>
 #include "main/stencil.h"<br>
<br>
+<br>
 static void<br>
 gen6_upload_blend_state(struct brw_context *brw)<br>
 {<br>
diff --git a/src/mesa/drivers/dri/i965/gen7_blorp.cpp b/src/mesa/drivers/dri/i965/gen7_blorp.cpp<br>
index 71f31b7..d66e5cc 100644<br>
--- a/src/mesa/drivers/dri/i965/gen7_blorp.cpp<br>
+++ b/src/mesa/drivers/dri/i965/gen7_blorp.cpp<br>
@@ -196,7 +196,7 @@ gen7_blorp_emit_surface_state(struct brw_context *brw,<br>
    surf[3] = pitch_bytes - 1;<br>
<br>
    surf[4] = gen7_surface_msaa_bits(surface->num_samples, surface->msaa_layout);<br>
-   if (surface->mt->mcs_mt) {<br>
+   if (surface->mt->mcs_mt && surface->msaa_layout != INTEL_MSAA_LAYOUT_UMS) {<br>
       gen7_set_surface_mcs_info(brw, surf, wm_surf_offset, surface->mt->mcs_mt,<br>
                                 is_render_target);<br>
    }<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.8.4.2<br>
<br>
</font></span></blockquote></div><br></div></div>