SPIR-V doesn't support parallelisation in patch constant functions. Merging into one phase allows generation of a single patch constant function and normalises to the shader model 6 pattern.
-- v3: vkd3d-shader: Merge all shader fork and join phases into a single phase.
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);
From: Conor McCarthy cmccarthy@codeweavers.com
SPIR-V doesn't support parallelisation in patch constant functions. Merging into one phase allows generation of a single patch constant function and normalises to the shader model 6 pattern. --- libs/vkd3d-shader/spirv.c | 556 +++++++++++++++-------- libs/vkd3d-shader/vkd3d_shader_private.h | 5 + 2 files changed, 368 insertions(+), 193 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 2c06ffe9..95ef0cda 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2197,11 +2197,7 @@ struct vkd3d_push_constant_buffer_binding
struct vkd3d_shader_phase { - enum vkd3d_shader_opcode type; - unsigned int idx; - unsigned int instance_count; uint32_t function_id; - uint32_t instance_id; size_t function_location; };
@@ -2276,9 +2272,9 @@ struct spirv_compiler unsigned int output_control_point_count; bool use_vocp;
- unsigned int shader_phase_count; - struct vkd3d_shader_phase *shader_phases; - size_t shader_phases_size; + enum vkd3d_shader_opcode phase; + struct vkd3d_shader_phase control_point_phase; + struct vkd3d_shader_phase patch_constant_phase;
uint32_t current_spec_constant_id; unsigned int spec_constant_count; @@ -2289,9 +2285,19 @@ struct spirv_compiler struct vkd3d_string_buffer_cache string_buffers; };
-static bool is_control_point_phase(const struct vkd3d_shader_phase *phase) +static bool is_in_default_phase(const struct spirv_compiler *compiler) +{ + return compiler->phase == VKD3DSIH_INVALID; +} + +static bool is_in_control_point_phase(const struct spirv_compiler *compiler) +{ + return compiler->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE; +} + +static bool is_in_fork_or_join_phase(const struct spirv_compiler *compiler) { - return phase && phase->type == VKD3DSIH_HS_CONTROL_POINT_PHASE; + return compiler->phase == VKD3DSIH_HS_FORK_PHASE || compiler->phase == VKD3DSIH_HS_JOIN_PHASE; }
static void spirv_compiler_emit_initial_declarations(struct spirv_compiler *compiler); @@ -2431,6 +2437,8 @@ struct spirv_compiler *spirv_compiler_create(const struct vkd3d_shader_version *
compiler->scan_descriptor_info = scan_descriptor_info;
+ compiler->phase = VKD3DSIH_INVALID; + vkd3d_string_buffer_cache_init(&compiler->string_buffers);
spirv_compiler_emit_initial_declarations(compiler); @@ -2881,12 +2889,6 @@ static bool spirv_compiler_get_register_name(char *buffer, unsigned int buffer_s case VKD3DSPR_DEPTHOUTLE: snprintf(buffer, buffer_size, "oDepth"); break; - case VKD3DSPR_FORKINSTID: - snprintf(buffer, buffer_size, "vForkInstanceId"); - break; - case VKD3DSPR_JOININSTID: - snprintf(buffer, buffer_size, "vJoinInstanceId"); - break; case VKD3DSPR_GSINSTID: snprintf(buffer, buffer_size, "vGSInstanceID"); break; @@ -4296,7 +4298,7 @@ static uint32_t spirv_compiler_emit_load_invocation_id(struct spirv_compiler *co }
static void spirv_compiler_emit_shader_phase_name(struct spirv_compiler *compiler, - uint32_t id, const struct vkd3d_shader_phase *phase, const char *suffix) + uint32_t id, const char *suffix) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; const char *name; @@ -4304,7 +4306,7 @@ static void spirv_compiler_emit_shader_phase_name(struct spirv_compiler *compile if (!suffix) suffix = "";
- switch (phase->type) + switch (compiler->phase) { case VKD3DSIH_HS_CONTROL_POINT_PHASE: name = "control"; @@ -4316,58 +4318,19 @@ static void spirv_compiler_emit_shader_phase_name(struct spirv_compiler *compile name = "join"; break; default: - ERR("Invalid phase type %#x.\n", phase->type); + ERR("Invalid phase type %#x.\n", compiler->phase); return; } - vkd3d_spirv_build_op_name(builder, id, "%s%u%s", name, phase->idx, suffix); -} - -static void spirv_compiler_begin_shader_phase(struct spirv_compiler *compiler, - struct vkd3d_shader_phase *phase) -{ - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - uint32_t void_id, function_type_id; - unsigned int param_count; - uint32_t param_type_id; - - if (phase->instance_count) - { - param_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1); - param_count = 1; - } - else - { - param_count = 0; - } - - phase->function_id = vkd3d_spirv_alloc_id(builder); - - void_id = vkd3d_spirv_get_op_type_void(builder); - function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, ¶m_type_id, param_count); - vkd3d_spirv_build_op_function(builder, void_id, phase->function_id, - SpvFunctionControlMaskNone, function_type_id); - - if (phase->instance_count) - phase->instance_id = vkd3d_spirv_build_op_function_parameter(builder, param_type_id); - - vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder)); - phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream); - - spirv_compiler_emit_shader_phase_name(compiler, phase->function_id, phase, NULL); + vkd3d_spirv_build_op_name(builder, id, "%s%s", name, suffix); }
static const struct vkd3d_shader_phase *spirv_compiler_get_current_shader_phase( struct spirv_compiler *compiler) { - struct vkd3d_shader_phase *phase; - - if (!compiler->shader_phase_count) + if (is_in_default_phase(compiler)) return NULL;
- phase = &compiler->shader_phases[compiler->shader_phase_count - 1]; - if (!phase->function_id) - spirv_compiler_begin_shader_phase(compiler, phase); - return phase; + return is_in_control_point_phase(compiler) ? &compiler->control_point_phase : &compiler->patch_constant_phase; }
static void spirv_compiler_decorate_xfb_output(struct spirv_compiler *compiler, @@ -4764,12 +4727,9 @@ static void spirv_compiler_emit_input_register(struct spirv_compiler *compiler, }
static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compiler, - const struct vkd3d_shader_phase *phase, const struct vkd3d_shader_dst_param *dst) + const struct vkd3d_shader_dst_param *dst) { - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; const struct vkd3d_shader_register *reg = &dst->reg; - struct vkd3d_symbol reg_symbol; - uint32_t val_id;
switch (reg->type) { @@ -4781,10 +4741,6 @@ static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compil case VKD3DSPR_PRIMID: spirv_compiler_emit_input_register(compiler, dst); return; - case VKD3DSPR_FORKINSTID: - case VKD3DSPR_JOININSTID: - val_id = phase->instance_id; - break; case VKD3DSPR_OUTPOINTID: /* Emitted in spirv_compiler_emit_initial_declarations(). */ case VKD3DSPR_OUTCONTROLPOINT: /* See spirv_compiler_leave_shader_phase(). */ return; @@ -4792,13 +4748,6 @@ static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compil FIXME("Unhandled shader phase input register %#x.\n", reg->type); return; } - - vkd3d_symbol_make_register(®_symbol, reg); - vkd3d_symbol_set_register_info(®_symbol, val_id, - SpvStorageClassMax /* Intermediate value */, - VKD3D_SHADER_COMPONENT_UINT, VKD3DSP_WRITEMASK_0); - spirv_compiler_put_symbol(compiler, ®_symbol); - spirv_compiler_emit_register_debug_name(builder, val_id, reg); }
static unsigned int spirv_compiler_get_output_variable_index( @@ -4971,7 +4920,7 @@ static void spirv_compiler_emit_output_register(struct spirv_compiler *compiler, }
static uint32_t spirv_compiler_emit_shader_phase_builtin_variable(struct spirv_compiler *compiler, - const struct vkd3d_shader_phase *phase, const struct vkd3d_spirv_builtin *builtin) + const struct vkd3d_spirv_builtin *builtin) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t *variable_id, id; @@ -4987,7 +4936,7 @@ static uint32_t spirv_compiler_emit_shader_phase_builtin_variable(struct spirv_c return *variable_id;
id = spirv_compiler_emit_builtin_variable(compiler, builtin, SpvStorageClassOutput, 0); - if (phase->type == VKD3DSIH_HS_FORK_PHASE || phase->type == VKD3DSIH_HS_JOIN_PHASE) + if (is_in_fork_or_join_phase(compiler)) vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationPatch, NULL, 0);
if (variable_id) @@ -5005,7 +4954,6 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, unsigned int component_idx, output_component_count; enum vkd3d_shader_component_type component_type; const struct vkd3d_spirv_builtin *builtin; - const struct vkd3d_shader_phase *phase; struct vkd3d_symbol *symbol = NULL; bool use_private_variable = false; struct vkd3d_symbol reg_symbol; @@ -5017,12 +4965,11 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, bool is_patch_constant; uint32_t id, var_id;
- phase = spirv_compiler_get_current_shader_phase(compiler); - is_patch_constant = phase && (phase->type == VKD3DSIH_HS_FORK_PHASE || phase->type == VKD3DSIH_HS_JOIN_PHASE); + is_patch_constant = is_in_fork_or_join_phase(compiler);
shader_signature = is_patch_constant ? compiler->patch_constant_signature : compiler->output_signature;
- array_size = is_control_point_phase(phase) ? compiler->output_control_point_count : 0; + array_size = is_in_control_point_phase(compiler) ? compiler->output_control_point_count : 0;
if (!(signature_element = vkd3d_find_signature_element_for_reg(shader_signature, &signature_idx, reg->idx[0].offset, dst->write_mask))) @@ -5077,8 +5024,8 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, } else if (builtin) { - if (phase) - id = spirv_compiler_emit_shader_phase_builtin_variable(compiler, phase, builtin); + if (spirv_compiler_get_current_shader_phase(compiler)) + id = spirv_compiler_emit_shader_phase_builtin_variable(compiler, builtin); else id = spirv_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size);
@@ -5137,7 +5084,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, use_private_variable ? VKD3D_SHADER_COMPONENT_FLOAT : component_type, use_private_variable ? VKD3DSP_WRITEMASK_ALL : write_mask); reg_symbol.info.reg.is_aggregate = use_private_variable ? is_patch_constant : array_size; - if (!use_private_variable && is_control_point_phase(phase)) + if (!use_private_variable && is_in_control_point_phase(compiler)) { reg_symbol.info.reg.member_idx = spirv_compiler_get_invocation_id(compiler); reg_symbol.info.reg.is_dynamically_indexed = true; @@ -5289,7 +5236,6 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler * uint32_t void_id, type_id, ptr_type_id, function_type_id, function_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; const struct vkd3d_shader_signature *signature; - const struct vkd3d_shader_phase *phase; uint32_t output_index_id = 0; bool is_patch_constant; unsigned int i, count; @@ -5300,8 +5246,7 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler * STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(compiler->private_output_variable_array_idx)); STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(compiler->private_output_variable_write_mask));
- phase = spirv_compiler_get_current_shader_phase(compiler); - is_patch_constant = phase && (phase->type == VKD3DSIH_HS_FORK_PHASE || phase->type == VKD3DSIH_HS_JOIN_PHASE); + is_patch_constant = is_in_fork_or_join_phase(compiler);
signature = is_patch_constant ? compiler->patch_constant_signature : compiler->output_signature;
@@ -5334,7 +5279,7 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler * param_id[i] = vkd3d_spirv_build_op_load(builder, type_id, param_id[i], SpvMemoryAccessMaskNone); }
- if (is_control_point_phase(phase)) + if (is_in_control_point_phase(compiler)) output_index_id = spirv_compiler_emit_load_invocation_id(compiler);
for (i = 0; i < signature->element_count; ++i) @@ -6179,10 +6124,9 @@ static void spirv_compiler_emit_dcl_input(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { const struct vkd3d_shader_dst_param *dst = &instruction->declaration.dst; - const struct vkd3d_shader_phase *phase;
- if ((phase = spirv_compiler_get_current_shader_phase(compiler))) - spirv_compiler_emit_shader_phase_input(compiler, phase, dst); + if (spirv_compiler_get_current_shader_phase(compiler)) + spirv_compiler_emit_shader_phase_input(compiler, dst); else if (vkd3d_shader_register_is_input(&dst->reg) || dst->reg.type == VKD3DSPR_PATCHCONST) spirv_compiler_emit_input(compiler, dst, VKD3D_SIV_NONE, VKD3DSIM_NONE); else @@ -6481,8 +6425,7 @@ static void spirv_compiler_emit_dcl_thread_group(struct spirv_compiler *compiler SpvExecutionModeLocalSize, local_size, ARRAY_SIZE(local_size)); }
-static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler, - const struct vkd3d_shader_phase *phase) +static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler) { const struct vkd3d_shader_signature *signature = compiler->output_signature; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; @@ -6501,11 +6444,11 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler, * point phase. Reinsert symbols for vocp registers while leaving the * control point phase. */ - if (is_control_point_phase(phase)) + if (is_in_control_point_phase(compiler)) { if (compiler->epilogue_function_id) { - spirv_compiler_emit_shader_phase_name(compiler, compiler->epilogue_function_id, phase, "_epilogue"); + spirv_compiler_emit_shader_phase_name(compiler, compiler->epilogue_function_id, "_epilogue"); spirv_compiler_emit_shader_epilogue_function(compiler); }
@@ -6546,79 +6489,38 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler, } } } - - if (phase->instance_count) - { - memset(®, 0, sizeof(reg)); - reg.type = phase->type == VKD3DSIH_HS_FORK_PHASE ? VKD3DSPR_FORKINSTID : VKD3DSPR_JOININSTID; - reg.idx[0].offset = ~0u; - reg.idx[1].offset = ~0u; - vkd3d_symbol_make_register(®_symbol, ®); - if ((entry = rb_get(&compiler->symbol_table, ®_symbol))) - { - rb_remove(&compiler->symbol_table, entry); - vkd3d_symbol_free(entry, NULL); - } - } }
static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { - const struct vkd3d_shader_phase *previous_phase; + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t function_id, void_id, function_type_id; struct vkd3d_shader_phase *phase;
- if ((previous_phase = spirv_compiler_get_current_shader_phase(compiler))) - spirv_compiler_leave_shader_phase(compiler, previous_phase); - - if (!vkd3d_array_reserve((void **)&compiler->shader_phases, &compiler->shader_phases_size, - compiler->shader_phase_count + 1, sizeof(*compiler->shader_phases))) + if (is_in_fork_or_join_phase(compiler) && (instruction->handler_idx == VKD3DSIH_HS_JOIN_PHASE + || instruction->handler_idx == VKD3DSIH_HS_FORK_PHASE)) return; - phase = &compiler->shader_phases[compiler->shader_phase_count];
- phase->type = instruction->handler_idx; - phase->idx = compiler->shader_phase_count; - phase->instance_count = 0; - phase->function_id = 0; - phase->instance_id = 0; - phase->function_location = 0; + if (compiler->phase != VKD3DSIH_INVALID) + spirv_compiler_leave_shader_phase(compiler);
- ++compiler->shader_phase_count; -} - -static int spirv_compiler_emit_shader_phase_instance_count(struct spirv_compiler *compiler, - const struct vkd3d_shader_instruction *instruction) -{ - struct vkd3d_shader_phase *phase = &compiler->shader_phases[compiler->shader_phase_count - 1]; + function_id = vkd3d_spirv_alloc_id(builder);
- if (!compiler->shader_phase_count - || (phase->type != VKD3DSIH_HS_FORK_PHASE && phase->type != VKD3DSIH_HS_JOIN_PHASE) - || phase->function_id) - { - WARN("Unexpected dcl_hs_{fork,join}_phase_instance_count instruction.\n"); - return VKD3D_ERROR_INVALID_SHADER; - } - - phase->instance_count = instruction->declaration.count; - - spirv_compiler_begin_shader_phase(compiler, phase); - - return VKD3D_OK; -} - -static const struct vkd3d_shader_phase *spirv_compiler_get_control_point_phase( - struct spirv_compiler *compiler) -{ - const struct vkd3d_shader_phase *phase; + void_id = vkd3d_spirv_get_op_type_void(builder); + function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, NULL, 0); + vkd3d_spirv_build_op_function(builder, void_id, function_id, + SpvFunctionControlMaskNone, function_type_id);
- if (compiler->shader_phase_count < 1) - return NULL; + vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
- phase = &compiler->shader_phases[0]; - if (is_control_point_phase(phase)) - return phase; + compiler->phase = instruction->handler_idx; + spirv_compiler_emit_shader_phase_name(compiler, function_id, NULL);
- return NULL; + phase = (instruction->handler_idx == VKD3DSIH_HS_CONTROL_POINT_PHASE) + ? &compiler->control_point_phase : &compiler->patch_constant_phase; + phase->function_id = function_id; + phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream); }
static void spirv_compiler_emit_default_control_point_phase(struct spirv_compiler *compiler) @@ -6840,9 +6742,6 @@ static void spirv_compiler_emit_shader_epilogue_invocation(struct spirv_compiler static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_phase *control_point_phase, *phase; - uint32_t phase_instance_id; - unsigned int i, j; uint32_t void_id;
vkd3d_spirv_builder_begin_main_function(builder); @@ -6851,35 +6750,16 @@ static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler
void_id = vkd3d_spirv_get_op_type_void(builder);
- if ((control_point_phase = spirv_compiler_get_control_point_phase(compiler))) - vkd3d_spirv_build_op_function_call(builder, void_id, control_point_phase->function_id, NULL, 0); + if (compiler->control_point_phase.function_id) + vkd3d_spirv_build_op_function_call(builder, void_id, compiler->control_point_phase.function_id, NULL, 0); else spirv_compiler_emit_default_control_point_phase(compiler);
- if (compiler->use_vocp) - spirv_compiler_emit_hull_shader_barrier(compiler); - - for (i = 0; i < compiler->shader_phase_count; ++i) - { - phase = &compiler->shader_phases[i]; - if (is_control_point_phase(phase)) - continue; - - if (phase->instance_count) - { - for (j = 0; j < phase->instance_count; ++j) - { - phase_instance_id = spirv_compiler_get_constant_uint(compiler, j); - vkd3d_spirv_build_op_function_call(builder, - void_id, phase->function_id, &phase_instance_id, 1); - } - } - else - { - vkd3d_spirv_build_op_function_call(builder, void_id, phase->function_id, NULL, 0); - } - } - + /* TODO: only call the patch constant function for invocation 0. The simplest way + * is to avoid use of private variables there, otherwise we would need a separate + * patch constant epilogue also only called from invocation 0. */ + spirv_compiler_emit_hull_shader_barrier(compiler); + vkd3d_spirv_build_op_function_call(builder, void_id, compiler->patch_constant_phase.function_id, NULL, 0); spirv_compiler_emit_shader_epilogue_invocation(compiler); vkd3d_spirv_build_op_return(builder); vkd3d_spirv_build_op_function_end(builder); @@ -7561,10 +7441,10 @@ static uint32_t spirv_compiler_emit_conditional_branch(struct spirv_compiler *co static void spirv_compiler_emit_return(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { - const struct vkd3d_shader_phase *phase = spirv_compiler_get_current_shader_phase(compiler); struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
- if (compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY && (!phase || is_control_point_phase(phase))) + if (compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY && (is_in_default_phase(compiler) + || is_in_control_point_phase(compiler))) spirv_compiler_emit_shader_epilogue_invocation(compiler);
vkd3d_spirv_build_op_return(builder); @@ -9685,10 +9565,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_DCL_THREAD_GROUP: spirv_compiler_emit_dcl_thread_group(compiler, instruction); break; - case VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT: - case VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT: - ret = spirv_compiler_emit_shader_phase_instance_count(compiler, instruction); - break; case VKD3DSIH_HS_CONTROL_POINT_PHASE: case VKD3DSIH_HS_FORK_PHASE: case VKD3DSIH_HS_JOIN_PHASE: @@ -9933,15 +9809,311 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, return ret; }
+struct vkd3d_shader_normaliser +{ + struct vkd3d_shader_instruction_array instructions; + + unsigned int max_temp_count; + unsigned int temp_dcl_idx; + uint64_t temp_is_instance_id; + + unsigned int instance_count; + unsigned int phase_body_idx; + enum vkd3d_shader_opcode phase; +}; + +static inline bool shader_normaliser_reserve_instructions(struct vkd3d_shader_normaliser *normaliser, unsigned int extra) +{ + return shader_instruction_array_reserve(&normaliser->instructions, extra); +} + +static void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser) +{ + shader_instruction_array_destroy(&normaliser->instructions, false); +} + +static inline bool shader_src_param_is_phase_instance_id(const struct vkd3d_shader_src_param *param, + const struct vkd3d_shader_normaliser *normaliser) +{ + const struct vkd3d_shader_register *reg = ¶m->reg; + return vkd3d_shader_register_is_phase_instance_id(reg) || (reg->type == VKD3DSPR_TEMP + && !vkd3d_swizzle_get_component(param->swizzle, 0) + && (normaliser->temp_is_instance_id & (1ull << reg->idx[0].offset))); +} + +static void shader_register_eliminate_phase_addressing(struct vkd3d_shader_register *reg, + unsigned int instance_id, const struct vkd3d_shader_normaliser *normaliser) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(reg->idx) && reg->idx[i].offset != ~0u; ++i) + { + if (reg->idx[i].rel_addr && shader_src_param_is_phase_instance_id(reg->idx[i].rel_addr, normaliser)) + { + reg->idx[i].rel_addr = NULL; + reg->idx[i].offset += instance_id; + } + } +} + +static void shader_instruction_eliminate_phase_instance_id(struct vkd3d_shader_instruction *ins, + unsigned int instance_id, const struct vkd3d_shader_normaliser *normaliser) +{ + struct vkd3d_shader_register *reg; + unsigned int i; + + for (i = 0; i < ins->src_count; ++i) + { + reg = (struct vkd3d_shader_register *)&ins->src[i].reg; + if (shader_src_param_is_phase_instance_id(&ins->src[i], normaliser)) + { + reg->type = VKD3DSPR_IMMCONST; + reg->precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; + reg->non_uniform = false; + reg->data_type = VKD3D_DATA_UINT; + reg->idx[0].offset = ~0u; + reg->idx[0].rel_addr = NULL; + reg->idx[1].offset = ~0u; + reg->idx[1].rel_addr = NULL; + reg->idx[2].offset = ~0u; + reg->idx[2].rel_addr = NULL; + reg->immconst_type = VKD3D_IMMCONST_SCALAR; + reg->u.immconst_uint[0] = instance_id; + continue; + } + shader_register_eliminate_phase_addressing(reg, instance_id, normaliser); + } + + for (i = 0; i < ins->dst_count; ++i) + shader_register_eliminate_phase_addressing((struct vkd3d_shader_register *)&ins->dst[i].reg, + instance_id, normaliser); +} + +static bool shader_register_clone_relative_addresses(struct vkd3d_shader_register *reg, + struct vkd3d_shader_instruction_array *instructions) +{ + struct vkd3d_shader_src_param *src; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(reg->idx) && reg->idx[i].offset != ~0u; ++i) + { + if (!reg->idx[i].rel_addr) + continue; + + if (!(src = shader_src_param_allocator_get(&instructions->src_params, 1))) + return false; + + memcpy(src, reg->idx[i].rel_addr, sizeof(*src)); + reg->idx[i].rel_addr = src; + } + + return true; +} + +static bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions, + unsigned int dst, const struct vkd3d_shader_instruction *src) +{ + struct vkd3d_shader_instruction *ins = &instructions->elements[dst]; + struct vkd3d_shader_dst_param *dst_params; + struct vkd3d_shader_src_param *src_params; + unsigned int i; + + *ins = *src; + + if (ins->dst_count && ins->dst) + { + if (!(dst_params = shader_dst_param_allocator_get(&instructions->dst_params, ins->dst_count))) + return false; + + memcpy(dst_params, ins->dst, ins->dst_count * sizeof(*ins->dst)); + ins->dst = dst_params; + for (i = 0; i < ins->dst_count; ++i) + { + if (!shader_register_clone_relative_addresses(&dst_params[i].reg, instructions)) + return false; + } + } + if (ins->src_count) + { + if (!(src_params = shader_src_param_allocator_get(&instructions->src_params, ins->src_count))) + return false; + + memcpy(src_params, ins->src, ins->src_count * sizeof(*ins->src)); + ins->src = src_params; + for (i = 0; i < ins->src_count; ++i) + { + if (!shader_register_clone_relative_addresses(&src_params[i].reg, instructions)) + return false; + } + } + + return true; +} + +static enum vkd3d_result shader_normaliser_eliminate_phase_instance_id(struct vkd3d_shader_normaliser *normaliser, + unsigned int *instruction_count) +{ + struct vkd3d_shader_instruction *ins = &normaliser->instructions.elements[normaliser->instructions.count]; + unsigned int i, j, count; + + if (ins->handler_idx == VKD3DSIH_HS_FORK_PHASE || ins->handler_idx == VKD3DSIH_HS_JOIN_PHASE) + { + /* Leave the first occurrence and delete the rest. */ + *instruction_count = normaliser->phase != ins->handler_idx; + /* Reset the phase info. */ + normaliser->phase_body_idx = ~0u; + normaliser->phase = ins->handler_idx; + normaliser->instance_count = 1; + normaliser->temp_is_instance_id = 0; + return VKD3D_OK; + } + else if (ins->handler_idx == VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT + || ins->handler_idx == VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT) + { + normaliser->instance_count = ins->declaration.count + !ins->declaration.count; + *instruction_count = 0; + return VKD3D_OK; + } + else if (ins->handler_idx == VKD3DSIH_DCL_INPUT && vkd3d_shader_register_is_phase_instance_id( + &ins->declaration.dst.reg)) + { + *instruction_count = 0; + return VKD3D_OK; + } + else if (ins->handler_idx == VKD3DSIH_DCL_TEMPS && normaliser->phase != VKD3DSIH_INVALID) + { + /* Leave only the first temp declaration and set it to the max count later. */ + if (!normaliser->max_temp_count) + normaliser->temp_dcl_idx = normaliser->instructions.count; + else + *instruction_count = 0; + normaliser->max_temp_count = max(normaliser->max_temp_count, ins->declaration.count); + return VKD3D_OK; + } + + if (normaliser->phase == VKD3DSIH_INVALID || is_dcl_instruction(ins->handler_idx)) + return VKD3D_OK; + + if (ins->handler_idx == VKD3DSIH_MOV && vkd3d_shader_register_is_phase_instance_id(&ins->src->reg)) + { + if (ins->dst->reg.type != VKD3DSPR_TEMP) + { + FIXME("Instance id not assigned to temp register.\n"); + return VKD3D_OK; + } + /* Instance id always seems to be assigned to r{n}.x */ + if (ins->dst->write_mask != VKD3DSP_WRITEMASK_0) + FIXME("Unsupported write mask %#x.\n", ins->dst->write_mask); + if (ins->dst->reg.idx[0].offset >= sizeof(normaliser->temp_is_instance_id) * CHAR_BIT) + FIXME("Unsupported temp idx %u.\n", ins->dst->reg.idx[0].offset); + else + normaliser->temp_is_instance_id |= 1ull << ins->dst->reg.idx[0].offset; + *instruction_count = 0; + return VKD3D_OK; + } + + if (normaliser->phase_body_idx == ~0u) + normaliser->phase_body_idx = normaliser->instructions.count; + + if (ins->handler_idx != VKD3DSIH_RET) + return VKD3D_OK; + + count = normaliser->instructions.count - normaliser->phase_body_idx; + + if (!shader_instruction_array_reserve(&normaliser->instructions, count * (normaliser->instance_count - 1))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + /* Make a copy of the non-dcl instructions for each instance. */ + ins = &normaliser->instructions.elements[normaliser->phase_body_idx]; + for (i = 1; i < normaliser->instance_count; ++i) + { + for (j = 0; j < count; ++j) + { + if (!shader_instruction_array_clone_instruction(&normaliser->instructions, + normaliser->phase_body_idx + count * i + j, &ins[j])) + return VKD3D_ERROR_OUT_OF_MEMORY; + } + } + /* Replace each reference to the instance id with a constant instance id. */ + for (i = 0; i < normaliser->instance_count; ++i) + { + for (j = 0; j < count; ++j) + shader_instruction_eliminate_phase_instance_id( + &normaliser->instructions.elements[normaliser->phase_body_idx + count * i + j], i, normaliser); + } + + *instruction_count = count * (normaliser->instance_count - 1); + return VKD3D_OK; +} + +static enum vkd3d_result shader_instruction_array_normalise(const struct vkd3d_shader_instruction_array *instructions, + struct vkd3d_shader_normaliser *normaliser) +{ + enum vkd3d_result result = VKD3D_OK; + unsigned int i, instruction_count; + + memset(normaliser, 0, sizeof(*normaliser)); + normaliser->phase = VKD3DSIH_INVALID; + if (!shader_instruction_array_init(&normaliser->instructions, instructions->count)) + { + ERR("Failed to allocate instructions.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + for (i = 0; i < instructions->count; ++i) + { + if (!shader_normaliser_reserve_instructions(normaliser, 1)) + { + result = VKD3D_ERROR_OUT_OF_MEMORY; + break; + } + + if (!shader_instruction_array_clone_instruction(&normaliser->instructions, normaliser->instructions.count, + &instructions->elements[i])) + { + result = VKD3D_ERROR_OUT_OF_MEMORY; + break; + } + + instruction_count = 1; + if ((result = shader_normaliser_eliminate_phase_instance_id(normaliser, &instruction_count)) < 0) + break; + + normaliser->instructions.count += instruction_count; + } + + if (result >= 0 && normaliser->phase != VKD3DSIH_INVALID) + { + if (normaliser->temp_dcl_idx) + normaliser->instructions.elements[normaliser->temp_dcl_idx].declaration.count = normaliser->max_temp_count; + if (!shader_normaliser_reserve_instructions(normaliser, 1)) + result = VKD3D_ERROR_OUT_OF_MEMORY; + else + normaliser->instructions.elements[normaliser->instructions.count++].handler_idx = VKD3DSIH_RET; + } + + return result; +} + int spirv_compiler_handle_instructions(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction_array *instructions) { + struct vkd3d_shader_normaliser normaliser; enum vkd3d_result result = VKD3D_OK; unsigned int i;
+ if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) + { + result = shader_instruction_array_normalise(instructions, &normaliser); + instructions = &normaliser.instructions; + } + for (i = 0; i < instructions->count && result >= 0; ++i) result = spirv_compiler_handle_instruction(compiler, &instructions->elements[i]);
+ if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) + shader_normaliser_destroy(&normaliser); + return result; }
@@ -9951,10 +10123,9 @@ int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info; const struct vkd3d_shader_spirv_domain_shader_target_info *ds_info; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_phase *phase;
- if ((phase = spirv_compiler_get_current_shader_phase(compiler))) - spirv_compiler_leave_shader_phase(compiler, phase); + if (!is_in_default_phase(compiler)) + spirv_compiler_leave_shader_phase(compiler); else vkd3d_spirv_build_op_function_end(builder);
@@ -10022,7 +10193,6 @@ void spirv_compiler_destroy(struct spirv_compiler *compiler)
rb_destroy(&compiler->symbol_table, vkd3d_symbol_free, NULL);
- vkd3d_free(compiler->shader_phases); vkd3d_free(compiler->spec_constants);
vkd3d_string_buffer_cache_cleanup(&compiler->string_buffers); diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 6e5294ba..16be7e29 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -923,6 +923,11 @@ static inline bool vkd3d_shader_register_is_output(const struct vkd3d_shader_reg return reg->type == VKD3DSPR_OUTPUT || reg->type == VKD3DSPR_COLOROUT; }
+static inline bool vkd3d_shader_register_is_phase_instance_id(const struct vkd3d_shader_register *reg) +{ + return reg->type == VKD3DSPR_FORKINSTID || reg->type == VKD3DSPR_JOININSTID; +} + struct vkd3d_shader_location { const char *source_name;
Broadly this seems in the right direction. Patch 1/2 should be split though; for example:
- Parse d3dbc bytecode up-front into a shader instruction array. This could keep the existing vkd3d_shader_parser interface, and just iterate over the instruction in the array in shader_sm1_read_instruction(). shader_sm1_reset() and shader_sm1_is_end() would have obvious implementations as well. - Do the same for vkd3d_shader_sm4_parser. - Use the instruction array interface in vkd3d_dxbc_binary_to_text() - Likewise for scan_with_parser(). - The GLSL backend. - The SPIR-V backend.
That's 6 separate parts right there; it seems plausible that the vkd3d_shader_sm1_parser and vkd3d_shader_sm4_parser parts could be further split, but I haven't looked that close yet.
+ if (!shader_instruction_array_reserve(instructions, 1)) + { + ... + } + ins = &instructions->elements[instructions->count];
shader_instruction_array_reserve() seems a bit awkward, in part because of the similarity in name to vkd3d_array_reserve(), which gets passed the total size to reserve. It might be nicer to do something like "shader_instruction_array_reserve(instructions, instructions->count + 1)".
+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; +};
It seems odd to use different types for "capacity" and "count" above. Could we use size_t for both?
Patch 2/2 is a "vkd3d-shader/spirv" patch. I'd probably reframe it as doing the existing transformation on the vkd3d_shader_instruction IR instead of during translation to SPIR-V.
- 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);
It's somewhat tangential to this series, but I think we should pass "parser" to spirv_compiler_generate_spirv(), and then just fold spirv_compiler_handle_instructions() into spirv_compiler_generate_spirv(), analogous to vkd3d_glsl_generator_generate().