Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
-- v3: 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
--- Makefile.am | 1 + tests/hlsl/annotations.shader_test | 90 ++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 tests/hlsl/annotations.shader_test
diff --git a/Makefile.am b/Makefile.am index 648dfb255..1b9abc350 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,6 +47,7 @@ vkd3d_shader_tests = \ tests/hlsl/abs.shader_test \ tests/hlsl/all.shader_test \ tests/hlsl/angle-unit.shader_test \ + tests/hlsl/annotations.shader_test \ tests/hlsl/any.shader_test \ tests/hlsl/arithmetic-float-uniform.shader_test \ tests/hlsl/arithmetic-float.shader_test \ diff --git a/tests/hlsl/annotations.shader_test b/tests/hlsl/annotations.shader_test new file mode 100644 index 000000000..8592d2743 --- /dev/null +++ b/tests/hlsl/annotations.shader_test @@ -0,0 +1,90 @@ +[require] +shader model >= 4.0 +shader model < 6.0 + +[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 todo] +// Evaluated literal constant expression for initial values +technique10 < int a = 1+2; > {} + +[effect todo] +// Using constant variables in the initializer +static const int b = 123; +technique10 < int a = b; > {} + +[effect todo] +// Implicitly sized array +technique10 < float a[] = {1, 2}; > {} + +[effect todo] +// Nested braces +technique10 < float4 a = {1, {{{2, {3}}, 4}}}; > {} + +[effect todo] +// Flattening +technique10 < float4 a = {1, float2(2, 3), 4}; > {} + +[effect todo] +// Comma separated initializers +technique10 < int a = 1, b = 2; > {} + +[effect todo] +// Majority modifier +technique10 < row_major float3x2 m = {1, 2, 3, 4, 5, 6}; > {} + +[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; > {} +} + +[effect fail] +// Without initializer +technique10 < int a; > {} + +[effect fail] +// Only numeric types and strings are allowed +technique10 < DepthStencilState ds = { 0 }; > {} + +[effect fail] +// Type declarations are not allowed +technique10 < struct s { int a; } var = { 2 }; > {} + +[effect fail] +// Static modifier is not allowed +technique10 < static int a = 5; > {} + +[effect fail] +// Initializer should not depend on other annotations +technique10 < int a = 1, b = a; > {} + +[effect fail] +technique10 < int a = 1; int b = a; > {}
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 +++++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 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 e30b3dc5f..4096ce453 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)) { @@ -4959,6 +4960,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 @@ -5084,6 +5086,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 @@ -5202,6 +5206,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 @@ -5262,11 +5288,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; }
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 6a5a6d0e3..a990e021f 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -3366,6 +3366,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 4096ce453..6b8e7fdd3 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) { @@ -5205,6 +5228,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 6b8e7fdd3..449f7d0c0 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)) { @@ -5227,9 +5229,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/annotations.shader_test | 30 +++++++++++++++--------------- 2 files changed, 23 insertions(+), 22 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 449f7d0c0..87085e6a4 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)) { @@ -5266,17 +5267,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); @@ -5285,12 +5286,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); @@ -5299,7 +5300,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/annotations.shader_test b/tests/hlsl/annotations.shader_test index 8592d2743..40e383aa3 100644 --- a/tests/hlsl/annotations.shader_test +++ b/tests/hlsl/annotations.shader_test @@ -2,19 +2,19 @@ shader model >= 4.0 shader model < 6.0
-[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;
@@ -23,32 +23,32 @@ technique10 t1 < int a = 1; > pass < int a = 2; > {} }
-[effect todo] +[effect] // Evaluated literal constant expression for initial values technique10 < int a = 1+2; > {}
-[effect todo] +[effect] // Using constant variables in the initializer static const int b = 123; technique10 < int a = b; > {}
-[effect todo] +[effect] // Implicitly sized array technique10 < float a[] = {1, 2}; > {}
-[effect todo] +[effect] // Nested braces technique10 < float4 a = {1, {{{2, {3}}, 4}}}; > {}
-[effect todo] +[effect] // Flattening technique10 < float4 a = {1, float2(2, 3), 4}; > {}
-[effect todo] +[effect] // Comma separated initializers technique10 < int a = 1, b = 2; > {}
-[effect todo] +[effect] // Majority modifier technique10 < row_major float3x2 m = {1, 2, 3, 4, 5, 6}; > {}
@@ -66,7 +66,7 @@ technique10 pass < int a = 0; float a = 1.0; > {} }
-[effect fail] +[effect fail todo] // Without initializer technique10 < int a; > {}
@@ -74,17 +74,17 @@ technique10 < int a; > {} // Only numeric types and strings are allowed technique10 < DepthStencilState ds = { 0 }; > {}
-[effect fail] +[effect fail todo] // Type declarations are not allowed technique10 < struct s { int a; } var = { 2 }; > {}
-[effect fail] +[effect fail todo] // Static modifier is not allowed technique10 < static int a = 5; > {}
-[effect fail] +[effect fail todo] // Initializer should not depend on other annotations technique10 < int a = 1, b = a; > {}
-[effect fail] +[effect fail todo] technique10 < int a = 1; int b = 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 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 119 insertions(+), 11 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) {
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 Thu Jan 18 17:22:04 2024 +0000, Zebediah Figura wrote:
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.
Thanks, that was very helpful. I think this list is covered now.