vkd3d-shader/sm1: Store parsed instructions in an array.

This commit is contained in:
Conor McCarthy 2023-01-20 11:13:01 +10:00 committed by Alexandre Julliard
parent 6b82ba9488
commit 007f894b94
Notes: Alexandre Julliard 2023-01-24 22:28:12 +01:00
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/60
3 changed files with 241 additions and 36 deletions

View File

@ -210,13 +210,6 @@ struct vkd3d_shader_sm1_parser
const uint32_t *start, *end;
bool abort;
struct vkd3d_shader_src_param src_rel_addr[4];
struct vkd3d_shader_src_param pred_rel_addr;
struct vkd3d_shader_src_param dst_rel_addr;
struct vkd3d_shader_src_param src_param[4];
struct vkd3d_shader_src_param pred_param;
struct vkd3d_shader_dst_param dst_param;
struct vkd3d_shader_parser p;
};
@ -556,33 +549,50 @@ static void shader_sm1_destroy(struct vkd3d_shader_parser *parser)
{
struct vkd3d_shader_sm1_parser *sm1 = vkd3d_shader_sm1_parser(parser);
shader_instruction_array_destroy(&parser->instructions);
free_shader_desc(&sm1->p.shader_desc);
vkd3d_free(sm1);
}
static void shader_sm1_read_src_param(struct vkd3d_shader_sm1_parser *sm1, const uint32_t **ptr,
struct vkd3d_shader_src_param *src_param, struct vkd3d_shader_src_param *src_rel_addr)
struct vkd3d_shader_src_param *src_param)
{
struct vkd3d_shader_src_param *src_rel_addr = NULL;
uint32_t token, addr_token;
shader_sm1_read_param(sm1, ptr, &token, &addr_token);
if (has_relative_address(token))
{
if (!(src_rel_addr = shader_parser_get_src_params(&sm1->p, 1)))
{
vkd3d_shader_parser_error(&sm1->p, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY,
"Out of memory.");
sm1->abort = true;
return;
}
shader_sm1_parse_src_param(addr_token, NULL, src_rel_addr);
else
src_rel_addr = NULL;
}
shader_sm1_parse_src_param(token, src_rel_addr, src_param);
}
static void shader_sm1_read_dst_param(struct vkd3d_shader_sm1_parser *sm1, const uint32_t **ptr,
struct vkd3d_shader_dst_param *dst_param, struct vkd3d_shader_src_param *dst_rel_addr)
struct vkd3d_shader_dst_param *dst_param)
{
struct vkd3d_shader_src_param *dst_rel_addr = NULL;
uint32_t token, addr_token;
shader_sm1_read_param(sm1, ptr, &token, &addr_token);
if (has_relative_address(token))
{
if (!(dst_rel_addr = shader_parser_get_src_params(&sm1->p, 1)))
{
vkd3d_shader_parser_error(&sm1->p, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY,
"Out of memory.");
sm1->abort = true;
return;
}
shader_sm1_parse_src_param(addr_token, NULL, dst_rel_addr);
else
dst_rel_addr = NULL;
}
shader_sm1_parse_dst_param(token, dst_rel_addr, dst_param);
}
@ -731,10 +741,13 @@ static void shader_sm1_validate_instruction(struct vkd3d_shader_sm1_parser *sm1,
static void shader_sm1_read_instruction(struct vkd3d_shader_parser *parser, struct vkd3d_shader_instruction *ins)
{
struct vkd3d_shader_sm1_parser *sm1 = vkd3d_shader_sm1_parser(parser);
struct vkd3d_shader_src_param *src_params, *predicate;
const struct vkd3d_sm1_opcode_info *opcode_info;
struct vkd3d_shader_dst_param *dst_param;
const uint32_t **ptr = &parser->ptr;
uint32_t opcode_token;
const uint32_t *p;
bool predicated;
unsigned int i;
shader_sm1_read_comment(sm1);
@ -761,11 +774,18 @@ static void shader_sm1_read_instruction(struct vkd3d_shader_parser *parser, stru
ins->coissue = opcode_token & VKD3D_SM1_COISSUE;
ins->raw = false;
ins->structured = false;
ins->predicate = opcode_token & VKD3D_SM1_INSTRUCTION_PREDICATED ? &sm1->pred_param : NULL;
predicated = !!(opcode_token & VKD3D_SM1_INSTRUCTION_PREDICATED);
ins->predicate = predicate = predicated ? shader_parser_get_src_params(parser, 1) : NULL;
ins->dst_count = opcode_info->dst_count;
ins->dst = &sm1->dst_param;
ins->dst = dst_param = shader_parser_get_dst_params(parser, ins->dst_count);
ins->src_count = opcode_info->src_count;
ins->src = sm1->src_param;
ins->src = src_params = shader_parser_get_src_params(parser, ins->src_count);
if ((!predicate && predicated) || (!src_params && ins->src_count) || (!dst_param && ins->dst_count))
{
vkd3d_shader_parser_error(parser, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY, "Out of memory.");
goto fail;
}
ins->resource_type = VKD3D_SHADER_RESOURCE_NONE;
ins->resource_stride = 0;
ins->resource_data_type[0] = VKD3D_DATA_FLOAT;
@ -790,32 +810,32 @@ static void shader_sm1_read_instruction(struct vkd3d_shader_parser *parser, stru
}
else if (ins->handler_idx == VKD3DSIH_DEF)
{
shader_sm1_read_dst_param(sm1, &p, &sm1->dst_param, &sm1->dst_rel_addr);
shader_sm1_read_immconst(sm1, &p, &sm1->src_param[0], VKD3D_IMMCONST_VEC4, VKD3D_DATA_FLOAT);
shader_sm1_read_dst_param(sm1, &p, dst_param);
shader_sm1_read_immconst(sm1, &p, &src_params[0], VKD3D_IMMCONST_VEC4, VKD3D_DATA_FLOAT);
}
else if (ins->handler_idx == VKD3DSIH_DEFB)
{
shader_sm1_read_dst_param(sm1, &p, &sm1->dst_param, &sm1->dst_rel_addr);
shader_sm1_read_immconst(sm1, &p, &sm1->src_param[0], VKD3D_IMMCONST_SCALAR, VKD3D_DATA_UINT);
shader_sm1_read_dst_param(sm1, &p, dst_param);
shader_sm1_read_immconst(sm1, &p, &src_params[0], VKD3D_IMMCONST_SCALAR, VKD3D_DATA_UINT);
}
else if (ins->handler_idx == VKD3DSIH_DEFI)
{
shader_sm1_read_dst_param(sm1, &p, &sm1->dst_param, &sm1->dst_rel_addr);
shader_sm1_read_immconst(sm1, &p, &sm1->src_param[0], VKD3D_IMMCONST_VEC4, VKD3D_DATA_INT);
shader_sm1_read_dst_param(sm1, &p, dst_param);
shader_sm1_read_immconst(sm1, &p, &src_params[0], VKD3D_IMMCONST_VEC4, VKD3D_DATA_INT);
}
else
{
/* Destination token */
if (ins->dst_count)
shader_sm1_read_dst_param(sm1, &p, &sm1->dst_param, &sm1->dst_rel_addr);
shader_sm1_read_dst_param(sm1, &p, dst_param);
/* Predication token */
if (ins->predicate)
shader_sm1_read_src_param(sm1, &p, &sm1->pred_param, &sm1->pred_rel_addr);
shader_sm1_read_src_param(sm1, &p, predicate);
/* Other source tokens */
for (i = 0; i < ins->src_count; ++i)
shader_sm1_read_src_param(sm1, &p, &sm1->src_param[i], &sm1->src_rel_addr[i]);
shader_sm1_read_src_param(sm1, &p, &src_params[i]);
}
if (sm1->abort)
@ -851,20 +871,12 @@ static bool shader_sm1_is_end(struct vkd3d_shader_parser *parser)
return false;
}
static void shader_sm1_reset(struct vkd3d_shader_parser *parser)
{
struct vkd3d_shader_sm1_parser *sm1 = vkd3d_shader_sm1_parser(parser);
parser->ptr = sm1->start;
parser->failed = false;
}
const struct vkd3d_shader_parser_ops shader_sm1_parser_ops =
{
.parser_reset = shader_sm1_reset,
.parser_reset = shader_parser_reset,
.parser_destroy = shader_sm1_destroy,
.parser_read_instruction = shader_sm1_read_instruction,
.parser_is_end = shader_sm1_is_end,
.parser_read_instruction = shader_parser_read_instruction,
.parser_is_end = shader_parser_is_end,
};
static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1,
@ -922,6 +934,10 @@ static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1,
sm1->start = &code[1];
sm1->end = &code[token_count];
/* Estimate instruction count to avoid reallocation in most shaders. */
if (!shader_instruction_array_init(&sm1->p.instructions, code_size != ~(size_t)0 ? token_count / 4u + 4: 16))
return VKD3D_ERROR_OUT_OF_MEMORY;
vkd3d_shader_parser_init(&sm1->p, message_context, compile_info->source_name, &version, &shader_sm1_parser_ops);
shader_desc = &sm1->p.shader_desc;
shader_desc->byte_code = code;
@ -934,6 +950,8 @@ static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1,
int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compile_info,
struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_parser **parser)
{
struct vkd3d_shader_instruction_array *instructions;
struct vkd3d_shader_instruction *ins;
struct vkd3d_shader_sm1_parser *sm1;
int ret;
@ -950,6 +968,28 @@ int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compi
return ret;
}
instructions = &sm1->p.instructions;
while (!shader_sm1_is_end(&sm1->p))
{
if (!shader_instruction_array_reserve(instructions, instructions->count + 1))
{
ERR("Failed to allocate instructions.\n");
vkd3d_shader_parser_error(&sm1->p, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY, "Out of memory.");
shader_sm1_destroy(&sm1->p);
return VKD3D_ERROR_OUT_OF_MEMORY;
}
ins = &instructions->elements[instructions->count];
shader_sm1_read_instruction(&sm1->p, ins);
if (ins->handler_idx == VKD3DSIH_INVALID)
{
WARN("Encountered unrecognized or invalid instruction.\n");
shader_sm1_destroy(&sm1->p);
return VKD3D_ERROR_INVALID_SHADER;
}
++instructions->count;
}
*parser = &sm1->p;
return VKD3D_OK;

View File

@ -461,6 +461,22 @@ void VKD3D_PRINTF_FUNC(3, 4) vkd3d_shader_parser_warning(struct vkd3d_shader_par
va_end(args);
}
void shader_parser_reset(struct vkd3d_shader_parser *parser)
{
parser->instruction_idx = 0;
parser->failed = false;
}
void shader_parser_read_instruction(struct vkd3d_shader_parser *parser, struct vkd3d_shader_instruction *ins)
{
*ins = parser->instructions.elements[parser->instruction_idx++];
}
bool shader_parser_is_end(struct vkd3d_shader_parser *parser)
{
return parser->instruction_idx >= parser->instructions.count;
}
static int vkd3d_shader_validate_compile_info(const struct vkd3d_shader_compile_info *compile_info,
bool validate_target_type)
{
@ -1583,3 +1599,89 @@ void vkd3d_shader_set_log_callback(PFN_vkd3d_log callback)
{
vkd3d_dbg_set_log_callback(callback);
}
static struct vkd3d_shader_param_node *shader_param_allocator_node_create(
struct vkd3d_shader_param_allocator *allocator)
{
struct vkd3d_shader_param_node *node;
if (!(node = vkd3d_malloc(offsetof(struct vkd3d_shader_param_node, param[allocator->count * allocator->stride]))))
return NULL;
node->next = NULL;
return node;
}
static void shader_param_allocator_init(struct vkd3d_shader_param_allocator *allocator,
unsigned int count, unsigned int stride)
{
allocator->count = max(count, 4);
allocator->stride = stride;
allocator->head = NULL;
allocator->current = NULL;
allocator->index = allocator->count;
}
static void shader_param_allocator_destroy(struct vkd3d_shader_param_allocator *allocator)
{
struct vkd3d_shader_param_node *current = allocator->head;
while (current)
{
struct vkd3d_shader_param_node *next = current->next;
vkd3d_free(current);
current = next;
}
}
void *shader_param_allocator_get(struct vkd3d_shader_param_allocator *allocator, unsigned int count)
{
void *params;
if (!count)
return NULL;
if (count > allocator->count - allocator->index)
{
struct vkd3d_shader_param_node *next = shader_param_allocator_node_create(allocator);
if (!next)
return NULL;
if (allocator->current)
allocator->current->next = next;
allocator->current = next;
allocator->index = 0;
}
params = &allocator->current->param[allocator->index * allocator->stride];
allocator->index += count;
return params;
}
bool shader_instruction_array_init(struct vkd3d_shader_instruction_array *instructions, unsigned int reserve)
{
memset(instructions, 0, sizeof(*instructions));
/* Size the parameter initial allocations so they are large enough for most shaders. The
* code path for chained allocations will be tested if a few shaders need to use it. */
shader_param_allocator_init(&instructions->dst_params, reserve - reserve / 8u,
sizeof(*instructions->elements->dst));
shader_param_allocator_init(&instructions->src_params, reserve * 2u, sizeof(*instructions->elements->src));
return shader_instruction_array_reserve(instructions, reserve);
}
bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *instructions, unsigned int reserve)
{
if (!vkd3d_array_reserve((void **)&instructions->elements, &instructions->capacity, reserve,
sizeof(*instructions->elements)))
{
ERR("Failed to allocate instructions.\n");
return false;
}
return true;
}
void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions)
{
vkd3d_free(instructions->elements);
shader_param_allocator_destroy(&instructions->dst_params);
shader_param_allocator_destroy(&instructions->src_params);
}

View File

@ -133,6 +133,7 @@ enum vkd3d_shader_error
VKD3D_SHADER_ERROR_D3DBC_INVALID_VERSION_TOKEN = 7001,
VKD3D_SHADER_ERROR_D3DBC_INVALID_OPCODE = 7002,
VKD3D_SHADER_ERROR_D3DBC_INVALID_RESOURCE_TYPE = 7003,
VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY = 7004,
VKD3D_SHADER_WARNING_D3DBC_IGNORED_INSTRUCTION_FLAGS= 7300,
};
@ -929,6 +930,51 @@ struct vkd3d_shader_location
unsigned int line, column;
};
struct vkd3d_shader_param_node
{
struct vkd3d_shader_param_node *next;
uint8_t param[];
};
struct vkd3d_shader_param_allocator
{
struct vkd3d_shader_param_node *head;
struct vkd3d_shader_param_node *current;
unsigned int count;
unsigned int stride;
unsigned int index;
};
void *shader_param_allocator_get(struct vkd3d_shader_param_allocator *allocator, unsigned int count);
static inline struct vkd3d_shader_src_param *shader_src_param_allocator_get(
struct vkd3d_shader_param_allocator *allocator, unsigned int count)
{
assert(allocator->stride == sizeof(struct vkd3d_shader_src_param));
return shader_param_allocator_get(allocator, count);
}
static inline struct vkd3d_shader_dst_param *shader_dst_param_allocator_get(
struct vkd3d_shader_param_allocator *allocator, unsigned int count)
{
assert(allocator->stride == sizeof(struct vkd3d_shader_dst_param));
return shader_param_allocator_get(allocator, count);
}
struct vkd3d_shader_instruction_array
{
struct vkd3d_shader_instruction *elements;
size_t capacity;
size_t count;
struct vkd3d_shader_param_allocator src_params;
struct vkd3d_shader_param_allocator dst_params;
};
bool shader_instruction_array_init(struct vkd3d_shader_instruction_array *instructions, unsigned int reserve);
bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *instructions, unsigned int reserve);
void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions);
struct vkd3d_shader_parser
{
struct vkd3d_shader_message_context *message_context;
@ -939,6 +985,8 @@ struct vkd3d_shader_parser
struct vkd3d_shader_version shader_version;
const uint32_t *ptr;
const struct vkd3d_shader_parser_ops *ops;
struct vkd3d_shader_instruction_array instructions;
size_t instruction_idx;
};
struct vkd3d_shader_parser_ops
@ -956,6 +1004,21 @@ void vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser,
const struct vkd3d_shader_version *version, const struct vkd3d_shader_parser_ops *ops);
void vkd3d_shader_parser_warning(struct vkd3d_shader_parser *parser,
enum vkd3d_shader_error error, const char *format, ...) VKD3D_PRINTF_FUNC(3, 4);
void shader_parser_reset(struct vkd3d_shader_parser *parser);
void shader_parser_read_instruction(struct vkd3d_shader_parser *parser, struct vkd3d_shader_instruction *ins);
bool shader_parser_is_end(struct vkd3d_shader_parser *parser);
static inline struct vkd3d_shader_dst_param *shader_parser_get_dst_params(
struct vkd3d_shader_parser *parser, unsigned int count)
{
return shader_dst_param_allocator_get(&parser->instructions.dst_params, count);
}
static inline struct vkd3d_shader_src_param *shader_parser_get_src_params(
struct vkd3d_shader_parser *parser, unsigned int count)
{
return shader_src_param_allocator_get(&parser->instructions.src_params, count);
}
static inline void vkd3d_shader_parser_destroy(struct vkd3d_shader_parser *parser)
{