From 940725a7d991939aae576f73e4815fad34a68a22 Mon Sep 17 00:00:00 2001 From: Iago Toral Quiroga Date: Tue, 13 Jul 2021 12:47:20 +0200 Subject: [PATCH] broadcom/compiler: implement gl_PrimitiveID in FS without a GS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Part-of: --- 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