draw: primitive ID is per-patch

Reviewed-by: Konstantin Seurer <konstantin.seurer@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/32231>
This commit is contained in:
Aleksi Sapon 2024-11-19 11:36:21 -05:00 committed by Marge Bot
parent c2b7bafd76
commit b80d0d8bf4
7 changed files with 86 additions and 26 deletions

View File

@ -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;
}

View File

@ -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,

View File

@ -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");

View File

@ -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);

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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