d3d12: Handle passthrough TCS in the case where eval is bound

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-03 12:49:28 -08:00 committed by Marge Bot
parent 224c1562c1
commit de438f381f
9 changed files with 246 additions and 14 deletions

View file

@ -354,7 +354,7 @@ fill_mode_lowered(struct d3d12_context *ctx, const struct pipe_draw_info *dinfo)
struct d3d12_shader_selector *vs = ctx->gfx_stages[PIPE_SHADER_VERTEX];
if ((ctx->gfx_stages[PIPE_SHADER_GEOMETRY] != NULL &&
!ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->is_gs_variant) ||
!ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->is_variant) ||
ctx->gfx_pipeline_state.rast == NULL ||
(dinfo->mode != PIPE_PRIM_TRIANGLES &&
dinfo->mode != PIPE_PRIM_TRIANGLE_STRIP))
@ -394,7 +394,7 @@ needs_point_sprite_lowering(struct d3d12_context *ctx, const struct pipe_draw_in
struct d3d12_shader_selector *vs = ctx->gfx_stages[PIPE_SHADER_VERTEX];
struct d3d12_shader_selector *gs = ctx->gfx_stages[PIPE_SHADER_GEOMETRY];
if (gs != NULL && !gs->is_gs_variant) {
if (gs != NULL && !gs->is_variant) {
/* There is an user GS; Check if it outputs points with PSIZE */
return (gs->initial->info.gs.output_primitive == GL_POINTS &&
(gs->initial->info.outputs_written & VARYING_BIT_PSIZ ||
@ -417,7 +417,7 @@ static unsigned
cull_mode_lowered(struct d3d12_context *ctx, unsigned fill_mode)
{
if ((ctx->gfx_stages[PIPE_SHADER_GEOMETRY] != NULL &&
!ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->is_gs_variant) ||
!ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->is_variant) ||
ctx->gfx_pipeline_state.rast == NULL ||
ctx->gfx_pipeline_state.rast->base.cull_face == PIPE_FACE_NONE)
return PIPE_FACE_NONE;
@ -435,7 +435,7 @@ get_provoking_vertex(struct d3d12_selection_context *sel_ctx, bool *alternate, c
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;
struct d3d12_shader_selector *last_vertex_stage = gs && !gs->is_variant ? gs : vs;
/* Make sure GL prims match Gallium prims */
STATIC_ASSERT(GL_POINTS == PIPE_PRIM_POINTS);
@ -457,7 +457,7 @@ get_provoking_vertex(struct d3d12_selection_context *sel_ctx, bool *alternate, c
bool flatshade_first = sel_ctx->ctx->gfx_pipeline_state.rast &&
sel_ctx->ctx->gfx_pipeline_state.rast->base.flatshade_first;
*alternate = (mode == GL_TRIANGLE_STRIP || mode == GL_TRIANGLE_STRIP_ADJACENCY) &&
(!gs || gs->is_gs_variant ||
(!gs || gs->is_variant ||
gs->initial->info.gs.vertices_out > u_prim_vertex_count(mode)->min);
return flatshade_first ? 0 : u_prim_vertex_count(mode)->min - 1;
}
@ -580,7 +580,7 @@ validate_geometry_shader_variant(struct d3d12_selection_context *sel_ctx)
d3d12_shader_selector *gs = ctx->gfx_stages[PIPE_SHADER_GEOMETRY];
/* Nothing to do if there is a user geometry shader bound */
if (gs != NULL && !gs->is_gs_variant)
if (gs != NULL && !gs->is_variant)
return;
/* Fill the geometry shader variant key */
@ -619,6 +619,37 @@ validate_geometry_shader_variant(struct d3d12_selection_context *sel_ctx)
ctx->gfx_stages[PIPE_SHADER_GEOMETRY] = gs;
}
static void
validate_tess_ctrl_shader_variant(struct d3d12_selection_context *sel_ctx)
{
struct d3d12_context *ctx = sel_ctx->ctx;
d3d12_shader_selector *vs = ctx->gfx_stages[PIPE_SHADER_VERTEX];
d3d12_shader_selector *tcs = ctx->gfx_stages[PIPE_SHADER_TESS_CTRL];
d3d12_shader_selector *tes = ctx->gfx_stages[PIPE_SHADER_TESS_EVAL];
struct d3d12_tcs_variant_key key = {0};
/* Nothing to do if there is a user tess ctrl shader bound */
if (tcs != NULL && !tcs->is_variant)
return;
bool variant_needed = tes != nullptr;
/* Fill the variant key */
if (variant_needed) {
fill_varyings(&key.varyings, vs->initial, nir_var_shader_out,
vs->initial->info.outputs_written, false);
key.vertices_out = ctx->patch_vertices;
}
/* Check if the currently bound tessellation control shader variant is correct */
if (tcs && memcmp(&tcs->tcs_key, &key, sizeof(key)) == 0)
return;
/* Find/create the proper variant and bind it */
tcs = variant_needed ? d3d12_get_tcs_variant(ctx, &key) : NULL;
ctx->gfx_stages[PIPE_SHADER_TESS_CTRL] = tcs;
}
static bool
d3d12_compare_shader_keys(const d3d12_shader_key *expect, const d3d12_shader_key *have)
{
@ -779,7 +810,7 @@ d3d12_fill_shader_key(struct d3d12_selection_context *sel_ctx,
/* We require as outputs what the next stage reads,
* except certain system values */
if (next) {
if (!next->is_gs_variant) {
if (!next->is_variant) {
if (stage == PIPE_SHADER_VERTEX)
system_generated_in_values |= VARYING_BIT_POS;
uint64_t mask = next->current->nir->info.inputs_read & ~system_generated_in_values;
@ -819,11 +850,11 @@ d3d12_fill_shader_key(struct d3d12_selection_context *sel_ctx,
key->gs.stream_output_factor = 6;
} else if (sel_ctx->fill_mode_lowered == PIPE_POLYGON_MODE_LINE) {
key->gs.stream_output_factor = 2;
} else if (sel_ctx->needs_vertex_reordering && !sel->is_gs_variant) {
} else if (sel_ctx->needs_vertex_reordering && !sel->is_variant) {
key->gs.triangle_strip = 1;
}
if (sel->is_gs_variant && next && next->initial->info.inputs_read & VARYING_BIT_PRIMITIVE_ID)
if (sel->is_variant && next && next->initial->info.inputs_read & VARYING_BIT_PRIMITIVE_ID)
key->gs.primitive_id = 1;
} else if (stage == PIPE_SHADER_FRAGMENT) {
key->fs.missing_dual_src_outputs = sel_ctx->missing_dual_src_outputs;
@ -901,7 +932,7 @@ d3d12_fill_shader_key(struct d3d12_selection_context *sel_ctx,
if (stage == PIPE_SHADER_FRAGMENT &&
sel_ctx->ctx->gfx_stages[PIPE_SHADER_GEOMETRY] &&
sel_ctx->ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->is_gs_variant &&
sel_ctx->ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->is_variant &&
sel_ctx->ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->gs_key.has_front_face) {
key->fs.remap_front_facing = 1;
}
@ -1338,6 +1369,7 @@ d3d12_select_shader_variants(struct d3d12_context *ctx, const struct pipe_draw_i
sel_ctx.manual_depth_range = manual_depth_range(ctx);
validate_geometry_shader_variant(&sel_ctx);
validate_tess_ctrl_shader_variant(&sel_ctx);
for (unsigned i = 0; i < ARRAY_SIZE(order); ++i) {
auto sel = ctx->gfx_stages[order[i]];

View file

@ -45,6 +45,8 @@ enum d3d12_state_var {
D3D12_STATE_VAR_PT_SPRITE,
D3D12_STATE_VAR_DRAW_PARAMS,
D3D12_STATE_VAR_DEPTH_TRANSFORM,
D3D12_STATE_VAR_DEFAULT_INNER_TESS_LEVEL,
D3D12_STATE_VAR_DEFAULT_OUTER_TESS_LEVEL,
D3D12_MAX_GRAPHICS_STATE_VARS,
D3D12_STATE_VAR_NUM_WORKGROUPS = 0,
@ -203,6 +205,12 @@ struct d3d12_gs_variant_key
struct d3d12_varying_info varyings;
};
struct d3d12_tcs_variant_key
{
unsigned vertices_out;
struct d3d12_varying_info varyings;
};
struct d3d12_shader_selector {
enum pipe_shader_type stage;
nir_shader *initial;
@ -215,8 +223,11 @@ struct d3d12_shader_selector {
unsigned compare_with_lod_bias_grad:1;
unsigned workgroup_size_variable:1;
bool is_gs_variant;
bool is_variant;
union {
struct d3d12_gs_variant_key gs_key;
struct d3d12_tcs_variant_key tcs_key;
};
};
struct d3d12_context;
@ -250,6 +261,15 @@ d3d12_gs_variant_cache_destroy(struct d3d12_context *ctx);
struct d3d12_shader_selector *
d3d12_get_gs_variant(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key);
void
d3d12_tcs_variant_cache_init(struct d3d12_context *ctx);
void
d3d12_tcs_variant_cache_destroy(struct d3d12_context *ctx);
struct d3d12_shader_selector *
d3d12_get_tcs_variant(struct d3d12_context *ctx, struct d3d12_tcs_variant_key *key);
#ifdef __cplusplus
}
#endif

View file

@ -2272,6 +2272,16 @@ d3d12_set_patch_vertices(struct pipe_context *pctx, uint8_t patch_vertices)
ctx->cmdlist_dirty |= D3D12_DIRTY_PRIM_MODE;
}
static void
d3d12_set_tess_state(struct pipe_context *pctx,
const float default_outer_level[4],
const float default_inner_level[2])
{
struct d3d12_context *ctx = d3d12_context(pctx);
memcpy(ctx->default_outer_tess_factor, default_outer_level, sizeof(ctx->default_outer_tess_factor));
memcpy(ctx->default_inner_tess_factor, default_inner_level, sizeof(ctx->default_inner_tess_factor));
}
struct pipe_context *
d3d12_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
{
@ -2331,6 +2341,7 @@ d3d12_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
ctx->base.delete_tes_state = d3d12_delete_tes_state;
ctx->base.set_patch_vertices = d3d12_set_patch_vertices;
ctx->base.set_tess_state = d3d12_set_tess_state;
ctx->base.create_compute_state = d3d12_create_compute_state;
ctx->base.bind_compute_state = d3d12_bind_compute_state;
@ -2404,6 +2415,7 @@ d3d12_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
d3d12_root_signature_cache_init(ctx);
d3d12_cmd_signature_cache_init(ctx);
d3d12_gs_variant_cache_init(ctx);
d3d12_tcs_variant_cache_init(ctx);
d3d12_compute_transform_cache_init(ctx);
util_dl_library *d3d12_mod = util_dl_open(UTIL_DL_PREFIX "d3d12" UTIL_DL_EXT);

View file

@ -173,6 +173,7 @@ struct d3d12_context {
struct hash_table *root_signature_cache;
struct hash_table *cmd_signature_cache;
struct hash_table *gs_variant_cache;
struct hash_table *tcs_variant_cache;
struct hash_table *compute_transform_cache;
struct d3d12_batch batches[4];
@ -222,6 +223,8 @@ struct d3d12_context {
D3D12_STREAM_OUTPUT_BUFFER_VIEW fake_so_buffer_views[PIPE_MAX_SO_BUFFERS];
unsigned fake_so_buffer_factor;
uint8_t patch_vertices;
float default_outer_tess_factor[4];
float default_inner_tess_factor[2];
struct d3d12_shader_selector *gfx_stages[D3D12_GFX_SHADER_STAGES];
struct d3d12_shader_selector *compute_state;

View file

@ -380,6 +380,14 @@ fill_graphics_state_vars(struct d3d12_context *ctx,
ptr[1] = fui(ctx->viewport_states[0].translate[2] - ctx->viewport_states[0].scale[2]);
size += 4;
break;
case D3D12_STATE_VAR_DEFAULT_INNER_TESS_LEVEL:
memcpy(ptr, ctx->default_inner_tess_factor, sizeof(ctx->default_inner_tess_factor));
size += 4;
break;
case D3D12_STATE_VAR_DEFAULT_OUTER_TESS_LEVEL:
memcpy(ptr, ctx->default_outer_tess_factor, sizeof(ctx->default_outer_tess_factor));
size += 4;
break;
default:
unreachable("unknown state variable");
}
@ -706,7 +714,7 @@ static inline struct d3d12_shader_selector *
d3d12_last_vertex_stage(struct d3d12_context *ctx)
{
struct d3d12_shader_selector *sel = ctx->gfx_stages[PIPE_SHADER_GEOMETRY];
if (!sel || sel->is_gs_variant)
if (!sel || sel->is_variant)
sel = ctx->gfx_stages[PIPE_SHADER_TESS_EVAL];
if (!sel)
sel = ctx->gfx_stages[PIPE_SHADER_VERTEX];

View file

@ -466,7 +466,7 @@ create_geometry_shader_variant(struct d3d12_context *ctx, struct d3d12_gs_varian
gs = d3d12_emit_lines(ctx, key);
if (gs) {
gs->is_gs_variant = true;
gs->is_variant = true;
gs->gs_key = *key;
}

View file

@ -35,6 +35,13 @@ struct d3d12_shader;
struct d3d12_image_format_conversion_info;
enum d3d12_state_var;
nir_ssa_def *
d3d12_get_state_var(nir_builder *b,
enum d3d12_state_var var_enum,
const char *var_name,
const struct glsl_type *var_type,
nir_variable **out_var);
nir_ssa_def *
d3d12_get_state_var(nir_builder *b,
enum d3d12_state_var var_enum,

View file

@ -0,0 +1,149 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "nir.h"
#include "nir_builder.h"
#include "d3d12_context.h"
#include "d3d12_compiler.h"
#include "d3d12_nir_passes.h"
#include "nir_to_dxil.h"
static uint32_t
hash_tcs_variant_key(const void *key)
{
return _mesa_hash_data(key, sizeof(struct d3d12_tcs_variant_key));
}
static bool
equals_tcs_variant_key(const void *a, const void *b)
{
return memcmp(a, b, sizeof(struct d3d12_tcs_variant_key)) == 0;
}
void
d3d12_tcs_variant_cache_init(struct d3d12_context *ctx)
{
ctx->tcs_variant_cache = _mesa_hash_table_create(NULL, NULL, equals_tcs_variant_key);
}
static void
delete_entry(struct hash_entry *entry)
{
d3d12_shader_free((d3d12_shader_selector *)entry->data);
}
void
d3d12_tcs_variant_cache_destroy(struct d3d12_context *ctx)
{
_mesa_hash_table_destroy(ctx->tcs_variant_cache, delete_entry);
}
static struct d3d12_shader_selector *
create_tess_ctrl_shader_variant(struct d3d12_context *ctx, struct d3d12_tcs_variant_key *key)
{
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_TESS_CTRL, dxil_get_nir_compiler_options(), "passthrough");
nir_shader *nir = b.shader;
nir_ssa_def *invocation_id = nir_load_invocation_id(&b);
uint64_t varying_mask = key->varyings.mask;
while(varying_mask) {
int var_idx = u_bit_scan64(&varying_mask);
auto var = &key->varyings.vars[var_idx];
const struct glsl_type *type = var->type;
const struct glsl_type *in_type = var->type;
const struct glsl_type *out_type = var->type;
in_type = glsl_array_type(type, key->vertices_out, 0);
out_type = glsl_array_type(type, key->vertices_out, 0);
char buf[1024];
snprintf(buf, sizeof(buf), "in_%d", var->driver_location);
nir_variable *in = nir_variable_create(nir, nir_var_shader_in, in_type, buf);
snprintf(buf, sizeof(buf), "out_%d", var->driver_location);
nir_variable *out = nir_variable_create(nir, nir_var_shader_out, out_type, buf);
out->data.location = in->data.location = var_idx;
out->data.driver_location = in->data.driver_location = var->driver_location;
for (unsigned i = 0; i < key->vertices_out; i++) {
nir_if *start_block = nir_push_if(&b, nir_ieq(&b, invocation_id, nir_imm_int(&b, i)));
nir_deref_instr *in_array_var = nir_build_deref_array(&b, nir_build_deref_var(&b, in), invocation_id);
nir_ssa_def *load = nir_load_deref(&b, in_array_var);
nir_deref_instr *out_array_var = nir_build_deref_array_imm(&b, nir_build_deref_var(&b, out), i);
nir_store_deref(&b, out_array_var, load, 0xff);
nir_pop_if(&b, start_block);
}
}
nir_variable *gl_TessLevelInner = nir_variable_create(nir, nir_var_shader_out, glsl_array_type(glsl_float_type(), 2, 0), "gl_TessLevelInner");
gl_TessLevelInner->data.location = VARYING_SLOT_TESS_LEVEL_INNER;
gl_TessLevelInner->data.patch = 1;
gl_TessLevelInner->data.compact = 1;
nir_variable *gl_TessLevelOuter = nir_variable_create(nir, nir_var_shader_out, glsl_array_type(glsl_float_type(), 4, 0), "gl_TessLevelOuter");
gl_TessLevelOuter->data.location = VARYING_SLOT_TESS_LEVEL_OUTER;
gl_TessLevelOuter->data.patch = 1;
gl_TessLevelOuter->data.compact = 1;
nir_variable *state_var_inner = NULL, *state_var_outer = NULL;
nir_ssa_def *load_inner = d3d12_get_state_var(&b, D3D12_STATE_VAR_DEFAULT_INNER_TESS_LEVEL, "d3d12_TessLevelInner", glsl_vec_type(2), &state_var_inner);
nir_ssa_def *load_outer = d3d12_get_state_var(&b, D3D12_STATE_VAR_DEFAULT_OUTER_TESS_LEVEL, "d3d12_TessLevelOuter", glsl_vec4_type(), &state_var_outer);
for (unsigned i = 0; i < 2; i++) {
nir_deref_instr *store_idx = nir_build_deref_array_imm(&b, nir_build_deref_var(&b, gl_TessLevelInner), i);
nir_store_deref(&b, store_idx, nir_channel(&b, load_inner, i), 0xff);
}
for (unsigned i = 0; i < 4; i++) {
nir_deref_instr *store_idx = nir_build_deref_array_imm(&b, nir_build_deref_var(&b, gl_TessLevelOuter), i);
nir_store_deref(&b, store_idx, nir_channel(&b, load_outer, i), 0xff);
}
nir->info.tess.tcs_vertices_out = key->vertices_out;
nir_validate_shader(nir, "created");
struct pipe_shader_state templ;
templ.type = PIPE_SHADER_IR_NIR;
templ.ir.nir = nir;
templ.stream_output.num_outputs = 0;
d3d12_shader_selector *tcs = d3d12_create_shader(ctx, PIPE_SHADER_TESS_CTRL, &templ);
if (tcs) {
tcs->is_variant = true;
memcpy(&tcs->tcs_key, key, sizeof(*key));
}
return tcs;
}
d3d12_shader_selector *
d3d12_get_tcs_variant(struct d3d12_context *ctx, struct d3d12_tcs_variant_key *key)
{
uint32_t hash = hash_tcs_variant_key(key);
struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ctx->tcs_variant_cache,
hash, key);
if (!entry) {
d3d12_shader_selector *tcs = create_tess_ctrl_shader_variant(ctx, key);
entry = _mesa_hash_table_insert_pre_hashed(ctx->tcs_variant_cache,
hash, &tcs->tcs_key, tcs);
assert(entry);
}
return (d3d12_shader_selector *)entry->data;
}

View file

@ -45,6 +45,7 @@ files_libd3d12 = files(
'd3d12_root_signature.cpp',
'd3d12_screen.cpp',
'd3d12_surface.cpp',
'd3d12_tcs_variant.cpp',
)
if host_machine.system() == 'windows'