From 10e8e5d62381bc132ac64fd9a5a7f1e39b3c843b Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 3 Oct 2024 10:05:51 +1000 Subject: [PATCH] Updated vkd3d to ae27fded1a039fda84b526cd9bd7b64aeb5573b5. --- libs/vkd3d/include/vkd3d_shader.h | 78 ++++- libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 37 ++- libs/vkd3d/libs/vkd3d-shader/fx.c | 172 ++++++++--- libs/vkd3d/libs/vkd3d-shader/glsl.c | 75 ++++- libs/vkd3d/libs/vkd3d-shader/hlsl.c | 106 ++++++- libs/vkd3d/libs/vkd3d-shader/hlsl.h | 24 +- libs/vkd3d/libs/vkd3d-shader/hlsl.y | 146 +++++---- libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 32 +- libs/vkd3d/libs/vkd3d-shader/ir.c | 281 +++++++++++++++++- libs/vkd3d/libs/vkd3d-shader/spirv.c | 131 +++++--- libs/vkd3d/libs/vkd3d-shader/tpf.c | 47 ++- .../libs/vkd3d-shader/vkd3d_shader_private.h | 3 + 12 files changed, 945 insertions(+), 187 deletions(-) diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h index 115bb21b932..d08ee74a3a0 100644 --- a/libs/vkd3d/include/vkd3d_shader.h +++ b/libs/vkd3d/include/vkd3d_shader.h @@ -480,8 +480,8 @@ enum vkd3d_shader_parameter_type /** The parameter value is embedded directly in the shader. */ VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT, /** - * The parameter value is provided to the shader via a specialization - * constant. This value is only supported for the SPIR-V target type. + * The parameter value is provided to the shader via specialization + * constants. This value is only supported for the SPIR-V target type. */ VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT, /** @@ -506,6 +506,13 @@ enum vkd3d_shader_parameter_data_type VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32, /** The parameter is provided as a 32-bit float. \since 1.13 */ VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32, + /** + * The parameter is provided as a 4-dimensional vector of 32-bit floats. + * This parameter must be used with struct vkd3d_shader_parameter1; + * it cannot be used with struct vkd3d_shader_parameter. + * \since 1.14 + */ + VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4, VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_DATA_TYPE), }; @@ -589,6 +596,58 @@ enum vkd3d_shader_parameter_name * \since 1.13 */ VKD3D_SHADER_PARAMETER_NAME_FLAT_INTERPOLATION, + /** + * A mask of enabled clip planes. + * + * When this parameter is provided to a vertex shader, for each nonzero bit + * of this mask, a user clip distance will be generated from vertex position + * in clip space, and the clip plane defined by the indexed vector, taken + * from the VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_# parameter. + * + * Regardless of the specific clip planes which are enabled, the clip + * distances which are output are a contiguous array starting from clip + * distance 0. This affects the interface of OpenGL. For example, if only + * clip planes 1 and 3 are enabled (and so the value of the mask is 0xa), + * the user should enable only GL_CLIP_DISTANCE0 and GL_CLIP_DISTANCE1. + * + * The default value is zero, i.e. do not enable any clip planes. + * + * The data type for this parameter must be + * VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32. + * + * Only VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT is supported in this + * version of vkd3d-shader. + * + * If the source shader writes clip distances and this parameter is nonzero, + * compilation fails. + * + * \since 1.14 + */ + VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_MASK, + /** + * Clip plane values. + * See VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_MASK for documentation of + * clip planes. + * + * These enum values are contiguous and arithmetic may safely be performed + * on them. That is, VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_[n] is + * VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_0 plus n. + * + * The data type for each parameter must be + * VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4. + * + * The default value for each plane is a (0, 0, 0, 0) vector. + * + * \since 1.14 + */ + VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_0, + VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_1, + VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_2, + VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_3, + VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_4, + VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_5, + VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_6, + VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_7, VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_NAME), }; @@ -636,6 +695,13 @@ struct vkd3d_shader_parameter_immediate_constant1 * VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32. */ float f32; + /** + * A pointer to the value if the parameter's data type is + * VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4. + * + * \since 1.14 + */ + float f32_vec4[4]; void *_pointer_pad; uint32_t _pad[4]; } u; @@ -647,7 +713,13 @@ struct vkd3d_shader_parameter_immediate_constant1 */ struct vkd3d_shader_parameter_specialization_constant { - /** The ID of the specialization constant. */ + /** + * The ID of the specialization constant. + * If the type comprises more than one constant, such as + * VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4, then a contiguous + * array of specialization constants should be used, one for each component, + * and this ID should point to the first component. + */ uint32_t id; }; diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c index 763d52e1b62..267cf410cbe 100644 --- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c @@ -457,17 +457,36 @@ static uint32_t swizzle_from_sm1(uint32_t swizzle) shader_sm1_get_swizzle_component(swizzle, 3)); } +/* D3DBC doesn't have the concept of index count. All registers implicitly have + * exactly one index. However for some register types the index doesn't make + * sense, so we remove it. */ +static unsigned int idx_count_from_reg_type(enum vkd3d_shader_register_type reg_type) +{ + switch (reg_type) + { + case VKD3DSPR_DEPTHOUT: + return 0; + + default: + return 1; + } +} + static void shader_sm1_parse_src_param(uint32_t param, struct vkd3d_shader_src_param *rel_addr, struct vkd3d_shader_src_param *src) { enum vkd3d_shader_register_type reg_type = ((param & VKD3D_SM1_REGISTER_TYPE_MASK) >> VKD3D_SM1_REGISTER_TYPE_SHIFT) | ((param & VKD3D_SM1_REGISTER_TYPE_MASK2) >> VKD3D_SM1_REGISTER_TYPE_SHIFT2); + unsigned int idx_count = idx_count_from_reg_type(reg_type); - vsir_register_init(&src->reg, reg_type, VKD3D_DATA_FLOAT, 1); + vsir_register_init(&src->reg, reg_type, VKD3D_DATA_FLOAT, idx_count); src->reg.precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; src->reg.non_uniform = false; - src->reg.idx[0].offset = param & VKD3D_SM1_REGISTER_NUMBER_MASK; - src->reg.idx[0].rel_addr = rel_addr; + if (idx_count == 1) + { + src->reg.idx[0].offset = param & VKD3D_SM1_REGISTER_NUMBER_MASK; + src->reg.idx[0].rel_addr = rel_addr; + } if (src->reg.type == VKD3DSPR_SAMPLER) src->reg.dimension = VSIR_DIMENSION_NONE; else if (src->reg.type == VKD3DSPR_DEPTHOUT) @@ -483,12 +502,16 @@ static void shader_sm1_parse_dst_param(uint32_t param, struct vkd3d_shader_src_p { enum vkd3d_shader_register_type reg_type = ((param & VKD3D_SM1_REGISTER_TYPE_MASK) >> VKD3D_SM1_REGISTER_TYPE_SHIFT) | ((param & VKD3D_SM1_REGISTER_TYPE_MASK2) >> VKD3D_SM1_REGISTER_TYPE_SHIFT2); + unsigned int idx_count = idx_count_from_reg_type(reg_type); - vsir_register_init(&dst->reg, reg_type, VKD3D_DATA_FLOAT, 1); + vsir_register_init(&dst->reg, reg_type, VKD3D_DATA_FLOAT, idx_count); dst->reg.precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; dst->reg.non_uniform = false; - dst->reg.idx[0].offset = param & VKD3D_SM1_REGISTER_NUMBER_MASK; - dst->reg.idx[0].rel_addr = rel_addr; + if (idx_count == 1) + { + dst->reg.idx[0].offset = param & VKD3D_SM1_REGISTER_NUMBER_MASK; + dst->reg.idx[0].rel_addr = rel_addr; + } if (dst->reg.type == VKD3DSPR_SAMPLER) dst->reg.dimension = VSIR_DIMENSION_NONE; else if (dst->reg.type == VKD3DSPR_DEPTHOUT) @@ -614,7 +637,7 @@ static bool add_signature_element_from_register(struct vkd3d_shader_sm1_parser * const struct vkd3d_shader_register *reg, bool is_dcl, unsigned int mask) { const struct vkd3d_shader_version *version = &sm1->p.program->shader_version; - unsigned int register_index = reg->idx[0].offset; + unsigned int register_index = reg->idx_count > 0 ? reg->idx[0].offset : 0; switch (reg->type) { diff --git a/libs/vkd3d/libs/vkd3d-shader/fx.c b/libs/vkd3d/libs/vkd3d-shader/fx.c index 84e827e7943..cc18857a010 100644 --- a/libs/vkd3d/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d/libs/vkd3d-shader/fx.c @@ -182,6 +182,7 @@ struct fx_write_context struct vkd3d_bytecode_buffer unstructured; struct vkd3d_bytecode_buffer structured; + struct vkd3d_bytecode_buffer objects; struct rb_tree strings; struct list types; @@ -1072,19 +1073,63 @@ static uint32_t write_fx_2_default_value(struct hlsl_type *value_type, struct hl return offset; } -static uint32_t write_fx_2_initial_value(const struct hlsl_ir_var *var, struct fx_write_context *fx) +static uint32_t write_fx_2_object_initializer(const struct hlsl_ir_var *var, struct fx_write_context *fx) { - struct vkd3d_bytecode_buffer *buffer = &fx->unstructured; - const struct hlsl_type *type = var->data_type; - uint32_t offset, elements_count = 1; + const struct hlsl_type *type = hlsl_get_multiarray_element_type(var->data_type); + unsigned int i, elements_count = hlsl_get_multiarray_size(var->data_type); + struct vkd3d_bytecode_buffer *buffer = &fx->objects; + uint32_t offset = fx->unstructured.size, id, size; struct hlsl_ctx *ctx = fx->ctx; + const void *data; - if (type->class == HLSL_CLASS_ARRAY) + for (i = 0; i < elements_count; ++i) { - elements_count = hlsl_get_multiarray_size(type); - type = hlsl_get_multiarray_element_type(type); + if (type->class == HLSL_CLASS_SAMPLER) + { + hlsl_fixme(ctx, &var->loc, "Writing fx_2_0 sampler objects initializers is not implemented."); + } + else + { + switch (type->class) + { + case HLSL_CLASS_STRING: + { + const char *string = var->default_values[i].string ? var->default_values[i].string : ""; + size = strlen(string) + 1; + data = string; + break; + } + case HLSL_CLASS_TEXTURE: + size = 0; + break; + case HLSL_CLASS_PIXEL_SHADER: + case HLSL_CLASS_VERTEX_SHADER: + size = 0; + hlsl_fixme(ctx, &var->loc, "Writing fx_2_0 shader objects initializers is not implemented."); + break; + default: + vkd3d_unreachable(); + } + id = fx->object_variable_count++; + + put_u32(&fx->unstructured, id); + + put_u32(buffer, id); + put_u32(buffer, size); + if (size) + bytecode_put_bytes(buffer, data, size); + } } + return offset; +} + +static uint32_t write_fx_2_initial_value(const struct hlsl_ir_var *var, struct fx_write_context *fx) +{ + const struct hlsl_type *type = hlsl_get_multiarray_element_type(var->data_type); + struct hlsl_ctx *ctx = fx->ctx; + uint32_t offset; + /* Note that struct fields must all be numeric; * this was validated in check_invalid_object_fields(). */ switch (type->class) @@ -1096,19 +1141,17 @@ static uint32_t write_fx_2_initial_value(const struct hlsl_ir_var *var, struct f offset = write_fx_2_default_value(var->data_type, var->default_values, fx); break; - case HLSL_CLASS_TEXTURE: - case HLSL_CLASS_PIXEL_SHADER: case HLSL_CLASS_SAMPLER: + case HLSL_CLASS_TEXTURE: case HLSL_CLASS_STRING: + case HLSL_CLASS_PIXEL_SHADER: case HLSL_CLASS_VERTEX_SHADER: - hlsl_fixme(ctx, &var->loc, "Write fx 2.0 object initializer."); - /* fallthrough */ + offset = write_fx_2_object_initializer(var, fx); + break; default: - /* Objects are given sequential ids. */ - offset = put_u32(buffer, fx->object_variable_count++); - for (uint32_t i = 1; i < elements_count; ++i) - put_u32(buffer, fx->object_variable_count++); + offset = 0; + hlsl_fixme(ctx, &var->loc, "Writing initializer not implemented for parameter class %#x.", type->class); break; } @@ -1134,6 +1177,7 @@ static bool is_type_supported_fx_2(struct hlsl_ctx *ctx, const struct hlsl_type return is_type_supported_fx_2(ctx, type->e.array.type, loc); case HLSL_CLASS_TEXTURE: + case HLSL_CLASS_SAMPLER: switch (type->sampler_dim) { case HLSL_SAMPLER_DIM_1D: @@ -1147,9 +1191,10 @@ static bool is_type_supported_fx_2(struct hlsl_ctx *ctx, const struct hlsl_type } break; - case HLSL_CLASS_PIXEL_SHADER: - case HLSL_CLASS_SAMPLER: case HLSL_CLASS_STRING: + return true; + + case HLSL_CLASS_PIXEL_SHADER: case HLSL_CLASS_VERTEX_SHADER: hlsl_fixme(ctx, loc, "Write fx 2.0 parameter class %#x.", type->class); return false; @@ -1257,19 +1302,18 @@ static int hlsl_fx_2_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) object_count = put_u32(structured, 0); write_fx_2_parameters(&fx); - set_u32(structured, parameter_count, fx.parameter_count); - set_u32(structured, object_count, fx.object_variable_count); - write_techniques(ctx->globals, &fx); - set_u32(structured, technique_count, fx.technique_count); - set_u32(structured, shader_count, fx.shader_count); - - put_u32(structured, 0); /* String count */ + put_u32(structured, fx.object_variable_count - 1); put_u32(structured, 0); /* Resource count */ - /* TODO: strings */ + bytecode_put_bytes(structured, fx.objects.data, fx.objects.size); /* TODO: resources */ + set_u32(structured, parameter_count, fx.parameter_count); + set_u32(structured, object_count, fx.object_variable_count); + set_u32(structured, technique_count, fx.technique_count); + set_u32(structured, shader_count, fx.shader_count); + size = align(fx.unstructured.size, 4); set_u32(&buffer, offset, size); @@ -1278,6 +1322,7 @@ static int hlsl_fx_2_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) vkd3d_free(fx.unstructured.data); vkd3d_free(fx.structured.data); + vkd3d_free(fx.objects.data); if (!fx.technique_count) hlsl_error(ctx, &ctx->location, VKD3D_SHADER_ERROR_HLSL_MISSING_TECHNIQUE, "No techniques found."); @@ -1516,11 +1561,14 @@ static uint32_t write_fx_4_state_numeric_value(struct hlsl_ir_constant *value, s static void write_fx_4_state_assignment(const struct hlsl_ir_var *var, struct hlsl_state_block_entry *entry, struct fx_write_context *fx) { - uint32_t value_offset = 0, assignment_type = 0, rhs_offset; - uint32_t type_offset; + uint32_t value_offset = 0, assignment_type = 0, rhs_offset, type_offset, offset; + struct vkd3d_bytecode_buffer *unstructured = &fx->unstructured; struct vkd3d_bytecode_buffer *buffer = &fx->structured; - struct hlsl_ctx *ctx = fx->ctx; struct hlsl_ir_node *value = entry->args->node; + struct hlsl_ctx *ctx = fx->ctx; + struct hlsl_ir_var *index_var; + struct hlsl_ir_constant *c; + struct hlsl_ir_load *load; put_u32(buffer, entry->name_id); put_u32(buffer, entry->lhs_index); @@ -1531,7 +1579,7 @@ static void write_fx_4_state_assignment(const struct hlsl_ir_var *var, struct hl { case HLSL_IR_CONSTANT: { - struct hlsl_ir_constant *c = hlsl_ir_constant(value); + c = hlsl_ir_constant(value); value_offset = write_fx_4_state_numeric_value(c, fx); assignment_type = 1; @@ -1539,15 +1587,71 @@ static void write_fx_4_state_assignment(const struct hlsl_ir_var *var, struct hl } case HLSL_IR_LOAD: { - struct hlsl_ir_load *l = hlsl_ir_load(value); + load = hlsl_ir_load(value); - if (l->src.path_len) + if (load->src.path_len) hlsl_fixme(ctx, &var->loc, "Indexed access in RHS values is not implemented."); - value_offset = write_fx_4_string(l->src.var->name, fx); + value_offset = write_fx_4_string(load->src.var->name, fx); assignment_type = 2; break; } + case HLSL_IR_INDEX: + { + struct hlsl_ir_index *index = hlsl_ir_index(value); + struct hlsl_ir_node *val = index->val.node; + struct hlsl_ir_node *idx = index->idx.node; + struct hlsl_type *type; + + if (val->type != HLSL_IR_LOAD) + { + hlsl_fixme(ctx, &var->loc, "Unexpected indexed RHS value type."); + break; + } + + load = hlsl_ir_load(val); + value_offset = write_fx_4_string(load->src.var->name, fx); + type = load->src.var->data_type; + + switch (idx->type) + { + case HLSL_IR_CONSTANT: + { + c = hlsl_ir_constant(idx); + value_offset = put_u32(unstructured, value_offset); + put_u32(unstructured, c->value.u[0].u); + assignment_type = 3; + + if (c->value.u[0].u >= type->e.array.elements_count) + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_OFFSET_OUT_OF_BOUNDS, + "Array index %u exceeds array size %u.", c->value.u[0].u, type->e.array.elements_count); + break; + } + + case HLSL_IR_LOAD: + { + load = hlsl_ir_load(idx); + index_var = load->src.var; + + /* Special case for uint index variables, for anything more complex use an expression. */ + if (hlsl_types_are_equal(index_var->data_type, hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT)) + && !load->src.path_len) + { + offset = write_fx_4_string(index_var->name, fx); + + value_offset = put_u32(unstructured, value_offset); + put_u32(unstructured, offset); + assignment_type = 4; + break; + } + } + /* fall through */ + + default: + hlsl_fixme(ctx, &var->loc, "Complex array index expressions in RHS values are not implemented."); + } + break; + } default: hlsl_fixme(ctx, &var->loc, "Unsupported assignment type for state %s.", entry->name); } @@ -2196,7 +2300,7 @@ static unsigned int decompose_fx_4_state_function_call(struct hlsl_ir_var *var, const struct function_component *comp = &components[i]; unsigned int arg_index = (i + 1) % entry->args_count; block->entries[entry_index + i] = clone_stateblock_entry(ctx, entry, comp->name, - comp->lhs_has_index, comp->lhs_index, arg_index); + comp->lhs_has_index, comp->lhs_index, true, arg_index); } hlsl_free_state_block_entry(entry); @@ -2242,7 +2346,7 @@ static unsigned int decompose_fx_4_state_block_expand_array(struct hlsl_ir_var * for (i = 1; i < array_size; ++i) { block->entries[entry_index + i] = clone_stateblock_entry(ctx, entry, - entry->name, true, i, 0); + entry->name, true, i, true, 0); } return array_size; diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c index 26fd4818970..e2bcca56f05 100644 --- a/libs/vkd3d/libs/vkd3d-shader/glsl.c +++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c @@ -365,18 +365,21 @@ static void VKD3D_PRINTF_FUNC(3, 4) shader_glsl_print_assignment( { const struct vkd3d_shader_register *dst_reg = &dst->vsir->reg; struct vkd3d_string_buffer *buffer = gen->buffer; + uint32_t modifiers = dst->vsir->modifiers; bool close = true; va_list args; if (dst->vsir->shift) vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, "Internal compiler error: Unhandled destination shift %#x.", dst->vsir->shift); - if (dst->vsir->modifiers) + if (modifiers & ~VKD3DSPDM_SATURATE) vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, - "Internal compiler error: Unhandled destination modifier(s) %#x.", dst->vsir->modifiers); + "Internal compiler error: Unhandled destination modifier(s) %#x.", modifiers); shader_glsl_print_indent(buffer, gen->indent); vkd3d_string_buffer_printf(buffer, "%s%s = ", dst->register_name->buffer, dst->mask->buffer); + if (modifiers & VKD3DSPDM_SATURATE) + vkd3d_string_buffer_printf(buffer, "clamp("); switch (dst_reg->data_type) { @@ -399,7 +402,11 @@ static void VKD3D_PRINTF_FUNC(3, 4) shader_glsl_print_assignment( vkd3d_string_buffer_vprintf(buffer, format, args); va_end(args); - vkd3d_string_buffer_printf(buffer, "%s;\n", close ? ")" : ""); + if (close) + vkd3d_string_buffer_printf(buffer, ")"); + if (modifiers & VKD3DSPDM_SATURATE) + vkd3d_string_buffer_printf(buffer, ", 0.0, 1.0)"); + vkd3d_string_buffer_printf(buffer, ";\n"); } static void shader_glsl_unhandled(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) @@ -455,16 +462,24 @@ static void shader_glsl_dot(struct vkd3d_glsl_generator *gen, static void shader_glsl_intrinsic(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins, const char *op) { + struct vkd3d_string_buffer *args; struct glsl_src src; struct glsl_dst dst; + unsigned int i; uint32_t mask; mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]); - glsl_src_init(&src, gen, &ins->src[0], mask); + args = vkd3d_string_buffer_get(&gen->string_buffers); - shader_glsl_print_assignment(gen, &dst, "%s(%s)", op, src.str->buffer); + for (i = 0; i < ins->src_count; ++i) + { + glsl_src_init(&src, gen, &ins->src[i], mask); + vkd3d_string_buffer_printf(args, "%s%s", i ? ", " : "", src.str->buffer); + glsl_src_cleanup(&src, &gen->string_buffers); + } + shader_glsl_print_assignment(gen, &dst, "%s(%s)", op, args->buffer); - glsl_src_cleanup(&src, &gen->string_buffers); + vkd3d_string_buffer_release(&gen->string_buffers, args); glsl_dst_cleanup(&dst, &gen->string_buffers); } @@ -532,6 +547,13 @@ static void shader_glsl_if(struct vkd3d_glsl_generator *gen, const struct vkd3d_ ++gen->indent; } +static void shader_glsl_else(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) +{ + unsigned int i = 4 * (gen->indent - 1); + + vkd3d_string_buffer_printf(gen->buffer, "%*s}\n%*selse\n%*s{\n", i, "", i, "", i, ""); +} + static void shader_glsl_endif(struct vkd3d_glsl_generator *gen) { --gen->indent; @@ -539,6 +561,22 @@ static void shader_glsl_endif(struct vkd3d_glsl_generator *gen) vkd3d_string_buffer_printf(gen->buffer, "}\n"); } +static void shader_glsl_unary_op(struct vkd3d_glsl_generator *gen, + const struct vkd3d_shader_instruction *ins, const char *op) +{ + struct glsl_src src; + struct glsl_dst dst; + uint32_t mask; + + mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]); + glsl_src_init(&src, gen, &ins->src[0], mask); + + shader_glsl_print_assignment(gen, &dst, "%s%s", op, src.str->buffer); + + glsl_src_cleanup(&src, &gen->string_buffers); + glsl_dst_cleanup(&dst, &gen->string_buffers); +} + static void shader_glsl_mov(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) { struct glsl_src src; @@ -757,6 +795,9 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, case VKD3DSIH_DP4: shader_glsl_dot(gen, ins, VKD3DSP_WRITEMASK_ALL); break; + case VKD3DSIH_ELSE: + shader_glsl_else(gen, ins); + break; case VKD3DSIH_ENDIF: shader_glsl_endif(gen); break; @@ -781,9 +822,25 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, case VKD3DSIH_IF: shader_glsl_if(gen, ins); break; + case VKD3DSIH_MAD: + shader_glsl_intrinsic(gen, ins, "fma"); + break; + case VKD3DSIH_ISHL: + shader_glsl_binop(gen, ins, "<<"); + break; + case VKD3DSIH_ISHR: + case VKD3DSIH_USHR: + shader_glsl_binop(gen, ins, ">>"); + break; case VKD3DSIH_LTO: shader_glsl_relop(gen, ins, "<", "lessThan"); break; + case VKD3DSIH_MAX: + shader_glsl_intrinsic(gen, ins, "max"); + break; + case VKD3DSIH_MIN: + shader_glsl_intrinsic(gen, ins, "min"); + break; case VKD3DSIH_INE: case VKD3DSIH_NEU: shader_glsl_relop(gen, ins, "!=", "notEqual"); @@ -804,6 +861,9 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, case VKD3DSIH_MUL: shader_glsl_binop(gen, ins, "*"); break; + case VKD3DSIH_NOT: + shader_glsl_unary_op(gen, ins, "~"); + break; case VKD3DSIH_OR: shader_glsl_binop(gen, ins, "|"); break; @@ -822,6 +882,9 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, case VKD3DSIH_ROUND_Z: shader_glsl_intrinsic(gen, ins, "trunc"); break; + case VKD3DSIH_RSQ: + shader_glsl_intrinsic(gen, ins, "inversesqrt"); + break; case VKD3DSIH_SQRT: shader_glsl_intrinsic(gen, ins, "sqrt"); break; diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c index f4401bc5d89..ce3dd91f04f 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c @@ -1907,6 +1907,59 @@ struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, enum hlsl_compile_ty return &compile->node; } +bool hlsl_state_block_add_entry(struct hlsl_state_block *state_block, + struct hlsl_state_block_entry *entry) +{ + if (!vkd3d_array_reserve((void **)&state_block->entries, + &state_block->capacity, state_block->count + 1, + sizeof(*state_block->entries))) + return false; + + state_block->entries[state_block->count++] = entry; + return true; +} + +struct hlsl_ir_node *hlsl_new_sampler_state(struct hlsl_ctx *ctx, + const struct hlsl_state_block *state_block, struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_sampler_state *sampler_state; + struct hlsl_type *type = ctx->builtin_types.sampler[HLSL_SAMPLER_DIM_GENERIC]; + + if (!(sampler_state = hlsl_alloc(ctx, sizeof(*sampler_state)))) + return NULL; + + init_node(&sampler_state->node, HLSL_IR_SAMPLER_STATE, type, loc); + + if (!(sampler_state->state_block = hlsl_alloc(ctx, sizeof(*sampler_state->state_block)))) + { + vkd3d_free(sampler_state); + return NULL; + } + + if (state_block) + { + for (unsigned int i = 0; i < state_block->count; ++i) + { + const struct hlsl_state_block_entry *src = state_block->entries[i]; + struct hlsl_state_block_entry *entry; + + if (!(entry = clone_stateblock_entry(ctx, src, src->name, src->lhs_has_index, src->lhs_index, false, 0))) + { + hlsl_free_instr(&sampler_state->node); + return NULL; + } + + if (!hlsl_state_block_add_entry(sampler_state->state_block, entry)) + { + hlsl_free_instr(&sampler_state->node); + return NULL; + } + } + } + + return &sampler_state->node; +} + struct hlsl_ir_node *hlsl_new_stateblock_constant(struct hlsl_ctx *ctx, const char *name, struct vkd3d_shader_location *loc) { @@ -2295,6 +2348,13 @@ static struct hlsl_ir_node *clone_compile(struct hlsl_ctx *ctx, return node; } +static struct hlsl_ir_node *clone_sampler_state(struct hlsl_ctx *ctx, + struct clone_instr_map *map, struct hlsl_ir_sampler_state *sampler_state) +{ + return hlsl_new_sampler_state(ctx, sampler_state->state_block, + &sampler_state->node.loc); +} + static struct hlsl_ir_node *clone_stateblock_constant(struct hlsl_ctx *ctx, struct clone_instr_map *map, struct hlsl_ir_stateblock_constant *constant) { @@ -2302,8 +2362,8 @@ static struct hlsl_ir_node *clone_stateblock_constant(struct hlsl_ctx *ctx, } struct hlsl_state_block_entry *clone_stateblock_entry(struct hlsl_ctx *ctx, - struct hlsl_state_block_entry *src, const char *name, bool lhs_has_index, - unsigned int lhs_index, unsigned int arg_index) + const struct hlsl_state_block_entry *src, const char *name, bool lhs_has_index, + unsigned int lhs_index, bool single_arg, unsigned int arg_index) { struct hlsl_state_block_entry *entry; struct clone_instr_map map = { 0 }; @@ -2319,7 +2379,11 @@ struct hlsl_state_block_entry *clone_stateblock_entry(struct hlsl_ctx *ctx, return NULL; } - entry->args_count = 1; + if (single_arg) + entry->args_count = 1; + else + entry->args_count = src->args_count; + if (!(entry->args = hlsl_alloc(ctx, sizeof(*entry->args) * entry->args_count))) { hlsl_free_state_block_entry(entry); @@ -2332,7 +2396,16 @@ struct hlsl_state_block_entry *clone_stateblock_entry(struct hlsl_ctx *ctx, hlsl_free_state_block_entry(entry); return NULL; } - clone_src(&map, entry->args, &src->args[arg_index]); + + if (single_arg) + { + clone_src(&map, entry->args, &src->args[arg_index]); + } + else + { + for (unsigned int i = 0; i < src->args_count; ++i) + clone_src(&map, &entry->args[i], &src->args[i]); + } vkd3d_free(map.instrs); return entry; @@ -2440,6 +2513,9 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx, case HLSL_IR_COMPILE: return clone_compile(ctx, map, hlsl_ir_compile(instr)); + case HLSL_IR_SAMPLER_STATE: + return clone_sampler_state(ctx, map, hlsl_ir_sampler_state(instr)); + case HLSL_IR_STATEBLOCK_CONSTANT: return clone_stateblock_constant(ctx, map, hlsl_ir_stateblock_constant(instr)); } @@ -2860,6 +2936,7 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type) [HLSL_IR_SWIZZLE ] = "HLSL_IR_SWIZZLE", [HLSL_IR_COMPILE] = "HLSL_IR_COMPILE", + [HLSL_IR_SAMPLER_STATE] = "HLSL_IR_SAMPLER_STATE", [HLSL_IR_STATEBLOCK_CONSTANT] = "HLSL_IR_STATEBLOCK_CONSTANT", }; @@ -3337,6 +3414,12 @@ static void dump_ir_compile(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *bu vkd3d_string_buffer_printf(buffer, ")"); } +static void dump_ir_sampler_state(struct vkd3d_string_buffer *buffer, + const struct hlsl_ir_sampler_state *sampler_state) +{ + vkd3d_string_buffer_printf(buffer, "sampler_state {...}"); +} + static void dump_ir_stateblock_constant(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_stateblock_constant *constant) { @@ -3440,6 +3523,10 @@ static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, dump_ir_compile(ctx, buffer, hlsl_ir_compile(instr)); break; + case HLSL_IR_SAMPLER_STATE: + dump_ir_sampler_state(buffer, hlsl_ir_sampler_state(instr)); + break; + case HLSL_IR_STATEBLOCK_CONSTANT: dump_ir_stateblock_constant(buffer, hlsl_ir_stateblock_constant(instr)); break; @@ -3665,6 +3752,13 @@ static void free_ir_compile(struct hlsl_ir_compile *compile) vkd3d_free(compile); } +static void free_ir_sampler_state(struct hlsl_ir_sampler_state *sampler_state) +{ + if (sampler_state->state_block) + hlsl_free_state_block(sampler_state->state_block); + vkd3d_free(sampler_state); +} + static void free_ir_stateblock_constant(struct hlsl_ir_stateblock_constant *constant) { vkd3d_free(constant->name); @@ -3737,6 +3831,10 @@ void hlsl_free_instr(struct hlsl_ir_node *node) free_ir_compile(hlsl_ir_compile(node)); break; + case HLSL_IR_SAMPLER_STATE: + free_ir_sampler_state(hlsl_ir_sampler_state(node)); + break; + case HLSL_IR_STATEBLOCK_CONSTANT: free_ir_stateblock_constant(hlsl_ir_stateblock_constant(node)); break; diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h index b8678962f67..4082b14fe04 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h @@ -326,6 +326,7 @@ enum hlsl_ir_node_type HLSL_IR_SWITCH, HLSL_IR_COMPILE, + HLSL_IR_SAMPLER_STATE, HLSL_IR_STATEBLOCK_CONSTANT, }; @@ -899,6 +900,14 @@ struct hlsl_ir_compile unsigned int args_count; }; +/* Represents a state block initialized with the "sampler_state" keyword. */ +struct hlsl_ir_sampler_state +{ + struct hlsl_ir_node node; + + struct hlsl_state_block *state_block; +}; + /* Stateblock constants are undeclared values found on state blocks or technique passes descriptions, * that do not concern regular pixel, vertex, or compute shaders, except for parsing. */ struct hlsl_ir_stateblock_constant @@ -1212,6 +1221,12 @@ static inline struct hlsl_ir_compile *hlsl_ir_compile(const struct hlsl_ir_node return CONTAINING_RECORD(node, struct hlsl_ir_compile, node); } +static inline struct hlsl_ir_sampler_state *hlsl_ir_sampler_state(const struct hlsl_ir_node *node) +{ + VKD3D_ASSERT(node->type == HLSL_IR_SAMPLER_STATE); + return CONTAINING_RECORD(node, struct hlsl_ir_sampler_state, node); +}; + static inline struct hlsl_ir_stateblock_constant *hlsl_ir_stateblock_constant(const struct hlsl_ir_node *node) { VKD3D_ASSERT(node->type == HLSL_IR_STATEBLOCK_CONSTANT); @@ -1396,12 +1411,15 @@ bool hlsl_clone_block(struct hlsl_ctx *ctx, struct hlsl_block *dst_block, const void hlsl_dump_function(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *func); void hlsl_dump_var_default_values(const struct hlsl_ir_var *var); +bool hlsl_state_block_add_entry(struct hlsl_state_block *state_block, + struct hlsl_state_block_entry *entry); bool hlsl_validate_state_block_entry(struct hlsl_ctx *ctx, struct hlsl_state_block_entry *entry, const struct vkd3d_shader_location *loc); struct hlsl_state_block_entry *clone_stateblock_entry(struct hlsl_ctx *ctx, - struct hlsl_state_block_entry *src, const char *name, bool lhs_has_index, - unsigned int lhs_index, unsigned int arg_index); + const struct hlsl_state_block_entry *src, const char *name, bool lhs_has_index, + unsigned int lhs_index, bool single_arg, unsigned int arg_index); +void hlsl_lower_index_loads(struct hlsl_ctx *ctx, struct hlsl_block *body); void hlsl_run_const_passes(struct hlsl_ctx *ctx, struct hlsl_block *body); int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, enum vkd3d_shader_target_type target_type, struct vkd3d_shader_code *out); @@ -1509,6 +1527,8 @@ struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name, struct hlsl_struct_field *fields, size_t field_count); struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, uint32_t s, unsigned int components, struct hlsl_ir_node *val, const struct vkd3d_shader_location *loc); +struct hlsl_ir_node *hlsl_new_sampler_state(struct hlsl_ctx *ctx, + const struct hlsl_state_block *state_block, struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_stateblock_constant(struct hlsl_ctx *ctx, const char *name, struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_string_constant(struct hlsl_ctx *ctx, const char *str, diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y index c39f2020ef7..b4d9f0988b0 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y @@ -437,6 +437,9 @@ static struct hlsl_ir_node *add_implicit_conversion(struct hlsl_ctx *ctx, struct if (hlsl_types_are_equal(src_type, dst_type)) return node; + if (node->type == HLSL_IR_SAMPLER_STATE && dst_type->class == HLSL_CLASS_SAMPLER) + return node; + if (!implicit_compatible_data_types(ctx, src_type, dst_type)) { struct vkd3d_string_buffer *src_string, *dst_string; @@ -613,6 +616,7 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx case HLSL_IR_COMPILE: case HLSL_IR_CONSTANT: case HLSL_IR_EXPR: + case HLSL_IR_SAMPLER_STATE: case HLSL_IR_STRING_CONSTANT: case HLSL_IR_SWIZZLE: case HLSL_IR_LOAD: @@ -648,6 +652,7 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx /* Wrap the node into a src to allow the reference to survive the multiple const passes. */ hlsl_src_from_node(&src, node); + hlsl_lower_index_loads(ctx, &expr); hlsl_run_const_passes(ctx, &expr); node = src.node; hlsl_src_remove(&src); @@ -2324,55 +2329,6 @@ static bool add_increment(struct hlsl_ctx *ctx, struct hlsl_block *block, bool d return true; } -/* For some reason, for matrices, values from default value initializers end up in different - * components than from regular initializers. Default value initializers fill the matrix in - * vertical reading order (left-to-right top-to-bottom) instead of regular reading order - * (top-to-bottom left-to-right), so they have to be adjusted. - * An exception is that the order of matrix initializers for function parameters are row-major - * (top-to-bottom left-to-right). */ -static unsigned int get_component_index_from_default_initializer_index(struct hlsl_ctx *ctx, - struct hlsl_type *type, unsigned int index) -{ - unsigned int element_comp_count, element, x, y, i; - unsigned int base = 0; - - if (ctx->profile->major_version < 4) - return index; - - if (ctx->profile->type == VKD3D_SHADER_TYPE_EFFECT) - return index; - - switch (type->class) - { - case HLSL_CLASS_MATRIX: - x = index / type->dimy; - y = index % type->dimy; - return y * type->dimx + x; - - case HLSL_CLASS_ARRAY: - element_comp_count = hlsl_type_component_count(type->e.array.type); - element = index / element_comp_count; - base = element * element_comp_count; - return base + get_component_index_from_default_initializer_index(ctx, type->e.array.type, index - base); - - case HLSL_CLASS_STRUCT: - for (i = 0; i < type->e.record.field_count; ++i) - { - struct hlsl_type *field_type = type->e.record.fields[i].type; - - element_comp_count = hlsl_type_component_count(field_type); - if (index - base < element_comp_count) - return base + get_component_index_from_default_initializer_index(ctx, field_type, index - base); - base += element_comp_count; - } - break; - - default: - return index; - } - vkd3d_unreachable(); -} - static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *instrs, struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src, bool is_default_values_initializer) @@ -2397,11 +2353,10 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i if (is_default_values_initializer) { struct hlsl_default_value default_value = {0}; - unsigned int dst_index; if (hlsl_is_numeric_type(dst_comp_type)) { - if (src->type == HLSL_IR_COMPILE) + if (src->type == HLSL_IR_COMPILE || src->type == HLSL_IR_SAMPLER_STATE) { /* Default values are discarded if they contain an object * literal expression for a numeric component. */ @@ -2420,13 +2375,8 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i return; default_value = evaluate_static_expression(ctx, &block, dst_comp_type, &src->loc); - if (dst->is_param) - dst_index = *store_index; - else - dst_index = get_component_index_from_default_initializer_index(ctx, dst->data_type, *store_index); - if (dst->default_values) - dst->default_values[dst_index] = default_value; + dst->default_values[*store_index] = default_value; hlsl_block_cleanup(&block); } @@ -2434,12 +2384,41 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i } else { - if (!(conv = add_implicit_conversion(ctx, instrs, load, dst_comp_type, &src->loc))) - return; + if (src->type == HLSL_IR_SAMPLER_STATE) + { + /* Sampler states end up in the variable's state_blocks instead of + * being used to initialize its value. */ + struct hlsl_ir_sampler_state *sampler_state = hlsl_ir_sampler_state(src); + + if (dst_comp_type->class != HLSL_CLASS_SAMPLER) + { + struct vkd3d_string_buffer *dst_string; + + dst_string = hlsl_type_to_string(ctx, dst_comp_type); + if (dst_string) + hlsl_error(ctx, &src->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Cannot assign sampler_state to %s.", dst_string->buffer); + hlsl_release_string_buffer(ctx, dst_string); + return; + } - if (!hlsl_new_store_component(ctx, &block, &dst_deref, *store_index, conv)) - return; - hlsl_block_add_block(instrs, &block); + if (!hlsl_array_reserve(ctx, (void **)&dst->state_blocks, &dst->state_block_capacity, + dst->state_block_count + 1, sizeof(*dst->state_blocks))) + return; + + dst->state_blocks[dst->state_block_count] = sampler_state->state_block; + sampler_state->state_block = NULL; + ++dst->state_block_count; + } + else + { + if (!(conv = add_implicit_conversion(ctx, instrs, load, dst_comp_type, &src->loc))) + return; + + if (!hlsl_new_store_component(ctx, &block, &dst_deref, *store_index, conv)) + return; + hlsl_block_add_block(instrs, &block); + } } ++*store_index; @@ -2778,6 +2757,8 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var is_default_values_initializer = (ctx->cur_buffer != ctx->globals_buffer) || (var->storage_modifiers & HLSL_STORAGE_UNIFORM) || ctx->cur_scope->annotations; + if (hlsl_get_multiarray_element_type(type)->class == HLSL_CLASS_SAMPLER) + is_default_values_initializer = false; if (hlsl_type_is_shader(type)) is_default_values_initializer = false; @@ -2836,6 +2817,9 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var { hlsl_block_add_block(initializers, v->initializer.instrs); } + + if (var->state_blocks) + TRACE("Variable %s has %u state blocks.\n", var->name, var->state_block_count); } else if (var->storage_modifiers & HLSL_STORAGE_STATIC) { @@ -6228,16 +6212,6 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, hlsl_release_string_buffer(ctx, string); } -static bool state_block_add_entry(struct hlsl_state_block *state_block, struct hlsl_state_block_entry *entry) -{ - if (!vkd3d_array_reserve((void **)&state_block->entries, &state_block->capacity, state_block->count + 1, - sizeof(*state_block->entries))) - return false; - - state_block->entries[state_block->count++] = entry; - return true; -} - } %locations @@ -7850,6 +7824,11 @@ stateblock_lhs_identifier: if (!($$ = hlsl_strdup(ctx, "pixelshader"))) YYABORT; } + | KW_TEXTURE + { + if (!($$ = hlsl_strdup(ctx, "texture"))) + YYABORT; + } | KW_VERTEXSHADER { if (!($$ = hlsl_strdup(ctx, "vertexshader"))) @@ -7907,7 +7886,7 @@ state_block: vkd3d_free($5.args); $$ = $1; - state_block_add_entry($$, entry); + hlsl_state_block_add_entry($$, entry); } | state_block any_identifier '(' func_arguments ')' ';' { @@ -7935,7 +7914,7 @@ state_block: hlsl_validate_state_block_entry(ctx, entry, &@4); $$ = $1; - state_block_add_entry($$, entry); + hlsl_state_block_add_entry($$, entry); } state_block_list: @@ -8668,6 +8647,25 @@ primary_expr: } vkd3d_free($1); } + | KW_SAMPLER_STATE '{' state_block_start state_block '}' + { + struct hlsl_ir_node *sampler_state; + ctx->in_state_block = 0; + + if (!ctx->in_state_block && ctx->cur_scope != ctx->globals) + hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_MISPLACED_SAMPLER_STATE, + "sampler_state must be in global scope or a state block."); + + if (!(sampler_state = hlsl_new_sampler_state(ctx, $4, &@1))) + { + hlsl_free_state_block($4); + YYABORT; + } + hlsl_free_state_block($4); + + if (!($$ = make_block(ctx, sampler_state))) + YYABORT; + } | NEW_IDENTIFIER { if (ctx->in_state_block) diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c index feab6cf06c1..c5dd5e71e02 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c @@ -4062,6 +4062,7 @@ static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) case HLSL_IR_RESOURCE_LOAD: case HLSL_IR_STRING_CONSTANT: case HLSL_IR_SWIZZLE: + case HLSL_IR_SAMPLER_STATE: if (list_empty(&instr->uses)) { list_remove(&instr->entry); @@ -4344,7 +4345,8 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop case HLSL_IR_STRING_CONSTANT: break; case HLSL_IR_COMPILE: - /* Compile calls are skipped as they are only relevent to effects. */ + case HLSL_IR_SAMPLER_STATE: + /* These types are skipped as they are only relevant to effects. */ break; } } @@ -5206,7 +5208,8 @@ static void allocate_semantic_registers(struct hlsl_ctx *ctx) } } -static const struct hlsl_buffer *get_reserved_buffer(struct hlsl_ctx *ctx, uint32_t space, uint32_t index) +static const struct hlsl_buffer *get_reserved_buffer(struct hlsl_ctx *ctx, + uint32_t space, uint32_t index, bool allocated_only) { const struct hlsl_buffer *buffer; @@ -5214,7 +5217,12 @@ static const struct hlsl_buffer *get_reserved_buffer(struct hlsl_ctx *ctx, uint3 { if (buffer->reservation.reg_type == 'b' && buffer->reservation.reg_space == space && buffer->reservation.reg_index == index) + { + if (allocated_only && !buffer->reg.allocated) + continue; + return buffer; + } } return NULL; } @@ -5397,8 +5405,8 @@ static void allocate_buffers(struct hlsl_ctx *ctx) if (reservation->reg_type == 'b') { - const struct hlsl_buffer *reserved_buffer = get_reserved_buffer(ctx, - reservation->reg_space, reservation->reg_index); + const struct hlsl_buffer *allocated_buffer = get_reserved_buffer(ctx, + reservation->reg_space, reservation->reg_index, true); unsigned int max_index = get_max_cbuffer_reg_index(ctx); if (buffer->reservation.reg_index > max_index) @@ -5406,14 +5414,14 @@ static void allocate_buffers(struct hlsl_ctx *ctx) "Buffer reservation cb%u exceeds target's maximum (cb%u).", buffer->reservation.reg_index, max_index); - if (reserved_buffer && reserved_buffer != buffer) + if (allocated_buffer && allocated_buffer != buffer) { hlsl_error(ctx, &buffer->loc, VKD3D_SHADER_ERROR_HLSL_OVERLAPPING_RESERVATIONS, "Multiple buffers bound to space %u, index %u.", reservation->reg_space, reservation->reg_index); - hlsl_note(ctx, &reserved_buffer->loc, VKD3D_SHADER_LOG_ERROR, + hlsl_note(ctx, &allocated_buffer->loc, VKD3D_SHADER_LOG_ERROR, "Buffer %s is already bound to space %u, index %u.", - reserved_buffer->name, reservation->reg_space, reservation->reg_index); + allocated_buffer->name, reservation->reg_space, reservation->reg_index); } buffer->reg.space = reservation->reg_space; @@ -5430,12 +5438,12 @@ static void allocate_buffers(struct hlsl_ctx *ctx) else if (!reservation->reg_type) { unsigned int max_index = get_max_cbuffer_reg_index(ctx); - while (get_reserved_buffer(ctx, 0, index)) + while (get_reserved_buffer(ctx, 0, index, false)) ++index; if (index > max_index) hlsl_error(ctx, &buffer->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION, - "Too many buffers allocated, target's maximum is %u.", max_index); + "Too many buffers reserved, target's maximum is %u.", max_index); buffer->reg.space = 0; buffer->reg.index = index; @@ -6178,12 +6186,16 @@ static void remove_unreachable_code(struct hlsl_ctx *ctx, struct hlsl_block *bod } } +void hlsl_lower_index_loads(struct hlsl_ctx *ctx, struct hlsl_block *body) +{ + lower_ir(ctx, lower_index_loads, body); +} + void hlsl_run_const_passes(struct hlsl_ctx *ctx, struct hlsl_block *body) { bool progress; lower_ir(ctx, lower_matrix_swizzles, body); - lower_ir(ctx, lower_index_loads, body); lower_ir(ctx, lower_broadcasts, body); while (hlsl_transform_ir(ctx, fold_redundant_casts, body, NULL)); diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c index 88650a97068..2fe5472167f 100644 --- a/libs/vkd3d/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d/libs/vkd3d-shader/ir.c @@ -215,6 +215,14 @@ static void src_param_init_temp_float(struct vkd3d_shader_src_param *src, unsign src->reg.idx[0].offset = idx; } +static void src_param_init_temp_float4(struct vkd3d_shader_src_param *src, unsigned int idx) +{ + vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); + src->reg.dimension = VSIR_DIMENSION_VEC4; + src->swizzle = VKD3D_SHADER_NO_SWIZZLE; + src->reg.idx[0].offset = idx; +} + static void src_param_init_temp_uint(struct vkd3d_shader_src_param *src, unsigned int idx) { vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1); @@ -1864,13 +1872,13 @@ static bool use_flat_interpolation(const struct vsir_program *program, if (parameter->type != VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT) { vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, - "Unsupported flat interpolation parameter type %#x.\n", parameter->type); + "Unsupported flat interpolation parameter type %#x.", parameter->type); return false; } if (parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32) { vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, - "Invalid flat interpolation parameter data type %#x.\n", parameter->data_type); + "Invalid flat interpolation parameter data type %#x.", parameter->data_type); return false; } @@ -5539,9 +5547,11 @@ static bool find_colour_signature_idx(const struct shader_signature *signature, static enum vkd3d_result insert_alpha_test_before_ret(struct vsir_program *program, const struct vkd3d_shader_instruction *ret, enum vkd3d_shader_comparison_func compare_func, - const struct vkd3d_shader_parameter1 *ref, uint32_t colour_signature_idx, uint32_t colour_temp, size_t *ret_pos) + const struct vkd3d_shader_parameter1 *ref, uint32_t colour_signature_idx, + uint32_t colour_temp, size_t *ret_pos, struct vkd3d_shader_message_context *message_context) { struct vkd3d_shader_instruction_array *instructions = &program->instructions; + static const struct vkd3d_shader_location no_loc; size_t pos = ret - instructions->elements; struct vkd3d_shader_instruction *ins; @@ -5596,6 +5606,11 @@ static enum vkd3d_result insert_alpha_test_before_ret(struct vsir_program *progr VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_REF, VKD3D_DATA_UINT); break; + case VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4: + vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_PARAMETER, + "Alpha test reference data type must be a single component."); + return VKD3D_ERROR_INVALID_ARGUMENT; + default: FIXME("Unhandled parameter data type %#x.\n", ref->data_type); return VKD3D_ERROR_NOT_IMPLEMENTED; @@ -5652,13 +5667,13 @@ static enum vkd3d_result vsir_program_insert_alpha_test(struct vsir_program *pro if (func->type != VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT) { vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, - "Unsupported alpha test function parameter type %#x.\n", func->type); + "Unsupported alpha test function parameter type %#x.", func->type); return VKD3D_ERROR_NOT_IMPLEMENTED; } if (func->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32) { vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, - "Invalid alpha test function parameter data type %#x.\n", func->data_type); + "Invalid alpha test function parameter data type %#x.", func->data_type); return VKD3D_ERROR_INVALID_ARGUMENT; } compare_func = func->u.immediate_constant.u.u32; @@ -5682,7 +5697,7 @@ static enum vkd3d_result vsir_program_insert_alpha_test(struct vsir_program *pro if (ins->opcode == VKD3DSIH_RET) { if ((ret = insert_alpha_test_before_ret(program, ins, compare_func, - ref, colour_signature_idx, colour_temp, &new_pos)) < 0) + ref, colour_signature_idx, colour_temp, &new_pos, message_context)) < 0) return ret; i = new_pos; continue; @@ -5709,6 +5724,202 @@ static enum vkd3d_result vsir_program_insert_alpha_test(struct vsir_program *pro return VKD3D_OK; } +static enum vkd3d_result insert_clip_planes_before_ret(struct vsir_program *program, + const struct vkd3d_shader_instruction *ret, uint32_t mask, uint32_t position_signature_idx, + uint32_t position_temp, uint32_t low_signature_idx, uint32_t high_signature_idx, size_t *ret_pos) +{ + struct vkd3d_shader_instruction_array *instructions = &program->instructions; + size_t pos = ret - instructions->elements; + struct vkd3d_shader_instruction *ins; + unsigned int output_idx = 0; + + if (!shader_instruction_array_insert_at(&program->instructions, pos, vkd3d_popcount(mask) + 1)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + ins = &program->instructions.elements[pos]; + + for (unsigned int i = 0; i < 8; ++i) + { + if (!(mask & (1u << i))) + continue; + + vsir_instruction_init_with_params(program, ins, &ret->location, VKD3DSIH_DP4, 1, 2); + src_param_init_temp_float4(&ins->src[0], position_temp); + src_param_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_0 + i, VKD3D_DATA_FLOAT); + ins->src[1].swizzle = VKD3D_SHADER_NO_SWIZZLE; + ins->src[1].reg.dimension = VSIR_DIMENSION_VEC4; + + vsir_dst_param_init(&ins->dst[0], VKD3DSPR_OUTPUT, VKD3D_DATA_FLOAT, 1); + if (output_idx < 4) + ins->dst[0].reg.idx[0].offset = low_signature_idx; + else + ins->dst[0].reg.idx[0].offset = high_signature_idx; + ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; + ins->dst[0].write_mask = (1u << (output_idx % 4)); + ++output_idx; + + ++ins; + } + + vsir_instruction_init_with_params(program, ins, &ret->location, VKD3DSIH_MOV, 1, 1); + vsir_dst_param_init(&ins->dst[0], VKD3DSPR_OUTPUT, VKD3D_DATA_FLOAT, 1); + ins->dst[0].reg.idx[0].offset = position_signature_idx; + ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; + ins->dst[0].write_mask = program->output_signature.elements[position_signature_idx].mask; + src_param_init_temp_float(&ins->src[0], position_temp); + ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; + ins->src[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; + + *ret_pos = pos + vkd3d_popcount(mask) + 1; + return VKD3D_OK; +} + +static bool find_position_signature_idx(const struct shader_signature *signature, uint32_t *idx) +{ + for (unsigned int i = 0; i < signature->element_count; ++i) + { + if (signature->elements[i].sysval_semantic == VKD3D_SHADER_SV_POSITION) + { + *idx = i; + return true; + } + } + + return false; +} + +static enum vkd3d_result vsir_program_insert_clip_planes(struct vsir_program *program, + struct vsir_transformation_context *ctx) +{ + struct shader_signature *signature = &program->output_signature; + unsigned int low_signature_idx = ~0u, high_signature_idx = ~0u; + const struct vkd3d_shader_parameter1 *mask_parameter = NULL; + struct signature_element *new_elements, *clip_element; + uint32_t position_signature_idx, position_temp, mask; + static const struct vkd3d_shader_location no_loc; + struct vkd3d_shader_instruction *ins; + unsigned int plane_count; + size_t new_pos; + int ret; + + if (program->shader_version.type != VKD3D_SHADER_TYPE_VERTEX) + return VKD3D_OK; + + for (unsigned int i = 0; i < program->parameter_count; ++i) + { + const struct vkd3d_shader_parameter1 *parameter = &program->parameters[i]; + + if (parameter->name == VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_MASK) + mask_parameter = parameter; + } + + if (!mask_parameter) + return VKD3D_OK; + + if (mask_parameter->type != VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT) + { + vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, + "Unsupported clip plane mask parameter type %#x.", mask_parameter->type); + return VKD3D_ERROR_NOT_IMPLEMENTED; + } + if (mask_parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32) + { + vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, + "Invalid clip plane mask parameter data type %#x.", mask_parameter->data_type); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + mask = mask_parameter->u.immediate_constant.u.u32; + + if (!mask) + return VKD3D_OK; + + for (unsigned int i = 0; i < signature->element_count; ++i) + { + if (signature->elements[i].sysval_semantic == VKD3D_SHADER_SV_CLIP_DISTANCE) + { + vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_PARAMETER, + "Clip planes cannot be used if the shader writes clip distance."); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + } + + if (!find_position_signature_idx(signature, &position_signature_idx)) + { + vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_MISSING_SEMANTIC, + "Shader does not write position."); + return VKD3D_ERROR_INVALID_SHADER; + } + + /* Append the clip plane signature indices. */ + + plane_count = vkd3d_popcount(mask); + + if (!(new_elements = vkd3d_realloc(signature->elements, + (signature->element_count + 2) * sizeof(*signature->elements)))) + return VKD3D_ERROR_OUT_OF_MEMORY; + signature->elements = new_elements; + + low_signature_idx = signature->element_count; + clip_element = &signature->elements[signature->element_count++]; + memset(clip_element, 0, sizeof(*clip_element)); + clip_element->sysval_semantic = VKD3D_SHADER_SV_CLIP_DISTANCE; + clip_element->component_type = VKD3D_SHADER_COMPONENT_FLOAT; + clip_element->register_count = 1; + clip_element->mask = vkd3d_write_mask_from_component_count(min(plane_count, 4)); + clip_element->used_mask = clip_element->mask; + clip_element->min_precision = VKD3D_SHADER_MINIMUM_PRECISION_NONE; + + if (plane_count > 4) + { + high_signature_idx = signature->element_count; + clip_element = &signature->elements[signature->element_count++]; + memset(clip_element, 0, sizeof(*clip_element)); + clip_element->sysval_semantic = VKD3D_SHADER_SV_CLIP_DISTANCE; + clip_element->semantic_index = 1; + clip_element->component_type = VKD3D_SHADER_COMPONENT_FLOAT; + clip_element->register_count = 1; + clip_element->mask = vkd3d_write_mask_from_component_count(plane_count - 4); + clip_element->used_mask = clip_element->mask; + clip_element->min_precision = VKD3D_SHADER_MINIMUM_PRECISION_NONE; + } + + /* We're going to be reading from the output position, so we need to go + * through the whole shader and convert it to a temp. */ + + position_temp = program->temp_count++; + + for (size_t i = 0; i < program->instructions.count; ++i) + { + ins = &program->instructions.elements[i]; + + if (vsir_instruction_is_dcl(ins)) + continue; + + if (ins->opcode == VKD3DSIH_RET) + { + if ((ret = insert_clip_planes_before_ret(program, ins, mask, position_signature_idx, + position_temp, low_signature_idx, high_signature_idx, &new_pos)) < 0) + return ret; + i = new_pos; + continue; + } + + for (size_t j = 0; j < ins->dst_count; ++j) + { + struct vkd3d_shader_dst_param *dst = &ins->dst[j]; + + /* Note we run after I/O normalization. */ + if (dst->reg.type == VKD3DSPR_OUTPUT && dst->reg.idx[0].offset == position_signature_idx) + { + dst->reg.type = VKD3DSPR_TEMP; + dst->reg.idx[0].offset = position_temp; + } + } + } + + return VKD3D_OK; +} + struct validation_context { struct vkd3d_shader_message_context *message_context; @@ -6012,6 +6223,63 @@ static void vsir_validate_register(struct validation_context *ctx, reg->dimension); break; + case VKD3DSPR_DEPTHOUT: + if (reg->idx_count != 0) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid index count %u for a DEPTHOUT register.", + reg->idx_count); + break; + + case VKD3DSPR_DEPTHOUTGE: + if (reg->idx_count != 0) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid index count %u for a DEPTHOUTGE register.", + reg->idx_count); + break; + + case VKD3DSPR_DEPTHOUTLE: + if (reg->idx_count != 0) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid index count %u for a DEPTHOUTLE register.", + reg->idx_count); + break; + + case VKD3DSPR_RASTOUT: + if (reg->idx_count != 1) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid index count %u for a RASTOUT register.", + reg->idx_count); + break; + } + + if (reg->idx[0].rel_addr) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "Non-NULL relative address for a RASTOUT register."); + + if (reg->idx[0].offset >= 3) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "Invalid offset for a RASTOUT register."); + break; + + case VKD3DSPR_MISCTYPE: + if (reg->idx_count != 1) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid index count %u for a MISCTYPE register.", + reg->idx_count); + break; + } + + if (reg->idx[0].rel_addr) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "Non-NULL relative address for a MISCTYPE register."); + + if (reg->idx[0].offset >= 2) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "Invalid offset for a MISCTYPE register."); + break; + default: break; } @@ -6842,6 +7110,7 @@ enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t } vsir_transform(&ctx, vsir_program_insert_alpha_test); + vsir_transform(&ctx, vsir_program_insert_clip_planes); if (TRACE_ON()) vkd3d_shader_trace(program); diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c index 0278a6ca232..11c054a28f5 100644 --- a/libs/vkd3d/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c @@ -1228,6 +1228,13 @@ static uint32_t vkd3d_spirv_build_op_constant_composite(struct vkd3d_spirv_build SpvOpConstantComposite, result_type, constituents, constituent_count); } +static uint32_t vkd3d_spirv_build_op_spec_constant_composite(struct vkd3d_spirv_builder *builder, + uint32_t result_type, const uint32_t *constituents, unsigned int constituent_count) +{ + return vkd3d_spirv_build_op_trv(builder, &builder->global_stream, + SpvOpSpecConstantComposite, result_type, constituents, constituent_count); +} + static uint32_t vkd3d_spirv_get_op_constant_composite(struct vkd3d_spirv_builder *builder, uint32_t result_type, const uint32_t *constituents, unsigned int constituent_count) { @@ -3324,8 +3331,10 @@ static const struct vkd3d_spec_constant_info *get_spec_constant_info(enum vkd3d_ return NULL; } -static uint32_t spirv_compiler_alloc_spec_constant_id(struct spirv_compiler *compiler) +static uint32_t spirv_compiler_alloc_spec_constant_id(struct spirv_compiler *compiler, unsigned int count) { + uint32_t ret; + if (!compiler->current_spec_constant_id) { unsigned int i, id = 0; @@ -3335,28 +3344,52 @@ static uint32_t spirv_compiler_alloc_spec_constant_id(struct spirv_compiler *com const struct vkd3d_shader_parameter1 *current = &compiler->program->parameters[i]; if (current->type == VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT) - id = max(current->u.specialization_constant.id + 1, id); + { + switch (current->data_type) + { + case VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4: + id = max(current->u.specialization_constant.id + 4, id); + break; + + default: + id = max(current->u.specialization_constant.id + 1, id); + break; + } + } } compiler->current_spec_constant_id = id; } - return compiler->current_spec_constant_id++; + ret = compiler->current_spec_constant_id; + compiler->current_spec_constant_id += count; + return ret; } static uint32_t spirv_compiler_emit_spec_constant(struct spirv_compiler *compiler, - enum vkd3d_shader_parameter_name name, uint32_t spec_id, enum vkd3d_data_type type) + enum vkd3d_shader_parameter_name name, uint32_t spec_id, + enum vkd3d_data_type type, unsigned int component_count) { + uint32_t scalar_type_id, vector_type_id, id, default_value, components[4]; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; const struct vkd3d_spec_constant_info *info; - uint32_t type_id, id, default_value; info = get_spec_constant_info(name); default_value = info ? info->default_value : 0; - type_id = vkd3d_spirv_get_type_id(builder, vkd3d_component_type_from_data_type(type), 1); - id = vkd3d_spirv_build_op_spec_constant(builder, type_id, default_value); - vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationSpecId, spec_id); + scalar_type_id = vkd3d_spirv_get_type_id(builder, vkd3d_component_type_from_data_type(type), 1); + vector_type_id = vkd3d_spirv_get_type_id(builder, vkd3d_component_type_from_data_type(type), component_count); + + for (unsigned int i = 0; i < component_count; ++i) + { + components[i] = vkd3d_spirv_build_op_spec_constant(builder, scalar_type_id, default_value); + vkd3d_spirv_build_op_decorate1(builder, components[i], SpvDecorationSpecId, spec_id + i); + } + + if (component_count == 1) + id = components[0]; + else + id = vkd3d_spirv_build_op_spec_constant_composite(builder, vector_type_id, components, component_count); if (info) vkd3d_spirv_build_op_name(builder, id, "%s", info->debug_name); @@ -3373,7 +3406,8 @@ static uint32_t spirv_compiler_emit_spec_constant(struct spirv_compiler *compile } static uint32_t spirv_compiler_get_spec_constant(struct spirv_compiler *compiler, - enum vkd3d_shader_parameter_name name, uint32_t spec_id, enum vkd3d_data_type type) + enum vkd3d_shader_parameter_name name, uint32_t spec_id, + enum vkd3d_data_type type, unsigned int component_count) { unsigned int i; @@ -3383,17 +3417,17 @@ static uint32_t spirv_compiler_get_spec_constant(struct spirv_compiler *compiler return compiler->spec_constants[i].id; } - return spirv_compiler_emit_spec_constant(compiler, name, spec_id, type); + return spirv_compiler_emit_spec_constant(compiler, name, spec_id, type, component_count); } static uint32_t spirv_compiler_get_buffer_parameter(struct spirv_compiler *compiler, - const struct vkd3d_shader_parameter1 *parameter, enum vkd3d_data_type type) + const struct vkd3d_shader_parameter1 *parameter, enum vkd3d_data_type type, unsigned int component_count) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; unsigned int index = parameter - compiler->program->parameters; uint32_t type_id, ptr_id, ptr_type_id; - type_id = vkd3d_spirv_get_type_id(builder, vkd3d_component_type_from_data_type(type), 1); + type_id = vkd3d_spirv_get_type_id(builder, vkd3d_component_type_from_data_type(type), component_count); ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassUniform, type_id); ptr_id = vkd3d_spirv_build_op_access_chain1(builder, ptr_type_id, compiler->spirv_parameter_info[index].buffer_id, @@ -3401,48 +3435,49 @@ static uint32_t spirv_compiler_get_buffer_parameter(struct spirv_compiler *compi return vkd3d_spirv_build_op_load(builder, type_id, ptr_id, SpvMemoryAccessMaskNone); } +static const struct +{ + enum vkd3d_data_type type; + unsigned int component_count; +} +parameter_data_type_map[] = +{ + [VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32] = {VKD3D_DATA_FLOAT, 1}, + [VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32] = {VKD3D_DATA_UINT, 1}, + [VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4] = {VKD3D_DATA_FLOAT, 4}, +}; + static uint32_t spirv_compiler_emit_shader_parameter(struct spirv_compiler *compiler, - enum vkd3d_shader_parameter_name name, enum vkd3d_data_type type) + enum vkd3d_shader_parameter_name name, enum vkd3d_data_type type, unsigned int component_count) { const struct vkd3d_shader_parameter1 *parameter; - static const struct - { - enum vkd3d_data_type type; - } - type_map[] = - { - [VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32] = {VKD3D_DATA_FLOAT}, - [VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32] = {VKD3D_DATA_UINT}, - }; - if (!(parameter = vsir_program_get_parameter(compiler->program, name))) { WARN("Unresolved shader parameter %#x.\n", name); goto default_parameter; } - if (type_map[parameter->data_type].type != type) - ERR("Expected data type %#x for parameter %#x, got %#x.\n", type, name, parameter->data_type); + if (parameter_data_type_map[parameter->data_type].type != type + || parameter_data_type_map[parameter->data_type].component_count != component_count) + ERR("Expected type %#x, count %u for parameter %#x, got %#x.\n", + type, component_count, name, parameter->data_type); if (parameter->type == VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT) - { - if (parameter->data_type == VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32) - return spirv_compiler_get_constant_float(compiler, parameter->u.immediate_constant.u.f32); - else - return spirv_compiler_get_constant_uint(compiler, parameter->u.immediate_constant.u.u32); - } + return spirv_compiler_get_constant(compiler, vkd3d_component_type_from_data_type(type), + component_count, (const uint32_t *)¶meter->u.immediate_constant); if (parameter->type == VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT) - return spirv_compiler_get_spec_constant(compiler, name, parameter->u.specialization_constant.id, type); + return spirv_compiler_get_spec_constant(compiler, name, + parameter->u.specialization_constant.id, type, component_count); if (parameter->type == VKD3D_SHADER_PARAMETER_TYPE_BUFFER) - return spirv_compiler_get_buffer_parameter(compiler, parameter, type); + return spirv_compiler_get_buffer_parameter(compiler, parameter, type, component_count); FIXME("Unhandled parameter type %#x.\n", parameter->type); default_parameter: return spirv_compiler_get_spec_constant(compiler, - name, spirv_compiler_alloc_spec_constant_id(compiler), type); + name, spirv_compiler_alloc_spec_constant_id(compiler, component_count), type, component_count); } static uint32_t spirv_compiler_emit_construct_vector(struct spirv_compiler *compiler, @@ -4218,7 +4253,8 @@ static uint32_t spirv_compiler_emit_load_reg(struct spirv_compiler *compiler, else if (reg->type == VKD3DSPR_UNDEF) return spirv_compiler_emit_load_undef(compiler, reg, write_mask); else if (reg->type == VKD3DSPR_PARAMETER) - return spirv_compiler_emit_shader_parameter(compiler, reg->idx[0].offset, reg->data_type); + return spirv_compiler_emit_shader_parameter(compiler, reg->idx[0].offset, + reg->data_type, reg->dimension == VSIR_DIMENSION_VEC4 ? 4 : 1); component_count = vsir_write_mask_component_count(write_mask); component_type = vkd3d_component_type_from_data_type(reg->data_type); @@ -4508,9 +4544,24 @@ static uint32_t spirv_compiler_emit_sat(struct spirv_compiler *compiler, static void spirv_compiler_emit_store_dst(struct spirv_compiler *compiler, const struct vkd3d_shader_dst_param *dst, uint32_t val_id) { - VKD3D_ASSERT(!(dst->modifiers & ~VKD3DSPDM_SATURATE)); - if (dst->modifiers & VKD3DSPDM_SATURATE) + uint32_t modifiers = dst->modifiers; + + /* It is always legitimate to ignore _pp. */ + modifiers &= ~VKD3DSPDM_PARTIALPRECISION; + + if (modifiers & VKD3DSPDM_SATURATE) + { val_id = spirv_compiler_emit_sat(compiler, &dst->reg, dst->write_mask, val_id); + modifiers &= ~VKD3DSPDM_SATURATE; + } + + if (dst->modifiers & VKD3DSPDM_MSAMPCENTROID) + { + FIXME("Ignoring _centroid modifier.\n"); + modifiers &= ~VKD3DSPDM_MSAMPCENTROID; + } + + VKD3D_ASSERT(!modifiers); spirv_compiler_emit_store_reg(compiler, &dst->reg, dst->write_mask, val_id); } @@ -9563,7 +9614,7 @@ static uint32_t spirv_compiler_emit_query_sample_count(struct spirv_compiler *co if (src->reg.type == VKD3DSPR_RASTERIZER) { val_id = spirv_compiler_emit_shader_parameter(compiler, - VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT, VKD3D_DATA_UINT); + VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT, VKD3D_DATA_UINT, 1); } else { @@ -10611,7 +10662,9 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, struct { uint32_t type_id, struct_id, ptr_type_id, var_id; - type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1); + type_id = vkd3d_spirv_get_type_id(builder, + vkd3d_component_type_from_data_type(parameter_data_type_map[parameter->data_type].type), + parameter_data_type_map[parameter->data_type].component_count); struct_id = vkd3d_spirv_build_op_type_struct(builder, &type_id, 1); vkd3d_spirv_build_op_decorate(builder, struct_id, SpvDecorationBlock, NULL, 0); diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c index 389946e2c2f..00a525c9ac3 100644 --- a/libs/vkd3d/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c @@ -3649,6 +3649,48 @@ static struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, un return extern_resources; } +/* For some reason, for matrices, values from default value initializers end up in different + * components than from regular initializers. Default value initializers fill the matrix in + * vertical reading order (left-to-right top-to-bottom) instead of regular reading order + * (top-to-bottom left-to-right), so they have to be adjusted. + * An exception is that the order of matrix initializers for function parameters are row-major + * (top-to-bottom left-to-right). */ +static unsigned int get_component_index_from_default_initializer_index(struct hlsl_type *type, unsigned int index) +{ + unsigned int element_comp_count, element, x, y, i; + unsigned int base = 0; + + switch (type->class) + { + case HLSL_CLASS_MATRIX: + x = index / type->dimy; + y = index % type->dimy; + return y * type->dimx + x; + + case HLSL_CLASS_ARRAY: + element_comp_count = hlsl_type_component_count(type->e.array.type); + element = index / element_comp_count; + base = element * element_comp_count; + return base + get_component_index_from_default_initializer_index(type->e.array.type, index - base); + + case HLSL_CLASS_STRUCT: + for (i = 0; i < type->e.record.field_count; ++i) + { + struct hlsl_type *field_type = type->e.record.fields[i].type; + + element_comp_count = hlsl_type_component_count(field_type); + if (index - base < element_comp_count) + return base + get_component_index_from_default_initializer_index(field_type, index - base); + base += element_comp_count; + } + break; + + default: + return index; + } + vkd3d_unreachable(); +} + static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) { uint32_t binding_desc_size = (hlsl_version_ge(ctx, 5, 1) ? 10 : 8) * sizeof(uint32_t); @@ -3849,7 +3891,7 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) for (k = 0; k < comp_count; ++k) { struct hlsl_type *comp_type = hlsl_type_get_component_type(ctx, var->data_type, k); - unsigned int comp_offset; + unsigned int comp_offset, comp_index; enum hlsl_regset regset; if (comp_type->class == HLSL_CLASS_STRING) @@ -3859,7 +3901,8 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) continue; } - comp_offset = hlsl_type_get_component_offset(ctx, var->data_type, k, ®set); + comp_index = get_component_index_from_default_initializer_index(var->data_type, k); + comp_offset = hlsl_type_get_component_offset(ctx, var->data_type, comp_index, ®set); if (regset == HLSL_REGSET_NUMERIC) { if (comp_type->e.numeric.type == HLSL_TYPE_DOUBLE) diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h index 112bdc4da7f..d9d5b4a405e 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h @@ -161,6 +161,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_HLSL_INVALID_CONTROL_POINT_COUNT = 5036, VKD3D_SHADER_ERROR_HLSL_INVALID_OUTPUT_PRIMITIVE = 5037, VKD3D_SHADER_ERROR_HLSL_INVALID_PARTITIONING = 5038, + VKD3D_SHADER_ERROR_HLSL_MISPLACED_SAMPLER_STATE = 5039, VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION = 5300, VKD3D_SHADER_WARNING_HLSL_DIVISION_BY_ZERO = 5301, @@ -241,6 +242,8 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_VSIR_INVALID_SSA_USAGE = 9017, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION = 9018, VKD3D_SHADER_ERROR_VSIR_INVALID_GS = 9019, + VKD3D_SHADER_ERROR_VSIR_INVALID_PARAMETER = 9020, + VKD3D_SHADER_ERROR_VSIR_MISSING_SEMANTIC = 9021, VKD3D_SHADER_WARNING_VSIR_DYNAMIC_DESCRIPTOR_ARRAY = 9300, -- 2.45.2