mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-01-28 13:05:02 -08:00
vkd3d-shader/hlsl: Store the type's register size for each register set.
This commit is contained in:
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
@ -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;
|
||||
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 = type->e.array.elements_count * element_size;
|
||||
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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user