vkd3d-shader/dxil: Read global function declarations.

This commit is contained in:
Conor McCarthy 2023-05-15 12:45:09 +10:00 committed by Alexandre Julliard
parent 22157c3da3
commit c96143abdc
Notes: Alexandre Julliard 2023-07-11 23:13:49 +02: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/259
2 changed files with 233 additions and 1 deletions

View File

@ -155,6 +155,28 @@ struct sm6_type
} u; } u;
}; };
enum sm6_value_type
{
VALUE_TYPE_FUNCTION,
};
struct sm6_function_data
{
const char *name;
bool is_prototype;
unsigned int attribs_id;
};
struct sm6_value
{
const struct sm6_type *type;
enum sm6_value_type value_type;
union
{
struct sm6_function_data function;
} u;
};
struct dxil_record struct dxil_record
{ {
unsigned int code; unsigned int code;
@ -211,6 +233,10 @@ struct sm6_parser
struct sm6_symbol *global_symbols; struct sm6_symbol *global_symbols;
size_t global_symbol_count; size_t global_symbol_count;
struct sm6_value *values;
size_t value_count;
size_t value_capacity;
struct vkd3d_shader_parser p; struct vkd3d_shader_parser p;
}; };
@ -810,6 +836,15 @@ static enum vkd3d_result dxil_block_init(struct dxil_block *block, const struct
return ret; return ret;
} }
static size_t dxil_block_compute_module_decl_count(const struct dxil_block *block)
{
size_t i, count;
for (i = 0, count = 0; i < block->record_count; ++i)
count += block->records[i]->code == MODULE_CODE_FUNCTION;
return count;
}
static void dxil_global_abbrevs_cleanup(struct dxil_global_abbrev **abbrevs, size_t count) static void dxil_global_abbrevs_cleanup(struct dxil_global_abbrev **abbrevs, size_t count)
{ {
size_t i; size_t i;
@ -1134,6 +1169,88 @@ static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6)
return VKD3D_OK; return VKD3D_OK;
} }
static inline bool sm6_type_is_void(const struct sm6_type *type)
{
return type->class == TYPE_CLASS_VOID;
}
static inline bool sm6_type_is_numeric(const struct sm6_type *type)
{
return type->class == TYPE_CLASS_INTEGER || type->class == TYPE_CLASS_FLOAT;
}
static inline bool sm6_type_is_pointer(const struct sm6_type *type)
{
return type->class == TYPE_CLASS_POINTER;
}
static bool sm6_type_is_numeric_aggregate(const struct sm6_type *type)
{
unsigned int i;
switch (type->class)
{
case TYPE_CLASS_ARRAY:
case TYPE_CLASS_VECTOR:
return sm6_type_is_numeric(type->u.array.elem_type);
case TYPE_CLASS_STRUCT:
/* Do not handle nested structs. Support can be added if they show up. */
for (i = 0; i < type->u.struc->elem_count; ++i)
if (!sm6_type_is_numeric(type->u.struc->elem_types[i]))
return false;
return true;
default:
return false;
}
}
static inline bool sm6_type_is_struct(const struct sm6_type *type)
{
return type->class == TYPE_CLASS_STRUCT;
}
static inline bool sm6_type_is_function(const struct sm6_type *type)
{
return type->class == TYPE_CLASS_FUNCTION;
}
static inline bool sm6_type_is_handle(const struct sm6_type *type)
{
return sm6_type_is_struct(type) && !strcmp(type->u.struc->name, "dx.types.Handle");
}
static const struct sm6_type *sm6_type_get_pointer_to_type(const struct sm6_type *type,
enum bitcode_address_space addr_space, struct sm6_parser *sm6)
{
size_t i, start = type - sm6->types;
const struct sm6_type *pointer_type;
/* DXC seems usually to place the pointer type immediately after its pointee. */
for (i = (start + 1) % sm6->type_count; i != start; i = (i + 1) % sm6->type_count)
{
pointer_type = &sm6->types[i];
if (sm6_type_is_pointer(pointer_type) && pointer_type->u.pointer.type == type
&& pointer_type->u.pointer.addr_space == addr_space)
return pointer_type;
}
return NULL;
}
static const struct sm6_type *sm6_parser_get_type(struct sm6_parser *sm6, uint64_t type_id)
{
if (type_id >= sm6->type_count)
{
WARN("Invalid type index %"PRIu64" at %zu.\n", type_id, sm6->value_count);
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_ID,
"DXIL type id %"PRIu64" is invalid.", type_id);
return NULL;
}
return &sm6->types[type_id];
}
static int global_symbol_compare(const void *a, const void *b) static int global_symbol_compare(const void *a, const void *b)
{ {
return vkd3d_u32_compare(((const struct sm6_symbol *)a)->id, ((const struct sm6_symbol *)b)->id); return vkd3d_u32_compare(((const struct sm6_symbol *)a)->id, ((const struct sm6_symbol *)b)->id);
@ -1208,6 +1325,104 @@ static enum vkd3d_result sm6_parser_symtab_init(struct sm6_parser *sm6)
return VKD3D_OK; return VKD3D_OK;
} }
static const char *sm6_parser_get_global_symbol_name(const struct sm6_parser *sm6, size_t id)
{
size_t i, start;
/* id == array index is normally true */
i = start = id % sm6->global_symbol_count;
do
{
if (sm6->global_symbols[i].id == id)
return sm6->global_symbols[i].name;
i = (i + 1) % sm6->global_symbol_count;
} while (i != start);
return NULL;
}
static inline bool sm6_value_is_dx_intrinsic_dcl(const struct sm6_value *fn)
{
assert(fn->value_type == VALUE_TYPE_FUNCTION);
return fn->u.function.is_prototype && !strncmp(fn->u.function.name, "dx.op.", 6);
}
static inline struct sm6_value *sm6_parser_get_current_value(const struct sm6_parser *sm6)
{
assert(sm6->value_count < sm6->value_capacity);
return &sm6->values[sm6->value_count];
}
static void sm6_parser_compute_max_value_count(struct sm6_parser *sm6,
const struct dxil_block *block)
{
sm6->value_capacity = dxil_block_compute_module_decl_count(block);
}
static bool sm6_parser_declare_function(struct sm6_parser *sm6, const struct dxil_record *record)
{
const unsigned int max_count = 15;
const struct sm6_type *ret_type;
struct sm6_value *fn;
unsigned int i, j;
if (!dxil_record_validate_operand_count(record, 8, max_count, sm6))
return false;
fn = sm6_parser_get_current_value(sm6);
fn->value_type = VALUE_TYPE_FUNCTION;
if (!(fn->u.function.name = sm6_parser_get_global_symbol_name(sm6, sm6->value_count)))
{
WARN("Missing symbol name for function %zu.\n", sm6->value_count);
fn->u.function.name = "";
}
if (!(fn->type = sm6_parser_get_type(sm6, record->operands[0])))
return false;
if (!sm6_type_is_function(fn->type))
{
WARN("Type is not a function.\n");
return false;
}
ret_type = fn->type->u.function->ret_type;
if (!(fn->type = sm6_type_get_pointer_to_type(fn->type, ADDRESS_SPACE_DEFAULT, sm6)))
{
WARN("Failed to get pointer type for type %u.\n", fn->type->class);
return false;
}
if (record->operands[1])
WARN("Ignoring calling convention %#"PRIx64".\n", record->operands[1]);
fn->u.function.is_prototype = !!record->operands[2];
if (record->operands[3])
WARN("Ignoring linkage %#"PRIx64".\n", record->operands[3]);
if (record->operands[4] > UINT_MAX)
WARN("Invalid attributes id %#"PRIx64".\n", record->operands[4]);
/* 1-based index. */
if ((fn->u.function.attribs_id = record->operands[4]))
TRACE("Ignoring function attributes.\n");
/* These always seem to be zero. */
for (i = 5, j = 0; i < min(record->operand_count, max_count); ++i)
j += !!record->operands[i];
if (j)
WARN("Ignoring %u operands.\n", j);
if (sm6_value_is_dx_intrinsic_dcl(fn) && !sm6_type_is_void(ret_type) && !sm6_type_is_numeric(ret_type)
&& !sm6_type_is_numeric_aggregate(ret_type) && !sm6_type_is_handle(ret_type))
{
WARN("Unexpected return type for dx intrinsic function '%s'.\n", fn->u.function.name);
}
++sm6->value_count;
return true;
}
static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6)
{ {
const struct dxil_block *block = &sm6->root_block; const struct dxil_block *block = &sm6->root_block;
@ -1225,7 +1440,12 @@ static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6)
switch (record->code) switch (record->code)
{ {
case MODULE_CODE_FUNCTION: case MODULE_CODE_FUNCTION:
FIXME("Functions are not implemented yet.\n"); if (!sm6_parser_declare_function(sm6, record))
{
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_FUNCTION_DCL,
"A DXIL function declaration is invalid.");
return VKD3D_ERROR_INVALID_SHADER;
}
break; break;
case MODULE_CODE_GLOBALVAR: case MODULE_CODE_GLOBALVAR:
@ -1295,6 +1515,7 @@ static void sm6_parser_destroy(struct vkd3d_shader_parser *parser)
shader_instruction_array_destroy(&parser->instructions); shader_instruction_array_destroy(&parser->instructions);
sm6_type_table_cleanup(sm6->types, sm6->type_count); sm6_type_table_cleanup(sm6->types, sm6->type_count);
sm6_symtab_cleanup(sm6->global_symbols, sm6->global_symbol_count); sm6_symtab_cleanup(sm6->global_symbols, sm6->global_symbol_count);
vkd3d_free(sm6->values);
free_shader_desc(&parser->shader_desc); free_shader_desc(&parser->shader_desc);
vkd3d_free(sm6); vkd3d_free(sm6);
} }
@ -1461,6 +1682,15 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
return ret; return ret;
} }
sm6_parser_compute_max_value_count(sm6, &sm6->root_block);
if (!(sm6->values = vkd3d_calloc(sm6->value_capacity, sizeof(*sm6->values))))
{
ERR("Failed to allocate value array.\n");
vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
"Out of memory allocating DXIL value array.");
return VKD3D_ERROR_OUT_OF_MEMORY;
}
if ((ret = sm6_parser_globals_init(sm6)) < 0) if ((ret = sm6_parser_globals_init(sm6)) < 0)
{ {
WARN("Failed to load global declarations.\n"); WARN("Failed to load global declarations.\n");

View File

@ -159,6 +159,8 @@ enum vkd3d_shader_error
VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_TABLE = 8006, VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_TABLE = 8006,
VKD3D_SHADER_ERROR_DXIL_INVALID_VALUE_SYMTAB = 8007, VKD3D_SHADER_ERROR_DXIL_INVALID_VALUE_SYMTAB = 8007,
VKD3D_SHADER_ERROR_DXIL_UNSUPPORTED_BITCODE_FORMAT = 8008, VKD3D_SHADER_ERROR_DXIL_UNSUPPORTED_BITCODE_FORMAT = 8008,
VKD3D_SHADER_ERROR_DXIL_INVALID_FUNCTION_DCL = 8009,
VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_ID = 8010,
VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER = 8300, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER = 8300,
VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE = 8301, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE = 8301,