glsl: lower the precision of imageLoad
authorMarek Olšák <marek.olsak@amd.com>
Sun, 10 May 2020 00:57:25 +0000 (20:57 -0400)
committerMarge Bot <eric+marge@anholt.net>
Tue, 2 Jun 2020 20:01:18 +0000 (20:01 +0000)
Acked-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Reviewed-by: Rob Clark <robdclark@chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5002>

src/compiler/glsl/lower_builtins.cpp
src/compiler/glsl/lower_precision.cpp
src/compiler/glsl/tests/lower_precision_test.py

index e7130df7ac6a21e15499085e4dea960515f4a7b3..7b5ac204e65da3eae0818717da8f8c641cd96713 100644 (file)
@@ -52,7 +52,10 @@ lower_builtins(exec_list *instructions)
 ir_visitor_status
 lower_builtins_visitor::visit_leave(ir_call *ir)
 {
-   if (!ir->callee->is_builtin())
+   /* lower_precision() also inlines some intrinsics, which can't be inlined
+    * further.
+    */
+   if (!ir->callee->is_builtin() || ir->callee->is_intrinsic())
       return visit_continue;
 
    ir->generate_inline(ir);
index b410e3290a2466daacf7aff9972cb271dbde8442..faa990703e6d38422f640f4232222ce439dbd589 100644 (file)
@@ -163,6 +163,7 @@ find_lowerable_rvalues_visitor::can_lower_type(const glsl_type *type) const
     */
    case GLSL_TYPE_BOOL:
    case GLSL_TYPE_SAMPLER:
+   case GLSL_TYPE_IMAGE:
       return true;
 
    case GLSL_TYPE_FLOAT:
@@ -416,6 +417,38 @@ static bool
 is_lowerable_builtin(ir_call *ir,
                      const struct set *lowerable_rvalues)
 {
+   /* The intrinsic call is inside the wrapper imageLoad function that will
+    * be inlined. We have to handle both of them.
+    */
+   if (ir->callee->intrinsic_id == ir_intrinsic_image_load ||
+       (ir->callee->is_builtin() &&
+        !strcmp(ir->callee_name(), "imageLoad"))) {
+      ir_rvalue *param = (ir_rvalue*)ir->actual_parameters.get_head();
+      ir_variable *resource = param->variable_referenced();
+
+      assert(ir->callee->return_precision == GLSL_PRECISION_NONE);
+      assert(resource->type->without_array()->is_image());
+
+      /* GLSL ES 3.20 requires that images have a precision modifier, but if
+       * you set one, it doesn't do anything, because all intrinsics are
+       * defined with highp. This seems to be a spec bug.
+       *
+       * In theory we could set the return value to mediump if the image
+       * format has a lower precision. This appears to be the most sensible
+       * thing to do.
+       */
+      const struct util_format_description *desc =
+         util_format_description(resource->data.image_format);
+      unsigned i =
+         util_format_get_first_non_void_channel(resource->data.image_format);
+
+      if (desc->channel[i].pure_integer ||
+          desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT)
+         return desc->channel[i].size <= 16;
+      else
+         return desc->channel[i].size <= 10; /* unorm/snorm */
+   }
+
    if (!ir->callee->is_builtin())
       return false;
 
@@ -728,17 +761,28 @@ find_precision_visitor::visit_enter(ir_call *ir)
 {
    ir_rvalue_enter_visitor::visit_enter(ir);
 
+   ir_variable *return_var =
+      ir->return_deref ? ir->return_deref->variable_referenced() : NULL;
+
+   /* Don't do anything for image_load here. We have only changed the return
+    * value to mediump/lowp, so that following instructions can use reduced
+    * precision.
+    *
+    * The return value type of the intrinsic itself isn't changed here, but
+    * can be changed in NIR if all users use the *2*mp opcode.
+    */
+   if (ir->callee->intrinsic_id == ir_intrinsic_image_load)
+      return visit_continue;
+
    /* If this is a call to a builtin and the find_lowerable_rvalues_visitor
     * overrode the precision of the temporary return variable, then we can
     * replace the builtin implementation with a lowered version.
     */
 
    if (!ir->callee->is_builtin() ||
-       ir->return_deref == NULL ||
-       (ir->return_deref->variable_referenced()->data.precision !=
-        GLSL_PRECISION_MEDIUM &&
-        ir->return_deref->variable_referenced()->data.precision !=
-        GLSL_PRECISION_LOW))
+       return_var == NULL ||
+       (return_var->data.precision != GLSL_PRECISION_MEDIUM &&
+        return_var->data.precision != GLSL_PRECISION_LOW))
       return visit_continue;
 
    ir->callee = map_builtin(ir->callee);
index 3626d8d2a4b71dd8b62bc8c9e8af4e41eda3b6b3..45175262878f4061d5af25d1693b46ee7abff284 100644 (file)
@@ -971,6 +971,78 @@ TESTS = [
          }
          """,
          r'\(expression +u16vec4 +/.*\(tex +u16vec4 +'),
+    Test("f32 image array",
+         """
+         #version 320 es
+         precision mediump float;
+
+         layout(rgba16f) readonly uniform mediump image2D img[2];
+         // highp shouldn't affect the return value of imageLoad
+         uniform highp ivec2 coord;
+         uniform float divisor;
+
+         out highp vec4 color;
+
+         void main()
+         {
+                 color = imageLoad(img[1], coord) / divisor;
+         }
+         """,
+         r'\(expression +f16vec4 +/'),
+    Test("f32 image load",
+         """
+         #version 310 es
+         precision mediump float;
+         precision mediump int;
+
+         layout(rgba16f) readonly uniform mediump image2D img;
+         uniform ivec2 coord;
+         uniform float divisor;
+
+         out highp vec4 color;
+
+         void main()
+         {
+                 color = imageLoad(img, coord) / divisor;
+         }
+         """,
+         r'\(expression +f16vec4 +/'),
+    Test("i32 image load",
+         """
+         #version 310 es
+         precision mediump float;
+         precision mediump int;
+
+         layout(rgba16i) readonly uniform mediump iimage2D img;
+         uniform ivec2 coord;
+         uniform int divisor;
+
+         out highp ivec4 color;
+
+         void main()
+         {
+                 color = imageLoad(img, coord) / divisor;
+         }
+         """,
+         r'\(expression +i16vec4 +/'),
+    Test("u32 image load",
+         """
+         #version 310 es
+         precision mediump float;
+         precision mediump int;
+
+         layout(rgba16ui) readonly uniform mediump uimage2D img;
+         uniform ivec2 coord;
+         uniform uint divisor;
+
+         out highp uvec4 color;
+
+         void main()
+         {
+                 color = imageLoad(img, coord) / divisor;
+         }
+         """,
+         r'\(expression +u16vec4 +/'),
     Test("f32 expression in lvalue",
          """
          uniform mediump float a, b;