Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
-- v2: vkd3d-shader/fx: Add initial support for writing passes for fx_2_0. vkd3d-shader/fx: Add initial support for writing fx_2_0 binaries. vkd3d-shader/fx: Check technique type in global scope as well. vkd3d-shader/hlsl: Allow annotations on techniques. vkd3d-shader/hlsl: Allow annotations on passes. vkd3d-shader/hlsl: Add passes variables to the techniques. vkd3d-shader/hlsl: Add initial support for parsing annotations. tests/hlsl: Add some tests for annotations.
From: Nikolay Sivov nsivov@codeweavers.com
--- tests/hlsl/technique-fx_2.shader_test | 35 +++++++++++ tests/hlsl/technique-fx_4.shader_test | 35 +++++++++++ tests/hlsl/technique-fx_5.shader_test | 84 +++++++++++++++++++++++++++ 3 files changed, 154 insertions(+)
diff --git a/tests/hlsl/technique-fx_2.shader_test b/tests/hlsl/technique-fx_2.shader_test index b84bbc167..af4cfb794 100644 --- a/tests/hlsl/technique-fx_2.shader_test +++ b/tests/hlsl/technique-fx_2.shader_test @@ -169,3 +169,38 @@ fxgroup group { technique10 {} } + +[effect todo] +// Annotations on techniques +technique t1 < int a = 1; > {} +technique t2 < int a = 2; int t1 = 3; int t2 = 4; > {} + +[effect todo] +// Annotations on passes +technique t1 < int a = 1; > +{ + pass < int t1 = 2; > {} +} + +[effect todo] +// Using names from the global scope +float a; + +technique t1 < int a = 1; > +{ + pass < int a = 2; > {} +} + +[effect fail] +// Without closing semicolon +technique t1 < int a = 1 > {} + +[effect fail] +// Redefinition +technique < int a = 0; float a = 1.0; > {} + +[effect fail] +technique +{ + pass < int a = 0; float a = 1.0; > {} +} diff --git a/tests/hlsl/technique-fx_4.shader_test b/tests/hlsl/technique-fx_4.shader_test index cdc5746e0..fde5e045f 100644 --- a/tests/hlsl/technique-fx_4.shader_test +++ b/tests/hlsl/technique-fx_4.shader_test @@ -142,3 +142,38 @@ fxgroup group { technique10 {} } + +[effect todo] +// Annotations on techniques +technique10 t1 < int a = 1; > {} +technique10 t2 < int a = 2; int t1 = 3; int t2 = 4; > {} + +[effect todo] +// Annotations on passes +technique10 t1 < int a = 1; > +{ + pass < int t1 = 2; > {} +} + +[effect todo] +// Using names from the global scope +float a; + +technique10 t1 < int a = 1; > +{ + pass < int a = 2; > {} +} + +[effect fail] +// Without closing semicolon +technique10 t1 < int a = 1 > {} + +[effect fail] +// Redefinition +technique10 < int a = 0; float a = 1.0; > {} + +[effect fail] +technique10 +{ + pass < int a = 0; float a = 1.0; > {} +} diff --git a/tests/hlsl/technique-fx_5.shader_test b/tests/hlsl/technique-fx_5.shader_test index c1e37ff17..f7851f9a8 100644 --- a/tests/hlsl/technique-fx_5.shader_test +++ b/tests/hlsl/technique-fx_5.shader_test @@ -184,3 +184,87 @@ fxgroup group2 { technique11 tech0 {} } + +[effect todo] +// Annotations on groups +fxgroup group1 <> +{ + technique11 {} +} + +fxgroup group2 < int a = 0; > +{ + technique11 {} +} + +fxgroup group3 < int a = 0; > +{ + technique11 {} +} + +[effect todo] +struct s +{ + int a; +}; + +typedef struct s s_type; + +fxgroup group1 < struct s a = (struct s)0; > +{ + technique11 {} +} + +fxgroup group2 < s_type a = (s_type)0; > +{ + technique11 {} +} + +[effect todo] +// Annotations on techniques +fxgroup group1 < int a = 0; > +{ + technique11 t1 < int a = 1; > {} + technique11 t2 < int a = 2; int t1 = 3; int t2 = 4; > {} +} + +[effect todo] +// Annotations on passes +fxgroup group1 < int a = 0; > +{ + technique11 t1 < int a = 1; > + { + pass < int t1 = 2; int group1 = 3; > {} + } +} + +[effect todo] +// Using names from the global scope +float a; + +fxgroup group1 < int a = 0; > +{ + technique11 t1 < int a = 1; > + { + pass < int a = 2; > {} + } +} + +[effect fail] +// Without closing semicolon +fxgroup group1 < int a = 0 > +{ + technique11 {} +} + +[effect fail] +// Redefinition +fxgroup group1 < int a = 0; float a = 1.0; > +{ + technique11 {} +} + +fxgroup group1 +{ + technique11 < int a = 0; float a = 1.0; > {} +}
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/hlsl.h | 2 ++ libs/vkd3d-shader/hlsl.y | 32 ++++++++++++++++++++++++--- tests/hlsl/technique-fx_5.shader_test | 4 ++-- 3 files changed, 33 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 536b46873..bf2f757fe 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -408,6 +408,8 @@ struct hlsl_ir_var struct list extern_entry; /* Scope that variable itself defines, used to provide a container for techniques and passes. */ struct hlsl_scope *scope; + /* Scope that contains annotations for this variable. */ + struct hlsl_scope *annotations;
/* Indexes of the IR instructions where the variable is first written and last read (liveness * range). The IR instructions are numerated starting from 2, because 0 means unused, and 1 diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index b11cbde26..82dffa1d0 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1122,7 +1122,7 @@ static bool add_technique(struct hlsl_ctx *ctx, const char *name, struct hlsl_sc }
static bool add_effect_group(struct hlsl_ctx *ctx, const char *name, struct hlsl_scope *scope, - const struct vkd3d_shader_location *loc) + struct hlsl_scope *annotations, const struct vkd3d_shader_location *loc) { struct hlsl_ir_var *var; struct hlsl_type *type; @@ -1131,6 +1131,7 @@ static bool add_effect_group(struct hlsl_ctx *ctx, const char *name, struct hlsl if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL))) return false; var->scope = scope; + var->annotations = annotations;
if (!hlsl_add_var(ctx, var, false)) { @@ -4916,6 +4917,7 @@ static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hls struct hlsl_attribute *attr; struct parse_attribute_list attr_list; struct hlsl_ir_switch_case *switch_case; + struct hlsl_scope *scope; }
%token KW_BLENDSTATE @@ -5041,6 +5043,8 @@ static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hls %token <name> STRING %token <name> TYPE_IDENTIFIER
+%type <scope> annotations_opt + %type <arrays> arrays
%type <assign_op> assign_op @@ -5159,6 +5163,28 @@ name_opt: pass: KW_PASS name_opt '{' '}'
+annotations_list: + variables_def_typed ';' + | annotations_list variables_def_typed ';' + +annotations_opt: + %empty + { + $$ = NULL; + } + | '<' scope_start '>' + { + hlsl_pop_scope(ctx); + $$ = NULL; + } + | '<' scope_start annotations_list '>' + { + struct hlsl_scope *scope = ctx->cur_scope; + + hlsl_pop_scope(ctx); + $$ = scope; + } + pass_list: pass | pass_list pass @@ -5219,11 +5245,11 @@ group_techniques: | group_techniques group_technique
effect_group: - KW_FXGROUP any_identifier '{' scope_start group_techniques '}' + KW_FXGROUP any_identifier annotations_opt '{' scope_start group_techniques '}' { struct hlsl_scope *scope = ctx->cur_scope; hlsl_pop_scope(ctx); - if (!(add_effect_group(ctx, $2, scope, &@2))) + if (!(add_effect_group(ctx, $2, scope, $3, &@2))) YYABORT; }
diff --git a/tests/hlsl/technique-fx_5.shader_test b/tests/hlsl/technique-fx_5.shader_test index f7851f9a8..1485ab84f 100644 --- a/tests/hlsl/technique-fx_5.shader_test +++ b/tests/hlsl/technique-fx_5.shader_test @@ -185,7 +185,7 @@ fxgroup group2 technique11 tech0 {} }
-[effect todo] +[effect] // Annotations on groups fxgroup group1 <> { @@ -202,7 +202,7 @@ fxgroup group3 < int a = 0; > technique11 {} }
-[effect todo] +[effect] struct s { int a;
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/hlsl.c | 1 + libs/vkd3d-shader/hlsl.h | 1 + libs/vkd3d-shader/hlsl.y | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 1e2474451..165cfe2de 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -3367,6 +3367,7 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) {"vector", HLSL_CLASS_VECTOR, HLSL_TYPE_FLOAT, 4, 1}, {"matrix", HLSL_CLASS_MATRIX, HLSL_TYPE_FLOAT, 4, 4}, {"fxgroup", HLSL_CLASS_OBJECT, HLSL_TYPE_EFFECT_GROUP, 1, 1}, + {"pass", HLSL_CLASS_OBJECT, HLSL_TYPE_PASS, 1, 1}, {"STRING", HLSL_CLASS_OBJECT, HLSL_TYPE_STRING, 1, 1}, {"TEXTURE", HLSL_CLASS_OBJECT, HLSL_TYPE_TEXTURE, 1, 1}, {"PIXELSHADER", HLSL_CLASS_OBJECT, HLSL_TYPE_PIXELSHADER, 1, 1}, diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index bf2f757fe..58188ce6f 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -95,6 +95,7 @@ enum hlsl_base_type HLSL_TYPE_UAV, HLSL_TYPE_PIXELSHADER, HLSL_TYPE_VERTEXSHADER, + HLSL_TYPE_PASS, HLSL_TYPE_TECHNIQUE, HLSL_TYPE_EFFECT_GROUP, HLSL_TYPE_STRING, diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 82dffa1d0..314a30c6b 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1096,6 +1096,29 @@ static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters return true; }
+static bool add_pass(struct hlsl_ctx *ctx, const char *name, const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_var *var; + struct hlsl_type *type; + + type = hlsl_get_type(ctx->globals, "pass", false, false); + if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL))) + return false; + + if (!hlsl_add_var(ctx, var, false)) + { + struct hlsl_ir_var *old = hlsl_get_var(ctx->cur_scope, var->name); + + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_REDEFINED, + "Identifier "%s" was already declared in this scope.", var->name); + hlsl_note(ctx, &old->loc, VKD3D_SHADER_LOG_ERROR, ""%s" was previously declared here.", old->name); + hlsl_free_var(var); + return false; + } + + return true; +} + static bool add_technique(struct hlsl_ctx *ctx, const char *name, struct hlsl_scope *scope, const char *typename, const struct vkd3d_shader_location *loc) { @@ -5162,6 +5185,10 @@ name_opt:
pass: KW_PASS name_opt '{' '}' + { + if (!add_pass(ctx, $2, &@1)) + YYABORT; + }
annotations_list: variables_def_typed ';'
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/hlsl.y | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 314a30c6b..1b9714619 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1096,7 +1096,8 @@ static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters return true; }
-static bool add_pass(struct hlsl_ctx *ctx, const char *name, const struct vkd3d_shader_location *loc) +static bool add_pass(struct hlsl_ctx *ctx, const char *name, struct hlsl_scope *annotations, + const struct vkd3d_shader_location *loc) { struct hlsl_ir_var *var; struct hlsl_type *type; @@ -1104,6 +1105,7 @@ static bool add_pass(struct hlsl_ctx *ctx, const char *name, const struct vkd3d_ type = hlsl_get_type(ctx->globals, "pass", false, false); if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL))) return false; + var->annotations = annotations;
if (!hlsl_add_var(ctx, var, false)) { @@ -5184,9 +5186,9 @@ name_opt: | any_identifier
pass: - KW_PASS name_opt '{' '}' + KW_PASS name_opt annotations_opt '{' '}' { - if (!add_pass(ctx, $2, &@1)) + if (!add_pass(ctx, $2, $3, &@1)) YYABORT; }
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/hlsl.y | 15 ++++++++------- tests/hlsl/technique-fx_4.shader_test | 6 +++--- tests/hlsl/technique-fx_5.shader_test | 4 ++-- 3 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 1b9714619..e1b84567e 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1122,7 +1122,7 @@ static bool add_pass(struct hlsl_ctx *ctx, const char *name, struct hlsl_scope * }
static bool add_technique(struct hlsl_ctx *ctx, const char *name, struct hlsl_scope *scope, - const char *typename, const struct vkd3d_shader_location *loc) + struct hlsl_scope *annotations, const char *typename, const struct vkd3d_shader_location *loc) { struct hlsl_ir_var *var; struct hlsl_type *type; @@ -1131,6 +1131,7 @@ static bool add_technique(struct hlsl_ctx *ctx, const char *name, struct hlsl_sc if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL))) return false; var->scope = scope; + var->annotations = annotations;
if (!hlsl_add_var(ctx, var, false)) { @@ -5223,17 +5224,17 @@ passes: | scope_start pass_list
technique9: - KW_TECHNIQUE name_opt '{' passes '}' + KW_TECHNIQUE name_opt annotations_opt '{' passes '}' { struct hlsl_scope *scope = ctx->cur_scope; hlsl_pop_scope(ctx);
- if (!add_technique(ctx, $2, scope, "technique", &@1)) + if (!add_technique(ctx, $2, scope, $3, "technique", &@1)) YYABORT; }
technique10: - KW_TECHNIQUE10 name_opt '{' passes '}' + KW_TECHNIQUE10 name_opt annotations_opt '{' passes '}' { struct hlsl_scope *scope = ctx->cur_scope; hlsl_pop_scope(ctx); @@ -5242,12 +5243,12 @@ technique10: hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "The 'technique10' keyword is invalid for this profile.");
- if (!add_technique(ctx, $2, scope, "technique10", &@1)) + if (!add_technique(ctx, $2, scope, $3, "technique10", &@1)) YYABORT; }
technique11: - KW_TECHNIQUE11 name_opt '{' passes '}' + KW_TECHNIQUE11 name_opt annotations_opt '{' passes '}' { struct hlsl_scope *scope = ctx->cur_scope; hlsl_pop_scope(ctx); @@ -5256,7 +5257,7 @@ technique11: hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "The 'technique11' keyword is invalid for this profile.");
- if (!add_technique(ctx, $2, scope, "technique11", &@1)) + if (!add_technique(ctx, $2, scope, $3, "technique11", &@1)) YYABORT; }
diff --git a/tests/hlsl/technique-fx_4.shader_test b/tests/hlsl/technique-fx_4.shader_test index fde5e045f..591277dea 100644 --- a/tests/hlsl/technique-fx_4.shader_test +++ b/tests/hlsl/technique-fx_4.shader_test @@ -143,19 +143,19 @@ fxgroup group technique10 {} }
-[effect todo] +[effect] // Annotations on techniques technique10 t1 < int a = 1; > {} technique10 t2 < int a = 2; int t1 = 3; int t2 = 4; > {}
-[effect todo] +[effect] // Annotations on passes technique10 t1 < int a = 1; > { pass < int t1 = 2; > {} }
-[effect todo] +[effect] // Using names from the global scope float a;
diff --git a/tests/hlsl/technique-fx_5.shader_test b/tests/hlsl/technique-fx_5.shader_test index 1485ab84f..5f63b0b4a 100644 --- a/tests/hlsl/technique-fx_5.shader_test +++ b/tests/hlsl/technique-fx_5.shader_test @@ -228,7 +228,7 @@ fxgroup group1 < int a = 0; > technique11 t2 < int a = 2; int t1 = 3; int t2 = 4; > {} }
-[effect todo] +[effect] // Annotations on passes fxgroup group1 < int a = 0; > { @@ -238,7 +238,7 @@ fxgroup group1 < int a = 0; > } }
-[effect todo] +[effect] // Using names from the global scope float a;
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/fx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c index 17b9627b6..f9e03adf0 100644 --- a/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d-shader/fx.c @@ -176,9 +176,7 @@ static void write_techniques(struct hlsl_scope *scope, struct fx_write_context *
LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry) { - const struct hlsl_type *type = var->data_type; - - if (type->base_type == HLSL_TYPE_TECHNIQUE && type->e.version == 10) + if (technique_matches_version(var, fx)) { write_technique(var, fx); ++fx->technique_count;
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/fx.c | 130 +++++++++++++++++++++++--- tests/hlsl/technique-fx_2.shader_test | 6 +- 2 files changed, 122 insertions(+), 14 deletions(-)
diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c index f9e03adf0..a737c486b 100644 --- a/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d-shader/fx.c @@ -43,6 +43,14 @@ static void string_storage_destroy(struct rb_entry *entry, void *context) vkd3d_free(string_entry); }
+struct fx_write_context; + +struct fx_write_context_ops +{ + uint32_t (*write_string)(const char *string, struct fx_write_context *fx); + void (*write_technique)(struct hlsl_ir_var *var, struct fx_write_context *fx); +}; + struct fx_write_context { struct hlsl_ctx *ctx; @@ -58,15 +66,24 @@ struct fx_write_context uint32_t technique_count; uint32_t group_count; int status; + + const struct fx_write_context_ops *ops; };
-static void fx_write_context_init(struct hlsl_ctx *ctx, struct fx_write_context *fx) +static uint32_t write_string(const char *string, struct fx_write_context *fx) +{ + return fx->ops->write_string(string, fx); +} + +static void fx_write_context_init(struct hlsl_ctx *ctx, const struct fx_write_context_ops *ops, + struct fx_write_context *fx) { unsigned int version = ctx->profile->major_version;
memset(fx, 0, sizeof(*fx));
fx->ctx = ctx; + fx->ops = ops; if (version == 2) { fx->min_technique_version = 9; @@ -104,7 +121,7 @@ static bool technique_matches_version(const struct hlsl_ir_var *var, const struc return type->e.version >= fx->min_technique_version && type->e.version <= fx->max_technique_version; }
-static uint32_t fx_put_raw_string(struct fx_write_context *fx, const char *string) +static uint32_t write_fx_4_string(const char *string, struct fx_write_context *fx) { struct string_entry *string_entry; struct rb_entry *entry; @@ -135,20 +152,20 @@ static void write_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) struct vkd3d_bytecode_buffer *buffer = &fx->structured; uint32_t name_offset;
- name_offset = fx_put_raw_string(fx, var->name); + name_offset = write_string(var->name, fx); put_u32(buffer, name_offset); put_u32(buffer, 0); /* Annotation count. */ put_u32(buffer, 0); /* Assignment count. */ }
-static void write_technique(struct hlsl_ir_var *var, struct fx_write_context *fx) +static void write_fx_4_technique(struct hlsl_ir_var *var, struct fx_write_context *fx) { struct vkd3d_bytecode_buffer *buffer = &fx->structured; uint32_t name_offset, count = 0; struct hlsl_ir_var *pass; uint32_t count_offset;
- name_offset = fx_put_raw_string(fx, var->name); + name_offset = write_string(var->name, fx); put_u32(buffer, name_offset); count_offset = put_u32(buffer, 0); put_u32(buffer, 0); /* Annotation count. */ @@ -178,7 +195,7 @@ static void write_techniques(struct hlsl_scope *scope, struct fx_write_context * { if (technique_matches_version(var, fx)) { - write_technique(var, fx); + fx->ops->write_technique(var, fx); ++fx->technique_count; } } @@ -190,7 +207,7 @@ static void write_techniques(struct hlsl_scope *scope, struct fx_write_context * static void write_group(struct hlsl_scope *scope, const char *name, struct fx_write_context *fx) { struct vkd3d_bytecode_buffer *buffer = &fx->structured; - uint32_t name_offset = fx_put_raw_string(fx, name); + uint32_t name_offset = write_string(name, fx); uint32_t count_offset, count;
put_u32(buffer, name_offset); @@ -229,13 +246,105 @@ static void write_groups(struct hlsl_scope *scope, struct fx_write_context *fx) } }
+static uint32_t write_fx_2_string(const char *string, struct fx_write_context *fx) +{ + struct vkd3d_bytecode_buffer *buffer = &fx->unstructured; + const char *s = string ? string : ""; + uint32_t size, offset; + + size = strlen(s) + 1; + offset = put_u32(buffer, size); + bytecode_put_bytes(buffer, s, size); + return offset; +} + +static void write_fx_2_technique(struct hlsl_ir_var *var, struct fx_write_context *fx) +{ + struct vkd3d_bytecode_buffer *buffer = &fx->structured; + uint32_t name_offset; + + name_offset = write_string(var->name, fx); + put_u32(buffer, name_offset); + put_u32(buffer, 0); /* Annotation count. */ + put_u32(buffer, 0); /* Pass count. */ + + /* FIXME: annotations */ + /* FIXME: passes */ +} + +static const struct fx_write_context_ops fx_2_ops = +{ + .write_string = write_fx_2_string, + .write_technique = write_fx_2_technique, +}; + +static int hlsl_fx_2_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) +{ + struct vkd3d_bytecode_buffer buffer = { 0 }; + struct vkd3d_bytecode_buffer *structured; + uint32_t offset, size, technique_count; + struct fx_write_context fx; + + fx_write_context_init(ctx, &fx_2_ops, &fx); + structured = &fx.structured; + + /* First entry is always zeroed and skipped. */ + put_u32(&fx.unstructured, 0); + + put_u32(&buffer, 0xfeff0901); /* Version. */ + offset = put_u32(&buffer, 0); + + put_u32(structured, 0); /* Parameter count */ + technique_count = put_u32(structured, 0); + put_u32(structured, 0); /* Unknown */ + put_u32(structured, 0); /* Object count */ + + /* TODO: parameters */ + + write_techniques(ctx->globals, &fx); + set_u32(structured, technique_count, fx.technique_count); + + put_u32(structured, 0); /* String count */ + put_u32(structured, 0); /* Resource count */ + + /* TODO: strings */ + /* TODO: resources */ + + size = align(fx.unstructured.size, 4); + /* Accounts for additional 4 bytes before the raw data section. */ + set_u32(&buffer, offset, size); + + bytecode_put_bytes(&buffer, fx.unstructured.data, fx.unstructured.size); + bytecode_put_bytes(&buffer, fx.structured.data, fx.structured.size); + + vkd3d_free(fx.unstructured.data); + vkd3d_free(fx.structured.data); + + if (!fx.status) + { + out->code = buffer.data; + out->size = buffer.size; + } + + if (fx.status < 0) + ctx->result = fx.status; + + return fx_write_context_cleanup(&fx); +} + +static const struct fx_write_context_ops fx_4_ops = +{ + .write_string = write_fx_4_string, + .write_technique = write_fx_4_technique, +}; + static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) { struct vkd3d_bytecode_buffer buffer = { 0 }; struct fx_write_context fx; uint32_t size_offset, size;
- fx_write_context_init(ctx, &fx); + fx_write_context_init(ctx, &fx_4_ops, &fx);
put_u32(&fx.unstructured, 0); /* Empty string placeholder. */
@@ -295,7 +404,7 @@ static int hlsl_fx_5_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) struct fx_write_context fx; uint32_t size_offset, size;
- fx_write_context_init(ctx, &fx); + fx_write_context_init(ctx, &fx_4_ops, &fx);
put_u32(&fx.unstructured, 0); /* Empty string placeholder. */
@@ -357,8 +466,7 @@ int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) { if (ctx->profile->major_version == 2) { - hlsl_fixme(ctx, &ctx->location, "Writing fx_2_0 binaries is not implemented."); - return VKD3D_ERROR_NOT_IMPLEMENTED; + return hlsl_fx_2_write(ctx, out); } else if (ctx->profile->major_version == 4) { diff --git a/tests/hlsl/technique-fx_2.shader_test b/tests/hlsl/technique-fx_2.shader_test index af4cfb794..6141c9917 100644 --- a/tests/hlsl/technique-fx_2.shader_test +++ b/tests/hlsl/technique-fx_2.shader_test @@ -170,19 +170,19 @@ fxgroup group technique10 {} }
-[effect todo] +[effect] // Annotations on techniques technique t1 < int a = 1; > {} technique t2 < int a = 2; int t1 = 3; int t2 = 4; > {}
-[effect todo] +[effect] // Annotations on passes technique t1 < int a = 1; > { pass < int t1 = 2; > {} }
-[effect todo] +[effect] // Using names from the global scope float a;
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/fx.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c index a737c486b..e1459f76c 100644 --- a/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d-shader/fx.c @@ -49,6 +49,7 @@ struct fx_write_context_ops { uint32_t (*write_string)(const char *string, struct fx_write_context *fx); void (*write_technique)(struct hlsl_ir_var *var, struct fx_write_context *fx); + void (*write_pass)(struct hlsl_ir_var *var, struct fx_write_context *fx); };
struct fx_write_context @@ -75,6 +76,11 @@ static uint32_t write_string(const char *string, struct fx_write_context *fx) return fx->ops->write_string(string, fx); }
+static void write_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) +{ + fx->ops->write_pass(var, fx); +} + static void fx_write_context_init(struct hlsl_ctx *ctx, const struct fx_write_context_ops *ops, struct fx_write_context *fx) { @@ -147,7 +153,21 @@ static uint32_t write_fx_4_string(const char *string, struct fx_write_context *f return string_entry->offset; }
-static void write_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) +static void write_fx_4_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) +{ + struct vkd3d_bytecode_buffer *buffer = &fx->structured; + uint32_t name_offset; + + name_offset = write_string(var->name, fx); + put_u32(buffer, name_offset); + put_u32(buffer, 0); /* Assignment count. */ + put_u32(buffer, 0); /* Annotation count. */ + + /* TODO: annotations */ + /* TODO: assignments */ +} + +static void write_fx_2_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) { struct vkd3d_bytecode_buffer *buffer = &fx->structured; uint32_t name_offset; @@ -156,6 +176,9 @@ static void write_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) put_u32(buffer, name_offset); put_u32(buffer, 0); /* Annotation count. */ put_u32(buffer, 0); /* Assignment count. */ + + /* TODO: annotations */ + /* TODO: assignments */ }
static void write_fx_4_technique(struct hlsl_ir_var *var, struct fx_write_context *fx) @@ -261,21 +284,30 @@ static uint32_t write_fx_2_string(const char *string, struct fx_write_context *f static void write_fx_2_technique(struct hlsl_ir_var *var, struct fx_write_context *fx) { struct vkd3d_bytecode_buffer *buffer = &fx->structured; - uint32_t name_offset; + uint32_t name_offset, count_offset, count = 0; + struct hlsl_ir_var *pass;
name_offset = write_string(var->name, fx); put_u32(buffer, name_offset); put_u32(buffer, 0); /* Annotation count. */ - put_u32(buffer, 0); /* Pass count. */ + count_offset = put_u32(buffer, 0); /* Pass count. */
/* FIXME: annotations */ - /* FIXME: passes */ + + LIST_FOR_EACH_ENTRY(pass, &var->scope->vars, struct hlsl_ir_var, scope_entry) + { + write_pass(pass, fx); + ++count; + } + + set_u32(buffer, count_offset, count); }
static const struct fx_write_context_ops fx_2_ops = { .write_string = write_fx_2_string, .write_technique = write_fx_2_technique, + .write_pass = write_fx_2_pass, };
static int hlsl_fx_2_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) @@ -311,7 +343,6 @@ static int hlsl_fx_2_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) /* TODO: resources */
size = align(fx.unstructured.size, 4); - /* Accounts for additional 4 bytes before the raw data section. */ set_u32(&buffer, offset, size);
bytecode_put_bytes(&buffer, fx.unstructured.data, fx.unstructured.size); @@ -336,6 +367,7 @@ static const struct fx_write_context_ops fx_4_ops = { .write_string = write_fx_4_string, .write_technique = write_fx_4_technique, + .write_pass = write_fx_4_pass, };
static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
On Wed Jan 17 15:15:04 2024 +0000, Nikolay Sivov wrote:
Yes, I'll start with that. Regarding redefinition for passes, what do you mean exactly? Name conflicts with multiple passes using same name, or something else?
Pushed something for basic tests.
On Wed Jan 17 18:19:54 2024 +0000, Nikolay Sivov wrote:
Pushed something for basic tests.
Yes. Since we have code in place to check for redefinition then we should have tests for that as well.
On Wed Jan 17 15:23:09 2024 +0000, Nikolay Sivov wrote:
I think initialize_vars() is not suitable for general use case of just storing initializer. Current it does produce blocks to initialize what could be actually initialized. For the purposes of effects metadata, what we need is per-variable initializer field, that could later be turned to such instruction blocks if necessary. Cases when it's not necessary are state objects, strings, and annotations.
I don't understand what's wrong with producing blocks?
On Wed Jan 17 19:12:32 2024 +0000, Zebediah Figura wrote:
I don't understand what's wrong with producing blocks?
Why would I produce blocks for e.g. assigning state object fields? It means that first you get instruction lists that you later have to iterate over again to figure out what to do with them. For example, for a matrix it's enough to simplify each element individually and then write them all together. Using blocks has an advantage of easily evaluating constant expressions, but then to write actual result for any type that's not a scalar, you'll have to sort of interpret such blocks. Then for strings, it will produce a string constant load, without string constants supported anywhere else.
On Wed Jan 17 20:02:59 2024 +0000, Nikolay Sivov wrote:
Why would I produce blocks for e.g. assigning state object fields? It means that first you get instruction lists that you later have to iterate over again to figure out what to do with them. For example, for a matrix it's enough to simplify each element individually and then write them all together. Using blocks has an advantage of easily evaluating constant expressions, but then to write actual result for any type that's not a scalar, you'll have to sort of interpret such blocks. Then for strings, it will produce a string constant load, without string constants supported anywhere else.
Oh, I see, you mean that it produces a single block.
It's not unworkable or even necessarily complex with a single block (consider e.g. emitting a load per component, adding a hlsl_src, then running copy-prop), but it may indeed be easier to work from the parse_variable_def list. But at the same time that probably means we're going to duplicate a lot of code. I'd have to see the code in question.
In any case it doesn't really affect this merge request enough to block it, so I'll set it aside for now.
These annotation tests are good to start with, but we could use more. Here are some that occur to me:
* Can you use braced initializers? They work the same way as the rest of HLSL, right? [E.g. braces aren't validated; unwritten components are initialized to zero; variable boundaries need not match.] Cf. initializer-nested.shader_test and initializer-flatten.shader_test; of course we don't need to copy every test but one or two should be enough to answer this question in the affirmative.
* Can you leave variables uninitialized? If so, can you put a state block in there?
* Can you declare a type *within* the annotation, via a typedef or struct declaration?
* If not, can you still declare a struct and a variable at the same time? (I.e. "struct apple { ...} a;")
* Can you give variables values that require constant folding?
* Can you give variables values that require copy-prop? (E.g. assigning to a previously declared static const variable).
* Can you give variables modifiers? Both type qualifiers like "row_major", and storage modifiers like "static", are interesting to test here.
* Can you use the comma to separate multiple variable declarations? Cf. also initializer-multi.shader_test.
* Can you declare implicitly sized arrays?
I also doubt it's worth duplicating the annotation tests for every effect model if they seem to behave identically. On the other hand, we might want to put them into a dedicated test file.