mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-01-28 13:05:02 -08:00
vkd3d-shader/dxil: Read DXIL metadata named nodes.
This commit is contained in:
parent
4ac201788d
commit
6034f4a976
Notes:
Alexandre Julliard
2023-10-12 23:35:11 +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/372
@ -333,6 +333,12 @@ struct sm6_metadata_table
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
struct sm6_named_metadata
|
||||
{
|
||||
char *name;
|
||||
struct sm6_metadata_value value;
|
||||
};
|
||||
|
||||
struct sm6_parser
|
||||
{
|
||||
const uint32_t *ptr, *start, *end;
|
||||
@ -359,6 +365,8 @@ struct sm6_parser
|
||||
size_t function_count;
|
||||
|
||||
struct sm6_metadata_table metadata_tables[VKD3D_SM6_MAX_METADATA_TABLES];
|
||||
struct sm6_named_metadata *named_metadata;
|
||||
unsigned int named_metadata_count;
|
||||
|
||||
struct sm6_value *values;
|
||||
size_t value_count;
|
||||
@ -2697,6 +2705,11 @@ static void sm6_parser_emit_ret(struct sm6_parser *sm6, const struct dxil_record
|
||||
ins->handler_idx = VKD3DSIH_NOP;
|
||||
}
|
||||
|
||||
static bool sm6_metadata_value_is_node(const struct sm6_metadata_value *m)
|
||||
{
|
||||
return m && m->type == VKD3D_METADATA_NODE;
|
||||
}
|
||||
|
||||
static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const struct dxil_block *block,
|
||||
struct sm6_function *function)
|
||||
{
|
||||
@ -2893,11 +2906,31 @@ static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const st
|
||||
return VKD3D_OK;
|
||||
}
|
||||
|
||||
static bool sm6_parser_allocate_named_metadata(struct sm6_parser *sm6)
|
||||
{
|
||||
struct dxil_block *block;
|
||||
unsigned int i, j, count;
|
||||
|
||||
for (i = 0, count = 0; i < sm6->root_block.child_block_count; ++i)
|
||||
{
|
||||
block = sm6->root_block.child_blocks[i];
|
||||
if (block->id != METADATA_BLOCK)
|
||||
continue;
|
||||
for (j = 0; j < block->record_count; ++j)
|
||||
count += block->records[j]->code == METADATA_NAMED_NODE;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
return true;
|
||||
|
||||
return !!(sm6->named_metadata = vkd3d_calloc(count, sizeof(*sm6->named_metadata)));
|
||||
}
|
||||
|
||||
static enum vkd3d_result metadata_value_create_node(struct sm6_metadata_value *m, struct sm6_metadata_table *table,
|
||||
unsigned int dst_idx, unsigned int end_count, const struct dxil_record *record, struct sm6_parser *sm6)
|
||||
{
|
||||
struct sm6_metadata_node *node;
|
||||
unsigned int i;
|
||||
unsigned int i, offset;
|
||||
|
||||
m->type = VKD3D_METADATA_NODE;
|
||||
if (!(m->value_type = sm6->metadata_type))
|
||||
@ -2918,12 +2951,14 @@ static enum vkd3d_result metadata_value_create_node(struct sm6_metadata_value *m
|
||||
|
||||
node->is_distinct = record->code == METADATA_DISTINCT_NODE;
|
||||
|
||||
offset = record->code != METADATA_NAMED_NODE;
|
||||
|
||||
for (i = 0; i < record->operand_count; ++i)
|
||||
{
|
||||
uint64_t ref;
|
||||
|
||||
ref = record->operands[i] - 1;
|
||||
if (record->operands[i] >= 1 && ref >= end_count)
|
||||
ref = record->operands[i] - offset;
|
||||
if (record->operands[i] >= offset && ref >= end_count)
|
||||
{
|
||||
WARN("Invalid metadata index %"PRIu64".\n", ref);
|
||||
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA,
|
||||
@ -2941,7 +2976,15 @@ static enum vkd3d_result metadata_value_create_node(struct sm6_metadata_value *m
|
||||
return VKD3D_ERROR_INVALID_SHADER;
|
||||
}
|
||||
|
||||
node->operands[i] = (record->operands[i] >= 1) ? &table->values[ref] : NULL;
|
||||
node->operands[i] = (record->operands[i] >= offset) ? &table->values[ref] : NULL;
|
||||
if (record->code == METADATA_NAMED_NODE && !sm6_metadata_value_is_node(node->operands[i]))
|
||||
{
|
||||
WARN("Named node operand is not a node.\n");
|
||||
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA,
|
||||
"The operand of a metadata named node is not a node.");
|
||||
vkd3d_free(node);
|
||||
return VKD3D_ERROR_INVALID_SHADER;
|
||||
}
|
||||
}
|
||||
|
||||
node->operand_count = record->operand_count;
|
||||
@ -2957,6 +3000,7 @@ static enum vkd3d_result sm6_parser_metadata_init(struct sm6_parser *sm6, const
|
||||
const struct dxil_record *record;
|
||||
const struct sm6_value *value;
|
||||
enum vkd3d_result ret;
|
||||
char *name;
|
||||
|
||||
for (i = 0, count = 0; i < block->record_count; ++i)
|
||||
count += block->records[i]->code != METADATA_NAME;
|
||||
@ -2970,7 +3014,7 @@ static enum vkd3d_result sm6_parser_metadata_init(struct sm6_parser *sm6, const
|
||||
}
|
||||
table->values = values;
|
||||
|
||||
for (i = 0; i < block->record_count; ++i)
|
||||
for (i = 0, name = NULL; i < block->record_count; ++i)
|
||||
{
|
||||
record = block->records[i];
|
||||
|
||||
@ -2979,6 +3023,27 @@ static enum vkd3d_result sm6_parser_metadata_init(struct sm6_parser *sm6, const
|
||||
|
||||
switch (record->code)
|
||||
{
|
||||
case METADATA_NAMED_NODE:
|
||||
if (!name)
|
||||
{
|
||||
WARN("Named node has no name.\n");
|
||||
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA,
|
||||
"A metadata named node has no name.");
|
||||
return VKD3D_ERROR_INVALID_SHADER;
|
||||
}
|
||||
|
||||
/* When DXC emits metadata value array reference indices it assumes named nodes
|
||||
* are not included in the array. Store named nodes separately. */
|
||||
m = &sm6->named_metadata[sm6->named_metadata_count].value;
|
||||
sm6->named_metadata[sm6->named_metadata_count].name = name;
|
||||
name = NULL;
|
||||
|
||||
if ((ret = metadata_value_create_node(m, table, UINT_MAX, count, record, sm6)) < 0)
|
||||
return ret;
|
||||
++sm6->named_metadata_count;
|
||||
/* Skip incrementing the table count. */
|
||||
continue;
|
||||
|
||||
case METADATA_DISTINCT_NODE:
|
||||
case METADATA_NODE:
|
||||
if ((ret = metadata_value_create_node(m, table, table_idx, count, record, sm6)) < 0)
|
||||
@ -2998,6 +3063,23 @@ static enum vkd3d_result sm6_parser_metadata_init(struct sm6_parser *sm6, const
|
||||
}
|
||||
break;
|
||||
|
||||
case METADATA_NAME:
|
||||
/* Check the next record to avoid freeing 'name' in all exit paths. */
|
||||
if (i + 1 == block->record_count || block->records[i + 1]->code != METADATA_NAMED_NODE)
|
||||
{
|
||||
WARN("Name is not followed by a named node.\n");
|
||||
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA,
|
||||
"A metadata node name is not followed by a named node.");
|
||||
return VKD3D_ERROR_INVALID_SHADER;
|
||||
}
|
||||
/* LLVM allows an empty string here. */
|
||||
if (!(name = dxil_record_to_string(record, 0, sm6)))
|
||||
{
|
||||
ERR("Failed to allocate name.\n");
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
continue;
|
||||
|
||||
case METADATA_STRING:
|
||||
/* LLVM allows an empty string here. */
|
||||
m->type = VKD3D_METADATA_STRING;
|
||||
@ -3081,6 +3163,12 @@ static void sm6_parser_metadata_cleanup(struct sm6_parser *sm6)
|
||||
sm6_metadata_value_destroy(&sm6->metadata_tables[i].values[j]);
|
||||
vkd3d_free(sm6->metadata_tables[i].values);
|
||||
}
|
||||
for (i = 0; i < sm6->named_metadata_count; ++i)
|
||||
{
|
||||
sm6_metadata_value_destroy(&sm6->named_metadata[i].value);
|
||||
vkd3d_free(sm6->named_metadata[i].name);
|
||||
}
|
||||
vkd3d_free(sm6->named_metadata);
|
||||
}
|
||||
|
||||
static void sm6_type_table_cleanup(struct sm6_type *types, size_t count)
|
||||
@ -3357,6 +3445,12 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!sm6_parser_allocate_named_metadata(sm6))
|
||||
{
|
||||
ERR("Failed to allocate named metadata array.\n");
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < sm6->root_block.child_block_count; ++i)
|
||||
{
|
||||
block = sm6->root_block.child_blocks[i];
|
||||
|
Loading…
x
Reference in New Issue
Block a user