From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/d3dbc.c | 110 +++++++++++------- libs/vkd3d-shader/dxbc.c | 135 ++++++++++++----------- libs/vkd3d-shader/glsl.c | 16 +-- libs/vkd3d-shader/spirv.c | 14 ++- libs/vkd3d-shader/trace.c | 27 ++--- libs/vkd3d-shader/vkd3d_shader_main.c | 135 +++++++++++++++++------ libs/vkd3d-shader/vkd3d_shader_private.h | 83 ++++++++++---- 7 files changed, 327 insertions(+), 193 deletions(-)
diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index c5518752..56a86fea 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -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, true); 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,9 @@ 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_destroy = shader_sm1_destroy, - .parser_read_instruction = shader_sm1_read_instruction, - .parser_is_end = shader_sm1_is_end, };
static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1, @@ -922,7 +931,10 @@ static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1, sm1->start = &code[1]; sm1->end = &code[token_count];
- vkd3d_shader_parser_init(&sm1->p, message_context, compile_info->source_name, &version, &shader_sm1_parser_ops); + /* Estimate instruction count to avoid reallocation in most shaders. */ + if (!vkd3d_shader_parser_init(&sm1->p, message_context, compile_info->source_name, &version, &shader_sm1_parser_ops, + code_size != ~(size_t)0 ? token_count / 4u : 16)) + return VKD3D_ERROR_OUT_OF_MEMORY; shader_desc = &sm1->p.shader_desc; shader_desc->byte_code = code; shader_desc->byte_code_size = code_size; @@ -934,6 +946,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 +964,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, 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; diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index c06741c5..d5eec522 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -96,12 +96,6 @@ struct vkd3d_shader_sm4_parser
unsigned int output_map[MAX_REG_OUTPUT];
- struct vkd3d_shader_src_param src_param[SM4_MAX_SRC_COUNT]; - struct vkd3d_shader_dst_param dst_param[SM4_MAX_DST_COUNT]; - struct list src_free; - struct list src; - struct vkd3d_shader_immediate_constant_buffer icb; - struct vkd3d_shader_parser p; };
@@ -206,7 +200,8 @@ static bool shader_sm4_read_register_space(struct vkd3d_shader_sm4_parser *priv, static void shader_sm4_read_conditional_op(struct vkd3d_shader_instruction *ins, uint32_t opcode, uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) { - shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_UINT, &priv->src_param[0]); + shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_UINT, + (struct vkd3d_shader_src_param *)&ins->src[0]); ins->flags = (opcode_token & VKD3D_SM4_CONDITIONAL_NZ) ? VKD3D_SHADER_CONDITIONAL_OP_NZ : VKD3D_SHADER_CONDITIONAL_OP_Z; } @@ -214,6 +209,7 @@ static void shader_sm4_read_conditional_op(struct vkd3d_shader_instruction *ins, static void shader_sm4_read_shader_data(struct vkd3d_shader_instruction *ins, uint32_t opcode, uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) { + struct vkd3d_shader_immediate_constant_buffer *icb; enum vkd3d_sm4_shader_data_type type; unsigned int icb_size;
@@ -227,16 +223,23 @@ static void shader_sm4_read_shader_data(struct vkd3d_shader_instruction *ins, ui
++tokens; icb_size = token_count - 1; - if (icb_size % 4 || icb_size > MAX_IMMEDIATE_CONSTANT_BUFFER_SIZE) + if (icb_size % 4) { FIXME("Unexpected immediate constant buffer size %u.\n", icb_size); ins->handler_idx = VKD3DSIH_INVALID; return; }
- priv->icb.vec4_count = icb_size / 4; - memcpy(priv->icb.data, tokens, sizeof(*tokens) * icb_size); - ins->declaration.icb = &priv->icb; + if (!(icb = vkd3d_malloc(sizeof(*icb) + sizeof(*tokens) * icb_size))) + { + ERR("Failed to allocate immediate constant buffer, size %u.\n", icb_size); + vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_OUT_OF_MEMORY, "Out of memory."); + ins->handler_idx = VKD3DSIH_INVALID; + return; + } + icb->vec4_count = icb_size / 4; + memcpy(icb->data, tokens, sizeof(*tokens) * icb_size); + ins->declaration.icb = icb; }
static void shader_sm4_set_descriptor_register_range(struct vkd3d_shader_sm4_parser *sm4, @@ -438,8 +441,9 @@ static void shader_sm4_read_dcl_global_flags(struct vkd3d_shader_instruction *in static void shader_sm5_read_fcall(struct vkd3d_shader_instruction *ins, uint32_t opcode, uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) { - priv->src_param[0].reg.u.fp_body_idx = *tokens++; - shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_OPAQUE, &priv->src_param[0]); + struct vkd3d_shader_src_param *src_params = (struct vkd3d_shader_src_param *)ins->src; + src_params[0].reg.u.fp_body_idx = *tokens++; + shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_OPAQUE, &src_params[0]); }
static void shader_sm5_read_dcl_function_body(struct vkd3d_shader_instruction *ins, uint32_t opcode, @@ -987,45 +991,18 @@ static enum vkd3d_data_type map_data_type(char t) static void shader_sm4_destroy(struct vkd3d_shader_parser *parser) { struct vkd3d_shader_sm4_parser *sm4 = vkd3d_shader_sm4_parser(parser); - struct vkd3d_shader_src_param_entry *e1, *e2;
- list_move_head(&sm4->src_free, &sm4->src); - LIST_FOR_EACH_ENTRY_SAFE(e1, e2, &sm4->src_free, struct vkd3d_shader_src_param_entry, entry) - { - vkd3d_free(e1); - } + shader_instruction_array_destroy(&parser->instructions, true); free_shader_desc(&parser->shader_desc); vkd3d_free(sm4); }
-static struct vkd3d_shader_src_param *get_src_param(struct vkd3d_shader_sm4_parser *priv) -{ - struct vkd3d_shader_src_param_entry *e; - struct list *elem; - - if (!list_empty(&priv->src_free)) - { - elem = list_head(&priv->src_free); - list_remove(elem); - } - else - { - if (!(e = vkd3d_malloc(sizeof(*e)))) - return NULL; - elem = &e->entry; - } - - list_add_tail(&priv->src, elem); - e = LIST_ENTRY(elem, struct vkd3d_shader_src_param_entry, entry); - return &e->param; -} - static bool shader_sm4_read_reg_idx(struct vkd3d_shader_sm4_parser *priv, const uint32_t **ptr, const uint32_t *end, uint32_t addressing, struct vkd3d_shader_register_index *reg_idx) { if (addressing & VKD3D_SM4_ADDRESSING_RELATIVE) { - struct vkd3d_shader_src_param *rel_addr = get_src_param(priv); + struct vkd3d_shader_src_param *rel_addr = shader_parser_get_src_params(&priv->p, 1);
if (!(reg_idx->rel_addr = rel_addr)) { @@ -1468,14 +1445,14 @@ static void shader_sm4_read_instruction(struct vkd3d_shader_parser *parser, stru struct vkd3d_shader_sm4_parser *sm4 = vkd3d_shader_sm4_parser(parser); const struct vkd3d_sm4_opcode_info *opcode_info; uint32_t opcode_token, opcode, previous_token; + struct vkd3d_shader_dst_param *dst_params; + struct vkd3d_shader_src_param *src_params; const uint32_t **ptr = &parser->ptr; unsigned int i, len; size_t remaining; const uint32_t *p; DWORD precise;
- list_move_head(&sm4->src_free, &sm4->src); - if (*ptr >= sm4->end) { WARN("End of byte-code, failed to read opcode.\n"); @@ -1520,11 +1497,15 @@ static void shader_sm4_read_instruction(struct vkd3d_shader_parser *parser, stru ins->structured = false; ins->predicate = NULL; ins->dst_count = strnlen(opcode_info->dst_info, SM4_MAX_DST_COUNT); - ins->dst = sm4->dst_param; ins->src_count = strnlen(opcode_info->src_info, SM4_MAX_SRC_COUNT); - ins->src = sm4->src_param; - assert(ins->dst_count <= ARRAY_SIZE(sm4->dst_param)); - assert(ins->src_count <= ARRAY_SIZE(sm4->src_param)); + ins->src = src_params = shader_parser_get_src_params(parser, ins->src_count); + if (!src_params && ins->src_count) + { + ERR("Failed to allocate src parameters.\n"); + vkd3d_shader_parser_error(parser, VKD3D_SHADER_ERROR_TPF_OUT_OF_MEMORY, "Out of memory."); + ins->handler_idx = VKD3DSIH_INVALID; + return; + } ins->resource_type = VKD3D_SHADER_RESOURCE_NONE; ins->resource_stride = 0; ins->resource_data_type[0] = VKD3D_DATA_FLOAT; @@ -1538,6 +1519,7 @@ static void shader_sm4_read_instruction(struct vkd3d_shader_parser *parser, stru
if (opcode_info->read_opcode_func) { + ins->dst = NULL; opcode_info->read_opcode_func(ins, opcode, opcode_token, p, len, sm4); } else @@ -1557,21 +1539,29 @@ static void shader_sm4_read_instruction(struct vkd3d_shader_parser *parser, stru precise = (opcode_token & VKD3D_SM5_PRECISE_MASK) >> VKD3D_SM5_PRECISE_SHIFT; ins->flags |= precise << VKD3DSI_PRECISE_SHIFT;
+ ins->dst = dst_params = shader_parser_get_dst_params(parser, ins->dst_count); + if (!dst_params && ins->dst_count) + { + ERR("Failed to allocate dst parameters.\n"); + vkd3d_shader_parser_error(parser, VKD3D_SHADER_ERROR_TPF_OUT_OF_MEMORY, "Out of memory."); + ins->handler_idx = VKD3DSIH_INVALID; + return; + } for (i = 0; i < ins->dst_count; ++i) { if (!(shader_sm4_read_dst_param(sm4, &p, *ptr, map_data_type(opcode_info->dst_info[i]), - &sm4->dst_param[i]))) + &dst_params[i]))) { ins->handler_idx = VKD3DSIH_INVALID; return; } - sm4->dst_param[i].modifiers |= instruction_dst_modifier; + dst_params[i].modifiers |= instruction_dst_modifier; }
for (i = 0; i < ins->src_count; ++i) { if (!(shader_sm4_read_src_param(sm4, &p, *ptr, map_data_type(opcode_info->src_info[i]), - &sm4->src_param[i]))) + &src_params[i]))) { ins->handler_idx = VKD3DSIH_INVALID; return; @@ -1594,20 +1584,9 @@ static bool shader_sm4_is_end(struct vkd3d_shader_parser *parser) return parser->ptr == sm4->end; }
-static void shader_sm4_reset(struct vkd3d_shader_parser *parser) -{ - struct vkd3d_shader_sm4_parser *sm4 = vkd3d_shader_sm4_parser(parser); - - parser->ptr = sm4->start; - parser->failed = false; -} - static const struct vkd3d_shader_parser_ops shader_sm4_parser_ops = { - .parser_reset = shader_sm4_reset, .parser_destroy = shader_sm4_destroy, - .parser_read_instruction = shader_sm4_read_instruction, - .parser_is_end = shader_sm4_is_end, };
static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, const uint32_t *byte_code, @@ -1670,7 +1649,10 @@ static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, const uint32_t version.major = VKD3D_SM4_VERSION_MAJOR(version_token); version.minor = VKD3D_SM4_VERSION_MINOR(version_token);
- vkd3d_shader_parser_init(&sm4->p, message_context, source_name, &version, &shader_sm4_parser_ops); + /* Estimate instruction count to avoid reallocation in most shaders. */ + if (!vkd3d_shader_parser_init(&sm4->p, message_context, source_name, &version, &shader_sm4_parser_ops, + token_count / 7u + 20)) + return false; sm4->p.ptr = sm4->start;
memset(sm4->output_map, 0xff, sizeof(sm4->output_map)); @@ -1690,9 +1672,6 @@ static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, const uint32_t sm4->output_map[e->register_index] = e->semantic_index; }
- list_init(&sm4->src_free); - list_init(&sm4->src); - return true; }
@@ -2061,7 +2040,9 @@ static int shader_extract_from_dxbc(const void *dxbc, size_t dxbc_length, int vkd3d_shader_sm4_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_desc *shader_desc; + struct vkd3d_shader_instruction *ins; struct vkd3d_shader_sm4_parser *sm4; int ret;
@@ -2089,6 +2070,28 @@ int vkd3d_shader_sm4_parser_create(const struct vkd3d_shader_compile_info *compi return VKD3D_ERROR_INVALID_ARGUMENT; }
+ instructions = &sm4->p.instructions; + while (!shader_sm4_is_end(&sm4->p)) + { + if (!shader_instruction_array_reserve(instructions, 1)) + { + ERR("Failed to allocate instructions.\n"); + vkd3d_shader_parser_error(&sm4->p, VKD3D_SHADER_ERROR_TPF_OUT_OF_MEMORY, "Out of memory."); + shader_sm4_destroy(&sm4->p); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + ins = &instructions->elements[instructions->count]; + shader_sm4_read_instruction(&sm4->p, ins); + + if (ins->handler_idx == VKD3DSIH_INVALID) + { + WARN("Encountered unrecognized or invalid instruction.\n"); + shader_sm4_destroy(&sm4->p); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + ++instructions->count; + } + *parser = &sm4->p;
return VKD3D_OK; diff --git a/libs/vkd3d-shader/glsl.c b/libs/vkd3d-shader/glsl.c index 56fa7043..5f68642d 100644 --- a/libs/vkd3d-shader/glsl.c +++ b/libs/vkd3d-shader/glsl.c @@ -93,25 +93,15 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *generator int vkd3d_glsl_generator_generate(struct vkd3d_glsl_generator *generator, struct vkd3d_shader_parser *parser, struct vkd3d_shader_code *out) { + unsigned int i; void *code; - struct vkd3d_shader_instruction ins;
vkd3d_string_buffer_printf(&generator->buffer, "#version 440\n\n"); vkd3d_string_buffer_printf(&generator->buffer, "void main()\n{\n");
- while (!vkd3d_shader_parser_is_end(parser)) + for (i = 0; i < parser->instructions.count; ++i) { - vkd3d_shader_parser_read_instruction(parser, &ins); - - if (ins.handler_idx == VKD3DSIH_INVALID) - { - vkd3d_glsl_compiler_error(generator, - VKD3D_SHADER_ERROR_GLSL_INTERNAL, - "Encountered unrecognized or invalid instruction."); - break; - } - - vkd3d_glsl_handle_instruction(generator, &ins); + vkd3d_glsl_handle_instruction(generator, &parser->instructions.elements[i]); }
if (parser->failed || generator->failed) diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 0d0515de..2c06ffe9 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -9577,7 +9577,7 @@ static bool is_dcl_instruction(enum vkd3d_shader_opcode handler_idx) || handler_idx == VKD3DSIH_HS_DECLS; }
-int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, +static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { int ret = VKD3D_OK; @@ -9933,6 +9933,18 @@ int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, return ret; }
+int spirv_compiler_handle_instructions(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction_array *instructions) +{ + enum vkd3d_result result = VKD3D_OK; + unsigned int i; + + for (i = 0; i < instructions->count && result >= 0; ++i) + result = spirv_compiler_handle_instruction(compiler, &instructions->elements[i]); + + return result; +} + int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *spirv) { diff --git a/libs/vkd3d-shader/trace.c b/libs/vkd3d-shader/trace.c index 6c30edc9..8e2cac16 100644 --- a/libs/vkd3d-shader/trace.c +++ b/libs/vkd3d-shader/trace.c @@ -1859,7 +1859,7 @@ enum vkd3d_result vkd3d_dxbc_binary_to_text(struct vkd3d_shader_parser *parser, struct vkd3d_d3d_asm_compiler compiler; enum vkd3d_result result = VKD3D_OK; struct vkd3d_string_buffer *buffer; - unsigned int indent, i; + unsigned int indent, i, j; const char *indent_str; void *code;
@@ -1920,21 +1920,11 @@ enum vkd3d_result vkd3d_dxbc_binary_to_text(struct vkd3d_shader_parser *parser, shader_version->minor, compiler.colours.reset);
indent = 0; - vkd3d_shader_parser_reset(parser); - while (!vkd3d_shader_parser_is_end(parser)) + for (i = 0; i < parser->instructions.count; ++i) { - struct vkd3d_shader_instruction ins; + struct vkd3d_shader_instruction *ins = &parser->instructions.elements[i];
- vkd3d_shader_parser_read_instruction(parser, &ins); - if (ins.handler_idx == VKD3DSIH_INVALID) - { - WARN("Skipping unrecognized instruction.\n"); - vkd3d_string_buffer_printf(buffer, "<unrecognized instruction>\n"); - result = VKD3D_ERROR; - continue; - } - - switch (ins.handler_idx) + switch (ins->handler_idx) { case VKD3DSIH_ELSE: case VKD3DSIH_ENDIF: @@ -1947,14 +1937,14 @@ enum vkd3d_result vkd3d_dxbc_binary_to_text(struct vkd3d_shader_parser *parser, break; }
- for (i = 0; i < indent; ++i) + for (j = 0; j < indent; ++j) { vkd3d_string_buffer_printf(buffer, "%s", indent_str); }
- shader_dump_instruction(&compiler, &ins); + shader_dump_instruction(&compiler, ins);
- switch (ins.handler_idx) + switch (ins->handler_idx) { case VKD3DSIH_ELSE: case VKD3DSIH_IF: @@ -1968,9 +1958,6 @@ enum vkd3d_result vkd3d_dxbc_binary_to_text(struct vkd3d_shader_parser *parser, } }
- if (parser->failed) - result = VKD3D_ERROR_INVALID_SHADER; - if ((code = vkd3d_malloc(buffer->content_size))) { memcpy(code, buffer->buffer, buffer->content_size); diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 72a6d2d8..5099492a 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -427,9 +427,10 @@ void vkd3d_shader_dump_shader(enum vkd3d_shader_source_type source_type, shader_get_source_type_suffix(source_type), shader->code, shader->size); }
-void vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser, +bool vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser, struct vkd3d_shader_message_context *message_context, const char *source_name, - const struct vkd3d_shader_version *version, const struct vkd3d_shader_parser_ops *ops) + const struct vkd3d_shader_version *version, const struct vkd3d_shader_parser_ops *ops, + unsigned int instruction_reserve) { parser->message_context = message_context; parser->location.source_name = source_name; @@ -437,6 +438,7 @@ void vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser, parser->location.column = 0; parser->shader_version = *version; parser->ops = ops; + return shader_instruction_array_init(&parser->instructions, instruction_reserve); }
void VKD3D_PRINTF_FUNC(3, 4) vkd3d_shader_parser_error(struct vkd3d_shader_parser *parser, @@ -1055,8 +1057,9 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_parser *parser) { struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info; - struct vkd3d_shader_instruction instruction; + struct vkd3d_shader_instruction *instruction; struct vkd3d_shader_scan_context context; + unsigned int i; int ret;
if ((scan_descriptor_info = vkd3d_find_struct(compile_info->next, SCAN_DESCRIPTOR_INFO))) @@ -1070,23 +1073,12 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info if (TRACE_ON()) { vkd3d_shader_trace(parser); - vkd3d_shader_parser_reset(parser); }
- while (!vkd3d_shader_parser_is_end(parser)) + for (i = 0; i < parser->instructions.count; ++i) { - vkd3d_shader_parser_read_instruction(parser, &instruction); - - if (instruction.handler_idx == VKD3DSIH_INVALID) - { - WARN("Encountered unrecognized or invalid instruction.\n"); - if (scan_descriptor_info) - vkd3d_shader_free_scan_descriptor_info(scan_descriptor_info); - ret = VKD3D_ERROR_INVALID_SHADER; - goto done; - } - - if ((ret = vkd3d_shader_scan_instruction(&context, &instruction)) < 0) + instruction = &parser->instructions.elements[i]; + if ((ret = vkd3d_shader_scan_instruction(&context, instruction)) < 0) { if (scan_descriptor_info) vkd3d_shader_free_scan_descriptor_info(scan_descriptor_info); @@ -1184,7 +1176,6 @@ static int compile_dxbc_tpf(const struct vkd3d_shader_compile_info *compile_info struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) { struct vkd3d_shader_scan_descriptor_info scan_descriptor_info; - struct vkd3d_shader_instruction instruction; struct vkd3d_shader_compile_info scan_info; struct spirv_compiler *spirv_compiler; struct vkd3d_shader_parser *parser; @@ -1245,23 +1236,7 @@ static int compile_dxbc_tpf(const struct vkd3d_shader_compile_info *compile_info return VKD3D_ERROR; }
- while (!vkd3d_shader_parser_is_end(parser)) - { - vkd3d_shader_parser_read_instruction(parser, &instruction); - - if (instruction.handler_idx == VKD3DSIH_INVALID) - { - WARN("Encountered unrecognized or invalid instruction.\n"); - ret = VKD3D_ERROR_INVALID_SHADER; - break; - } - - if ((ret = spirv_compiler_handle_instruction(spirv_compiler, &instruction)) < 0) - break; - } - - if (parser->failed) - ret = VKD3D_ERROR_INVALID_SHADER; + ret = spirv_compiler_handle_instructions(spirv_compiler, &parser->instructions);
if (ret >= 0) ret = spirv_compiler_generate_spirv(spirv_compiler, compile_info, out); @@ -1583,3 +1558,93 @@ 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(sizeof(*node) + allocator->count * allocator->stride))) + return NULL; + node->next = NULL; + return node; +} + +static bool 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 = shader_param_allocator_node_create(allocator); + allocator->current = allocator->head; + allocator->index = 0; + + return true; +} + +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 (allocator->index + count > allocator->count) + { + struct vkd3d_shader_param_node *next = shader_param_allocator_node_create(allocator); + 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. */ + return shader_instruction_array_reserve(instructions, reserve) + && 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)); +} + +bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *instructions, unsigned int extra) +{ + if (!vkd3d_array_reserve((void **)&instructions->elements, &instructions->capacity, + instructions->count + extra, sizeof(*instructions->elements))) + { + ERR("Failed to allocate instructions.\n"); + return false; + } + return true; +} + +void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions, bool destroy_instructions) +{ + unsigned int i; + + if (destroy_instructions) + { + for (i = 0; i < instructions->count; ++i) + if (instructions->elements[i].handler_idx == VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER) + vkd3d_free((void *)instructions->elements[i].declaration.icb); + } + vkd3d_free(instructions->elements); + shader_param_allocator_destroy(&instructions->dst_params); + shader_param_allocator_destroy(&instructions->src_params); +} diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 74edf049..6e5294ba 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -71,6 +71,7 @@ enum vkd3d_shader_error
VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF = 1000, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_RANGE = 1001, + VKD3D_SHADER_ERROR_TPF_OUT_OF_MEMORY = 1002,
VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_BINDING_NOT_FOUND = 2000, VKD3D_SHADER_ERROR_SPV_INVALID_REGISTER_TYPE = 2001, @@ -132,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, }; @@ -617,7 +619,6 @@ enum vkd3d_shader_conditional_op VKD3D_SHADER_CONDITIONAL_OP_Z = 1 };
-#define MAX_IMMEDIATE_CONSTANT_BUFFER_SIZE 4096 #define MAX_REG_OUTPUT 32
enum vkd3d_shader_type @@ -647,7 +648,7 @@ struct vkd3d_shader_version struct vkd3d_shader_immediate_constant_buffer { unsigned int vec4_count; - uint32_t data[MAX_IMMEDIATE_CONSTANT_BUFFER_SIZE]; + uint32_t data[]; };
struct vkd3d_shader_indexable_temp @@ -928,6 +929,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; + unsigned int 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 extra); +void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions, bool destroy_instructions); + struct vkd3d_shader_parser { struct vkd3d_shader_message_context *message_context; @@ -938,43 +984,38 @@ 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; };
struct vkd3d_shader_parser_ops { - void (*parser_reset)(struct vkd3d_shader_parser *parser); void (*parser_destroy)(struct vkd3d_shader_parser *parser); - void (*parser_read_instruction)(struct vkd3d_shader_parser *parser, struct vkd3d_shader_instruction *instruction); - bool (*parser_is_end)(struct vkd3d_shader_parser *parser); };
void vkd3d_shader_parser_error(struct vkd3d_shader_parser *parser, enum vkd3d_shader_error error, const char *format, ...) VKD3D_PRINTF_FUNC(3, 4); -void vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser, +bool vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser, struct vkd3d_shader_message_context *message_context, const char *source_name, - const struct vkd3d_shader_version *version, const struct vkd3d_shader_parser_ops *ops); + const struct vkd3d_shader_version *version, const struct vkd3d_shader_parser_ops *ops, + unsigned int instruction_reserve); void vkd3d_shader_parser_warning(struct vkd3d_shader_parser *parser, enum vkd3d_shader_error error, const char *format, ...) VKD3D_PRINTF_FUNC(3, 4);
-static inline void vkd3d_shader_parser_destroy(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) { - parser->ops->parser_destroy(parser); -} - -static inline bool vkd3d_shader_parser_is_end(struct vkd3d_shader_parser *parser) -{ - return parser->ops->parser_is_end(parser); + return shader_dst_param_allocator_get(&parser->instructions.dst_params, count); }
-static inline void vkd3d_shader_parser_read_instruction(struct vkd3d_shader_parser *parser, - struct vkd3d_shader_instruction *instruction) +static inline struct vkd3d_shader_src_param *shader_parser_get_src_params( + struct vkd3d_shader_parser *parser, unsigned int count) { - parser->ops->parser_read_instruction(parser, instruction); + return shader_src_param_allocator_get(&parser->instructions.src_params, count); }
-static inline void vkd3d_shader_parser_reset(struct vkd3d_shader_parser *parser) +static inline void vkd3d_shader_parser_destroy(struct vkd3d_shader_parser *parser) { - parser->ops->parser_reset(parser); + parser->ops->parser_destroy(parser); }
void vkd3d_shader_trace(struct vkd3d_shader_parser *parser); @@ -1096,8 +1137,8 @@ struct spirv_compiler *spirv_compiler_create(const struct vkd3d_shader_version * const struct vkd3d_shader_desc *shader_desc, const struct vkd3d_shader_compile_info *compile_info, const struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info, struct vkd3d_shader_message_context *message_context, const struct vkd3d_shader_location *location); -int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, - const struct vkd3d_shader_instruction *instruction); +int spirv_compiler_handle_instructions(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction_array *instructions); int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *spirv); void spirv_compiler_destroy(struct spirv_compiler *compiler);