diff --git a/src/gallium/auxiliary/draw/draw_gs.c b/src/gallium/auxiliary/draw/draw_gs.c index 95f378a0d54..f029e0e7c57 100644 --- a/src/gallium/auxiliary/draw/draw_gs.c +++ b/src/gallium/auxiliary/draw/draw_gs.c @@ -449,6 +449,32 @@ gs_flush(struct draw_geometry_shader *shader) } +static void +increment_prim(struct draw_geometry_shader *shader) +{ + /* Primitive ID must be per-patch instead of per + * tessellation primitive. If we have patch lengths + * we use these to compute the primitive index. + * See patch_lengths in llvm_pipeline_generic for + * more info. + */ + ++shader->fetched_prim_count; + if (shader->next_patch_length) { + shader->tess_prim_idx++; + if (shader->tess_prim_idx >= *shader->next_patch_length) { + ++shader->in_prim_idx; + ++shader->next_patch_length; + shader->tess_prim_idx = 0; + } + } else { + ++shader->in_prim_idx; + } + + if (draw_gs_should_flush(shader)) + gs_flush(shader); +} + + static void gs_point(struct draw_geometry_shader *shader, int idx) { @@ -458,11 +484,8 @@ gs_point(struct draw_geometry_shader *shader, int idx) shader->fetch_inputs(shader, indices, 1, shader->fetched_prim_count); - ++shader->in_prim_idx; - ++shader->fetched_prim_count; - if (draw_gs_should_flush(shader)) - gs_flush(shader); + increment_prim(shader); } @@ -476,11 +499,8 @@ gs_line(struct draw_geometry_shader *shader, int i0, int i1) shader->fetch_inputs(shader, indices, 2, shader->fetched_prim_count); - ++shader->in_prim_idx; - ++shader->fetched_prim_count; - if (draw_gs_should_flush(shader)) - gs_flush(shader); + increment_prim(shader); } @@ -497,11 +517,8 @@ gs_line_adj(struct draw_geometry_shader *shader, shader->fetch_inputs(shader, indices, 4, shader->fetched_prim_count); - ++shader->in_prim_idx; - ++shader->fetched_prim_count; - if (draw_gs_should_flush(shader)) - gs_flush(shader); + increment_prim(shader); } @@ -517,11 +534,8 @@ gs_tri(struct draw_geometry_shader *shader, shader->fetch_inputs(shader, indices, 3, shader->fetched_prim_count); - ++shader->in_prim_idx; - ++shader->fetched_prim_count; - if (draw_gs_should_flush(shader)) - gs_flush(shader); + increment_prim(shader); } @@ -541,11 +555,8 @@ gs_tri_adj(struct draw_geometry_shader *shader, shader->fetch_inputs(shader, indices, 6, shader->fetched_prim_count); - ++shader->in_prim_idx; - ++shader->fetched_prim_count; - if (draw_gs_should_flush(shader)) - gs_flush(shader); + increment_prim(shader); } #define FUNC gs_run @@ -568,6 +579,7 @@ draw_geometry_shader_run(struct draw_geometry_shader *shader, const struct draw_vertex_info *input_verts, const struct draw_prim_info *input_prim, const struct tgsi_shader_info *input_info, + uint32_t *const *patch_lengths, struct draw_vertex_info *output_verts, struct draw_prim_info *output_prims) { @@ -638,6 +650,7 @@ draw_geometry_shader_run(struct draw_geometry_shader *shader, shader->input_vertex_stride = input_stride; shader->input = input; shader->input_info = input_info; + shader->next_patch_length = patch_lengths ? *patch_lengths : NULL; #if DRAW_LLVM_AVAILABLE if (shader->draw->llvm) { @@ -1007,4 +1020,5 @@ draw_geometry_shader_new_instance(struct draw_geometry_shader *gs) return; gs->in_prim_idx = 0; + gs->tess_prim_idx = 0; } diff --git a/src/gallium/auxiliary/draw/draw_gs.h b/src/gallium/auxiliary/draw/draw_gs.h index 3aae41f10b0..024d49ac77d 100644 --- a/src/gallium/auxiliary/draw/draw_gs.h +++ b/src/gallium/auxiliary/draw/draw_gs.h @@ -89,6 +89,8 @@ struct draw_geometry_shader { unsigned num_vertex_streams; unsigned in_prim_idx; + unsigned tess_prim_idx; + const uint32_t *next_patch_length; unsigned input_vertex_stride; unsigned fetched_prim_count; const float (*input)[4]; @@ -142,8 +144,9 @@ draw_geometry_shader_run(struct draw_geometry_shader *shader, const struct draw_vertex_info *input_verts, const struct draw_prim_info *input_prim, const struct tgsi_shader_info *input_info, + uint32_t *const *patch_lengths, struct draw_vertex_info *output_verts, - struct draw_prim_info *output_prims ); + struct draw_prim_info *output_prims); void draw_geometry_shader_prepare(struct draw_geometry_shader *shader, diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c index 886d36f7d2a..3ea87e4abbc 100644 --- a/src/gallium/auxiliary/draw/draw_llvm.c +++ b/src/gallium/auxiliary/draw/draw_llvm.c @@ -3601,6 +3601,11 @@ draw_tes_llvm_generate(struct draw_llvm *llvm, system_values.vertices_in = lp_build_broadcast_scalar(&bldvec, patch_vertices_in); if (variant->key.primid_needed) { + /* In a fragment shader, it (gl_PrimitiveID) will contain the [...] value that would have been + * presented as input to the geometry shader had it been present. + * https://docs.vulkan.org/spec/latest/chapters/interfaces.html#interfaces-builtin-variables + * Store the primitive ID as-if the geometry shader did `gl_PrimitiveID = gl_PrimitiveIDIn`. + */ int slot = variant->key.primid_output; for (unsigned i = 0; i < 4; i++) { outputs[slot][i] = lp_build_alloca(gallivm, lp_build_int_vec_type(gallivm, tes_type), "primid"); diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c index a1791d953ce..535a27518fb 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c @@ -289,6 +289,7 @@ fetch_pipeline_generic(struct draw_pt_middle_end *middle, vert_info, prim_info, &vshader->info, + NULL, gs_vert_info, gs_prim_info); diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c index 940fec5cf62..caf3cb0ec77 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c @@ -575,6 +575,24 @@ llvm_pipeline_generic(struct draw_pt_middle_end *middle, vert_info = &llvm_vert_info; } + /* Keep track of the patch lengths if we have a geometry shader, this way we can increment + * gl_PrimitiveID once per patch, instead of per tessellation output primitive. + * The Vulkan and OpenGL specs say: + * In a geometry shader, it (gl_PrimitiveID) will contain the number of primitives presented + * as input to the shader since the current set of rendering primitives was started. + * This sounds like gl_PrimitiveID will be the index of each output primitive from the + * tessellation shader, so multiple per patch. But drivers implement the more specific language + * from ARB_tessellation_shader: + * In geometry language the input variable gl_PrimitiveIDIn behaves identically to the + * tessellation control and evaluation shader input variable gl_PrimitiveID. + * Which implies on primitive index per patch. DirectX is also more specific: + * The geometry-shader stage can consume the SV_PrimitiveID system-generated value that is + * auto-generated by the IA. This allows per-primitive data to be fetched or computed if desired. + * The input-assembler (IA) stage happens before the tessellation, so we would expect one index + * per patch. + */ + uint32_t *patch_lengths = NULL; + if (opt & PT_SHADE) { struct draw_vertex_shader *vshader = draw->vs.vertex_shader; if (tcs_shader) { @@ -602,7 +620,9 @@ llvm_pipeline_generic(struct draw_pt_middle_end *middle, prim_info, tcs_shader ? &tcs_shader->info : &vshader->info, &tes_vert_info, - &tes_prim_info, &tes_elts_out); + &tes_prim_info, + gshader ? &patch_lengths : NULL, + &tes_elts_out); FREE(vert_info->verts); vert_info = &tes_vert_info; @@ -631,6 +651,7 @@ llvm_pipeline_generic(struct draw_pt_middle_end *middle, vert_info, prim_info, tes_shader ? &tes_shader->info : &vshader->info, + tes_shader ? &patch_lengths : NULL, gs_vert_info, gs_prim_info); @@ -706,9 +727,14 @@ llvm_pipeline_generic(struct draw_pt_middle_end *middle, } FREE(vert_info->verts); - if (gshader && gshader->num_vertex_streams > 1) + if (gshader && gshader->num_vertex_streams > 1) { for (unsigned i = 1; i < gshader->num_vertex_streams; i++) FREE(gs_vert_info[i].verts); + } + + if (patch_lengths) { + FREE(patch_lengths); + } if (free_prim_info) { FREE(tes_elts_out); diff --git a/src/gallium/auxiliary/draw/draw_tess.c b/src/gallium/auxiliary/draw/draw_tess.c index eb294254cb5..fe9f32c0e0b 100644 --- a/src/gallium/auxiliary/draw/draw_tess.c +++ b/src/gallium/auxiliary/draw/draw_tess.c @@ -325,6 +325,7 @@ int draw_tess_eval_shader_run(struct draw_tess_eval_shader *shader, const struct tgsi_shader_info *input_info, struct draw_vertex_info *output_verts, struct draw_prim_info *output_prims, + uint32_t **patch_lengths, uint16_t **elts_out) { const float (*input)[4] = (const float (*)[4])input_verts->verts->data; @@ -346,6 +347,10 @@ int draw_tess_eval_shader_run(struct draw_tess_eval_shader *shader, output_prims->primitive_lengths = NULL; output_prims->primitive_count = 0; + if (patch_lengths) { + *patch_lengths = MALLOC(input_prim->primitive_count * sizeof(uint32_t)); + } + shader->input = input; shader->input_vertex_stride = input_stride; shader->input_info = input_info; @@ -382,7 +387,7 @@ int draw_tess_eval_shader_run(struct draw_tess_eval_shader *shader, elts = REALLOC(elts, elt_start * sizeof(uint16_t), output_prims->count * sizeof(uint16_t)); - for (unsigned i = 0; i < data.num_indices; i++) + for (uint32_t i = 0; i < data.num_indices; i++) elts[elt_start + i] = vert_start + data.indices[i]; llvm_fetch_tes_input(shader, input_prim, i, num_input_vertices_per_patch); @@ -396,10 +401,15 @@ int draw_tess_eval_shader_run(struct draw_tess_eval_shader *shader, } uint32_t prim_len = u_prim_vertex_count(output_prims->prim)->min; - output_prims->primitive_count += data.num_indices / prim_len; + uint32_t prims_per_patch = data.num_indices / prim_len; + output_prims->primitive_count += prims_per_patch; + if (patch_lengths) { + (*patch_lengths)[i] = prims_per_patch; + } + output_prims->primitive_lengths = REALLOC(output_prims->primitive_lengths, prim_start * sizeof(uint32_t), output_prims->primitive_count * sizeof(uint32_t)); - for (unsigned i = prim_start; i < output_prims->primitive_count; i++) { + for (uint32_t i = prim_start; i < output_prims->primitive_count; i++) { output_prims->primitive_lengths[i] = prim_len; } } diff --git a/src/gallium/auxiliary/draw/draw_tess.h b/src/gallium/auxiliary/draw/draw_tess.h index 49c2c50320c..19fbad59383 100644 --- a/src/gallium/auxiliary/draw/draw_tess.h +++ b/src/gallium/auxiliary/draw/draw_tess.h @@ -117,6 +117,7 @@ int draw_tess_eval_shader_run(struct draw_tess_eval_shader *shader, const struct tgsi_shader_info *input_info, struct draw_vertex_info *output_verts, struct draw_prim_info *output_prims, + uint32_t **patch_lengths, uint16_t **elts_out); #if DRAW_LLVM_AVAILABLE