Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- Makefile.am | 2 ++ tests/hlsl-function-overload.shader_test | 40 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 tests/hlsl-function-overload.shader_test
diff --git a/Makefile.am b/Makefile.am index f51233c2..721a6b66 100644 --- a/Makefile.am +++ b/Makefile.am @@ -58,6 +58,7 @@ vkd3d_shader_tests = \ tests/hlsl-array-dimension.shader_test \ tests/hlsl-comma.shader_test \ tests/hlsl-duplicate-modifiers.shader_test \ + tests/hlsl-function-overload.shader_test \ tests/hlsl-invalid.shader_test \ tests/hlsl-majority-pragma.shader_test \ tests/hlsl-majority-typedef.shader_test \ @@ -266,6 +267,7 @@ XFAIL_TESTS = \ tests/hlsl-array-dimension.shader_test \ tests/hlsl-comma.shader_test \ tests/hlsl-duplicate-modifiers.shader_test \ + tests/hlsl-function-overload.shader_test \ tests/hlsl-majority-pragma.shader_test \ tests/hlsl-majority-typedef.shader_test \ tests/hlsl-nested-arrays.shader_test \ diff --git a/tests/hlsl-function-overload.shader_test b/tests/hlsl-function-overload.shader_test new file mode 100644 index 00000000..c6e0ccfe --- /dev/null +++ b/tests/hlsl-function-overload.shader_test @@ -0,0 +1,40 @@ +[pixel shader fail] +/* The same function signature cannot be defined twice. */ + +float func(int arg) +{ + return 0.1; +} + +float func(int arg) +{ + return 0.1; +} + +float4 main() : sv_target +{ + return 0; +} + +[pixel shader] +/* Test a basic overload. */ +float func(int arg) +{ + return 0.1; +} + +float func(uint arg) +{ + return 0.2; +} + +float4 main() : sv_target +{ + int i = 1; + uint u = 1; + return float4(func(i), func(u), func(int2(1, 1)), func(uint2(1, 1))); +} + +[test] +draw quad +probe all rgba (0.1, 0.2, 0.1, 0.2)
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl.y | 77 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 26ba4695..ddc429ba 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1523,6 +1523,67 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t return statements_list; }
+struct find_function_call_args +{ + const struct parse_initializer *params; + const struct hlsl_ir_function_decl *decl; +}; + +static void find_function_call_exact(struct rb_entry *entry, void *context) +{ + const struct hlsl_ir_function_decl *decl = RB_ENTRY_VALUE(entry, const struct hlsl_ir_function_decl, entry); + struct find_function_call_args *args = context; + const struct hlsl_ir_var *param; + unsigned int i = 0; + + LIST_FOR_EACH_ENTRY(param, decl->parameters, struct hlsl_ir_var, param_entry) + { + if (i >= args->params->args_count + || !hlsl_types_are_equal(param->data_type, args->params->args[i++]->data_type)) + return; + } + if (i == args->params->args_count) + args->decl = decl; +} + +static const struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *ctx, + const char *name, const struct parse_initializer *params) +{ + struct find_function_call_args args = {.params = params}; + struct hlsl_ir_function *func; + struct rb_entry *entry; + + if (!(entry = rb_get(&ctx->functions, name))) + return NULL; + func = RB_ENTRY_VALUE(entry, struct hlsl_ir_function, entry); + + rb_for_each_entry(&func->overloads, find_function_call_exact, &args); + if (!args.decl) + FIXME("Search for compatible overloads.\n"); + return args.decl; +} + +static struct list *add_call(struct hlsl_ctx *ctx, const char *name, + struct parse_initializer *params, struct vkd3d_shader_location loc) +{ + const struct hlsl_ir_function_decl *decl; + + if ((decl = find_function_call(ctx, name, params))) + { + hlsl_fixme(ctx, loc, "Call to user-defined function "%s".", name); + free_parse_initializer(params); + return NULL; + } + else + { + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, "Function "%s" is not defined.", name); + free_parse_initializer(params); + return NULL; + } + vkd3d_free(params->args); + return params->instrs; +} + }
%locations @@ -1714,6 +1775,7 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t %type <function> func_prototype
%type <initializer> complex_initializer +%type <initializer> func_arguments %type <initializer> initializer_expr_list
%type <if_body> if_body @@ -2575,6 +2637,16 @@ expr_statement: $$ = $1; }
+func_arguments: + %empty + { + $$.args = NULL; + $$.args_count = 0; + if (!($$.instrs = make_empty_list(ctx))) + YYABORT; + } + | initializer_expr_list + primary_expr: C_FLOAT { @@ -2631,6 +2703,11 @@ primary_expr: { $$ = $2; } + | var_identifier '(' func_arguments ')' + { + if (!($$ = add_call(ctx, $1, &$3, @1))) + YYABORT; + }
postfix_expr: primary_expr
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com
Il 02/09/21 00:20, Zebediah Figura ha scritto:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
libs/vkd3d-shader/hlsl.y | 77 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 26ba4695..ddc429ba 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1523,6 +1523,67 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t return statements_list; }
+struct find_function_call_args +{
- const struct parse_initializer *params;
- const struct hlsl_ir_function_decl *decl;
+};
+static void find_function_call_exact(struct rb_entry *entry, void *context) +{
- const struct hlsl_ir_function_decl *decl = RB_ENTRY_VALUE(entry, const struct hlsl_ir_function_decl, entry);
- struct find_function_call_args *args = context;
- const struct hlsl_ir_var *param;
- unsigned int i = 0;
- LIST_FOR_EACH_ENTRY(param, decl->parameters, struct hlsl_ir_var, param_entry)
- {
if (i >= args->params->args_count
|| !hlsl_types_are_equal(param->data_type, args->params->args[i++]->data_type))
return;
- }
- if (i == args->params->args_count)
args->decl = decl;
+}
+static const struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *ctx,
const char *name, const struct parse_initializer *params)
+{
- struct find_function_call_args args = {.params = params};
- struct hlsl_ir_function *func;
- struct rb_entry *entry;
- if (!(entry = rb_get(&ctx->functions, name)))
return NULL;
- func = RB_ENTRY_VALUE(entry, struct hlsl_ir_function, entry);
- rb_for_each_entry(&func->overloads, find_function_call_exact, &args);
- if (!args.decl)
FIXME("Search for compatible overloads.\n");
- return args.decl;
+}
+static struct list *add_call(struct hlsl_ctx *ctx, const char *name,
struct parse_initializer *params, struct vkd3d_shader_location loc)
+{
- const struct hlsl_ir_function_decl *decl;
- if ((decl = find_function_call(ctx, name, params)))
- {
hlsl_fixme(ctx, loc, "Call to user-defined function \"%s\".", name);
free_parse_initializer(params);
return NULL;
- }
- else
- {
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, "Function \"%s\" is not defined.", name);
free_parse_initializer(params);
return NULL;
- }
- vkd3d_free(params->args);
- return params->instrs;
+}
}
%locations
@@ -1714,6 +1775,7 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t %type <function> func_prototype
%type <initializer> complex_initializer +%type <initializer> func_arguments %type <initializer> initializer_expr_list
%type <if_body> if_body @@ -2575,6 +2637,16 @@ expr_statement: $$ = $1; }
+func_arguments:
%empty
{
$$.args = NULL;
$$.args_count = 0;
if (!($$.instrs = make_empty_list(ctx)))
YYABORT;
}
- | initializer_expr_list
- primary_expr: C_FLOAT {
@@ -2631,6 +2703,11 @@ primary_expr: { $$ = $2; }
| var_identifier '(' func_arguments ')'
{
if (!($$ = add_call(ctx, $1, &$3, @1)))
YYABORT;
}
postfix_expr: primary_expr
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
The parameters are specified as a list of hlsl_ir_var structures, but add_call() is given an array of hlsl_ir_node pointers. Even if the former were changed to use an array instead, it's not worth trying to reuse the same function for both cases.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl.y | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index ddc429ba..2512bcc0 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -790,25 +790,17 @@ static struct hlsl_reg_reservation parse_reg_reservation(const char *reg_string) return reservation; }
-static const struct hlsl_ir_function_decl *get_overloaded_func(struct rb_tree *funcs, char *name, - struct list *params, bool exact_signature) +static const struct hlsl_ir_function_decl *get_func_decl(struct rb_tree *funcs, char *name, struct list *params) { struct hlsl_ir_function *func; struct rb_entry *entry;
- entry = rb_get(funcs, name); - if (entry) + if ((entry = rb_get(funcs, name))) { func = RB_ENTRY_VALUE(entry, struct hlsl_ir_function, entry);
- entry = rb_get(&func->overloads, params); - if (!entry) - { - if (!exact_signature) - FIXME("No exact match, search for a compatible overloaded function (if any).\n"); - return NULL; - } - return RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry); + if ((entry = rb_get(&func->overloads, params))) + return RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry); } return NULL; } @@ -1813,7 +1805,7 @@ hlsl_prog: { const struct hlsl_ir_function_decl *decl;
- decl = get_overloaded_func(&ctx->functions, $2.name, $2.decl->parameters, true); + decl = get_func_decl(&ctx->functions, $2.name, $2.decl->parameters); if (decl && !decl->func->intrinsic) { if (decl->body && $2.decl->body)
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
On Thu, Sep 2, 2021 at 12:23 AM Zebediah Figura zfigura@codeweavers.com wrote:
The parameters are specified as a list of hlsl_ir_var structures, but add_call() is given an array of hlsl_ir_node pointers. Even if the former were changed to use an array instead, it's not worth trying to reuse the same function for both cases.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
libs/vkd3d-shader/hlsl.y | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index ddc429ba..2512bcc0 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -790,25 +790,17 @@ static struct hlsl_reg_reservation parse_reg_reservation(const char *reg_string) return reservation; }
-static const struct hlsl_ir_function_decl *get_overloaded_func(struct rb_tree *funcs, char *name,
struct list *params, bool exact_signature)
+static const struct hlsl_ir_function_decl *get_func_decl(struct rb_tree *funcs, char *name, struct list *params) { struct hlsl_ir_function *func; struct rb_entry *entry;
- entry = rb_get(funcs, name);
- if (entry)
- if ((entry = rb_get(funcs, name))) { func = RB_ENTRY_VALUE(entry, struct hlsl_ir_function, entry);
entry = rb_get(&func->overloads, params);
if (!entry)
{
if (!exact_signature)
FIXME("No exact match, search for a compatible overloaded function (if any).\n");
return NULL;
}
return RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry);
if ((entry = rb_get(&func->overloads, params)))
} return NULL;return RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry);
} @@ -1813,7 +1805,7 @@ hlsl_prog: { const struct hlsl_ir_function_decl *decl;
decl = get_overloaded_func(&ctx->functions, $2.name, $2.decl->parameters, true);
decl = get_func_decl(&ctx->functions, $2.name, $2.decl->parameters); if (decl && !decl->func->intrinsic) { if (decl->body && $2.decl->body)
I have a question / concern unrelated to the patch itself but in the same general area. There's a hlsl_get_func_decl() function, currently used only to find the entry point, that basically returns the first overload of a function. Should we make sure to throw an error in there if there are multiple overloads? Also, are there other instances where we'll need to use that function? I'm wondering if it makes sense to rename it to hlsl_get_entry_point_function() or something and move it into hlsl.y.
On 9/3/21 7:13 AM, Matteo Bruni wrote:
On Thu, Sep 2, 2021 at 12:23 AM Zebediah Figura zfigura@codeweavers.com wrote:
The parameters are specified as a list of hlsl_ir_var structures, but add_call() is given an array of hlsl_ir_node pointers. Even if the former were changed to use an array instead, it's not worth trying to reuse the same function for both cases.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
libs/vkd3d-shader/hlsl.y | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index ddc429ba..2512bcc0 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -790,25 +790,17 @@ static struct hlsl_reg_reservation parse_reg_reservation(const char *reg_string) return reservation; }
-static const struct hlsl_ir_function_decl *get_overloaded_func(struct rb_tree *funcs, char *name,
struct list *params, bool exact_signature)
+static const struct hlsl_ir_function_decl *get_func_decl(struct rb_tree *funcs, char *name, struct list *params) { struct hlsl_ir_function *func; struct rb_entry *entry;
- entry = rb_get(funcs, name);
- if (entry)
- if ((entry = rb_get(funcs, name))) { func = RB_ENTRY_VALUE(entry, struct hlsl_ir_function, entry);
entry = rb_get(&func->overloads, params);
if (!entry)
{
if (!exact_signature)
FIXME("No exact match, search for a compatible overloaded function (if any).\n");
return NULL;
}
return RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry);
if ((entry = rb_get(&func->overloads, params)))
}return RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry); } return NULL;
@@ -1813,7 +1805,7 @@ hlsl_prog: { const struct hlsl_ir_function_decl *decl;
decl = get_overloaded_func(&ctx->functions, $2.name, $2.decl->parameters, true);
decl = get_func_decl(&ctx->functions, $2.name, $2.decl->parameters); if (decl && !decl->func->intrinsic) { if (decl->body && $2.decl->body)
I have a question / concern unrelated to the patch itself but in the same general area. There's a hlsl_get_func_decl() function, currently used only to find the entry point, that basically returns the first overload of a function. Should we make sure to throw an error in there if there are multiple overloads? Also, are there other instances where we'll need to use that function? I'm wondering if it makes sense to rename it to hlsl_get_entry_point_function() or something and move it into hlsl.y.
It's used in two places: to find the entry point, and to check if a variable name was previously defined as a function. But yeah, we probably want to return an hlsl_ir_function instead, for both purposes. I'll put it on the to-do list.
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com
Il 02/09/21 00:20, Zebediah Figura ha scritto:
The parameters are specified as a list of hlsl_ir_var structures, but add_call() is given an array of hlsl_ir_node pointers. Even if the former were changed to use an array instead, it's not worth trying to reuse the same function for both cases.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
libs/vkd3d-shader/hlsl.y | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index ddc429ba..2512bcc0 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -790,25 +790,17 @@ static struct hlsl_reg_reservation parse_reg_reservation(const char *reg_string) return reservation; }
-static const struct hlsl_ir_function_decl *get_overloaded_func(struct rb_tree *funcs, char *name,
struct list *params, bool exact_signature)
+static const struct hlsl_ir_function_decl *get_func_decl(struct rb_tree *funcs, char *name, struct list *params) { struct hlsl_ir_function *func; struct rb_entry *entry;
- entry = rb_get(funcs, name);
- if (entry)
- if ((entry = rb_get(funcs, name))) { func = RB_ENTRY_VALUE(entry, struct hlsl_ir_function, entry);
entry = rb_get(&func->overloads, params);
if (!entry)
{
if (!exact_signature)
FIXME("No exact match, search for a compatible overloaded function (if any).\n");
return NULL;
}
return RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry);
if ((entry = rb_get(&func->overloads, params)))
}return RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry); } return NULL;
@@ -1813,7 +1805,7 @@ hlsl_prog: { const struct hlsl_ir_function_decl *decl;
decl = get_overloaded_func(&ctx->functions, $2.name, $2.decl->parameters, true);
decl = get_func_decl(&ctx->functions, $2.name, $2.decl->parameters); if (decl && !decl->func->intrinsic) { if (decl->body && $2.decl->body)
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- Makefile.am | 2 ++ libs/vkd3d-shader/hlsl.y | 67 +++++++++++++++++++++++++++++++++++++ tests/max.shader_test | 23 +++++++++++++ tests/shader_runner_d3d12.c | 2 ++ 4 files changed, 94 insertions(+) create mode 100644 tests/max.shader_test
diff --git a/Makefile.am b/Makefile.am index 721a6b66..09d3755b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -72,6 +72,7 @@ vkd3d_shader_tests = \ tests/hlsl-vector-indexing.shader_test \ tests/hlsl-vector-indexing-uniform.shader_test \ tests/math.shader_test \ + tests/max.shader_test \ tests/preproc-if.shader_test \ tests/preproc-ifdef.shader_test \ tests/preproc-if-expr.shader_test \ @@ -278,6 +279,7 @@ XFAIL_TESTS = \ tests/hlsl-vector-indexing.shader_test \ tests/hlsl-vector-indexing-uniform.shader_test \ tests/math.shader_test \ + tests/max.shader_test \ tests/trigonometry.shader_test \ tests/writemask-assignop-1.shader_test endif diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 2512bcc0..d374f64b 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1555,10 +1555,38 @@ static const struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *c return args.decl; }
+static bool intrinsic_max(struct hlsl_ctx *ctx, + const struct parse_initializer *params, struct vkd3d_shader_location loc) +{ + struct hlsl_ir_node *args[3] = {params->args[0], params->args[1]}; + + return !!add_expr(ctx, params->instrs, HLSL_OP2_MAX, args, &loc); +} + +static const struct intrinsic_function +{ + const char *name; + int param_count; + bool check_numeric; + bool (*handler)(struct hlsl_ctx *ctx, const struct parse_initializer *params, struct vkd3d_shader_location loc); +} +intrinsic_functions[] = +{ + {"max", 2, true, intrinsic_max}, +}; + +static int intrinsic_function_name_compare(const void *a, const void *b) +{ + const struct intrinsic_function *func = b; + + return strcmp(a, func->name); +} + static struct list *add_call(struct hlsl_ctx *ctx, const char *name, struct parse_initializer *params, struct vkd3d_shader_location loc) { const struct hlsl_ir_function_decl *decl; + struct intrinsic_function *intrinsic;
if ((decl = find_function_call(ctx, name, params))) { @@ -1566,6 +1594,45 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, free_parse_initializer(params); return NULL; } + else if ((intrinsic = bsearch(name, intrinsic_functions, ARRAY_SIZE(intrinsic_functions), + sizeof(*intrinsic_functions), intrinsic_function_name_compare))) + { + if (intrinsic->param_count >= 0 && params->args_count != intrinsic->param_count) + { + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, + "Wrong number of arguments to function '%s': expected %u, but got %u.\n", + name, intrinsic->param_count, params->args_count); + free_parse_initializer(params); + return NULL; + } + + if (intrinsic->check_numeric) + { + unsigned int i; + + for (i = 0; i < params->args_count; ++i) + { + if (params->args[i]->data_type->type > HLSL_CLASS_LAST_NUMERIC) + { + struct vkd3d_string_buffer *string; + + if ((string = hlsl_type_to_string(ctx, params->args[i]->data_type))) + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Wrong type for argument %u of '%s': expected a numeric type, but got '%s'.\n", + i + 1, name, string->buffer); + hlsl_release_string_buffer(ctx, string); + free_parse_initializer(params); + return NULL; + } + } + } + + if (!intrinsic->handler(ctx, params, loc)) + { + free_parse_initializer(params); + return NULL; + } + } else { hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, "Function "%s" is not defined.", name); diff --git a/tests/max.shader_test b/tests/max.shader_test new file mode 100644 index 00000000..56c9a84e --- /dev/null +++ b/tests/max.shader_test @@ -0,0 +1,23 @@ +[pixel shader] +float4 main(uniform float u, uniform float v) : sv_target +{ + return float4(max(u, v), max(2, 2.1), max(true, 2), max(-1, -1)); +} + +[test] +uniform 0 float4 0.7 -0.1 0.0 0.0 +draw quad +probe all rgba (0.7, 2.1, 2.0, -1.0) + +[pixel shader] +float4 main(uniform float2 u, uniform float2 v) : sv_target +{ + float3 a = float3(-0.1, 0.2, 0.3); + + return float4(max(u, v), max(a, u)); +} + +[test] +uniform 0 float4 0.7 -0.1 0.4 0.8 +draw quad +probe all rgba (0.7, 0.8, 0.7, 0.2) diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index 3cc859ab..2221c0f8 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -136,6 +136,8 @@ static void parse_test_directive(struct shader_context *context, const char *lin static const float clear_color[4]; ID3D12PipelineState *pso;
+ if (context->c.root_signature) + ID3D12RootSignature_Release(context->c.root_signature); context->c.root_signature = create_32bit_constants_root_signature(context->c.device, 0, context->uniform_count, D3D12_SHADER_VISIBILITY_ALL);
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
On Thu, Sep 2, 2021 at 12:23 AM Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
Makefile.am | 2 ++ libs/vkd3d-shader/hlsl.y | 67 +++++++++++++++++++++++++++++++++++++ tests/max.shader_test | 23 +++++++++++++ tests/shader_runner_d3d12.c | 2 ++ 4 files changed, 94 insertions(+) create mode 100644 tests/max.shader_test
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 2512bcc0..d374f64b 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1555,10 +1555,38 @@ static const struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *c return args.decl; }
+static bool intrinsic_max(struct hlsl_ctx *ctx,
const struct parse_initializer *params, struct vkd3d_shader_location loc)
+{
- struct hlsl_ir_node *args[3] = {params->args[0], params->args[1]};
- return !!add_expr(ctx, params->instrs, HLSL_OP2_MAX, args, &loc);
+}
+static const struct intrinsic_function +{
- const char *name;
- int param_count;
- bool check_numeric;
- bool (*handler)(struct hlsl_ctx *ctx, const struct parse_initializer *params, struct vkd3d_shader_location loc);
+} +intrinsic_functions[] = +{
- {"max", 2, true, intrinsic_max},
+};
+static int intrinsic_function_name_compare(const void *a, const void *b) +{
- const struct intrinsic_function *func = b;
- return strcmp(a, func->name);
+}
static struct list *add_call(struct hlsl_ctx *ctx, const char *name, struct parse_initializer *params, struct vkd3d_shader_location loc) { const struct hlsl_ir_function_decl *decl;
struct intrinsic_function *intrinsic;
if ((decl = find_function_call(ctx, name, params))) {
@@ -1566,6 +1594,45 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, free_parse_initializer(params); return NULL; }
- else if ((intrinsic = bsearch(name, intrinsic_functions, ARRAY_SIZE(intrinsic_functions),
sizeof(*intrinsic_functions), intrinsic_function_name_compare)))
- {
if (intrinsic->param_count >= 0 && params->args_count != intrinsic->param_count)
{
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT,
"Wrong number of arguments to function '%s': expected %u, but got %u.\n",
name, intrinsic->param_count, params->args_count);
free_parse_initializer(params);
return NULL;
}
I guess the idea is to use param_count == 0 to mark intrinsic functions with a variable number of parameters? I think it would be better to use a different number (e.g. -1 if you keep int for param_count, or ~0u otherwise) given that we probably want to check that calls to e.g. AllMemoryBarrier() don't have arguments.
On 9/3/21 7:13 AM, Matteo Bruni wrote:
On Thu, Sep 2, 2021 at 12:23 AM Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
Makefile.am | 2 ++ libs/vkd3d-shader/hlsl.y | 67 +++++++++++++++++++++++++++++++++++++ tests/max.shader_test | 23 +++++++++++++ tests/shader_runner_d3d12.c | 2 ++ 4 files changed, 94 insertions(+) create mode 100644 tests/max.shader_test
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 2512bcc0..d374f64b 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1555,10 +1555,38 @@ static const struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *c return args.decl; }
+static bool intrinsic_max(struct hlsl_ctx *ctx,
const struct parse_initializer *params, struct vkd3d_shader_location loc)
+{
- struct hlsl_ir_node *args[3] = {params->args[0], params->args[1]};
- return !!add_expr(ctx, params->instrs, HLSL_OP2_MAX, args, &loc);
+}
+static const struct intrinsic_function +{
- const char *name;
- int param_count;
- bool check_numeric;
- bool (*handler)(struct hlsl_ctx *ctx, const struct parse_initializer *params, struct vkd3d_shader_location loc);
+} +intrinsic_functions[] = +{
- {"max", 2, true, intrinsic_max},
+};
+static int intrinsic_function_name_compare(const void *a, const void *b) +{
- const struct intrinsic_function *func = b;
- return strcmp(a, func->name);
+}
static struct list *add_call(struct hlsl_ctx *ctx, const char *name, struct parse_initializer *params, struct vkd3d_shader_location loc) { const struct hlsl_ir_function_decl *decl;
struct intrinsic_function *intrinsic;
if ((decl = find_function_call(ctx, name, params))) {
@@ -1566,6 +1594,45 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, free_parse_initializer(params); return NULL; }
- else if ((intrinsic = bsearch(name, intrinsic_functions, ARRAY_SIZE(intrinsic_functions),
sizeof(*intrinsic_functions), intrinsic_function_name_compare)))
- {
if (intrinsic->param_count >= 0 && params->args_count != intrinsic->param_count)
{
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT,
"Wrong number of arguments to function '%s': expected %u, but got %u.\n",
name, intrinsic->param_count, params->args_count);
free_parse_initializer(params);
return NULL;
}
I guess the idea is to use param_count == 0 to mark intrinsic functions with a variable number of parameters? I think it would be better to use a different number (e.g. -1 if you keep int for param_count, or ~0u otherwise) given that we probably want to check that calls to e.g. AllMemoryBarrier() don't have arguments.
The idea is to use -1. That's a >=, not a >.
On Fri, Sep 3, 2021 at 6:37 PM Zebediah Figura (she/her) zfigura@codeweavers.com wrote:
On 9/3/21 7:13 AM, Matteo Bruni wrote:
On Thu, Sep 2, 2021 at 12:23 AM Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
Makefile.am | 2 ++ libs/vkd3d-shader/hlsl.y | 67 +++++++++++++++++++++++++++++++++++++ tests/max.shader_test | 23 +++++++++++++ tests/shader_runner_d3d12.c | 2 ++ 4 files changed, 94 insertions(+) create mode 100644 tests/max.shader_test
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 2512bcc0..d374f64b 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1555,10 +1555,38 @@ static const struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *c return args.decl; }
+static bool intrinsic_max(struct hlsl_ctx *ctx,
const struct parse_initializer *params, struct vkd3d_shader_location loc)
+{
- struct hlsl_ir_node *args[3] = {params->args[0], params->args[1]};
- return !!add_expr(ctx, params->instrs, HLSL_OP2_MAX, args, &loc);
+}
+static const struct intrinsic_function +{
- const char *name;
- int param_count;
- bool check_numeric;
- bool (*handler)(struct hlsl_ctx *ctx, const struct parse_initializer *params, struct vkd3d_shader_location loc);
+} +intrinsic_functions[] = +{
- {"max", 2, true, intrinsic_max},
+};
+static int intrinsic_function_name_compare(const void *a, const void *b) +{
- const struct intrinsic_function *func = b;
- return strcmp(a, func->name);
+}
static struct list *add_call(struct hlsl_ctx *ctx, const char *name, struct parse_initializer *params, struct vkd3d_shader_location loc) { const struct hlsl_ir_function_decl *decl;
struct intrinsic_function *intrinsic;
if ((decl = find_function_call(ctx, name, params))) {
@@ -1566,6 +1594,45 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, free_parse_initializer(params); return NULL; }
- else if ((intrinsic = bsearch(name, intrinsic_functions, ARRAY_SIZE(intrinsic_functions),
sizeof(*intrinsic_functions), intrinsic_function_name_compare)))
- {
if (intrinsic->param_count >= 0 && params->args_count != intrinsic->param_count)
{
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT,
"Wrong number of arguments to function '%s': expected %u, but got %u.\n",
name, intrinsic->param_count, params->args_count);
free_parse_initializer(params);
return NULL;
}
I guess the idea is to use param_count == 0 to mark intrinsic functions with a variable number of parameters? I think it would be better to use a different number (e.g. -1 if you keep int for param_count, or ~0u otherwise) given that we probably want to check that calls to e.g. AllMemoryBarrier() don't have arguments.
The idea is to use -1. That's a >=, not a >.
Indeed, I can't read.
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com
Il 02/09/21 00:20, Zebediah Figura ha scritto:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
Makefile.am | 2 ++ libs/vkd3d-shader/hlsl.y | 67 +++++++++++++++++++++++++++++++++++++ tests/max.shader_test | 23 +++++++++++++ tests/shader_runner_d3d12.c | 2 ++ 4 files changed, 94 insertions(+) create mode 100644 tests/max.shader_test
diff --git a/Makefile.am b/Makefile.am index 721a6b66..09d3755b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -72,6 +72,7 @@ vkd3d_shader_tests = \ tests/hlsl-vector-indexing.shader_test \ tests/hlsl-vector-indexing-uniform.shader_test \ tests/math.shader_test \
- tests/max.shader_test \ tests/preproc-if.shader_test \ tests/preproc-ifdef.shader_test \ tests/preproc-if-expr.shader_test \
@@ -278,6 +279,7 @@ XFAIL_TESTS = \ tests/hlsl-vector-indexing.shader_test \ tests/hlsl-vector-indexing-uniform.shader_test \ tests/math.shader_test \
- tests/max.shader_test \ tests/trigonometry.shader_test \ tests/writemask-assignop-1.shader_test endif
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 2512bcc0..d374f64b 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1555,10 +1555,38 @@ static const struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *c return args.decl; }
+static bool intrinsic_max(struct hlsl_ctx *ctx,
const struct parse_initializer *params, struct vkd3d_shader_location loc)
+{
- struct hlsl_ir_node *args[3] = {params->args[0], params->args[1]};
- return !!add_expr(ctx, params->instrs, HLSL_OP2_MAX, args, &loc);
+}
+static const struct intrinsic_function +{
- const char *name;
- int param_count;
- bool check_numeric;
- bool (*handler)(struct hlsl_ctx *ctx, const struct parse_initializer *params, struct vkd3d_shader_location loc);
+} +intrinsic_functions[] = +{
- {"max", 2, true, intrinsic_max},
+};
+static int intrinsic_function_name_compare(const void *a, const void *b) +{
- const struct intrinsic_function *func = b;
- return strcmp(a, func->name);
+}
static struct list *add_call(struct hlsl_ctx *ctx, const char *name, struct parse_initializer *params, struct vkd3d_shader_location loc) { const struct hlsl_ir_function_decl *decl;
struct intrinsic_function *intrinsic;
if ((decl = find_function_call(ctx, name, params))) {
@@ -1566,6 +1594,45 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, free_parse_initializer(params); return NULL; }
- else if ((intrinsic = bsearch(name, intrinsic_functions, ARRAY_SIZE(intrinsic_functions),
sizeof(*intrinsic_functions), intrinsic_function_name_compare)))
- {
if (intrinsic->param_count >= 0 && params->args_count != intrinsic->param_count)
{
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT,
"Wrong number of arguments to function '%s': expected %u, but got %u.\n",
name, intrinsic->param_count, params->args_count);
free_parse_initializer(params);
return NULL;
}
if (intrinsic->check_numeric)
{
unsigned int i;
for (i = 0; i < params->args_count; ++i)
{
if (params->args[i]->data_type->type > HLSL_CLASS_LAST_NUMERIC)
{
struct vkd3d_string_buffer *string;
if ((string = hlsl_type_to_string(ctx, params->args[i]->data_type)))
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
"Wrong type for argument %u of '%s': expected a numeric type, but got '%s'.\n",
i + 1, name, string->buffer);
hlsl_release_string_buffer(ctx, string);
free_parse_initializer(params);
return NULL;
}
}
}
if (!intrinsic->handler(ctx, params, loc))
{
free_parse_initializer(params);
return NULL;
}
- } else { hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, "Function "%s" is not defined.", name);
diff --git a/tests/max.shader_test b/tests/max.shader_test new file mode 100644 index 00000000..56c9a84e --- /dev/null +++ b/tests/max.shader_test @@ -0,0 +1,23 @@ +[pixel shader] +float4 main(uniform float u, uniform float v) : sv_target +{
- return float4(max(u, v), max(2, 2.1), max(true, 2), max(-1, -1));
+}
+[test] +uniform 0 float4 0.7 -0.1 0.0 0.0 +draw quad +probe all rgba (0.7, 2.1, 2.0, -1.0)
+[pixel shader] +float4 main(uniform float2 u, uniform float2 v) : sv_target +{
- float3 a = float3(-0.1, 0.2, 0.3);
- return float4(max(u, v), max(a, u));
+}
+[test] +uniform 0 float4 0.7 -0.1 0.4 0.8 +draw quad +probe all rgba (0.7, 0.8, 0.7, 0.2) diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index 3cc859ab..2221c0f8 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -136,6 +136,8 @@ static void parse_test_directive(struct shader_context *context, const char *lin static const float clear_color[4]; ID3D12PipelineState *pso;
if (context->c.root_signature)
ID3D12RootSignature_Release(context->c.root_signature); context->c.root_signature = create_32bit_constants_root_signature(context->c.device, 0, context->uniform_count, D3D12_SHADER_VISIBILITY_ALL);
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- Makefile.am | 2 ++ libs/vkd3d-shader/hlsl.y | 15 +++++++++++++++ tests/hlsl-clamp.shader_test | 10 ++++++++++ 3 files changed, 27 insertions(+) create mode 100644 tests/hlsl-clamp.shader_test
diff --git a/Makefile.am b/Makefile.am index 09d3755b..3c18c318 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,6 +56,7 @@ vkd3d_shader_runners = \ vkd3d_shader_tests = \ tests/conditional.shader_test \ tests/hlsl-array-dimension.shader_test \ + tests/hlsl-clamp.shader_test \ tests/hlsl-comma.shader_test \ tests/hlsl-duplicate-modifiers.shader_test \ tests/hlsl-function-overload.shader_test \ @@ -266,6 +267,7 @@ SHADER_TEST_LOG_COMPILER = tests/shader_runner_d3d12 XFAIL_TESTS = \ tests/conditional.shader_test \ tests/hlsl-array-dimension.shader_test \ + tests/hlsl-clamp.shader_test \ tests/hlsl-comma.shader_test \ tests/hlsl-duplicate-modifiers.shader_test \ tests/hlsl-function-overload.shader_test \ diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index d374f64b..8f634728 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1555,6 +1555,20 @@ static const struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *c return args.decl; }
+static bool intrinsic_clamp(struct hlsl_ctx *ctx, + const struct parse_initializer *params, struct vkd3d_shader_location loc) +{ + struct hlsl_ir_node *args[3] = {params->args[0], params->args[1]}; + struct hlsl_ir_expr *max; + + if (!(max = add_expr(ctx, params->instrs, HLSL_OP2_MAX, args, &loc))) + return false; + + args[0] = &max->node; + args[1] = params->args[2]; + return !!add_expr(ctx, params->instrs, HLSL_OP2_MIN, args, &loc); +} + static bool intrinsic_max(struct hlsl_ctx *ctx, const struct parse_initializer *params, struct vkd3d_shader_location loc) { @@ -1572,6 +1586,7 @@ static const struct intrinsic_function } intrinsic_functions[] = { + {"clamp", 3, true, intrinsic_clamp}, {"max", 2, true, intrinsic_max}, };
diff --git a/tests/hlsl-clamp.shader_test b/tests/hlsl-clamp.shader_test new file mode 100644 index 00000000..73f396ff --- /dev/null +++ b/tests/hlsl-clamp.shader_test @@ -0,0 +1,10 @@ +[pixel shader] +float4 main(uniform float u, uniform float v, uniform float w) : sv_target +{ + return float4(clamp(u, v, w), clamp(0.9, v, w), clamp(u, -0.5, w), clamp(0.6, -0.4, 0.3)); +} + +[test] +uniform 0 float4 -0.3 -0.1 0.7 0.0 +draw quad +probe all rgba (-0.1, 0.7, -0.3, 0.3)
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com
Il 02/09/21 00:20, Zebediah Figura ha scritto:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
Makefile.am | 2 ++ libs/vkd3d-shader/hlsl.y | 15 +++++++++++++++ tests/hlsl-clamp.shader_test | 10 ++++++++++ 3 files changed, 27 insertions(+) create mode 100644 tests/hlsl-clamp.shader_test
diff --git a/Makefile.am b/Makefile.am index 09d3755b..3c18c318 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,6 +56,7 @@ vkd3d_shader_runners = \ vkd3d_shader_tests = \ tests/conditional.shader_test \ tests/hlsl-array-dimension.shader_test \
- tests/hlsl-clamp.shader_test \ tests/hlsl-comma.shader_test \ tests/hlsl-duplicate-modifiers.shader_test \ tests/hlsl-function-overload.shader_test \
@@ -266,6 +267,7 @@ SHADER_TEST_LOG_COMPILER = tests/shader_runner_d3d12 XFAIL_TESTS = \ tests/conditional.shader_test \ tests/hlsl-array-dimension.shader_test \
- tests/hlsl-clamp.shader_test \ tests/hlsl-comma.shader_test \ tests/hlsl-duplicate-modifiers.shader_test \ tests/hlsl-function-overload.shader_test \
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index d374f64b..8f634728 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1555,6 +1555,20 @@ static const struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *c return args.decl; }
+static bool intrinsic_clamp(struct hlsl_ctx *ctx,
const struct parse_initializer *params, struct vkd3d_shader_location loc)
+{
- struct hlsl_ir_node *args[3] = {params->args[0], params->args[1]};
- struct hlsl_ir_expr *max;
- if (!(max = add_expr(ctx, params->instrs, HLSL_OP2_MAX, args, &loc)))
return false;
- args[0] = &max->node;
- args[1] = params->args[2];
- return !!add_expr(ctx, params->instrs, HLSL_OP2_MIN, args, &loc);
+}
- static bool intrinsic_max(struct hlsl_ctx *ctx, const struct parse_initializer *params, struct vkd3d_shader_location loc) {
@@ -1572,6 +1586,7 @@ static const struct intrinsic_function } intrinsic_functions[] = {
- {"clamp", 3, true, intrinsic_clamp}, {"max", 2, true, intrinsic_max}, };
diff --git a/tests/hlsl-clamp.shader_test b/tests/hlsl-clamp.shader_test new file mode 100644 index 00000000..73f396ff --- /dev/null +++ b/tests/hlsl-clamp.shader_test @@ -0,0 +1,10 @@ +[pixel shader] +float4 main(uniform float u, uniform float v, uniform float w) : sv_target +{
- return float4(clamp(u, v, w), clamp(0.9, v, w), clamp(u, -0.5, w), clamp(0.6, -0.4, 0.3));
+}
+[test] +uniform 0 float4 -0.3 -0.1 0.7 0.0 +draw quad +probe all rgba (-0.1, 0.7, -0.3, 0.3)
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com
Il 02/09/21 00:20, Zebediah Figura ha scritto:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
Makefile.am | 2 ++ tests/hlsl-function-overload.shader_test | 40 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 tests/hlsl-function-overload.shader_test
diff --git a/Makefile.am b/Makefile.am index f51233c2..721a6b66 100644 --- a/Makefile.am +++ b/Makefile.am @@ -58,6 +58,7 @@ vkd3d_shader_tests = \ tests/hlsl-array-dimension.shader_test \ tests/hlsl-comma.shader_test \ tests/hlsl-duplicate-modifiers.shader_test \
- tests/hlsl-function-overload.shader_test \ tests/hlsl-invalid.shader_test \ tests/hlsl-majority-pragma.shader_test \ tests/hlsl-majority-typedef.shader_test \
@@ -266,6 +267,7 @@ XFAIL_TESTS = \ tests/hlsl-array-dimension.shader_test \ tests/hlsl-comma.shader_test \ tests/hlsl-duplicate-modifiers.shader_test \
- tests/hlsl-function-overload.shader_test \ tests/hlsl-majority-pragma.shader_test \ tests/hlsl-majority-typedef.shader_test \ tests/hlsl-nested-arrays.shader_test \
diff --git a/tests/hlsl-function-overload.shader_test b/tests/hlsl-function-overload.shader_test new file mode 100644 index 00000000..c6e0ccfe --- /dev/null +++ b/tests/hlsl-function-overload.shader_test @@ -0,0 +1,40 @@ +[pixel shader fail] +/* The same function signature cannot be defined twice. */
+float func(int arg) +{
- return 0.1;
+}
+float func(int arg) +{
- return 0.1;
+}
+float4 main() : sv_target +{
- return 0;
+}
+[pixel shader] +/* Test a basic overload. */ +float func(int arg) +{
- return 0.1;
+}
+float func(uint arg) +{
- return 0.2;
+}
+float4 main() : sv_target +{
- int i = 1;
- uint u = 1;
- return float4(func(i), func(u), func(int2(1, 1)), func(uint2(1, 1)));
+}
+[test] +draw quad +probe all rgba (0.1, 0.2, 0.1, 0.2)