From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- include/private/vkd3d_common.h | 1 + libs/vkd3d-shader/hlsl.c | 8 ++ libs/vkd3d-shader/hlsl.h | 2 + libs/vkd3d-shader/hlsl_codegen.c | 41 +++++++ libs/vkd3d-shader/tpf.c | 129 +++++++++++++++++++++++ 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, 221 insertions(+), 9 deletions(-)
diff --git a/include/private/vkd3d_common.h b/include/private/vkd3d_common.h index 619665ad..b098c114 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/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 66cd26b8..dad61e57 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -3673,6 +3673,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 b6611ddd..9a2026e7 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 51c3d68f..ebd70ab4 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -4877,3 +4877,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/tpf.c b/libs/vkd3d-shader/tpf.c index afdf8473..65572263 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -5751,3 +5751,132 @@ int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_fun vkd3d_shader_free_shader_code(&dxbc.sections[i].data); return ret; } + +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 */ +} + +static void write_fx10(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) +{ + 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); + + add_section(ctx, dxbc, TAG_FX10, &buffer); +} + +int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) +{ + struct dxbc_writer dxbc; + size_t i; + int ret; + + dxbc_writer_init(&dxbc); + + write_fx10(ctx, &dxbc); + + if (!(ret = ctx->result)) + ret = dxbc_writer_write(&dxbc, out); + for (i = 0; i < dxbc.section_count; ++i) + vkd3d_shader_free_shader_code(&dxbc.sections[i].data); + return ret; +} diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 28d647b3..78f1815d 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 912267e0..2d85bf6b 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1302,7 +1302,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 4a18430a..10b6fdf0 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 9bd1a8d7..cdc5746e 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