[Mesa-dev] [PATCH 5/5] spirv: Make images, samplers, and sampled images normal SSA values

Jason Ekstrand jason at jlekstrand.net
Sat Sep 22 21:39:22 UTC 2018


Instead of treating image, sampler, and combined image sampler SSA
values as pointers and special-casing them various places, we now allow
them to be part of regular SSA values.  Among other things, this means
that composites of opaque types should now work correctly.
---
 src/compiler/spirv/spirv_to_nir.c  | 53 ++++++++++------------
 src/compiler/spirv/vtn_cfg.c       | 70 +++++++++++++++---------------
 src/compiler/spirv/vtn_private.h   |  7 ++-
 src/compiler/spirv/vtn_variables.c | 51 ++++++++++------------
 4 files changed, 86 insertions(+), 95 deletions(-)

diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c
index 2ad83196e46..b6e9d9fe11a 100644
--- a/src/compiler/spirv/spirv_to_nir.c
+++ b/src/compiler/spirv/spirv_to_nir.c
@@ -1860,25 +1860,19 @@ vtn_handle_texture(struct vtn_builder *b, SpvOp opcode,
                    const uint32_t *w, unsigned count)
 {
    if (opcode == SpvOpSampledImage) {
-      struct vtn_value *val =
-         vtn_push_value(b, w[2], vtn_value_type_sampled_image);
-      val->sampled_image = ralloc(b, struct vtn_sampled_image);
-      val->sampled_image->type =
-         vtn_value(b, w[1], vtn_value_type_type)->type;
-      val->sampled_image->image =
-         vtn_value(b, w[3], vtn_value_type_pointer)->pointer;
-      val->sampled_image->sampler =
-         vtn_value(b, w[4], vtn_value_type_pointer)->pointer;
+      struct vtn_type *res_type = vtn_value(b, w[1], vtn_value_type_type)->type;
+      struct vtn_ssa_value *ssa = vtn_create_ssa_value(b, res_type->type);
+      ssa->sampled_image = ralloc(b, struct vtn_sampled_image);
+      ssa->sampled_image->type = res_type;
+      ssa->sampled_image->image = vtn_ssa_value(b, w[3])->image;
+      ssa->sampled_image->sampler = vtn_ssa_value(b, w[4])->sampler;
+      vtn_push_ssa(b, w[2], res_type, ssa);
       return;
    } else if (opcode == SpvOpImage) {
-      struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_pointer);
-      struct vtn_value *src_val = vtn_untyped_value(b, w[3]);
-      if (src_val->value_type == vtn_value_type_sampled_image) {
-         val->pointer = src_val->sampled_image->image;
-      } else {
-         vtn_assert(src_val->value_type == vtn_value_type_pointer);
-         val->pointer = src_val->pointer;
-      }
+      struct vtn_type *res_type = vtn_value(b, w[1], vtn_value_type_type)->type;
+      struct vtn_ssa_value *ssa = vtn_create_ssa_value(b, res_type->type);
+      ssa->image = vtn_ssa_value(b, w[3])->sampled_image->image;
+      vtn_push_ssa(b, w[2], res_type, ssa);
       return;
    }
 
@@ -1886,14 +1880,14 @@ vtn_handle_texture(struct vtn_builder *b, SpvOp opcode,
    struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
 
    struct vtn_sampled_image sampled;
-   struct vtn_value *sampled_val = vtn_untyped_value(b, w[3]);
-   if (sampled_val->value_type == vtn_value_type_sampled_image) {
-      sampled = *sampled_val->sampled_image;
+   struct vtn_value *sampled_val = vtn_value(b, w[3], vtn_value_type_ssa);
+   if (sampled_val->type->base_type == vtn_base_type_sampled_image) {
+      sampled = *sampled_val->ssa->sampled_image;
    } else {
-      vtn_assert(sampled_val->value_type == vtn_value_type_pointer);
-      sampled.type = sampled_val->pointer->type;
+      vtn_assert(sampled_val->type->base_type == vtn_base_type_image);
+      sampled.type = sampled_val->type;
       sampled.image = NULL;
-      sampled.sampler = sampled_val->pointer;
+      sampled.sampler = sampled_val->ssa->image;
    }
 
    const struct glsl_type *image_type = sampled.type->type;
@@ -2319,13 +2313,13 @@ vtn_handle_image(struct vtn_builder *b, SpvOp opcode,
       break;
 
    case SpvOpImageQuerySize:
-      image.image = vtn_value(b, w[3], vtn_value_type_pointer)->pointer;
+      image.image = vtn_ssa_value(b, w[3])->image;
       image.coord = NULL;
       image.sample = NULL;
       break;
 
    case SpvOpImageRead:
-      image.image = vtn_value(b, w[3], vtn_value_type_pointer)->pointer;
+      image.image = vtn_ssa_value(b, w[3])->image;
       image.coord = get_image_coord(b, w[4]);
 
       if (count > 5 && (w[5] & SpvImageOperandsSampleMask)) {
@@ -2337,7 +2331,7 @@ vtn_handle_image(struct vtn_builder *b, SpvOp opcode,
       break;
 
    case SpvOpImageWrite:
-      image.image = vtn_value(b, w[1], vtn_value_type_pointer)->pointer;
+      image.image = vtn_ssa_value(b, w[1])->image;
       image.coord = get_image_coord(b, w[2]);
 
       /* texel = w[3] */
@@ -3836,12 +3830,11 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
       break;
 
    case SpvOpImageQuerySize: {
-      struct vtn_pointer *image =
-         vtn_value(b, w[3], vtn_value_type_pointer)->pointer;
-      if (glsl_type_is_image(image->type->type)) {
+      struct vtn_value *val = vtn_value(b, w[3], vtn_value_type_ssa);
+      if (glsl_type_is_image(val->type->type)) {
          vtn_handle_image(b, opcode, w, count);
       } else {
-         vtn_assert(glsl_type_is_sampler(image->type->type));
+         vtn_assert(glsl_type_is_sampler(val->type->type));
          vtn_handle_texture(b, opcode, w, count);
       }
       break;
diff --git a/src/compiler/spirv/vtn_cfg.c b/src/compiler/spirv/vtn_cfg.c
index 1020b2722f4..747f6d40694 100644
--- a/src/compiler/spirv/vtn_cfg.c
+++ b/src/compiler/spirv/vtn_cfg.c
@@ -138,6 +138,19 @@ vtn_ssa_value_add_to_call_params(struct vtn_builder *b,
       }
       break;
 
+   case vtn_base_type_sampled_image:
+      call->params[(*param_idx)++] =
+         nir_src_for_ssa(vtn_pointer_to_ssa(b, value->sampled_image->image));
+      call->params[(*param_idx)++] =
+         nir_src_for_ssa(vtn_pointer_to_ssa(b, value->sampled_image->sampler));
+      break;
+
+   case vtn_base_type_image:
+   case vtn_base_type_sampler:
+      call->params[(*param_idx)++] =
+         nir_src_for_ssa(vtn_pointer_to_ssa(b, value->image));
+      break;
+
    default:
       call->params[(*param_idx)++] = nir_src_for_ssa(value->def);
       break;
@@ -165,6 +178,26 @@ vtn_ssa_value_load_function_param(struct vtn_builder *b,
       }
       break;
 
+   case vtn_base_type_sampled_image: {
+      value->sampled_image = ralloc(b, struct vtn_sampled_image);
+      value->sampled_image->type = type;
+
+      struct vtn_type *sampler_type = rzalloc(b, struct vtn_type);
+      sampler_type->base_type = vtn_base_type_sampler;
+      sampler_type->type = glsl_bare_sampler_type();
+
+      value->sampled_image->image =
+         vtn_load_param_pointer(b, type, (*param_idx)++);
+      value->sampled_image->sampler =
+         vtn_load_param_pointer(b, sampler_type, (*param_idx)++);
+      break;
+   }
+
+   case vtn_base_type_image:
+   case vtn_base_type_sampler:
+      value->image = vtn_load_param_pointer(b, type, (*param_idx)++);
+      break;
+
    default:
       value->def = nir_load_param(&b->nb, b->func_param_idx++);
       break;
@@ -199,17 +232,7 @@ vtn_handle_function_call(struct vtn_builder *b, SpvOp opcode,
       struct vtn_type *arg_type = vtn_callee->type->params[i];
       unsigned arg_id = w[4 + i];
 
-      if (arg_type->base_type == vtn_base_type_sampled_image) {
-         struct vtn_sampled_image *sampled_image =
-            vtn_value(b, arg_id, vtn_value_type_sampled_image)->sampled_image;
-
-         call->params[param_idx++] =
-            nir_src_for_ssa(&sampled_image->image->deref->dest.ssa);
-         call->params[param_idx++] =
-            nir_src_for_ssa(&sampled_image->sampler->deref->dest.ssa);
-      } else if (arg_type->base_type == vtn_base_type_pointer ||
-                 arg_type->base_type == vtn_base_type_image ||
-                 arg_type->base_type == vtn_base_type_sampler) {
+      if (arg_type->base_type == vtn_base_type_pointer) {
          struct vtn_pointer *pointer =
             vtn_value(b, arg_id, vtn_value_type_pointer)->pointer;
          call->params[param_idx++] =
@@ -300,34 +323,13 @@ vtn_cfg_handle_prepass_instruction(struct vtn_builder *b, SpvOp opcode,
 
       vtn_assert(b->func_param_idx < b->func->impl->function->num_params);
 
-      if (type->base_type == vtn_base_type_sampled_image) {
-         /* Sampled images are actually two parameters.  The first is the
-          * image and the second is the sampler.
-          */
-         struct vtn_value *val =
-            vtn_push_value(b, w[2], vtn_value_type_sampled_image);
-
-         val->sampled_image = ralloc(b, struct vtn_sampled_image);
-         val->sampled_image->type = type;
-
-         struct vtn_type *sampler_type = rzalloc(b, struct vtn_type);
-         sampler_type->base_type = vtn_base_type_sampler;
-         sampler_type->type = glsl_bare_sampler_type();
-
-         val->sampled_image->image =
-            vtn_load_param_pointer(b, type, b->func_param_idx++);
-         val->sampled_image->sampler =
-            vtn_load_param_pointer(b, sampler_type, b->func_param_idx++);
-      } else if (type->base_type == vtn_base_type_pointer &&
-                 type->type != NULL) {
+      if (type->base_type == vtn_base_type_pointer && type->type != NULL) {
          /* This is a pointer with an actual storage type */
          struct vtn_value *val =
             vtn_push_value(b, w[2], vtn_value_type_pointer);
          nir_ssa_def *ssa_ptr = nir_load_param(&b->nb, b->func_param_idx++);
          val->pointer = vtn_pointer_from_ssa(b, ssa_ptr, type);
-      } else if (type->base_type == vtn_base_type_pointer ||
-                 type->base_type == vtn_base_type_image ||
-                 type->base_type == vtn_base_type_sampler) {
+      } else if (type->base_type == vtn_base_type_pointer) {
          struct vtn_value *val =
             vtn_push_value(b, w[2], vtn_value_type_pointer);
          val->pointer =
diff --git a/src/compiler/spirv/vtn_private.h b/src/compiler/spirv/vtn_private.h
index a31202d1295..46575469744 100644
--- a/src/compiler/spirv/vtn_private.h
+++ b/src/compiler/spirv/vtn_private.h
@@ -112,7 +112,6 @@ enum vtn_value_type {
    vtn_value_type_ssa,
    vtn_value_type_extension,
    vtn_value_type_image_pointer,
-   vtn_value_type_sampled_image,
 };
 
 enum vtn_branch_type {
@@ -250,9 +249,14 @@ const uint32_t *
 vtn_foreach_instruction(struct vtn_builder *b, const uint32_t *start,
                         const uint32_t *end, vtn_instruction_handler handler);
 
+struct vtn_pointer;
+
 struct vtn_ssa_value {
    union {
       nir_ssa_def *def;
+      struct vtn_sampled_image *sampled_image;
+      struct vtn_pointer *image;
+      struct vtn_pointer *sampler;
       struct vtn_ssa_value **elems;
    };
 
@@ -513,7 +517,6 @@ struct vtn_value {
       nir_constant *constant;
       struct vtn_pointer *pointer;
       struct vtn_image_pointer *image;
-      struct vtn_sampled_image *sampled_image;
       struct vtn_function *func;
       struct vtn_block *block;
       struct vtn_ssa_value *ssa;
diff --git a/src/compiler/spirv/vtn_variables.c b/src/compiler/spirv/vtn_variables.c
index 358ff4bef7a..9ec35fa8380 100644
--- a/src/compiler/spirv/vtn_variables.c
+++ b/src/compiler/spirv/vtn_variables.c
@@ -868,6 +868,22 @@ _vtn_variable_load_store(struct vtn_builder *b, bool load,
       }
       return;
 
+   case GLSL_TYPE_SAMPLER:
+   case GLSL_TYPE_IMAGE:
+      vtn_fail_if(!load, "Attempted to store to an image or sampler");
+      (*inout) = vtn_create_ssa_value(b, ptr->type->type);
+      if (ptr->type->base_type == vtn_base_type_sampled_image) {
+         (*inout)->sampled_image = ralloc(b, struct vtn_sampled_image);
+         (*inout)->sampled_image->type = ptr->type;
+         (*inout)->sampled_image->image = ptr;
+         (*inout)->sampled_image->sampler = ptr;
+      } else {
+         assert(ptr->type->base_type == vtn_base_type_image ||
+                ptr->type->base_type == vtn_base_type_sampler);
+         (*inout)->image = ptr;
+      }
+      return;
+
    case GLSL_TYPE_ARRAY:
    case GLSL_TYPE_STRUCT: {
       unsigned elems = glsl_get_length(ptr->type->type);
@@ -1895,29 +1911,12 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
       }
 
       struct vtn_type *ptr_type = vtn_value(b, w[1], vtn_value_type_type)->type;
-      struct vtn_value *base_val = vtn_untyped_value(b, w[3]);
-      if (base_val->value_type == vtn_value_type_sampled_image) {
-         /* This is rather insane.  SPIR-V allows you to use OpSampledImage
-          * to combine an array of images with a single sampler to get an
-          * array of sampled images that all share the same sampler.
-          * Fortunately, this means that we can more-or-less ignore the
-          * sampler when crawling the access chain, but it does leave us
-          * with this rather awkward little special-case.
-          */
-         struct vtn_value *val =
-            vtn_push_value(b, w[2], vtn_value_type_sampled_image);
-         val->sampled_image = ralloc(b, struct vtn_sampled_image);
-         val->sampled_image->type = base_val->sampled_image->type;
-         val->sampled_image->image =
-            vtn_pointer_dereference(b, base_val->sampled_image->image, chain);
-         val->sampled_image->sampler = base_val->sampled_image->sampler;
-      } else {
-         vtn_assert(base_val->value_type == vtn_value_type_pointer);
-         struct vtn_value *val =
-            vtn_push_value(b, w[2], vtn_value_type_pointer);
-         val->pointer = vtn_pointer_dereference(b, base_val->pointer, chain);
-         val->pointer->ptr_type = ptr_type;
-      }
+      struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_pointer);
+      struct vtn_pointer *base =
+         vtn_value(b, w[3], vtn_value_type_pointer)->pointer;
+
+      val->pointer = vtn_pointer_dereference(b, base, chain);
+      val->pointer->ptr_type = ptr_type;
       break;
    }
 
@@ -1939,12 +1938,6 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
 
       vtn_assert_types_equal(b, opcode, res_type, src_val->type->deref);
 
-      if (glsl_type_is_image(res_type->type) ||
-          glsl_type_is_sampler(res_type->type)) {
-         vtn_push_value(b, w[2], vtn_value_type_pointer)->pointer = src;
-         return;
-      }
-
       vtn_push_ssa(b, w[2], res_type, vtn_variable_load(b, src));
       break;
    }
-- 
2.17.1



More information about the mesa-dev mailing list