From b346f28453a97a34ebe3ed2fbfafff59482abd2a Mon Sep 17 00:00:00 2001 From: Jesse Natalie Date: Mon, 3 Jan 2022 06:20:25 -0800 Subject: [PATCH] microsoft/compiler: Emit HS PSV validation and entrypoint metadata Note that this requires the shader info "tess" data to be correct. For GLSL tess control shaders, only the output primitive count is automatically available. The rest will need to be either guessed or filled in from a matching tess eval (domain) shader. This is handled by the d3d12 driver in a later patch. Reviewed-by: Boris Brezillon Reviewed-by: Bill Kristiansen Part-of: --- src/microsoft/compiler/dxil_enums.h | 23 ++++++++ src/microsoft/compiler/dxil_module.c | 14 +++++ src/microsoft/compiler/dxil_module.h | 3 + src/microsoft/compiler/dxil_signature.h | 7 +++ src/microsoft/compiler/nir_to_dxil.c | 78 +++++++++++++++++++++++++ 5 files changed, 125 insertions(+) diff --git a/src/microsoft/compiler/dxil_enums.h b/src/microsoft/compiler/dxil_enums.h index 4ec0c42d190..17c69b3d3b3 100644 --- a/src/microsoft/compiler/dxil_enums.h +++ b/src/microsoft/compiler/dxil_enums.h @@ -316,6 +316,29 @@ enum dxil_sync_scope { DXIL_SYNC_SCOPE_CROSSTHREAD = 1, }; +enum dxil_tessellator_domain { + DXIL_TESSELLATOR_DOMAIN_UNDEFINED = 0, + DXIL_TESSELLATOR_DOMAIN_ISOLINE = 1, + DXIL_TESSELLATOR_DOMAIN_TRI = 2, + DXIL_TESSELLATOR_DOMAIN_QUAD = 3, +}; + +enum dxil_tessellator_output_primitive { + DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_UNDEFINED = 0, + DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_POINT = 1, + DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_LINE = 2, + DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_TRIANGLE_CW = 3, + DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_TRIANGLE_CCW = 4, +}; + +enum dxil_tessellator_partitioning { + DXIL_TESSELLATOR_PARTITIONING_UNDEFINED = 0, + DXIL_TESSELLATOR_PARTITIONING_INTEGER = 1, + DXIL_TESSELLATOR_PARTITIONING_POW2 = 2, + DXIL_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD = 3, + DXIL_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN = 4, +}; + #ifdef __cplusplus extern "C" { #endif diff --git a/src/microsoft/compiler/dxil_module.c b/src/microsoft/compiler/dxil_module.c index c5b4100630a..6ed223f47aa 100644 --- a/src/microsoft/compiler/dxil_module.c +++ b/src/microsoft/compiler/dxil_module.c @@ -2426,6 +2426,20 @@ dxil_get_metadata_int64(struct dxil_module *m, int64_t value) return dxil_get_metadata_value(m, type, const_value); } +const struct dxil_mdnode * +dxil_get_metadata_float32(struct dxil_module *m, float value) +{ + const struct dxil_type *type = get_float32_type(m); + if (!type) + return NULL; + + const struct dxil_value *const_value = dxil_module_get_float_const(m, value); + if (!const_value) + return NULL; + + return dxil_get_metadata_value(m, type, const_value); +} + bool dxil_add_metadata_named_node(struct dxil_module *m, const char *name, const struct dxil_mdnode *subnodes[], diff --git a/src/microsoft/compiler/dxil_module.h b/src/microsoft/compiler/dxil_module.h index 08021082099..7a60812e8a6 100644 --- a/src/microsoft/compiler/dxil_module.h +++ b/src/microsoft/compiler/dxil_module.h @@ -380,6 +380,9 @@ dxil_get_metadata_int32(struct dxil_module *m, int32_t value); const struct dxil_mdnode * dxil_get_metadata_int64(struct dxil_module *m, int64_t value); +const struct dxil_mdnode * +dxil_get_metadata_float32(struct dxil_module *m, float value); + const struct dxil_mdnode * dxil_get_metadata_node(struct dxil_module *m, const struct dxil_mdnode *subnodes[], diff --git a/src/microsoft/compiler/dxil_signature.h b/src/microsoft/compiler/dxil_signature.h index df8199883c9..4c523b82c02 100644 --- a/src/microsoft/compiler/dxil_signature.h +++ b/src/microsoft/compiler/dxil_signature.h @@ -85,6 +85,13 @@ struct dxil_psv_runtime_info_0 { char output_position_present; } vs; + struct { + uint32_t input_control_point_count; + uint32_t output_control_point_count; + uint32_t tessellator_domain; + uint32_t tessellator_output_primitive; + } hs; + struct { uint32_t input_primitive; uint32_t output_toplology; diff --git a/src/microsoft/compiler/nir_to_dxil.c b/src/microsoft/compiler/nir_to_dxil.c index 45b9e2cd0f3..d24f804e3c0 100644 --- a/src/microsoft/compiler/nir_to_dxil.c +++ b/src/microsoft/compiler/nir_to_dxil.c @@ -464,8 +464,10 @@ struct ntd_context { nir_variable *system_value[SYSTEM_VALUE_MAX]; nir_function *tess_ctrl_patch_constant_func; + unsigned tess_input_control_point_count; struct dxil_func_def *main_func_def; + struct dxil_func_def *tess_ctrl_patch_constant_func_def; }; static const char* @@ -1297,6 +1299,63 @@ emit_gs_state(struct ntd_context *ctx) return dxil_get_metadata_node(&ctx->mod, gs_state_nodes, ARRAY_SIZE(gs_state_nodes)); } +static enum dxil_tessellator_domain +get_tessellator_domain(enum tess_primitive_mode primitive_mode) +{ + switch (primitive_mode) { + case TESS_PRIMITIVE_QUADS: return DXIL_TESSELLATOR_DOMAIN_QUAD; + case TESS_PRIMITIVE_TRIANGLES: return DXIL_TESSELLATOR_DOMAIN_TRI; + case TESS_PRIMITIVE_ISOLINES: return DXIL_TESSELLATOR_DOMAIN_ISOLINE; + default: + unreachable("Invalid tessellator primitive mode"); + } +} + +static enum dxil_tessellator_partitioning +get_tessellator_partitioning(enum gl_tess_spacing spacing) +{ + switch (spacing) { + default: + case TESS_SPACING_EQUAL: + return DXIL_TESSELLATOR_PARTITIONING_INTEGER; + case TESS_SPACING_FRACTIONAL_EVEN: + return DXIL_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN; + case TESS_SPACING_FRACTIONAL_ODD: + return DXIL_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD; + } +} + +static enum dxil_tessellator_output_primitive +get_tessellator_output_primitive(const struct shader_info *info) +{ + if (info->tess.point_mode) + return DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_POINT; + if (info->tess._primitive_mode == TESS_PRIMITIVE_ISOLINES) + return DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_LINE; + /* Note: GL tessellation domain is inverted from D3D, which means triangle + * winding needs to be inverted. + */ + if (info->tess.ccw) + return DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_TRIANGLE_CW; + return DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_TRIANGLE_CCW; +} + +static const struct dxil_mdnode * +emit_hs_state(struct ntd_context *ctx) +{ + const struct dxil_mdnode *hs_state_nodes[7]; + + hs_state_nodes[0] = dxil_get_metadata_func(&ctx->mod, ctx->tess_ctrl_patch_constant_func_def->func); + hs_state_nodes[1] = dxil_get_metadata_int32(&ctx->mod, ctx->tess_input_control_point_count); + hs_state_nodes[2] = dxil_get_metadata_int32(&ctx->mod, ctx->shader->info.tess.tcs_vertices_out); + hs_state_nodes[3] = dxil_get_metadata_int32(&ctx->mod, get_tessellator_domain(ctx->shader->info.tess._primitive_mode)); + hs_state_nodes[4] = dxil_get_metadata_int32(&ctx->mod, get_tessellator_partitioning(ctx->shader->info.tess.spacing)); + hs_state_nodes[5] = dxil_get_metadata_int32(&ctx->mod, get_tessellator_output_primitive(&ctx->shader->info)); + hs_state_nodes[6] = dxil_get_metadata_float32(&ctx->mod, 64.0f); + + return dxil_get_metadata_node(&ctx->mod, hs_state_nodes, ARRAY_SIZE(hs_state_nodes)); +} + static const struct dxil_mdnode * emit_threads(struct ntd_context *ctx) { @@ -1465,6 +1524,17 @@ emit_metadata(struct ntd_context *ctx) if (ctx->mod.shader_kind == DXIL_GEOMETRY_SHADER) { if (!emit_tag(ctx, DXIL_SHADER_TAG_GS_STATE, emit_gs_state(ctx))) return false; + } else if (ctx->mod.shader_kind == DXIL_HULL_SHADER) { + ctx->tess_input_control_point_count = 32; + nir_foreach_variable_with_modes(var, ctx->shader, nir_var_shader_in) { + if (nir_is_arrayed_io(var, MESA_SHADER_TESS_CTRL)) { + ctx->tess_input_control_point_count = glsl_array_size(var->type); + break; + } + } + + if (!emit_tag(ctx, DXIL_SHADER_TAG_HS_STATE, emit_hs_state(ctx))) + return false; } else if (ctx->mod.shader_kind == DXIL_COMPUTE_SHADER) { if (!emit_tag(ctx, DXIL_SHADER_TAG_NUM_THREADS, emit_threads(ctx))) return false; @@ -4898,6 +4968,8 @@ emit_function(struct ntd_context *ctx, nir_function *func) if (func->is_entrypoint) ctx->main_func_def = func_def; + else if (func == ctx->tess_ctrl_patch_constant_func) + ctx->tess_ctrl_patch_constant_func_def = func_def; ctx->defs = rzalloc_array(ctx->ralloc_ctx, struct dxil_def, impl->ssa_alloc); if (!ctx->defs) @@ -5196,6 +5268,12 @@ void dxil_fill_validation_state(struct ntd_context *ctx, state->state.psv0.gs.output_stream_mask = MAX2(ctx->shader->info.gs.active_stream_mask, 1); state->state.psv0.gs.output_position_present = ctx->mod.info.has_out_position; break; + case DXIL_HULL_SHADER: + state->state.psv0.hs.input_control_point_count = ctx->tess_input_control_point_count; + state->state.psv0.hs.output_control_point_count = ctx->shader->info.tess.tcs_vertices_out; + state->state.psv0.hs.tessellator_domain = get_tessellator_domain(ctx->shader->info.tess._primitive_mode); + state->state.psv0.hs.tessellator_output_primitive = get_tessellator_output_primitive(&ctx->shader->info); + break; default: assert(0 && "Shader type not (yet) supported"); }