d3d12: Link tesselation control and eval shaders

GLSL puts a bunch of tessellation info in the eval shaders, because
passthrough control shaders can exist. D3D12 puts it in the control
(hull) shader instead. So, when specializing, copy info from domain
to hull. For initial compiles (no domain shader), just make something
up.

D3D12 also requires the domain and hull shaders to have identical
patch constant signatures. Use the existing infrastructure and extend
it to also propagate patch constants. Notably, patch constant locations
are outside of the 64-bit range value so they require a separate pass
to avoid shifts larger than 64.

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Bill Kristiansen <billkris@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14399>
This commit is contained in:
Jesse Natalie 2022-01-02 13:03:32 -08:00 committed by Marge Bot
parent 0ed7b44f5c
commit c83476ff13
2 changed files with 117 additions and 12 deletions

View file

@ -428,6 +428,11 @@ cull_mode_lowered(struct d3d12_context *ctx, unsigned fill_mode)
static unsigned
get_provoking_vertex(struct d3d12_selection_context *sel_ctx, bool *alternate, const struct pipe_draw_info *dinfo)
{
if (dinfo->mode == GL_PATCHES) {
*alternate = false;
return 0;
}
struct d3d12_shader_selector *vs = sel_ctx->ctx->gfx_stages[PIPE_SHADER_VERTEX];
struct d3d12_shader_selector *gs = sel_ctx->ctx->gfx_stages[PIPE_SHADER_GEOMETRY];
struct d3d12_shader_selector *last_vertex_stage = gs && !gs->is_gs_variant ? gs : vs;
@ -506,7 +511,7 @@ needs_vertex_reordering(struct d3d12_selection_context *sel_ctx, const struct pi
static nir_variable *
create_varying_from_info(nir_shader *nir, struct d3d12_varying_info *info,
unsigned slot, nir_variable_mode mode)
unsigned slot, nir_variable_mode mode, bool patch)
{
nir_variable *var;
char tmp[100];
@ -518,16 +523,25 @@ create_varying_from_info(nir_shader *nir, struct d3d12_varying_info *info,
var->data.location = slot;
var->data.driver_location = info->vars[slot].driver_location;
var->data.interpolation = info->vars[slot].interpolation;
var->data.patch = info->vars[slot].patch;
var->data.compact = info->vars[slot].compact;
if (patch)
var->data.location += VARYING_SLOT_PATCH0;
return var;
}
static void
fill_varyings(struct d3d12_varying_info *info, nir_shader *s,
nir_variable_mode modes, uint64_t mask)
nir_variable_mode modes, uint64_t mask, bool patch)
{
nir_foreach_variable_with_modes(var, s, modes) {
unsigned slot = var->data.location;
bool is_generic_patch = slot >= VARYING_SLOT_PATCH0;
if (patch ^ is_generic_patch)
continue;
if (is_generic_patch)
slot -= VARYING_SLOT_PATCH0;
uint64_t slot_bit = BITFIELD64_BIT(slot);
if (!(mask & slot_bit))
@ -535,6 +549,8 @@ fill_varyings(struct d3d12_varying_info *info, nir_shader *s,
info->vars[slot].driver_location = var->data.driver_location;
info->vars[slot].type = var->type;
info->vars[slot].interpolation = var->data.interpolation;
info->vars[slot].patch = var->data.patch;
info->vars[slot].compact = var->data.compact;
info->mask |= slot_bit;
}
}
@ -591,7 +607,7 @@ validate_geometry_shader_variant(struct d3d12_selection_context *sel_ctx)
if (variant_needed) {
fill_varyings(&key.varyings, vs->initial, nir_var_shader_out,
vs->initial->info.outputs_written);
vs->initial->info.outputs_written, false);
}
/* Check if the currently bound geometry shader variant is correct */
@ -648,6 +664,21 @@ d3d12_compare_shader_keys(const d3d12_shader_key *expect, const d3d12_shader_key
if (memcmp(expect->cs.workgroup_size, have->cs.workgroup_size,
sizeof(have->cs.workgroup_size)))
return false;
} else if (expect->stage == PIPE_SHADER_TESS_CTRL) {
if (expect->hs.primitive_mode != have->hs.primitive_mode ||
expect->hs.ccw != have->hs.ccw ||
expect->hs.point_mode != have->hs.point_mode ||
expect->hs.spacing != have->hs.spacing ||
memcmp(&expect->hs.required_patch_outputs, &have->hs.required_patch_outputs,
sizeof(struct d3d12_varying_info)) ||
expect->hs.next_patch_inputs != have->hs.next_patch_inputs)
return false;
} else if (expect->stage == PIPE_SHADER_TESS_EVAL) {
if (expect->ds.tcs_vertices_out != have->ds.tcs_vertices_out ||
memcmp(&expect->ds.required_patch_inputs, &have->ds.required_patch_inputs,
sizeof(struct d3d12_varying_info)) ||
expect->ds.prev_patch_outputs != have ->ds.prev_patch_outputs)
return false;
}
if (expect->tex_saturate_s != have->tex_saturate_s ||
@ -727,9 +758,16 @@ d3d12_fill_shader_key(struct d3d12_selection_context *sel_ctx,
system_out_values |= VARYING_BIT_PSIZ;
uint64_t mask = prev->current->nir->info.outputs_written & ~system_out_values;
fill_varyings(&key->required_varying_inputs, prev->current->nir,
nir_var_shader_out, mask);
nir_var_shader_out, mask, false);
key->prev_varying_outputs = prev->current->nir->info.outputs_written;
if (stage == PIPE_SHADER_TESS_EVAL) {
uint32_t patch_mask = prev->current->nir->info.patch_outputs_written;
fill_varyings(&key->ds.required_patch_inputs, prev->current->nir,
nir_var_shader_out, patch_mask, true);
key->ds.prev_patch_outputs = patch_mask;
}
/* Set the provoking vertex based on the previous shader output. Only set the
* key value if the driver actually supports changing the provoking vertex though */
if (stage == PIPE_SHADER_FRAGMENT && sel_ctx->ctx->gfx_pipeline_state.rast &&
@ -746,13 +784,22 @@ d3d12_fill_shader_key(struct d3d12_selection_context *sel_ctx,
system_generated_in_values |= VARYING_BIT_POS;
uint64_t mask = next->current->nir->info.inputs_read & ~system_generated_in_values;
fill_varyings(&key->required_varying_outputs, next->current->nir,
nir_var_shader_in, mask);
nir_var_shader_in, mask, false);
if (stage == PIPE_SHADER_TESS_CTRL) {
uint32_t patch_mask = next->current->nir->info.patch_outputs_read;
fill_varyings(&key->hs.required_patch_outputs, prev->current->nir,
nir_var_shader_in, patch_mask, true);
key->hs.next_patch_inputs = patch_mask;
}
}
key->next_varying_inputs = next->current->nir->info.inputs_read;
}
if (stage == PIPE_SHADER_GEOMETRY ||
(stage == PIPE_SHADER_VERTEX && (!next || next->stage != PIPE_SHADER_GEOMETRY))) {
((stage == PIPE_SHADER_VERTEX || stage == PIPE_SHADER_TESS_EVAL) &&
(!next || next->stage == PIPE_SHADER_FRAGMENT))) {
key->last_vertex_processing_stage = 1;
key->invert_depth = sel_ctx->ctx->reverse_depth_range;
if (sel_ctx->ctx->pstipple.enabled)
@ -791,6 +838,23 @@ d3d12_fill_shader_key(struct d3d12_selection_context *sel_ctx,
key->fs.cast_to_uint = util_format_is_unorm(sel_ctx->ctx->fb.cbufs[0]->format);
key->fs.cast_to_int = !key->fs.cast_to_uint;
}
} else if (stage == PIPE_SHADER_TESS_CTRL) {
if (next && next->current->nir->info.stage == MESA_SHADER_TESS_EVAL) {
key->hs.primitive_mode = next->current->nir->info.tess._primitive_mode;
key->hs.ccw = next->current->nir->info.tess.ccw;
key->hs.point_mode = next->current->nir->info.tess.point_mode;
key->hs.spacing = next->current->nir->info.tess.spacing;
} else {
key->hs.primitive_mode = TESS_PRIMITIVE_QUADS;
key->hs.ccw = true;
key->hs.point_mode = false;
key->hs.spacing = TESS_SPACING_EQUAL;
}
} else if (stage == PIPE_SHADER_TESS_EVAL) {
if (prev && prev->current->nir->info.stage == MESA_SHADER_TESS_CTRL)
key->ds.tcs_vertices_out = prev->current->nir->info.tess.tcs_vertices_out;
else
key->ds.tcs_vertices_out = 32;
}
if (sel->samples_int_textures) {
@ -944,6 +1008,15 @@ select_shader_variant(struct d3d12_selection_context *sel_ctx, d3d12_shader_sele
new_nir_variant->info.workgroup_size[2] = key.cs.workgroup_size[2];
}
if (new_nir_variant->info.stage == MESA_SHADER_TESS_CTRL) {
new_nir_variant->info.tess._primitive_mode = (tess_primitive_mode)key.hs.primitive_mode;
new_nir_variant->info.tess.ccw = key.hs.ccw;
new_nir_variant->info.tess.point_mode = key.hs.point_mode;
new_nir_variant->info.tess.spacing = key.hs.spacing;
} else if (new_nir_variant->info.stage == MESA_SHADER_TESS_EVAL) {
new_nir_variant->info.tess.tcs_vertices_out = key.ds.tcs_vertices_out;
}
{
struct nir_lower_tex_options tex_options = { };
tex_options.lower_txp = ~0u; /* No equivalent for textureProj */
@ -957,26 +1030,41 @@ select_shader_variant(struct d3d12_selection_context *sel_ctx, d3d12_shader_sele
}
/* Add the needed in and outputs, and re-sort */
uint64_t mask = key.required_varying_inputs.mask & ~new_nir_variant->info.inputs_read;
if (prev) {
uint64_t mask = key.required_varying_inputs.mask & ~new_nir_variant->info.inputs_read;
while (mask) {
int slot = u_bit_scan64(&mask);
create_varying_from_info(new_nir_variant, &key.required_varying_inputs, slot, nir_var_shader_in);
create_varying_from_info(new_nir_variant, &key.required_varying_inputs, slot, nir_var_shader_in, false);
}
if (sel->stage == PIPE_SHADER_TESS_EVAL) {
uint32_t patch_mask = (uint32_t)key.ds.required_patch_inputs.mask & ~new_nir_variant->info.patch_inputs_read;
while (patch_mask) {
int slot = u_bit_scan(&patch_mask);
create_varying_from_info(new_nir_variant, &key.ds.required_patch_inputs, slot, nir_var_shader_in, true);
}
}
dxil_reassign_driver_locations(new_nir_variant, nir_var_shader_in,
key.prev_varying_outputs);
}
mask = key.required_varying_outputs.mask & ~new_nir_variant->info.outputs_written;
if (next) {
uint64_t mask = key.required_varying_outputs.mask & ~new_nir_variant->info.outputs_written;
while (mask) {
int slot = u_bit_scan64(&mask);
create_varying_from_info(new_nir_variant, &key.required_varying_outputs, slot, nir_var_shader_out);
create_varying_from_info(new_nir_variant, &key.required_varying_outputs, slot, nir_var_shader_out, false);
}
if (sel->stage == PIPE_SHADER_TESS_CTRL) {
uint32_t patch_mask = (uint32_t)key.hs.required_patch_outputs.mask & ~new_nir_variant->info.patch_outputs_written;
while (patch_mask) {
int slot = u_bit_scan(&patch_mask);
create_varying_from_info(new_nir_variant, &key.ds.required_patch_inputs, slot, nir_var_shader_out, true);
}
}
dxil_reassign_driver_locations(new_nir_variant, nir_var_shader_out,
key.next_varying_inputs);
key.next_varying_inputs);
}
d3d12_shader *new_variant = compile_nir(ctx, sel, &key, new_nir_variant);

View file

@ -70,6 +70,8 @@ struct d3d12_varying_info {
const struct glsl_type *type;
unsigned interpolation:3; // INTERP_MODE_COUNT = 5
unsigned driver_location:6; // VARYING_SLOT_MAX = 64
unsigned patch:1;
unsigned compact:1;
} vars[VARYING_SLOT_MAX];
uint64_t mask;
};
@ -109,6 +111,21 @@ struct d3d12_shader_key {
unsigned triangle_strip:1;
} gs;
struct {
unsigned primitive_mode:2;
unsigned ccw:1;
unsigned point_mode:1;
unsigned spacing:2;
struct d3d12_varying_info required_patch_outputs;
uint32_t next_patch_inputs;
} hs;
struct {
unsigned tcs_vertices_out;
struct d3d12_varying_info required_patch_inputs;
uint32_t prev_patch_outputs;
} ds;
struct {
unsigned missing_dual_src_outputs : 2;
unsigned frag_result_color_lowering : 4;