Mesa (main): broadcom/compiler: implement gl_PrimitiveID in FS without a GS

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Jul 14 12:20:28 UTC 2021


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

Author: Iago Toral Quiroga <itoral at igalia.com>
Date:   Tue Jul 13 12:47:20 2021 +0200

broadcom/compiler: implement gl_PrimitiveID in FS without a GS

OpenGL ES 3.1 specifies that a geometry shader can write to gl_PrimitiveID,
which can then be read by a fragment shader.

OpenGL ES 3.2 additionally adds the capacity for the fragment shader
to read gl_PrimitiveID even if there is no geometry shader. This
commit adds support for this feature, which is also implicitly
expected by the geometry shader feature in Vulkan 1.0.

Fixes:
dEQP-VK.pipeline.framebuffer_attachment.no_attachments
dEQP-VK.pipeline.framebuffer_attachment.no_attachments_ms

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

---

 src/broadcom/compiler/nir_to_vir.c     | 21 ++++++++++++++++++---
 src/broadcom/compiler/v3d_compiler.h   | 21 ++++++++++++++++++++-
 src/broadcom/compiler/vir.c            |  1 +
 src/broadcom/vulkan/v3dv_pipeline.c    |  3 +++
 src/broadcom/vulkan/v3dvx_cmd_buffer.c |  4 +++-
 src/gallium/drivers/v3d/v3d_program.c  |  1 +
 src/gallium/drivers/v3d/v3dx_draw.c    |  6 ++++--
 7 files changed, 50 insertions(+), 7 deletions(-)

diff --git a/src/broadcom/compiler/nir_to_vir.c b/src/broadcom/compiler/nir_to_vir.c
index ab04e4cf269..9f0dc14519f 100644
--- a/src/broadcom/compiler/nir_to_vir.c
+++ b/src/broadcom/compiler/nir_to_vir.c
@@ -2101,6 +2101,14 @@ ntq_setup_fs_inputs(struct v3d_compile *c)
 
                 if (var->data.location == VARYING_SLOT_POS) {
                         emit_fragcoord_input(c, loc);
+                } else if (var->data.location == VARYING_SLOT_PRIMITIVE_ID &&
+                           !c->fs_key->has_gs) {
+                        /* If the fragment shader reads gl_PrimitiveID and we
+                         * don't have a geometry shader in the pipeline to write
+                         * it then we program the hardware to inject it as
+                         * an implicit varying. Take it from there.
+                         */
+                        c->inputs[loc * 4] = c->primitive_id;
                 } else if (util_varying_is_point_coord(var->data.location,
                                                        c->fs_key->point_sprite_mask)) {
                         c->inputs[loc * 4 + 0] = c->point_x;
@@ -3143,6 +3151,7 @@ ntq_emit_intrinsic(struct v3d_compile *c, nir_intrinsic_instr *instr)
                  * VPM output header. According to docs, we should read this
                  * using ldvpm(v,d)_in (See Table 71).
                  */
+                assert(c->s->info.stage == MESA_SHADER_GEOMETRY);
                 ntq_store_dest(c, &instr->dest, 0,
                                vir_LDVPMV_IN(c, vir_uniform_ui(c, 0)));
                 break;
@@ -3764,9 +3773,15 @@ nir_to_vir(struct v3d_compile *c)
                 c->payload_w_centroid = vir_MOV(c, vir_reg(QFILE_REG, 1));
                 c->payload_z = vir_MOV(c, vir_reg(QFILE_REG, 2));
 
-                /* V3D 4.x can disable implicit point coordinate varyings if
-                 * they are not used.
-                 */
+                /* V3D 4.x can disable implicit varyings if they are not used */
+                c->fs_uses_primitive_id =
+                        nir_find_variable_with_location(c->s, nir_var_shader_in,
+                                                        VARYING_SLOT_PRIMITIVE_ID);
+                if (c->fs_uses_primitive_id && !c->fs_key->has_gs) {
+                       c->primitive_id =
+                               emit_fragment_varying(c, NULL, -1, 0, 0);
+                }
+
                 if (c->fs_key->is_points &&
                     (c->devinfo->ver < 40 || program_reads_point_coord(c))) {
                         c->point_x = emit_fragment_varying(c, NULL, -1, 0, 0);
diff --git a/src/broadcom/compiler/v3d_compiler.h b/src/broadcom/compiler/v3d_compiler.h
index b3dae552201..c1ea346bead 100644
--- a/src/broadcom/compiler/v3d_compiler.h
+++ b/src/broadcom/compiler/v3d_compiler.h
@@ -421,6 +421,19 @@ struct v3d_fs_key {
         uint32_t point_sprite_mask;
 
         struct pipe_rt_blend_state blend;
+
+        /* If the fragment shader reads gl_PrimitiveID then we have 2 scenarios:
+         *
+         * - If there is a geometry shader, then gl_PrimitiveID must be written
+         *   by it and the fragment shader loads it as a regular explicit input
+         *   varying. This is the only valid use case in GLES 3.1.
+         *
+         * - If there is not a geometry shader (allowed since GLES 3.2 and
+         *   Vulkan 1.0), then gl_PrimitiveID must be implicitly written by
+         *   hardware and is considered an implicit input varying in the
+         *   fragment shader.
+         */
+        bool has_gs;
 };
 
 struct v3d_gs_key {
@@ -636,6 +649,9 @@ struct v3d_compile {
         bool writes_z;
         bool uses_implicit_point_line_varyings;
 
+        /* True if a fragment shader reads gl_PrimitiveID */
+        bool fs_uses_primitive_id;
+
         /* If the fragment shader does anything that requires to force
          * per-sample MSAA, such as reading gl_SampleID.
          */
@@ -701,7 +717,7 @@ struct v3d_compile {
         struct qreg execute;
         bool in_control_flow;
 
-        struct qreg line_x, point_x, point_y;
+        struct qreg line_x, point_x, point_y, primitive_id;
 
         /**
          * Instance ID, which comes in before the vertex attribute payload if
@@ -925,6 +941,9 @@ struct v3d_gs_prog_data {
 struct v3d_fs_prog_data {
         struct v3d_prog_data base;
 
+        /* Whether the program reads gl_PrimitiveID */
+        bool uses_pid;
+
         struct v3d_varying_slot input_slots[V3D_MAX_FS_INPUTS];
 
         /* Array of flat shade flags.
diff --git a/src/broadcom/compiler/vir.c b/src/broadcom/compiler/vir.c
index 990648b61a6..259f6bd70eb 100644
--- a/src/broadcom/compiler/vir.c
+++ b/src/broadcom/compiler/vir.c
@@ -800,6 +800,7 @@ v3d_fs_set_prog_data(struct v3d_compile *c,
         prog_data->lock_scoreboard_on_first_thrsw =
                 c->lock_scoreboard_on_first_thrsw;
         prog_data->force_per_sample_msaa = c->force_per_sample_msaa;
+        prog_data->uses_pid = c->fs_uses_primitive_id;
 }
 
 static void
diff --git a/src/broadcom/vulkan/v3dv_pipeline.c b/src/broadcom/vulkan/v3dv_pipeline.c
index fe69f6d0e5e..f7eab650a8f 100644
--- a/src/broadcom/vulkan/v3dv_pipeline.c
+++ b/src/broadcom/vulkan/v3dv_pipeline.c
@@ -1156,6 +1156,7 @@ static void
 pipeline_populate_v3d_fs_key(struct v3d_fs_key *key,
                              const VkGraphicsPipelineCreateInfo *pCreateInfo,
                              const struct v3dv_pipeline_stage *p_stage,
+                             bool has_geometry_shader,
                              uint32_t ucp_enables)
 {
    assert(p_stage->stage == BROADCOM_SHADER_FRAGMENT);
@@ -1172,6 +1173,7 @@ pipeline_populate_v3d_fs_key(struct v3d_fs_key *key,
    key->is_points = (topology == PIPE_PRIM_POINTS);
    key->is_lines = (topology >= PIPE_PRIM_LINES &&
                     topology <= PIPE_PRIM_LINE_STRIP);
+   key->has_gs = has_geometry_shader;
 
    const VkPipelineColorBlendStateCreateInfo *cb_info =
       pCreateInfo->pColorBlendState;
@@ -1969,6 +1971,7 @@ pipeline_compile_fragment_shader(struct v3dv_pipeline *pipeline,
    struct v3d_fs_key key;
 
    pipeline_populate_v3d_fs_key(&key, pCreateInfo, p_stage,
+                                pipeline->gs != NULL,
                                 get_ucp_enable_mask(pipeline->vs));
 
    VkResult vk_result;
diff --git a/src/broadcom/vulkan/v3dvx_cmd_buffer.c b/src/broadcom/vulkan/v3dvx_cmd_buffer.c
index b52e0327834..20b18ce934a 100644
--- a/src/broadcom/vulkan/v3dvx_cmd_buffer.c
+++ b/src/broadcom/vulkan/v3dvx_cmd_buffer.c
@@ -1869,7 +1869,9 @@ v3dX(cmd_buffer_emit_gl_shader_state)(struct v3dv_cmd_buffer *cmd_buffer)
          v3dv_cl_address(default_attribute_values, 0);
 
       shader.any_shader_reads_hardware_written_primitive_id =
-         pipeline->has_gs ? prog_data_gs->uses_pid : false;
+         (pipeline->has_gs && prog_data_gs->uses_pid) || prog_data_fs->uses_pid;
+      shader.insert_primitive_id_as_first_varying_to_fragment_shader =
+         !pipeline->has_gs && prog_data_fs->uses_pid;
    }
 
    /* Upload vertex element attributes (SHADER_STATE_ATTRIBUTE_RECORD) */
diff --git a/src/gallium/drivers/v3d/v3d_program.c b/src/gallium/drivers/v3d/v3d_program.c
index 4050b933319..db376cbb3c9 100644
--- a/src/gallium/drivers/v3d/v3d_program.c
+++ b/src/gallium/drivers/v3d/v3d_program.c
@@ -543,6 +543,7 @@ v3d_update_compiled_fs(struct v3d_context *v3d, uint8_t prim_mode)
                          prim_mode <= PIPE_PRIM_LINE_STRIP);
         key->line_smoothing = (key->is_lines &&
                                v3d_line_smoothing_enabled(v3d));
+        key->has_gs = v3d->prog.bind_gs != NULL;
         if (v3d->blend->base.logicop_enable) {
                 key->logicop_func = v3d->blend->base.logicop_func;
         } else {
diff --git a/src/gallium/drivers/v3d/v3dx_draw.c b/src/gallium/drivers/v3d/v3dx_draw.c
index 0cf4b65d78d..b637ca679d1 100644
--- a/src/gallium/drivers/v3d/v3dx_draw.c
+++ b/src/gallium/drivers/v3d/v3dx_draw.c
@@ -618,8 +618,10 @@ v3d_emit_gl_shader_state(struct v3d_context *v3d,
 
 #if V3D_VERSION >= 41
                 shader.any_shader_reads_hardware_written_primitive_id =
-                        v3d->prog.gs ? v3d->prog.gs->prog_data.gs->uses_pid :
-                                       false;
+                        (v3d->prog.gs && v3d->prog.gs->prog_data.gs->uses_pid) ||
+                        v3d->prog.fs->prog_data.fs->uses_pid;
+                shader.insert_primitive_id_as_first_varying_to_fragment_shader =
+                        !v3d->prog.gs && v3d->prog.fs->prog_data.fs->uses_pid;
 #endif
 
 #if V3D_VERSION >= 40



More information about the mesa-commit mailing list