From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 259 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 255 insertions(+), 4 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 718bc18a..0481a9d2 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -53,6 +53,15 @@ enum dxil_bc_block_abbreviation UNABBREV_RECORD = 3, };
+enum dxil_bc_abbrev_type +{ + ABBREV_FIXED = 1, + ABBREV_VBR = 2, + ABBREV_ARRAY = 3, + ABBREV_CHAR = 4, + ABBREV_BLOB = 5, +}; + struct vkd3d_shader_sm6_record { unsigned int code; @@ -69,6 +78,10 @@ struct vkd3d_shader_sm6_block unsigned int length; unsigned int level;
+ /* The abbrev, block and record structs are not relocatable. */ + struct vkd3d_shader_sm6_abbrev **abbrevs; + size_t abbrev_capacity; + size_t abbrev_count; unsigned int blockinfo_bid;
struct vkd3d_shader_sm6_block **child_blocks; @@ -90,6 +103,19 @@ struct vkd3d_shader_sm6_parser struct vkd3d_shader_parser p; };
+struct vkd3d_shader_sm6_abbrev_operand +{ + uint64_t context; + bool (*read_operand)(struct vkd3d_shader_parser *parser, uint64_t context, uint64_t *operand); +}; + +struct vkd3d_shader_sm6_abbrev +{ + unsigned int count; + bool is_array; + struct vkd3d_shader_sm6_abbrev_operand operands[]; +}; + static struct vkd3d_shader_sm6_parser *vkd3d_shader_sm6_parser(struct vkd3d_shader_parser *parser) { return CONTAINING_RECORD(parser, struct vkd3d_shader_sm6_parser, p); @@ -282,6 +308,216 @@ static enum vkd3d_result shader_sm6_read_unabbrev_record(struct vkd3d_shader_par return ret; }
+static bool shader_sm6_read_literal_operand(struct vkd3d_shader_parser *parser, uint64_t context, + uint64_t *op) +{ + *op = context; + return !parser->failed; +} + +static bool shader_sm6_read_fixed_operand(struct vkd3d_shader_parser *parser, uint64_t context, + uint64_t *op) +{ + *op = shader_sm6_read_bits(parser, context); + return !parser->failed; +} + +static bool shader_sm6_read_vbr_operand(struct vkd3d_shader_parser *parser, uint64_t context, + uint64_t *op) +{ + *op = shader_sm6_read_vbr(parser, context); + return !parser->failed; +} + +static bool shader_sm6_read_char6_operand(struct vkd3d_shader_parser *parser, uint64_t context, + uint64_t *op) +{ + *op = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._"[shader_sm6_read_bits(parser, 6)]; + return !parser->failed; +} + +static bool shader_sm6_read_blob_operand(struct vkd3d_shader_parser *parser, uint64_t context, + uint64_t *op) +{ + int count = shader_sm6_read_vbr(parser, 6); + shader_sm6_align_32(parser); + for (; count > 0; count -= 4) + shader_sm6_read_uint32(parser); + FIXME("Unhandled blob operand.\n"); + return false; +} + +static enum vkd3d_result shader_sm6_abbrev_init(struct vkd3d_shader_sm6_abbrev *abbrev, + unsigned int count, struct vkd3d_shader_parser *parser) +{ + enum dxil_bc_abbrev_type prev_type, type; + unsigned int i; + + abbrev->is_array = false; + + for (i = 0, prev_type = 0; i < count && !parser->failed; ++i) + { + if (shader_sm6_read_bits(parser, 1)) + { + if (prev_type == ABBREV_ARRAY) + { + FIXME("Unexpected literal abbreviation after array.\n"); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + abbrev->operands[i].context = shader_sm6_read_vbr(parser, 8); + abbrev->operands[i].read_operand = shader_sm6_read_literal_operand; + continue; + } + + switch (type = shader_sm6_read_bits(parser, 3)) + { + case ABBREV_FIXED: + case ABBREV_VBR: + abbrev->operands[i].context = shader_sm6_read_vbr(parser, 5); + abbrev->operands[i].read_operand = (type == ABBREV_FIXED) ? shader_sm6_read_fixed_operand + : shader_sm6_read_vbr_operand; + break; + + case ABBREV_ARRAY: + if (prev_type == ABBREV_ARRAY || i != count - 2) + { + FIXME("Unexpected array abbreviation.\n"); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + abbrev->is_array = true; + --i; + --count; + break; + + case ABBREV_CHAR: + abbrev->operands[i].read_operand = shader_sm6_read_char6_operand; + break; + + case ABBREV_BLOB: + if (prev_type == ABBREV_ARRAY || i != count - 1) + { + FIXME("Unexpected blob abbreviation.\n"); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + abbrev->operands[i].read_operand = shader_sm6_read_blob_operand; + break; + } + + prev_type = type; + } + + abbrev->count = count; + + return parser->failed ? VKD3D_ERROR_INVALID_ARGUMENT : VKD3D_OK; +} + +static enum vkd3d_result shader_sm6_add_block_abbrev(struct vkd3d_shader_parser *parser) +{ + struct vkd3d_shader_sm6_parser *sm6 = vkd3d_shader_sm6_parser(parser); + struct vkd3d_shader_sm6_block *block = sm6->current_block; + struct vkd3d_shader_sm6_abbrev *abbrev; + enum vkd3d_result ret; + unsigned int count; + + if (block->id == BLOCKINFO_BLOCK) + { + FIXME("Unhandled global abbreviation.\n"); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + + count = shader_sm6_read_vbr(parser, 5); + if (!vkd3d_array_reserve((void **)&block->abbrevs, &block->abbrev_capacity, block->abbrev_count + 1, sizeof(*block->abbrevs)) + || !(abbrev = vkd3d_malloc(sizeof(*abbrev) + count * sizeof(abbrev->operands[0])))) + { + ERR("Failed to allocate block abbreviation.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + if ((ret = shader_sm6_abbrev_init(abbrev, count, parser)) < 0) + { + vkd3d_free(abbrev); + return ret; + } + + block->abbrevs[block->abbrev_count++] = abbrev; + + return VKD3D_OK; +} + +static enum vkd3d_result shader_sm6_read_abbrev_record(struct vkd3d_shader_parser *parser, unsigned int abbrev_id) +{ + struct vkd3d_shader_sm6_parser *sm6 = vkd3d_shader_sm6_parser(parser); + struct vkd3d_shader_sm6_block *block = sm6->current_block; + enum vkd3d_result ret = VKD3D_ERROR_INVALID_ARGUMENT; + struct vkd3d_shader_sm6_record *temp, *record; + struct vkd3d_shader_sm6_abbrev *abbrev; + unsigned int i, count, array_len; + uint64_t code; + + if (abbrev_id >= block->abbrev_count) + { + FIXME("Invalid abbreviation id %u.\n", abbrev_id); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + + abbrev = block->abbrevs[abbrev_id]; + if (!(count = abbrev->count)) + return VKD3D_OK; + if (count == 1 && abbrev->is_array) + return VKD3D_ERROR_INVALID_ARGUMENT; + + /* First operand is the record code. The array is included in the count, but will be done separately. */ + count -= abbrev->is_array + 1; + if (!(record = vkd3d_malloc(sizeof(*record) + count * sizeof(record->operands[0])))) + { + ERR("Failed to allocate record with %u operands.\n", count); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + if (!abbrev->operands[0].read_operand(parser, abbrev->operands[0].context, &code)) + goto fail; + if (code > UINT_MAX) + FIXME("Truncating 64-bit record code %#"PRIx64".\n", code); + record->code = code; + + for (i = 0; i < count; ++i) + if (!abbrev->operands[i + 1].read_operand(parser, abbrev->operands[i + 1].context, &record->operands[i])) + goto fail; + record->operand_count = count; + + /* An array can occur only as the last operand. */ + if (abbrev->is_array) + { + array_len = shader_sm6_read_vbr(parser, 6); + if (!(temp = vkd3d_realloc(record, sizeof(*record) + (count + array_len) * sizeof(record->operands[0])))) + { + ERR("Failed to allocate record with %u operands.\n", count + array_len); + ret = VKD3D_ERROR_OUT_OF_MEMORY; + goto fail; + } + record = temp; + + for (i = 0; i < array_len; ++i) + { + if (!abbrev->operands[count + 1].read_operand(parser, abbrev->operands[count + 1].context, + &record->operands[count + i])) + { + goto fail; + } + } + record->operand_count += array_len; + } + + if ((ret = shader_sm6_block_add_record(block, record)) < 0) + goto fail; + + return VKD3D_OK; + +fail: + vkd3d_free(record); + return ret; +} + static enum vkd3d_result shader_sm6_block_init(struct vkd3d_shader_sm6_block *block, const struct vkd3d_shader_sm6_block *parent, struct vkd3d_shader_parser *parser);
@@ -324,8 +560,9 @@ static enum vkd3d_result shader_sm6_block_read(struct vkd3d_shader_sm6_block *pa break;
case DEFINE_ABBREV: - FIXME("Unhandled abbreviation definition.\n"); - return VKD3D_ERROR_INVALID_ARGUMENT; + if ((ret = shader_sm6_add_block_abbrev(parser)) < 0) + return ret; + break;
case UNABBREV_RECORD: if ((ret = shader_sm6_read_unabbrev_record(parser)) < 0) @@ -336,8 +573,12 @@ static enum vkd3d_result shader_sm6_block_read(struct vkd3d_shader_sm6_block *pa break;
default: - FIXME("Unhandled abbreviated record %u.\n", abbrev_id); - return VKD3D_ERROR_INVALID_ARGUMENT; + if ((ret = shader_sm6_read_abbrev_record(parser, abbrev_id - 4)) < 0) + { + FIXME("Failed to read abbreviated record.\n"); + return ret; + } + break; } } while (!parser->failed);
@@ -349,6 +590,7 @@ static enum vkd3d_result shader_sm6_block_init(struct vkd3d_shader_sm6_block *bl { struct vkd3d_shader_sm6_parser *sm6 = vkd3d_shader_sm6_parser(parser); enum vkd3d_result ret; + unsigned int i;
block->parent = parent; block->level = parent ? parent->level + 1 : 0; @@ -357,6 +599,9 @@ static enum vkd3d_result shader_sm6_block_init(struct vkd3d_shader_sm6_block *bl shader_sm6_align_32(parser); block->length = shader_sm6_read_uint32(parser); block->start = parser->ptr - sm6->start; + block->abbrevs = NULL; + block->abbrev_capacity = 0; + block->abbrev_count = 0;
if (parser->failed) return VKD3D_ERROR_INVALID_ARGUMENT; @@ -370,6 +615,12 @@ static enum vkd3d_result shader_sm6_block_init(struct vkd3d_shader_sm6_block *bl
ret = shader_sm6_block_read(block, parser);
+ for (i = 0; i < block->abbrev_count; ++i) + vkd3d_free(block->abbrevs[i]); + vkd3d_free(block->abbrevs); + block->abbrevs = NULL; + block->abbrev_count = 0; + return ret; }