vkd3d-shader/hlsl: Validate and record InputPatch/OutputPatch types.

This commit is contained in:
Shaun Ren
2025-01-20 15:39:31 -05:00
committed by Henri Verbeet
parent f4d5e05d96
commit f064a4022a
Notes: Henri Verbeet 2025-01-29 18:04:29 +01:00
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Francisco Casas (@fcasas)
Approved-by: Elizabeth Figura (@zfigura)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1355
4 changed files with 141 additions and 5 deletions

View File

@@ -4581,6 +4581,7 @@ static bool hlsl_ctx_init(struct hlsl_ctx *ctx, const struct vkd3d_shader_compil
ctx->output_control_point_count = UINT_MAX;
ctx->output_primitive = 0;
ctx->partitioning = 0;
ctx->input_control_point_count = UINT_MAX;
return true;
}

View File

@@ -1155,11 +1155,30 @@ struct hlsl_ctx
* compute shader profiles. It is set using the numthreads() attribute in the entry point. */
uint32_t thread_count[3];
/* Declared information in tessellation shaders.
*
* The following fields are specific to hull shaders: output_control_point_count,
* output_control_point_type, output_primitive, partitioning, and patch_constant_func.
*
* The output_control_point_count and output_control_point_type fields correspond to the return
* type and the "outputcontrolpoints" attribute of a hull shader's control point function,
* respectively. Moreover, if an OutputPatch parameter is declared in the hull shader's patch
* constant function, its type and element count must match these fields.
*
* The input_control_point_count and input_control_point_type fields are specified by the
* InputPatch parameter in hull shaders, or by the _OutputPatch_ parameter in domain
* shaders.
*
* For input_ and output_control_point_count, the value UINT_MAX indicates that the value is
* unknown or not set by the shader. */
enum vkd3d_tessellator_domain domain;
unsigned int output_control_point_count;
struct hlsl_type *output_control_point_type;
enum vkd3d_shader_tessellator_output_primitive output_primitive;
enum vkd3d_shader_tessellator_partitioning partitioning;
struct hlsl_ir_function_decl *patch_constant_func;
unsigned int input_control_point_count;
struct hlsl_type *input_control_point_type;
/* In some cases we generate opcodes by parsing an HLSL function and then
* invoking it. If not NULL, this field is the name of the function that we

View File

@@ -6810,6 +6810,77 @@ static void validate_hull_shader_attributes(struct hlsl_ctx *ctx, const struct h
}
}
static void validate_and_record_patch_type(struct hlsl_ctx *ctx, bool is_patch_constant_func, struct hlsl_ir_var *var)
{
unsigned int control_point_count = var->data_type->e.array.elements_count;
enum hlsl_array_type array_type = var->data_type->e.array.array_type;
struct hlsl_type *control_point_type = var->data_type->e.array.type;
const struct hlsl_profile_info *profile = ctx->profile;
if (array_type == HLSL_ARRAY_PATCH_INPUT)
{
if (profile->type != VKD3D_SHADER_TYPE_HULL
&& !(profile->type == VKD3D_SHADER_TYPE_GEOMETRY && hlsl_version_ge(ctx, 5, 0)))
{
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INCOMPATIBLE_PROFILE,
"InputPatch parameters can only be used in hull shaders, "
"and geometry shaders with shader model 5.0 or higher.");
return;
}
}
else
{
if (!is_patch_constant_func && profile->type != VKD3D_SHADER_TYPE_DOMAIN)
{
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INCOMPATIBLE_PROFILE,
"OutputPatch parameters can only be used in "
"hull shader patch constant functions and domain shaders.");
return;
}
}
if (control_point_count > 32)
{
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_CONTROL_POINT_COUNT,
"Control point count %u exceeds 32.", control_point_count);
return;
}
VKD3D_ASSERT(control_point_count > 0);
if (is_patch_constant_func && array_type == HLSL_ARRAY_PATCH_OUTPUT)
{
if (control_point_count != ctx->output_control_point_count)
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_CONTROL_POINT_COUNT,
"Output control point count %u does not match the count %u specified in the control point function.",
control_point_count, ctx->output_control_point_count);
if (!hlsl_types_are_equal(control_point_type, ctx->output_control_point_type))
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
"Output control point type does not match the output type of the control point function.");
return;
}
if (ctx->input_control_point_count != UINT_MAX)
{
VKD3D_ASSERT(is_patch_constant_func);
if (control_point_count != ctx->input_control_point_count)
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_CONTROL_POINT_COUNT,
"Input control point count %u does not match the count %u specified in the control point function.",
control_point_count, ctx->input_control_point_count);
if (!hlsl_types_are_equal(control_point_type, ctx->input_control_point_type))
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
"Input control point type does not match the input type specified in the control point function.");
return;
}
ctx->input_control_point_count = control_point_count;
ctx->input_control_point_type = control_point_type;
}
static void remove_unreachable_code(struct hlsl_ctx *ctx, struct hlsl_block *body)
{
struct hlsl_ir_node *instr, *next;
@@ -10917,7 +10988,8 @@ static void sm4_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl
}
else if (version.type == VKD3D_SHADER_TYPE_HULL)
{
program->input_control_point_count = 1; /* TODO: Obtain from InputPatch */
program->input_control_point_count = ctx->input_control_point_count == UINT_MAX
? 1 : ctx->input_control_point_count;
program->output_control_point_count = ctx->output_control_point_count;
program->tess_domain = ctx->domain;
program->tess_partitioning = ctx->partitioning;
@@ -10925,7 +10997,8 @@ static void sm4_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl
}
else if (version.type == VKD3D_SHADER_TYPE_DOMAIN)
{
program->input_control_point_count = 0; /* TODO: Obtain from OutputPatch */
program->input_control_point_count = ctx->input_control_point_count == UINT_MAX
? 0 : ctx->input_control_point_count;
program->tess_domain = ctx->domain;
}
@@ -12134,6 +12207,8 @@ static bool lower_isinf(struct hlsl_ctx *ctx, struct hlsl_ir_node *node, struct
static void process_entry_function(struct hlsl_ctx *ctx,
const struct hlsl_block *global_uniform_block, struct hlsl_ir_function_decl *entry_func)
{
bool is_patch_constant_func = entry_func == ctx->patch_constant_func;
const struct hlsl_ir_var *input_patch = NULL, *output_patch = NULL;
const struct hlsl_profile_info *profile = ctx->profile;
struct hlsl_block static_initializers, global_uniforms;
struct hlsl_block *const body = &entry_func->body;
@@ -12184,7 +12259,7 @@ static void process_entry_function(struct hlsl_ctx *ctx,
}
else if ((var->storage_modifiers & HLSL_STORAGE_UNIFORM))
{
if (ctx->profile->type == VKD3D_SHADER_TYPE_HULL && entry_func == ctx->patch_constant_func)
if (ctx->profile->type == VKD3D_SHADER_TYPE_HULL && is_patch_constant_func)
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_MODIFIER,
"Patch constant function parameter \"%s\" cannot be uniform.", var->name);
else
@@ -12192,7 +12267,33 @@ static void process_entry_function(struct hlsl_ctx *ctx,
}
else if (hlsl_type_is_patch_array(var->data_type))
{
hlsl_fixme(ctx, &var->loc, "InputPatch/OutputPatch function parameters.");
if (var->data_type->e.array.array_type == HLSL_ARRAY_PATCH_INPUT)
{
if (input_patch)
{
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_DUPLICATE_PATCH,
"Found multiple InputPatch parameters.");
hlsl_note(ctx, &input_patch->loc, VKD3D_SHADER_LOG_ERROR,
"The InputPatch parameter was previously declared here.");
continue;
}
input_patch = var;
}
else
{
if (output_patch)
{
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_DUPLICATE_PATCH,
"Found multiple OutputPatch parameters.");
hlsl_note(ctx, &output_patch->loc, VKD3D_SHADER_LOG_ERROR,
"The OutputPatch parameter was previously declared here.");
continue;
}
output_patch = var;
}
validate_and_record_patch_type(ctx, is_patch_constant_func, var);
hlsl_fixme(ctx, &var->loc, "InputPatch/OutputPatch parameters.");
}
else
{
@@ -12207,7 +12308,13 @@ static void process_entry_function(struct hlsl_ctx *ctx,
if (var->storage_modifiers & HLSL_STORAGE_IN)
prepend_input_var_copy(ctx, entry_func, var);
if (var->storage_modifiers & HLSL_STORAGE_OUT)
append_output_var_copy(ctx, entry_func, var);
{
if (profile->type == VKD3D_SHADER_TYPE_HULL && !is_patch_constant_func)
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_MODIFIER,
"Output parameters are not supported in hull shader control point functions.");
else
append_output_var_copy(ctx, entry_func, var);
}
}
}
if (entry_func->return_var)
@@ -12217,6 +12324,14 @@ static void process_entry_function(struct hlsl_ctx *ctx,
"Entry point \"%s\" is missing a return value semantic.", entry_func->func->name);
append_output_var_copy(ctx, entry_func, entry_func->return_var);
if (profile->type == VKD3D_SHADER_TYPE_HULL && !is_patch_constant_func)
ctx->output_control_point_type = entry_func->return_var->data_type;
}
else
{
if (profile->type == VKD3D_SHADER_TYPE_HULL && !is_patch_constant_func)
hlsl_fixme(ctx, &entry_func->loc, "Passthrough hull shader control point function.");
}
if (hlsl_version_ge(ctx, 4, 0))

View File

@@ -166,6 +166,7 @@ enum vkd3d_shader_error
VKD3D_SHADER_ERROR_HLSL_INVALID_PARTITIONING = 5038,
VKD3D_SHADER_ERROR_HLSL_MISPLACED_SAMPLER_STATE = 5039,
VKD3D_SHADER_ERROR_HLSL_AMBIGUOUS_CALL = 5040,
VKD3D_SHADER_ERROR_HLSL_DUPLICATE_PATCH = 5041,
VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION = 5300,
VKD3D_SHADER_WARNING_HLSL_DIVISION_BY_ZERO = 5301,