Revert "i965: Always use Y-tiled buffers on SKL+"
[mesa.git] / src / mesa / drivers / dri / i965 / brw_meta_fast_clear.c
index cd3503508f99147e9df105dfe7f9935df525653a..76988bfda7bdff230da0c50c86aaec7bb44f5310 100644 (file)
@@ -26,6 +26,7 @@
 #include "main/context.h"
 #include "main/objectlabel.h"
 #include "main/shaderapi.h"
+#include "main/shaderobj.h"
 #include "main/arrayobj.h"
 #include "main/bufferobj.h"
 #include "main/buffers.h"
 #include "main/varray.h"
 #include "main/uniforms.h"
 #include "main/fbobject.h"
+#include "main/framebuffer.h"
+#include "main/renderbuffer.h"
 #include "main/texobj.h"
 
 #include "main/api_validate.h"
 #include "main/state.h"
 
+#include "util/format_srgb.h"
+
 #include "vbo/vbo_context.h"
 
 #include "drivers/common/meta.h"
 #include "brw_defines.h"
 #include "brw_context.h"
 #include "brw_draw.h"
+#include "brw_state.h"
 #include "intel_fbo.h"
 #include "intel_batchbuffer.h"
 
 #include "brw_blorp.h"
+#include "brw_meta_util.h"
 
 struct brw_fast_clear_state {
    struct gl_buffer_object *buf_obj;
    struct gl_vertex_array_object *array_obj;
+   struct gl_shader_program *shader_prog;
    GLuint vao;
-   GLuint shader_prog;
    GLint color_location;
 };
 
@@ -105,7 +112,8 @@ brw_bind_rep_write_shader(struct brw_context *brw, float *color)
    const char *vs_source =
       "#extension GL_AMD_vertex_shader_layer : enable\n"
       "#extension GL_ARB_draw_instanced : enable\n"
-      "attribute vec4 position;\n"
+      "#extension GL_ARB_explicit_attrib_location : enable\n"
+      "layout(location = 0) in vec4 position;\n"
       "uniform int layer;\n"
       "void main()\n"
       "{\n"
@@ -121,32 +129,23 @@ brw_bind_rep_write_shader(struct brw_context *brw, float *color)
       "   gl_FragColor = color;\n"
       "}\n";
 
-   GLuint vs, fs;
    struct brw_fast_clear_state *clear = brw->fast_clear_state;
    struct gl_context *ctx = &brw->ctx;
 
    if (clear->shader_prog) {
-      _mesa_UseProgram(clear->shader_prog);
+      _mesa_meta_use_program(ctx, clear->shader_prog);
       _mesa_Uniform4fv(clear->color_location, 1, color);
       return;
    }
 
-   vs = _mesa_meta_compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_source);
-   fs = _mesa_meta_compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_source);
-
-   clear->shader_prog = _mesa_CreateProgram();
-   _mesa_AttachShader(clear->shader_prog, fs);
-   _mesa_DeleteShader(fs);
-   _mesa_AttachShader(clear->shader_prog, vs);
-   _mesa_DeleteShader(vs);
-   _mesa_BindAttribLocation(clear->shader_prog, 0, "position");
-   _mesa_ObjectLabel(GL_PROGRAM, clear->shader_prog, -1, "meta repclear");
-   _mesa_LinkProgram(clear->shader_prog);
+   _mesa_meta_compile_and_link_program(ctx, vs_source, fs_source,
+                                       "meta repclear",
+                                       &clear->shader_prog);
 
    clear->color_location =
-      _mesa_GetUniformLocation(clear->shader_prog, "color");
+      _mesa_program_resource_location(clear->shader_prog, GL_UNIFORM, "color");
 
-   _mesa_UseProgram(clear->shader_prog);
+   _mesa_meta_use_program(ctx, clear->shader_prog);
    _mesa_Uniform4fv(clear->color_location, 1, color);
 }
 
@@ -163,7 +162,7 @@ brw_meta_fast_clear_free(struct brw_context *brw)
 
    _mesa_DeleteVertexArrays(1, &clear->vao);
    _mesa_reference_buffer_object(&brw->ctx, &clear->buf_obj, NULL);
-   _mesa_DeleteProgram(clear->shader_prog);
+   _mesa_reference_shader_program(&brw->ctx, &clear->shader_prog, NULL);
    free(clear);
 
    if (old_context)
@@ -173,7 +172,7 @@ brw_meta_fast_clear_free(struct brw_context *brw)
 }
 
 struct rect {
-   int x0, y0, x1, y1;
+   unsigned x0, y0, x1, y1;
 };
 
 static void
@@ -217,14 +216,19 @@ brw_draw_rectlist(struct brw_context *brw, struct rect *rect, int num_instances)
                   NULL, 0, NULL);
 }
 
-static void
-get_fast_clear_rect(struct brw_context *brw, struct gl_framebuffer *fb,
-                    struct intel_renderbuffer *irb, struct rect *rect)
+void
+brw_get_fast_clear_rect(const struct brw_context *brw,
+                        const struct gl_framebuffer *fb,
+                        const struct intel_mipmap_tree* mt,
+                        unsigned *x0, unsigned *y0,
+                        unsigned *x1, unsigned *y1)
 {
    unsigned int x_align, y_align;
    unsigned int x_scaledown, y_scaledown;
 
-   if (irb->mt->msaa_layout == INTEL_MSAA_LAYOUT_NONE) {
+   /* Only single sampled surfaces need to (and actually can) be resolved. */
+   if (mt->msaa_layout == INTEL_MSAA_LAYOUT_NONE ||
+       intel_miptree_is_lossless_compressed(brw, mt)) {
       /* From the Ivy Bridge PRM, Vol2 Part1 11.7 "MCS Buffer for Render
        * Target(s)", beneath the "Fast Color Clear" bullet (p327):
        *
@@ -240,7 +244,7 @@ get_fast_clear_rect(struct brw_context *brw, struct gl_framebuffer *fb,
        * alignment size returned by intel_get_non_msrt_mcs_alignment(), but
        * with X alignment multiplied by 16 and Y alignment multiplied by 32.
        */
-      intel_get_non_msrt_mcs_alignment(irb->mt, &x_align, &y_align);
+      intel_get_non_msrt_mcs_alignment(mt, &x_align, &y_align);
       x_align *= 16;
 
       /* SKL+ line alignment requirement for Y-tiled are half those of the prior
@@ -304,7 +308,7 @@ get_fast_clear_rect(struct brw_context *brw, struct gl_framebuffer *fb,
        * vertically and either 4 or 16 horizontally, and the scaledown
        * factor is 2 vertically and either 2 or 8 horizontally.
        */
-      switch (irb->mt->num_samples) {
+      switch (mt->num_samples) {
       case 2:
       case 4:
          x_scaledown = 8;
@@ -323,33 +327,35 @@ get_fast_clear_rect(struct brw_context *brw, struct gl_framebuffer *fb,
       y_align = y_scaledown * 2;
    }
 
-   rect->x0 = fb->_Xmin;
-   rect->x1 = fb->_Xmax;
+   *x0 = fb->_Xmin;
+   *x1 = fb->_Xmax;
    if (fb->Name != 0) {
-      rect->y0 = fb->_Ymin;
-      rect->y1 = fb->_Ymax;
+      *y0 = fb->_Ymin;
+      *y1 = fb->_Ymax;
    } else {
-      rect->y0 = fb->Height - fb->_Ymax;
-      rect->y1 = fb->Height - fb->_Ymin;
+      *y0 = fb->Height - fb->_Ymax;
+      *y1 = fb->Height - fb->_Ymin;
    }
 
-   rect->x0 = ROUND_DOWN_TO(rect->x0,  x_align) / x_scaledown;
-   rect->y0 = ROUND_DOWN_TO(rect->y0, y_align) / y_scaledown;
-   rect->x1 = ALIGN(rect->x1, x_align) / x_scaledown;
-   rect->y1 = ALIGN(rect->y1, y_align) / y_scaledown;
+   *x0 = ROUND_DOWN_TO(*x0,  x_align) / x_scaledown;
+   *y0 = ROUND_DOWN_TO(*y0, y_align) / y_scaledown;
+   *x1 = ALIGN(*x1, x_align) / x_scaledown;
+   *y1 = ALIGN(*y1, y_align) / y_scaledown;
 }
 
-static void
-get_buffer_rect(const struct gl_framebuffer *fb, struct rect *rect)
+void
+brw_meta_get_buffer_rect(const struct gl_framebuffer *fb,
+                         unsigned *x0, unsigned *y0,
+                         unsigned *x1, unsigned *y1)
 {
-   rect->x0 = fb->_Xmin;
-   rect->x1 = fb->_Xmax;
+   *x0 = fb->_Xmin;
+   *x1 = fb->_Xmax;
    if (fb->Name != 0) {
-      rect->y0 = fb->_Ymin;
-      rect->y1 = fb->_Ymax;
+      *y0 = fb->_Ymin;
+      *y1 = fb->_Ymax;
    } else {
-      rect->y0 = fb->Height - fb->_Ymax;
-      rect->y1 = fb->Height - fb->_Ymin;
+      *y0 = fb->Height - fb->_Ymax;
+      *y1 = fb->Height - fb->_Ymin;
    }
 }
 
@@ -359,11 +365,38 @@ get_buffer_rect(const struct gl_framebuffer *fb, struct rect *rect)
  * Fast color clear can only clear to color values of 1.0 or 0.0.  At the
  * moment we only support floating point, unorm, and snorm buffers.
  */
-static bool
-is_color_fast_clear_compatible(struct brw_context *brw,
-                               mesa_format format,
-                               const union gl_color_union *color)
+bool
+brw_is_color_fast_clear_compatible(struct brw_context *brw,
+                                   const struct intel_mipmap_tree *mt,
+                                   const union gl_color_union *color)
 {
+   const struct gl_context *ctx = &brw->ctx;
+
+   /* If we're mapping the render format to a different format than the
+    * format we use for texturing then it is a bit questionable whether it
+    * should be possible to use a fast clear. Although we only actually
+    * render using a renderable format, without the override workaround it
+    * wouldn't be possible to have a non-renderable surface in a fast clear
+    * state so the hardware probably legitimately doesn't need to support
+    * this case. At least on Gen9 this really does seem to cause problems.
+    */
+   if (brw->gen >= 9 &&
+       brw_format_for_mesa_format(mt->format) !=
+       brw->render_target_format[mt->format])
+      return false;
+
+   /* Gen9 doesn't support fast clear on single-sampled SRGB buffers. When
+    * GL_FRAMEBUFFER_SRGB is enabled any color renderbuffers will be
+    * resolved in intel_update_state. In that case it's pointless to do a
+    * fast clear because it's very likely to be immediately resolved.
+    */
+   if (brw->gen >= 9 &&
+       mt->num_samples <= 1 &&
+       ctx->Color.sRGBEnabled &&
+       _mesa_get_srgb_format_linear(mt->format) != mt->format)
+      return false;
+
+   const mesa_format format = _mesa_get_render_format(ctx, mt->format);
    if (_mesa_is_format_integer_color(format)) {
       if (brw->gen >= 8) {
          perf_debug("Integer fast clear not enabled for (%s)",
@@ -389,10 +422,10 @@ is_color_fast_clear_compatible(struct brw_context *brw,
  * Convert the given color to a bitfield suitable for ORing into DWORD 7 of
  * SURFACE_STATE (DWORD 12-15 on SKL+).
  */
-static void
-set_fast_clear_color(struct brw_context *brw,
-                     struct intel_mipmap_tree *mt,
-                     const union gl_color_union *color)
+void
+brw_meta_set_fast_clear_color(struct brw_context *brw,
+                              struct intel_mipmap_tree *mt,
+                              const union gl_color_union *color)
 {
    union gl_color_union override_color = *color;
 
@@ -424,6 +457,15 @@ set_fast_clear_color(struct brw_context *brw,
          override_color.f[3] = 1.0f;
    }
 
+   /* Handle linear→SRGB conversion */
+   if (brw->ctx.Color.sRGBEnabled &&
+       _mesa_get_srgb_format_linear(mt->format) != mt->format) {
+      for (int i = 0; i < 3; i++) {
+         override_color.f[i] =
+            util_format_linear_to_srgb_float(override_color.f[i]);
+      }
+   }
+
    if (brw->gen >= 9) {
       mt->gen9_fast_clear_color = override_color;
    } else {
@@ -493,8 +535,20 @@ fast_clear_attachments(struct brw_context *brw,
                        uint32_t fast_clear_buffers,
                        struct rect fast_clear_rect)
 {
-   assert(brw->gen >= 9);
    struct gl_context *ctx = &brw->ctx;
+   const bool srgb_enabled = ctx->Color.sRGBEnabled;
+
+   assert(brw->gen >= 9);
+
+   /* Make sure the GL_FRAMEBUFFER_SRGB is disabled during fast clear so that
+    * the surface state will always be uploaded with a linear buffer. SRGB
+    * buffers are not supported on Gen9 because they are not marked as
+    * losslessly compressible. This shouldn't matter for the fast clear
+    * because the color is not written to the framebuffer yet so the hardware
+    * doesn't need to do any SRGB conversion.
+    */
+   if (srgb_enabled)
+      _mesa_set_framebuffer_srgb(ctx, GL_FALSE);
 
    brw_bind_rep_write_shader(brw, (float *) fast_clear_color);
 
@@ -511,7 +565,7 @@ fast_clear_attachments(struct brw_context *brw,
 
       _mesa_meta_drawbuffers_from_bitfield(1 << index);
 
-      brw_draw_rectlist(ctx, &fast_clear_rect, MAX2(1, fb->MaxNumLayers));
+      brw_draw_rectlist(brw, &fast_clear_rect, MAX2(1, fb->MaxNumLayers));
 
       /* Now set the mcs we cleared to INTEL_FAST_CLEAR_STATE_CLEAR so we'll
        * resolve them eventually.
@@ -522,6 +576,9 @@ fast_clear_attachments(struct brw_context *brw,
    }
 
    set_fast_clear_op(brw, 0);
+
+   if (srgb_enabled)
+      _mesa_set_framebuffer_srgb(ctx, GL_TRUE);
 }
 
 bool
@@ -529,7 +586,6 @@ brw_meta_fast_clear(struct brw_context *brw, struct gl_framebuffer *fb,
                     GLbitfield buffers, bool partial_clear)
 {
    struct gl_context *ctx = &brw->ctx;
-   mesa_format format;
    enum { FAST_CLEAR, REP_CLEAR, PLAIN_CLEAR } clear_type;
    GLbitfield plain_clear_buffers, meta_save, rep_clear_buffers, fast_clear_buffers;
    struct rect fast_clear_rect, clear_rect;
@@ -563,13 +619,6 @@ brw_meta_fast_clear(struct brw_context *brw, struct gl_framebuffer *fb,
       if (brw->gen < 7)
          clear_type = REP_CLEAR;
 
-      /* Certain formats have unresolved issues with sampling from the MCS
-       * buffer on Gen9. This disables fast clears altogether for MSRTs until
-       * we can figure out what's going on.
-       */
-      if (brw->gen >= 9 && irb->mt->num_samples > 1)
-         clear_type = REP_CLEAR;
-
       if (irb->mt->fast_clear_state == INTEL_FAST_CLEAR_STATE_NO_MCS)
          clear_type = REP_CLEAR;
 
@@ -582,8 +631,8 @@ brw_meta_fast_clear(struct brw_context *brw, struct gl_framebuffer *fb,
       /* Fast clear is only supported for colors where all components are
        * either 0 or 1.
        */
-      format = _mesa_get_render_format(ctx, irb->mt->format);
-      if (!is_color_fast_clear_compatible(brw, format, &ctx->Color.ClearColor))
+      if (!brw_is_color_fast_clear_compatible(brw, irb->mt,
+                                              &ctx->Color.ClearColor))
          clear_type = REP_CLEAR;
 
       /* From the SNB PRM (Vol4_Part1):
@@ -604,6 +653,7 @@ brw_meta_fast_clear(struct brw_context *brw, struct gl_framebuffer *fb,
       GLubyte *color_mask = ctx->Color.ColorMask[buf];
       for (int i = 0; i < 4; i++) {
          if (_mesa_format_has_color_component(irb->mt->format, i) &&
+             !(i == 3 && irb->Base.Base._BaseFormat == GL_RGB) &&
              !color_mask[i]) {
             perf_debug("Falling back to plain clear on %dx%d buffer because of color mask\n",
                        irb->mt->logical_width0, irb->mt->logical_height0);
@@ -621,7 +671,7 @@ brw_meta_fast_clear(struct brw_context *brw, struct gl_framebuffer *fb,
 
       switch (clear_type) {
       case FAST_CLEAR:
-         set_fast_clear_color(brw, irb->mt, &ctx->Color.ClearColor);
+         brw_meta_set_fast_clear_color(brw, irb->mt, &ctx->Color.ClearColor);
          irb->need_downsample = true;
 
          /* If the buffer is already in INTEL_FAST_CLEAR_STATE_CLEAR, the
@@ -637,17 +687,23 @@ brw_meta_fast_clear(struct brw_context *brw, struct gl_framebuffer *fb,
          irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_RESOLVED;
          irb->need_downsample = true;
          fast_clear_buffers |= 1 << index;
-         get_fast_clear_rect(brw, fb, irb, &fast_clear_rect);
+         brw_get_fast_clear_rect(brw, fb, irb->mt,
+                                 &fast_clear_rect.x0, &fast_clear_rect.y0,
+                                 &fast_clear_rect.x1, &fast_clear_rect.y1);
          break;
 
       case REP_CLEAR:
          rep_clear_buffers |= 1 << index;
-         get_buffer_rect(fb, &clear_rect);
+         brw_meta_get_buffer_rect(fb,
+                                  &clear_rect.x0, &clear_rect.y0,
+                                  &clear_rect.x1, &clear_rect.y1);
          break;
 
       case PLAIN_CLEAR:
          plain_clear_buffers |= 1 << index;
-         get_buffer_rect(fb, &clear_rect);
+         brw_meta_get_buffer_rect(fb,
+                                  &clear_rect.x0, &clear_rect.y0,
+                                  &clear_rect.x1, &clear_rect.y1);
          continue;
       }
    }
@@ -761,9 +817,11 @@ brw_meta_fast_clear(struct brw_context *brw, struct gl_framebuffer *fb,
    return true;
 }
 
-static void
-get_resolve_rect(struct brw_context *brw,
-                 struct intel_mipmap_tree *mt, struct rect *rect)
+void
+brw_get_resolve_rect(const struct brw_context *brw,
+                     const struct intel_mipmap_tree *mt,
+                     unsigned *x0, unsigned *y0,
+                     unsigned *x1, unsigned *y1)
 {
    unsigned x_align, y_align;
    unsigned x_scaledown, y_scaledown;
@@ -791,9 +849,9 @@ get_resolve_rect(struct brw_context *brw,
       x_scaledown = x_align / 2;
       y_scaledown = y_align / 2;
    }
-   rect->x0 = rect->y0 = 0;
-   rect->x1 = ALIGN(mt->logical_width0, x_scaledown) / x_scaledown;
-   rect->y1 = ALIGN(mt->logical_height0, y_scaledown) / y_scaledown;
+   *x0 = *y0 = 0;
+   *x1 = ALIGN(mt->logical_width0, x_scaledown) / x_scaledown;
+   *y1 = ALIGN(mt->logical_height0, y_scaledown) / y_scaledown;
 }
 
 void
@@ -801,20 +859,25 @@ brw_meta_resolve_color(struct brw_context *brw,
                        struct intel_mipmap_tree *mt)
 {
    struct gl_context *ctx = &brw->ctx;
-   GLuint fbo, rbo;
+   struct gl_framebuffer *drawFb;
+   struct gl_renderbuffer *rb;
    struct rect rect;
 
    brw_emit_mi_flush(brw);
 
+   drawFb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF);
+   if (drawFb == NULL) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "in %s", __func__);
+      return;
+   }
+
    _mesa_meta_begin(ctx, MESA_META_ALL);
 
-   _mesa_GenFramebuffers(1, &fbo);
-   rbo = brw_get_rb_for_slice(brw, mt, 0, 0, false);
+   rb = brw_get_rb_for_slice(brw, mt, 0, 0, false);
 
-   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
-   _mesa_FramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER,
-                                 GL_COLOR_ATTACHMENT0,
-                                 GL_RENDERBUFFER, rbo);
+   _mesa_bind_framebuffers(ctx, drawFb, ctx->ReadBuffer);
+   _mesa_framebuffer_renderbuffer(ctx, ctx->DrawBuffer, GL_COLOR_ATTACHMENT0,
+                                  rb);
    _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);
 
    brw_fast_clear_init(brw);
@@ -827,18 +890,21 @@ brw_meta_resolve_color(struct brw_context *brw,
     * bits to let us select the type of resolve.  For fast clear resolves, it
     * turns out we can use the same value as pre-SKL though.
     */
-   set_fast_clear_op(brw, GEN7_PS_RENDER_TARGET_RESOLVE_ENABLE);
+   if (intel_miptree_is_lossless_compressed(brw, mt))
+      set_fast_clear_op(brw, GEN9_PS_RENDER_TARGET_RESOLVE_FULL);
+   else
+      set_fast_clear_op(brw, GEN7_PS_RENDER_TARGET_RESOLVE_ENABLE);
 
    mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_RESOLVED;
-   get_resolve_rect(brw, mt, &rect);
+   brw_get_resolve_rect(brw, mt, &rect.x0, &rect.y0, &rect.x1, &rect.y1);
 
    brw_draw_rectlist(brw, &rect, 1);
 
    set_fast_clear_op(brw, 0);
    use_rectlist(brw, false);
 
-   _mesa_DeleteRenderbuffers(1, &rbo);
-   _mesa_DeleteFramebuffers(1, &fbo);
+   _mesa_reference_renderbuffer(&rb, NULL);
+   _mesa_reference_framebuffer(&drawFb, NULL);
 
    _mesa_meta_end(ctx);