diff --git a/Makefile.am b/Makefile.am index 2ab2233a..cbf75ad8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,6 +7,7 @@ widl_headers = \ include/vkd3d_d3d12.h \ include/vkd3d_d3d12sdklayers.h \ include/vkd3d_d3dcommon.h \ + include/vkd3d_d3dx9shader.h \ include/vkd3d_dxgi.h \ include/vkd3d_dxgi1_2.h \ include/vkd3d_dxgi1_3.h \ @@ -22,6 +23,7 @@ vkd3d_public_headers = \ include/vkd3d_d3d9types.h \ include/vkd3d_d3dcommon.h \ include/vkd3d_d3dcompiler.h \ + include/vkd3d_d3dx9shader.h \ include/vkd3d_dxgibase.h \ include/vkd3d_dxgiformat.h \ include/vkd3d_shader.h \ diff --git a/include/.gitignore b/include/.gitignore index 3c711da0..37b101d4 100644 --- a/include/.gitignore +++ b/include/.gitignore @@ -5,6 +5,7 @@ stamp-h1 vkd3d_d3d12.h vkd3d_d3d12sdklayers.h vkd3d_d3dcommon.h +vkd3d_d3dx9shader.h vkd3d_dxgi.h vkd3d_dxgi1_2.h vkd3d_dxgi1_3.h diff --git a/include/vkd3d_d3d9types.h b/include/vkd3d_d3d9types.h index de2ba471..7a8c15f4 100644 --- a/include/vkd3d_d3d9types.h +++ b/include/vkd3d_d3d9types.h @@ -21,6 +21,12 @@ #define __VKD3D_D3D9TYPES_H #ifndef _d3d9TYPES_H_ +#ifndef MAKEFOURCC +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \ + ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 )) +#endif + #define D3DPS_VERSION(major, minor) (0xffff0000 | ((major) << 8) | (minor)) #define D3DVS_VERSION(major, minor) (0xfffe0000 | ((major) << 8) | (minor)) diff --git a/include/vkd3d_d3dx9shader.idl b/include/vkd3d_d3dx9shader.idl new file mode 100644 index 00000000..4000ff29 --- /dev/null +++ b/include/vkd3d_d3dx9shader.idl @@ -0,0 +1,76 @@ +/* + * Copyright 2008 Luis Busquets + * + * 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 + */ + +import "vkd3d_windows.h"; +import "vkd3d_d3d9types.h"; + +typedef enum _D3DXREGISTER_SET +{ + D3DXRS_BOOL, + D3DXRS_INT4, + D3DXRS_FLOAT4, + D3DXRS_SAMPLER, + D3DXRS_FORCE_DWORD = 0x7fffffff, +} D3DXREGISTER_SET; + +typedef enum D3DXPARAMETER_CLASS +{ + D3DXPC_SCALAR, + D3DXPC_VECTOR, + D3DXPC_MATRIX_ROWS, + D3DXPC_MATRIX_COLUMNS, + D3DXPC_OBJECT, + D3DXPC_STRUCT, + D3DXPC_FORCE_DWORD = 0x7fffffff, +} D3DXPARAMETER_CLASS; + +typedef enum D3DXPARAMETER_TYPE +{ + D3DXPT_VOID, + D3DXPT_BOOL, + D3DXPT_INT, + D3DXPT_FLOAT, + D3DXPT_STRING, + D3DXPT_TEXTURE, + D3DXPT_TEXTURE1D, + D3DXPT_TEXTURE2D, + D3DXPT_TEXTURE3D, + D3DXPT_TEXTURECUBE, + D3DXPT_SAMPLER, + D3DXPT_SAMPLER1D, + D3DXPT_SAMPLER2D, + D3DXPT_SAMPLER3D, + D3DXPT_SAMPLERCUBE, + D3DXPT_PIXELSHADER, + D3DXPT_VERTEXSHADER, + D3DXPT_PIXELFRAGMENT, + D3DXPT_VERTEXFRAGMENT, + D3DXPT_UNSUPPORTED, + D3DXPT_FORCE_DWORD = 0x7fffffff, +} D3DXPARAMETER_TYPE; + +typedef struct _D3DXSHADER_CONSTANTTABLE +{ + DWORD Size; + DWORD Creator; + DWORD Version; + DWORD Constants; + DWORD ConstantInfo; + DWORD Flags; + DWORD Target; +} D3DXSHADER_CONSTANTTABLE; diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 3a0bf38d..3dc7a26b 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -115,7 +115,6 @@ struct hlsl_type unsigned int modifiers; unsigned int dimx; unsigned int dimy; - unsigned int reg_size; union { struct list *elements; @@ -125,6 +124,9 @@ struct hlsl_type unsigned int elements_count; } array; } e; + + unsigned int reg_size; + unsigned int bytecode_offset; }; struct hlsl_struct_field @@ -134,7 +136,9 @@ struct hlsl_struct_field struct hlsl_type *type; const char *name; const char *semantic; + unsigned int reg_offset; + unsigned int name_offset; }; struct hlsl_reg @@ -221,6 +225,7 @@ struct hlsl_ir_var uint32_t is_input_varying : 1; uint32_t is_output_varying : 1; uint32_t is_uniform : 1; + uint32_t is_param : 1; }; struct hlsl_ir_function diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 6216b100..8cd80533 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -765,6 +765,7 @@ static bool add_func_parameter(struct hlsl_ctx *ctx, struct list *list, if (!(var = hlsl_new_var(param->name, param->type, loc, param->semantic, param->reg_reservation))) return false; + var->is_param = 1; if (param->type->type != HLSL_CLASS_OBJECT) { diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 25227057..73f8bdb0 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -20,7 +20,7 @@ #include "hlsl.h" #include -#include "vkd3d_d3d9types.h" +#include "vkd3d_d3dx9shader.h" /* Split uniforms into two variables representing the constant and temp * registers, and copy the former to the latter, so that writes to uniforms @@ -44,6 +44,7 @@ static void prepend_uniform_copy(struct hlsl_ctx *ctx, struct list *instrs, stru list_add_tail(&ctx->extern_vars, &uniform->extern_entry); temp->is_uniform = 0; uniform->is_uniform = 1; + uniform->is_param = temp->is_param; if (!(name = vkd3d_string_buffer_get(&ctx->string_buffers))) { @@ -92,6 +93,7 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct } vkd3d_string_buffer_release(&ctx->string_buffers, name); varying->is_input_varying = 1; + varying->is_param = var->is_param; list_add_before(&var->scope_entry, &varying->scope_entry); list_add_tail(&ctx->extern_vars, &varying->extern_entry); @@ -170,6 +172,7 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct } vkd3d_string_buffer_release(&ctx->string_buffers, name); varying->is_output_varying = 1; + varying->is_param = var->is_param; list_add_before(&var->scope_entry, &varying->scope_entry); list_add_tail(&ctx->extern_vars, &varying->extern_entry); @@ -896,6 +899,34 @@ static void put_dword(struct bytecode_buffer *buffer, uint32_t value) buffer->data[buffer->count++] = value; } +static void set_dword(struct bytecode_buffer *buffer, unsigned int index, uint32_t value) +{ + if (buffer->status) + return; + + assert(index < buffer->count); + buffer->data[index] = value; +} + +static void put_string(struct bytecode_buffer *buffer, const char *str) +{ + size_t len = strlen(str) + 1; + unsigned int token_count = (len + 3) / sizeof(*buffer->data); + + if (buffer->status) + return; + + if (!vkd3d_array_reserve((void **)&buffer->data, &buffer->size, buffer->count + token_count, sizeof(*buffer->data))) + { + buffer->status = E_OUTOFMEMORY; + return; + } + + buffer->data[buffer->count + token_count - 1] = 0xabababab; + memcpy(buffer->data + buffer->count, str, len); + buffer->count += token_count; +} + static uint32_t sm1_version(enum vkd3d_shader_type type, unsigned int major, unsigned int minor) { if (type == VKD3D_SHADER_TYPE_VERTEX) @@ -904,6 +935,223 @@ static uint32_t sm1_version(enum vkd3d_shader_type type, unsigned int major, uns return D3DPS_VERSION(major, minor); } +static D3DXPARAMETER_CLASS sm1_class(const struct hlsl_type *type) +{ + switch (type->type) + { + case HLSL_CLASS_ARRAY: + return sm1_class(type->e.array.type); + case HLSL_CLASS_MATRIX: + assert(type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK); + if (type->modifiers & HLSL_MODIFIER_COLUMN_MAJOR) + return D3DXPC_MATRIX_COLUMNS; + else + return D3DXPC_MATRIX_ROWS; + case HLSL_CLASS_OBJECT: + return D3DXPC_OBJECT; + case HLSL_CLASS_SCALAR: + return D3DXPC_SCALAR; + case HLSL_CLASS_STRUCT: + return D3DXPC_STRUCT; + case HLSL_CLASS_VECTOR: + return D3DXPC_VECTOR; + default: + ERR("Invalid class %#x.\n", type->type); + assert(0); + return 0; + } +} + +static D3DXPARAMETER_TYPE sm1_base_type(const struct hlsl_type *type) +{ + switch (type->base_type) + { + case HLSL_TYPE_BOOL: + return D3DXPT_BOOL; + case HLSL_TYPE_FLOAT: + case HLSL_TYPE_HALF: + return D3DXPT_FLOAT; + case HLSL_TYPE_INT: + case HLSL_TYPE_UINT: + return D3DXPT_INT; + case HLSL_TYPE_PIXELSHADER: + return D3DXPT_PIXELSHADER; + case HLSL_TYPE_SAMPLER: + switch (type->sampler_dim) + { + case HLSL_SAMPLER_DIM_1D: + return D3DXPT_SAMPLER1D; + case HLSL_SAMPLER_DIM_2D: + return D3DXPT_SAMPLER2D; + case HLSL_SAMPLER_DIM_3D: + return D3DXPT_SAMPLER3D; + case HLSL_SAMPLER_DIM_CUBE: + return D3DXPT_SAMPLERCUBE; + case HLSL_SAMPLER_DIM_GENERIC: + return D3DXPT_SAMPLER; + default: + ERR("Invalid dimension %#x.\n", type->sampler_dim); + } + break; + case HLSL_TYPE_STRING: + return D3DXPT_STRING; + case HLSL_TYPE_TEXTURE: + switch (type->sampler_dim) + { + case HLSL_SAMPLER_DIM_1D: + return D3DXPT_TEXTURE1D; + case HLSL_SAMPLER_DIM_2D: + return D3DXPT_TEXTURE2D; + case HLSL_SAMPLER_DIM_3D: + return D3DXPT_TEXTURE3D; + case HLSL_SAMPLER_DIM_CUBE: + return D3DXPT_TEXTURECUBE; + case HLSL_SAMPLER_DIM_GENERIC: + return D3DXPT_TEXTURE; + default: + ERR("Invalid dimension %#x.\n", type->sampler_dim); + } + break; + case HLSL_TYPE_VERTEXSHADER: + return D3DXPT_VERTEXSHADER; + case HLSL_TYPE_VOID: + return D3DXPT_VOID; + default: + assert(0); + } + assert(0); + return 0; +} + +static const struct hlsl_type *get_array_type(const struct hlsl_type *type) +{ + if (type->type == HLSL_CLASS_ARRAY) + return get_array_type(type->e.array.type); + return type; +} + +static unsigned int get_array_size(const struct hlsl_type *type) +{ + if (type->type == HLSL_CLASS_ARRAY) + return get_array_size(type->e.array.type) * type->e.array.elements_count; + return 1; +} + +static void write_sm1_type(struct bytecode_buffer *buffer, struct hlsl_type *type, unsigned int ctab_start) +{ + const struct hlsl_type *array_type = get_array_type(type); + unsigned int fields_offset = 0, field_count = 0; + unsigned int array_size = get_array_size(type); + struct hlsl_struct_field *field; + + if (type->bytecode_offset) + return; + + if (array_type->type == HLSL_CLASS_STRUCT) + { + LIST_FOR_EACH_ENTRY(field, array_type->e.elements, struct hlsl_struct_field, entry) + { + field->name_offset = buffer->count; + put_string(buffer, field->name); + write_sm1_type(buffer, field->type, ctab_start); + } + + fields_offset = (buffer->count - ctab_start) * sizeof(*buffer->data); + + LIST_FOR_EACH_ENTRY(field, array_type->e.elements, struct hlsl_struct_field, entry) + { + put_dword(buffer, (field->name_offset - ctab_start) * sizeof(*buffer->data)); + put_dword(buffer, (field->type->bytecode_offset - ctab_start) * sizeof(*buffer->data)); + ++field_count; + } + } + + type->bytecode_offset = buffer->count; + put_dword(buffer, sm1_class(type) | (sm1_base_type(type) << 16)); + put_dword(buffer, type->dimy | (type->dimx << 16)); + put_dword(buffer, array_size | (field_count << 16)); + put_dword(buffer, fields_offset); +} + +static void write_sm1_uniforms(struct hlsl_ctx *ctx, struct bytecode_buffer *buffer, + struct hlsl_ir_function_decl *entry_func) +{ + unsigned int ctab_start, vars_start; + unsigned int uniform_count = 0; + struct hlsl_ir_var *var; + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + if (!var->semantic && var->reg.allocated) + { + ++uniform_count; + + if (var->is_param && var->is_uniform) + { + struct vkd3d_string_buffer *name; + + if (!(name = vkd3d_string_buffer_get(&ctx->string_buffers))) + { + buffer->status = VKD3D_ERROR_OUT_OF_MEMORY; + return; + } + vkd3d_string_buffer_printf(name, "$%s", var->name); + vkd3d_free((char *)var->name); + var->name = vkd3d_strdup(name->buffer); + vkd3d_string_buffer_release(&ctx->string_buffers, name); + } + } + } + + put_dword(buffer, 0); /* COMMENT tag + size */ + put_dword(buffer, MAKEFOURCC('C','T','A','B')); + + ctab_start = buffer->count; + + put_dword(buffer, sizeof(D3DXSHADER_CONSTANTTABLE)); /* size of this header */ + put_dword(buffer, 0); /* creator */ + put_dword(buffer, sm1_version(ctx->profile->type, ctx->profile->major_version, ctx->profile->minor_version)); + put_dword(buffer, uniform_count); + put_dword(buffer, sizeof(D3DXSHADER_CONSTANTTABLE)); /* offset of constants */ + put_dword(buffer, 0); /* FIXME: flags */ + put_dword(buffer, 0); /* FIXME: target string */ + + vars_start = buffer->count; + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + if (!var->semantic && var->reg.allocated) + { + put_dword(buffer, 0); /* name */ + put_dword(buffer, D3DXRS_FLOAT4 | (var->reg.id << 16)); + put_dword(buffer, var->data_type->reg_size); + put_dword(buffer, 0); /* type */ + put_dword(buffer, 0); /* FIXME: default value */ + } + } + + uniform_count = 0; + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + if (!var->semantic && var->reg.allocated) + { + set_dword(buffer, vars_start + (uniform_count * 5), (buffer->count - ctab_start) * sizeof(*buffer->data)); + put_string(buffer, var->name); + + write_sm1_type(buffer, var->data_type, ctab_start); + set_dword(buffer, vars_start + (uniform_count * 5) + 3, + (var->data_type->bytecode_offset - ctab_start) * sizeof(*buffer->data)); + ++uniform_count; + } + } + + set_dword(buffer, ctab_start + 1, (buffer->count - ctab_start) * sizeof(*buffer->data)); + put_string(buffer, vkd3d_shader_get_version(NULL, NULL)); + + set_dword(buffer, ctab_start - 2, D3DSIO_COMMENT | ((buffer->count - (ctab_start - 1)) << 16)); +} + static int write_sm1_shader(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out) { @@ -912,12 +1160,14 @@ static int write_sm1_shader(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl * put_dword(&buffer, sm1_version(ctx->profile->type, ctx->profile->major_version, ctx->profile->minor_version)); + write_sm1_uniforms(ctx, &buffer, entry_func); + put_dword(&buffer, D3DSIO_END); if (!(ret = buffer.status)) { out->code = buffer.data; - out->size = buffer.count * sizeof(uint32_t); + out->size = buffer.count * sizeof(*buffer.data); } return ret; }