vkd3d-shader/hlsl: Store the type's register size for each register set.

This commit is contained in:
Francisco Casas 2022-10-28 12:23:05 -03:00 committed by Alexandre Julliard
parent 315966dc21
commit d07247249a
Notes: Alexandre Julliard 2023-02-22 21:51:16 +01:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Zebediah Figura (@zfigura)
Approved-by: Francisco Casas (@fcasas)
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/66
5 changed files with 137 additions and 52 deletions

View File

@ -164,6 +164,49 @@ static unsigned int get_array_size(const struct hlsl_type *type)
return 1;
}
bool hlsl_type_is_resource(const struct hlsl_type *type)
{
if (type->type == HLSL_CLASS_OBJECT)
{
switch (type->base_type)
{
case HLSL_TYPE_TEXTURE:
case HLSL_TYPE_SAMPLER:
case HLSL_TYPE_UAV:
return true;
default:
return false;
}
}
return false;
}
enum hlsl_regset hlsl_type_get_regset(const struct hlsl_type *type)
{
if (type->type <= HLSL_CLASS_LAST_NUMERIC)
return HLSL_REGSET_NUMERIC;
if (type->type == HLSL_CLASS_OBJECT)
{
switch (type->base_type)
{
case HLSL_TYPE_TEXTURE:
return HLSL_REGSET_TEXTURES;
case HLSL_TYPE_SAMPLER:
return HLSL_REGSET_SAMPLERS;
case HLSL_TYPE_UAV:
return HLSL_REGSET_UAVS;
default:
vkd3d_unreachable();
}
}
vkd3d_unreachable();
}
unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int offset)
{
/* Align to the next vec4 boundary if:
@ -171,7 +214,7 @@ unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int
* (b) the type would cross a vec4 boundary; i.e. a vec3 and a
* vec1 can be packed together, but not a vec3 and a vec2.
*/
if (type->type > HLSL_CLASS_LAST_NUMERIC || (offset & 3) + type->reg_size > 4)
if (type->type > HLSL_CLASS_LAST_NUMERIC || (offset & 3) + type->reg_size[HLSL_REGSET_NUMERIC] > 4)
return align(offset, 4);
return offset;
}
@ -179,31 +222,40 @@ unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int
static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type *type)
{
bool is_sm4 = (ctx->profile->major_version >= 4);
unsigned int k;
for (k = 0; k <= HLSL_REGSET_LAST; ++k)
type->reg_size[k] = 0;
switch (type->type)
{
case HLSL_CLASS_SCALAR:
case HLSL_CLASS_VECTOR:
type->reg_size = is_sm4 ? type->dimx : 4;
type->reg_size[HLSL_REGSET_NUMERIC] = is_sm4 ? type->dimx : 4;
break;
case HLSL_CLASS_MATRIX:
if (hlsl_type_is_row_major(type))
type->reg_size = is_sm4 ? (4 * (type->dimy - 1) + type->dimx) : (4 * type->dimy);
type->reg_size[HLSL_REGSET_NUMERIC] = is_sm4 ? (4 * (type->dimy - 1) + type->dimx) : (4 * type->dimy);
else
type->reg_size = is_sm4 ? (4 * (type->dimx - 1) + type->dimy) : (4 * type->dimx);
type->reg_size[HLSL_REGSET_NUMERIC] = is_sm4 ? (4 * (type->dimx - 1) + type->dimy) : (4 * type->dimx);
break;
case HLSL_CLASS_ARRAY:
{
unsigned int element_size = type->e.array.type->reg_size;
if (type->e.array.elements_count == HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT)
type->reg_size = 0;
else if (is_sm4)
type->reg_size = (type->e.array.elements_count - 1) * align(element_size, 4) + element_size;
else
type->reg_size = type->e.array.elements_count * element_size;
break;
for (k = 0; k <= HLSL_REGSET_LAST; ++k)
{
unsigned int element_size = type->e.array.type->reg_size[k];
if (is_sm4 && k == HLSL_REGSET_NUMERIC)
type->reg_size[k] = (type->e.array.elements_count - 1) * align(element_size, 4) + element_size;
else
type->reg_size[k] = type->e.array.elements_count * element_size;
}
break;
}
@ -212,16 +264,17 @@ static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type
unsigned int i;
type->dimx = 0;
type->reg_size = 0;
for (i = 0; i < type->e.record.field_count; ++i)
{
struct hlsl_struct_field *field = &type->e.record.fields[i];
unsigned int field_size = field->type->reg_size;
type->reg_size = hlsl_type_get_sm4_offset(field->type, type->reg_size);
field->reg_offset = type->reg_size;
type->reg_size += field_size;
for (k = 0; k <= HLSL_REGSET_LAST; ++k)
{
if (k == HLSL_REGSET_NUMERIC)
type->reg_size[k] = hlsl_type_get_sm4_offset(field->type, type->reg_size[k]);
field->reg_offset[k] = type->reg_size[k];
type->reg_size[k] += field->type->reg_size[k];
}
type->dimx += field->type->dimx * field->type->dimy * get_array_size(field->type);
}
@ -229,16 +282,25 @@ static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type
}
case HLSL_CLASS_OBJECT:
type->reg_size = 0;
{
if (hlsl_type_is_resource(type))
{
enum hlsl_regset regset = hlsl_type_get_regset(type);
type->reg_size[regset] = 1;
}
break;
}
}
}
/* Returns the size of a type, considered as part of an array of that type.
* As such it includes padding after the type. */
unsigned int hlsl_type_get_array_element_reg_size(const struct hlsl_type *type)
/* Returns the size of a type, considered as part of an array of that type, within a specific
* register set. As such it includes padding after the type, when applicable. */
unsigned int hlsl_type_get_array_element_reg_size(const struct hlsl_type *type, enum hlsl_regset regset)
{
return align(type->reg_size, 4);
if (regset == HLSL_REGSET_NUMERIC)
return align(type->reg_size[regset], 4);
return type->reg_size[regset];
}
static struct hlsl_type *hlsl_new_type(struct hlsl_ctx *ctx, const char *name, enum hlsl_type_class type_class,

View File

@ -122,6 +122,16 @@ enum hlsl_matrix_majority
HLSL_ROW_MAJOR
};
enum hlsl_regset
{
HLSL_REGSET_SAMPLERS,
HLSL_REGSET_TEXTURES,
HLSL_REGSET_UAVS,
HLSL_REGSET_LAST_OBJECT = HLSL_REGSET_UAVS,
HLSL_REGSET_NUMERIC,
HLSL_REGSET_LAST = HLSL_REGSET_NUMERIC,
};
/* An HLSL source-level data type, including anonymous structs and typedefs. */
struct hlsl_type
{
@ -183,12 +193,12 @@ struct hlsl_type
struct hlsl_type *resource_format;
} e;
/* Number of numeric register components used by one value of this type (4 components make 1
* register).
* If type is HLSL_CLASS_STRUCT or HLSL_CLASS_ARRAY, this value includes the reg_size of
* their elements and padding (which varies according to the backend).
* This value is 0 for types without numeric components, like objects. */
unsigned int reg_size;
/* Number of numeric register components used by one value of this type, for each regset.
* For HLSL_REGSET_NUMERIC, 4 components make 1 register, while for other regsets 1 component makes
* 1 register.
* If type is HLSL_CLASS_STRUCT or HLSL_CLASS_ARRAY, the reg_size of their elements and padding
* (which varies according to the backend) is also included. */
unsigned int reg_size[HLSL_REGSET_LAST + 1];
/* Offset where the type's description starts in the output bytecode, in bytes. */
size_t bytecode_offset;
@ -215,8 +225,8 @@ struct hlsl_struct_field
* type->modifiers instead) and that also are specific to the field and not the whole variable.
* In particular, interpolation modifiers. */
unsigned int storage_modifiers;
/* Offset of the field within the type it belongs to, in numeric register components. */
unsigned int reg_offset;
/* Offset of the field within the type it belongs to, in register components, for each regset. */
unsigned int reg_offset[HLSL_REGSET_LAST + 1];
/* Offset where the fields's name starts in the output bytecode, in bytes. */
size_t name_bytecode_offset;
@ -556,10 +566,12 @@ struct hlsl_deref
struct hlsl_src *path;
/* Single instruction node of data type uint used to represent the register offset (in register
* components), from the start of the variable, of the part referenced.
* 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. */
struct hlsl_src offset;
enum hlsl_regset offset_regset;
};
struct hlsl_ir_load
@ -1086,13 +1098,15 @@ bool hlsl_scope_add_type(struct hlsl_scope *scope, struct hlsl_type *type);
struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old,
unsigned int default_majority, unsigned int modifiers);
unsigned int hlsl_type_component_count(const struct hlsl_type *type);
unsigned int hlsl_type_get_array_element_reg_size(const struct hlsl_type *type);
unsigned int hlsl_type_get_array_element_reg_size(const struct hlsl_type *type, enum hlsl_regset regset);
struct hlsl_type *hlsl_type_get_component_type(struct hlsl_ctx *ctx, struct hlsl_type *type,
unsigned int index);
bool hlsl_type_is_row_major(const struct hlsl_type *type);
unsigned int hlsl_type_minor_size(const struct hlsl_type *type);
unsigned int hlsl_type_major_size(const struct hlsl_type *type);
unsigned int hlsl_type_element_count(const struct hlsl_type *type);
bool hlsl_type_is_resource(const struct hlsl_type *type);
enum hlsl_regset hlsl_type_get_regset(const struct hlsl_type *type);
unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int offset);
bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2);

View File

@ -24,7 +24,7 @@
/* 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,
const struct vkd3d_shader_location *loc)
enum hlsl_regset regset, const struct vkd3d_shader_location *loc)
{
struct hlsl_ir_node *idx_offset = NULL;
struct hlsl_ir_constant *c;
@ -52,7 +52,7 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str
case HLSL_CLASS_ARRAY:
{
unsigned int size = hlsl_type_get_array_element_reg_size(type->e.array.type);
unsigned int size = hlsl_type_get_array_element_reg_size(type->e.array.type, regset);
if (!(c = hlsl_new_uint_constant(ctx, size, loc)))
return NULL;
@ -70,7 +70,7 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str
unsigned int field_idx = hlsl_ir_constant(idx)->value[0].u;
struct hlsl_struct_field *field = &type->e.record.fields[field_idx];
if (!(c = hlsl_new_uint_constant(ctx, field->reg_offset, loc)))
if (!(c = hlsl_new_uint_constant(ctx, field->reg_offset[regset], loc)))
return NULL;
list_add_tail(&block->instrs, &c->node.entry);
@ -110,7 +110,8 @@ 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, loc)))
if (!(offset = new_offset_from_path_index(ctx, &idx_block, type, offset, deref->path[i].node,
deref->offset_regset, loc)))
return NULL;
list_move_tail(&block->instrs, &idx_block.instrs);
@ -145,6 +146,8 @@ static void replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_der
return;
}
deref->offset_regset = hlsl_type_get_regset(type);
if (!(offset = new_offset_instr_from_deref(ctx, &block, deref, &instr->loc)))
return;
list_move_before(&instr->entry, &block.instrs);
@ -2488,24 +2491,26 @@ static struct hlsl_reg allocate_range(struct hlsl_ctx *ctx, struct liveness *liv
static struct hlsl_reg allocate_numeric_registers_for_type(struct hlsl_ctx *ctx, struct liveness *liveness,
unsigned int first_write, unsigned int last_read, const struct hlsl_type *type)
{
unsigned int reg_size = type->reg_size[HLSL_REGSET_NUMERIC];
if (type->type <= HLSL_CLASS_VECTOR)
return allocate_register(ctx, liveness, first_write, last_read, type->reg_size, type->dimx);
return allocate_register(ctx, liveness, first_write, last_read, reg_size, type->dimx);
else
return allocate_range(ctx, liveness, first_write, last_read, type->reg_size);
return allocate_range(ctx, liveness, first_write, last_read, reg_size);
}
static const char *debug_register(char class, struct hlsl_reg reg, const struct hlsl_type *type)
{
static const char writemask_offset[] = {'w','x','y','z'};
unsigned int reg_size = type->reg_size[HLSL_REGSET_NUMERIC];
if (type->reg_size > 4)
if (reg_size > 4)
{
if (type->reg_size & 3)
return vkd3d_dbg_sprintf("%c%u-%c%u.%c", class, reg.id, class,
reg.id + (type->reg_size / 4), writemask_offset[type->reg_size & 3]);
if (reg_size & 3)
return vkd3d_dbg_sprintf("%c%u-%c%u.%c", class, reg.id, class, reg.id + (reg_size / 4),
writemask_offset[reg_size & 3]);
return vkd3d_dbg_sprintf("%c%u-%c%u", class, reg.id, class,
reg.id + (type->reg_size / 4) - 1);
return vkd3d_dbg_sprintf("%c%u-%c%u", class, reg.id, class, reg.id + (reg_size / 4) - 1);
}
return vkd3d_dbg_sprintf("%c%u%s", class, reg.id, debug_hlsl_writemask(reg.writemask));
}
@ -2592,7 +2597,7 @@ static void allocate_const_registers_recurse(struct hlsl_ctx *ctx, struct hlsl_b
struct hlsl_ir_constant *constant = hlsl_ir_constant(instr);
const struct hlsl_type *type = instr->data_type;
unsigned int x, y, i, writemask, end_reg;
unsigned int reg_size = type->reg_size;
unsigned int reg_size = type->reg_size[HLSL_REGSET_NUMERIC];
constant->reg = allocate_numeric_registers_for_type(ctx, liveness, 1, UINT_MAX, type);
TRACE("Allocated constant @%u to %s.\n", instr->index, debug_register('c', constant->reg, type));
@ -2688,7 +2693,7 @@ static void allocate_const_registers(struct hlsl_ctx *ctx, struct hlsl_ir_functi
{
if (var->is_uniform && var->last_read)
{
if (var->data_type->reg_size == 0)
if (var->data_type->reg_size[HLSL_REGSET_NUMERIC] == 0)
continue;
var->reg = allocate_numeric_registers_for_type(ctx, &liveness, 1, UINT_MAX, var->data_type);
@ -2807,7 +2812,7 @@ static void calculate_buffer_offset(struct hlsl_ir_var *var)
var->buffer_offset = buffer->size;
TRACE("Allocated buffer offset %u to %s.\n", var->buffer_offset, var->name);
buffer->size += var->data_type->reg_size;
buffer->size += var->data_type->reg_size[HLSL_REGSET_NUMERIC];
if (var->last_read)
buffer->used_size = buffer->size;
}
@ -3062,6 +3067,7 @@ bool hlsl_component_index_range_from_deref(struct hlsl_ctx *ctx, const struct hl
bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref, unsigned int *offset)
{
struct hlsl_ir_node *offset_node = deref->offset.node;
unsigned int size;
if (!offset_node)
{
@ -3078,10 +3084,11 @@ bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref
*offset = hlsl_ir_constant(offset_node)->value[0].u;
if (*offset >= deref->var->data_type->reg_size)
size = deref->var->data_type->reg_size[deref->offset_regset];
if (*offset >= size)
{
hlsl_error(ctx, &deref->offset.node->loc, VKD3D_SHADER_ERROR_HLSL_OFFSET_OUT_OF_BOUNDS,
"Dereference is out of bounds. %u/%u", *offset, deref->var->data_type->reg_size);
"Dereference is out of bounds. %u/%u", *offset, size);
return false;
}
@ -3107,6 +3114,8 @@ struct hlsl_reg hlsl_reg_from_deref(struct hlsl_ctx *ctx, const struct hlsl_dere
struct hlsl_reg ret = var->reg;
unsigned int offset = hlsl_offset_from_deref_safe(ctx, deref);
assert(deref->offset_regset == HLSL_REGSET_NUMERIC);
ret.id += offset / 4;
ret.writemask = 0xf & (0xf << (offset % 4));

View File

@ -366,7 +366,7 @@ static void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffe
else
{
put_u32(buffer, vkd3d_make_u32(D3DXRS_FLOAT4, var->reg.id));
put_u32(buffer, var->data_type->reg_size / 4);
put_u32(buffer, var->data_type->reg_size[HLSL_REGSET_NUMERIC] / 4);
}
put_u32(buffer, 0); /* type */
put_u32(buffer, 0); /* FIXME: default value */

View File

@ -395,7 +395,7 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b
put_u32(buffer, field->name_bytecode_offset);
put_u32(buffer, field->type->bytecode_offset);
put_u32(buffer, field->reg_offset);
put_u32(buffer, field->reg_offset[HLSL_REGSET_NUMERIC]);
}
}
@ -711,7 +711,7 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc)
put_u32(&buffer, 0); /* name */
put_u32(&buffer, var->buffer_offset * sizeof(float));
put_u32(&buffer, var->data_type->reg_size * sizeof(float));
put_u32(&buffer, var->data_type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float));
put_u32(&buffer, flags);
put_u32(&buffer, 0); /* type */
put_u32(&buffer, 0); /* FIXME: default value */