Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl.y | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 4e17e806..9eef5e2f 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -763,6 +763,10 @@ static bool add_func_parameter(struct hlsl_ctx *ctx, struct list *list, if (param->type->type == HLSL_CLASS_MATRIX) assert(param->type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK);
+ if ((param->modifiers & HLSL_STORAGE_OUT) && (param->modifiers & HLSL_STORAGE_UNIFORM)) + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_MODIFIER, + "Parameter '%s' is declared as both "out" and "uniform".", param->name); + if (!(var = hlsl_new_var(param->name, param->type, loc, ¶m->semantic, param->modifiers, param->reg_reservation))) return false; var->is_param = 1;
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- libs/vkd3d-shader/hlsl.y | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 9eef5e2f..2c9fe551 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1423,6 +1423,10 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t { local = false;
+ if ((modifiers & HLSL_STORAGE_UNIFORM) && (modifiers & HLSL_STORAGE_STATIC)) + hlsl_error(ctx, var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_MODIFIER, + "Variable '%s' is declared as both "uniform" and "static".", var->name); + if ((func = hlsl_get_func_decl(ctx, var->name))) { hlsl_error(ctx, var->loc, VKD3D_SHADER_ERROR_HLSL_REDEFINED,
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- Makefile.am | 2 + tests/hlsl-invalid.shader_test | 60 +++++++++++++++++++++++ tests/hlsl-storage-qualifiers.shader_test | 20 ++++++++ 3 files changed, 82 insertions(+) create mode 100644 tests/hlsl-storage-qualifiers.shader_test
diff --git a/Makefile.am b/Makefile.am index 542b66e7..e8537864 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,6 +64,7 @@ vkd3d_shader_tests = \ tests/hlsl-return-implicit-conversion.shader_test \ tests/hlsl-return-void.shader_test \ tests/hlsl-static-initializer.shader_test \ + tests/hlsl-storage-qualifiers.shader_test \ tests/hlsl-struct-assignment.shader_test \ tests/hlsl-struct-semantics.shader_test \ tests/hlsl-vector-indexing.shader_test \ @@ -261,6 +262,7 @@ XFAIL_TESTS = \ tests/hlsl-return-implicit-conversion.shader_test \ tests/hlsl-return-void.shader_test \ tests/hlsl-static-initializer.shader_test \ + tests/hlsl-storage-qualifiers.shader_test \ tests/hlsl-struct-assignment.shader_test \ tests/hlsl-struct-semantics.shader_test \ tests/hlsl-vector-indexing.shader_test \ diff --git a/tests/hlsl-invalid.shader_test b/tests/hlsl-invalid.shader_test index 0711d266..72055989 100644 --- a/tests/hlsl-invalid.shader_test +++ b/tests/hlsl-invalid.shader_test @@ -121,6 +121,12 @@ float4 main(in float4 i) : sv_target return 0; }
+[pixel shader fail] +float4 main(float4 i) : sv_target +{ + return 0; +} + [pixel shader fail] struct {float4 a;};
@@ -159,3 +165,57 @@ void main(out struct output o) o.t = float4(0, 0, 0, 0); o.a = 0; } + +[pixel shader fail] +uniform in float4 f; +float4 main() : sv_target { return 0; } + +[pixel shader fail] +in float4 f; +float4 main() : sv_target { return 0; } + +[pixel shader fail] +static uniform float4 f; +float4 main() : sv_target { return 0; } + +[pixel shader fail] +void main(out uniform float4 o : sv_target) +{ + o = 0; +} + +[pixel shader fail] +void sub(out uniform float4 o) +{ + o = 0; +} + +void main(out float4 o : sv_target) +{ + sub(o); +} + +[pixel shader fail] +void sub(in out uniform float4 o) +{ +} + +void main(out float4 o : sv_target) +{ + o = 0; + sub(o); +} + +[pixel shader fail] +float4 main(void) : sv_target +{ + uniform float f; + return 0; +} + +[pixel shader fail] +float4 main(void) : sv_target +{ + in float f; + return 0; +} diff --git a/tests/hlsl-storage-qualifiers.shader_test b/tests/hlsl-storage-qualifiers.shader_test new file mode 100644 index 00000000..0e22bb6f --- /dev/null +++ b/tests/hlsl-storage-qualifiers.shader_test @@ -0,0 +1,20 @@ +[pixel shader] +void sub2(in uniform float4 i, out float4 o) +{ + o = i; +} + +void sub(float a, uniform float b, in float c, uniform in float d, out float4 o) +{ + sub2(float4(a, b, c, d), o); +} + +void main(in uniform float a, uniform float b, out float4 o : sv_target) +{ + sub(a, b, 0.3, 0.4, o); +} + +[test] +uniform 0 float4 0.1 0.2 0.0 0.0 +draw quad +probe all rgba (0.1, 0.2, 0.3, 0.4)
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- include/vkd3d_d3d9types.h | 32 +++++++++ libs/vkd3d-shader/hlsl_codegen.c | 114 ++++++++++++++++++++++++++++++- 2 files changed, 145 insertions(+), 1 deletion(-)
diff --git a/include/vkd3d_d3d9types.h b/include/vkd3d_d3d9types.h index 1f886443..c204202e 100644 --- a/include/vkd3d_d3d9types.h +++ b/include/vkd3d_d3d9types.h @@ -29,6 +29,10 @@
#define D3DSI_INSTLENGTH_SHIFT 24
+#define D3DSP_DCL_USAGE_SHIFT 0 +#define D3DSP_DCL_USAGEINDEX_SHIFT 16 +#define D3DSP_DSTMOD_SHIFT 20 + #define D3DSP_REGTYPE_SHIFT 28 #define D3DSP_REGTYPE_SHIFT2 8 #define D3DSP_REGTYPE_MASK (0x7 << D3DSP_REGTYPE_SHIFT) @@ -43,6 +47,24 @@ #define D3DPS_VERSION(major, minor) (0xffff0000 | ((major) << 8) | (minor)) #define D3DVS_VERSION(major, minor) (0xfffe0000 | ((major) << 8) | (minor))
+typedef enum _D3DDECLUSAGE +{ + D3DDECLUSAGE_POSITION = 0x0, + D3DDECLUSAGE_BLENDWEIGHT = 0x1, + D3DDECLUSAGE_BLENDINDICES = 0x2, + D3DDECLUSAGE_NORMAL = 0x3, + D3DDECLUSAGE_PSIZE = 0x4, + D3DDECLUSAGE_TEXCOORD = 0x5, + D3DDECLUSAGE_TANGENT = 0x6, + D3DDECLUSAGE_BINORMAL = 0x7, + D3DDECLUSAGE_TESSFACTOR = 0x8, + D3DDECLUSAGE_POSITIONT = 0x9, + D3DDECLUSAGE_COLOR = 0xa, + D3DDECLUSAGE_FOG = 0xb, + D3DDECLUSAGE_DEPTH = 0xc, + D3DDECLUSAGE_SAMPLE = 0xd, +} D3DDECLUSAGE; + typedef enum _D3DSHADER_INSTRUCTION_OPCODE_TYPE { D3DSIO_NOP = 0x00, @@ -136,6 +158,16 @@ typedef enum _D3DSHADER_INSTRUCTION_OPCODE_TYPE D3DSIO_FORCE_DWORD = 0x7fffffff, } D3DSHADER_INSTRUCTION_OPCODE_TYPE;
+typedef enum _D3DSHADER_PARAM_DSTMOD_TYPE +{ + D3DSPDM_NONE = 0 << D3DSP_DSTMOD_SHIFT, + D3DSPDM_SATURATE = 1 << D3DSP_DSTMOD_SHIFT, + D3DSPDM_PARTIALPRECISION = 2 << D3DSP_DSTMOD_SHIFT, + D3DSPDM_MSAMPCENTROID = 4 << D3DSP_DSTMOD_SHIFT, + + D3DSPDM_FORCE_DWORD = 0x7fffffff, +} D3DSHADER_PARAM_DSTMOD_TYPE; + typedef enum _D3DSHADER_PARAM_REGISTER_TYPE { D3DSPR_TEMP = 0x00, diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 9f2c278c..d4995110 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -1013,6 +1013,49 @@ static bool sm1_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_s return false; }
+static bool sm1_usage_from_semantic(const struct hlsl_semantic *semantic, D3DDECLUSAGE *usage, uint32_t *usage_idx) +{ + static const struct + { + const char *name; + D3DDECLUSAGE usage; + } + semantics[] = + { + {"binormal", D3DDECLUSAGE_BINORMAL}, + {"blendindices", D3DDECLUSAGE_BLENDINDICES}, + {"blendweight", D3DDECLUSAGE_BLENDWEIGHT}, + {"color", D3DDECLUSAGE_COLOR}, + {"depth", D3DDECLUSAGE_DEPTH}, + {"fog", D3DDECLUSAGE_FOG}, + {"normal", D3DDECLUSAGE_NORMAL}, + {"position", D3DDECLUSAGE_POSITION}, + {"positiont", D3DDECLUSAGE_POSITIONT}, + {"psize", D3DDECLUSAGE_PSIZE}, + {"sample", D3DDECLUSAGE_SAMPLE}, + {"sv_depth", D3DDECLUSAGE_DEPTH}, + {"sv_position", D3DDECLUSAGE_POSITION}, + {"sv_target", D3DDECLUSAGE_COLOR}, + {"tangent", D3DDECLUSAGE_TANGENT}, + {"tessfactor", D3DDECLUSAGE_TESSFACTOR}, + {"texcoord", D3DDECLUSAGE_TEXCOORD}, + }; + + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(semantics); ++i) + { + if (!ascii_strcasecmp(semantic->name, semantics[i].name)) + { + *usage = semantics[i].usage; + *usage_idx = semantic->index; + return true; + } + } + + return false; +} + static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, unsigned int *counter, bool output) { assert(var->semantic.name); @@ -1020,7 +1063,15 @@ static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var if (ctx->profile->major_version < 4) { D3DSHADER_PARAM_REGISTER_TYPE type; - unsigned int reg; + uint32_t reg, usage_idx; + D3DDECLUSAGE usage; + + if (!sm1_usage_from_semantic(&var->semantic, &usage, &usage_idx)) + { + hlsl_error(ctx, var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC, + "Invalid semantic '%s'.", var->semantic.name); + return; + }
if (!sm1_register_from_semantic(ctx, &var->semantic, output, &type, ®)) { @@ -1371,6 +1422,12 @@ static uint32_t sm1_encode_register_type(D3DSHADER_PARAM_REGISTER_TYPE type) | ((type << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2); }
+static uint32_t sm1_encode_dst(D3DSHADER_PARAM_REGISTER_TYPE type, + D3DSHADER_PARAM_DSTMOD_TYPE modifier, unsigned int writemask, unsigned int reg) +{ + return (1u << 31) | sm1_encode_register_type(type) | modifier | (writemask << 16) | reg; +} + static void write_sm1_constant_defs(struct hlsl_ctx *ctx, struct bytecode_buffer *buffer) { unsigned int i, x; @@ -1393,6 +1450,60 @@ static void write_sm1_constant_defs(struct hlsl_ctx *ctx, struct bytecode_buffer } }
+static void write_sm1_semantic_dcl(struct hlsl_ctx *ctx, struct bytecode_buffer *buffer, + const struct hlsl_ir_var *var, bool output) +{ + D3DSHADER_PARAM_REGISTER_TYPE type; + uint32_t token, usage_idx, reg_idx; + D3DDECLUSAGE usage; + bool ret; + + if (sm1_register_from_semantic(ctx, &var->semantic, output, &type, ®_idx)) + { + usage = 0; + usage_idx = 0; + } + else + { + ret = sm1_usage_from_semantic(&var->semantic, &usage, &usage_idx); + assert(ret); + type = output ? D3DSPR_OUTPUT : D3DSPR_INPUT; + reg_idx = var->reg.id; + } + + token = D3DSIO_DCL; + if (ctx->profile->major_version > 1) + token |= 2 << D3DSI_INSTLENGTH_SHIFT; + put_dword(buffer, token); + + token = (1u << 31); + token |= usage << D3DSP_DCL_USAGE_SHIFT; + token |= usage_idx << D3DSP_DCL_USAGEINDEX_SHIFT; + put_dword(buffer, token); + put_dword(buffer, sm1_encode_dst(type, D3DSPDM_NONE, (1 << var->data_type->dimx) - 1, reg_idx)); +} + +static void write_sm1_semantic_dcls(struct hlsl_ctx *ctx, struct bytecode_buffer *buffer) +{ + bool write_in = false, write_out = false; + struct hlsl_ir_var *var; + + if (ctx->profile->type == VKD3D_SHADER_TYPE_PIXEL) + write_in = true; + else if (ctx->profile->type == VKD3D_SHADER_TYPE_VERTEX && ctx->profile->major_version == 3) + write_in = write_out = true; + else if (ctx->profile->type == VKD3D_SHADER_TYPE_VERTEX && ctx->profile->major_version < 3) + write_in = true; + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + if (write_in && var->is_input_semantic) + write_sm1_semantic_dcl(ctx, buffer, var, false); + if (write_out && var->is_output_semantic) + write_sm1_semantic_dcl(ctx, buffer, var, true); + } +} + static int write_sm1_shader(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out) { @@ -1404,6 +1515,7 @@ static int write_sm1_shader(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl * write_sm1_uniforms(ctx, &buffer, entry_func);
write_sm1_constant_defs(ctx, &buffer); + write_sm1_semantic_dcls(ctx, &buffer);
put_dword(&buffer, D3DSIO_END);
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- include/vkd3d_d3d9types.h | 22 ++++ libs/vkd3d-shader/hlsl_codegen.c | 220 +++++++++++++++++++++++++++++++ 2 files changed, 242 insertions(+)
diff --git a/include/vkd3d_d3d9types.h b/include/vkd3d_d3d9types.h index c204202e..75d04614 100644 --- a/include/vkd3d_d3d9types.h +++ b/include/vkd3d_d3d9types.h @@ -33,6 +33,8 @@ #define D3DSP_DCL_USAGEINDEX_SHIFT 16 #define D3DSP_DSTMOD_SHIFT 20
+#define D3DSP_SRCMOD_SHIFT 24 + #define D3DSP_REGTYPE_SHIFT 28 #define D3DSP_REGTYPE_SHIFT2 8 #define D3DSP_REGTYPE_MASK (0x7 << D3DSP_REGTYPE_SHIFT) @@ -196,6 +198,26 @@ typedef enum _D3DSHADER_PARAM_REGISTER_TYPE D3DSPR_FORCE_DWORD = 0x7fffffff, } D3DSHADER_PARAM_REGISTER_TYPE;
+typedef enum _D3DSHADER_PARAM_SRCMOD_TYPE +{ + D3DSPSM_NONE = 0x0 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_NEG = 0x1 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_BIAS = 0x2 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_BIASNEG = 0x3 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_SIGN = 0x4 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_SIGNNEG = 0x5 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_COMP = 0x6 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_X2 = 0x7 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_X2NEG = 0x8 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_DZ = 0x9 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_DW = 0xa << D3DSP_SRCMOD_SHIFT, + D3DSPSM_ABS = 0xb << D3DSP_SRCMOD_SHIFT, + D3DSPSM_ABSNEG = 0xc << D3DSP_SRCMOD_SHIFT, + D3DSPSM_NOT = 0xd << D3DSP_SRCMOD_SHIFT, + + D3DSPSM_FORCE_DWORD = 0x7fffffff, +} D3DSHADER_PARAM_SRCMOD_TYPE; + typedef enum _D3DSHADER_MISCTYPE_OFFSETS { D3DSMO_POSITION = 0x0, diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index d4995110..0dfbfb9f 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -1097,6 +1097,101 @@ static void allocate_semantic_registers(struct hlsl_ctx *ctx) } }
+static unsigned int map_swizzle(unsigned int swizzle, unsigned int writemask) +{ + unsigned int i, ret = 0; + + for (i = 0; i < 4; ++i) + { + if (writemask & (1 << i)) + { + ret |= (swizzle & 3) << (i * 2); + swizzle >>= 2; + } + } + return ret; +} + +static unsigned int swizzle_from_writemask(unsigned int writemask) +{ + static const unsigned int swizzles[16] = + { + 0, + HLSL_SWIZZLE(X, X, X, X), + HLSL_SWIZZLE(Y, Y, Y, Y), + HLSL_SWIZZLE(X, Y, X, X), + HLSL_SWIZZLE(Z, Z, Z, Z), + HLSL_SWIZZLE(X, Z, X, X), + HLSL_SWIZZLE(Y, Z, X, X), + HLSL_SWIZZLE(X, Y, Z, X), + HLSL_SWIZZLE(W, W, W, W), + HLSL_SWIZZLE(X, W, X, X), + HLSL_SWIZZLE(Y, W, X, X), + HLSL_SWIZZLE(X, Y, W, X), + HLSL_SWIZZLE(Z, W, X, X), + HLSL_SWIZZLE(X, Z, W, X), + HLSL_SWIZZLE(Y, Z, W, X), + HLSL_SWIZZLE(X, Y, Z, W), + }; + + return swizzles[writemask & 0xf]; +} + +static unsigned int combine_writemasks(unsigned int first, unsigned int second) +{ + unsigned int ret = 0, i, j = 0; + + for (i = 0; i < 4; ++i) + { + if (first & (1 << i)) + { + if (second & (1 << j++)) + ret |= (1 << i); + } + } + + return ret; +} + +static bool type_is_single_reg(const struct hlsl_type *type) +{ + return type->type == HLSL_CLASS_SCALAR || type->type == HLSL_CLASS_VECTOR; +} + +static struct hlsl_reg hlsl_reg_from_deref(const struct hlsl_deref *deref, const struct hlsl_type *type) +{ + struct hlsl_ir_node *offset_node = deref->offset.node; + const struct hlsl_ir_var *var = deref->var; + struct hlsl_reg ret = {0}; + unsigned int offset = 0; + + if (offset_node && offset_node->type != HLSL_IR_CONSTANT) + { + FIXME("Dereference with non-constant offset of type %s.\n", hlsl_node_type_to_string(offset_node->type)); + return ret; + } + + ret = var->reg; + + ret.allocated = var->reg.allocated; + ret.id = var->reg.id; + if (offset_node) + offset = hlsl_ir_constant(offset_node)->value.u[0]; + ret.id += offset / 4; + + if (type_is_single_reg(var->data_type)) + { + assert(!offset); + ret.writemask = var->reg.writemask; + } + else + { + assert(type_is_single_reg(type)); + ret.writemask = ((1 << type->dimx) - 1) << (offset & 3); + } + return ret; +} + struct bytecode_buffer { uint32_t *data; @@ -1428,6 +1523,57 @@ static uint32_t sm1_encode_dst(D3DSHADER_PARAM_REGISTER_TYPE type, return (1u << 31) | sm1_encode_register_type(type) | modifier | (writemask << 16) | reg; }
+static uint32_t sm1_encode_src(D3DSHADER_PARAM_REGISTER_TYPE type, + D3DSHADER_PARAM_SRCMOD_TYPE modifier, unsigned int swizzle, uint32_t reg) +{ + return (1u << 31) | sm1_encode_register_type(type) | modifier | (swizzle << 16) | reg; +} + +struct sm1_instruction +{ + D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode; + + struct + { + D3DSHADER_PARAM_REGISTER_TYPE type; + D3DSHADER_PARAM_DSTMOD_TYPE mod; + unsigned int writemask; + uint32_t reg; + } dst; + + struct + { + D3DSHADER_PARAM_REGISTER_TYPE type; + D3DSHADER_PARAM_SRCMOD_TYPE mod; + unsigned int swizzle; + uint32_t reg; + } srcs[2]; + unsigned int src_count; + + unsigned int has_dst; +}; + +static void write_sm1_instruction(struct hlsl_ctx *ctx, struct bytecode_buffer *buffer, + const struct sm1_instruction *instr) +{ + uint32_t token = instr->opcode; + unsigned int i; + + if (ctx->profile->major_version > 1) + token |= (instr->has_dst + instr->src_count) << D3DSI_INSTLENGTH_SHIFT; + put_dword(buffer, token); + + if (instr->has_dst) + { + assert(instr->dst.writemask); + put_dword(buffer, sm1_encode_dst(instr->dst.type, instr->dst.mod, instr->dst.writemask, instr->dst.reg)); + } + + for (i = 0; i < instr->src_count; ++i) + put_dword(buffer, sm1_encode_src(instr->srcs[i].type, instr->srcs[i].mod, + map_swizzle(instr->srcs[i].swizzle, instr->dst.writemask), instr->srcs[i].reg)); +}; + static void write_sm1_constant_defs(struct hlsl_ctx *ctx, struct bytecode_buffer *buffer) { unsigned int i, x; @@ -1504,6 +1650,79 @@ static void write_sm1_semantic_dcls(struct hlsl_ctx *ctx, struct bytecode_buffer } }
+static void write_sm1_store(struct hlsl_ctx *ctx, struct bytecode_buffer *buffer, const struct hlsl_ir_node *instr) +{ + const struct hlsl_ir_store *store = hlsl_ir_store(instr); + const struct hlsl_ir_node *rhs = store->rhs.node; + const struct hlsl_reg reg = hlsl_reg_from_deref(&store->lhs, rhs->data_type); + struct sm1_instruction sm1_instr = + { + .opcode = D3DSIO_MOV, + + .dst.type = D3DSPR_TEMP, + .dst.reg = reg.id, + .dst.writemask = combine_writemasks(reg.writemask, store->writemask), + .has_dst = 1, + + .srcs[0].type = D3DSPR_TEMP, + .srcs[0].reg = rhs->reg.id, + .srcs[0].swizzle = swizzle_from_writemask(rhs->reg.writemask), + .src_count = 1, + }; + + if (store->lhs.var->data_type->type == HLSL_CLASS_MATRIX) + { + FIXME("Matrix writemasks need to be lowered.\n"); + return; + } + + if (store->lhs.var->is_output_semantic) + { + if (!sm1_register_from_semantic(ctx, &store->lhs.var->semantic, true, &sm1_instr.dst.type, &sm1_instr.dst.reg)) + { + assert(reg.allocated); + sm1_instr.dst.type = D3DSPR_OUTPUT; + sm1_instr.dst.reg = reg.id; + } + else + sm1_instr.dst.writemask = (1u << store->lhs.var->data_type->dimx) - 1; + } + else + assert(reg.allocated); + + write_sm1_instruction(ctx, buffer, &sm1_instr); +} + +static void write_sm1_instructions(struct hlsl_ctx *ctx, struct bytecode_buffer *buffer, + const struct hlsl_ir_function_decl *entry_func) +{ + const struct hlsl_ir_node *instr; + + LIST_FOR_EACH_ENTRY(instr, entry_func->body, struct hlsl_ir_node, entry) + { + if (instr->data_type) + { + if (instr->data_type->type == HLSL_CLASS_MATRIX) + { + FIXME("Matrix operations need to be lowered.\n"); + break; + } + + assert(instr->data_type->type == HLSL_CLASS_SCALAR || instr->data_type->type == HLSL_CLASS_VECTOR); + } + + switch (instr->type) + { + case HLSL_IR_STORE: + write_sm1_store(ctx, buffer, instr); + break; + + default: + FIXME("Unhandled instruction type %s.\n", hlsl_node_type_to_string(instr->type)); + } + } +} + static int write_sm1_shader(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out) { @@ -1516,6 +1735,7 @@ static int write_sm1_shader(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *
write_sm1_constant_defs(ctx, &buffer); write_sm1_semantic_dcls(ctx, &buffer); + write_sm1_instructions(ctx, &buffer, entry_func);
put_dword(&buffer, D3DSIO_END);
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
On Tue, May 11, 2021 at 6:36 AM Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
include/vkd3d_d3d9types.h | 22 ++++ libs/vkd3d-shader/hlsl_codegen.c | 220 +++++++++++++++++++++++++++++++ 2 files changed, 242 insertions(+)
Very nice. The generated bytecode looks a bit silly right now, because oftentimes we end up generating instructions like "mov r0, r0" but 1. it doesn't matter and 2. it shouldn't be hard to clean it up at some point.
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index d4995110..0dfbfb9f 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c
+static struct hlsl_reg hlsl_reg_from_deref(const struct hlsl_deref *deref, const struct hlsl_type *type) +{
- struct hlsl_ir_node *offset_node = deref->offset.node;
- const struct hlsl_ir_var *var = deref->var;
- struct hlsl_reg ret = {0};
- unsigned int offset = 0;
- if (offset_node && offset_node->type != HLSL_IR_CONSTANT)
- {
FIXME("Dereference with non-constant offset of type %s.\n", hlsl_node_type_to_string(offset_node->type));
return ret;
- }
- ret = var->reg;
- ret.allocated = var->reg.allocated;
- ret.id = var->reg.id;
- if (offset_node)
offset = hlsl_ir_constant(offset_node)->value.u[0];
Maybe it makes sense to assert() that the offset is a HLSL_TYPE_UINT scalar?
@@ -1428,6 +1523,57 @@ static uint32_t sm1_encode_dst(D3DSHADER_PARAM_REGISTER_TYPE type, return (1u << 31) | sm1_encode_register_type(type) | modifier | (writemask << 16) | reg; }
+static uint32_t sm1_encode_src(D3DSHADER_PARAM_REGISTER_TYPE type,
D3DSHADER_PARAM_SRCMOD_TYPE modifier, unsigned int swizzle, uint32_t reg)
+{
- return (1u << 31) | sm1_encode_register_type(type) | modifier | (swizzle << 16) | reg;
+}
+struct sm1_instruction +{
- D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode;
- struct
- {
D3DSHADER_PARAM_REGISTER_TYPE type;
D3DSHADER_PARAM_DSTMOD_TYPE mod;
unsigned int writemask;
uint32_t reg;
- } dst;
- struct
- {
D3DSHADER_PARAM_REGISTER_TYPE type;
D3DSHADER_PARAM_SRCMOD_TYPE mod;
unsigned int swizzle;
uint32_t reg;
- } srcs[2];
- unsigned int src_count;
- unsigned int has_dst;
+};
It might make sense to embrace this direction and e.g. assign a type to the src / dst register structs, so that you can pass a pointer to the struct to sm1_encode_(src,dst)() instead of each piece of register specification individually. We could even go a step further and have an array of struct sm1_instruction as a low-level IR, splitting the actual bytecode emission from the instruction generation.
Not a must by any means, but do keep the possibility in mind: there is a non-zero chance that some transformation passes become much simpler in a lower level IR.
On 5/14/21 4:41 AM, Matteo Bruni wrote:
On Tue, May 11, 2021 at 6:36 AM Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
include/vkd3d_d3d9types.h | 22 ++++ libs/vkd3d-shader/hlsl_codegen.c | 220 +++++++++++++++++++++++++++++++ 2 files changed, 242 insertions(+)
Very nice. The generated bytecode looks a bit silly right now, because oftentimes we end up generating instructions like "mov r0, r0" but 1. it doesn't matter and 2. it shouldn't be hard to clean it up at some point.
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index d4995110..0dfbfb9f 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c
+static struct hlsl_reg hlsl_reg_from_deref(const struct hlsl_deref *deref, const struct hlsl_type *type) +{
- struct hlsl_ir_node *offset_node = deref->offset.node;
- const struct hlsl_ir_var *var = deref->var;
- struct hlsl_reg ret = {0};
- unsigned int offset = 0;
- if (offset_node && offset_node->type != HLSL_IR_CONSTANT)
- {
FIXME("Dereference with non-constant offset of type %s.\n", hlsl_node_type_to_string(offset_node->type));
return ret;
- }
- ret = var->reg;
- ret.allocated = var->reg.allocated;
- ret.id = var->reg.id;
- if (offset_node)
offset = hlsl_ir_constant(offset_node)->value.u[0];
Maybe it makes sense to assert() that the offset is a HLSL_TYPE_UINT scalar?
Eh, yes, that's a good idea, will do.
@@ -1428,6 +1523,57 @@ static uint32_t sm1_encode_dst(D3DSHADER_PARAM_REGISTER_TYPE type, return (1u << 31) | sm1_encode_register_type(type) | modifier | (writemask << 16) | reg; }
+static uint32_t sm1_encode_src(D3DSHADER_PARAM_REGISTER_TYPE type,
D3DSHADER_PARAM_SRCMOD_TYPE modifier, unsigned int swizzle, uint32_t reg)
+{
- return (1u << 31) | sm1_encode_register_type(type) | modifier | (swizzle << 16) | reg;
+}
+struct sm1_instruction +{
- D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode;
- struct
- {
D3DSHADER_PARAM_REGISTER_TYPE type;
D3DSHADER_PARAM_DSTMOD_TYPE mod;
unsigned int writemask;
uint32_t reg;
- } dst;
- struct
- {
D3DSHADER_PARAM_REGISTER_TYPE type;
D3DSHADER_PARAM_SRCMOD_TYPE mod;
unsigned int swizzle;
uint32_t reg;
- } srcs[2];
- unsigned int src_count;
- unsigned int has_dst;
+};
It might make sense to embrace this direction and e.g. assign a type to the src / dst register structs, so that you can pass a pointer to the struct to sm1_encode_(src,dst)() instead of each piece of register specification individually.
I think the only reason I didn't do this in the first place was because of semantic declarations, but honestly it should be easy to just create structures, if not sm1_instruction as a whole.
That, or this code was gradually transformed from a version that didn't even have the sm1_instruction helper.
We could even go a step further and have an array of struct sm1_instruction as a low-level IR, splitting the actual bytecode emission from the instruction generation.
Not a must by any means, but do keep the possibility in mind: there is a non-zero chance that some transformation passes become much simpler in a lower level IR.
There are probably some optimization passes that do get easy at a very low level, though I can't immediately of any that can't also be solved at a higher level. Plus hlsl_ir could probably be made lower-level than it is anyway. I dunno, compilers are hard...
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com