From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl.c | 11 ++++- libs/vkd3d-shader/hlsl.h | 11 ++--- libs/vkd3d-shader/hlsl_codegen.c | 72 +++++++++++++++++++------------- 3 files changed, 59 insertions(+), 35 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index f439c9f3..80fa725a 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -435,6 +435,7 @@ static bool init_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hl { deref->var = var; deref->path_len = path_len; + deref->offset_const = 0; deref->offset.node = NULL;
if (path_len == 0) @@ -462,6 +463,7 @@ bool hlsl_init_deref_from_index_chain(struct hlsl_ctx *ctx, struct hlsl_deref *d
deref->path = NULL; deref->path_len = 0; + deref->offset_const = 0; deref->offset.node = NULL;
assert(chain); @@ -2210,10 +2212,15 @@ static void dump_deref(struct vkd3d_string_buffer *buffer, const struct hlsl_der } vkd3d_string_buffer_printf(buffer, "]"); } - else if (deref->offset.node) + else if (deref->offset.node || deref->offset_const) { vkd3d_string_buffer_printf(buffer, "["); - dump_src(buffer, &deref->offset); + if (deref->offset.node) + dump_src(buffer, &deref->offset); + if (deref->offset.node && deref->offset_const) + vkd3d_string_buffer_printf(buffer, " + "); + if (deref->offset_const) + vkd3d_string_buffer_printf(buffer, "%u/4", deref->offset_const); vkd3d_string_buffer_printf(buffer, "]"); } } diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 107ee153..09a9654f 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -599,12 +599,13 @@ struct hlsl_deref unsigned int path_len; struct hlsl_src *path;
- /* Single instruction node of data type uint used to represent the register offset (in register - * components, within the pertaining regset), from the start of the variable, of the part - * referenced. - * The path is lowered to this single offset -- whose value may vary between SM1 and SM4 -- - * before writing the bytecode. */ + /* Before writing the bytecode, the deref path is lowered into an offset from the start of the + * variable (within the pertaining regset), to the part of the variable that is referenced. + * This offset is composed of two parts, which are added together: + * - offset: An instruction node, storing the offset in whole registers. + * - offset_const: A constant offset, in number of register components. */ struct hlsl_src offset; + unsigned int offset_const; enum hlsl_regset offset_regset; };
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 2dc92f00..d4b7243a 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -23,8 +23,8 @@
/* TODO: remove when no longer needed, only used for new_offset_instr_from_deref() */ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, struct hlsl_block *block, - struct hlsl_type *type, struct hlsl_ir_node *offset, struct hlsl_ir_node *idx, - enum hlsl_regset regset, const struct vkd3d_shader_location *loc) + struct hlsl_type *type, struct hlsl_ir_node *base_offset, struct hlsl_ir_node *idx, + enum hlsl_regset regset, unsigned int *offset_component, const struct vkd3d_shader_location *loc) { struct hlsl_ir_node *idx_offset = NULL; struct hlsl_ir_node *c; @@ -34,27 +34,21 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str switch (type->class) { case HLSL_CLASS_VECTOR: - idx_offset = idx; + *offset_component += hlsl_ir_constant(idx)->value.u[0].u; break;
case HLSL_CLASS_MATRIX: - { - if (!(c = hlsl_new_uint_constant(ctx, 4, loc))) - return NULL; - hlsl_block_add_instr(block, c); - - if (!(idx_offset = hlsl_new_binary_expr(ctx, HLSL_OP2_MUL, c, idx))) - return NULL; - hlsl_block_add_instr(block, idx_offset); - + idx_offset = idx; break; - }
case HLSL_CLASS_ARRAY: { - unsigned int size = hlsl_type_get_array_element_reg_size(type->e.array.type, regset); + unsigned int elem_size = hlsl_type_get_array_element_reg_size(type->e.array.type, regset); + + if (regset == HLSL_REGSET_NUMERIC) + elem_size /= 4;
- if (!(c = hlsl_new_uint_constant(ctx, size, loc))) + if (!(c = hlsl_new_uint_constant(ctx, elem_size, loc))) return NULL; hlsl_block_add_instr(block, c);
@@ -69,8 +63,16 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str { unsigned int field_idx = hlsl_ir_constant(idx)->value.u[0].u; struct hlsl_struct_field *field = &type->e.record.fields[field_idx]; + unsigned int field_offset = field->reg_offset[regset];
- if (!(c = hlsl_new_uint_constant(ctx, field->reg_offset[regset], loc))) + if (regset == HLSL_REGSET_NUMERIC) + { + assert(*offset_component == 0); + *offset_component = field_offset % 4; + field_offset /= 4; + } + + if (!(c = hlsl_new_uint_constant(ctx, field_offset, loc))) return NULL; hlsl_block_add_instr(block, c);
@@ -83,26 +85,33 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str vkd3d_unreachable(); }
- if (offset) + if (idx_offset) { - if (!(idx_offset = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, offset, idx_offset))) + if (!(base_offset = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, base_offset, idx_offset))) return NULL; - hlsl_block_add_instr(block, idx_offset); + hlsl_block_add_instr(block, base_offset); }
- return idx_offset; + return base_offset; }
/* TODO: remove when no longer needed, only used for replace_deref_path_with_offset() */ static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, struct hlsl_block *block, - const struct hlsl_deref *deref, const struct vkd3d_shader_location *loc) + const struct hlsl_deref *deref, unsigned int *offset_component, const struct vkd3d_shader_location *loc) { - struct hlsl_ir_node *offset = NULL; + struct hlsl_ir_node *offset, *zero; struct hlsl_type *type; unsigned int i;
+ *offset_component = 0; + hlsl_block_init(block);
+ if (!(zero = hlsl_new_uint_constant(ctx, 0, loc))) + return NULL; + hlsl_block_add_instr(block, zero); + offset = zero; + assert(deref->var); type = deref->var->data_type;
@@ -111,8 +120,11 @@ static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, st struct hlsl_block idx_block;
if (!(offset = new_offset_from_path_index(ctx, &idx_block, type, offset, deref->path[i].node, - deref->offset_regset, loc))) + deref->offset_regset, offset_component, loc))) + { + hlsl_block_cleanup(&idx_block); return NULL; + }
hlsl_block_add_block(block, &idx_block);
@@ -126,6 +138,7 @@ static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, st static bool replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_ir_node *instr) { + unsigned int offset_component; const struct hlsl_type *type; struct hlsl_ir_node *offset; struct hlsl_block block; @@ -147,12 +160,13 @@ static bool replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_der
deref->offset_regset = hlsl_type_get_regset(type);
- if (!(offset = new_offset_instr_from_deref(ctx, &block, deref, &instr->loc))) + if (!(offset = new_offset_instr_from_deref(ctx, &block, deref, &offset_component, &instr->loc))) return false; list_move_before(&instr->entry, &block.instrs);
hlsl_cleanup_deref(deref); hlsl_src_from_node(&deref->offset, offset); + deref->offset_const = offset_component;
return true; } @@ -3860,11 +3874,10 @@ bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref struct hlsl_ir_node *offset_node = deref->offset.node; unsigned int size;
+ *offset = deref->offset_const; + if (!offset_node) - { - *offset = 0; return true; - }
/* We should always have generated a cast to UINT. */ assert(offset_node->data_type->class == HLSL_CLASS_SCALAR @@ -3873,7 +3886,10 @@ bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref if (offset_node->type != HLSL_IR_CONSTANT) return false;
- *offset = hlsl_ir_constant(offset_node)->value.u[0].u; + if (deref->offset_regset == HLSL_REGSET_NUMERIC) + *offset += 4 * hlsl_ir_constant(offset_node)->value.u[0].u; + else + *offset += hlsl_ir_constant(offset_node)->value.u[0].u;
size = deref->var->data_type->reg_size[deref->offset_regset]; if (*offset >= size)