Mesa (main): v3dv: emit state packets for geometry shaders

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Jul 12 07:56:03 UTC 2021


Module: Mesa
Branch: main
Commit: 991cca2e77b730113dc6388db8b617b76e359e6e
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=991cca2e77b730113dc6388db8b617b76e359e6e

Author: Iago Toral Quiroga <itoral at igalia.com>
Date:   Thu Jul  1 09:08:02 2021 +0200

v3dv: emit state packets for geometry shaders

Reviewed-by: Alejandro Piñeiro <apinheiro at igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11783>

---

 src/broadcom/vulkan/v3dv_cmd_buffer.c  |  34 ++++++
 src/broadcom/vulkan/v3dv_private.h     |   2 +
 src/broadcom/vulkan/v3dvx_cmd_buffer.c | 203 ++++++++++++++++++++++++++++++---
 3 files changed, 222 insertions(+), 17 deletions(-)

diff --git a/src/broadcom/vulkan/v3dv_cmd_buffer.c b/src/broadcom/vulkan/v3dv_cmd_buffer.c
index 72092b2c47e..42755a7923d 100644
--- a/src/broadcom/vulkan/v3dv_cmd_buffer.c
+++ b/src/broadcom/vulkan/v3dv_cmd_buffer.c
@@ -2086,6 +2086,7 @@ update_gfx_uniform_state(struct v3dv_cmd_buffer *cmd_buffer,
    const bool has_new_push_constants = dirty_uniform_state & V3DV_CMD_DIRTY_PUSH_CONSTANTS;
    const bool has_new_descriptors = dirty_uniform_state & V3DV_CMD_DIRTY_DESCRIPTOR_SETS;
 
+   /* VK_SHADER_STAGE_FRAGMENT_BIT */
    const bool has_new_descriptors_fs =
       has_new_descriptors &&
       (cmd_buffer->state.dirty_descriptor_stages & VK_SHADER_STAGE_FRAGMENT_BIT);
@@ -2106,6 +2107,39 @@ update_gfx_uniform_state(struct v3dv_cmd_buffer *cmd_buffer,
          v3dv_write_uniforms(cmd_buffer, pipeline, fs_variant);
    }
 
+   /* VK_SHADER_STAGE_GEOMETRY_BIT */
+   if (pipeline->has_gs) {
+      const bool has_new_descriptors_gs =
+         has_new_descriptors &&
+         (cmd_buffer->state.dirty_descriptor_stages &
+          VK_SHADER_STAGE_GEOMETRY_BIT);
+
+      const bool has_new_push_constants_gs =
+         has_new_push_constants &&
+         (cmd_buffer->state.dirty_push_constants_stages &
+          VK_SHADER_STAGE_GEOMETRY_BIT);
+
+      const bool needs_gs_update = has_new_viewport ||
+                                   has_new_pipeline ||
+                                   has_new_push_constants_gs ||
+                                   has_new_descriptors_gs;
+
+      if (needs_gs_update) {
+         struct v3dv_shader_variant *gs_variant =
+            pipeline->shared_data->variants[BROADCOM_SHADER_GEOMETRY];
+
+          struct v3dv_shader_variant *gs_bin_variant =
+            pipeline->shared_data->variants[BROADCOM_SHADER_GEOMETRY_BIN];
+
+         cmd_buffer->state.uniforms.gs =
+            v3dv_write_uniforms(cmd_buffer, pipeline, gs_variant);
+
+         cmd_buffer->state.uniforms.gs_bin =
+            v3dv_write_uniforms(cmd_buffer, pipeline, gs_bin_variant);
+      }
+   }
+
+   /* VK_SHADER_STAGE_VERTEX_BIT */
    const bool has_new_descriptors_vs =
       has_new_descriptors &&
       (cmd_buffer->state.dirty_descriptor_stages & VK_SHADER_STAGE_VERTEX_BIT);
diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h
index 6440695246d..e53a2f9f5a0 100644
--- a/src/broadcom/vulkan/v3dv_private.h
+++ b/src/broadcom/vulkan/v3dv_private.h
@@ -1132,6 +1132,8 @@ struct v3dv_cmd_buffer_state {
    struct {
       struct v3dv_cl_reloc vs_bin;
       struct v3dv_cl_reloc vs;
+      struct v3dv_cl_reloc gs_bin;
+      struct v3dv_cl_reloc gs;
       struct v3dv_cl_reloc fs;
    } uniforms;
 
diff --git a/src/broadcom/vulkan/v3dvx_cmd_buffer.c b/src/broadcom/vulkan/v3dvx_cmd_buffer.c
index 3f71ad72cbf..933f55b2737 100644
--- a/src/broadcom/vulkan/v3dvx_cmd_buffer.c
+++ b/src/broadcom/vulkan/v3dvx_cmd_buffer.c
@@ -1648,6 +1648,117 @@ v3dX(cmd_buffer_execute_inside_pass)(struct v3dv_cmd_buffer *primary,
    }
 }
 
+static void
+emit_gs_shader_state_record(struct v3dv_job *job,
+                            struct v3dv_bo *assembly_bo,
+                            struct v3dv_shader_variant *gs_bin,
+                            struct v3dv_cl_reloc gs_bin_uniforms,
+                            struct v3dv_shader_variant *gs,
+                            struct v3dv_cl_reloc gs_render_uniforms)
+{
+   cl_emit(&job->indirect, GEOMETRY_SHADER_STATE_RECORD, shader) {
+      shader.geometry_bin_mode_shader_code_address =
+         v3dv_cl_address(assembly_bo, gs_bin->assembly_offset);
+      shader.geometry_bin_mode_shader_4_way_threadable =
+         gs_bin->prog_data.gs->base.threads == 4;
+      shader.geometry_bin_mode_shader_start_in_final_thread_section =
+         gs_bin->prog_data.gs->base.single_seg;
+      shader.geometry_bin_mode_shader_propagate_nans = true;
+      shader.geometry_bin_mode_shader_uniforms_address =
+         gs_bin_uniforms;
+
+      shader.geometry_render_mode_shader_code_address =
+         v3dv_cl_address(assembly_bo, gs->assembly_offset);
+      shader.geometry_render_mode_shader_4_way_threadable =
+         gs->prog_data.gs->base.threads == 4;
+      shader.geometry_render_mode_shader_start_in_final_thread_section =
+         gs->prog_data.gs->base.single_seg;
+      shader.geometry_render_mode_shader_propagate_nans = true;
+      shader.geometry_render_mode_shader_uniforms_address =
+         gs_render_uniforms;
+   }
+}
+
+static uint8_t
+v3d_gs_output_primitive(uint32_t prim_type)
+{
+    switch (prim_type) {
+    case GL_POINTS:
+        return GEOMETRY_SHADER_POINTS;
+    case GL_LINE_STRIP:
+        return GEOMETRY_SHADER_LINE_STRIP;
+    case GL_TRIANGLE_STRIP:
+        return GEOMETRY_SHADER_TRI_STRIP;
+    default:
+        unreachable("Unsupported primitive type");
+    }
+}
+
+static void
+emit_tes_gs_common_params(struct v3dv_job *job,
+                          uint8_t gs_out_prim_type,
+                          uint8_t gs_num_invocations)
+{
+   cl_emit(&job->indirect, TESSELLATION_GEOMETRY_COMMON_PARAMS, shader) {
+      shader.tessellation_type = TESSELLATION_TYPE_TRIANGLE;
+      shader.tessellation_point_mode = false;
+      shader.tessellation_edge_spacing = TESSELLATION_EDGE_SPACING_EVEN;
+      shader.tessellation_clockwise = true;
+      shader.tessellation_invocations = 1;
+
+      shader.geometry_shader_output_format =
+         v3d_gs_output_primitive(gs_out_prim_type);
+      shader.geometry_shader_instances = gs_num_invocations & 0x1F;
+   }
+}
+
+static uint8_t
+simd_width_to_gs_pack_mode(uint32_t width)
+{
+   switch (width) {
+   case 16:
+      return V3D_PACK_MODE_16_WAY;
+   case 8:
+      return V3D_PACK_MODE_8_WAY;
+   case 4:
+      return V3D_PACK_MODE_4_WAY;
+   case 1:
+      return V3D_PACK_MODE_1_WAY;
+   default:
+      unreachable("Invalid SIMD width");
+   };
+}
+
+static void
+emit_tes_gs_shader_params(struct v3dv_job *job,
+                          uint32_t gs_simd,
+                          uint32_t gs_vpm_output_size,
+                          uint32_t gs_max_vpm_input_size_per_batch)
+{
+   cl_emit(&job->indirect, TESSELLATION_GEOMETRY_SHADER_PARAMS, shader) {
+      shader.tcs_batch_flush_mode = V3D_TCS_FLUSH_MODE_FULLY_PACKED;
+      shader.per_patch_data_column_depth = 1;
+      shader.tcs_output_segment_size_in_sectors = 1;
+      shader.tcs_output_segment_pack_mode = V3D_PACK_MODE_16_WAY;
+      shader.tes_output_segment_size_in_sectors = 1;
+      shader.tes_output_segment_pack_mode = V3D_PACK_MODE_16_WAY;
+      shader.gs_output_segment_size_in_sectors = gs_vpm_output_size;
+      shader.gs_output_segment_pack_mode =
+         simd_width_to_gs_pack_mode(gs_simd);
+      shader.tbg_max_patches_per_tcs_batch = 1;
+      shader.tbg_max_extra_vertex_segs_for_patches_after_first = 0;
+      shader.tbg_min_tcs_output_segments_required_in_play = 1;
+      shader.tbg_min_per_patch_data_segments_required_in_play = 1;
+      shader.tpg_max_patches_per_tes_batch = 1;
+      shader.tpg_max_vertex_segments_per_tes_batch = 0;
+      shader.tpg_max_tcs_output_segments_per_tes_batch = 1;
+      shader.tpg_min_tes_output_segments_required_in_play = 1;
+      shader.gbg_max_tes_output_vertex_segments_per_gs_batch =
+         gs_max_vpm_input_size_per_batch;
+      shader.gbg_min_gs_output_segments_required_in_play = 1;
+   }
+}
+
 void
 v3dX(cmd_buffer_emit_gl_shader_state)(struct v3dv_cmd_buffer *cmd_buffer)
 {
@@ -1658,37 +1769,86 @@ v3dX(cmd_buffer_emit_gl_shader_state)(struct v3dv_cmd_buffer *cmd_buffer)
    struct v3dv_pipeline *pipeline = state->gfx.pipeline;
    assert(pipeline);
 
-   struct v3d_vs_prog_data *prog_data_vs =
-      pipeline->shared_data->variants[BROADCOM_SHADER_VERTEX]->prog_data.vs;
-   struct v3d_vs_prog_data *prog_data_vs_bin =
-      pipeline->shared_data->variants[BROADCOM_SHADER_VERTEX_BIN]->prog_data.vs;
-   struct v3d_fs_prog_data *prog_data_fs =
-      pipeline->shared_data->variants[BROADCOM_SHADER_FRAGMENT]->prog_data.fs;
+   struct v3dv_shader_variant *vs_variant =
+      pipeline->shared_data->variants[BROADCOM_SHADER_VERTEX];
+   struct v3d_vs_prog_data *prog_data_vs = vs_variant->prog_data.vs;
+
+   struct v3dv_shader_variant *vs_bin_variant =
+      pipeline->shared_data->variants[BROADCOM_SHADER_VERTEX_BIN];
+   struct v3d_vs_prog_data *prog_data_vs_bin = vs_bin_variant->prog_data.vs;
+
+   struct v3dv_shader_variant *fs_variant =
+      pipeline->shared_data->variants[BROADCOM_SHADER_FRAGMENT];
+   struct v3d_fs_prog_data *prog_data_fs = fs_variant->prog_data.fs;
+
+   struct v3dv_shader_variant *gs_variant = NULL;
+   struct v3dv_shader_variant *gs_bin_variant = NULL;
+   struct v3d_gs_prog_data *prog_data_gs = NULL;
+   struct v3d_gs_prog_data *prog_data_gs_bin = NULL;
+   if (pipeline->has_gs) {
+      gs_variant =
+         pipeline->shared_data->variants[BROADCOM_SHADER_GEOMETRY];
+      prog_data_gs = gs_variant->prog_data.gs;
+
+      gs_bin_variant =
+         pipeline->shared_data->variants[BROADCOM_SHADER_GEOMETRY_BIN];
+      prog_data_gs_bin = gs_bin_variant->prog_data.gs;
+   }
 
    /* Update the cache dirty flag based on the shader progs data */
    job->tmu_dirty_rcl |= prog_data_vs_bin->base.tmu_dirty_rcl;
    job->tmu_dirty_rcl |= prog_data_vs->base.tmu_dirty_rcl;
    job->tmu_dirty_rcl |= prog_data_fs->base.tmu_dirty_rcl;
+   if (pipeline->has_gs) {
+      job->tmu_dirty_rcl |= prog_data_gs_bin->base.tmu_dirty_rcl;
+      job->tmu_dirty_rcl |= prog_data_gs->base.tmu_dirty_rcl;
+   }
 
    /* See GFXH-930 workaround below */
    uint32_t num_elements_to_emit = MAX2(pipeline->va_count, 1);
 
+   uint32_t shader_state_record_length =
+      cl_packet_length(GL_SHADER_STATE_RECORD);
+   if (pipeline->has_gs) {
+      shader_state_record_length +=
+         cl_packet_length(GEOMETRY_SHADER_STATE_RECORD) +
+         cl_packet_length(TESSELLATION_GEOMETRY_COMMON_PARAMS) +
+         2 * cl_packet_length(TESSELLATION_GEOMETRY_SHADER_PARAMS);
+   }
+
    uint32_t shader_rec_offset =
       v3dv_cl_ensure_space(&job->indirect,
-                           cl_packet_length(GL_SHADER_STATE_RECORD) +
+                           shader_state_record_length +
                            num_elements_to_emit *
                            cl_packet_length(GL_SHADER_STATE_ATTRIBUTE_RECORD),
                            32);
    v3dv_return_if_oom(cmd_buffer, NULL);
 
-   struct v3dv_shader_variant *vs_variant =
-      pipeline->shared_data->variants[BROADCOM_SHADER_VERTEX];
-   struct v3dv_shader_variant *vs_bin_variant =
-      pipeline->shared_data->variants[BROADCOM_SHADER_VERTEX_BIN];
-   struct v3dv_shader_variant *fs_variant =
-      pipeline->shared_data->variants[BROADCOM_SHADER_FRAGMENT];
    struct v3dv_bo *assembly_bo = pipeline->shared_data->assembly_bo;
 
+   if (pipeline->has_gs) {
+      emit_gs_shader_state_record(job,
+                                  assembly_bo,
+                                  gs_bin_variant,
+                                  cmd_buffer->state.uniforms.gs_bin,
+                                  gs_variant,
+                                  cmd_buffer->state.uniforms.gs);
+
+      emit_tes_gs_common_params(job,
+                                prog_data_gs->out_prim_type,
+                                prog_data_gs->num_invocations);
+
+      emit_tes_gs_shader_params(job,
+                                pipeline->vpm_cfg_bin.gs_width,
+                                pipeline->vpm_cfg_bin.Gd,
+                                pipeline->vpm_cfg_bin.Gv);
+
+      emit_tes_gs_shader_params(job,
+                                pipeline->vpm_cfg.gs_width,
+                                pipeline->vpm_cfg.Gd,
+                                pipeline->vpm_cfg.Gv);
+   }
+
    struct v3dv_bo *default_attribute_values =
       pipeline->default_attribute_values != NULL ?
       pipeline->default_attribute_values :
@@ -1720,6 +1880,9 @@ v3dX(cmd_buffer_emit_gl_shader_state)(struct v3dv_cmd_buffer *cmd_buffer)
 
       shader.address_of_default_attribute_values =
          v3dv_cl_address(default_attribute_values, 0);
+
+      shader.any_shader_reads_hardware_written_primitive_id =
+         pipeline->has_gs ? prog_data_gs->uses_pid : false;
    }
 
    /* Upload vertex element attributes (SHADER_STATE_ATTRIBUTE_RECORD) */
@@ -1815,10 +1978,16 @@ v3dX(cmd_buffer_emit_gl_shader_state)(struct v3dv_cmd_buffer *cmd_buffer)
                                     cl_packet_length(GL_SHADER_STATE));
    v3dv_return_if_oom(cmd_buffer, NULL);
 
-   cl_emit(&job->bcl, GL_SHADER_STATE, state) {
-      state.address = v3dv_cl_address(job->indirect.bo,
-                                      shader_rec_offset);
-      state.number_of_attribute_arrays = num_elements_to_emit;
+   if (pipeline->has_gs) {
+      cl_emit(&job->bcl, GL_SHADER_STATE_INCLUDING_GS, state) {
+         state.address = v3dv_cl_address(job->indirect.bo, shader_rec_offset);
+         state.number_of_attribute_arrays = num_elements_to_emit;
+      }
+   } else {
+      cl_emit(&job->bcl, GL_SHADER_STATE, state) {
+         state.address = v3dv_cl_address(job->indirect.bo, shader_rec_offset);
+         state.number_of_attribute_arrays = num_elements_to_emit;
+      }
    }
 
    cmd_buffer->state.dirty &= ~(V3DV_CMD_DIRTY_VERTEX_BUFFER |



More information about the mesa-commit mailing list