Names are optional for both techniques and passes.
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
From: Nikolay Sivov nsivov@codeweavers.com
Names are optional for both techniques and passes.
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/hlsl.y | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 7424e63a4..7c77f0e81 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -5102,7 +5102,7 @@ static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hls
%type <name> any_identifier %type <name> var_identifier -%type <name> technique_name +%type <name> name_opt
%type <parameter> parameter
@@ -5148,7 +5148,7 @@ hlsl_prog: | hlsl_prog effect_group | hlsl_prog ';'
-technique_name: +name_opt: %empty { $$ = NULL; @@ -5159,14 +5159,14 @@ pass_list: %empty
technique9: - KW_TECHNIQUE technique_name '{' pass_list '}' + KW_TECHNIQUE name_opt '{' pass_list '}' { if (!add_technique(ctx, $2, "technique", &@1)) YYABORT; }
technique10: - KW_TECHNIQUE10 technique_name '{' pass_list '}' + KW_TECHNIQUE10 name_opt '{' pass_list '}' { if (ctx->profile->type == VKD3D_SHADER_TYPE_EFFECT && ctx->profile->major_version == 2) hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, @@ -5177,7 +5177,7 @@ technique10: }
technique11: - KW_TECHNIQUE11 technique_name '{' pass_list '}' + KW_TECHNIQUE11 name_opt '{' pass_list '}' { if (ctx->profile->type == VKD3D_SHADER_TYPE_EFFECT && ctx->profile->major_version == 2) hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/hlsl.y | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 7c77f0e81..b11cbde26 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1096,8 +1096,8 @@ 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) +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_ir_var *var; struct hlsl_type *type; @@ -1105,6 +1105,7 @@ static bool add_technique(struct hlsl_ctx *ctx, const char *name, const char *ty type = hlsl_get_type(ctx->globals, typename, 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)) { @@ -5155,35 +5156,52 @@ name_opt: } | any_identifier
+pass: + KW_PASS name_opt '{' '}' + pass_list: - %empty + pass + | pass_list pass + +passes: + scope_start + | scope_start pass_list
technique9: - KW_TECHNIQUE name_opt '{' pass_list '}' + KW_TECHNIQUE name_opt '{' passes '}' { - if (!add_technique(ctx, $2, "technique", &@1)) + struct hlsl_scope *scope = ctx->cur_scope; + hlsl_pop_scope(ctx); + + if (!add_technique(ctx, $2, scope, "technique", &@1)) YYABORT; }
technique10: - KW_TECHNIQUE10 name_opt '{' pass_list '}' + KW_TECHNIQUE10 name_opt '{' passes '}' { + struct hlsl_scope *scope = ctx->cur_scope; + hlsl_pop_scope(ctx); + if (ctx->profile->type == VKD3D_SHADER_TYPE_EFFECT && ctx->profile->major_version == 2) hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "The 'technique10' keyword is invalid for this profile.");
- if (!add_technique(ctx, $2, "technique10", &@1)) + if (!add_technique(ctx, $2, scope, "technique10", &@1)) YYABORT; }
technique11: - KW_TECHNIQUE11 name_opt '{' pass_list '}' + KW_TECHNIQUE11 name_opt '{' passes '}' { + struct hlsl_scope *scope = ctx->cur_scope; + hlsl_pop_scope(ctx); + if (ctx->profile->type == VKD3D_SHADER_TYPE_EFFECT && ctx->profile->major_version == 2) hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "The 'technique11' keyword is invalid for this profile.");
- if (!add_technique(ctx, $2, "technique11", &@1)) + if (!add_technique(ctx, $2, scope, "technique11", &@1)) YYABORT; }
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/fx.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c index 6c4c1203d..ca6bb7a83 100644 --- a/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d-shader/fx.c @@ -35,17 +35,36 @@ static uint32_t fx_put_raw_string(struct fx_write_context *fx, const char *strin return string ? put_string(&fx->unstructured, string) : 0; }
-static void write_technique(struct hlsl_ir_var *var, struct fx_write_context *fx) +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); put_u32(buffer, name_offset); - put_u32(buffer, 0); /* Pass count. */ 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) +{ + 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); + put_u32(buffer, name_offset); + count_offset = put_u32(buffer, 0); + put_u32(buffer, 0); /* Annotation count. */ + + LIST_FOR_EACH_ENTRY(pass, &var->scope->vars, struct hlsl_ir_var, scope_entry) + { + write_pass(pass, fx); + ++count; + }
- /* TODO: passes */ + set_u32(buffer, count_offset, count); }
static void set_status(struct fx_write_context *fx, int status)
From: Nikolay Sivov nsivov@codeweavers.com
--- libs/vkd3d-shader/fx.c | 148 +++++++++++++++++++++++++- tests/hlsl/technique-fx_5.shader_test | 12 +-- 2 files changed, 151 insertions(+), 9 deletions(-)
diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c index ca6bb7a83..97ea924c0 100644 --- a/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d-shader/fx.c @@ -25,10 +25,47 @@ struct fx_write_context struct vkd3d_bytecode_buffer unstructured; struct vkd3d_bytecode_buffer structured;
+ unsigned int min_technique_version; + unsigned int max_technique_version; + uint32_t technique_count; + uint32_t group_count; int status; };
+static void fx_write_context_init(const struct hlsl_ctx *ctx, struct fx_write_context *fx) +{ + unsigned int version = ctx->profile->major_version; + + memset(fx, 0, sizeof(*fx)); + + if (version == 2) + { + fx->min_technique_version = 9; + fx->max_technique_version = 9; + } + else if (version == 4) + { + fx->min_technique_version = 10; + fx->max_technique_version = 10; + } + else if (version == 5) + { + fx->min_technique_version = 10; + fx->max_technique_version = 11; + } +} + +static bool technique_matches_version(const struct hlsl_ir_var *var, const struct fx_write_context *fx) +{ + const struct hlsl_type *type = var->data_type; + + if (type->base_type != HLSL_TYPE_TECHNIQUE) + return false; + + 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) { /* NULLs are emitted as empty strings using the same 4 bytes at the start of the section. */ @@ -94,13 +131,55 @@ static void write_techniques(struct hlsl_scope *scope, struct fx_write_context * set_status(fx, fx->structured.status); }
+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 count_offset, count; + + put_u32(buffer, name_offset); + count_offset = put_u32(buffer, 0); /* Technique count */ + put_u32(buffer, 0); /* Annotation count */ + + count = fx->technique_count; + write_techniques(scope, fx); + set_u32(buffer, count_offset, fx->technique_count - count); + + ++fx->group_count; +} + +static void write_groups(struct hlsl_scope *scope, struct fx_write_context *fx) +{ + bool needs_default_group = false; + struct hlsl_ir_var *var; + + LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry) + { + if (technique_matches_version(var, fx)) + { + needs_default_group = true; + break; + } + } + + if (needs_default_group) + write_group(scope, NULL, fx); + 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_EFFECT_GROUP) + write_group(var->scope, var->name, fx); + } +} + 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;
- memset(&fx, 0, sizeof(fx)); + fx_write_context_init(ctx, &fx);
put_u32(&fx.unstructured, 0); /* Empty string placeholder. */
@@ -154,6 +233,70 @@ static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) return fx.status; }
+static int hlsl_fx_5_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); + + put_u32(&fx.unstructured, 0); /* Empty string placeholder. */ + + /* TODO: buffers */ + /* TODO: objects */ + /* TODO: interface variables */ + + write_groups(ctx->globals, &fx); + + put_u32(&buffer, 0xfeff2001); /* 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.technique_count); + size_offset = put_u32(&buffer, 0); /* Unstructured 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. */ + put_u32(&buffer, fx.group_count); /* Group count. */ + put_u32(&buffer, 0); /* UAV count. */ + put_u32(&buffer, 0); /* Interface variables count. */ + put_u32(&buffer, 0); /* Interface variable element count. */ + put_u32(&buffer, 0); /* Class instance elements count. */ + + size = align(fx.unstructured.size, 4); + set_u32(&buffer, size_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); + + set_status(&fx, buffer.status); + + if (!fx.status) + { + out->code = buffer.data; + out->size = buffer.size; + } + + if (fx.status < 0) + ctx->result = fx.status; + + return fx.status; +} + int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) { if (ctx->profile->major_version == 2) @@ -167,8 +310,7 @@ int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *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; + return hlsl_fx_5_write(ctx, out); } else { diff --git a/tests/hlsl/technique-fx_5.shader_test b/tests/hlsl/technique-fx_5.shader_test index 0ef88cd0e..c1e37ff17 100644 --- a/tests/hlsl/technique-fx_5.shader_test +++ b/tests/hlsl/technique-fx_5.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_5_0 -[effect todo] +[effect] float4 f;
% fx_2_0 keyword is allowed with fx_5_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 @@ -174,7 +174,7 @@ fxgroup group }
% Group provides scope for techniques -[effect todo] +[effect] fxgroup group1 { technique11 tech0 {}
From: Nikolay Sivov nsivov@codeweavers.com
--- libs/vkd3d-shader/fx.c | 66 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 4 deletions(-)
diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c index 97ea924c0..17b9627b6 100644 --- a/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d-shader/fx.c @@ -20,11 +20,38 @@
#include "hlsl.h"
+struct string_entry +{ + struct rb_entry entry; + /* String points to original data, should not be freed. */ + const char *string; + uint32_t offset; +}; + +static int string_storage_compare(const void *key, const struct rb_entry *entry) +{ + struct string_entry *string_entry = RB_ENTRY_VALUE(entry, struct string_entry, entry); + const char *string = key; + + return strcmp(string, string_entry->string); +} + +static void string_storage_destroy(struct rb_entry *entry, void *context) +{ + struct string_entry *string_entry = RB_ENTRY_VALUE(entry, struct string_entry, entry); + + vkd3d_free(string_entry); +} + struct fx_write_context { + struct hlsl_ctx *ctx; + struct vkd3d_bytecode_buffer unstructured; struct vkd3d_bytecode_buffer structured;
+ struct rb_tree strings; + unsigned int min_technique_version; unsigned int max_technique_version;
@@ -33,12 +60,13 @@ struct fx_write_context int status; };
-static void fx_write_context_init(const struct hlsl_ctx *ctx, struct fx_write_context *fx) +static void fx_write_context_init(struct hlsl_ctx *ctx, struct fx_write_context *fx) { unsigned int version = ctx->profile->major_version;
memset(fx, 0, sizeof(*fx));
+ fx->ctx = ctx; if (version == 2) { fx->min_technique_version = 9; @@ -54,6 +82,16 @@ static void fx_write_context_init(const struct hlsl_ctx *ctx, struct fx_write_co fx->min_technique_version = 10; fx->max_technique_version = 11; } + + rb_init(&fx->strings, string_storage_compare); +} + +static int fx_write_context_cleanup(struct fx_write_context *fx) +{ + int status = fx->status; + rb_destroy(&fx->strings, string_storage_destroy, NULL); + + return status; }
static bool technique_matches_version(const struct hlsl_ir_var *var, const struct fx_write_context *fx) @@ -68,8 +106,28 @@ static bool technique_matches_version(const struct hlsl_ir_var *var, const struc
static uint32_t fx_put_raw_string(struct fx_write_context *fx, const char *string) { + struct string_entry *string_entry; + struct rb_entry *entry; + /* NULLs are emitted as empty strings using the same 4 bytes at the start of the section. */ - return string ? put_string(&fx->unstructured, string) : 0; + if (!string) + return 0; + + if ((entry = rb_get(&fx->strings, string))) + { + string_entry = RB_ENTRY_VALUE(entry, struct string_entry, entry); + return string_entry->offset; + } + + if (!(string_entry = hlsl_alloc(fx->ctx, sizeof(*string_entry)))) + return 0; + + string_entry->offset = put_string(&fx->unstructured, string); + string_entry->string = string; + + rb_put(&fx->strings, string, &string_entry->entry); + + return string_entry->offset; }
static void write_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) @@ -230,7 +288,7 @@ static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) if (fx.status < 0) ctx->result = fx.status;
- return fx.status; + return fx_write_context_cleanup(&fx); }
static int hlsl_fx_5_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) @@ -294,7 +352,7 @@ static int hlsl_fx_5_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) if (fx.status < 0) ctx->result = fx.status;
- return fx.status; + return fx_write_context_cleanup(&fx); }
int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
This merge request was approved by Henri Verbeet.