vkd3d-shader/dxil: Read the value symbol table.

This commit is contained in:
Conor McCarthy 2023-07-10 13:46:45 +10:00 committed by Alexandre Julliard
parent 571d807dd8
commit eca4b62c7e
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 119 additions and 5 deletions

View File

@ -89,6 +89,12 @@ enum bitcode_type_code
TYPE_CODE_FUNCTION = 21,
};
enum bitcode_value_symtab_code
{
VST_CODE_ENTRY = 1,
VST_CODE_BBENTRY = 2,
};
struct sm6_pointer_info
{
const struct sm6_type *type;
@ -149,6 +155,12 @@ struct dxil_record
uint64_t operands[];
};
struct sm6_symbol
{
unsigned int id;
const char *name;
};
struct dxil_block
{
const struct dxil_block *parent;
@ -189,6 +201,9 @@ struct sm6_parser
struct sm6_type *types;
size_t type_count;
struct sm6_symbol *global_symbols;
size_t global_symbol_count;
struct vkd3d_shader_parser p;
};
@ -818,16 +833,17 @@ static const struct dxil_block *sm6_parser_get_level_one_block(const struct sm6_
return found;
}
static char *dxil_record_to_string(const struct dxil_record *record)
static char *dxil_record_to_string(const struct dxil_record *record, unsigned int offset)
{
unsigned int i;
char *str;
if (!(str = vkd3d_calloc(record->operand_count + 1, 1)))
assert(offset <= record->operand_count);
if (!(str = vkd3d_calloc(record->operand_count - offset + 1, 1)))
return NULL;
for (i = 0; i < record->operand_count; ++i)
str[i] = record->operands[i];
for (i = offset; i < record->operand_count; ++i)
str[i - offset] = record->operands[i];
return str;
}
@ -1079,7 +1095,7 @@ static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6)
break;
case TYPE_CODE_STRUCT_NAME:
if (!(struct_name = dxil_record_to_string(record)))
if (!(struct_name = dxil_record_to_string(record, 0)))
{
ERR("Failed to allocate struct name.\n");
return VKD3D_ERROR_OUT_OF_MEMORY;
@ -1111,6 +1127,80 @@ static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6)
return VKD3D_OK;
}
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);
}
static enum vkd3d_result sm6_parser_symtab_init(struct sm6_parser *sm6)
{
const struct dxil_record *record;
const struct dxil_block *block;
struct sm6_symbol *symbol;
size_t i, count;
bool is_unique;
sm6->p.location.line = 0;
sm6->p.location.column = 0;
if (!(block = sm6_parser_get_level_one_block(sm6, VALUE_SYMTAB_BLOCK, &is_unique)))
{
/* There should always be at least one symbol: the name of the entry point function. */
WARN("No value symtab block found.\n");
return VKD3D_ERROR_INVALID_SHADER;
}
if (!is_unique)
FIXME("Ignoring extra value symtab block(s).\n");
sm6->p.location.line = block->id;
for (i = 0, count = 0; i < block->record_count; ++i)
count += block->records[i]->code == VST_CODE_ENTRY;
if (!(sm6->global_symbols = vkd3d_calloc(count, sizeof(*sm6->global_symbols))))
{
ERR("Failed to allocate global symbols.\n");
return VKD3D_ERROR_OUT_OF_MEMORY;
}
for (i = 0; i < block->record_count; ++i)
{
sm6->p.location.column = i;
record = block->records[i];
if (record->code != VST_CODE_ENTRY)
{
FIXME("Unhandled symtab code %u.\n", record->code);
continue;
}
if (!dxil_record_validate_operand_min_count(record, 1, sm6))
continue;
symbol = &sm6->global_symbols[sm6->global_symbol_count];
symbol->id = record->operands[0];
if (!(symbol->name = dxil_record_to_string(record, 1)))
{
ERR("Failed to allocate symbol name.\n");
return VKD3D_ERROR_OUT_OF_MEMORY;
}
++sm6->global_symbol_count;
}
sm6->p.location.column = block->record_count;
qsort(sm6->global_symbols, sm6->global_symbol_count, sizeof(*sm6->global_symbols), global_symbol_compare);
for (i = 1; i < sm6->global_symbol_count; ++i)
{
if (sm6->global_symbols[i].id == sm6->global_symbols[i - 1].id)
{
WARN("Invalid duplicate symbol id %u.\n", sm6->global_symbols[i].id);
return VKD3D_ERROR_INVALID_SHADER;
}
}
return VKD3D_OK;
}
static void sm6_type_table_cleanup(struct sm6_type *types, size_t count)
{
size_t i;
@ -1137,6 +1227,15 @@ static void sm6_type_table_cleanup(struct sm6_type *types, size_t count)
vkd3d_free(types);
}
static void sm6_symtab_cleanup(struct sm6_symbol *symbols, size_t count)
{
size_t i;
for (i = 0; i < count; ++i)
vkd3d_free((void *)symbols[i].name);
vkd3d_free(symbols);
}
static void sm6_parser_destroy(struct vkd3d_shader_parser *parser)
{
struct sm6_parser *sm6 = sm6_parser(parser);
@ -1145,6 +1244,7 @@ static void sm6_parser_destroy(struct vkd3d_shader_parser *parser)
dxil_global_abbrevs_cleanup(sm6->abbrevs, sm6->abbrev_count);
shader_instruction_array_destroy(&parser->instructions);
sm6_type_table_cleanup(sm6->types, sm6->type_count);
sm6_symtab_cleanup(sm6->global_symbols, sm6->global_symbol_count);
free_shader_desc(&parser->shader_desc);
vkd3d_free(sm6);
}
@ -1298,6 +1398,19 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
return ret;
}
if ((ret = sm6_parser_symtab_init(sm6)) < 0)
{
if (ret == VKD3D_ERROR_OUT_OF_MEMORY)
vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
"Out of memory parsing DXIL value symbol table.");
else if (ret == VKD3D_ERROR_INVALID_SHADER)
vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_VALUE_SYMTAB,
"DXIL value symbol table is invalid.");
else
vkd3d_unreachable();
return ret;
}
dxil_block_destroy(&sm6->root_block);
return VKD3D_OK;

View File

@ -157,6 +157,7 @@ enum vkd3d_shader_error
VKD3D_SHADER_ERROR_DXIL_INVALID_BITCODE = 8004,
VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT = 8005,
VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_TABLE = 8006,
VKD3D_SHADER_ERROR_DXIL_INVALID_VALUE_SYMTAB = 8007,
VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER = 8300,
VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE = 8301,