From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- Makefile.am | 1 + libs/vkd3d-shader/fx.c | 158 +++++++++++++++++++++++ libs/vkd3d-shader/hlsl.c | 8 ++ libs/vkd3d-shader/hlsl.h | 1 + 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 +- 8 files changed, 208 insertions(+), 9 deletions(-) create mode 100644 libs/vkd3d-shader/fx.c
diff --git a/Makefile.am b/Makefile.am index 23e7add3c..bc648b631 100644 --- a/Makefile.am +++ b/Makefile.am @@ -294,6 +294,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..6c4c1203d --- /dev/null +++ b/libs/vkd3d-shader/fx.c @@ -0,0 +1,158 @@ +/* + * 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" + +struct fx_write_context +{ + struct vkd3d_bytecode_buffer unstructured; + struct vkd3d_bytecode_buffer structured; + + uint32_t technique_count; + int status; +}; + +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. */ + return string ? put_string(&fx->unstructured, string) : 0; +} + +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; + + 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. */ + + /* TODO: passes */ +} + +static void set_status(struct fx_write_context *fx, int status) +{ + if (fx->status < 0) + return; + if (status < 0) + fx->status = status; +} + +static void write_techniques(struct hlsl_scope *scope, struct fx_write_context *fx) +{ + struct hlsl_ir_var *var; + + 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) + { + write_technique(var, fx); + ++fx->technique_count; + } + } + + set_status(fx, fx->unstructured.status); + set_status(fx, fx->structured.status); +} + +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)); + + put_u32(&fx.unstructured, 0); /* Empty string placeholder. */ + + /* TODO: buffers */ + /* TODO: objects */ + /* TODO: shared buffers */ + /* TODO: shared objects */ + + write_techniques(ctx->globals, &fx); + + 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.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. */ + + 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) + { + 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/hlsl.c b/libs/vkd3d-shader/hlsl.c index aeb00eab1..10fcd4218 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))) { LIST_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 0c9ad9b45..536b46873 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -1168,6 +1168,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); diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 5d20906d8..31d4fc69e 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -383,13 +383,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, 0, 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 199a47a76..ff02cdc3a 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1357,7 +1357,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 37774fbcb..b84bbc167 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