glsl: add sparse texture image load builtin functions
authorQiang Yu <yuq825@gmail.com>
Fri, 24 Dec 2021 08:59:10 +0000 (16:59 +0800)
committerQiang Yu <yuq825@gmail.com>
Tue, 18 Jan 2022 08:10:35 +0000 (16:10 +0800)
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14362>

src/compiler/glsl/builtin_functions.cpp
src/compiler/glsl/ir.h
src/mesa/state_tracker/st_glsl_to_tgsi.cpp

index 6702bad..f7937d0 100644 (file)
@@ -935,6 +935,13 @@ texture_multisample_array_and_sparse(const _mesa_glsl_parse_state *state)
       state->ARB_sparse_texture2_enable;
 }
 
+static bool
+shader_image_load_store_and_sparse(const _mesa_glsl_parse_state *state)
+{
+   return shader_image_load_store(state) &&
+      state->ARB_sparse_texture2_enable;
+}
+
 /** @} */
 
 /******************************************************************************/
@@ -1337,6 +1344,7 @@ enum image_function_flags {
    IMAGE_FUNCTION_AVAIL_ATOMIC_ADD = (1 << 9),
    IMAGE_FUNCTION_EXT_ONLY = (1 << 10),
    IMAGE_FUNCTION_SUPPORTS_SIGNED_DATA_TYPE = (1 << 11),
+   IMAGE_FUNCTION_SPARSE = (1 << 12),
 };
 
 } /* anonymous namespace */
@@ -5156,6 +5164,18 @@ builtin_builder::add_image_function(const char *name,
          continue;
       if ((types[i]->sampler_dimensionality != GLSL_SAMPLER_DIM_MS) && (flags & IMAGE_FUNCTION_MS_ONLY))
          continue;
+      if (flags & IMAGE_FUNCTION_SPARSE) {
+         switch (types[i]->sampler_dimensionality) {
+         case GLSL_SAMPLER_DIM_2D:
+         case GLSL_SAMPLER_DIM_3D:
+         case GLSL_SAMPLER_DIM_CUBE:
+         case GLSL_SAMPLER_DIM_RECT:
+         case GLSL_SAMPLER_DIM_MS:
+            break;
+         default:
+            continue;
+         }
+      }
       f->add_signature(_image(prototype, types[i], intrinsic_name,
                               num_arguments, flags, intrinsic_id));
    }
@@ -5268,6 +5288,17 @@ builtin_builder::add_image_functions(bool glsl)
                       &builtin_builder::_image_prototype, 1,
                       (atom_flags | IMAGE_FUNCTION_EXT_ONLY),
                       ir_intrinsic_image_atomic_dec_wrap);
+
+   /* ARB_sparse_texture2 */
+   add_image_function(glsl ? "sparseImageLoadARB" : "__intrinsic_image_sparse_load",
+                      "__intrinsic_image_sparse_load",
+                      &builtin_builder::_image_prototype, 0,
+                      (flags | IMAGE_FUNCTION_HAS_VECTOR_DATA_TYPE |
+                       IMAGE_FUNCTION_SUPPORTS_FLOAT_DATA_TYPE |
+                       IMAGE_FUNCTION_SUPPORTS_SIGNED_DATA_TYPE |
+                       IMAGE_FUNCTION_READ_ONLY |
+                       IMAGE_FUNCTION_SPARSE),
+                      ir_intrinsic_image_sparse_load);
 }
 
 ir_variable *
@@ -7869,6 +7900,9 @@ get_image_available_predicate(const glsl_type *type, unsigned flags)
    else if (flags & IMAGE_FUNCTION_EXT_ONLY)
       return shader_image_load_store_ext;
 
+   else if (flags & IMAGE_FUNCTION_SPARSE)
+      return shader_image_load_store_and_sparse;
+
    else
       return shader_image_load_store;
 }
@@ -7882,8 +7916,23 @@ builtin_builder::_image_prototype(const glsl_type *image_type,
       image_type->sampled_type,
       (flags & IMAGE_FUNCTION_HAS_VECTOR_DATA_TYPE ? 4 : 1),
       1);
-   const glsl_type *ret_type = (flags & IMAGE_FUNCTION_RETURNS_VOID ?
-                                glsl_type::void_type : data_type);
+
+   const glsl_type *ret_type;
+   if (flags & IMAGE_FUNCTION_RETURNS_VOID)
+      ret_type = glsl_type::void_type;
+   else if (flags & IMAGE_FUNCTION_SPARSE) {
+      if (flags & IMAGE_FUNCTION_EMIT_STUB)
+         ret_type = glsl_type::int_type;
+      else {
+         /* code holds residency info */
+         glsl_struct_field fields[2] = {
+            glsl_struct_field(glsl_type::int_type, "code"),
+            glsl_struct_field(data_type, "texel"),
+         };
+         ret_type = glsl_type::get_struct_instance(fields, 2, "struct");
+      }
+   } else
+      ret_type = data_type;
 
    /* Addressing arguments that are always present. */
    ir_variable *image = in_var(image_type, "image");
@@ -8003,6 +8052,25 @@ builtin_builder::_image(image_prototype_ctr prototype,
 
       if (flags & IMAGE_FUNCTION_RETURNS_VOID) {
          body.emit(call(f, NULL, sig->parameters));
+      } else if (flags & IMAGE_FUNCTION_SPARSE) {
+         ir_function_signature *intr_sig =
+            f->exact_matching_signature(NULL, &sig->parameters);
+         assert(intr_sig);
+
+         ir_variable *ret_val = body.make_temp(intr_sig->return_type, "_ret_val");
+         ir_dereference_record *texel_field = record_ref(ret_val, "texel");
+         ir_variable *texel = out_var(texel_field->type, "texel");
+
+         /* Add texel param to builtin function after call intrinsic function
+          * because they have different prototype:
+          *   struct {int code; gvec4 texel;} __intrinsic_image_sparse_load(in)
+          *   int sparseImageLoad(in, out texel)
+          */
+         body.emit(call(f, ret_val, sig->parameters));
+         sig->parameters.push_tail(texel);
+
+         body.emit(assign(texel, texel_field));
+         body.emit(ret(record_ref(ret_val, "code")));
       } else {
          ir_variable *ret_val =
             body.make_temp(sig->return_type, "_ret_val");
index de61e14..47b5000 100644 (file)
@@ -1132,6 +1132,7 @@ enum ir_intrinsic_id {
    ir_intrinsic_image_samples,
    ir_intrinsic_image_atomic_inc_wrap,
    ir_intrinsic_image_atomic_dec_wrap,
+   ir_intrinsic_image_sparse_load,
 
    ir_intrinsic_ssbo_load,
    ir_intrinsic_ssbo_store = MAKE_INTRINSIC_FOR_TYPE(store, ssbo),
index 0cf4de5..0996bbe 100644 (file)
@@ -4347,6 +4347,7 @@ glsl_to_tgsi_visitor::visit(ir_call *ir)
    case ir_intrinsic_generic_atomic_comp_swap:
    case ir_intrinsic_begin_invocation_interlock:
    case ir_intrinsic_end_invocation_interlock:
+   case ir_intrinsic_image_sparse_load:
       unreachable("Invalid intrinsic");
    }
 }