mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2024-09-13 09:16:14 -07:00
vkd3d-shader/hlsl: Support default values for function parameters.
This commit is contained in:
parent
29699d3d22
commit
49caeee1fd
Notes:
Henri Verbeet
2024-07-23 15:43:19 +02:00
Approved-by: Francisco Casas (@fcasas) Approved-by: Elizabeth Figura (@zfigura) Approved-by: Henri Verbeet (@hverbeet) Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/942
@ -34,6 +34,14 @@ struct parse_fields
|
||||
size_t count, capacity;
|
||||
};
|
||||
|
||||
struct parse_initializer
|
||||
{
|
||||
struct hlsl_ir_node **args;
|
||||
unsigned int args_count;
|
||||
struct hlsl_block *instrs;
|
||||
bool braces;
|
||||
};
|
||||
|
||||
struct parse_parameter
|
||||
{
|
||||
struct hlsl_type *type;
|
||||
@ -41,6 +49,7 @@ struct parse_parameter
|
||||
struct hlsl_semantic semantic;
|
||||
struct hlsl_reg_reservation reg_reservation;
|
||||
uint32_t modifiers;
|
||||
struct parse_initializer initializer;
|
||||
};
|
||||
|
||||
struct parse_colon_attribute
|
||||
@ -49,14 +58,6 @@ struct parse_colon_attribute
|
||||
struct hlsl_reg_reservation reg_reservation;
|
||||
};
|
||||
|
||||
struct parse_initializer
|
||||
{
|
||||
struct hlsl_ir_node **args;
|
||||
unsigned int args_count;
|
||||
struct hlsl_block *instrs;
|
||||
bool braces;
|
||||
};
|
||||
|
||||
struct parse_array_sizes
|
||||
{
|
||||
uint32_t *sizes; /* innermost first */
|
||||
@ -1189,6 +1190,9 @@ static bool add_typedef(struct hlsl_ctx *ctx, struct hlsl_type *const orig_type,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *instrs,
|
||||
struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src);
|
||||
|
||||
static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters *parameters,
|
||||
struct parse_parameter *param, const struct vkd3d_shader_location *loc)
|
||||
{
|
||||
@ -1205,11 +1209,52 @@ static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters
|
||||
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
|
||||
"packoffset() is not allowed on function parameters.");
|
||||
|
||||
if (parameters->count && parameters->vars[parameters->count - 1]->default_values
|
||||
&& !param->initializer.args_count)
|
||||
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_MISSING_INITIALIZER,
|
||||
"Missing default value for parameter '%s'.", param->name);
|
||||
|
||||
if (param->initializer.args_count && (param->modifiers & HLSL_STORAGE_OUT))
|
||||
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_MODIFIER,
|
||||
"Output parameter '%s' has a default value.", param->name);
|
||||
|
||||
if (!(var = hlsl_new_var(ctx, param->name, param->type, loc, ¶m->semantic, param->modifiers,
|
||||
¶m->reg_reservation)))
|
||||
return false;
|
||||
var->is_param = 1;
|
||||
|
||||
if (param->initializer.args_count)
|
||||
{
|
||||
unsigned int component_count = hlsl_type_component_count(param->type);
|
||||
unsigned int store_index = 0;
|
||||
unsigned int size, i;
|
||||
|
||||
if (!(var->default_values = hlsl_calloc(ctx, component_count, sizeof(*var->default_values))))
|
||||
return false;
|
||||
|
||||
if (!param->initializer.braces)
|
||||
{
|
||||
if (!(add_implicit_conversion(ctx, param->initializer.instrs, param->initializer.args[0], param->type, loc)))
|
||||
return false;
|
||||
|
||||
param->initializer.args[0] = node_from_block(param->initializer.instrs);
|
||||
}
|
||||
|
||||
size = initializer_size(¶m->initializer);
|
||||
if (component_count != size)
|
||||
{
|
||||
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT,
|
||||
"Expected %u components in initializer, but got %u.", component_count, size);
|
||||
}
|
||||
|
||||
for (i = 0; i < param->initializer.args_count; ++i)
|
||||
{
|
||||
initialize_var_components(ctx, param->initializer.instrs, var, &store_index, param->initializer.args[i]);
|
||||
}
|
||||
|
||||
free_parse_initializer(¶m->initializer);
|
||||
}
|
||||
|
||||
if (!hlsl_add_var(ctx, var, false))
|
||||
{
|
||||
hlsl_free_var(var);
|
||||
@ -2227,7 +2272,9 @@ static bool add_increment(struct hlsl_ctx *ctx, struct hlsl_block *block, bool d
|
||||
/* For some reason, for matrices, values from default value initializers end up in different
|
||||
* components than from regular initializers. Default value initializers fill the matrix in
|
||||
* vertical reading order (left-to-right top-to-bottom) instead of regular reading order
|
||||
* (top-to-bottom left-to-right), so they have to be adjusted. */
|
||||
* (top-to-bottom left-to-right), so they have to be adjusted.
|
||||
* An exception is that the order of matrix initializers for function parameters are row-major
|
||||
* (top-to-bottom left-to-right). */
|
||||
static unsigned int get_component_index_from_default_initializer_index(struct hlsl_ctx *ctx,
|
||||
struct hlsl_type *type, unsigned int index)
|
||||
{
|
||||
@ -2300,7 +2347,11 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i
|
||||
return;
|
||||
default_value.value = evaluate_static_expression(ctx, &block, dst_comp_type, &src->loc);
|
||||
|
||||
dst_index = get_component_index_from_default_initializer_index(ctx, dst->data_type, *store_index);
|
||||
if (dst->is_param)
|
||||
dst_index = *store_index;
|
||||
else
|
||||
dst_index = get_component_index_from_default_initializer_index(ctx, dst->data_type, *store_index);
|
||||
|
||||
dst->default_values[dst_index] = default_value;
|
||||
|
||||
hlsl_block_cleanup(&block);
|
||||
@ -2751,14 +2802,18 @@ static bool func_is_compatible_match(struct hlsl_ctx *ctx,
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (decl->parameters.count != args->args_count)
|
||||
if (decl->parameters.count < args->args_count)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < decl->parameters.count; ++i)
|
||||
for (i = 0; i < args->args_count; ++i)
|
||||
{
|
||||
if (!implicit_compatible_data_types(ctx, args->args[i]->data_type, decl->parameters.vars[i]->data_type))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args->args_count < decl->parameters.count && !decl->parameters.vars[args->args_count]->default_values)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2801,11 +2856,11 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu
|
||||
const struct parse_initializer *args, const struct vkd3d_shader_location *loc)
|
||||
{
|
||||
struct hlsl_ir_node *call;
|
||||
unsigned int i;
|
||||
unsigned int i, j;
|
||||
|
||||
assert(args->args_count == func->parameters.count);
|
||||
assert(args->args_count <= func->parameters.count);
|
||||
|
||||
for (i = 0; i < func->parameters.count; ++i)
|
||||
for (i = 0; i < args->args_count; ++i)
|
||||
{
|
||||
struct hlsl_ir_var *param = func->parameters.vars[i];
|
||||
struct hlsl_ir_node *arg = args->args[i];
|
||||
@ -2830,11 +2885,40 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu
|
||||
}
|
||||
}
|
||||
|
||||
/* Add default values for the remaining parameters. */
|
||||
for (i = args->args_count; i < func->parameters.count; ++i)
|
||||
{
|
||||
struct hlsl_ir_var *param = func->parameters.vars[i];
|
||||
unsigned int comp_count = hlsl_type_component_count(param->data_type);
|
||||
struct hlsl_deref param_deref;
|
||||
|
||||
assert(param->default_values);
|
||||
|
||||
hlsl_init_simple_deref_from_var(¶m_deref, param);
|
||||
|
||||
for (j = 0; j < comp_count; ++j)
|
||||
{
|
||||
struct hlsl_type *type = hlsl_type_get_component_type(ctx, param->data_type, j);
|
||||
struct hlsl_constant_value value;
|
||||
struct hlsl_ir_node *comp;
|
||||
struct hlsl_block store_block;
|
||||
|
||||
value.u[0] = param->default_values[j].value;
|
||||
if (!(comp = hlsl_new_constant(ctx, type, &value, loc)))
|
||||
return false;
|
||||
hlsl_block_add_instr(args->instrs, comp);
|
||||
|
||||
if (!hlsl_new_store_component(ctx, &store_block, ¶m_deref, j, comp))
|
||||
return false;
|
||||
hlsl_block_add_block(args->instrs, &store_block);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(call = hlsl_new_call(ctx, func, loc)))
|
||||
return false;
|
||||
hlsl_block_add_instr(args->instrs, call);
|
||||
|
||||
for (i = 0; i < func->parameters.count; ++i)
|
||||
for (i = 0; i < args->args_count; ++i)
|
||||
{
|
||||
struct hlsl_ir_var *param = func->parameters.vars[i];
|
||||
struct hlsl_ir_node *arg = args->args[i];
|
||||
@ -6076,6 +6160,7 @@ static bool state_block_add_entry(struct hlsl_state_block *state_block, struct h
|
||||
%type <name> name_opt
|
||||
|
||||
%type <parameter> parameter
|
||||
%type <parameter> parameter_decl
|
||||
|
||||
%type <parameters> param_list
|
||||
%type <parameters> parameters
|
||||
@ -6911,6 +6996,14 @@ param_list:
|
||||
}
|
||||
|
||||
parameter:
|
||||
parameter_decl
|
||||
| parameter_decl '=' complex_initializer
|
||||
{
|
||||
$$ = $1;
|
||||
$$.initializer = $3;
|
||||
}
|
||||
|
||||
parameter_decl:
|
||||
var_modifiers type_no_void any_identifier arrays colon_attribute
|
||||
{
|
||||
uint32_t modifiers = $1;
|
||||
@ -6943,6 +7036,8 @@ parameter:
|
||||
$$.name = $3;
|
||||
$$.semantic = $5.semantic;
|
||||
$$.reg_reservation = $5.reg_reservation;
|
||||
|
||||
memset(&$$.initializer, 0, sizeof($$.initializer));
|
||||
}
|
||||
|
||||
texture_type:
|
||||
|
@ -345,3 +345,156 @@ export float4 main() : sv_target
|
||||
[test]
|
||||
todo(glsl) draw quad
|
||||
probe (0, 0) rgba (1.0, 2.0, 3.0, 4.0)
|
||||
|
||||
% Default parameter values
|
||||
|
||||
[pixel shader]
|
||||
float func(float a, float b = 2.0f, float c = 3.0f, float d=4.0f)
|
||||
{
|
||||
return a + b + c + d;
|
||||
}
|
||||
|
||||
float4 main() : sv_target
|
||||
{
|
||||
return float4(func(1.0), func(1.0, 3.0), func(1.0, 3.0, 5.0), func(1.0, 3.0, 5.0, 7.0));
|
||||
}
|
||||
|
||||
[test]
|
||||
todo(glsl) draw quad
|
||||
probe (0, 0) rgba (10.0, 11.0, 13.0, 16.0)
|
||||
|
||||
[pixel shader]
|
||||
float4 func(float4 a = 1.0, float4 b = float4(1.0, 2.0, 3.0, 4.0))
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
|
||||
float4 main() : sv_target
|
||||
{
|
||||
return func() + func(float4(-3.0, -4.0, -5.0, -6.0), float4(3.0, 4.0, 5.0, 6.0));
|
||||
}
|
||||
|
||||
[test]
|
||||
todo(glsl) draw quad
|
||||
probe (0, 0) rgba (2.0, 3.0, 4.0, 5.0)
|
||||
|
||||
[pixel shader fail(sm>=6)]
|
||||
float4 func(float4 a = 1.0, float4 b = {1.0, 2.0, 3.0, 4.0})
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
|
||||
float4 main() : sv_target
|
||||
{
|
||||
return func() + func(float4(-3.0, -4.0, -5.0, -6.0), float4(3.0, 4.0, 5.0, 6.0));
|
||||
}
|
||||
|
||||
[test]
|
||||
todo(glsl) draw quad
|
||||
probe (0, 0) rgba (2.0, 3.0, 4.0, 5.0)
|
||||
|
||||
|
||||
% For parameters, the order of matrix initializers is row-major.
|
||||
|
||||
[pixel shader]
|
||||
float4 func(float2x2 m = float2x2(1, 2, 3, 4))
|
||||
{
|
||||
return float4(m);
|
||||
}
|
||||
|
||||
float4 main() : sv_target
|
||||
{
|
||||
return func();
|
||||
}
|
||||
|
||||
[test]
|
||||
todo(glsl) draw quad
|
||||
probe (0, 0) rgba (1.0, 2.0, 3.0, 4.0)
|
||||
|
||||
% Missing default value for parameter c.
|
||||
|
||||
[pixel shader fail]
|
||||
float func(float a, float b = 1.0f, float c)
|
||||
{
|
||||
return a + b + c;
|
||||
}
|
||||
|
||||
float4 main() : sv_target
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
% Output parameters can't have default values for SM < 6.
|
||||
% The default values for output parameters are ignored for SM6.
|
||||
|
||||
[pixel shader fail(sm<6)]
|
||||
float func(float a, out float b = 1.0)
|
||||
{
|
||||
b += a;
|
||||
return b;
|
||||
}
|
||||
|
||||
float4 main() : sv_target
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
[pixel shader fail(sm<6)]
|
||||
float func(float a, out float b = 1.0)
|
||||
{
|
||||
b += a;
|
||||
return b;
|
||||
}
|
||||
|
||||
float4 main() : sv_target
|
||||
{
|
||||
float x = 2.0;
|
||||
float y = func(4.0, x);
|
||||
return float4(x, y, 0, 0);
|
||||
}
|
||||
|
||||
[test]
|
||||
todo(sm>=6 | glsl) draw quad
|
||||
probe (0, 0) rgba (4.0, 4.0, 0.0, 0.0)
|
||||
|
||||
[pixel shader fail(sm<6)]
|
||||
float func(float a, inout float b = 1.0)
|
||||
{
|
||||
b += a;
|
||||
return b;
|
||||
}
|
||||
|
||||
float4 main() : sv_target
|
||||
{
|
||||
float x = 2.0;
|
||||
float y = func(4.0, x);
|
||||
return float4(x, y, 0, 0);
|
||||
}
|
||||
|
||||
[test]
|
||||
todo(glsl) draw quad
|
||||
probe (0, 0) rgba (6.0, 6.0, 0.0, 0.0)
|
||||
|
||||
% Parameters before outputs can't have default values.
|
||||
|
||||
[pixel shader fail]
|
||||
float func(float a = 1.0f, out float b)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
float4 main() : sv_target
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
[pixel shader fail]
|
||||
float func(float a = 1.0f, inout float b)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
float4 main() : sv_target
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user