vkd3d-shader/dxil: Implement DX instruction CreateHandle.

This commit is contained in:
Conor McCarthy 2023-10-16 11:47:11 +10:00 committed by Alexandre Julliard
parent f57d65361a
commit 3b1bbe2b0a
Notes: Alexandre Julliard 2023-11-01 22:39:52 +01:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/408
2 changed files with 140 additions and 14 deletions

View File

@ -246,6 +246,7 @@ enum dx_intrinsic_opcode
{ {
DX_LOAD_INPUT = 4, DX_LOAD_INPUT = 4,
DX_STORE_OUTPUT = 5, DX_STORE_OUTPUT = 5,
DX_CREATE_HANDLE = 57,
}; };
struct sm6_pointer_info struct sm6_pointer_info
@ -305,6 +306,7 @@ enum sm6_value_type
{ {
VALUE_TYPE_FUNCTION, VALUE_TYPE_FUNCTION,
VALUE_TYPE_REG, VALUE_TYPE_REG,
VALUE_TYPE_HANDLE,
}; };
struct sm6_function_data struct sm6_function_data
@ -314,6 +316,12 @@ struct sm6_function_data
unsigned int attribs_id; unsigned int attribs_id;
}; };
struct sm6_handle_data
{
const struct sm6_descriptor_info *d;
struct vkd3d_shader_register reg;
};
struct sm6_value struct sm6_value
{ {
const struct sm6_type *type; const struct sm6_type *type;
@ -323,6 +331,7 @@ struct sm6_value
{ {
struct sm6_function_data function; struct sm6_function_data function;
struct vkd3d_shader_register reg; struct vkd3d_shader_register reg;
struct sm6_handle_data handle;
} u; } u;
}; };
@ -427,6 +436,13 @@ struct sm6_named_metadata
struct sm6_metadata_value value; struct sm6_metadata_value value;
}; };
struct sm6_descriptor_info
{
enum vkd3d_shader_descriptor_type type;
unsigned int id;
struct vkd3d_shader_register_range range;
};
struct sm6_parser struct sm6_parser
{ {
const uint32_t *ptr, *start, *end; const uint32_t *ptr, *start, *end;
@ -442,6 +458,7 @@ struct sm6_parser
struct sm6_type *types; struct sm6_type *types;
size_t type_count; size_t type_count;
struct sm6_type *metadata_type; struct sm6_type *metadata_type;
struct sm6_type *handle_type;
struct sm6_symbol *global_symbols; struct sm6_symbol *global_symbols;
size_t global_symbol_count; size_t global_symbol_count;
@ -458,6 +475,10 @@ struct sm6_parser
struct sm6_named_metadata *named_metadata; struct sm6_named_metadata *named_metadata;
unsigned int named_metadata_count; unsigned int named_metadata_count;
struct sm6_descriptor_info *descriptors;
size_t descriptor_capacity;
size_t descriptor_count;
struct sm6_value *values; struct sm6_value *values;
size_t value_count; size_t value_count;
size_t value_capacity; size_t value_capacity;
@ -1391,6 +1412,9 @@ static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6)
break; break;
} }
if (!ascii_strcasecmp(struct_name, "dx.types.Handle"))
sm6->handle_type = type;
type->u.struc->name = struct_name; type->u.struc->name = struct_name;
struct_name = NULL; struct_name = NULL;
break; break;
@ -1438,6 +1462,11 @@ static inline bool sm6_type_is_integer(const struct sm6_type *type)
return type->class == TYPE_CLASS_INTEGER; return type->class == TYPE_CLASS_INTEGER;
} }
static bool sm6_type_is_bool(const struct sm6_type *type)
{
return type->class == TYPE_CLASS_INTEGER && type->u.width == 1;
}
static inline bool sm6_type_is_i8(const struct sm6_type *type) static inline bool sm6_type_is_i8(const struct sm6_type *type)
{ {
return type->class == TYPE_CLASS_INTEGER && type->u.width == 8; return type->class == TYPE_CLASS_INTEGER && type->u.width == 8;
@ -1710,6 +1739,11 @@ static inline bool sm6_value_is_register(const struct sm6_value *value)
return value->value_type == VALUE_TYPE_REG; return value->value_type == VALUE_TYPE_REG;
} }
static bool sm6_value_is_handle(const struct sm6_value *value)
{
return value->value_type == VALUE_TYPE_HANDLE;
}
static inline bool sm6_value_is_constant(const struct sm6_value *value) static inline bool sm6_value_is_constant(const struct sm6_value *value)
{ {
return sm6_value_is_register(value) && register_is_constant(&value->u.reg); return sm6_value_is_register(value) && register_is_constant(&value->u.reg);
@ -1782,6 +1816,8 @@ static enum vkd3d_data_type vkd3d_data_type_from_sm6_type(const struct sm6_type
{ {
switch (type->u.width) switch (type->u.width)
{ {
case 1:
return VKD3D_DATA_BOOL;
case 8: case 8:
return VKD3D_DATA_UINT8; return VKD3D_DATA_UINT8;
case 32: case 32:
@ -2518,6 +2554,66 @@ static struct sm6_block *sm6_block_create()
return block; return block;
} }
static const struct sm6_descriptor_info *sm6_parser_get_descriptor(struct sm6_parser *sm6,
enum vkd3d_shader_descriptor_type type, unsigned int id, const struct sm6_value *address)
{
const struct sm6_descriptor_info *d;
unsigned int register_index;
size_t i;
for (i = 0; i < sm6->descriptor_count; ++i)
{
d = &sm6->descriptors[i];
if (d->type != type || d->id != id)
continue;
if (!sm6_value_is_constant(address))
return d;
register_index = sm6_value_get_constant_uint(address);
if (register_index >= d->range.first && register_index <= d->range.last)
return d;
}
return NULL;
}
static void sm6_parser_emit_dx_create_handle(struct sm6_parser *sm6, struct sm6_block *code_block,
enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins)
{
enum vkd3d_shader_descriptor_type type;
const struct sm6_descriptor_info *d;
struct vkd3d_shader_register *reg;
struct sm6_value *dst;
unsigned int id;
type = sm6_value_get_constant_uint(operands[0]);
id = sm6_value_get_constant_uint(operands[1]);
if (!(d = sm6_parser_get_descriptor(sm6, type, id, operands[2])))
{
WARN("Failed to find resource type %#x, id %#x.\n", type, id);
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
"Descriptor for resource type %#x, id %#x was not found.", type, id);
return;
}
dst = sm6_parser_get_current_value(sm6);
dst->value_type = VALUE_TYPE_HANDLE;
dst->u.handle.d = d;
reg = &dst->u.handle.reg;
/* Set idx_count to 3 for use with load instructions.
* TODO: set register type from resource type when other types are supported. */
vsir_register_init(reg, VKD3DSPR_CONSTBUFFER, VKD3D_DATA_FLOAT, 3);
reg->idx[0].offset = id;
register_index_address_init(&reg->idx[1], operands[2], sm6);
reg->non_uniform = !!sm6_value_get_constant_uint(operands[3]);
/* NOP is used to flag no instruction emitted. */
ins->handler_idx = VKD3DSIH_NOP;
}
static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, struct sm6_block *code_block, static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, struct sm6_block *code_block,
enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins) enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins)
{ {
@ -2613,18 +2709,28 @@ struct sm6_dx_opcode_info
/* /*
8 -> int8 8 -> int8
b -> constant int1
c -> constant int8/16/32
i -> int32 i -> int32
H -> handle
v -> void v -> void
o -> overloaded o -> overloaded
*/ */
static const struct sm6_dx_opcode_info sm6_dx_op_table[] = static const struct sm6_dx_opcode_info sm6_dx_op_table[] =
{ {
[DX_CREATE_HANDLE ] = {'H', "ccib", sm6_parser_emit_dx_create_handle},
[DX_LOAD_INPUT ] = {'o', "ii8i", sm6_parser_emit_dx_load_input}, [DX_LOAD_INPUT ] = {'o', "ii8i", sm6_parser_emit_dx_load_input},
[DX_STORE_OUTPUT ] = {'v', "ii8o", sm6_parser_emit_dx_store_output}, [DX_STORE_OUTPUT ] = {'v', "ii8o", sm6_parser_emit_dx_store_output},
}; };
static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struct sm6_type *type, char info_type) static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struct sm6_value *value, char info_type,
bool is_return)
{ {
const struct sm6_type *type = value->type;
if (info_type != 'H' && !sm6_value_is_register(value))
return false;
switch (info_type) switch (info_type)
{ {
case 0: case 0:
@ -2632,8 +2738,15 @@ static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struc
return false; return false;
case '8': case '8':
return sm6_type_is_i8(type); return sm6_type_is_i8(type);
case 'b':
return sm6_value_is_constant(value) && sm6_type_is_bool(type);
case 'c':
return sm6_value_is_constant(value) && sm6_type_is_integer(type) && type->u.width >= 8
&& type->u.width <= 32;
case 'i': case 'i':
return sm6_type_is_i32(type); return sm6_type_is_i32(type);
case 'H':
return (is_return || sm6_value_is_handle(value)) && type == sm6->handle_type;
case 'v': case 'v':
return !type; return !type;
case 'o': case 'o':
@ -2653,7 +2766,7 @@ static bool sm6_parser_validate_dx_op(struct sm6_parser *sm6, enum dx_intrinsic_
info = &sm6_dx_op_table[op]; info = &sm6_dx_op_table[op];
if (!sm6_parser_validate_operand_type(sm6, dst->type, info->ret_type)) if (!sm6_parser_validate_operand_type(sm6, dst, info->ret_type, true))
{ {
WARN("Failed to validate return type for dx intrinsic id %u, '%s'.\n", op, name); WARN("Failed to validate return type for dx intrinsic id %u, '%s'.\n", op, name);
/* Return type validation failure is not so critical. We only need to set /* Return type validation failure is not so critical. We only need to set
@ -2663,7 +2776,7 @@ static bool sm6_parser_validate_dx_op(struct sm6_parser *sm6, enum dx_intrinsic_
for (i = 0; i < operand_count; ++i) for (i = 0; i < operand_count; ++i)
{ {
const struct sm6_value *value = operands[i]; const struct sm6_value *value = operands[i];
if (!sm6_value_is_register(value) || !sm6_parser_validate_operand_type(sm6, value->type, info->operand_info[i])) if (!sm6_parser_validate_operand_type(sm6, value, info->operand_info[i], false))
{ {
WARN("Failed to validate operand %u for dx intrinsic id %u, '%s'.\n", i + 1, op, name); WARN("Failed to validate operand %u for dx intrinsic id %u, '%s'.\n", i + 1, op, name);
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
@ -3422,8 +3535,7 @@ static bool sm6_parser_resources_load_register_range(struct sm6_parser *sm6,
} }
static enum vkd3d_result sm6_parser_resources_load_cbv(struct sm6_parser *sm6, static enum vkd3d_result sm6_parser_resources_load_cbv(struct sm6_parser *sm6,
const struct sm6_metadata_node *node, const struct vkd3d_shader_register_range *range, const struct sm6_metadata_node *node, struct sm6_descriptor_info *d, struct vkd3d_shader_instruction *ins)
unsigned int register_id, struct vkd3d_shader_instruction *ins)
{ {
struct vkd3d_shader_register *reg; struct vkd3d_shader_register *reg;
unsigned int buffer_size; unsigned int buffer_size;
@ -3458,11 +3570,11 @@ static enum vkd3d_result sm6_parser_resources_load_cbv(struct sm6_parser *sm6,
reg = &ins->declaration.cb.src.reg; reg = &ins->declaration.cb.src.reg;
vsir_register_init(reg, VKD3DSPR_CONSTBUFFER, VKD3D_DATA_FLOAT, 3); vsir_register_init(reg, VKD3DSPR_CONSTBUFFER, VKD3D_DATA_FLOAT, 3);
reg->idx[0].offset = register_id; reg->idx[0].offset = d->id;
reg->idx[1].offset = range->first; reg->idx[1].offset = d->range.first;
reg->idx[2].offset = range->last; reg->idx[2].offset = d->range.last;
ins->declaration.cb.range = *range; ins->declaration.cb.range = d->range;
return VKD3D_OK; return VKD3D_OK;
} }
@ -3470,12 +3582,12 @@ static enum vkd3d_result sm6_parser_resources_load_cbv(struct sm6_parser *sm6,
static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6, static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6,
enum vkd3d_shader_descriptor_type type, const struct sm6_metadata_node *descriptor_node) enum vkd3d_shader_descriptor_type type, const struct sm6_metadata_node *descriptor_node)
{ {
struct vkd3d_shader_register_range range;
struct vkd3d_shader_instruction *ins; struct vkd3d_shader_instruction *ins;
const struct sm6_metadata_node *node; const struct sm6_metadata_node *node;
const struct sm6_metadata_value *m; const struct sm6_metadata_value *m;
unsigned int i, register_id; struct sm6_descriptor_info *d;
enum vkd3d_result ret; enum vkd3d_result ret;
unsigned int i;
for (i = 0; i < descriptor_node->operand_count; ++i) for (i = 0; i < descriptor_node->operand_count; ++i)
{ {
@ -3497,7 +3609,18 @@ static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6,
return VKD3D_ERROR_INVALID_SHADER; return VKD3D_ERROR_INVALID_SHADER;
} }
if (!sm6_metadata_get_uint_value(sm6, node->operands[0], &register_id)) if (!vkd3d_array_reserve((void **)&sm6->descriptors, &sm6->descriptor_capacity,
sm6->descriptor_count + 1, sizeof(*sm6->descriptors)))
{
ERR("Failed to allocate descriptor array.\n");
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
"Out of memory allocating the descriptor array.");
return VKD3D_ERROR_OUT_OF_MEMORY;
}
d = &sm6->descriptors[sm6->descriptor_count];
d->type = type;
if (!sm6_metadata_get_uint_value(sm6, node->operands[0], &d->id))
{ {
WARN("Failed to load resource id.\n"); WARN("Failed to load resource id.\n");
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES,
@ -3505,7 +3628,7 @@ static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6,
return VKD3D_ERROR_INVALID_SHADER; return VKD3D_ERROR_INVALID_SHADER;
} }
if (!sm6_parser_resources_load_register_range(sm6, node, &range)) if (!sm6_parser_resources_load_register_range(sm6, node, &d->range))
{ {
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES,
"Resource register range is invalid."); "Resource register range is invalid.");
@ -3521,7 +3644,7 @@ static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6,
switch (type) switch (type)
{ {
case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV: case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV:
if ((ret = sm6_parser_resources_load_cbv(sm6, node, &range, register_id, ins)) < 0) if ((ret = sm6_parser_resources_load_cbv(sm6, node, d, ins)) < 0)
return ret; return ret;
break; break;
default: default:
@ -3531,6 +3654,7 @@ static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6,
return VKD3D_ERROR_INVALID_SHADER; return VKD3D_ERROR_INVALID_SHADER;
} }
++sm6->descriptor_count;
++sm6->p.instructions.count; ++sm6->p.instructions.count;
} }
@ -4131,6 +4255,7 @@ static void sm6_parser_destroy(struct vkd3d_shader_parser *parser)
sm6_symtab_cleanup(sm6->global_symbols, sm6->global_symbol_count); sm6_symtab_cleanup(sm6->global_symbols, sm6->global_symbol_count);
sm6_functions_cleanup(sm6->functions, sm6->function_count); sm6_functions_cleanup(sm6->functions, sm6->function_count);
sm6_parser_metadata_cleanup(sm6); sm6_parser_metadata_cleanup(sm6);
vkd3d_free(sm6->descriptors);
vkd3d_free(sm6->values); vkd3d_free(sm6->values);
free_shader_desc(&parser->shader_desc); free_shader_desc(&parser->shader_desc);
vkd3d_free(sm6); vkd3d_free(sm6);

View File

@ -575,6 +575,7 @@ enum vkd3d_data_type
VKD3D_DATA_UNUSED, VKD3D_DATA_UNUSED,
VKD3D_DATA_UINT8, VKD3D_DATA_UINT8,
VKD3D_DATA_UINT64, VKD3D_DATA_UINT64,
VKD3D_DATA_BOOL,
}; };
static inline bool data_type_is_integer(enum vkd3d_data_type data_type) static inline bool data_type_is_integer(enum vkd3d_data_type data_type)