wine-staging/patches/vkd3d-latest/0005-Updated-vkd3d-to-a597dc8755af5d2ef4826f1b570927379af.patch
2023-08-31 09:25:00 +10:00

1609 lines
60 KiB
Diff

From 464fcf91e1a7e67b22c83e29d0ea3ec5dceecd35 Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
Date: Thu, 31 Aug 2023 09:08:26 +1000
Subject: [PATCH] Updated vkd3d to a597dc8755af5d2ef4826f1b570927379afc5824.
---
libs/vkd3d/include/vkd3d_shader.h | 2 +
libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 11 +-
libs/vkd3d/libs/vkd3d-shader/dxil.c | 620 +++++++++++++++++-
libs/vkd3d/libs/vkd3d-shader/hlsl.c | 75 ++-
libs/vkd3d/libs/vkd3d-shader/hlsl.h | 13 +
libs/vkd3d/libs/vkd3d-shader/hlsl.y | 316 ++++-----
libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 25 +-
libs/vkd3d/libs/vkd3d-shader/ir.c | 2 +-
libs/vkd3d/libs/vkd3d-shader/spirv.c | 13 +-
.../libs/vkd3d-shader/vkd3d_shader_main.c | 3 -
.../libs/vkd3d-shader/vkd3d_shader_private.h | 10 +
11 files changed, 848 insertions(+), 242 deletions(-)
diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h
index cfe54dbff53..d329e205fd1 100644
--- a/libs/vkd3d/include/vkd3d_shader.h
+++ b/libs/vkd3d/include/vkd3d_shader.h
@@ -1463,6 +1463,8 @@ enum vkd3d_shader_sysval_semantic
VKD3D_SHADER_SV_TESS_FACTOR_TRIINT = 0x0e,
VKD3D_SHADER_SV_TESS_FACTOR_LINEDET = 0x0f,
VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN = 0x10,
+ /** Render target; SV_Target in Direct3D shader model 6 shaders. */
+ VKD3D_SHADER_SV_TARGET = 0x40,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SYSVAL_SEMANTIC),
};
diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c
index 99a5bd7a438..2b02d51f59a 100644
--- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c
+++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c
@@ -1638,17 +1638,12 @@ static void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffe
if (var->is_param && var->is_uniform)
{
- struct vkd3d_string_buffer *name;
+ char *new_name;
- if (!(name = hlsl_get_string_buffer(ctx)))
- {
- buffer->status = VKD3D_ERROR_OUT_OF_MEMORY;
+ if (!(new_name = hlsl_sprintf_alloc(ctx, "$%s", var->name)))
return;
- }
- vkd3d_string_buffer_printf(name, "$%s", var->name);
vkd3d_free((char *)var->name);
- var->name = hlsl_strdup(ctx, name->buffer);
- hlsl_release_string_buffer(ctx, name);
+ var->name = new_name;
}
}
}
diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c
index f9efe47f95d..666d8b08614 100644
--- a/libs/vkd3d/libs/vkd3d-shader/dxil.c
+++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c
@@ -22,6 +22,7 @@
#define VKD3D_SM6_VERSION_MINOR(version) (((version) >> 0) & 0xf)
#define BITCODE_MAGIC VKD3D_MAKE_TAG('B', 'C', 0xc0, 0xde)
+#define DXIL_OP_MAX_OPERANDS 17
enum bitcode_block_id
{
@@ -138,6 +139,11 @@ enum bitcode_value_symtab_code
VST_CODE_BBENTRY = 2,
};
+enum dx_intrinsic_opcode
+{
+ DX_STORE_OUTPUT = 5,
+};
+
struct sm6_pointer_info
{
const struct sm6_type *type;
@@ -242,6 +248,8 @@ struct sm6_function
struct sm6_block *blocks[1];
size_t block_count;
+
+ size_t value_count;
};
struct dxil_block
@@ -287,12 +295,15 @@ struct sm6_parser
struct sm6_symbol *global_symbols;
size_t global_symbol_count;
+ struct vkd3d_shader_dst_param *output_params;
+
struct sm6_function *functions;
size_t function_count;
struct sm6_value *values;
size_t value_count;
size_t value_capacity;
+ size_t cur_max_value;
struct vkd3d_shader_parser p;
};
@@ -316,6 +327,8 @@ struct dxil_global_abbrev
struct dxil_abbrev abbrev;
};
+static const uint64_t CALL_CONV_FLAG_EXPLICIT_TYPE = 1ull << 15;
+
static size_t size_add_with_overflow_check(size_t a, size_t b)
{
size_t i = a + b;
@@ -1261,6 +1274,16 @@ static inline bool sm6_type_is_integer(const struct sm6_type *type)
return type->class == TYPE_CLASS_INTEGER;
}
+static inline bool sm6_type_is_i8(const struct sm6_type *type)
+{
+ return type->class == TYPE_CLASS_INTEGER && type->u.width == 8;
+}
+
+static inline bool sm6_type_is_i32(const struct sm6_type *type)
+{
+ return type->class == TYPE_CLASS_INTEGER && type->u.width == 32;
+}
+
static inline bool sm6_type_is_floating_point(const struct sm6_type *type)
{
return type->class == TYPE_CLASS_FLOAT;
@@ -1341,6 +1364,30 @@ static const struct sm6_type *sm6_type_get_pointer_to_type(const struct sm6_type
return NULL;
}
+/* Never returns null for elem_idx 0. */
+static const struct sm6_type *sm6_type_get_scalar_type(const struct sm6_type *type, unsigned int elem_idx)
+{
+ switch (type->class)
+ {
+ case TYPE_CLASS_ARRAY:
+ case TYPE_CLASS_VECTOR:
+ if (elem_idx >= type->u.array.count)
+ return NULL;
+ return sm6_type_get_scalar_type(type->u.array.elem_type, 0);
+
+ case TYPE_CLASS_POINTER:
+ return sm6_type_get_scalar_type(type->u.pointer.type, 0);
+
+ case TYPE_CLASS_STRUCT:
+ if (elem_idx >= type->u.struc->elem_count)
+ return NULL;
+ return sm6_type_get_scalar_type(type->u.struc->elem_types[elem_idx], 0);
+
+ default:
+ return type;
+ }
+}
+
static const struct sm6_type *sm6_parser_get_type(struct sm6_parser *sm6, uint64_t type_id)
{
if (type_id >= sm6->type_count)
@@ -1443,9 +1490,32 @@ static const char *sm6_parser_get_global_symbol_name(const struct sm6_parser *sm
return NULL;
}
+static unsigned int register_get_uint_value(const struct vkd3d_shader_register *reg)
+{
+ if (!register_is_constant(reg) || !data_type_is_integer(reg->data_type))
+ return UINT_MAX;
+
+ if (reg->immconst_type == VKD3D_IMMCONST_VEC4)
+ WARN("Returning vec4.x.\n");
+
+ if (reg->type == VKD3DSPR_IMMCONST64)
+ {
+ if (reg->u.immconst_uint64[0] > UINT_MAX)
+ FIXME("Truncating 64-bit value.\n");
+ return reg->u.immconst_uint64[0];
+ }
+
+ return reg->u.immconst_uint[0];
+}
+
+static inline bool sm6_value_is_function_dcl(const struct sm6_value *value)
+{
+ return value->value_type == VALUE_TYPE_FUNCTION;
+}
+
static inline bool sm6_value_is_dx_intrinsic_dcl(const struct sm6_value *fn)
{
- assert(fn->value_type == VALUE_TYPE_FUNCTION);
+ assert(sm6_value_is_function_dcl(fn));
return fn->u.function.is_prototype && !strncmp(fn->u.function.name, "dx.op.", 6);
}
@@ -1455,6 +1525,60 @@ static inline struct sm6_value *sm6_parser_get_current_value(const struct sm6_pa
return &sm6->values[sm6->value_count];
}
+static inline bool sm6_value_is_register(const struct sm6_value *value)
+{
+ return value->value_type == VALUE_TYPE_REG;
+}
+
+static inline bool sm6_value_is_constant(const struct sm6_value *value)
+{
+ return sm6_value_is_register(value) && register_is_constant(&value->u.reg);
+}
+
+static inline bool sm6_value_is_undef(const struct sm6_value *value)
+{
+ return sm6_value_is_register(value) && value->u.reg.type == VKD3DSPR_UNDEF;
+}
+
+static inline unsigned int sm6_value_get_constant_uint(const struct sm6_value *value)
+{
+ if (!sm6_value_is_constant(value))
+ return UINT_MAX;
+ return register_get_uint_value(&value->u.reg);
+}
+
+static struct vkd3d_shader_src_param *instruction_src_params_alloc(struct vkd3d_shader_instruction *ins,
+ unsigned int count, struct sm6_parser *sm6)
+{
+ struct vkd3d_shader_src_param *params = shader_parser_get_src_params(&sm6->p, count);
+ if (!params)
+ {
+ ERR("Failed to allocate src params.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ "Out of memory allocating instruction src paramaters.");
+ return NULL;
+ }
+ ins->src = params;
+ ins->src_count = count;
+ return params;
+}
+
+static struct vkd3d_shader_dst_param *instruction_dst_params_alloc(struct vkd3d_shader_instruction *ins,
+ unsigned int count, struct sm6_parser *sm6)
+{
+ struct vkd3d_shader_dst_param *params = shader_parser_get_dst_params(&sm6->p, count);
+ if (!params)
+ {
+ ERR("Failed to allocate dst params.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ "Out of memory allocating instruction dst paramaters.");
+ return NULL;
+ }
+ ins->dst = params;
+ ins->dst_count = count;
+ return params;
+}
+
static enum vkd3d_data_type vkd3d_data_type_from_sm6_type(const struct sm6_type *type)
{
if (type->class == TYPE_CLASS_INTEGER)
@@ -1488,6 +1612,47 @@ static enum vkd3d_data_type vkd3d_data_type_from_sm6_type(const struct sm6_type
return VKD3D_DATA_UINT;
}
+static inline void dst_param_init_scalar(struct vkd3d_shader_dst_param *param, unsigned int component_idx)
+{
+ param->write_mask = 1u << component_idx;
+ param->modifiers = 0;
+ param->shift = 0;
+}
+
+static inline void src_param_init(struct vkd3d_shader_src_param *param)
+{
+ param->swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X);
+ param->modifiers = VKD3DSPSM_NONE;
+}
+
+static void src_param_init_from_value(struct vkd3d_shader_src_param *param, const struct sm6_value *src)
+{
+ src_param_init(param);
+ param->reg = src->u.reg;
+}
+
+static void register_address_init(struct vkd3d_shader_register *reg, const struct sm6_value *address,
+ unsigned int idx, struct sm6_parser *sm6)
+{
+ assert(idx < ARRAY_SIZE(reg->idx));
+ if (sm6_value_is_constant(address))
+ {
+ reg->idx[idx].offset = sm6_value_get_constant_uint(address);
+ }
+ else if (sm6_value_is_undef(address))
+ {
+ reg->idx[idx].offset = 0;
+ }
+ else
+ {
+ struct vkd3d_shader_src_param *rel_addr = shader_parser_get_src_params(&sm6->p, 1);
+ if (rel_addr)
+ src_param_init_from_value(rel_addr, address);
+ reg->idx[idx].offset = 0;
+ reg->idx[idx].rel_addr = rel_addr;
+ }
+}
+
/* Recurse through the block tree while maintaining a current value count. The current
* count is the sum of the global count plus all declarations within the current function.
* Store into value_capacity the highest count seen. */
@@ -1513,6 +1678,7 @@ static size_t sm6_parser_compute_max_value_count(struct sm6_parser *sm6,
* overestimate the value count somewhat, but this should be no problem. */
value_count = size_add_with_overflow_check(value_count, max(block->record_count, 1u) - 1);
sm6->value_capacity = max(sm6->value_capacity, value_count);
+ sm6->functions[sm6->function_count].value_count = value_count;
/* The value count returns to its previous value after handling a function. */
if (value_count < SIZE_MAX)
value_count = old_value_count;
@@ -1524,6 +1690,77 @@ static size_t sm6_parser_compute_max_value_count(struct sm6_parser *sm6,
return value_count;
}
+static size_t sm6_parser_get_value_index(struct sm6_parser *sm6, uint64_t idx)
+{
+ size_t i;
+
+ /* The value relative index is 32 bits. */
+ if (idx > UINT32_MAX)
+ WARN("Ignoring upper 32 bits of relative index.\n");
+ i = (uint32_t)sm6->value_count - (uint32_t)idx;
+
+ /* This may underflow to produce a forward reference, but it must not exceeed the final value count. */
+ if (i >= sm6->cur_max_value)
+ {
+ WARN("Invalid value index %"PRIx64" at %zu.\n", idx, sm6->value_count);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Invalid value relative index %u.", (unsigned int)idx);
+ return SIZE_MAX;
+ }
+ if (i == sm6->value_count)
+ {
+ WARN("Invalid value self-reference at %zu.\n", sm6->value_count);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Invalid value self-reference.");
+ return SIZE_MAX;
+ }
+
+ return i;
+}
+
+static size_t sm6_parser_get_value_idx_by_ref(struct sm6_parser *sm6, const struct dxil_record *record,
+ const struct sm6_type *fwd_type, unsigned int *rec_idx)
+{
+ unsigned int idx;
+ uint64_t val_ref;
+ size_t operand;
+
+ idx = *rec_idx;
+ if (!dxil_record_validate_operand_min_count(record, idx + 1, sm6))
+ return SIZE_MAX;
+ val_ref = record->operands[idx++];
+
+ operand = sm6_parser_get_value_index(sm6, val_ref);
+ if (operand == SIZE_MAX)
+ return SIZE_MAX;
+
+ if (operand >= sm6->value_count)
+ {
+ if (!fwd_type)
+ {
+ /* Forward references are followed by a type id unless an earlier operand set the type,
+ * or it is contained in a function declaration. */
+ if (!dxil_record_validate_operand_min_count(record, idx + 1, sm6))
+ return SIZE_MAX;
+ if (!(fwd_type = sm6_parser_get_type(sm6, record->operands[idx++])))
+ return SIZE_MAX;
+ }
+ FIXME("Forward value references are not supported yet.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Unsupported value forward reference.");
+ return SIZE_MAX;
+ }
+ *rec_idx = idx;
+
+ return operand;
+}
+
+static const struct sm6_value *sm6_parser_get_value_by_ref(struct sm6_parser *sm6,
+ const struct dxil_record *record, const struct sm6_type *type, unsigned int *rec_idx)
+{
+ size_t operand = sm6_parser_get_value_idx_by_ref(sm6, record, type, rec_idx);
+ return operand == SIZE_MAX ? NULL : &sm6->values[operand];
+}
+
static bool sm6_parser_declare_function(struct sm6_parser *sm6, const struct dxil_record *record)
{
const unsigned int max_count = 15;
@@ -1816,6 +2053,81 @@ static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6)
return VKD3D_OK;
}
+static void dst_param_io_init(struct vkd3d_shader_dst_param *param,
+ const struct signature_element *e, enum vkd3d_shader_register_type reg_type)
+{
+ enum vkd3d_shader_component_type component_type;
+
+ param->write_mask = e->mask;
+ param->modifiers = 0;
+ param->shift = 0;
+ /* DXIL types do not have signedness. Load signed elements as unsigned. */
+ component_type = e->component_type == VKD3D_SHADER_COMPONENT_INT ? VKD3D_SHADER_COMPONENT_UINT : e->component_type;
+ shader_register_init(&param->reg, reg_type, vkd3d_data_type_from_component_type(component_type), 0);
+}
+
+static void sm6_parser_init_signature(struct sm6_parser *sm6, const struct shader_signature *s,
+ enum vkd3d_shader_register_type reg_type, struct vkd3d_shader_dst_param *params)
+{
+ struct vkd3d_shader_dst_param *param;
+ const struct signature_element *e;
+ unsigned int i;
+
+ for (i = 0; i < s->element_count; ++i)
+ {
+ e = &s->elements[i];
+
+ param = &params[i];
+ dst_param_io_init(param, e, reg_type);
+ param->reg.idx[0].offset = i;
+ param->reg.idx_count = 1;
+ }
+}
+
+static void sm6_parser_emit_signature(struct sm6_parser *sm6, const struct shader_signature *s,
+ enum vkd3d_shader_opcode handler_idx, enum vkd3d_shader_opcode siv_handler_idx,
+ struct vkd3d_shader_dst_param *params)
+{
+ struct vkd3d_shader_instruction *ins;
+ struct vkd3d_shader_dst_param *param;
+ const struct signature_element *e;
+ unsigned int i;
+
+ for (i = 0; i < s->element_count; ++i)
+ {
+ e = &s->elements[i];
+
+ /* Do not check e->used_mask because in some cases it is zero for used elements.
+ * TODO: scan ahead for used I/O elements. */
+
+ if (e->sysval_semantic != VKD3D_SHADER_SV_NONE && e->sysval_semantic != VKD3D_SHADER_SV_TARGET)
+ {
+ ins = sm6_parser_add_instruction(sm6, siv_handler_idx);
+ param = &ins->declaration.register_semantic.reg;
+ ins->declaration.register_semantic.sysval_semantic = vkd3d_siv_from_sysval(e->sysval_semantic);
+ }
+ else
+ {
+ ins = sm6_parser_add_instruction(sm6, handler_idx);
+ param = &ins->declaration.dst;
+ }
+
+ *param = params[i];
+ }
+}
+
+static void sm6_parser_init_output_signature(struct sm6_parser *sm6, const struct shader_signature *output_signature)
+{
+ sm6_parser_init_signature(sm6, output_signature,
+ (sm6->p.shader_version.type == VKD3D_SHADER_TYPE_PIXEL) ? VKD3DSPR_COLOROUT : VKD3DSPR_OUTPUT,
+ sm6->output_params);
+}
+
+static void sm6_parser_emit_output_signature(struct sm6_parser *sm6, const struct shader_signature *output_signature)
+{
+ sm6_parser_emit_signature(sm6, output_signature, VKD3DSIH_DCL_OUTPUT, VKD3DSIH_DCL_OUTPUT_SIV, sm6->output_params);
+}
+
static const struct sm6_value *sm6_parser_next_function_definition(struct sm6_parser *sm6)
{
size_t i, count = sm6->function_count;
@@ -1838,6 +2150,258 @@ static struct sm6_block *sm6_block_create()
return block;
}
+static void sm6_parser_emit_dx_store_output(struct sm6_parser *sm6, struct sm6_block *code_block,
+ enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins)
+{
+ struct vkd3d_shader_src_param *src_param;
+ struct vkd3d_shader_dst_param *dst_param;
+ const struct shader_signature *signature;
+ unsigned int row_index, column_index;
+ const struct signature_element *e;
+ const struct sm6_value *value;
+
+ row_index = sm6_value_get_constant_uint(operands[0]);
+ column_index = sm6_value_get_constant_uint(operands[2]);
+
+ signature = &sm6->p.shader_desc.output_signature;
+ if (row_index >= signature->element_count)
+ {
+ WARN("Invalid row index %u.\n", row_index);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Invalid output row index %u.", row_index);
+ return;
+ }
+ e = &signature->elements[row_index];
+
+ if (column_index >= VKD3D_VEC4_SIZE)
+ {
+ WARN("Invalid column index %u.\n", column_index);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Invalid output column index %u.", column_index);
+ return;
+ }
+
+ value = operands[3];
+ if (!sm6_value_is_register(value))
+ {
+ WARN("Source value is not a register.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Expected store operation source to be a register.");
+ return;
+ }
+
+ shader_instruction_init(ins, VKD3DSIH_MOV);
+
+ if (!(dst_param = instruction_dst_params_alloc(ins, 1, sm6)))
+ return;
+ dst_param_init_scalar(dst_param, column_index);
+ dst_param->reg = sm6->output_params[row_index].reg;
+ if (e->register_count > 1)
+ register_address_init(&dst_param->reg, operands[1], 0, sm6);
+
+ if ((src_param = instruction_src_params_alloc(ins, 1, sm6)))
+ src_param_init_from_value(src_param, value);
+}
+
+struct sm6_dx_opcode_info
+{
+ const char ret_type;
+ const char *operand_info;
+ void (*handler)(struct sm6_parser *, struct sm6_block *, enum dx_intrinsic_opcode,
+ const struct sm6_value **, struct vkd3d_shader_instruction *);
+};
+
+/*
+ 8 -> int8
+ i -> int32
+ v -> void
+ o -> overloaded
+ */
+static const struct sm6_dx_opcode_info sm6_dx_op_table[] =
+{
+ [DX_STORE_OUTPUT ] = {'v', "ii8o", sm6_parser_emit_dx_store_output},
+};
+
+static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struct sm6_type *type, char info_type)
+{
+ switch (info_type)
+ {
+ case 0:
+ FIXME("Invalid operand count.\n");
+ return false;
+ case '8':
+ return sm6_type_is_i8(type);
+ case 'i':
+ return sm6_type_is_i32(type);
+ case 'v':
+ return !type;
+ case 'o':
+ /* TODO: some type checking may be possible */
+ return true;
+ default:
+ FIXME("Unhandled operand code '%c'.\n", info_type);
+ return false;
+ }
+}
+
+static bool sm6_parser_validate_dx_op(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const char *name,
+ const struct sm6_value **operands, unsigned int operand_count, struct sm6_value *dst)
+{
+ const struct sm6_dx_opcode_info *info;
+ unsigned int i;
+
+ info = &sm6_dx_op_table[op];
+
+ if (!sm6_parser_validate_operand_type(sm6, dst->type, info->ret_type))
+ {
+ WARN("Failed to validate return type for dx intrinsic id %u, '%s'.\n", op, name);
+ /* Return type validation failure is not so critical. We only need to set
+ * a data type for the SSA result. */
+ }
+
+ for (i = 0; i < operand_count; ++i)
+ {
+ const struct sm6_value *value = operands[i];
+ if (!sm6_value_is_register(value) || !sm6_parser_validate_operand_type(sm6, value->type, info->operand_info[i]))
+ {
+ WARN("Failed to validate operand %u for dx intrinsic id %u, '%s'.\n", i + 1, op, name);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Operand %u for call to dx intrinsic function '%s' is invalid.", i + 1, name);
+ return false;
+ }
+ }
+ if (info->operand_info[operand_count])
+ {
+ WARN("Missing operands for dx intrinsic id %u, '%s'.\n", op, name);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT,
+ "Call to dx intrinsic function '%s' has missing operands.", name);
+ return false;
+ }
+
+ return true;
+}
+
+static void sm6_parser_emit_unhandled(struct sm6_parser *sm6, struct vkd3d_shader_instruction *ins,
+ struct sm6_value *dst)
+{
+ const struct sm6_type *type;
+
+ ins->handler_idx = VKD3DSIH_NOP;
+
+ if (!dst->type)
+ return;
+
+ type = sm6_type_get_scalar_type(dst->type, 0);
+ shader_register_init(&dst->u.reg, VKD3DSPR_UNDEF, vkd3d_data_type_from_sm6_type(type), 0);
+ /* dst->is_undefined is not set here because it flags only explicitly undefined values. */
+}
+
+static void sm6_parser_decode_dx_op(struct sm6_parser *sm6, struct sm6_block *code_block, enum dx_intrinsic_opcode op,
+ const char *name, const struct sm6_value **operands, unsigned int operand_count,
+ struct vkd3d_shader_instruction *ins, struct sm6_value *dst)
+{
+ if (op >= ARRAY_SIZE(sm6_dx_op_table) || !sm6_dx_op_table[op].operand_info)
+ {
+ FIXME("Unhandled dx intrinsic function id %u, '%s'.\n", op, name);
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_UNHANDLED_INTRINSIC,
+ "Call to intrinsic function %s is unhandled.", name);
+ sm6_parser_emit_unhandled(sm6, ins, dst);
+ return;
+ }
+
+ if (sm6_parser_validate_dx_op(sm6, op, name, operands, operand_count, dst))
+ sm6_dx_op_table[op].handler(sm6, code_block, op, operands, ins);
+ else
+ sm6_parser_emit_unhandled(sm6, ins, dst);
+}
+
+static void sm6_parser_emit_call(struct sm6_parser *sm6, const struct dxil_record *record,
+ struct sm6_block *code_block, struct vkd3d_shader_instruction *ins, struct sm6_value *dst)
+{
+ const struct sm6_value *operands[DXIL_OP_MAX_OPERANDS];
+ const struct sm6_value *fn_value, *op_value;
+ unsigned int i = 1, j, operand_count;
+ const struct sm6_type *type = NULL;
+ uint64_t call_conv;
+
+ if (!dxil_record_validate_operand_min_count(record, 2, sm6))
+ return;
+
+ /* TODO: load the 1-based attributes index from record->operands[0] and validate against attribute count. */
+
+ if ((call_conv = record->operands[i++]) & CALL_CONV_FLAG_EXPLICIT_TYPE)
+ type = sm6_parser_get_type(sm6, record->operands[i++]);
+ if (call_conv &= ~CALL_CONV_FLAG_EXPLICIT_TYPE)
+ WARN("Ignoring calling convention %#"PRIx64".\n", call_conv);
+
+ if (!(fn_value = sm6_parser_get_value_by_ref(sm6, record, NULL, &i)))
+ return;
+ if (!sm6_value_is_function_dcl(fn_value))
+ {
+ WARN("Function target value is not a function declaration.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Function call target value is not a function declaration.");
+ return;
+ }
+
+ if (type && type != fn_value->type->u.pointer.type)
+ WARN("Explicit call type does not match function type.\n");
+ type = fn_value->type->u.pointer.type;
+
+ if (!sm6_type_is_void(type->u.function->ret_type))
+ dst->type = type->u.function->ret_type;
+
+ operand_count = type->u.function->param_count;
+ if (operand_count > ARRAY_SIZE(operands))
+ {
+ WARN("Ignoring %zu operands.\n", operand_count - ARRAY_SIZE(operands));
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS,
+ "Ignoring %zu operands for function call.", operand_count - ARRAY_SIZE(operands));
+ operand_count = ARRAY_SIZE(operands);
+ }
+
+ for (j = 0; j < operand_count; ++j)
+ {
+ if (!(operands[j] = sm6_parser_get_value_by_ref(sm6, record, type->u.function->param_types[j], &i)))
+ return;
+ }
+ if ((j = record->operand_count - i))
+ {
+ WARN("Ignoring %u operands beyond the function parameter list.\n", j);
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS,
+ "Ignoring %u function call operands beyond the parameter list.", j);
+ }
+
+ if (!fn_value->u.function.is_prototype)
+ {
+ FIXME("Unhandled call to local function.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Call to a local function is unsupported.");
+ return;
+ }
+ if (!sm6_value_is_dx_intrinsic_dcl(fn_value))
+ WARN("External function is not a dx intrinsic.\n");
+
+ if (!operand_count)
+ {
+ WARN("Missing dx intrinsic function id.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT,
+ "The id for a dx intrinsic function is missing.");
+ return;
+ }
+
+ op_value = operands[0];
+ if (!sm6_value_is_constant(op_value) || !sm6_type_is_integer(op_value->type))
+ {
+ WARN("dx intrinsic function id is not a constant int.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Expected a constant integer dx intrinsic function id.");
+ return;
+ }
+ sm6_parser_decode_dx_op(sm6, code_block, register_get_uint_value(&op_value->u.reg),
+ fn_value->u.function.name, &operands[1], operand_count - 1, ins, dst);
+}
+
static void sm6_parser_emit_ret(struct sm6_parser *sm6, const struct dxil_record *record,
struct sm6_block *code_block, struct vkd3d_shader_instruction *ins)
{
@@ -1855,15 +2419,10 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
{
struct vkd3d_shader_instruction *ins;
const struct dxil_record *record;
+ bool ret_found, is_terminator;
struct sm6_block *code_block;
struct sm6_value *dst;
size_t i, block_idx;
- bool ret_found;
- enum
- {
- RESULT_VALUE,
- RESULT_TERMINATE,
- } result_type;
if (sm6->function_count)
{
@@ -1907,10 +2466,20 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
}
code_block = function->blocks[0];
+ sm6->cur_max_value = function->value_count;
+
for (i = 1, block_idx = 0, ret_found = false; i < block->record_count; ++i)
{
sm6->p.location.column = i;
+ if (!code_block)
+ {
+ WARN("Invalid block count %zu.\n", function->block_count);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Invalid block count %zu.", function->block_count);
+ return VKD3D_ERROR_INVALID_SHADER;
+ }
+
/* block->record_count - 1 is the instruction count, but some instructions
* can emit >1 IR instruction, so extra may be used. */
if (!vkd3d_array_reserve((void **)&code_block->instructions, &code_block->instruction_capacity,
@@ -1926,14 +2495,17 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
dst = sm6_parser_get_current_value(sm6);
dst->type = NULL;
dst->value_type = VALUE_TYPE_REG;
- result_type = RESULT_VALUE;
+ is_terminator = false;
record = block->records[i];
switch (record->code)
{
+ case FUNC_CODE_INST_CALL:
+ sm6_parser_emit_call(sm6, record, code_block, ins, dst);
+ break;
case FUNC_CODE_INST_RET:
sm6_parser_emit_ret(sm6, record, code_block, ins);
- result_type = RESULT_TERMINATE;
+ is_terminator = true;
ret_found = true;
break;
default:
@@ -1941,7 +2513,11 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
return VKD3D_ERROR_INVALID_SHADER;
}
- if (result_type == RESULT_TERMINATE)
+ if (sm6->p.failed)
+ return VKD3D_ERROR;
+ assert(ins->handler_idx != VKD3DSIH_INVALID);
+
+ if (is_terminator)
{
++block_idx;
code_block = (block_idx < function->block_count) ? function->blocks[block_idx] : NULL;
@@ -1950,6 +2526,7 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
code_block->instruction_count += ins->handler_idx != VKD3DSIH_NOP;
else
assert(ins->handler_idx == VKD3DSIH_NOP);
+
sm6->value_count += !!dst->type;
}
@@ -1996,6 +2573,8 @@ static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const st
switch (block->id)
{
case CONSTANTS_BLOCK:
+ function = &sm6->functions[sm6->function_count];
+ sm6->cur_max_value = function->value_count;
return sm6_parser_constants_init(sm6, block);
case FUNCTION_BLOCK:
@@ -2103,6 +2682,7 @@ static const struct vkd3d_shader_parser_ops sm6_parser_ops =
static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t *byte_code, size_t byte_code_size,
const char *source_name, struct vkd3d_shader_message_context *message_context)
{
+ const struct shader_signature *output_signature = &sm6->p.shader_desc.output_signature;
const struct vkd3d_shader_location location = {.source_name = source_name};
uint32_t version_token, dxil_version, token_count, magic;
unsigned int chunk_offset, chunk_size;
@@ -2258,6 +2838,14 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
return ret;
}
+ if (!(sm6->output_params = shader_parser_get_dst_params(&sm6->p, output_signature->element_count)))
+ {
+ ERR("Failed to allocate output parameters.\n");
+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ "Out of memory allocating output parameters.");
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+ }
+
function_count = dxil_block_compute_function_count(&sm6->root_block);
if (!(sm6->functions = vkd3d_calloc(function_count, sizeof(*sm6->functions))))
{
@@ -2288,6 +2876,8 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
return ret;
}
+ sm6_parser_init_output_signature(sm6, output_signature);
+
if ((ret = sm6_parser_module_init(sm6, &sm6->root_block, 0)) < 0)
{
if (ret == VKD3D_ERROR_OUT_OF_MEMORY)
@@ -2296,11 +2886,17 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
else if (ret == VKD3D_ERROR_INVALID_SHADER)
vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE,
"DXIL module is invalid.");
- else
- vkd3d_unreachable();
return ret;
}
+ if (!sm6_parser_require_space(sm6, output_signature->element_count))
+ {
+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ "Out of memory emitting shader signature declarations.");
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+ }
+ sm6_parser_emit_output_signature(sm6, output_signature);
+
for (i = 0; i < sm6->function_count; ++i)
{
if (!sm6_block_emit_instructions(sm6->functions[i].blocks[0], sm6))
diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c
index 8b706e1e667..b8cf6813f67 100644
--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c
+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c
@@ -72,6 +72,27 @@ void hlsl_fixme(struct hlsl_ctx *ctx, const struct vkd3d_shader_location *loc, c
ctx->result = VKD3D_ERROR_NOT_IMPLEMENTED;
}
+char *hlsl_sprintf_alloc(struct hlsl_ctx *ctx, const char *fmt, ...)
+{
+ struct vkd3d_string_buffer *string;
+ va_list args;
+ char *ret;
+
+ if (!(string = hlsl_get_string_buffer(ctx)))
+ return NULL;
+ va_start(args, fmt);
+ if (vkd3d_string_buffer_vprintf(string, fmt, args) < 0)
+ {
+ va_end(args);
+ hlsl_release_string_buffer(ctx, string);
+ return NULL;
+ }
+ va_end(args);
+ ret = hlsl_strdup(ctx, string->buffer);
+ hlsl_release_string_buffer(ctx, string);
+ return ret;
+}
+
bool hlsl_add_var(struct hlsl_ctx *ctx, struct hlsl_ir_var *decl, bool local_var)
{
struct hlsl_scope *scope = ctx->cur_scope;
@@ -1039,11 +1060,10 @@ struct hlsl_ir_var *hlsl_new_synthetic_var(struct hlsl_ctx *ctx, const char *tem
{
struct vkd3d_string_buffer *string;
struct hlsl_ir_var *var;
- static LONG counter;
if (!(string = hlsl_get_string_buffer(ctx)))
return NULL;
- vkd3d_string_buffer_printf(string, "<%s-%u>", template, InterlockedIncrement(&counter));
+ vkd3d_string_buffer_printf(string, "<%s-%u>", template, ctx->internal_name_counter++);
var = hlsl_new_synthetic_var_named(ctx, string->buffer, type, loc, true);
hlsl_release_string_buffer(ctx, string);
return var;
@@ -2968,6 +2988,16 @@ void hlsl_add_function(struct hlsl_ctx *ctx, char *name, struct hlsl_ir_function
struct hlsl_ir_function *func;
struct rb_entry *func_entry;
+ if (ctx->internal_func_name)
+ {
+ char *internal_name;
+
+ if (!(internal_name = hlsl_strdup(ctx, ctx->internal_func_name)))
+ return;
+ vkd3d_free(name);
+ name = internal_name;
+ }
+
func_entry = rb_get(&ctx->functions, name);
if (func_entry)
{
@@ -3499,3 +3529,44 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d
hlsl_ctx_cleanup(&ctx);
return ret;
}
+
+struct hlsl_ir_function_decl *hlsl_compile_internal_function(struct hlsl_ctx *ctx, const char *name, const char *hlsl)
+{
+ const struct hlsl_ir_function_decl *saved_cur_function = ctx->cur_function;
+ struct vkd3d_shader_code code = {.code = hlsl, .size = strlen(hlsl)};
+ const char *saved_internal_func_name = ctx->internal_func_name;
+ struct vkd3d_string_buffer *internal_name;
+ struct hlsl_ir_function_decl *func;
+ void *saved_scanner = ctx->scanner;
+ int ret;
+
+ TRACE("name %s, hlsl %s.\n", debugstr_a(name), debugstr_a(hlsl));
+
+ /* The actual name of the function is mangled with a unique prefix, both to
+ * allow defining multiple variants of a function with the same name, and to
+ * avoid polluting the user name space. */
+
+ if (!(internal_name = hlsl_get_string_buffer(ctx)))
+ return NULL;
+ vkd3d_string_buffer_printf(internal_name, "<%s-%u>", name, ctx->internal_name_counter++);
+
+ /* Save and restore everything that matters.
+ * Note that saving the scope stack is hard, and shouldn't be necessary. */
+
+ ctx->scanner = NULL;
+ ctx->internal_func_name = internal_name->buffer;
+ ctx->cur_function = NULL;
+ ret = hlsl_lexer_compile(ctx, &code);
+ ctx->scanner = saved_scanner;
+ ctx->internal_func_name = saved_internal_func_name;
+ ctx->cur_function = saved_cur_function;
+ if (ret)
+ {
+ ERR("Failed to compile intrinsic, error %u.\n", ret);
+ hlsl_release_string_buffer(ctx, internal_name);
+ return NULL;
+ }
+ func = hlsl_get_func_decl(ctx, internal_name->buffer);
+ hlsl_release_string_buffer(ctx, internal_name);
+ return func;
+}
diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h
index 070fec74326..73b08ee3ea0 100644
--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h
+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h
@@ -798,6 +798,9 @@ struct hlsl_ctx
/* Pointer to the current function; changes as the parser reads the code. */
const struct hlsl_ir_function_decl *cur_function;
+ /* Counter for generating unique internal variable names. */
+ unsigned int internal_name_counter;
+
/* Default matrix majority for matrix types. Can be set by a pragma within the HLSL source. */
unsigned int matrix_majority;
@@ -834,6 +837,12 @@ struct hlsl_ctx
* compute shader profiles. It is set using the numthreads() attribute in the entry point. */
uint32_t thread_count[3];
+ /* In some cases we generate opcodes by parsing an HLSL function and then
+ * invoking it. If not NULL, this field is the name of the function that we
+ * are currently parsing, "mangled" with an internal prefix to avoid
+ * polluting the user namespace. */
+ const char *internal_func_name;
+
/* Whether the parser is inside a state block (effects' metadata) inside a variable declaration. */
uint32_t in_state_block : 1;
/* Whether the numthreads() attribute has been provided in the entry-point function. */
@@ -1069,6 +1078,8 @@ static inline unsigned int hlsl_sampler_dim_count(enum hlsl_sampler_dim dim)
}
}
+char *hlsl_sprintf_alloc(struct hlsl_ctx *ctx, const char *fmt, ...) VKD3D_PRINTF_FUNC(2, 3);
+
const char *debug_hlsl_expr_op(enum hlsl_ir_expr_op op);
const char *debug_hlsl_type(struct hlsl_ctx *ctx, const struct hlsl_type *type);
const char *debug_hlsl_writemask(unsigned int writemask);
@@ -1258,6 +1269,8 @@ bool hlsl_sm4_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_sem
bool output, enum vkd3d_shader_register_type *type, enum vkd3d_sm4_swizzle_type *swizzle_type, bool *has_idx);
int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out);
+struct hlsl_ir_function_decl *hlsl_compile_internal_function(struct hlsl_ctx *ctx, const char *name, const char *hlsl);
+
int hlsl_lexer_compile(struct hlsl_ctx *ctx, const struct vkd3d_shader_code *hlsl);
#endif
diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y
index 43ea4b4d038..161d1ab42c3 100644
--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y
+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y
@@ -2330,6 +2330,92 @@ static struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *ctx,
return args.decl;
}
+static struct hlsl_ir_node *hlsl_new_void_expr(struct hlsl_ctx *ctx, const struct vkd3d_shader_location *loc)
+{
+ struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS] = {0};
+
+ return hlsl_new_expr(ctx, HLSL_OP0_VOID, operands, ctx->builtin_types.Void, loc);
+}
+
+static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func,
+ const struct parse_initializer *args, const struct vkd3d_shader_location *loc)
+{
+ struct hlsl_ir_node *call;
+ unsigned int i;
+
+ assert(args->args_count == func->parameters.count);
+
+ for (i = 0; i < func->parameters.count; ++i)
+ {
+ struct hlsl_ir_var *param = func->parameters.vars[i];
+ struct hlsl_ir_node *arg = args->args[i];
+
+ if (!hlsl_types_are_equal(arg->data_type, param->data_type))
+ {
+ struct hlsl_ir_node *cast;
+
+ if (!(cast = add_cast(ctx, args->instrs, arg, param->data_type, &arg->loc)))
+ return false;
+ args->args[i] = cast;
+ arg = cast;
+ }
+
+ if (param->storage_modifiers & HLSL_STORAGE_IN)
+ {
+ struct hlsl_ir_node *store;
+
+ if (!(store = hlsl_new_simple_store(ctx, param, arg)))
+ return false;
+ hlsl_block_add_instr(args->instrs, store);
+ }
+ }
+
+ if (!(call = hlsl_new_call(ctx, func, loc)))
+ return false;
+ hlsl_block_add_instr(args->instrs, call);
+
+ for (i = 0; i < func->parameters.count; ++i)
+ {
+ struct hlsl_ir_var *param = func->parameters.vars[i];
+ struct hlsl_ir_node *arg = args->args[i];
+
+ if (param->storage_modifiers & HLSL_STORAGE_OUT)
+ {
+ struct hlsl_ir_load *load;
+
+ if (arg->data_type->modifiers & HLSL_MODIFIER_CONST)
+ hlsl_error(ctx, &arg->loc, VKD3D_SHADER_ERROR_HLSL_MODIFIES_CONST,
+ "Output argument to \"%s\" is const.", func->func->name);
+
+ if (!(load = hlsl_new_var_load(ctx, param, &arg->loc)))
+ return false;
+ hlsl_block_add_instr(args->instrs, &load->node);
+
+ if (!add_assignment(ctx, args->instrs, arg, ASSIGN_OP_ASSIGN, &load->node))
+ return false;
+ }
+ }
+
+ if (func->return_var)
+ {
+ struct hlsl_ir_load *load;
+
+ if (!(load = hlsl_new_var_load(ctx, func->return_var, loc)))
+ return false;
+ hlsl_block_add_instr(args->instrs, &load->node);
+ }
+ else
+ {
+ struct hlsl_ir_node *expr;
+
+ if (!(expr = hlsl_new_void_expr(ctx, loc)))
+ return false;
+ hlsl_block_add_instr(args->instrs, expr);
+ }
+
+ return true;
+}
+
static struct hlsl_ir_node *intrinsic_float_convert_arg(struct hlsl_ctx *ctx,
const struct parse_initializer *params, struct hlsl_ir_node *arg, const struct vkd3d_shader_location *loc)
{
@@ -2948,14 +3034,17 @@ static struct hlsl_ir_node * add_pow_expr(struct hlsl_ctx *ctx,
static bool intrinsic_lit(struct hlsl_ctx *ctx,
const struct parse_initializer *params, const struct vkd3d_shader_location *loc)
{
- struct hlsl_ir_node *n_l_neg, *n_h_neg, *specular_or, *specular_pow, *load;
- struct hlsl_ir_node *n_l, *n_h, *m, *diffuse, *zero, *store, *init;
- struct hlsl_constant_value init_value;
- struct hlsl_ir_load *var_load;
- struct hlsl_deref var_deref;
- struct hlsl_type *ret_type;
- struct hlsl_ir_var *var;
- struct hlsl_block block;
+ struct hlsl_ir_function_decl *func;
+
+ static const char body[] =
+ "float4 lit(float n_l, float n_h, float m)\n"
+ "{\n"
+ " float4 ret;\n"
+ " ret.xw = 1.0;\n"
+ " ret.y = max(n_l, 0);\n"
+ " ret.z = (n_l < 0 || n_h < 0) ? 0 : pow(n_h, m);\n"
+ " return ret;\n"
+ "}";
if (params->args[0]->data_type->class != HLSL_CLASS_SCALAR
|| params->args[1]->data_type->class != HLSL_CLASS_SCALAR
@@ -2965,70 +3054,10 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx,
return false;
}
- if (!(n_l = intrinsic_float_convert_arg(ctx, params, params->args[0], loc)))
- return false;
-
- if (!(n_h = intrinsic_float_convert_arg(ctx, params, params->args[1], loc)))
- return false;
-
- if (!(m = intrinsic_float_convert_arg(ctx, params, params->args[2], loc)))
- return false;
-
- ret_type = hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, 4);
-
- if (!(var = hlsl_new_synthetic_var(ctx, "lit", ret_type, loc)))
- return false;
- hlsl_init_simple_deref_from_var(&var_deref, var);
-
- init_value.u[0].f = 1.0f;
- init_value.u[1].f = 0.0f;
- init_value.u[2].f = 0.0f;
- init_value.u[3].f = 1.0f;
- if (!(init = hlsl_new_constant(ctx, ret_type, &init_value, loc)))
- return false;
- hlsl_block_add_instr(params->instrs, init);
-
- if (!(store = hlsl_new_simple_store(ctx, var, init)))
- return false;
- hlsl_block_add_instr(params->instrs, store);
-
- if (!(zero = hlsl_new_float_constant(ctx, 0.0f, loc)))
- return false;
- hlsl_block_add_instr(params->instrs, zero);
-
- /* Diffuse component. */
- if (!(diffuse = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MAX, n_l, zero, loc)))
+ if (!(func = hlsl_compile_internal_function(ctx, "lit", body)))
return false;
- if (!hlsl_new_store_component(ctx, &block, &var_deref, 1, diffuse))
- return false;
- hlsl_block_add_block(params->instrs, &block);
-
- /* Specular component. */
- if (!(n_h_neg = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, n_h, zero, loc)))
- return false;
-
- if (!(n_l_neg = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, n_l, zero, loc)))
- return false;
-
- if (!(specular_or = add_binary_logical_expr(ctx, params->instrs, HLSL_OP2_LOGIC_OR, n_l_neg, n_h_neg, loc)))
- return false;
-
- if (!(specular_pow = add_pow_expr(ctx, params->instrs, n_h, m, loc)))
- return false;
-
- if (!(load = hlsl_add_conditional(ctx, params->instrs, specular_or, zero, specular_pow)))
- return false;
-
- if (!hlsl_new_store_component(ctx, &block, &var_deref, 2, load))
- return false;
- hlsl_block_add_block(params->instrs, &block);
-
- if (!(var_load = hlsl_new_var_load(ctx, var, loc)))
- return false;
- hlsl_block_add_instr(params->instrs, &var_load->node);
-
- return true;
+ return add_user_call(ctx, func, params, loc);
}
static bool intrinsic_log(struct hlsl_ctx *ctx,
@@ -3336,58 +3365,29 @@ static bool intrinsic_sin(struct hlsl_ctx *ctx,
static bool intrinsic_smoothstep(struct hlsl_ctx *ctx,
const struct parse_initializer *params, const struct vkd3d_shader_location *loc)
{
- struct hlsl_ir_node *min_arg, *max_arg, *x_arg, *p, *p_num, *p_denom, *res, *one, *minus_two, *three;
-
- if (!elementwise_intrinsic_float_convert_args(ctx, params, loc))
- return false;
-
- min_arg = params->args[0];
- max_arg = params->args[1];
- x_arg = params->args[2];
-
- if (!(min_arg = add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_NEG, min_arg, loc)))
- return false;
-
- if (!(p_num = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_ADD, x_arg, min_arg, loc)))
- return false;
-
- if (!(p_denom = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_ADD, max_arg, min_arg, loc)))
- return false;
-
- if (!(one = hlsl_new_float_constant(ctx, 1.0, loc)))
- return false;
- hlsl_block_add_instr(params->instrs, one);
-
- if (!(p_denom = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_DIV, one, p_denom, loc)))
- return false;
-
- if (!(p = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, p_num, p_denom, loc)))
- return false;
-
- if (!(p = add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_SAT, p, loc)))
- return false;
-
- if (!(minus_two = hlsl_new_float_constant(ctx, -2.0, loc)))
- return false;
- hlsl_block_add_instr(params->instrs, minus_two);
-
- if (!(three = hlsl_new_float_constant(ctx, 3.0, loc)))
- return false;
- hlsl_block_add_instr(params->instrs, three);
+ struct hlsl_ir_function_decl *func;
+ struct hlsl_type *type;
+ char *body;
- if (!(res = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, minus_two, p, loc)))
- return false;
+ static const char template[] =
+ "%s smoothstep(%s low, %s high, %s x)\n"
+ "{\n"
+ " %s p = saturate((x - low) / (high - low));\n"
+ " return (p * p) * (3 - 2 * p);\n"
+ "}";
- if (!(res = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_ADD, three, res, loc)))
+ if (!(type = elementwise_intrinsic_get_common_type(ctx, params, loc)))
return false;
+ type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy);
- if (!(p = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, p, p, loc)))
+ if (!(body = hlsl_sprintf_alloc(ctx, template, type->name, type->name, type->name, type->name, type->name)))
return false;
-
- if (!(res = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, p, res, loc)))
+ func = hlsl_compile_internal_function(ctx, "smoothstep", body);
+ vkd3d_free(body);
+ if (!func)
return false;
- return true;
+ return add_user_call(ctx, func, params, loc);
}
static bool intrinsic_sqrt(struct hlsl_ctx *ctx,
@@ -3478,6 +3478,12 @@ static bool intrinsic_tex3D(struct hlsl_ctx *ctx,
return intrinsic_tex(ctx, params, loc, "tex3D", HLSL_SAMPLER_DIM_3D);
}
+static bool intrinsic_texCUBE(struct hlsl_ctx *ctx,
+ const struct parse_initializer *params, const struct vkd3d_shader_location *loc)
+{
+ return intrinsic_tex(ctx, params, loc, "texCUBE", HLSL_SAMPLER_DIM_CUBE);
+}
+
static bool intrinsic_transpose(struct hlsl_ctx *ctx,
const struct parse_initializer *params, const struct vkd3d_shader_location *loc)
{
@@ -3648,6 +3654,7 @@ intrinsic_functions[] =
{"step", 2, true, intrinsic_step},
{"tex2D", -1, false, intrinsic_tex2D},
{"tex3D", -1, false, intrinsic_tex3D},
+ {"texCUBE", -1, false, intrinsic_texCUBE},
{"transpose", 1, true, intrinsic_transpose},
{"trunc", 1, true, intrinsic_trunc},
};
@@ -3659,13 +3666,6 @@ static int intrinsic_function_name_compare(const void *a, const void *b)
return strcmp(a, func->name);
}
-static struct hlsl_ir_node *hlsl_new_void_expr(struct hlsl_ctx *ctx, const struct vkd3d_shader_location *loc)
-{
- struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS] = {0};
-
- return hlsl_new_expr(ctx, HLSL_OP0_VOID, operands, ctx->builtin_types.Void, loc);
-}
-
static struct hlsl_block *add_call(struct hlsl_ctx *ctx, const char *name,
struct parse_initializer *args, const struct vkd3d_shader_location *loc)
{
@@ -3674,78 +3674,8 @@ static struct hlsl_block *add_call(struct hlsl_ctx *ctx, const char *name,
if ((decl = find_function_call(ctx, name, args, loc)))
{
- struct hlsl_ir_node *call;
- unsigned int i;
-
- assert(args->args_count == decl->parameters.count);
-
- for (i = 0; i < decl->parameters.count; ++i)
- {
- struct hlsl_ir_var *param = decl->parameters.vars[i];
- struct hlsl_ir_node *arg = args->args[i];
-
- if (!hlsl_types_are_equal(arg->data_type, param->data_type))
- {
- struct hlsl_ir_node *cast;
-
- if (!(cast = add_cast(ctx, args->instrs, arg, param->data_type, &arg->loc)))
- goto fail;
- args->args[i] = cast;
- arg = cast;
- }
-
- if (param->storage_modifiers & HLSL_STORAGE_IN)
- {
- struct hlsl_ir_node *store;
-
- if (!(store = hlsl_new_simple_store(ctx, param, arg)))
- goto fail;
- hlsl_block_add_instr(args->instrs, store);
- }
- }
-
- if (!(call = hlsl_new_call(ctx, decl, loc)))
+ if (!add_user_call(ctx, decl, args, loc))
goto fail;
- hlsl_block_add_instr(args->instrs, call);
-
- for (i = 0; i < decl->parameters.count; ++i)
- {
- struct hlsl_ir_var *param = decl->parameters.vars[i];
- struct hlsl_ir_node *arg = args->args[i];
-
- if (param->storage_modifiers & HLSL_STORAGE_OUT)
- {
- struct hlsl_ir_load *load;
-
- if (arg->data_type->modifiers & HLSL_MODIFIER_CONST)
- hlsl_error(ctx, &arg->loc, VKD3D_SHADER_ERROR_HLSL_MODIFIES_CONST,
- "Output argument to \"%s\" is const.", decl->func->name);
-
- if (!(load = hlsl_new_var_load(ctx, param, &arg->loc)))
- goto fail;
- hlsl_block_add_instr(args->instrs, &load->node);
-
- if (!add_assignment(ctx, args->instrs, arg, ASSIGN_OP_ASSIGN, &load->node))
- goto fail;
- }
- }
-
- if (decl->return_var)
- {
- struct hlsl_ir_load *load;
-
- if (!(load = hlsl_new_var_load(ctx, decl->return_var, loc)))
- goto fail;
- hlsl_block_add_instr(args->instrs, &load->node);
- }
- else
- {
- struct hlsl_ir_node *expr;
-
- if (!(expr = hlsl_new_void_expr(ctx, loc)))
- goto fail;
- hlsl_block_add_instr(args->instrs, expr);
- }
}
else if ((intrinsic = bsearch(name, intrinsic_functions, ARRAY_SIZE(intrinsic_functions),
sizeof(*intrinsic_functions), intrinsic_function_name_compare)))
diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c
index bae8e5f9a5f..710d2908166 100644
--- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c
+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c
@@ -163,10 +163,10 @@ static bool replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_der
* work. */
static void prepend_uniform_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_var *temp)
{
- struct vkd3d_string_buffer *name;
struct hlsl_ir_var *uniform;
struct hlsl_ir_node *store;
struct hlsl_ir_load *load;
+ char *new_name;
/* Use the synthetic name for the temp, rather than the uniform, so that we
* can write the uniform name into the shader reflection data. */
@@ -180,11 +180,9 @@ static void prepend_uniform_copy(struct hlsl_ctx *ctx, struct hlsl_block *block,
uniform->is_param = temp->is_param;
uniform->buffer = temp->buffer;
- if (!(name = hlsl_get_string_buffer(ctx)))
+ if (!(new_name = hlsl_sprintf_alloc(ctx, "<temp-%s>", temp->name)))
return;
- vkd3d_string_buffer_printf(name, "<temp-%s>", temp->name);
- temp->name = hlsl_strdup(ctx, name->buffer);
- hlsl_release_string_buffer(ctx, name);
+ temp->name = new_name;
if (!(load = hlsl_new_var_load(ctx, uniform, &temp->loc)))
return;
@@ -235,16 +233,15 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir
uint32_t index, bool output, const struct vkd3d_shader_location *loc)
{
struct hlsl_semantic new_semantic;
- struct vkd3d_string_buffer *name;
struct hlsl_ir_var *ext_var;
+ char *new_name;
- if (!(name = hlsl_get_string_buffer(ctx)))
+ if (!(new_name = hlsl_sprintf_alloc(ctx, "<%s-%s%u>", output ? "output" : "input", semantic->name, index)))
return NULL;
- vkd3d_string_buffer_printf(name, "<%s-%s%u>", output ? "output" : "input", semantic->name, index);
LIST_FOR_EACH_ENTRY(ext_var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
{
- if (!ascii_strcasecmp(ext_var->name, name->buffer))
+ if (!ascii_strcasecmp(ext_var->name, new_name))
{
if (output)
{
@@ -271,25 +268,23 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir
}
}
- hlsl_release_string_buffer(ctx, name);
+ vkd3d_free(new_name);
return ext_var;
}
}
if (!(new_semantic.name = hlsl_strdup(ctx, semantic->name)))
{
- hlsl_release_string_buffer(ctx, name);
+ vkd3d_free(new_name);
return NULL;
}
new_semantic.index = index;
- if (!(ext_var = hlsl_new_var(ctx, hlsl_strdup(ctx, name->buffer), type, loc, &new_semantic,
- modifiers, NULL)))
+ if (!(ext_var = hlsl_new_var(ctx, new_name, type, loc, &new_semantic, modifiers, NULL)))
{
- hlsl_release_string_buffer(ctx, name);
+ vkd3d_free(new_name);
hlsl_cleanup_semantic(&new_semantic);
return NULL;
}
- hlsl_release_string_buffer(ctx, name);
if (output)
ext_var->is_output_semantic = 1;
else
diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c
index 705905f7888..6d7c89653e3 100644
--- a/libs/vkd3d/libs/vkd3d-shader/ir.c
+++ b/libs/vkd3d/libs/vkd3d-shader/ir.c
@@ -296,7 +296,7 @@ static enum vkd3d_result flattener_flatten_phases(struct hull_flattener *normali
return VKD3D_OK;
}
-static void shader_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_register_type reg_type,
+void shader_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_register_type reg_type,
enum vkd3d_data_type data_type, unsigned int idx_count)
{
reg->type = reg_type;
diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c
index 9b3084538ba..f93960d6d54 100644
--- a/libs/vkd3d/libs/vkd3d-shader/spirv.c
+++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c
@@ -4792,13 +4792,16 @@ static bool is_dual_source_blending(const struct spirv_compiler *compiler)
static void calculate_clip_or_cull_distance_mask(const struct signature_element *e, uint32_t *mask)
{
+ unsigned int write_mask;
+
if (e->semantic_index >= sizeof(*mask) * CHAR_BIT / VKD3D_VEC4_SIZE)
{
FIXME("Invalid semantic index %u for clip/cull distance.\n", e->semantic_index);
return;
}
- *mask |= (e->mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * e->semantic_index);
+ write_mask = e->mask >> vkd3d_write_mask_get_component_idx(e->mask);
+ *mask |= (write_mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * e->semantic_index);
}
/* Emits arrayed SPIR-V built-in variables. */
@@ -4962,7 +4965,6 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler,
component_type = builtin->component_type;
if (!builtin->spirv_array_size)
output_component_count = builtin->component_count;
- component_idx = 0;
}
else
{
@@ -4976,14 +4978,9 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler,
|| needs_private_io_variable(builtin))
{
use_private_variable = true;
- reg_write_mask = write_mask;
- }
- else
- {
- component_idx = vkd3d_write_mask_get_component_idx(write_mask);
- reg_write_mask = write_mask >> component_idx;
}
+ reg_write_mask = write_mask >> component_idx;
vkd3d_symbol_make_register(&reg_symbol, reg);
if (rb_get(&compiler->symbol_table, &reg_symbol))
diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
index 2bc8613f2ef..a70894a160d 100644
--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
@@ -1771,9 +1771,6 @@ void *shader_param_allocator_get(struct vkd3d_shader_param_allocator *allocator,
{
void *params;
- if (!count)
- return NULL;
-
if (count > allocator->count - allocator->index)
{
struct vkd3d_shader_param_node *next = shader_param_allocator_node_create(allocator);
diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
index 84614a4eb79..eab1c730ae9 100644
--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
@@ -173,12 +173,14 @@ enum vkd3d_shader_error
VKD3D_SHADER_ERROR_DXIL_INVALID_FUNCTION_DCL = 8009,
VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_ID = 8010,
VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE = 8011,
+ VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND = 8012,
VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER = 8300,
VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE = 8301,
VKD3D_SHADER_WARNING_DXIL_INVALID_BLOCK_LENGTH = 8302,
VKD3D_SHADER_WARNING_DXIL_INVALID_MODULE_LENGTH = 8303,
VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS = 8304,
+ VKD3D_SHADER_WARNING_DXIL_UNHANDLED_INTRINSIC = 8305,
VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED = 9000,
};
@@ -556,6 +558,11 @@ enum vkd3d_data_type
VKD3D_DATA_UINT8,
};
+static inline bool data_type_is_integer(enum vkd3d_data_type data_type)
+{
+ return data_type == VKD3D_DATA_INT || data_type == VKD3D_DATA_UINT8 || data_type == VKD3D_DATA_UINT;
+}
+
enum vkd3d_immconst_type
{
VKD3D_IMMCONST_SCALAR,
@@ -734,6 +741,9 @@ struct vkd3d_shader_register
} u;
};
+void shader_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_register_type reg_type,
+ enum vkd3d_data_type data_type, unsigned int idx_count);
+
struct vkd3d_shader_dst_param
{
struct vkd3d_shader_register reg;
--
2.40.1