dzn: Add a helper to generate triangle->point GS
authorJesse Natalie <jenatali@microsoft.com>
Mon, 3 Apr 2023 22:17:45 +0000 (15:17 -0700)
committerMarge Bot <emma+marge@anholt.net>
Tue, 4 Apr 2023 21:48:19 +0000 (21:48 +0000)
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22277>

src/microsoft/vulkan/dzn_nir.c
src/microsoft/vulkan/dzn_nir.h

index 9c15262..0c2b316 100644 (file)
@@ -26,6 +26,7 @@
 #include "spirv_to_dxil.h"
 #include "nir_to_dxil.h"
 #include "nir_builder.h"
+#include "nir_builtin_builder.h"
 #include "nir_vulkan.h"
 
 static nir_ssa_def *
@@ -748,3 +749,153 @@ dzn_nir_blit_fs(const struct dzn_nir_blit_info *info)
 
    return b.shader;
 }
+
+static nir_ssa_def *
+cull_face(nir_builder *b, nir_variable *vertices, bool ccw)
+{
+   nir_ssa_def *v0 =
+      nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 0)));
+   nir_ssa_def *v1 =
+      nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 1)));
+   nir_ssa_def *v2 =
+      nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 2)));
+
+   nir_ssa_def *dir = nir_fdot(b, nir_cross4(b, nir_fsub(b, v1, v0),
+                                                nir_fsub(b, v2, v0)),
+                               nir_imm_vec4(b, 0.0, 0.0, -1.0, 0.0));
+   if (ccw)
+      return nir_fge(b, nir_imm_int(b, 0), dir);
+   else
+      return nir_flt(b, nir_imm_int(b, 0), dir);
+}
+
+static void
+copy_vars(nir_builder *b, nir_deref_instr *dst, nir_deref_instr *src)
+{
+   assert(glsl_get_bare_type(dst->type) == glsl_get_bare_type(src->type));
+   if (glsl_type_is_struct(dst->type)) {
+      for (unsigned i = 0; i < glsl_get_length(dst->type); ++i) {
+         copy_vars(b, nir_build_deref_struct(b, dst, i), nir_build_deref_struct(b, src, i));
+      }
+   } else if (glsl_type_is_array_or_matrix(dst->type)) {
+      copy_vars(b, nir_build_deref_array_wildcard(b, dst), nir_build_deref_array_wildcard(b, src));
+   } else {
+      nir_copy_deref(b, dst, src);
+   }
+}
+
+nir_shader *
+dzn_nir_polygon_point_mode_gs(const nir_shader *previous_shader, unsigned cull_mode, bool front_ccw)
+{
+   nir_builder builder;
+   nir_builder *b = &builder;
+   nir_variable *pos_var = NULL;
+
+   unsigned num_vars = 0;
+   nir_variable *in[VARYING_SLOT_MAX];
+   nir_variable *out[VARYING_SLOT_MAX];
+
+
+   builder = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY,
+                                            dxil_get_nir_compiler_options(),
+                                            "implicit_gs");
+
+   nir_shader *nir = b->shader;
+   nir->info.inputs_read = nir->info.outputs_written = previous_shader->info.outputs_written;
+   nir->info.outputs_written |= (1ull << VARYING_SLOT_VAR12);
+   nir->info.gs.input_primitive = PIPE_PRIM_TRIANGLES;
+   nir->info.gs.output_primitive = PIPE_PRIM_POINTS;
+   nir->info.gs.vertices_in = 3;
+   nir->info.gs.vertices_out = 3;
+   nir->info.gs.invocations = 1;
+   nir->info.gs.active_stream_mask = 1;
+
+   nir_foreach_shader_out_variable(var, previous_shader) {
+      char tmp[100];
+      snprintf(tmp, ARRAY_SIZE(tmp), "in_%d", num_vars);
+      in[num_vars] = nir_variable_create(nir,
+                                         nir_var_shader_in,
+                                         glsl_array_type(var->type, 3, 0),
+                                         tmp);
+      in[num_vars]->data = var->data;
+      in[num_vars]->data.mode = nir_var_shader_in;
+
+      if (var->data.location == VARYING_SLOT_POS)
+         pos_var = in[num_vars];
+
+      snprintf(tmp, ARRAY_SIZE(tmp), "out_%d", num_vars);
+      out[num_vars] = nir_variable_create(nir, nir_var_shader_out, var->type, tmp);
+      out[num_vars]->data = var->data;
+
+      num_vars++;
+   }
+
+   nir_variable *front_facing_var = nir_variable_create(nir,
+                                                        nir_var_shader_out,
+                                                        glsl_uint_type(),
+                                                        "gl_FrontFacing");
+   front_facing_var->data.location = VARYING_SLOT_VAR12;
+   front_facing_var->data.driver_location = num_vars;
+   front_facing_var->data.interpolation = INTERP_MODE_FLAT;
+
+   /* Temporary variable "loop_index" to loop over input vertices */
+   nir_function_impl *impl = nir_shader_get_entrypoint(nir);
+   nir_variable *loop_index_var =
+      nir_local_variable_create(impl, glsl_uint_type(), "loop_index");
+   nir_deref_instr *loop_index_deref = nir_build_deref_var(b, loop_index_var);
+   nir_store_deref(b, loop_index_deref, nir_imm_int(b, 0), 1);
+
+   nir_ssa_def *cull_pass = nir_imm_bool(b, true);
+   nir_ssa_def *front_facing;
+   assert(cull_mode != VK_CULL_MODE_FRONT_AND_BACK);
+   if (cull_mode == VK_CULL_MODE_FRONT_BIT) {
+      cull_pass = cull_face(b, pos_var, front_ccw);
+      front_facing = nir_b2i32(b, cull_pass);
+   } else if (cull_mode == VK_CULL_MODE_BACK_BIT) {
+      cull_pass = cull_face(b, pos_var, !front_ccw);
+      front_facing = nir_inot(b, nir_b2i32(b, cull_pass));
+   } else
+      front_facing = nir_i2i32(b, cull_face(b, pos_var, front_ccw));
+
+   /**
+    *  if (cull_pass) {
+    *     while {
+    *        if (loop_index >= 3)
+    *           break;
+    */
+   nir_if *cull_check = nir_push_if(b, cull_pass);
+   nir_loop *loop = nir_push_loop(b);
+
+   nir_ssa_def *loop_index = nir_load_deref(b, loop_index_deref);
+   nir_ssa_def *cmp = nir_ige(b, loop_index,
+                              nir_imm_int(b, 3));
+   nir_if *loop_check = nir_push_if(b, cmp);
+   nir_jump(b, nir_jump_break);
+   nir_pop_if(b, loop_check);
+
+   /**
+    *        [...] // Copy all variables
+    *        EmitVertex();
+    */
+   for (unsigned i = 0; i < num_vars; ++i) {
+      nir_ssa_def *index = loop_index;
+      nir_deref_instr *in_value = nir_build_deref_array(b, nir_build_deref_var(b, in[i]), index);
+      copy_vars(b, nir_build_deref_var(b, out[i]), in_value);
+   }
+   nir_store_var(b, front_facing_var, front_facing, 0x1);
+   nir_emit_vertex(b, 0);
+
+   /**
+    *        loop_index++;
+    *     }
+    *  }
+    */
+   nir_store_deref(b, loop_index_deref, nir_iadd_imm(b, loop_index, 1), 1);
+   nir_pop_loop(b, loop);
+   nir_pop_if(b, cull_check);
+
+   nir_validate_shader(nir, "in dzn_nir_polygon_point_mode_gs");
+
+   NIR_PASS_V(nir, nir_lower_var_copies);
+   return b->shader;
+}
index a6e4383..881d8e1 100644 (file)
@@ -158,4 +158,7 @@ dzn_nir_blit_vs(void);
 nir_shader *
 dzn_nir_blit_fs(const struct dzn_nir_blit_info *info);
 
+nir_shader *
+dzn_nir_polygon_point_mode_gs(const nir_shader *vs, unsigned cull_mode, bool front_ccw);
+
 #endif