vulkan/meta: Insert a geometry shader when needed
authorFaith Ekstrand <faith.ekstrand@collabora.com>
Fri, 31 Mar 2023 16:44:09 +0000 (11:44 -0500)
committerMarge Bot <emma+marge@anholt.net>
Fri, 4 Aug 2023 21:32:03 +0000 (21:32 +0000)
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24326>

src/vulkan/runtime/vk_meta.c
src/vulkan/runtime/vk_meta.h
src/vulkan/runtime/vk_meta_draw_rects.c
src/vulkan/runtime/vk_meta_private.h

index a6ccbf6..bcdc869 100644 (file)
@@ -276,24 +276,46 @@ create_rect_list_pipeline(struct vk_device *device,
 
    VkGraphicsPipelineCreateInfo info_local = *info;
 
-   STACK_ARRAY(VkPipelineShaderStageCreateInfo, stages, info->stageCount + 1);
-   for (uint32_t i = 0; i < info->stageCount; i++) {
-      assert(info->pStages[i].stage != VK_SHADER_STAGE_VERTEX_BIT);
-      stages[i + 1] = info->pStages[i];
-   }
+   /* We always configure for layered rendering for now */
+   bool use_gs = meta->use_gs_for_layer;
+
+   STACK_ARRAY(VkPipelineShaderStageCreateInfo, stages,
+               info->stageCount + 1 + use_gs);
+   uint32_t stage_count = 0;
 
    VkPipelineShaderStageNirCreateInfoMESA vs_nir_info = {
       .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_NIR_CREATE_INFO_MESA,
-      .nir = vk_meta_draw_rects_vs_nir(meta),
+      .nir = vk_meta_draw_rects_vs_nir(meta, use_gs),
    };
-   stages[0] = (VkPipelineShaderStageCreateInfo) {
+   stages[stage_count++] = (VkPipelineShaderStageCreateInfo) {
       .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
       .pNext = &vs_nir_info,
       .stage = VK_SHADER_STAGE_VERTEX_BIT,
       .pName = "main",
    };
 
-   info_local.stageCount = info->stageCount + 1;
+   VkPipelineShaderStageNirCreateInfoMESA gs_nir_info;
+   if (use_gs) {
+      gs_nir_info = (VkPipelineShaderStageNirCreateInfoMESA) {
+         .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_NIR_CREATE_INFO_MESA,
+         .nir = vk_meta_draw_rects_gs_nir(meta),
+      };
+      stages[stage_count++] = (VkPipelineShaderStageCreateInfo) {
+         .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+         .pNext = &gs_nir_info,
+         .stage = VK_SHADER_STAGE_GEOMETRY_BIT,
+         .pName = "main",
+      };
+   }
+
+   for (uint32_t i = 0; i < info->stageCount; i++) {
+      assert(info->pStages[i].stage != VK_SHADER_STAGE_VERTEX_BIT);
+      if (use_gs)
+         assert(info->pStages[i].stage != VK_SHADER_STAGE_GEOMETRY_BIT);
+      stages[stage_count++] = info->pStages[i];
+   }
+
+   info_local.stageCount = stage_count;
    info_local.pStages = stages;
    info_local.pVertexInputState = &vk_meta_draw_rects_vi_state;
    info_local.pViewportState = &vk_meta_draw_rects_vs_state;
index cac550e..da085bc 100644 (file)
@@ -52,6 +52,7 @@ struct vk_meta_device {
 
    uint32_t max_bind_map_buffer_size_B;
    bool use_layered_rendering;
+   bool use_gs_for_layer;
    bool use_stencil_export;
 
    VkResult (*cmd_bind_map_buffer)(struct vk_command_buffer *cmd,
index cba81e8..d0fd7fc 100644 (file)
@@ -59,7 +59,7 @@ const VkPipelineViewportStateCreateInfo vk_meta_draw_rects_vs_state = {
 };
 
 nir_shader *
-vk_meta_draw_rects_vs_nir(struct vk_meta_device *device)
+vk_meta_draw_rects_vs_nir(struct vk_meta_device *device, bool use_gs)
 {
    nir_builder build = nir_builder_init_simple_shader(MESA_SHADER_VERTEX, NULL,
                                                       "vk-meta-draw-rects-vs");
@@ -69,13 +69,15 @@ vk_meta_draw_rects_vs_nir(struct vk_meta_device *device)
                                           glsl_uvec4_type(), "vtx_in");
    in->data.location = VERT_ATTRIB_GENERIC0;
 
-   nir_variable *pos = nir_variable_create(b->shader, nir_var_shader_out,
-                                           glsl_vec4_type(), "gl_Position");
-   pos->data.location = VARYING_SLOT_POS;
+   nir_variable *pos =
+      nir_variable_create(b->shader, nir_var_shader_out, glsl_vec4_type(),
+                          use_gs ? "pos_out" : "gl_Position");
+   pos->data.location = use_gs ? VARYING_SLOT_VAR0 : VARYING_SLOT_POS;
 
-   nir_variable *layer = nir_variable_create(b->shader, nir_var_shader_out,
-                                             glsl_int_type(), "gl_Layer");
-   layer->data.location = VARYING_SLOT_LAYER;
+   nir_variable *layer =
+      nir_variable_create(b->shader, nir_var_shader_out, glsl_int_type(),
+                          use_gs ? "layer_out" : "gl_Layer");
+   layer->data.location = use_gs ? VARYING_SLOT_VAR1 : VARYING_SLOT_LAYER;
 
    nir_ssa_def *vtx = nir_load_var(b, in);
    nir_store_var(b, pos, nir_vec4(b, nir_channel(b, vtx, 0),
@@ -83,6 +85,7 @@ vk_meta_draw_rects_vs_nir(struct vk_meta_device *device)
                                      nir_channel(b, vtx, 2),
                                      nir_imm_float(b, 1)),
                  0xf);
+
    nir_store_var(b, layer, nir_iadd(b, nir_load_instance_id(b),
                                        nir_channel(b, vtx, 3)),
                  0x1);
@@ -90,6 +93,58 @@ vk_meta_draw_rects_vs_nir(struct vk_meta_device *device)
    return b->shader;
 }
 
+nir_shader *
+vk_meta_draw_rects_gs_nir(struct vk_meta_device *device)
+{
+   nir_builder build =
+      nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY, NULL,
+                                     "vk-meta-draw-rects-gs");
+   nir_builder *b = &build;
+
+   nir_variable *pos_in =
+      nir_variable_create(b->shader, nir_var_shader_in,
+                          glsl_array_type(glsl_vec4_type(), 3, 0), "pos_in");
+   pos_in->data.location = VARYING_SLOT_VAR0;
+
+   nir_variable *layer_in =
+      nir_variable_create(b->shader, nir_var_shader_in,
+                          glsl_array_type(glsl_int_type(), 3, 0), "layer_in");
+   layer_in->data.location = VARYING_SLOT_VAR1;
+
+   nir_variable *pos_out =
+      nir_variable_create(b->shader, nir_var_shader_out,
+                          glsl_vec4_type(), "gl_Position");
+   pos_out->data.location = VARYING_SLOT_POS;
+
+   nir_variable *layer_out =
+      nir_variable_create(b->shader, nir_var_shader_out,
+                          glsl_int_type(), "gl_Layer");
+   layer_out->data.location = VARYING_SLOT_LAYER;
+
+   for (unsigned i = 0; i < 3; i++) {
+      nir_deref_instr *pos_in_deref =
+         nir_build_deref_array_imm(b, nir_build_deref_var(b, pos_in), i);
+      nir_deref_instr *layer_in_deref =
+         nir_build_deref_array_imm(b, nir_build_deref_var(b, layer_in), i);
+
+      nir_store_var(b, pos_out, nir_load_deref(b, pos_in_deref), 0xf);
+      nir_store_var(b, layer_out, nir_load_deref(b, layer_in_deref), 1);
+      nir_emit_vertex(b);
+   }
+
+   nir_end_primitive(b);
+
+   struct shader_info *info = &build.shader->info;
+   info->gs.input_primitive = MESA_PRIM_TRIANGLES;
+   info->gs.output_primitive = MESA_PRIM_TRIANGLE_STRIP;
+   info->gs.vertices_in = 3;
+   info->gs.vertices_out = 3;
+   info->gs.invocations = 1;
+   info->gs.active_stream_mask = 1;
+
+   return b->shader;
+}
+
 struct vertex {
    float x, y, z;
    uint32_t layer;
index e83d02f..a8b2a97 100644 (file)
@@ -34,7 +34,11 @@ extern const VkPipelineVertexInputStateCreateInfo vk_meta_draw_rects_vi_state;
 extern const VkPipelineInputAssemblyStateCreateInfo vk_meta_draw_rects_ia_state;
 extern const VkPipelineViewportStateCreateInfo vk_meta_draw_rects_vs_state;
 
-struct nir_shader *vk_meta_draw_rects_vs_nir(struct vk_meta_device *device);
+struct nir_shader *
+vk_meta_draw_rects_vs_nir(struct vk_meta_device *device, bool use_gs);
+
+struct nir_shader *
+vk_meta_draw_rects_gs_nir(struct vk_meta_device *device);
 
 static inline void
 vk_meta_rendering_info_copy(struct vk_meta_rendering_info *dst,