Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
-- v7: vkd3d-shader/tpf: Initial support for writing fx_4_0/fx_4_1 binaries. vkd3d-shader: Add separate binary target type for effects. vkd3d-shader/hlsl: Handle effect group statement. vkd3d-shader/hlsl: Add variables for techniques. vkd3d-shader/hlsl: Rename rule for top-level techniques. vkd3d-shader/hlsl: Add 'fxgroup' token. tests: Add some tests for effects groups syntax.
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- tests/hlsl/technique-fx_2.shader_test | 31 +++++++++++++ tests/hlsl/technique-fx_4.shader_test | 24 ++++++++++ tests/hlsl/technique-fx_5.shader_test | 66 +++++++++++++++++++++++++++ 3 files changed, 121 insertions(+)
diff --git a/tests/hlsl/technique-fx_2.shader_test b/tests/hlsl/technique-fx_2.shader_test index 90c734d53..42e523f22 100644 --- a/tests/hlsl/technique-fx_2.shader_test +++ b/tests/hlsl/technique-fx_2.shader_test @@ -38,6 +38,13 @@ float4 main() : sv_target return float4(0, 0, 0, 0); }
+[pixel shader fail todo] +float4 main() : sv_target +{ + float4 fxgroup = {0, 0, 0, 0}; + return fxgroup; +} + [pixel shader] typedef float4 Technique10; typedef float4 Technique11; @@ -62,6 +69,13 @@ float4 main() : sv_target return teChnique11; }
+[pixel shader] +float4 main() : sv_target +{ + float4 fxGroup = {0, 0, 0, 0}; + return fxGroup; +} + [effect todo] technique { @@ -103,6 +117,11 @@ tEchnique11 { }
+[effect fail] +fxgroup group +{ +} + % Regular shaders with technique blocks [vertex shader todo] float4 main() : sv_position @@ -122,6 +141,12 @@ technique11 { }
+// Empty groups are not allowed +fxgroup group +{ + technique10 {} +} + [pixel shader todo] float4 main() : sv_target { @@ -139,3 +164,9 @@ technique10 technique11 { } + +// Empty groups are not allowed +fxgroup group +{ + technique10 {} +} diff --git a/tests/hlsl/technique-fx_4.shader_test b/tests/hlsl/technique-fx_4.shader_test index fb8a3e675..2fc481de5 100644 --- a/tests/hlsl/technique-fx_4.shader_test +++ b/tests/hlsl/technique-fx_4.shader_test @@ -9,6 +9,13 @@ float4 main() : sv_target return teChnique; }
+[pixel shader fail todo] +float4 main() : sv_target +{ + float4 fxgroup = {0, 0, 0, 0}; + return fxgroup; +} + [pixel shader] float4 main() : sv_target { @@ -23,6 +30,13 @@ float4 main() : sv_target return teChnique11; }
+[pixel shader] +float4 main() : sv_target +{ + float4 fxGroup = {0, 0, 0, 0}; + return fxGroup; +} + [effect todo] technique { @@ -101,6 +115,11 @@ technique11 { }
+fxgroup group +{ + technique10 {} +} + [pixel shader todo] float4 main() : sv_target { @@ -118,3 +137,8 @@ technique10 technique11 { } + +fxgroup group +{ + technique10 {} +} diff --git a/tests/hlsl/technique-fx_5.shader_test b/tests/hlsl/technique-fx_5.shader_test index aeea1a84f..152227c62 100644 --- a/tests/hlsl/technique-fx_5.shader_test +++ b/tests/hlsl/technique-fx_5.shader_test @@ -9,6 +9,13 @@ float4 main() : sv_target return teChnique; }
+[pixel shader fail todo] +float4 main() : sv_target +{ + float4 fxgroup = {0, 0, 0, 0}; + return fxgroup; +} + [pixel shader] float4 main() : sv_target { @@ -23,6 +30,13 @@ float4 main() : sv_target return teChnique11; }
+[pixel shader] +float4 main() : sv_target +{ + float4 fxGroup = {0, 0, 0, 0}; + return fxGroup; +} + [effect todo] technique { @@ -101,6 +115,11 @@ technique11 { }
+fxgroup group +{ + technique10 {} +} + [pixel shader todo] float4 main() : sv_target { @@ -118,3 +137,50 @@ technique10 technique11 { } + +fxgroup group +{ + technique10 {} +} + +% Groups syntax + +% Name has to be specified, it belongs to global scope +[effect fail] +fxgroup +{ +} + +% Group can't be empty +[effect fail] +fxgroup group +{ +} + +[effect fail] +float4 group; + +fxgroup group +{ +} + +% Groups can only contain a list of techniques +[effect fail] +fxgroup group +{ + float4 v; + + technique11 {} +} + +% Group provides scope for techniques +[effect todo] +fxgroup group1 +{ + technique11 tech0 {} +} + +fxgroup group2 +{ + technique11 tech0 {} +}
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/hlsl.l | 1 + libs/vkd3d-shader/hlsl.y | 1 + tests/hlsl/technique-fx_2.shader_test | 2 +- tests/hlsl/technique-fx_4.shader_test | 2 +- tests/hlsl/technique-fx_5.shader_test | 2 +- 5 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.l b/libs/vkd3d-shader/hlsl.l index 0e5f2bb61..c4c0dd249 100644 --- a/libs/vkd3d-shader/hlsl.l +++ b/libs/vkd3d-shader/hlsl.l @@ -89,6 +89,7 @@ else {return KW_ELSE; } extern {return KW_EXTERN; } false {return KW_FALSE; } for {return KW_FOR; } +fxgroup {return KW_FXGROUP; } GeometryShader {return KW_GEOMETRYSHADER; } groupshared {return KW_GROUPSHARED; } if {return KW_IF; } diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 0e72a539e..553387b1e 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -4788,6 +4788,7 @@ static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hls %token KW_EXTERN %token KW_FALSE %token KW_FOR +%token KW_FXGROUP %token KW_GEOMETRYSHADER %token KW_GROUPSHARED %token KW_IF diff --git a/tests/hlsl/technique-fx_2.shader_test b/tests/hlsl/technique-fx_2.shader_test index 42e523f22..f86cc005d 100644 --- a/tests/hlsl/technique-fx_2.shader_test +++ b/tests/hlsl/technique-fx_2.shader_test @@ -38,7 +38,7 @@ float4 main() : sv_target return float4(0, 0, 0, 0); }
-[pixel shader fail todo] +[pixel shader fail] float4 main() : sv_target { float4 fxgroup = {0, 0, 0, 0}; diff --git a/tests/hlsl/technique-fx_4.shader_test b/tests/hlsl/technique-fx_4.shader_test index 2fc481de5..7968cb9de 100644 --- a/tests/hlsl/technique-fx_4.shader_test +++ b/tests/hlsl/technique-fx_4.shader_test @@ -9,7 +9,7 @@ float4 main() : sv_target return teChnique; }
-[pixel shader fail todo] +[pixel shader fail] float4 main() : sv_target { float4 fxgroup = {0, 0, 0, 0}; diff --git a/tests/hlsl/technique-fx_5.shader_test b/tests/hlsl/technique-fx_5.shader_test index 152227c62..29aa616f9 100644 --- a/tests/hlsl/technique-fx_5.shader_test +++ b/tests/hlsl/technique-fx_5.shader_test @@ -9,7 +9,7 @@ float4 main() : sv_target return teChnique; }
-[pixel shader fail todo] +[pixel shader fail] float4 main() : sv_target { float4 fxgroup = {0, 0, 0, 0};
From: Nikolay Sivov nsivov@codeweavers.com
Only technique10 and technique11 types could be nested in groups.
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/hlsl.y | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 553387b1e..9ce27c3ff 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -4993,7 +4993,7 @@ hlsl_prog: destroy_block($2); } | hlsl_prog preproc_directive - | hlsl_prog technique + | hlsl_prog global_technique | hlsl_prog ';'
technique_name: @@ -5032,7 +5032,7 @@ technique11: hlsl_fixme(ctx, &@$, "Unsupported 'technique11' declaration."); }
-technique: +global_technique: technique9 | technique10 | technique11
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/hlsl.c | 3 +++ libs/vkd3d-shader/hlsl.h | 3 +++ libs/vkd3d-shader/hlsl.y | 36 ++++++++++++++++++++++++--- tests/hlsl/technique-fx_2.shader_test | 6 ++--- tests/hlsl/technique-fx_4.shader_test | 4 +-- tests/hlsl/technique-fx_5.shader_test | 4 +-- 6 files changed, 46 insertions(+), 10 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 1d3fd0f7d..290be3add 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -3388,6 +3388,9 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) {"float", HLSL_CLASS_SCALAR, HLSL_TYPE_FLOAT, 1, 1}, {"vector", HLSL_CLASS_VECTOR, HLSL_TYPE_FLOAT, 4, 1}, {"matrix", HLSL_CLASS_MATRIX, HLSL_TYPE_FLOAT, 4, 4}, + {"technique", HLSL_CLASS_OBJECT, HLSL_TYPE_TECHNIQUE, 1, 1}, + {"technique10", HLSL_CLASS_OBJECT, HLSL_TYPE_TECHNIQUE10, 1, 1}, + {"technique11", HLSL_CLASS_OBJECT, HLSL_TYPE_TECHNIQUE11, 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 309d7080f..8fd1429b8 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -95,6 +95,9 @@ enum hlsl_base_type HLSL_TYPE_UAV, HLSL_TYPE_PIXELSHADER, HLSL_TYPE_VERTEXSHADER, + HLSL_TYPE_TECHNIQUE, + HLSL_TYPE_TECHNIQUE10, + HLSL_TYPE_TECHNIQUE11, HLSL_TYPE_STRING, HLSL_TYPE_VOID, }; diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 9ce27c3ff..b52e571fb 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1096,6 +1096,33 @@ static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters return true; }
+static bool add_technique(struct hlsl_ctx *ctx, const char *name, const char *typename, + const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_var *var; + struct hlsl_type *type; + + if (!name) + name = hlsl_sprintf_alloc(ctx, "<technique-%u>", ctx->internal_name_counter++); + type = hlsl_get_type(ctx->globals, typename, 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, + "Variable "%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 struct hlsl_reg_reservation parse_reg_reservation(const char *reg_string) { struct hlsl_reg_reservation reservation = {0}; @@ -5009,7 +5036,8 @@ pass_list: technique9: KW_TECHNIQUE technique_name '{' pass_list '}' { - hlsl_fixme(ctx, &@$, "Unsupported 'technique' declaration."); + if (!add_technique(ctx, $2, "technique", &@1)) + YYABORT; }
technique10: @@ -5019,7 +5047,8 @@ technique10: hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "The 'technique10' keyword is invalid for this profile.");
- hlsl_fixme(ctx, &@$, "Unsupported 'technique10' declaration."); + if (!add_technique(ctx, $2, "technique10", &@1)) + YYABORT; }
technique11: @@ -5029,7 +5058,8 @@ technique11: hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "The 'technique11' keyword is invalid for this profile.");
- hlsl_fixme(ctx, &@$, "Unsupported 'technique11' declaration."); + if (!add_technique(ctx, $2, "technique11", &@1)) + YYABORT; }
global_technique: diff --git a/tests/hlsl/technique-fx_2.shader_test b/tests/hlsl/technique-fx_2.shader_test index f86cc005d..e0ac1901e 100644 --- a/tests/hlsl/technique-fx_2.shader_test +++ b/tests/hlsl/technique-fx_2.shader_test @@ -90,7 +90,7 @@ technique10 float4 f;
% fx_5_0 keyword fails with fx_2_0 profile -[effect fail todo] +[effect fail] technique { } @@ -99,7 +99,7 @@ technique11 { }
-[effect fail todo] +[effect fail] technique { } @@ -108,7 +108,7 @@ tEchnique10 { }
-[effect fail todo] +[effect fail] technique { } diff --git a/tests/hlsl/technique-fx_4.shader_test b/tests/hlsl/technique-fx_4.shader_test index 7968cb9de..02317483a 100644 --- a/tests/hlsl/technique-fx_4.shader_test +++ b/tests/hlsl/technique-fx_4.shader_test @@ -60,7 +60,7 @@ technique11 { }
-[effect fail todo] +[effect fail] technique { } @@ -69,7 +69,7 @@ tEchnique10 { }
-[effect fail todo] +[effect fail] technique { } diff --git a/tests/hlsl/technique-fx_5.shader_test b/tests/hlsl/technique-fx_5.shader_test index 29aa616f9..fd1cf4cf9 100644 --- a/tests/hlsl/technique-fx_5.shader_test +++ b/tests/hlsl/technique-fx_5.shader_test @@ -60,7 +60,7 @@ technique11 { }
-[effect fail todo] +[effect fail] technique { } @@ -69,7 +69,7 @@ tEchnique10 { }
-[effect fail todo] +[effect fail] technique { }
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 | 3 ++ libs/vkd3d-shader/hlsl.y | 43 +++++++++++++++++++++++++++ tests/hlsl/technique-fx_2.shader_test | 4 +-- tests/hlsl/technique-fx_4.shader_test | 4 +-- tests/hlsl/technique-fx_5.shader_test | 4 +-- 6 files changed, 53 insertions(+), 6 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 290be3add..1b0862d63 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -3391,6 +3391,7 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) {"technique", HLSL_CLASS_OBJECT, HLSL_TYPE_TECHNIQUE, 1, 1}, {"technique10", HLSL_CLASS_OBJECT, HLSL_TYPE_TECHNIQUE10, 1, 1}, {"technique11", HLSL_CLASS_OBJECT, HLSL_TYPE_TECHNIQUE11, 1, 1}, + {"fxgroup", HLSL_CLASS_OBJECT, HLSL_TYPE_EFFECT_GROUP, 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 8fd1429b8..b6611dddc 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -98,6 +98,7 @@ enum hlsl_base_type HLSL_TYPE_TECHNIQUE, HLSL_TYPE_TECHNIQUE10, HLSL_TYPE_TECHNIQUE11, + HLSL_TYPE_EFFECT_GROUP, HLSL_TYPE_STRING, HLSL_TYPE_VOID, }; @@ -402,6 +403,8 @@ struct hlsl_ir_var struct list scope_entry; /* Item entry in hlsl_ctx.extern_vars, if the variable is extern. */ struct list extern_entry; + /* Scope that variable itself defines, used to provide a container for techniques and passes. */ + struct hlsl_scope *scope;
/* 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 b52e571fb..adcd91b22 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1123,6 +1123,31 @@ static bool add_technique(struct hlsl_ctx *ctx, const char *name, const char *ty return true; }
+static bool add_effect_group(struct hlsl_ctx *ctx, const char *name, struct hlsl_scope *scope, + const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_var *var; + struct hlsl_type *type; + + type = hlsl_get_type(ctx->globals, "fxgroup", false, false); + if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL))) + return false; + var->scope = scope; + + 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, + "Variable "%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 struct hlsl_reg_reservation parse_reg_reservation(const char *reg_string) { struct hlsl_reg_reservation reservation = {0}; @@ -5021,6 +5046,7 @@ hlsl_prog: } | hlsl_prog preproc_directive | hlsl_prog global_technique + | hlsl_prog effect_group | hlsl_prog ';'
technique_name: @@ -5067,6 +5093,23 @@ global_technique: | technique10 | technique11
+group_technique: + technique10 + | technique11 + +group_techniques: + group_technique + | group_techniques group_technique + +effect_group: + KW_FXGROUP any_identifier '{' scope_start group_techniques '}' + { + struct hlsl_scope *scope = ctx->cur_scope; + hlsl_pop_scope(ctx); + if (!(add_effect_group(ctx, $2, scope, &@2))) + YYABORT; + } + buffer_declaration: buffer_type any_identifier colon_attribute { diff --git a/tests/hlsl/technique-fx_2.shader_test b/tests/hlsl/technique-fx_2.shader_test index e0ac1901e..4a18430ad 100644 --- a/tests/hlsl/technique-fx_2.shader_test +++ b/tests/hlsl/technique-fx_2.shader_test @@ -123,7 +123,7 @@ fxgroup group }
% Regular shaders with technique blocks -[vertex shader todo] +[vertex shader] float4 main() : sv_position { return 0; @@ -147,7 +147,7 @@ fxgroup group technique10 {} }
-[pixel shader todo] +[pixel shader] float4 main() : sv_target { return 0; diff --git a/tests/hlsl/technique-fx_4.shader_test b/tests/hlsl/technique-fx_4.shader_test index 02317483a..9bd1a8d74 100644 --- a/tests/hlsl/technique-fx_4.shader_test +++ b/tests/hlsl/technique-fx_4.shader_test @@ -97,7 +97,7 @@ float4 technIque10; float4 technIque11;
% Regular shaders with technique blocks -[vertex shader todo] +[vertex shader] float4 main() : sv_position { return 0; @@ -120,7 +120,7 @@ fxgroup group technique10 {} }
-[pixel shader todo] +[pixel shader] float4 main() : sv_target { return 0; diff --git a/tests/hlsl/technique-fx_5.shader_test b/tests/hlsl/technique-fx_5.shader_test index fd1cf4cf9..0ef88cd0e 100644 --- a/tests/hlsl/technique-fx_5.shader_test +++ b/tests/hlsl/technique-fx_5.shader_test @@ -97,7 +97,7 @@ float4 technIque10; float4 technIque11;
% Regular shaders with technique blocks -[vertex shader todo] +[vertex shader] float4 main() : sv_position { return 0; @@ -120,7 +120,7 @@ fxgroup group technique10 {} }
-[pixel shader todo] +[pixel shader] float4 main() : sv_target { return 0;
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- include/private/vkd3d_common.h | 1 + include/vkd3d_shader.h | 5 ++ libs/vkd3d-shader/hlsl.c | 6 ++ libs/vkd3d-shader/vkd3d_shader_main.c | 1 + libs/vkd3d-utils/vkd3d_utils_main.c | 87 ++++++++++++++++++--------- programs/vkd3d-compiler/main.c | 3 + 6 files changed, 73 insertions(+), 30 deletions(-)
diff --git a/include/private/vkd3d_common.h b/include/private/vkd3d_common.h index 619665ad3..b098c1144 100644 --- a/include/private/vkd3d_common.h +++ b/include/private/vkd3d_common.h @@ -52,6 +52,7 @@ #define TAG_AON9 VKD3D_MAKE_TAG('A', 'o', 'n', '9') #define TAG_DXBC VKD3D_MAKE_TAG('D', 'X', 'B', 'C') #define TAG_DXIL VKD3D_MAKE_TAG('D', 'X', 'I', 'L') +#define TAG_FX10 VKD3D_MAKE_TAG('F', 'X', '1', '0') #define TAG_ISG1 VKD3D_MAKE_TAG('I', 'S', 'G', '1') #define TAG_ISGN VKD3D_MAKE_TAG('I', 'S', 'G', 'N') #define TAG_OSG1 VKD3D_MAKE_TAG('O', 'S', 'G', '1') diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 94f79c7c7..8b5303a1b 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -734,6 +734,11 @@ enum vkd3d_shader_target_type * An 'OpenGL Shading Language' shader. \since 1.3 */ VKD3D_SHADER_TARGET_GLSL, + /** + * Binary format used by Direct3D 9/10.x/11 effects profiles. + * Output is a raw FX section without container. \since 1.10 + */ + VKD3D_SHADER_TARGET_FX,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_TARGET_TYPE), }; diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 1b0862d63..ae3c8e38f 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -3649,6 +3649,12 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d "The '%s' target profile is incompatible with the 'dxbc-tpf' target type.", profile->name); return VKD3D_ERROR_INVALID_ARGUMENT; } + else if (compile_info->target_type == VKD3D_SHADER_TARGET_FX && profile->type != VKD3D_SHADER_TYPE_EFFECT) + { + vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_HLSL_INCOMPATIBLE_PROFILE, + "The '%s' target profile is incompatible with the 'fx' target type.", profile->name); + return VKD3D_ERROR_INVALID_ARGUMENT; + }
if (!hlsl_ctx_init(&ctx, compile_info, profile, message_context)) return VKD3D_ERROR_OUT_OF_MEMORY; diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 28d647b3d..c3b918dcd 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1724,6 +1724,7 @@ const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types( { VKD3D_SHADER_TARGET_D3D_BYTECODE, VKD3D_SHADER_TARGET_DXBC_TPF, + VKD3D_SHADER_TARGET_FX, };
static const enum vkd3d_shader_target_type d3dbc_types[] = diff --git a/libs/vkd3d-utils/vkd3d_utils_main.c b/libs/vkd3d-utils/vkd3d_utils_main.c index 306674cd1..b69958e03 100644 --- a/libs/vkd3d-utils/vkd3d_utils_main.c +++ b/libs/vkd3d-utils/vkd3d_utils_main.c @@ -179,28 +179,12 @@ static void close_include(const struct vkd3d_shader_code *code, void *context) ID3DInclude_Close(iface, code->code); }
-HRESULT WINAPI D3DCompile2(const void *data, SIZE_T data_size, const char *filename, - const D3D_SHADER_MACRO *macros, ID3DInclude *include, const char *entry_point, - const char *profile, UINT flags, UINT effect_flags, UINT secondary_flags, - const void *secondary_data, SIZE_T secondary_data_size, ID3DBlob **shader_blob, - ID3DBlob **messages_blob) +static enum vkd3d_shader_target_type get_target_for_profile(const char *profile) { - struct vkd3d_shader_preprocess_info preprocess_info; - struct vkd3d_shader_hlsl_source_info hlsl_info; - struct vkd3d_shader_compile_option options[4]; - struct vkd3d_shader_compile_info compile_info; - struct vkd3d_shader_compile_option *option; - struct vkd3d_shader_code byte_code; - const D3D_SHADER_MACRO *macro; size_t profile_len, i; - char *messages; - HRESULT hr; - int ret;
static const char * const d3dbc_profiles[] = { - "fx_2_", - "ps.1.", "ps.2.", "ps.3.", @@ -220,6 +204,46 @@ HRESULT WINAPI D3DCompile2(const void *data, SIZE_T data_size, const char *filen "tx_1_", };
+ static const char * const fx_profiles[] = + { + "fx_2_0", + }; + + profile_len = strlen(profile); + for (i = 0; i < ARRAY_SIZE(d3dbc_profiles); ++i) + { + size_t len = strlen(d3dbc_profiles[i]); + + if (len <= profile_len && !memcmp(profile, d3dbc_profiles[i], len)) + return VKD3D_SHADER_TARGET_D3D_BYTECODE; + } + + for (i = 0; i < ARRAY_SIZE(fx_profiles); ++i) + { + if (!strcmp(profile, fx_profiles[i])) + return VKD3D_SHADER_TARGET_FX; + } + + return VKD3D_SHADER_TARGET_DXBC_TPF; +} + +HRESULT WINAPI D3DCompile2(const void *data, SIZE_T data_size, const char *filename, + const D3D_SHADER_MACRO *macros, ID3DInclude *include, const char *entry_point, + const char *profile, UINT flags, UINT effect_flags, UINT secondary_flags, + const void *secondary_data, SIZE_T secondary_data_size, ID3DBlob **shader_blob, + ID3DBlob **messages_blob) +{ + struct vkd3d_shader_preprocess_info preprocess_info; + struct vkd3d_shader_hlsl_source_info hlsl_info; + struct vkd3d_shader_compile_option options[4]; + struct vkd3d_shader_compile_info compile_info; + struct vkd3d_shader_compile_option *option; + struct vkd3d_shader_code byte_code; + const D3D_SHADER_MACRO *macro; + char *messages; + HRESULT hr; + int ret; + TRACE("data %p, data_size %lu, filename %s, macros %p, include %p, entry_point %s, " "profile %s, flags %#x, effect_flags %#x, secondary_flags %#x, secondary_data %p, " "secondary_data_size %lu, shader_blob %p, messages_blob %p.\n", @@ -246,24 +270,12 @@ HRESULT WINAPI D3DCompile2(const void *data, SIZE_T data_size, const char *filen compile_info.source.code = data; compile_info.source.size = data_size; compile_info.source_type = VKD3D_SHADER_SOURCE_HLSL; - compile_info.target_type = VKD3D_SHADER_TARGET_DXBC_TPF; + compile_info.target_type = get_target_for_profile(profile); compile_info.options = options; compile_info.option_count = 1; compile_info.log_level = VKD3D_SHADER_LOG_INFO; compile_info.source_name = filename;
- profile_len = strlen(profile); - for (i = 0; i < ARRAY_SIZE(d3dbc_profiles); ++i) - { - size_t len = strlen(d3dbc_profiles[i]); - - if (len <= profile_len && !memcmp(profile, d3dbc_profiles[i], len)) - { - compile_info.target_type = VKD3D_SHADER_TARGET_D3D_BYTECODE; - break; - } - } - preprocess_info.type = VKD3D_SHADER_STRUCTURE_TYPE_PREPROCESS_INFO; preprocess_info.next = &hlsl_info; preprocess_info.macros = (const struct vkd3d_shader_macro *)macros; @@ -325,6 +337,21 @@ HRESULT WINAPI D3DCompile2(const void *data, SIZE_T data_size, const char *filen
if (!ret) { + /* Unlike other effect profiles fx_4_x is using DXBC container. */ + if (!strcmp(profile, "fx_4_0") || !strcmp(profile, "fx_4_1")) + { + struct vkd3d_shader_dxbc_section_desc section = { .tag = TAG_FX10, .data = byte_code }; + struct vkd3d_shader_code dxbc; + + if ((ret = vkd3d_shader_serialize_dxbc(1, §ion, &dxbc, NULL))) + { + vkd3d_shader_free_shader_code(&byte_code); + return hresult_from_vkd3d_result(ret); + } + + byte_code = dxbc; + } + if (FAILED(hr = vkd3d_blob_create((void *)byte_code.code, byte_code.size, shader_blob))) { vkd3d_shader_free_shader_code(&byte_code); diff --git a/programs/vkd3d-compiler/main.c b/programs/vkd3d-compiler/main.c index 2e5f2b977..39471ff0a 100644 --- a/programs/vkd3d-compiler/main.c +++ b/programs/vkd3d-compiler/main.c @@ -105,6 +105,9 @@ target_type_info[] = "dxbc-tpf", "A 'Tokenized Program Format' shader embedded in a DXBC container.\n" " This is the format used for Direct3D shader model 4 and 5 shaders.\n", true}, + {VKD3D_SHADER_TARGET_FX, + "fx", "Binary format used by Direct3D 9/10.x/11 effects.\n", + true}, {VKD3D_SHADER_TARGET_GLSL, "glsl", "An 'OpenGL Shading Language' shader.\n", false}
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- Makefile.am | 1 + libs/vkd3d-shader/fx.c | 142 +++++++++++++++++++++++ libs/vkd3d-shader/hlsl.c | 8 ++ libs/vkd3d-shader/hlsl.h | 2 + libs/vkd3d-shader/hlsl_codegen.c | 41 +++++++ libs/vkd3d-shader/vkd3d_shader_main.c | 35 +++++- libs/vkd3d-shader/vkd3d_shader_private.h | 2 + tests/hlsl/technique-fx_2.shader_test | 2 +- tests/hlsl/technique-fx_4.shader_test | 10 +- 9 files changed, 234 insertions(+), 9 deletions(-) create mode 100644 libs/vkd3d-shader/fx.c
diff --git a/Makefile.am b/Makefile.am index 14b5cf096..5db3099da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -289,6 +289,7 @@ libvkd3d_shader_la_SOURCES = \ libs/vkd3d-shader/d3dbc.c \ libs/vkd3d-shader/dxbc.c \ libs/vkd3d-shader/dxil.c \ + libs/vkd3d-shader/fx.c \ libs/vkd3d-shader/glsl.c \ libs/vkd3d-shader/hlsl.c \ libs/vkd3d-shader/hlsl.h \ diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c new file mode 100644 index 000000000..540ae1169 --- /dev/null +++ b/libs/vkd3d-shader/fx.c @@ -0,0 +1,142 @@ +/* + * FX (Direct3D 9/10/11 effect) support + * + * Copyright 2023 Nikolay Sivov for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "hlsl.h" + +static uint32_t fx_get_string_size(const char *s) +{ + /* All empty strings share the same block. */ + return s ? strlen(s) + 1 : 0; +} + +struct fx_context +{ + uint32_t raw_section_size; + uint32_t raw_section_offset; + uint32_t raw_section_used; + uint32_t technique_count; +}; + +static uint32_t fx_put_raw_u32(struct vkd3d_bytecode_buffer *buffer, struct fx_context *ctx, uint32_t value) +{ + uint32_t offset = ctx->raw_section_offset + ctx->raw_section_used; + uint32_t ret = ctx->raw_section_used; + + set_u32(buffer, offset, value); + ctx->raw_section_used += sizeof(value); + return ret; +} + +static uint32_t fx_put_raw_string(struct vkd3d_bytecode_buffer *buffer, struct fx_context *ctx, const char *string) +{ + uint32_t ret = ctx->raw_section_used; + size_t size; + + /* Empty strings are using the same 4 bytes at the start of the section. */ + if (!string) + return 0; + + size = strlen(string) + 1; + set_string(buffer, ctx->raw_section_offset + ctx->raw_section_used, string, size); + ctx->raw_section_used += size; + return ret; +} + +typedef void (*fx_technique_func)(struct hlsl_ir_var *var, struct fx_context *ctx, struct vkd3d_bytecode_buffer *buffer); + +static void fx_foreach_technique(struct hlsl_scope *scope, fx_technique_func func, struct fx_context *ctx, + struct vkd3d_bytecode_buffer *buffer) +{ + struct hlsl_ir_var *var; + + LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry) + { + if (var->data_type->base_type == HLSL_TYPE_TECHNIQUE10) + func(var, ctx, buffer); + } +} + +static void fx_technique_collect_stats(struct hlsl_ir_var *var, struct fx_context *ctx, struct vkd3d_bytecode_buffer *buffer) +{ + ctx->raw_section_size += fx_get_string_size(var->name); + ctx->technique_count++; +} + +static void fx_technique_write(struct hlsl_ir_var *var, struct fx_context *ctx, struct vkd3d_bytecode_buffer *buffer) +{ + uint32_t name_offset; + + name_offset = fx_put_raw_string(buffer, ctx, var->name); + put_u32(buffer, name_offset); + put_u32(buffer, 0); /* Pass count. */ + put_u32(buffer, 0); /* Annotation count. */ + + /* TODO: passes */ +} + +int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) +{ + struct fx_context fx_ctx = { .raw_section_size = 4 }; + struct vkd3d_bytecode_buffer buffer = { 0 }; + + fx_foreach_technique(ctx->globals, fx_technique_collect_stats, &fx_ctx, &buffer); + fx_ctx.raw_section_size = align(fx_ctx.raw_section_size, 4); + + put_u32(&buffer, ctx->profile->minor_version == 0 ? 0xfeff1001 : 0xfeff1011); /* Version. */ + put_u32(&buffer, 0); /* Buffer count. */ + put_u32(&buffer, 0); /* Variable count. */ + put_u32(&buffer, 0); /* Object count. */ + put_u32(&buffer, 0); /* Pool buffer count. */ + put_u32(&buffer, 0); /* Pool variable count. */ + put_u32(&buffer, 0); /* Pool object count. */ + put_u32(&buffer, fx_ctx.technique_count); + put_u32(&buffer, fx_ctx.raw_section_size); + put_u32(&buffer, 0); /* String count. */ + put_u32(&buffer, 0); /* Texture object count. */ + put_u32(&buffer, 0); /* Depth stencil state count. */ + put_u32(&buffer, 0); /* Blend state count. */ + put_u32(&buffer, 0); /* Rasterizer state count. */ + put_u32(&buffer, 0); /* Sampler state count. */ + put_u32(&buffer, 0); /* Rendertarget view count. */ + put_u32(&buffer, 0); /* Depth stencil view count. */ + put_u32(&buffer, 0); /* Shader count. */ + put_u32(&buffer, 0); /* Inline shader count. */ + + fx_ctx.raw_section_offset = bytecode_reserve_bytes(&buffer, fx_ctx.raw_section_size); + fx_put_raw_u32(&buffer, &fx_ctx, 0); + + /* TODO: write buffers */ + /* TODO: write objects */ + /* TODO: shared buffers */ + /* TODO: shared objects */ + + fx_foreach_technique(ctx->globals, fx_technique_write, &fx_ctx, &buffer); + + if (!buffer.status) + { + out->code = buffer.data; + out->size = buffer.size; + } + + if (buffer.status < 0) + ctx->result = buffer.status; + + return buffer.status; +} diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index ae3c8e38f..325bc3514 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -3679,6 +3679,14 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d return VKD3D_ERROR_NOT_IMPLEMENTED; }
+ if (ctx.profile->type == VKD3D_SHADER_TYPE_EFFECT) + { + ret = hlsl_emit_effect_binary(&ctx, out); + + hlsl_ctx_cleanup(&ctx); + return ret; + } + if ((func = hlsl_get_function(&ctx, entry_point))) { RB_FOR_EACH_ENTRY(decl, &func->overloads, struct hlsl_ir_function_decl, entry) diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index b6611dddc..9a2026e70 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -1155,6 +1155,7 @@ void hlsl_dump_function(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl
int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, enum vkd3d_shader_target_type target_type, struct vkd3d_shader_code *out); +int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out);
bool hlsl_init_deref_from_index_chain(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_ir_node *chain); bool hlsl_copy_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, const struct hlsl_deref *other); @@ -1328,6 +1329,7 @@ bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, bool hlsl_sm4_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic, bool output, enum vkd3d_shader_register_type *type, bool *has_idx); int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out); +int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out);
struct hlsl_ir_function_decl *hlsl_compile_internal_function(struct hlsl_ctx *ctx, const char *name, const char *hlsl);
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 76a010fb3..be91046ff 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -4883,3 +4883,44 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry return VKD3D_ERROR_INVALID_ARGUMENT; } } + +int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) +{ + struct hlsl_ir_var *var; + + /* Reset generated names to simplify serialization. */ + LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct hlsl_ir_var, scope_entry) + { + enum hlsl_base_type type = var->data_type->base_type; + + if (type == HLSL_TYPE_TECHNIQUE + || type == HLSL_TYPE_TECHNIQUE10 + || type == HLSL_TYPE_TECHNIQUE11) + { + if (*var->name == '<') + { + vkd3d_free((void *)var->name); + var->name = NULL; + } + } + } + + if (ctx->profile->major_version == 2) + { + hlsl_fixme(ctx, &ctx->location, "Writing fx_2_0 binaries is not implemented."); + return VKD3D_ERROR_NOT_IMPLEMENTED; + } + else if (ctx->profile->major_version == 4) + { + return hlsl_fx_4_write(ctx, out); + } + else if (ctx->profile->major_version == 5) + { + hlsl_fixme(ctx, &ctx->location, "Writing fx_5_0 binaries is not implemented."); + return VKD3D_ERROR_NOT_IMPLEMENTED; + } + else + { + vkd3d_unreachable(); + } +} diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index c3b918dcd..e3a382942 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -373,13 +373,42 @@ size_t bytecode_put_bytes(struct vkd3d_bytecode_buffer *buffer, const void *byte return offset; }
-void set_u32(struct vkd3d_bytecode_buffer *buffer, size_t offset, uint32_t value) +size_t bytecode_reserve_bytes(struct vkd3d_bytecode_buffer *buffer, size_t size) +{ + size_t offset = bytecode_align(buffer); + + if (buffer->status) + return offset; + + if (!vkd3d_array_reserve((void **)&buffer->data, &buffer->capacity, offset + size, 1)) + { + buffer->status = VKD3D_ERROR_OUT_OF_MEMORY; + return offset; + } + + memset(buffer->data + offset, 0xcd, size); + buffer->size = offset + size; + return offset; +} + +static void bytecode_set_bytes(struct vkd3d_bytecode_buffer *buffer, size_t offset, + const void *value, size_t size) { if (buffer->status) return;
- assert(vkd3d_bound_range(offset, sizeof(value), buffer->size)); - memcpy(buffer->data + offset, &value, sizeof(value)); + assert(vkd3d_bound_range(offset, size, buffer->size)); + memcpy(buffer->data + offset, value, size); +} + +void set_u32(struct vkd3d_bytecode_buffer *buffer, size_t offset, uint32_t value) +{ + bytecode_set_bytes(buffer, offset, &value, sizeof(value)); +} + +void set_string(struct vkd3d_bytecode_buffer *buffer, size_t offset, const char *string, size_t length) +{ + bytecode_set_bytes(buffer, offset, string, length); }
static void vkd3d_shader_dump_blob(const char *path, const char *profile, diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 0871f8b1a..b9e1d188d 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1316,7 +1316,9 @@ struct vkd3d_bytecode_buffer /* Align to the next 4-byte offset, and return that offset. */ size_t bytecode_align(struct vkd3d_bytecode_buffer *buffer); size_t bytecode_put_bytes(struct vkd3d_bytecode_buffer *buffer, const void *bytes, size_t size); +size_t bytecode_reserve_bytes(struct vkd3d_bytecode_buffer *buffer, size_t size); void set_u32(struct vkd3d_bytecode_buffer *buffer, size_t offset, uint32_t value); +void set_string(struct vkd3d_bytecode_buffer *buffer, size_t offset, const char *string, size_t length);
static inline size_t put_u32(struct vkd3d_bytecode_buffer *buffer, uint32_t value) { diff --git a/tests/hlsl/technique-fx_2.shader_test b/tests/hlsl/technique-fx_2.shader_test index 4a18430ad..10b6fdf09 100644 --- a/tests/hlsl/technique-fx_2.shader_test +++ b/tests/hlsl/technique-fx_2.shader_test @@ -86,7 +86,7 @@ technique10 }
% Effects without techniques are not allowed for fx_2_0 -[effect fail] +[effect fail todo] float4 f;
% fx_5_0 keyword fails with fx_2_0 profile diff --git a/tests/hlsl/technique-fx_4.shader_test b/tests/hlsl/technique-fx_4.shader_test index 9bd1a8d74..cdc5746e0 100644 --- a/tests/hlsl/technique-fx_4.shader_test +++ b/tests/hlsl/technique-fx_4.shader_test @@ -37,7 +37,7 @@ float4 main() : sv_target return fxGroup; }
-[effect todo] +[effect] technique { } @@ -47,11 +47,11 @@ technique10 }
% Effects without techniques are allowed for fx_4_0+ -[effect todo] +[effect] float4 f;
% fx_2_0 keyword is allowed with fx_4_0+ profiles -[effect todo] +[effect] technique { } @@ -90,10 +90,10 @@ float4 technique10; [effect fail] float4 technique11;
-[effect todo] +[effect] float4 technIque10;
-[effect todo] +[effect] float4 technIque11;
% Regular shaders with technique blocks
Zebediah Figura (@zfigura) commented about libs/vkd3d-shader/fx.c:
+{
- struct fx_context fx_ctx = { .raw_section_size = 4 };
- struct vkd3d_bytecode_buffer buffer = { 0 };
- fx_foreach_technique(ctx->globals, fx_technique_collect_stats, &fx_ctx, &buffer);
- fx_ctx.raw_section_size = align(fx_ctx.raw_section_size, 4);
- put_u32(&buffer, ctx->profile->minor_version == 0 ? 0xfeff1001 : 0xfeff1011); /* Version. */
- put_u32(&buffer, 0); /* Buffer count. */
- put_u32(&buffer, 0); /* Variable count. */
- put_u32(&buffer, 0); /* Object count. */
- put_u32(&buffer, 0); /* Pool buffer count. */
- put_u32(&buffer, 0); /* Pool variable count. */
- put_u32(&buffer, 0); /* Pool object count. */
- put_u32(&buffer, fx_ctx.technique_count);
- put_u32(&buffer, fx_ctx.raw_section_size);
The point of set_u32() is that you can set these offsets after writing them, instead of needing to do two passes over the same data.
Zebediah Figura (@zfigura) commented about libs/vkd3d-shader/hlsl_codegen.c:
- struct hlsl_ir_var *var;
- /* Reset generated names to simplify serialization. */
- LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct hlsl_ir_var, scope_entry)
- {
enum hlsl_base_type type = var->data_type->base_type;
if (type == HLSL_TYPE_TECHNIQUE
|| type == HLSL_TYPE_TECHNIQUE10
|| type == HLSL_TYPE_TECHNIQUE11)
{
if (*var->name == '<')
{
vkd3d_free((void *)var->name);
var->name = NULL;
}
I can live with this, though I'm not thrilled about it. How hard would it actually be to just never set the name in these cases?
Zebediah Figura (@zfigura) commented about libs/vkd3d-shader/hlsl_codegen.c:
return VKD3D_ERROR_INVALID_ARGUMENT; }
}
+int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) +{
- struct hlsl_ir_var *var;
- /* Reset generated names to simplify serialization. */
- LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct hlsl_ir_var, scope_entry)
- {
enum hlsl_base_type type = var->data_type->base_type;
if (type == HLSL_TYPE_TECHNIQUE
|| type == HLSL_TYPE_TECHNIQUE10
|| type == HLSL_TYPE_TECHNIQUE11)
Would it make sense to have a single HLSL_TYPE_TECHNIQUE plus a field for the version?
Zebediah Figura (@zfigura) commented about libs/vkd3d-shader/hlsl.h:
struct list scope_entry; /* Item entry in hlsl_ctx.extern_vars, if the variable is extern. */ struct list extern_entry;
- /* Scope that variable itself defines, used to provide a container for techniques and passes. */
- struct hlsl_scope *scope;
This should probably go in the union.
Zebediah Figura (@zfigura) commented about libs/vkd3d-shader/hlsl.c:
"The '%s' target profile is incompatible with the 'dxbc-tpf' target type.", profile->name); return VKD3D_ERROR_INVALID_ARGUMENT; }
- else if (compile_info->target_type == VKD3D_SHADER_TARGET_FX && profile->type != VKD3D_SHADER_TYPE_EFFECT)
- {
vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_HLSL_INCOMPATIBLE_PROFILE,
"The '%s' target profile is incompatible with the 'fx' target type.", profile->name);
return VKD3D_ERROR_INVALID_ARGUMENT;
- }
We also need to check the inverse here.
From a HLSL perspective this is mostly good. The API parts may need more bikeshedding.
On Thu Nov 9 19:45:08 2023 +0000, Zebediah Figura wrote:
The point of set_u32() is that you can set these offsets after writing them, instead of needing to do two passes over the same data.
I think this could also be avoided. What I'll probably end up with is two buffers, one for structured part - (cbuffers, variables, etc), and another for unstructured part for strings, default values, and so one. I think shader blobs also go in there.
On Thu Nov 9 19:45:10 2023 +0000, Zebediah Figura wrote:
I can live with this, though I'm not thrilled about it. How hard would it actually be to just never set the name in these cases?
That's probably the part I dislike the most. It will probably work, but it will need some workarounds in get_var() and such, to make sure NULL != NULL, and maybe some other logic. That's needed because you can have multiple entries without a name in the same scope.
On Thu Nov 9 19:45:10 2023 +0000, Zebediah Figura wrote:
Would it make sense to have a single HLSL_TYPE_TECHNIQUE plus a field for the version?
Additional field in hlsl_ir_var? Sure, my intent was to avoid changes to commonly used structures. But I agree about having fewer types.
On Thu Nov 9 19:45:12 2023 +0000, Zebediah Figura wrote:
This should probably go in the union.
New field together with what? 'extern_entry' ? I don't understand what you're suggesting I'm afraid.
On Thu Nov 9 20:06:40 2023 +0000, Nikolay Sivov wrote:
That's probably the part I dislike the most. It will probably work, but it will need some workarounds in get_var() and such, to make sure NULL != NULL, and maybe some other logic. That's needed because you can have multiple entries without a name in the same scope.
I think if a variable doesn't have a name we can just not add it to the scope.
On Thu Nov 9 20:07:47 2023 +0000, Nikolay Sivov wrote:
Additional field in hlsl_ir_var? Sure, my intent was to avoid changes to commonly used structures. But I agree about having fewer types.
I don't think touching hlsl_ir_var is much of a problem. As long as we're adding new subtypes we can definitely add new data for those subtypes.
It's mostly a matter of whether it'll end up being more convenient to work with that way.
On Thu Nov 9 20:04:06 2023 +0000, Nikolay Sivov wrote:
I think this could also be avoided. What I'll probably end up with is two buffers, one for structured part - (cbuffers, variables, etc), and another for unstructured part for strings, default values, and so one. I think shader blobs also go in there.
I say this mostly because, in the current form, it's not obvious that we need to do anything that complex. I.e. we can write sections one at a time, recording counts and sizes as we do so, and then go back and write those counts and sizes in the header. Maybe further logic will complicate that approach, though...
From a HLSL perspective this is mostly good. The API parts may need more bikeshedding.
On Thu Nov 9 20:13:57 2023 +0000, Zebediah Figura wrote:
I don't think touching hlsl_ir_var is much of a problem. As long as we're adding new subtypes we can definitely add new data for those subtypes. It's mostly a matter of whether it'll end up being more convenient to work with that way.
I'll try with additional field. I think having a single type is better than three.
On Thu Nov 9 20:12:59 2023 +0000, Zebediah Figura wrote:
I think if a variable doesn't have a name we can just not add it to the scope.
Iterating through the scope list is the only way I use to see what groups/techniques/passes contain.
On Thu Nov 9 20:09:28 2023 +0000, Nikolay Sivov wrote:
New field together with what? 'extern_entry' ? I don't understand what you're suggesting I'm afraid.
I mean the "e" union. I.e. it should be accessed like type->e.effect_group.scope or type->e.effect_group_scope, rather than type->scope.
On Thu Nov 9 20:16:15 2023 +0000, Nikolay Sivov wrote:
Iterating through the scope list is the only way I use to see what groups/techniques/passes contain.
Oh, right, and that's how we free vars too. I think I confused this with Rosé where I did something similar, but I think that was with types rather than vars.
We can't not add it to the scope, but we can make it so that they're never looked up, i.e. just skip anything nameless in hlsl_get_var(). We should never need to look up anything that doesn't have a name.
From a HLSL perspective this is mostly good. The API parts may need more bikeshedding.
On Thu Nov 9 20:14:48 2023 +0000, Zebediah Figura wrote:
I say this mostly because, in the current form, it's not obvious that we need to do anything that complex. I.e. we can write sections one at a time, recording counts and sizes as we do so, and then go back and write those counts and sizes in the header. Maybe further logic will complicate that approach, though...
Writing them separately makes it easier because I don't need to know total unstructured size in advance. It won't complicate anything, I don't think. Offsets are relative to the beginning of unstructured block, so writing both, collecting stats for the header, and then doing header+buffer 1+buffer 2, should be enough.
One additional feature that's easy to add later is deduplicate string data - on windows you won't get the same string twice, except for fx_2_0. I haven't checked in details how it's stored there. It should work fine without this storage optimization.
On Thu Nov 9 20:16:26 2023 +0000, Zebediah Figura wrote:
I mean the "e" union. I.e. it should be accessed like type->e.effect_group.scope or type->e.effect_group_scope, rather than type->scope.
Why would it be stored in type data?
On Thu Nov 9 20:18:50 2023 +0000, Zebediah Figura wrote:
Oh, right, and that's how we free vars too. I think I confused this with Rosé where I did something similar, but I think that was with types rather than vars. We can't not add it to the scope, but we can make it so that they're never looked up, i.e. just skip anything nameless in hlsl_get_var(). We should never need to look up anything that doesn't have a name.
Alright, that makes sense.
On Thu Nov 9 20:22:57 2023 +0000, Nikolay Sivov wrote:
Why would it be stored in type data?
Ugh, sorry, I completely forgot what I'm doing. Ignore this.
On Thu Nov 9 20:21:44 2023 +0000, Nikolay Sivov wrote:
Writing them separately makes it easier because I don't need to know total unstructured size in advance. It won't complicate anything, I don't think. Offsets are relative to the beginning of unstructured block, so writing both, collecting stats for the header, and then doing header+buffer 1+buffer 2, should be enough. One additional feature that's easy to add later is deduplicate string data - on windows you won't get the same string twice, except for fx_2_0. I haven't checked in details how it's stored there. It should work fine without this storage optimization.
That works too, but with set_u32() you don't need to know sizes in advance either, you just go back and set them once you do know.