mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2024-11-21 16:46:41 -08:00
vkd3d-shader/hlsl: Support multiple-register variables in object regsets.
Variables that contain more than one object (arrays or structs) require the allocation of contiguous registers in the respective object register spaces.
This commit is contained in:
parent
9a8a440b9b
commit
69ff249ef4
Notes:
Alexandre Julliard
2023-05-08 22:34:16 +02:00
Approved-by: Giovanni Mascellani (@giomasce) Approved-by: Zebediah Figura (@zfigura) Approved-by: Henri Verbeet (@hverbeet) Approved-by: Alexandre Julliard (@julliard) Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/159
@ -1323,19 +1323,15 @@ static void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffe
|
||||
if (!var->semantic.name && var->regs[regset].allocated)
|
||||
{
|
||||
put_u32(buffer, 0); /* name */
|
||||
if (var->data_type->class == HLSL_CLASS_OBJECT
|
||||
&& (var->data_type->base_type == HLSL_TYPE_SAMPLER
|
||||
|| var->data_type->base_type == HLSL_TYPE_TEXTURE))
|
||||
if (regset == HLSL_REGSET_NUMERIC)
|
||||
{
|
||||
assert(regset == HLSL_REGSET_SAMPLERS);
|
||||
put_u32(buffer, vkd3d_make_u32(D3DXRS_SAMPLER, var->regs[regset].id));
|
||||
put_u32(buffer, 1);
|
||||
put_u32(buffer, vkd3d_make_u32(D3DXRS_FLOAT4, var->regs[regset].id));
|
||||
put_u32(buffer, var->data_type->reg_size[regset] / 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(regset == HLSL_REGSET_NUMERIC);
|
||||
put_u32(buffer, vkd3d_make_u32(D3DXRS_FLOAT4, var->regs[regset].id));
|
||||
put_u32(buffer, var->data_type->reg_size[regset] / 4);
|
||||
put_u32(buffer, vkd3d_make_u32(D3DXRS_SAMPLER, var->regs[regset].id));
|
||||
put_u32(buffer, var->regs[regset].bind_count);
|
||||
}
|
||||
put_u32(buffer, 0); /* type */
|
||||
put_u32(buffer, 0); /* FIXME: default value */
|
||||
|
@ -173,6 +173,9 @@ unsigned int hlsl_get_multiarray_size(const struct hlsl_type *type)
|
||||
|
||||
bool hlsl_type_is_resource(const struct hlsl_type *type)
|
||||
{
|
||||
if (type->class == HLSL_CLASS_ARRAY)
|
||||
return hlsl_type_is_resource(type->e.array.type);
|
||||
|
||||
if (type->class == HLSL_CLASS_OBJECT)
|
||||
{
|
||||
switch (type->base_type)
|
||||
@ -193,6 +196,9 @@ enum hlsl_regset hlsl_type_get_regset(const struct hlsl_type *type)
|
||||
if (type->class <= HLSL_CLASS_LAST_NUMERIC)
|
||||
return HLSL_REGSET_NUMERIC;
|
||||
|
||||
if (type->class == HLSL_CLASS_ARRAY)
|
||||
return hlsl_type_get_regset(type->e.array.type);
|
||||
|
||||
if (type->class == HLSL_CLASS_OBJECT)
|
||||
{
|
||||
switch (type->base_type)
|
||||
@ -210,8 +216,6 @@ enum hlsl_regset hlsl_type_get_regset(const struct hlsl_type *type)
|
||||
vkd3d_unreachable();
|
||||
}
|
||||
}
|
||||
else if (type->class == HLSL_CLASS_ARRAY)
|
||||
return hlsl_type_get_regset(type->e.array.type);
|
||||
|
||||
vkd3d_unreachable();
|
||||
}
|
||||
|
@ -240,16 +240,21 @@ struct hlsl_struct_field
|
||||
size_t name_bytecode_offset;
|
||||
};
|
||||
|
||||
/* Information of the register allocated for an instruction node or variable.
|
||||
/* Information of the register(s) allocated for an instruction node or variable.
|
||||
* These values are initialized at the end of hlsl_emit_bytecode(), after the compilation passes,
|
||||
* just before writing the bytecode.
|
||||
* For numeric registers, a writemask can be provided to indicate the reservation of only some of the
|
||||
* 4 components.
|
||||
* The type of register (register class) is implied from its use, so it is not stored in this
|
||||
* struct. */
|
||||
struct hlsl_reg
|
||||
{
|
||||
/* Index of the first register allocated. */
|
||||
uint32_t id;
|
||||
/* Number of registers to be allocated.
|
||||
* Unlike the variable's type's regsize, it is not expressed in register components, but rather
|
||||
* in whole registers, and may depend on which components are used within the shader. */
|
||||
uint32_t bind_count;
|
||||
/* For numeric registers, a writemask can be provided to indicate the reservation of only some
|
||||
* of the 4 components. */
|
||||
unsigned int writemask;
|
||||
/* Whether the register has been allocated. */
|
||||
bool allocated;
|
||||
|
@ -2586,8 +2586,10 @@ static void allocate_register_reservations(struct hlsl_ctx *ctx)
|
||||
{
|
||||
var->regs[regset].allocated = true;
|
||||
var->regs[regset].id = var->reg_reservation.reg_index;
|
||||
TRACE("Allocated reserved %s to %c%u.\n", var->name, var->reg_reservation.reg_type,
|
||||
var->reg_reservation.reg_index);
|
||||
var->regs[regset].bind_count = var->data_type->reg_size[regset];
|
||||
TRACE("Allocated reserved %s to %c%u-%c%u.\n", var->name, var->reg_reservation.reg_type,
|
||||
var->reg_reservation.reg_index, var->reg_reservation.reg_type,
|
||||
var->reg_reservation.reg_index + var->regs[regset].bind_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2829,6 +2831,7 @@ static struct hlsl_reg allocate_register(struct hlsl_ctx *ctx, struct register_a
|
||||
record_allocation(ctx, allocator, reg_idx, writemask, first_write, last_read);
|
||||
|
||||
ret.id = reg_idx;
|
||||
ret.bind_count = 1;
|
||||
ret.writemask = hlsl_combine_writemasks(writemask, (1u << component_count) - 1);
|
||||
ret.allocated = true;
|
||||
return ret;
|
||||
@ -2864,6 +2867,7 @@ static struct hlsl_reg allocate_range(struct hlsl_ctx *ctx, struct register_allo
|
||||
record_allocation(ctx, allocator, reg_idx + i, VKD3DSP_WRITEMASK_ALL, first_write, last_read);
|
||||
|
||||
ret.id = reg_idx;
|
||||
ret.bind_count = align(reg_size, 4) / 4;
|
||||
ret.allocated = true;
|
||||
return ret;
|
||||
}
|
||||
@ -3183,6 +3187,7 @@ static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var
|
||||
{
|
||||
var->regs[HLSL_REGSET_NUMERIC].allocated = true;
|
||||
var->regs[HLSL_REGSET_NUMERIC].id = (*counter)++;
|
||||
var->regs[HLSL_REGSET_NUMERIC].bind_count = 1;
|
||||
var->regs[HLSL_REGSET_NUMERIC].writemask = (1 << var->data_type->dimx) - 1;
|
||||
TRACE("Allocated %s to %s.\n", var->name, debug_register(output ? 'o' : 'v',
|
||||
var->regs[HLSL_REGSET_NUMERIC], var->data_type));
|
||||
@ -3361,6 +3366,7 @@ static void allocate_buffers(struct hlsl_ctx *ctx)
|
||||
}
|
||||
|
||||
buffer->reg.id = buffer->reservation.reg_index;
|
||||
buffer->reg.bind_count = 1;
|
||||
buffer->reg.allocated = true;
|
||||
TRACE("Allocated reserved %s to cb%u.\n", buffer->name, index);
|
||||
}
|
||||
@ -3370,6 +3376,7 @@ static void allocate_buffers(struct hlsl_ctx *ctx)
|
||||
++index;
|
||||
|
||||
buffer->reg.id = index;
|
||||
buffer->reg.bind_count = 1;
|
||||
buffer->reg.allocated = true;
|
||||
TRACE("Allocated %s to cb%u.\n", buffer->name, index);
|
||||
++index;
|
||||
@ -3391,13 +3398,17 @@ static const struct hlsl_ir_var *get_allocated_object(struct hlsl_ctx *ctx, enum
|
||||
uint32_t index)
|
||||
{
|
||||
const struct hlsl_ir_var *var;
|
||||
unsigned int start, count;
|
||||
|
||||
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, const struct hlsl_ir_var, extern_entry)
|
||||
{
|
||||
if (!var->regs[regset].allocated)
|
||||
continue;
|
||||
|
||||
if (index == var->regs[regset].id)
|
||||
start = var->regs[regset].id;
|
||||
count = var->regs[regset].bind_count;
|
||||
|
||||
if (start <= index && index < start + count)
|
||||
return var;
|
||||
}
|
||||
return NULL;
|
||||
@ -3408,7 +3419,6 @@ static void allocate_objects(struct hlsl_ctx *ctx, enum hlsl_regset regset)
|
||||
char regset_name = get_regset_name(regset);
|
||||
struct hlsl_ir_var *var;
|
||||
uint32_t min_index = 0;
|
||||
uint32_t index;
|
||||
|
||||
if (regset == HLSL_REGSET_UAVS)
|
||||
{
|
||||
@ -3420,19 +3430,17 @@ static void allocate_objects(struct hlsl_ctx *ctx, enum hlsl_regset regset)
|
||||
}
|
||||
}
|
||||
|
||||
index = min_index;
|
||||
|
||||
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
|
||||
{
|
||||
if (!var->last_read || !var->data_type->reg_size[regset])
|
||||
unsigned int count = var->regs[regset].bind_count;
|
||||
|
||||
if (count == 0)
|
||||
continue;
|
||||
|
||||
if (var->regs[regset].allocated)
|
||||
{
|
||||
const struct hlsl_ir_var *reserved_object;
|
||||
unsigned int index = var->regs[regset].id;
|
||||
|
||||
reserved_object = get_allocated_object(ctx, regset, index);
|
||||
const struct hlsl_ir_var *reserved_object, *last_reported = NULL;
|
||||
unsigned int index, i;
|
||||
|
||||
if (var->regs[regset].id < min_index)
|
||||
{
|
||||
@ -3440,28 +3448,44 @@ static void allocate_objects(struct hlsl_ctx *ctx, enum hlsl_regset regset)
|
||||
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_OVERLAPPING_RESERVATIONS,
|
||||
"UAV index (%u) must be higher than the maximum render target index (%u).",
|
||||
var->regs[regset].id, min_index - 1);
|
||||
}
|
||||
else if (reserved_object && reserved_object != var)
|
||||
{
|
||||
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_OVERLAPPING_RESERVATIONS,
|
||||
"Multiple objects bound to %c%u.", regset_name, index);
|
||||
hlsl_note(ctx, &reserved_object->loc, VKD3D_SHADER_LOG_ERROR,
|
||||
"Object '%s' is already bound to %c%u.", reserved_object->name,
|
||||
regset_name, index);
|
||||
continue;
|
||||
}
|
||||
|
||||
var->regs[regset].id = var->reg_reservation.reg_index;
|
||||
var->regs[regset].allocated = true;
|
||||
TRACE("Allocated reserved %s to %c%u.\n", var->name, regset_name, var->regs[regset].id);
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
index = var->regs[regset].id + i;
|
||||
|
||||
reserved_object = get_allocated_object(ctx, regset, index);
|
||||
if (reserved_object && reserved_object != var && reserved_object != last_reported)
|
||||
{
|
||||
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_OVERLAPPING_RESERVATIONS,
|
||||
"Multiple variables bound to %c%u.", regset_name, index);
|
||||
hlsl_note(ctx, &reserved_object->loc, VKD3D_SHADER_LOG_ERROR,
|
||||
"Variable '%s' is already bound to %c%u.", reserved_object->name,
|
||||
regset_name, index);
|
||||
last_reported = reserved_object;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (get_allocated_object(ctx, regset, index))
|
||||
unsigned int index = min_index;
|
||||
unsigned int available = 0;
|
||||
|
||||
while (available < count)
|
||||
{
|
||||
if (get_allocated_object(ctx, regset, index))
|
||||
available = 0;
|
||||
else
|
||||
++available;
|
||||
++index;
|
||||
}
|
||||
index -= count;
|
||||
|
||||
var->regs[regset].id = index;
|
||||
var->regs[regset].allocated = true;
|
||||
TRACE("Allocated object to %c%u.\n", regset_name, index);
|
||||
TRACE("Allocated variable %s to %c%u-%c%u.\n", var->name, regset_name, index, regset_name,
|
||||
index + count);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
@ -3787,6 +3811,19 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry
|
||||
rb_for_each_entry(&ctx->functions, dump_function, ctx);
|
||||
|
||||
allocate_register_reservations(ctx);
|
||||
|
||||
/* For now, request all the registers for each variable, as long as it is used. */
|
||||
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
|
||||
{
|
||||
unsigned int k;
|
||||
|
||||
for (k = 0; k <= HLSL_REGSET_LAST_OBJECT; ++k)
|
||||
{
|
||||
if (!var->regs[k].allocated)
|
||||
var->regs[k].bind_count = var->last_read ? var->data_type->reg_size[k] : 0;
|
||||
}
|
||||
}
|
||||
|
||||
allocate_temp_registers(ctx, entry_func);
|
||||
if (profile->major_version < 4)
|
||||
{
|
||||
|
@ -2595,6 +2595,9 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b
|
||||
|
||||
static D3D_SHADER_INPUT_TYPE sm4_resource_type(const struct hlsl_type *type)
|
||||
{
|
||||
if (type->class == HLSL_CLASS_ARRAY)
|
||||
return sm4_resource_type(type->e.array.type);
|
||||
|
||||
switch (type->base_type)
|
||||
{
|
||||
case HLSL_TYPE_SAMPLER:
|
||||
@ -2610,6 +2613,9 @@ static D3D_SHADER_INPUT_TYPE sm4_resource_type(const struct hlsl_type *type)
|
||||
|
||||
static D3D_RESOURCE_RETURN_TYPE sm4_resource_format(const struct hlsl_type *type)
|
||||
{
|
||||
if (type->class == HLSL_CLASS_ARRAY)
|
||||
return sm4_resource_format(type->e.array.type);
|
||||
|
||||
switch (type->e.resource_format->base_type)
|
||||
{
|
||||
case HLSL_TYPE_DOUBLE:
|
||||
@ -2634,6 +2640,9 @@ static D3D_RESOURCE_RETURN_TYPE sm4_resource_format(const struct hlsl_type *type
|
||||
|
||||
static D3D_SRV_DIMENSION sm4_rdef_resource_dimension(const struct hlsl_type *type)
|
||||
{
|
||||
if (type->class == HLSL_CLASS_ARRAY)
|
||||
return sm4_rdef_resource_dimension(type->e.array.type);
|
||||
|
||||
switch (type->sampler_dim)
|
||||
{
|
||||
case HLSL_SAMPLER_DIM_1D:
|
||||
@ -3037,7 +3046,9 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r
|
||||
|
||||
if (var->is_uniform)
|
||||
{
|
||||
if (data_type->class == HLSL_CLASS_OBJECT && data_type->base_type == HLSL_TYPE_TEXTURE)
|
||||
enum hlsl_regset regset = hlsl_type_get_regset(data_type);
|
||||
|
||||
if (regset == HLSL_REGSET_TEXTURES)
|
||||
{
|
||||
reg->type = VKD3D_SM4_RT_RESOURCE;
|
||||
reg->dim = VKD3D_SM4_DIMENSION_VEC4;
|
||||
@ -3047,7 +3058,7 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r
|
||||
reg->idx_count = 1;
|
||||
*writemask = VKD3DSP_WRITEMASK_ALL;
|
||||
}
|
||||
else if (data_type->class == HLSL_CLASS_OBJECT && data_type->base_type == HLSL_TYPE_UAV)
|
||||
else if (regset == HLSL_REGSET_UAVS)
|
||||
{
|
||||
reg->type = VKD3D_SM5_RT_UAV;
|
||||
reg->dim = VKD3D_SM4_DIMENSION_VEC4;
|
||||
@ -3057,7 +3068,7 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r
|
||||
reg->idx_count = 1;
|
||||
*writemask = VKD3DSP_WRITEMASK_ALL;
|
||||
}
|
||||
else if (data_type->class == HLSL_CLASS_OBJECT && data_type->base_type == HLSL_TYPE_SAMPLER)
|
||||
else if (regset == HLSL_REGSET_SAMPLERS)
|
||||
{
|
||||
reg->type = VKD3D_SM4_RT_SAMPLER;
|
||||
reg->dim = VKD3D_SM4_DIMENSION_NONE;
|
||||
|
@ -80,4 +80,4 @@ float4 main() : sv_target
|
||||
|
||||
[test]
|
||||
draw quad
|
||||
todo probe all rgba (4.0, 4.0, 4.0, 99.0)
|
||||
probe all rgba (4.0, 4.0, 4.0, 99.0)
|
||||
|
Loading…
Reference in New Issue
Block a user