You've already forked wine-staging
mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-12-15 08:03:15 -08:00
2184 lines
94 KiB
Diff
2184 lines
94 KiB
Diff
From 6d86bb0b97e0548173f19a2f6c2dc4c9d9e64190 Mon Sep 17 00:00:00 2001
|
|
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
|
|
Date: Thu, 27 Nov 2025 13:40:15 +1100
|
|
Subject: [PATCH] Updated vkd3d to 54aa285b307a8b3b7c914487290a52efc6b4d920.
|
|
|
|
---
|
|
libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 2 +-
|
|
libs/vkd3d/libs/vkd3d-shader/dxbc.c | 13 +-
|
|
libs/vkd3d/libs/vkd3d-shader/glsl.c | 4 +-
|
|
libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 172 +++-
|
|
libs/vkd3d/libs/vkd3d-shader/ir.c | 804 +++++++++++++++++-
|
|
libs/vkd3d/libs/vkd3d-shader/msl.c | 4 +-
|
|
libs/vkd3d/libs/vkd3d-shader/spirv.c | 210 +----
|
|
libs/vkd3d/libs/vkd3d-shader/tpf.c | 15 +-
|
|
.../libs/vkd3d-shader/vkd3d_shader_main.c | 50 +-
|
|
.../libs/vkd3d-shader/vkd3d_shader_private.h | 63 +-
|
|
libs/vkd3d/libs/vkd3d/device.c | 17 +
|
|
libs/vkd3d/libs/vkd3d/resource.c | 38 +-
|
|
libs/vkd3d/libs/vkd3d/vkd3d_private.h | 1 +
|
|
13 files changed, 1084 insertions(+), 309 deletions(-)
|
|
|
|
diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c
|
|
index 87a7d48acca..65c469e9a71 100644
|
|
--- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c
|
|
+++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c
|
|
@@ -1595,7 +1595,7 @@ int d3dbc_parse(const struct vkd3d_shader_compile_info *compile_info, uint64_t c
|
|
}
|
|
}
|
|
|
|
- program->has_descriptor_info = true;
|
|
+ program->normalisation_flags.has_descriptor_info = true;
|
|
|
|
if (TRACE_ON())
|
|
vsir_program_trace(program);
|
|
diff --git a/libs/vkd3d/libs/vkd3d-shader/dxbc.c b/libs/vkd3d/libs/vkd3d-shader/dxbc.c
|
|
index 45a45c3ad4a..f1533fbcd54 100644
|
|
--- a/libs/vkd3d/libs/vkd3d-shader/dxbc.c
|
|
+++ b/libs/vkd3d/libs/vkd3d-shader/dxbc.c
|
|
@@ -340,11 +340,7 @@ int vkd3d_shader_parse_dxbc(const struct vkd3d_shader_code *dxbc,
|
|
ret = parse_dxbc(dxbc, &message_context, NULL, flags, desc);
|
|
|
|
vkd3d_shader_message_context_trace_messages(&message_context);
|
|
- if (!vkd3d_shader_message_context_copy_messages(&message_context, messages) && ret >= 0)
|
|
- {
|
|
- vkd3d_shader_free_dxbc(desc);
|
|
- ret = VKD3D_ERROR_OUT_OF_MEMORY;
|
|
- }
|
|
+ vkd3d_shader_string_from_message_context(messages, &message_context);
|
|
vkd3d_shader_message_context_cleanup(&message_context);
|
|
|
|
if (ret < 0)
|
|
@@ -1106,9 +1102,7 @@ int vkd3d_shader_parse_root_signature(const struct vkd3d_shader_code *dxbc,
|
|
|
|
ret = for_each_dxbc_section(dxbc, &message_context, NULL, rts0_handler, root_signature);
|
|
vkd3d_shader_message_context_trace_messages(&message_context);
|
|
- if (!vkd3d_shader_message_context_copy_messages(&message_context, messages))
|
|
- ret = VKD3D_ERROR_OUT_OF_MEMORY;
|
|
-
|
|
+ vkd3d_shader_string_from_message_context(messages, &message_context);
|
|
vkd3d_shader_message_context_cleanup(&message_context);
|
|
if (ret < 0)
|
|
vkd3d_shader_free_root_signature(root_signature);
|
|
@@ -1558,8 +1552,7 @@ int vkd3d_shader_serialize_root_signature(const struct vkd3d_shader_versioned_ro
|
|
|
|
done:
|
|
vkd3d_shader_message_context_trace_messages(&context.message_context);
|
|
- if (!vkd3d_shader_message_context_copy_messages(&context.message_context, messages))
|
|
- ret = VKD3D_ERROR_OUT_OF_MEMORY;
|
|
+ vkd3d_shader_string_from_message_context(messages, &context.message_context);
|
|
vkd3d_shader_message_context_cleanup(&context.message_context);
|
|
return ret;
|
|
}
|
|
diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c
|
|
index 4d7505d8740..2e41a8609e4 100644
|
|
--- a/libs/vkd3d/libs/vkd3d-shader/glsl.c
|
|
+++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c
|
|
@@ -2481,8 +2481,8 @@ int glsl_compile(struct vsir_program *program, uint64_t config_flags,
|
|
return ret;
|
|
|
|
VKD3D_ASSERT(program->normalisation_level == VSIR_NORMALISED_SM6);
|
|
- VKD3D_ASSERT(program->has_descriptor_info);
|
|
- VKD3D_ASSERT(program->has_no_modifiers);
|
|
+ VKD3D_ASSERT(program->normalisation_flags.has_descriptor_info);
|
|
+ VKD3D_ASSERT(program->normalisation_flags.has_no_modifiers);
|
|
|
|
vkd3d_glsl_generator_init(&generator, program, compile_info,
|
|
combined_sampler_info, message_context);
|
|
diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c
|
|
index f1368b151aa..6add89969d9 100644
|
|
--- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c
|
|
+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c
|
|
@@ -1413,24 +1413,49 @@ static struct hlsl_ir_node *lower_matrix_swizzles(struct hlsl_ctx *ctx,
|
|
return hlsl_block_add_simple_load(ctx, block, var, &instr->loc);
|
|
}
|
|
|
|
-/* hlsl_ir_index nodes are a parse-time construct used to represent array indexing and struct
|
|
- * record access before knowing if they will be used in the lhs of an assignment --in which case
|
|
- * they are lowered into a deref-- or as the load of an element within a larger value.
|
|
- * For the latter case, this pass takes care of lowering hlsl_ir_indexes into individual
|
|
- * hlsl_ir_loads, or individual hlsl_ir_resource_loads, in case the indexing is a
|
|
- * resource access. */
|
|
-static struct hlsl_ir_node *lower_index_loads(struct hlsl_ctx *ctx,
|
|
- struct hlsl_ir_node *instr, struct hlsl_block *block)
|
|
+/* Usually when INDEX nodes are constructed, it's a direct variable load
|
|
+ * followed by the INDEX. As described below in lower_index_load(), we know in
|
|
+ * that case that the variable in question is unmodified and we can convert the
|
|
+ * INDEX to a LOAD of the same variable instead of copying it to a temp.
|
|
+ * This function is an unsophisticated heuristic meant to detect this case.
|
|
+ *
|
|
+ * For various reasons there may be CONSTANT or EXPR instructions between the
|
|
+ * two, so we have to search until we find the source node. */
|
|
+static bool is_indexed_value_known_unmodified(const struct hlsl_block *block, const struct hlsl_ir_index *index)
|
|
+{
|
|
+ const struct list *entry = &index->node.entry;
|
|
+
|
|
+ while ((entry = list_prev(&block->instrs, entry)))
|
|
+ {
|
|
+ const struct hlsl_ir_node *instr = LIST_ENTRY(entry, struct hlsl_ir_node, entry);
|
|
+
|
|
+ if (instr == index->val.node)
|
|
+ return true;
|
|
+
|
|
+ switch (instr->type)
|
|
+ {
|
|
+ case HLSL_IR_CONSTANT:
|
|
+ case HLSL_IR_EXPR:
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static struct hlsl_ir_node *lower_index_load(struct hlsl_ctx *ctx, struct hlsl_ir_index *index,
|
|
+ struct hlsl_block *block, struct hlsl_block *containing_block)
|
|
{
|
|
+ struct hlsl_ir_node *instr = &index->node;
|
|
+ const struct hlsl_deref *deref;
|
|
struct hlsl_deref var_deref;
|
|
- struct hlsl_ir_index *index;
|
|
struct hlsl_ir_load *load;
|
|
struct hlsl_ir_node *val;
|
|
struct hlsl_ir_var *var;
|
|
|
|
- if (instr->type != HLSL_IR_INDEX)
|
|
- return NULL;
|
|
- index = hlsl_ir_index(instr);
|
|
val = index->val.node;
|
|
|
|
if (hlsl_index_is_resource_access(index))
|
|
@@ -1519,11 +1544,46 @@ static struct hlsl_ir_node *lower_index_loads(struct hlsl_ctx *ctx,
|
|
}
|
|
}
|
|
|
|
- if (!(var = hlsl_new_synthetic_var(ctx, "index-val", val->data_type, &instr->loc)))
|
|
- return NULL;
|
|
- hlsl_init_simple_deref_from_var(&var_deref, var);
|
|
+ /* Indexed values don't have to be variable loads, but a LOAD must be of a
|
|
+ * variable, so we may need to copy the indexed value to a synthetic
|
|
+ * variable first.
|
|
+ * Even if an INDEX is of a variable load, due to the structure of our IR,
|
|
+ * it's legal for that variable to have been modified between the LOAD and
|
|
+ * the INDEX. For example, we can have a sequence like:
|
|
+ *
|
|
+ * 2: x
|
|
+ * 3: x = 1
|
|
+ * 4: @2[...]
|
|
+ *
|
|
+ * Because the defined semantics of the IR are essentially "pass by value",
|
|
+ * we can't just convert @4 into a LOAD of x. We have to copy it into a
|
|
+ * synthetic temp first.
|
|
+ *
|
|
+ * This situation generally doesn't actually happen with the IR that comes
|
|
+ * from parsing, but it can happen in certain cases related to function
|
|
+ * calls.
|
|
+ *
|
|
+ * Always creating an extra copy is fine in theory, since copy propagation
|
|
+ * will later undo it. Some of these variables can be extremely large,
|
|
+ * however, such that we can observe a noticeable speed improvement by
|
|
+ * avoiding the copy in the first place. */
|
|
|
|
- hlsl_block_add_simple_store(ctx, block, var, val);
|
|
+ if (val->type == HLSL_IR_LOAD && is_indexed_value_known_unmodified(containing_block, index))
|
|
+ {
|
|
+ /* Note that in a chain of indices only the first will be a LOAD.
|
|
+ * However, because we convert from top to bottom, and replace as we go,
|
|
+ * we should end up catching every index in a chain this way. */
|
|
+ deref = &hlsl_ir_load(val)->src;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (!(var = hlsl_new_synthetic_var(ctx, "index-val", val->data_type, &instr->loc)))
|
|
+ return NULL;
|
|
+ hlsl_init_simple_deref_from_var(&var_deref, var);
|
|
+ deref = &var_deref;
|
|
+
|
|
+ hlsl_block_add_simple_store(ctx, block, var, val);
|
|
+ }
|
|
|
|
if (hlsl_index_is_noncontiguous(index))
|
|
{
|
|
@@ -1543,7 +1603,7 @@ static struct hlsl_ir_node *lower_index_loads(struct hlsl_ctx *ctx,
|
|
|
|
c = hlsl_block_add_uint_constant(ctx, block, i, &instr->loc);
|
|
|
|
- if (!(load = hlsl_new_load_index(ctx, &var_deref, c, &instr->loc)))
|
|
+ if (!(load = hlsl_new_load_index(ctx, deref, c, &instr->loc)))
|
|
return NULL;
|
|
hlsl_block_add_instr(block, &load->node);
|
|
|
|
@@ -1557,7 +1617,67 @@ static struct hlsl_ir_node *lower_index_loads(struct hlsl_ctx *ctx,
|
|
return hlsl_block_add_simple_load(ctx, block, var, &instr->loc);
|
|
}
|
|
|
|
- return hlsl_block_add_load_index(ctx, block, &var_deref, index->idx.node, &instr->loc);
|
|
+ return hlsl_block_add_load_index(ctx, block, deref, index->idx.node, &instr->loc);
|
|
+}
|
|
+
|
|
+/* hlsl_ir_index nodes are a parse-time construct used to represent array
|
|
+ * indexing and struct record access before knowing if they will be used in the
|
|
+ * LHS of an assignment—in which case they are lowered into a deref—or as the
|
|
+ * load of an element within a larger value.
|
|
+ * For the latter case, this pass takes care of lowering hlsl_ir_indexes into
|
|
+ * individual hlsl_ir_load or hlsl_ir_resource_load. */
|
|
+void hlsl_lower_index_loads(struct hlsl_ctx *ctx, struct hlsl_block *block)
|
|
+{
|
|
+ struct hlsl_ir_node *instr, *next;
|
|
+
|
|
+ LIST_FOR_EACH_ENTRY_SAFE(instr, next, &block->instrs, struct hlsl_ir_node, entry)
|
|
+ {
|
|
+ switch (instr->type)
|
|
+ {
|
|
+ case HLSL_IR_INDEX:
|
|
+ {
|
|
+ struct hlsl_ir_node *replacement;
|
|
+ struct hlsl_block new_block;
|
|
+
|
|
+ hlsl_block_init(&new_block);
|
|
+ if ((replacement = lower_index_load(ctx, hlsl_ir_index(instr), &new_block, block)))
|
|
+ {
|
|
+ list_move_before(&instr->entry, &new_block.instrs);
|
|
+ hlsl_replace_node(instr, replacement);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ hlsl_block_cleanup(&new_block);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ case HLSL_IR_IF:
|
|
+ {
|
|
+ struct hlsl_ir_if *iff = hlsl_ir_if(instr);
|
|
+ hlsl_lower_index_loads(ctx, &iff->then_block);
|
|
+ hlsl_lower_index_loads(ctx, &iff->else_block);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ case HLSL_IR_LOOP:
|
|
+ hlsl_lower_index_loads(ctx, &hlsl_ir_loop(instr)->body);
|
|
+ break;
|
|
+
|
|
+ case HLSL_IR_SWITCH:
|
|
+ {
|
|
+ struct hlsl_ir_switch *s = hlsl_ir_switch(instr);
|
|
+ struct hlsl_ir_switch_case *c;
|
|
+
|
|
+ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry)
|
|
+ hlsl_lower_index_loads(ctx, &c->body);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
/* Lower casts from vec1 to vecN to swizzles. */
|
|
@@ -6439,8 +6559,9 @@ static void register_deref_usage(struct hlsl_ctx *ctx, const struct hlsl_deref *
|
|
else if (regset == HLSL_REGSET_NUMERIC)
|
|
{
|
|
type = hlsl_deref_get_type(ctx, deref);
|
|
+ VKD3D_ASSERT(type->class <= HLSL_CLASS_VECTOR);
|
|
|
|
- required_bind_count = align(index + type->reg_size[regset], 4) / 4;
|
|
+ required_bind_count = align(index + type->e.numeric.dimx, 4) / 4;
|
|
var->bind_count[regset] = max(var->bind_count[regset], required_bind_count);
|
|
}
|
|
else
|
|
@@ -7753,6 +7874,10 @@ bool hlsl_regset_index_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref
|
|
*index += 4 * idx;
|
|
break;
|
|
|
|
+ case HLSL_CLASS_VECTOR:
|
|
+ *index += idx;
|
|
+ break;
|
|
+
|
|
default:
|
|
vkd3d_unreachable();
|
|
}
|
|
@@ -8511,11 +8636,6 @@ 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)
|
|
-{
|
|
- replace_ir(ctx, lower_index_loads, body);
|
|
-}
|
|
-
|
|
static enum hlsl_ir_expr_op invert_comparison_op(enum hlsl_ir_expr_op op)
|
|
{
|
|
switch (op)
|
|
@@ -13478,7 +13598,7 @@ static void generate_vsir_descriptors(struct hlsl_ctx *ctx, struct vsir_program
|
|
}
|
|
}
|
|
|
|
- program->has_descriptor_info = true;
|
|
+ program->normalisation_flags.has_descriptor_info = true;
|
|
}
|
|
|
|
/* For some reason, for matrices, values from default value initializers end
|
|
@@ -14927,7 +15047,7 @@ static void process_entry_function(struct hlsl_ctx *ctx, struct list *semantic_v
|
|
|
|
replace_ir(ctx, lower_complex_casts, body);
|
|
replace_ir(ctx, lower_matrix_swizzles, body);
|
|
- replace_ir(ctx, lower_index_loads, body);
|
|
+ hlsl_lower_index_loads(ctx, body);
|
|
|
|
replace_ir(ctx, lower_tgsm_loads, body);
|
|
replace_ir(ctx, lower_tgsm_stores, body);
|
|
diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c
|
|
index 241006e32c6..1a0c9d83306 100644
|
|
--- a/libs/vkd3d/libs/vkd3d-shader/ir.c
|
|
+++ b/libs/vkd3d/libs/vkd3d-shader/ir.c
|
|
@@ -749,6 +749,21 @@ bool vsir_signature_find_sysval(const struct shader_signature *signature,
|
|
return false;
|
|
}
|
|
|
|
+unsigned int vsir_signature_next_location(const struct shader_signature *signature)
|
|
+{
|
|
+ unsigned int i, max_row;
|
|
+
|
|
+ if (!signature)
|
|
+ return 0;
|
|
+
|
|
+ for (i = 0, max_row = 0; i < signature->element_count; ++i)
|
|
+ {
|
|
+ max_row = max(max_row, signature->elements[i].register_index + signature->elements[i].register_count);
|
|
+ }
|
|
+
|
|
+ return max_row;
|
|
+}
|
|
+
|
|
struct vkd3d_shader_descriptor_info1 *vsir_program_add_descriptor(struct vsir_program *program,
|
|
enum vkd3d_shader_descriptor_type type, unsigned int register_id,
|
|
const struct vkd3d_shader_register_range *range,
|
|
@@ -2535,7 +2550,7 @@ static enum vkd3d_result vsir_program_lower_modifiers(struct vsir_program *progr
|
|
}
|
|
}
|
|
|
|
- program->has_no_modifiers = true;
|
|
+ program->normalisation_flags.has_no_modifiers = true;
|
|
|
|
return ret;
|
|
}
|
|
@@ -3064,11 +3079,6 @@ struct hull_flattener
|
|
unsigned int orig_ssa_count;
|
|
};
|
|
|
|
-static bool flattener_is_in_fork_or_join_phase(const struct hull_flattener *flattener)
|
|
-{
|
|
- return flattener->phase == VSIR_OP_HS_FORK_PHASE || flattener->phase == VSIR_OP_HS_JOIN_PHASE;
|
|
-}
|
|
-
|
|
static void flattener_fixup_ssa_register(struct hull_flattener *normaliser,
|
|
struct vkd3d_shader_register *reg, unsigned int instance_id)
|
|
{
|
|
@@ -3190,9 +3200,9 @@ static enum vkd3d_result flattener_flatten_phases(struct hull_flattener *normali
|
|
normaliser->phase = VSIR_OP_INVALID;
|
|
for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it))
|
|
{
|
|
- if (ins->opcode == VSIR_OP_HS_FORK_PHASE || ins->opcode == VSIR_OP_HS_JOIN_PHASE)
|
|
+ if (vsir_opcode_is_fork_or_join_phase(ins->opcode))
|
|
{
|
|
- b = flattener_is_in_fork_or_join_phase(normaliser);
|
|
+ b = vsir_opcode_is_fork_or_join_phase(normaliser->phase);
|
|
/* Reset the phase info. */
|
|
phase_body_it_valid = false;
|
|
normaliser->phase = ins->opcode;
|
|
@@ -3279,11 +3289,6 @@ struct control_point_normaliser
|
|
struct vkd3d_shader_src_param *outpointid_param;
|
|
};
|
|
|
|
-static bool control_point_normaliser_is_in_control_point_phase(const struct control_point_normaliser *normaliser)
|
|
-{
|
|
- return normaliser->phase == VSIR_OP_HS_CONTROL_POINT_PHASE;
|
|
-}
|
|
-
|
|
struct vkd3d_shader_src_param *vsir_program_create_outpointid_param(struct vsir_program *program)
|
|
{
|
|
struct vkd3d_shader_src_param *rel_addr;
|
|
@@ -3303,7 +3308,7 @@ static void shader_dst_param_normalise_outpointid(struct vkd3d_shader_dst_param
|
|
{
|
|
struct vkd3d_shader_register *reg = &dst_param->reg;
|
|
|
|
- if (control_point_normaliser_is_in_control_point_phase(normaliser) && reg->type == VKD3DSPR_OUTPUT)
|
|
+ if (vsir_opcode_is_control_point_phase(normaliser->phase) && reg->type == VKD3DSPR_OUTPUT)
|
|
{
|
|
/* The TPF reader validates idx_count. */
|
|
VKD3D_ASSERT(reg->idx_count == 1);
|
|
@@ -3468,6 +3473,7 @@ struct io_normaliser
|
|
struct shader_signature *input_signature;
|
|
struct shader_signature *output_signature;
|
|
struct shader_signature *patch_constant_signature;
|
|
+ struct vsir_normalisation_flags *normalisation_flags;
|
|
|
|
enum vkd3d_shader_opcode phase;
|
|
|
|
@@ -3481,11 +3487,6 @@ struct io_normaliser
|
|
bool use_vocp;
|
|
};
|
|
|
|
-static bool io_normaliser_is_in_fork_or_join_phase(const struct io_normaliser *normaliser)
|
|
-{
|
|
- return normaliser->phase == VSIR_OP_HS_FORK_PHASE || normaliser->phase == VSIR_OP_HS_JOIN_PHASE;
|
|
-}
|
|
-
|
|
static bool shader_signature_find_element_for_reg(const struct shader_signature *signature,
|
|
unsigned int reg_idx, unsigned int write_mask, unsigned int *element_idx)
|
|
{
|
|
@@ -3603,7 +3604,7 @@ static enum vkd3d_result io_normaliser_add_index_range(struct io_normaliser *nor
|
|
signature = normaliser->output_signature;
|
|
break;
|
|
case VKD3DSPR_OUTPUT:
|
|
- if (!io_normaliser_is_in_fork_or_join_phase(normaliser))
|
|
+ if (!vsir_opcode_is_fork_or_join_phase(normaliser->phase))
|
|
{
|
|
range_map = normaliser->output_range_map;
|
|
signature = normaliser->output_signature;
|
|
@@ -3889,7 +3890,7 @@ static bool shader_dst_param_io_normalise(struct vkd3d_shader_dst_param *dst_par
|
|
{
|
|
case VKD3DSPR_OUTPUT:
|
|
reg_idx = reg->idx[reg->idx_count - 1].offset;
|
|
- if (io_normaliser_is_in_fork_or_join_phase(normaliser))
|
|
+ if (vsir_opcode_is_fork_or_join_phase(normaliser->phase))
|
|
{
|
|
signature = normaliser->patch_constant_signature;
|
|
/* Convert patch constant outputs to the patch constant register type to avoid the need
|
|
@@ -3952,7 +3953,7 @@ static bool shader_dst_param_io_normalise(struct vkd3d_shader_dst_param *dst_par
|
|
vkd3d_unreachable();
|
|
e = &signature->elements[element_idx];
|
|
|
|
- if ((e->register_count > 1 || vsir_sysval_semantic_is_tess_factor(e->sysval_semantic)))
|
|
+ if (vsir_signature_element_is_array(e, normaliser->normalisation_flags))
|
|
id_idx = shader_register_normalise_arrayed_addressing(reg, id_idx, e->register_index);
|
|
|
|
/* Replace the register index with the signature element index */
|
|
@@ -4005,7 +4006,7 @@ static void shader_src_param_io_normalise(struct vkd3d_shader_src_param *src_par
|
|
|
|
case VKD3DSPR_OUTCONTROLPOINT:
|
|
reg->type = VKD3DSPR_OUTPUT;
|
|
- if (io_normaliser_is_in_fork_or_join_phase(normaliser))
|
|
+ if (vsir_opcode_is_fork_or_join_phase(normaliser->phase))
|
|
normaliser->use_vocp = true;
|
|
/* fall through */
|
|
case VKD3DSPR_OUTPUT:
|
|
@@ -4034,7 +4035,7 @@ static void shader_src_param_io_normalise(struct vkd3d_shader_src_param *src_par
|
|
}
|
|
|
|
e = &signature->elements[element_idx];
|
|
- if ((e->register_count > 1 || vsir_sysval_semantic_is_tess_factor(e->sysval_semantic)))
|
|
+ if (vsir_signature_element_is_array(e, normaliser->normalisation_flags))
|
|
id_idx = shader_register_normalise_arrayed_addressing(reg, id_idx, e->register_index);
|
|
reg->idx[id_idx].offset = element_idx;
|
|
reg->idx_count = id_idx + 1;
|
|
@@ -4089,6 +4090,7 @@ static enum vkd3d_result vsir_program_normalise_io_registers(struct vsir_program
|
|
normaliser.input_signature = &program->input_signature;
|
|
normaliser.output_signature = &program->output_signature;
|
|
normaliser.patch_constant_signature = &program->patch_constant_signature;
|
|
+ normaliser.normalisation_flags = &program->normalisation_flags;
|
|
|
|
for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it))
|
|
{
|
|
@@ -8091,9 +8093,9 @@ static enum vkd3d_result vsir_program_insert_clip_planes(struct vsir_program *pr
|
|
unsigned int low_signature_idx = ~0u, high_signature_idx = ~0u;
|
|
const struct vkd3d_shader_parameter1 *mask_parameter = NULL;
|
|
uint32_t position_signature_idx, position_temp, mask;
|
|
+ unsigned int plane_count, next_register_index;
|
|
struct signature_element *clip_element;
|
|
struct vkd3d_shader_instruction *ins;
|
|
- unsigned int plane_count;
|
|
int ret;
|
|
|
|
if (program->shader_version.type != VKD3D_SHADER_TYPE_VERTEX)
|
|
@@ -8149,16 +8151,18 @@ static enum vkd3d_result vsir_program_insert_clip_planes(struct vsir_program *pr
|
|
plane_count = vkd3d_popcount(mask);
|
|
|
|
/* Register mask is ignored since we operate after I/O normalisation. */
|
|
+ next_register_index = vsir_signature_next_location(signature);
|
|
if (!(clip_element = add_signature_element(signature, "SV_ClipDistance", 0,
|
|
- vkd3d_write_mask_from_component_count(min(plane_count, 4)), 0, VKD3DSIM_NONE)))
|
|
+ vkd3d_write_mask_from_component_count(min(plane_count, 4)), next_register_index, VKD3DSIM_NONE)))
|
|
return VKD3D_ERROR_OUT_OF_MEMORY;
|
|
low_signature_idx = clip_element - signature->elements;
|
|
clip_element->sysval_semantic = VKD3D_SHADER_SV_CLIP_DISTANCE;
|
|
|
|
if (plane_count > 4)
|
|
{
|
|
+ next_register_index = vsir_signature_next_location(signature);
|
|
if (!(clip_element = add_signature_element(signature, "SV_ClipDistance", 1,
|
|
- vkd3d_write_mask_from_component_count(plane_count - 4), 0, VKD3DSIM_NONE)))
|
|
+ vkd3d_write_mask_from_component_count(plane_count - 4), next_register_index, VKD3DSIM_NONE)))
|
|
return VKD3D_ERROR_OUT_OF_MEMORY;
|
|
high_signature_idx = clip_element - signature->elements;
|
|
clip_element->sysval_semantic = VKD3D_SHADER_SV_CLIP_DISTANCE;
|
|
@@ -8198,6 +8202,742 @@ static enum vkd3d_result vsir_program_insert_clip_planes(struct vsir_program *pr
|
|
return VKD3D_OK;
|
|
}
|
|
|
|
+struct sysval_array_normaliser
|
|
+{
|
|
+ struct vsir_transformation_context *ctx;
|
|
+
|
|
+ /* sysval semantic currently being normalised. */
|
|
+ enum vkd3d_shader_sysval_semantic sysval_semantic;
|
|
+ bool output;
|
|
+
|
|
+ /* Registers used by the sysval elements of the original signature. */
|
|
+ struct
|
|
+ {
|
|
+ unsigned int index;
|
|
+ unsigned int mask;
|
|
+ } regs[2];
|
|
+ unsigned int reg_count;
|
|
+
|
|
+ /* Index of the signature element created for the new array. */
|
|
+ unsigned int element_idx;
|
|
+ /* Indexable temporary reserved to store a copy of the native sysval
|
|
+ * values for the current phase. If ~0u, the temporary has not been
|
|
+ * allocated for this phase yet. */
|
|
+ unsigned int idxtemp_idx;
|
|
+
|
|
+ enum vkd3d_shader_opcode phase;
|
|
+};
|
|
+
|
|
+static enum vkd3d_result sysval_array_normaliser_add_components(
|
|
+ struct sysval_array_normaliser *normaliser, unsigned int index, unsigned int mask)
|
|
+{
|
|
+ unsigned int q;
|
|
+
|
|
+ for (q = 0; q < normaliser->reg_count; ++q)
|
|
+ {
|
|
+ if (index == normaliser->regs[q].index)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (q == normaliser->reg_count)
|
|
+ {
|
|
+ if (normaliser->reg_count >= ARRAY_SIZE(normaliser->regs))
|
|
+ {
|
|
+ vkd3d_shader_error(normaliser->ctx->message_context,
|
|
+ &normaliser->ctx->null_location, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE,
|
|
+ "Sysval semantic %#x elements require more than %zu registers.\n",
|
|
+ normaliser->sysval_semantic, ARRAY_SIZE(normaliser->regs));
|
|
+ return VKD3D_ERROR_INVALID_SHADER;
|
|
+ }
|
|
+ normaliser->reg_count += 1;
|
|
+ }
|
|
+ normaliser->regs[q].index = index;
|
|
+ normaliser->regs[q].mask |= mask;
|
|
+
|
|
+ return VKD3D_OK;
|
|
+}
|
|
+
|
|
+static enum vkd3d_result sysval_array_normaliser_init(struct vsir_transformation_context *ctx,
|
|
+ const char *semantic_name, enum vkd3d_shader_sysval_semantic sysval_semantic,
|
|
+ bool output, struct sysval_array_normaliser *normaliser)
|
|
+{
|
|
+ unsigned int component_count = 0, next_register_index;
|
|
+ struct shader_signature *signature;
|
|
+ struct signature_element *element;
|
|
+ enum vkd3d_result res;
|
|
+
|
|
+ memset(normaliser, 0, sizeof(*normaliser));
|
|
+ normaliser->ctx = ctx;
|
|
+ normaliser->sysval_semantic = sysval_semantic;
|
|
+ normaliser->output = output;
|
|
+ normaliser->element_idx = ~0u;
|
|
+
|
|
+ normaliser->phase = VSIR_OP_INVALID;
|
|
+
|
|
+ signature = output ? &ctx->program->output_signature : &ctx->program->input_signature;
|
|
+
|
|
+ for (unsigned int i = 0; i < signature->element_count; ++i)
|
|
+ {
|
|
+ element = &signature->elements[i];
|
|
+ if (element->sysval_semantic != sysval_semantic)
|
|
+ continue;
|
|
+
|
|
+ for (unsigned int j = 0; j < element->register_count; ++j)
|
|
+ {
|
|
+ if ((res = sysval_array_normaliser_add_components(normaliser,
|
|
+ element->register_index + j, element->mask)) < 0)
|
|
+ return res;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!normaliser->reg_count)
|
|
+ return VKD3D_OK;
|
|
+ next_register_index = vsir_signature_next_location(signature);
|
|
+ if (!(element = add_signature_element(signature, semantic_name, next_register_index,
|
|
+ VKD3DSP_WRITEMASK_0, signature->element_count, element->interpolation_mode)))
|
|
+ return VKD3D_ERROR_OUT_OF_MEMORY;
|
|
+ element->sysval_semantic = sysval_semantic;
|
|
+ for (unsigned int q = 0; q < normaliser->reg_count; ++q)
|
|
+ {
|
|
+ component_count += vkd3d_popcount(normaliser->regs[q].mask);
|
|
+ }
|
|
+ element->register_count = component_count;
|
|
+ normaliser->element_idx = signature->element_count - 1;
|
|
+
|
|
+ return VKD3D_OK;
|
|
+}
|
|
+
|
|
+/* For every component 'k' that belongs to an output signature element that
|
|
+ * has the sysval currently being handled by the sysval_array_normaliser, add
|
|
+ * the following instruction before the return points of the program:
|
|
+ *
|
|
+ * mov o[k][e].x, x[idxtmp_idx][q].kkkk
|
|
+ *
|
|
+ * or in case this is the control point phase of a hull shader:
|
|
+ *
|
|
+ * mov o[k][P][e].x, x[idxtmp_idx][q].kkkk
|
|
+ *
|
|
+ * where:
|
|
+ * 'q' is the index of the register containing 'k' in the normaliser's
|
|
+ * internal list.
|
|
+ * '.kkkk' is the replicated swizzle that corresponds to component 'k'.
|
|
+ * 'e' is the new array's signature element index.
|
|
+ * 'idxtmp_idx' is the index of the indexable temp reserved by the
|
|
+ * normaliser.
|
|
+ * 'P' is the output control point ID.
|
|
+ */
|
|
+static enum vkd3d_result sysval_array_normaliser_add_output_copy(
|
|
+ struct sysval_array_normaliser *normaliser, struct vsir_program_iterator *it)
|
|
+{
|
|
+ struct vsir_program *program = normaliser->ctx->program;
|
|
+ struct vkd3d_shader_src_param *outpointid_param = NULL;
|
|
+ unsigned int output_component_count = 0;
|
|
+ struct vkd3d_shader_instruction *mov;
|
|
+ struct signature_element *element;
|
|
+ struct vkd3d_shader_location loc;
|
|
+
|
|
+ if (!normaliser->output)
|
|
+ return VKD3D_OK;
|
|
+ if (vsir_opcode_is_fork_or_join_phase(normaliser->phase))
|
|
+ return VKD3D_OK;
|
|
+ if (normaliser->idxtemp_idx == ~0u)
|
|
+ return VKD3D_OK;
|
|
+
|
|
+ element = &program->output_signature.elements[normaliser->element_idx];
|
|
+ loc = vsir_program_iterator_current(it)->location;
|
|
+
|
|
+ if (program->shader_version.type == VKD3D_SHADER_TYPE_HULL
|
|
+ && !(outpointid_param = vsir_program_create_outpointid_param(program)))
|
|
+ {
|
|
+ ERR("Failed to allocate outpointid param.\n");
|
|
+ return VKD3D_ERROR_OUT_OF_MEMORY;
|
|
+ }
|
|
+
|
|
+ for (unsigned int q = 0; q < normaliser->reg_count; ++q)
|
|
+ {
|
|
+ for (unsigned int k = 0; k < VKD3D_VEC4_SIZE; ++k)
|
|
+ {
|
|
+ struct vkd3d_shader_dst_param *dst;
|
|
+ struct vkd3d_shader_src_param *src;
|
|
+
|
|
+ if (!(normaliser->regs[q].mask & (1u << k)))
|
|
+ continue;
|
|
+
|
|
+ if (!(mov = vsir_program_iterator_insert_before_and_move(it, 1)))
|
|
+ return VKD3D_ERROR_OUT_OF_MEMORY;
|
|
+
|
|
+ if (!vsir_instruction_init_with_params(program, mov, &loc, VSIR_OP_MOV, 1, 1))
|
|
+ return VKD3D_ERROR_OUT_OF_MEMORY;
|
|
+
|
|
+ dst = &mov->dst[0];
|
|
+ vsir_dst_param_init(dst, VKD3DSPR_OUTPUT, VSIR_DATA_F32, 2);
|
|
+ dst->reg.idx[0].offset = output_component_count++;
|
|
+ dst->reg.idx[1].offset = normaliser->element_idx;
|
|
+ dst->reg.dimension = VSIR_DIMENSION_VEC4;
|
|
+ dst->write_mask = VKD3DSP_WRITEMASK_0;
|
|
+ if (outpointid_param)
|
|
+ {
|
|
+ dst->reg.idx_count = 3;
|
|
+ dst->reg.idx[2] = dst->reg.idx[1];
|
|
+ dst->reg.idx[1].rel_addr = outpointid_param;
|
|
+ dst->reg.idx[1].offset = 0;
|
|
+ }
|
|
+
|
|
+ src = &mov->src[0];
|
|
+ vsir_src_param_init(src, VKD3DSPR_IDXTEMP, VSIR_DATA_F32, 2);
|
|
+ src->reg.idx[0].offset = normaliser->idxtemp_idx;
|
|
+ src->reg.idx[1].offset = q;
|
|
+ src->reg.dimension = VSIR_DIMENSION_VEC4;
|
|
+ src->swizzle = vsir_swizzle_from_writemask(1u << k);
|
|
+
|
|
+ vsir_program_iterator_next(it);
|
|
+ }
|
|
+ }
|
|
+ VKD3D_ASSERT(output_component_count == element->register_count);
|
|
+
|
|
+ return VKD3D_OK;
|
|
+}
|
|
+
|
|
+/* For every component 'k' that belongs to an input signature element that has
|
|
+ * the sysval currently being handled by the sysval_array_normaliser, add the
|
|
+ * following single instruction at the beginning of the program:
|
|
+ *
|
|
+ * mov x[idxtmp_idx][q].k, v[k][e].x
|
|
+ *
|
|
+ * or in case there are multiple input control points, add multiple
|
|
+ * instructions, one for every one of them 'p':
|
|
+ *
|
|
+ * mov x[idxtmp_idx][p * reg_count + q].k, v[k][p][e].x
|
|
+ *
|
|
+ * where:
|
|
+ * 'q' is the index of the register containing 'k' in the normaliser's
|
|
+ * internal list.
|
|
+ * '.k' is the write mask that corresponds to component 'k'
|
|
+ * 'e' is the new array's signature element index.
|
|
+ * 'idxtmp_idx' is the index of the indexable temp reserved by the
|
|
+ * normaliser.
|
|
+ * 'reg_count' is the number of registers in the normaliser's internal
|
|
+ * list.
|
|
+ *
|
|
+ * NOTE: This function also does this for components 'k' that belong to an
|
|
+ * output signature in case the normaliser is handling an output semantic and
|
|
+ * this is the fork or join phase of a hull shader, where they can be used as
|
|
+ * source operands. Naturally, 'o' registers are used as source operands on
|
|
+ * such 'mov' instructions instead of 'v'.
|
|
+ */
|
|
+static enum vkd3d_result sysval_array_normaliser_add_input_copy(
|
|
+ struct sysval_array_normaliser *normaliser, struct vsir_program_iterator *it)
|
|
+{
|
|
+ struct vsir_program *program = normaliser->ctx->program;
|
|
+ struct vkd3d_shader_instruction *mov;
|
|
+ struct signature_element *element;
|
|
+ unsigned int control_point_count;
|
|
+ struct vkd3d_shader_location loc;
|
|
+
|
|
+ loc = vsir_program_iterator_current(it)->location;
|
|
+ if (normaliser->output)
|
|
+ {
|
|
+ control_point_count = program->output_control_point_count;
|
|
+ element = &program->output_signature.elements[normaliser->element_idx];
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ control_point_count = program->input_control_point_count;
|
|
+ element = &program->input_signature.elements[normaliser->element_idx];
|
|
+ }
|
|
+
|
|
+ if (!vsir_program_iterator_insert_before_and_move(it, max(1, control_point_count) * element->register_count))
|
|
+ return VKD3D_ERROR_OUT_OF_MEMORY;
|
|
+
|
|
+ for (unsigned int p = 0; p < max(1, control_point_count); ++p)
|
|
+ {
|
|
+ unsigned int input_component_count = 0;
|
|
+
|
|
+ for (unsigned int q = 0; q < normaliser->reg_count; ++q)
|
|
+ {
|
|
+ for (unsigned int k = 0; k < VKD3D_VEC4_SIZE; ++k)
|
|
+ {
|
|
+ struct vkd3d_shader_dst_param *dst;
|
|
+ struct vkd3d_shader_src_param *src;
|
|
+
|
|
+ if (!(normaliser->regs[q].mask & (1u << k)))
|
|
+ continue;
|
|
+
|
|
+ mov = vsir_program_iterator_current(it);
|
|
+ vsir_instruction_init_with_params(program, mov, &loc, VSIR_OP_MOV, 1, 1);
|
|
+
|
|
+ dst = &mov->dst[0];
|
|
+ vsir_dst_param_init(dst, VKD3DSPR_IDXTEMP, VSIR_DATA_F32, 2);
|
|
+ dst->reg.idx[0].offset = normaliser->idxtemp_idx;
|
|
+ dst->reg.idx[1].offset = p * normaliser->reg_count + q;
|
|
+ dst->reg.dimension = VSIR_DIMENSION_VEC4;
|
|
+ dst->write_mask = 1u << k;
|
|
+
|
|
+ src = &mov->src[0];
|
|
+ if (control_point_count)
|
|
+ {
|
|
+ vsir_src_param_init(src, normaliser->output ? VKD3DSPR_OUTPUT : VKD3DSPR_INPUT, VSIR_DATA_F32, 3);
|
|
+ src->reg.idx[0].offset = input_component_count++;
|
|
+ src->reg.idx[1].offset = p;
|
|
+ src->reg.idx[2].offset = normaliser->element_idx;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ vsir_src_param_init(src, VKD3DSPR_INPUT, VSIR_DATA_F32, 2);
|
|
+ src->reg.idx[0].offset = input_component_count++;
|
|
+ src->reg.idx[1].offset = normaliser->element_idx;
|
|
+ }
|
|
+ src->reg.dimension = VSIR_DIMENSION_VEC4;
|
|
+ src->swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X);
|
|
+
|
|
+ vsir_program_iterator_next(it);
|
|
+ }
|
|
+ }
|
|
+ VKD3D_ASSERT(input_component_count == element->register_count);
|
|
+ }
|
|
+
|
|
+ return VKD3D_OK;
|
|
+}
|
|
+
|
|
+/* NOTE: This might be replaced by a single field in vsir_program at some point. */
|
|
+static unsigned int vsir_program_get_idxtemp_count(struct vsir_program *program)
|
|
+{
|
|
+ struct vsir_program_iterator it = vsir_program_iterator(&program->instructions);
|
|
+ struct vkd3d_shader_instruction *ins;
|
|
+ size_t count = 0;
|
|
+
|
|
+ for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it))
|
|
+ {
|
|
+ if (ins->opcode != VSIR_OP_DCL_INDEXABLE_TEMP)
|
|
+ continue;
|
|
+ if (count < ins->declaration.indexable_temp.register_idx)
|
|
+ count = ins->declaration.indexable_temp.register_idx;
|
|
+ }
|
|
+
|
|
+ return count;
|
|
+}
|
|
+
|
|
+static enum vkd3d_result sysval_array_normaliser_dcl_indexable_temp(
|
|
+ struct sysval_array_normaliser *normaliser, struct vsir_program_iterator *it, size_t idx)
|
|
+{
|
|
+ struct vsir_program *program = normaliser->ctx->program;
|
|
+ unsigned int register_size = normaliser->reg_count;
|
|
+ struct vkd3d_shader_indexable_temp *t;
|
|
+ struct vkd3d_shader_instruction *ins;
|
|
+ unsigned int control_point_count;
|
|
+
|
|
+ normaliser->idxtemp_idx = idx;
|
|
+ control_point_count = normaliser->output
|
|
+ ? program->output_control_point_count : program->input_control_point_count;
|
|
+
|
|
+ if (control_point_count && (!normaliser->output || vsir_opcode_is_fork_or_join_phase(normaliser->phase)))
|
|
+ register_size *= program->input_control_point_count;
|
|
+
|
|
+ if (!(ins = vsir_program_iterator_insert_before_and_move(it, 1)))
|
|
+ return VKD3D_ERROR_OUT_OF_MEMORY;
|
|
+
|
|
+ vsir_instruction_init_with_params(program, ins, &normaliser->ctx->null_location, VSIR_OP_DCL_INDEXABLE_TEMP, 0, 0);
|
|
+ t = &ins->declaration.indexable_temp;
|
|
+ t->register_idx = normaliser->idxtemp_idx;
|
|
+ t->register_size = register_size;
|
|
+ t->alignment = 0;
|
|
+ t->data_type = VSIR_DATA_F32;
|
|
+ t->component_count = 4;
|
|
+ t->has_function_scope = false;
|
|
+
|
|
+ vsir_program_iterator_next(it);
|
|
+
|
|
+ return VKD3D_OK;
|
|
+}
|
|
+
|
|
+static bool vsir_program_validate_outpointid_control_point_index(const struct vkd3d_shader_register *reg)
|
|
+{
|
|
+ const struct vkd3d_shader_register_index *index;
|
|
+
|
|
+ if (reg->idx_count < 2)
|
|
+ return false;
|
|
+
|
|
+ index = ®->idx[reg->idx_count - 2];
|
|
+ if (index->offset)
|
|
+ return false;
|
|
+ if (!index->rel_addr || index->rel_addr->reg.type != VKD3DSPR_OUTPOINTID)
|
|
+ return false;
|
|
+ if (index->rel_addr->reg.idx_count)
|
|
+ return false;
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/* If a register refers to a signature element of index 'e' that has the
|
|
+ * sysval being handled by the normaliser, this maps the register as follows:
|
|
+ *
|
|
+ * v[e] -> x[idxtmp_idx][q]
|
|
+ *
|
|
+ * v[i][e] -> x[idxtmp_idx][i + q]
|
|
+ * on shaders without control points.
|
|
+ *
|
|
+ * v[p][e] -> x[idxtmp_idx][p * reg_count + q],
|
|
+ * on shaders with control points.
|
|
+ *
|
|
+ * v[i][p][e] -> x[idxtmp_idx][p * reg_count + i + q]
|
|
+ * on shaders with control points.
|
|
+ *
|
|
+ * o[e] -> x[idxtmp_idx][q]
|
|
+ *
|
|
+ * o[i][e] -> x[idxtmp_idx][i + q]
|
|
+ * on shaders without control points.
|
|
+ *
|
|
+ * o[p][e] -> x[idxtmp_idx][p * reg_count + q]
|
|
+ * if on HS fork/join phase, where it is a src.
|
|
+ *
|
|
+ * o[P][e] -> x[idxtmp_idx][q]
|
|
+ * if on HS control point phase, where it is a dst.
|
|
+ * P is expected to always be the output control point ID.
|
|
+ *
|
|
+ * o[i][p][e] -> x[idxtmp_idx][p * reg_count + i + q]
|
|
+ * if on HS fork/join phase, where it is a src.
|
|
+ *
|
|
+ * o[i][P][e] -> x[idxtmp_idx][i + q]
|
|
+ * if on HS control point phase, where it is a dst.
|
|
+ * P is expected to always be the output control point ID.
|
|
+ *
|
|
+ * where:
|
|
+ * 'q' is the index of the register that matches signature element 'e' in
|
|
+ * the normaliser's internal list.
|
|
+ * 'idxtmp_idx' is the index of the indexable temp reserved by the
|
|
+ * normaliser.
|
|
+ * 'reg_count' is the number of registers in the normaliser's internal
|
|
+ * list.
|
|
+ *
|
|
+ * The swizzle (for source operands) is also combined with the mask of the
|
|
+ * relevant signature element 'e'.
|
|
+ */
|
|
+static enum vkd3d_result sysval_array_normaliser_map_register(struct sysval_array_normaliser *normaliser,
|
|
+ struct vsir_program_iterator *it, struct vkd3d_shader_register *reg, unsigned int *src_swizzle)
|
|
+{
|
|
+ struct vkd3d_shader_register_index i_idx = {0}, p_idx = {0};
|
|
+ struct vsir_program *program = normaliser->ctx->program;
|
|
+ unsigned int element_index, control_point_count;
|
|
+ struct vkd3d_shader_instruction *ssa_ins;
|
|
+ struct shader_signature *signature;
|
|
+ struct signature_element *element;
|
|
+ struct vkd3d_shader_location loc;
|
|
+ unsigned int q;
|
|
+
|
|
+ loc = vsir_program_iterator_current(it)->location;
|
|
+
|
|
+ signature = normaliser->output ? &program->output_signature : &program->input_signature;
|
|
+ control_point_count = normaliser->output ? program->output_control_point_count
|
|
+ : program->input_control_point_count;
|
|
+
|
|
+ for (unsigned int i = 0; i < reg->idx_count; ++i)
|
|
+ {
|
|
+ if (reg->idx[i].rel_addr)
|
|
+ sysval_array_normaliser_map_register(normaliser, it,
|
|
+ ®->idx[i].rel_addr->reg, ®->idx[i].rel_addr->swizzle);
|
|
+ }
|
|
+
|
|
+ if (normaliser->output && reg->type != VKD3DSPR_OUTPUT)
|
|
+ return VKD3D_OK;
|
|
+ if (!normaliser->output && reg->type != VKD3DSPR_INPUT)
|
|
+ return VKD3D_OK;
|
|
+
|
|
+ element_index = reg->idx[reg->idx_count - 1].offset;
|
|
+ element = &signature->elements[element_index];
|
|
+ if (element->sysval_semantic != normaliser->sysval_semantic)
|
|
+ return VKD3D_OK;
|
|
+
|
|
+ for (q = 0; q < normaliser->reg_count; ++q)
|
|
+ {
|
|
+ if (normaliser->regs[q].index == element->register_index)
|
|
+ break;
|
|
+ }
|
|
+ VKD3D_ASSERT(q < normaliser->reg_count);
|
|
+
|
|
+ if (normaliser->output && normaliser->phase == VSIR_OP_HS_CONTROL_POINT_PHASE)
|
|
+ {
|
|
+ if (!vsir_program_validate_outpointid_control_point_index(reg))
|
|
+ vkd3d_shader_error(normaliser->ctx->message_context, &loc, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX,
|
|
+ "Control point index of output source operand is not OUTPOINTID.\n");
|
|
+ }
|
|
+
|
|
+ if (control_point_count)
|
|
+ {
|
|
+ if (reg->idx_count == 3)
|
|
+ {
|
|
+ i_idx = reg->idx[0];
|
|
+ p_idx = reg->idx[1];
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ p_idx = reg->idx[0];
|
|
+ }
|
|
+ }
|
|
+ else if (reg->idx_count == 2)
|
|
+ {
|
|
+ i_idx = reg->idx[0];
|
|
+ }
|
|
+
|
|
+ reg->type = VKD3DSPR_IDXTEMP;
|
|
+ reg->idx[0].offset = normaliser->idxtemp_idx;
|
|
+ reg->idx[0].rel_addr = NULL;
|
|
+ reg->idx_count = 2;
|
|
+
|
|
+ if (p_idx.rel_addr && !(normaliser->output && normaliser->phase == VSIR_OP_HS_CONTROL_POINT_PHASE))
|
|
+ {
|
|
+ if (!(ssa_ins = vsir_program_iterator_insert_before_and_move(it, 1 + !!i_idx.rel_addr)))
|
|
+ return VKD3D_ERROR_OUT_OF_MEMORY;
|
|
+
|
|
+ if (!vsir_instruction_init_with_params(program, ssa_ins, &loc, VSIR_OP_IMUL_LOW, 1, 2))
|
|
+ return VKD3D_ERROR_OUT_OF_MEMORY;
|
|
+
|
|
+ vsir_register_init(&ssa_ins->dst[0].reg, VKD3DSPR_SSA, VSIR_DATA_U32, 1);
|
|
+ ssa_ins->dst[0].reg.idx[0].offset = program->ssa_count++;
|
|
+ ssa_ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4;
|
|
+ ssa_ins->dst[0].write_mask = VKD3DSP_WRITEMASK_0;
|
|
+ ssa_ins->src[0] = *p_idx.rel_addr;
|
|
+ src_param_init_const_uint(&ssa_ins->src[1], normaliser->reg_count);
|
|
+
|
|
+ if (i_idx.rel_addr)
|
|
+ {
|
|
+ ssa_ins = vsir_program_iterator_next(it);
|
|
+ if (!vsir_instruction_init_with_params(program, ssa_ins, &loc, VSIR_OP_ADD, 1, 2))
|
|
+ return VKD3D_ERROR_OUT_OF_MEMORY;
|
|
+
|
|
+ vsir_register_init(&ssa_ins->dst[0].reg, VKD3DSPR_SSA, VSIR_DATA_U32, 1);
|
|
+ ssa_ins->dst[0].reg.idx[0].offset = program->ssa_count++;
|
|
+ ssa_ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4;
|
|
+ ssa_ins->dst[0].write_mask = VKD3DSP_WRITEMASK_0;
|
|
+ vsir_register_init(&ssa_ins->src[0].reg, VKD3DSPR_SSA, VSIR_DATA_U32, 1);
|
|
+ ssa_ins->src[0].reg.idx[0].offset = program->ssa_count - 2;
|
|
+ ssa_ins->src[1] = *i_idx.rel_addr;
|
|
+ }
|
|
+
|
|
+ vsir_program_iterator_next(it);
|
|
+
|
|
+ reg->idx[1].offset = normaliser->reg_count * p_idx.offset + i_idx.offset + q;
|
|
+ if (!(reg->idx[1].rel_addr = vsir_program_get_src_params(program, 1)))
|
|
+ return VKD3D_ERROR_OUT_OF_MEMORY;
|
|
+ vsir_register_init(®->idx[1].rel_addr->reg, VKD3DSPR_SSA, VSIR_DATA_U32, 1);
|
|
+ reg->idx[1].rel_addr->reg.idx[0].offset = program->ssa_count - 1;
|
|
+ reg->idx[1].rel_addr->reg.dimension = VSIR_DIMENSION_VEC4;
|
|
+ reg->idx[1].rel_addr->swizzle = VKD3D_SHADER_SWIZZLE_X;
|
|
+ reg->idx[1].rel_addr->modifiers = 0;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ reg->idx[1].offset = normaliser->reg_count * p_idx.offset + i_idx.offset + q;
|
|
+ reg->idx[1].rel_addr = i_idx.rel_addr;
|
|
+ }
|
|
+
|
|
+ if (src_swizzle)
|
|
+ *src_swizzle = vsir_combine_swizzles(vsir_swizzle_from_writemask(element->mask), *src_swizzle);
|
|
+
|
|
+ return VKD3D_OK;
|
|
+}
|
|
+
|
|
+static enum vkd3d_result sysval_array_normaliser_map_instruction(
|
|
+ struct sysval_array_normaliser *normaliser, struct vsir_program_iterator *it)
|
|
+{
|
|
+ struct vkd3d_shader_instruction *ins = vsir_program_iterator_current(it);
|
|
+ unsigned int src_count, dst_count;
|
|
+ enum vkd3d_result res;
|
|
+
|
|
+ if (vsir_instruction_is_dcl(ins))
|
|
+ return VKD3D_OK;
|
|
+
|
|
+ dst_count = ins->dst_count;
|
|
+ src_count = ins->src_count;
|
|
+
|
|
+ for (unsigned int k = 0; k < dst_count; ++k)
|
|
+ {
|
|
+ ins = vsir_program_iterator_current(it);
|
|
+ if ((res = sysval_array_normaliser_map_register(normaliser, it, &ins->dst[k].reg, NULL)))
|
|
+ return res;
|
|
+ }
|
|
+
|
|
+ for (unsigned int k = 0; k < src_count; ++k)
|
|
+ {
|
|
+ ins = vsir_program_iterator_current(it);
|
|
+ if ((res = sysval_array_normaliser_map_register(normaliser, it, &ins->src[k].reg, &ins->src[k].swizzle)))
|
|
+ return res;
|
|
+ }
|
|
+
|
|
+ return VKD3D_OK;
|
|
+}
|
|
+
|
|
+static void shader_register_remove_signature_element(struct vkd3d_shader_register *reg,
|
|
+ enum vkd3d_shader_register_type type, unsigned int index)
|
|
+{
|
|
+ unsigned int current_idx;
|
|
+
|
|
+ for (unsigned int i = 0; i < reg->idx_count; ++i)
|
|
+ {
|
|
+ if (reg->idx[i].rel_addr)
|
|
+ shader_register_remove_signature_element(®->idx[i].rel_addr->reg, type, index);
|
|
+ }
|
|
+
|
|
+ if (reg->type != type)
|
|
+ return;
|
|
+
|
|
+ VKD3D_ASSERT(!reg->idx[reg->idx_count - 1].rel_addr);
|
|
+ current_idx = reg->idx[reg->idx_count - 1].offset;
|
|
+ VKD3D_ASSERT(current_idx != index);
|
|
+ if (current_idx > index)
|
|
+ --reg->idx[reg->idx_count - 1].offset;
|
|
+}
|
|
+
|
|
+static void vsir_program_remove_signature_element(struct vsir_program *program,
|
|
+ enum vkd3d_shader_register_type type, unsigned int index)
|
|
+{
|
|
+ struct vsir_program_iterator it = vsir_program_iterator(&program->instructions);
|
|
+ struct vkd3d_shader_instruction *ins;
|
|
+ struct shader_signature *signature;
|
|
+
|
|
+ switch (type)
|
|
+ {
|
|
+ case VKD3DSPR_INPUT:
|
|
+ signature = &program->input_signature;
|
|
+ break;
|
|
+ case VKD3DSPR_OUTPUT:
|
|
+ signature = &program->output_signature;
|
|
+ break;
|
|
+ case VKD3DSPR_PATCHCONST:
|
|
+ signature = &program->patch_constant_signature;
|
|
+ break;
|
|
+ default:
|
|
+ vkd3d_unreachable();
|
|
+ }
|
|
+
|
|
+ for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it))
|
|
+ {
|
|
+ if (vsir_instruction_is_dcl(ins))
|
|
+ continue;
|
|
+ for (unsigned int i = 0; i < ins->dst_count; ++i)
|
|
+ shader_register_remove_signature_element(&ins->dst[i].reg, type, index);
|
|
+ for (unsigned int i = 0; i < ins->src_count; ++i)
|
|
+ shader_register_remove_signature_element(&ins->src[i].reg, type, index);
|
|
+ }
|
|
+
|
|
+ memmove(&signature->elements[index], &signature->elements[index + 1],
|
|
+ sizeof(*signature->elements) * (signature->element_count - 1 - index));
|
|
+ --signature->element_count;
|
|
+}
|
|
+
|
|
+static void sysval_array_normaliser_remove_old_signature_elements(struct sysval_array_normaliser *normaliser)
|
|
+{
|
|
+ struct vsir_program *program = normaliser->ctx->program;
|
|
+ enum vkd3d_shader_register_type type;
|
|
+ struct shader_signature *signature;
|
|
+ struct signature_element *element;
|
|
+
|
|
+ signature = normaliser->output ? &program->output_signature : &program->input_signature;
|
|
+ type = normaliser->output ? VKD3DSPR_OUTPUT : VKD3DSPR_INPUT;
|
|
+
|
|
+ for (int i = signature->element_count - 2; i >= 0; --i)
|
|
+ {
|
|
+ element = &signature->elements[i];
|
|
+ if (element->sysval_semantic != normaliser->sysval_semantic)
|
|
+ continue;
|
|
+ TRACE("Removing %s signature element index %u.\n", normaliser->output ? "output" : "input", i);
|
|
+ vsir_program_remove_signature_element(program, type, i);
|
|
+ }
|
|
+}
|
|
+
|
|
+static enum vkd3d_result vsir_program_normalise_sysval_array(struct vsir_transformation_context *ctx,
|
|
+ const char *semantic_name, enum vkd3d_shader_sysval_semantic sysval_semantic, bool output)
|
|
+{
|
|
+ struct vsir_program *program = ctx->program;
|
|
+ struct sysval_array_normaliser normaliser;
|
|
+ struct vkd3d_shader_instruction *ins;
|
|
+ struct vsir_program_iterator it;
|
|
+ bool declarations = true;
|
|
+ enum vkd3d_result res;
|
|
+
|
|
+ if ((res = sysval_array_normaliser_init(ctx, semantic_name, sysval_semantic, output, &normaliser)) < 0)
|
|
+ return res;
|
|
+
|
|
+ if (!normaliser.reg_count)
|
|
+ return VKD3D_OK;
|
|
+
|
|
+ if (!output && program->shader_version.type == VKD3D_SHADER_TYPE_VERTEX)
|
|
+ return VKD3D_OK;
|
|
+
|
|
+ if (TRACE_ON())
|
|
+ vsir_program_trace(program);
|
|
+
|
|
+ it = vsir_program_iterator(&program->instructions);
|
|
+ for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it))
|
|
+ {
|
|
+ if (ins->opcode == VSIR_OP_HS_DECLS || ins->opcode == VSIR_OP_HS_CONTROL_POINT_PHASE
|
|
+ || ins->opcode == VSIR_OP_HS_FORK_PHASE || ins->opcode == VSIR_OP_HS_JOIN_PHASE)
|
|
+ {
|
|
+ normaliser.phase = ins->opcode;
|
|
+ declarations = true;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (declarations && !vsir_instruction_is_dcl(ins) && ins->opcode != VSIR_OP_NOP)
|
|
+ {
|
|
+ unsigned int idxtemp_idx = vsir_program_get_idxtemp_count(program) + 1;
|
|
+
|
|
+ declarations = false;
|
|
+
|
|
+ if ((res = sysval_array_normaliser_dcl_indexable_temp(&normaliser, &it, idxtemp_idx)) < 0)
|
|
+ return res;
|
|
+
|
|
+ if (vsir_program_iterator_current(&it)->opcode == VSIR_OP_LABEL)
|
|
+ ins = vsir_program_iterator_next(&it);
|
|
+
|
|
+ if ((!output || vsir_opcode_is_fork_or_join_phase(normaliser.phase))
|
|
+ && (res = sysval_array_normaliser_add_input_copy(&normaliser, &it)) < 0)
|
|
+ return res;
|
|
+ }
|
|
+
|
|
+ if (!declarations)
|
|
+ {
|
|
+ if (ins->opcode == VSIR_OP_RET || ins->opcode == VSIR_OP_EMIT || ins->opcode == VSIR_OP_EMIT_STREAM)
|
|
+ {
|
|
+ if ((output && !vsir_opcode_is_fork_or_join_phase(normaliser.phase))
|
|
+ && (res = sysval_array_normaliser_add_output_copy(&normaliser, &it)) < 0)
|
|
+ return res;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if ((res = sysval_array_normaliser_map_instruction(&normaliser, &it)) < 0)
|
|
+ return res;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ VKD3D_ASSERT(!declarations);
|
|
+ if (TRACE_ON())
|
|
+ vsir_program_trace(program);
|
|
+ sysval_array_normaliser_remove_old_signature_elements(&normaliser);
|
|
+
|
|
+ return VKD3D_OK;
|
|
+}
|
|
+
|
|
+/* This pass transform clip/cull system values from the Direct3D convention of
|
|
+ * 2 4-component registers, into the SPIR-V/GLSL convention of 8-element
|
|
+ * scalar float arrays. */
|
|
+static enum vkd3d_result vsir_program_normalise_clip_cull(
|
|
+ struct vsir_program *program, struct vsir_transformation_context *ctx)
|
|
+{
|
|
+ enum vkd3d_result res;
|
|
+
|
|
+ if ((res = vsir_program_normalise_sysval_array(ctx, "SV_ClipDistance", VKD3D_SHADER_SV_CLIP_DISTANCE, false)) < 0)
|
|
+ return res;
|
|
+ if ((res = vsir_program_normalise_sysval_array(ctx, "SV_ClipDistance", VKD3D_SHADER_SV_CLIP_DISTANCE, true)) < 0)
|
|
+ return res;
|
|
+ if ((res = vsir_program_normalise_sysval_array(ctx, "SV_CullDistance", VKD3D_SHADER_SV_CULL_DISTANCE, false)) < 0)
|
|
+ return res;
|
|
+ if ((res = vsir_program_normalise_sysval_array(ctx, "SV_CullDistance", VKD3D_SHADER_SV_CULL_DISTANCE, true)) < 0)
|
|
+ return res;
|
|
+
|
|
+ program->normalisation_flags.normalised_clip_cull_arrays = true;
|
|
+
|
|
+ return VKD3D_OK;
|
|
+}
|
|
+
|
|
static bool is_pre_rasterization_shader(enum vkd3d_shader_type type)
|
|
{
|
|
return type == VKD3D_SHADER_TYPE_VERTEX
|
|
@@ -10527,8 +11267,7 @@ static void vsir_validate_io_register(struct validation_context *ctx, const stru
|
|
}
|
|
|
|
element = &signature->elements[signature_idx];
|
|
- if (element->register_count > 1 || vsir_sysval_semantic_is_tess_factor(element->sysval_semantic))
|
|
- is_array = true;
|
|
+ is_array = vsir_signature_element_is_array(element, &ctx->program->normalisation_flags);
|
|
|
|
expected_idx_count = 1 + !!has_control_point + !!is_array;
|
|
control_point_index = !!is_array;
|
|
@@ -10721,7 +11460,7 @@ static void vsir_validate_descriptor_indices(struct validation_context *ctx,
|
|
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX,
|
|
"Non-NULL indirect address for the ID of a register of type \"%s\".", name);
|
|
|
|
- if (!ctx->program->has_descriptor_info)
|
|
+ if (!ctx->program->normalisation_flags.has_descriptor_info)
|
|
return;
|
|
|
|
if (!(descriptor = vkd3d_shader_find_descriptor(&ctx->program->descriptors, type, reg->idx[0].offset)))
|
|
@@ -11158,7 +11897,7 @@ static void vsir_validate_dst_param(struct validation_context *ctx,
|
|
break;
|
|
}
|
|
|
|
- if (dst->modifiers & ~VKD3DSPDM_MASK || (ctx->program->has_no_modifiers && dst->modifiers))
|
|
+ if (dst->modifiers & ~VKD3DSPDM_MASK || (ctx->program->normalisation_flags.has_no_modifiers && dst->modifiers))
|
|
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, "Destination has invalid modifiers %#x.",
|
|
dst->modifiers);
|
|
|
|
@@ -11339,7 +12078,7 @@ static void vsir_validate_src_param(struct validation_context *ctx,
|
|
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SWIZZLE,
|
|
"Immediate constant source has invalid swizzle %#x.", src->swizzle);
|
|
|
|
- if (src->modifiers >= VKD3DSPSM_COUNT || (ctx->program->has_no_modifiers && src->modifiers))
|
|
+ if (src->modifiers >= VKD3DSPSM_COUNT || (ctx->program->normalisation_flags.has_no_modifiers && src->modifiers))
|
|
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, "Source has invalid modifiers %#x.",
|
|
src->modifiers);
|
|
|
|
@@ -14242,6 +14981,7 @@ enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t
|
|
vsir_transform(&ctx, vsir_program_apply_flat_interpolation);
|
|
vsir_transform(&ctx, vsir_program_insert_alpha_test);
|
|
vsir_transform(&ctx, vsir_program_insert_clip_planes);
|
|
+ vsir_transform(&ctx, vsir_program_normalise_clip_cull);
|
|
vsir_transform(&ctx, vsir_program_insert_point_size);
|
|
vsir_transform(&ctx, vsir_program_insert_point_size_clamp);
|
|
vsir_transform(&ctx, vsir_program_insert_point_coord);
|
|
diff --git a/libs/vkd3d/libs/vkd3d-shader/msl.c b/libs/vkd3d/libs/vkd3d-shader/msl.c
|
|
index d34133d6d4c..2a6a243ee9f 100644
|
|
--- a/libs/vkd3d/libs/vkd3d-shader/msl.c
|
|
+++ b/libs/vkd3d/libs/vkd3d-shader/msl.c
|
|
@@ -2401,8 +2401,8 @@ int msl_compile(struct vsir_program *program, uint64_t config_flags,
|
|
return ret;
|
|
|
|
VKD3D_ASSERT(program->normalisation_level == VSIR_NORMALISED_SM6);
|
|
- VKD3D_ASSERT(program->has_descriptor_info);
|
|
- VKD3D_ASSERT(program->has_no_modifiers);
|
|
+ VKD3D_ASSERT(program->normalisation_flags.has_descriptor_info);
|
|
+ VKD3D_ASSERT(program->normalisation_flags.has_no_modifiers);
|
|
|
|
if ((ret = msl_generator_init(&generator, program, compile_info, message_context)) < 0)
|
|
return ret;
|
|
diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c
|
|
index 0d260d63542..83cc0eb18a5 100644
|
|
--- a/libs/vkd3d/libs/vkd3d-shader/spirv.c
|
|
+++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c
|
|
@@ -2972,7 +2972,6 @@ struct spirv_compiler
|
|
{
|
|
uint32_t id;
|
|
enum vsir_data_type data_type;
|
|
- uint32_t array_element_mask;
|
|
} *output_info;
|
|
uint32_t private_output_variable[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */
|
|
uint32_t private_output_variable_write_mask[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */
|
|
@@ -3019,16 +3018,6 @@ static bool is_in_default_phase(const struct spirv_compiler *compiler)
|
|
return compiler->phase == VSIR_OP_INVALID;
|
|
}
|
|
|
|
-static bool is_in_control_point_phase(const struct spirv_compiler *compiler)
|
|
-{
|
|
- return compiler->phase == VSIR_OP_HS_CONTROL_POINT_PHASE;
|
|
-}
|
|
-
|
|
-static bool is_in_fork_or_join_phase(const struct spirv_compiler *compiler)
|
|
-{
|
|
- return compiler->phase == VSIR_OP_HS_FORK_PHASE || compiler->phase == VSIR_OP_HS_JOIN_PHASE;
|
|
-}
|
|
-
|
|
static void spirv_compiler_emit_initial_declarations(struct spirv_compiler *compiler);
|
|
static size_t spirv_compiler_get_current_function_location(struct spirv_compiler *compiler);
|
|
static void spirv_compiler_emit_main_prolog(struct spirv_compiler *compiler);
|
|
@@ -5462,7 +5451,8 @@ static const struct vkd3d_shader_phase *spirv_compiler_get_current_shader_phase(
|
|
if (is_in_default_phase(compiler))
|
|
return NULL;
|
|
|
|
- return is_in_control_point_phase(compiler) ? &compiler->control_point_phase : &compiler->patch_constant_phase;
|
|
+ return vsir_opcode_is_control_point_phase(compiler->phase)
|
|
+ ? &compiler->control_point_phase : &compiler->patch_constant_phase;
|
|
}
|
|
|
|
static void spirv_compiler_decorate_xfb_output(struct spirv_compiler *compiler,
|
|
@@ -5561,18 +5551,6 @@ static bool needs_private_io_variable(const struct vkd3d_spirv_builtin *builtin)
|
|
return builtin && builtin->fixup_pfn;
|
|
}
|
|
|
|
-static unsigned int shader_signature_next_location(const struct shader_signature *signature)
|
|
-{
|
|
- unsigned int i, max_row;
|
|
-
|
|
- if (!signature)
|
|
- return 0;
|
|
-
|
|
- for (i = 0, max_row = 0; i < signature->element_count; ++i)
|
|
- max_row = max(max_row, signature->elements[i].register_index + signature->elements[i].register_count);
|
|
- return max_row;
|
|
-}
|
|
-
|
|
static const struct vkd3d_symbol *spirv_compiler_emit_io_register(struct spirv_compiler *compiler,
|
|
const struct vkd3d_shader_dst_param *dst)
|
|
{
|
|
@@ -5581,11 +5559,13 @@ static const struct vkd3d_symbol *spirv_compiler_emit_io_register(struct spirv_c
|
|
const struct vkd3d_spirv_builtin *builtin;
|
|
struct vkd3d_symbol reg_symbol;
|
|
SpvStorageClass storage_class;
|
|
+ unsigned int array_size;
|
|
uint32_t write_mask, id;
|
|
struct rb_entry *entry;
|
|
|
|
- VKD3D_ASSERT(!reg->idx_count || !reg->idx[0].rel_addr);
|
|
- VKD3D_ASSERT(reg->idx_count < 2);
|
|
+ VKD3D_ASSERT(reg->idx_count < 1 || !reg->idx[0].rel_addr);
|
|
+ VKD3D_ASSERT(reg->idx_count < 2 || !reg->idx[1].rel_addr);
|
|
+ VKD3D_ASSERT(reg->idx_count < 3);
|
|
|
|
if (reg->type == VKD3DSPR_RASTOUT && reg->idx[0].offset == VSIR_RASTOUT_POINT_SIZE)
|
|
{
|
|
@@ -5603,7 +5583,8 @@ static const struct vkd3d_symbol *spirv_compiler_emit_io_register(struct spirv_c
|
|
if ((entry = rb_get(&compiler->symbol_table, ®_symbol)))
|
|
return RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
|
|
|
|
- id = spirv_compiler_emit_builtin_variable(compiler, builtin, storage_class, 0);
|
|
+ array_size = (reg->idx_count > 1) ? reg->idx[0].offset : 0;
|
|
+ id = spirv_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size);
|
|
spirv_compiler_emit_register_execution_mode(compiler, reg->type);
|
|
spirv_compiler_emit_register_debug_name(builder, id, reg);
|
|
|
|
@@ -5667,11 +5648,8 @@ static void spirv_compiler_emit_input(struct spirv_compiler *compiler,
|
|
|
|
array_sizes[0] = signature_element->register_count;
|
|
array_sizes[1] = (reg_type == VKD3DSPR_PATCHCONST ? 0 : compiler->input_control_point_count);
|
|
- if (array_sizes[0] == 1 && !vsir_sysval_semantic_is_tess_factor(signature_element->sysval_semantic)
|
|
- && (!vsir_sysval_semantic_is_clip_cull(signature_element->sysval_semantic) || array_sizes[1]))
|
|
- {
|
|
+ if (!vsir_signature_element_is_array(signature_element, &compiler->program->normalisation_flags))
|
|
array_sizes[0] = 0;
|
|
- }
|
|
|
|
write_mask = signature_element->mask;
|
|
|
|
@@ -5708,7 +5686,7 @@ static void spirv_compiler_emit_input(struct spirv_compiler *compiler,
|
|
* duplicate declarations are: a single register split into multiple declarations having
|
|
* different components, which should have been merged, and declarations in one phase
|
|
* being repeated in another (i.e. vcp/vocp), which should have been deleted. */
|
|
- if (reg_type != VKD3DSPR_INPUT || !is_in_fork_or_join_phase(compiler))
|
|
+ if (reg_type != VKD3DSPR_INPUT || !vsir_opcode_is_fork_or_join_phase(compiler->phase))
|
|
FIXME("Duplicate input definition found.\n");
|
|
return;
|
|
}
|
|
@@ -5729,7 +5707,7 @@ static void spirv_compiler_emit_input(struct spirv_compiler *compiler,
|
|
if (reg_type == VKD3DSPR_PATCHCONST)
|
|
{
|
|
vkd3d_spirv_build_op_decorate(builder, input_id, SpvDecorationPatch, NULL, 0);
|
|
- location += shader_signature_next_location(&compiler->program->input_signature);
|
|
+ location += vsir_signature_next_location(&compiler->program->input_signature);
|
|
}
|
|
vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationLocation, location);
|
|
if (component_idx)
|
|
@@ -5803,88 +5781,6 @@ static bool is_dual_source_blending(const struct spirv_compiler *compiler)
|
|
return compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL && info && info->dual_source_blending;
|
|
}
|
|
|
|
-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;
|
|
- }
|
|
-
|
|
- write_mask = e->mask;
|
|
- *mask |= (write_mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * e->semantic_index);
|
|
-}
|
|
-
|
|
-/* Emits arrayed SPIR-V built-in variables. */
|
|
-static void spirv_compiler_emit_shader_signature_outputs(struct spirv_compiler *compiler)
|
|
-{
|
|
- const struct shader_signature *output_signature = &compiler->program->output_signature;
|
|
- uint32_t clip_distance_mask = 0, clip_distance_id = 0;
|
|
- uint32_t cull_distance_mask = 0, cull_distance_id = 0;
|
|
- const struct vkd3d_spirv_builtin *builtin;
|
|
- unsigned int i, count;
|
|
-
|
|
- for (i = 0; i < output_signature->element_count; ++i)
|
|
- {
|
|
- const struct signature_element *e = &output_signature->elements[i];
|
|
-
|
|
- switch (e->sysval_semantic)
|
|
- {
|
|
- case VKD3D_SHADER_SV_CLIP_DISTANCE:
|
|
- calculate_clip_or_cull_distance_mask(e, &clip_distance_mask);
|
|
- break;
|
|
-
|
|
- case VKD3D_SHADER_SV_CULL_DISTANCE:
|
|
- calculate_clip_or_cull_distance_mask(e, &cull_distance_mask);
|
|
- break;
|
|
-
|
|
- default:
|
|
- break;
|
|
- }
|
|
- }
|
|
-
|
|
- if (clip_distance_mask)
|
|
- {
|
|
- count = vkd3d_popcount(clip_distance_mask);
|
|
- builtin = get_spirv_builtin_for_sysval(compiler, VKD3D_SHADER_SV_CLIP_DISTANCE);
|
|
- clip_distance_id = spirv_compiler_emit_builtin_variable(compiler,
|
|
- builtin, SpvStorageClassOutput, count);
|
|
- }
|
|
-
|
|
- if (cull_distance_mask)
|
|
- {
|
|
- count = vkd3d_popcount(cull_distance_mask);
|
|
- builtin = get_spirv_builtin_for_sysval(compiler, VKD3D_SHADER_SV_CULL_DISTANCE);
|
|
- cull_distance_id = spirv_compiler_emit_builtin_variable(compiler,
|
|
- builtin, SpvStorageClassOutput, count);
|
|
- }
|
|
-
|
|
- for (i = 0; i < output_signature->element_count; ++i)
|
|
- {
|
|
- const struct signature_element *e = &output_signature->elements[i];
|
|
-
|
|
- switch (e->sysval_semantic)
|
|
- {
|
|
- case VKD3D_SHADER_SV_CLIP_DISTANCE:
|
|
- compiler->output_info[i].id = clip_distance_id;
|
|
- compiler->output_info[i].data_type = VSIR_DATA_F32;
|
|
- compiler->output_info[i].array_element_mask = clip_distance_mask;
|
|
- break;
|
|
-
|
|
- case VKD3D_SHADER_SV_CULL_DISTANCE:
|
|
- compiler->output_info[i].id = cull_distance_id;
|
|
- compiler->output_info[i].data_type = VSIR_DATA_F32;
|
|
- compiler->output_info[i].array_element_mask = cull_distance_mask;
|
|
- break;
|
|
-
|
|
- default:
|
|
- break;
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
static uint32_t spirv_compiler_emit_shader_phase_builtin_variable(struct spirv_compiler *compiler,
|
|
const struct vkd3d_spirv_builtin *builtin, const unsigned int *array_sizes, unsigned int size_count)
|
|
{
|
|
@@ -5902,7 +5798,7 @@ static uint32_t spirv_compiler_emit_shader_phase_builtin_variable(struct spirv_c
|
|
return *variable_id;
|
|
|
|
id = spirv_compiler_emit_builtin_variable_v(compiler, builtin, SpvStorageClassOutput, array_sizes, size_count);
|
|
- if (is_in_fork_or_join_phase(compiler))
|
|
+ if (vsir_opcode_is_fork_or_join_phase(compiler->phase))
|
|
vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationPatch, NULL, 0);
|
|
|
|
if (variable_id)
|
|
@@ -5940,7 +5836,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler,
|
|
sysval = VKD3D_SHADER_SV_NONE;
|
|
array_sizes[0] = signature_element->register_count;
|
|
array_sizes[1] = (reg_type == VKD3DSPR_PATCHCONST ? 0 : compiler->output_control_point_count);
|
|
- if (array_sizes[0] == 1 && !vsir_sysval_semantic_is_tess_factor(signature_element->sysval_semantic))
|
|
+ if (!vsir_signature_element_is_array(signature_element, &compiler->program->normalisation_flags))
|
|
array_sizes[0] = 0;
|
|
|
|
builtin = vkd3d_get_spirv_builtin(compiler, reg_type, sysval);
|
|
@@ -5966,8 +5862,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler,
|
|
use_private_variable = true;
|
|
|
|
if (!is_patch_constant
|
|
- && (get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_SHADER_NO_SWIZZLE
|
|
- || (compiler->output_info[element_idx].id && compiler->output_info[element_idx].array_element_mask)))
|
|
+ && get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_SHADER_NO_SWIZZLE)
|
|
{
|
|
use_private_variable = true;
|
|
}
|
|
@@ -6005,7 +5900,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler,
|
|
unsigned int location = signature_element->target_location;
|
|
|
|
if (is_patch_constant)
|
|
- location += shader_signature_next_location(&compiler->program->output_signature);
|
|
+ location += vsir_signature_next_location(&compiler->program->output_signature);
|
|
else if (compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL
|
|
&& signature_element->sysval_semantic == VKD3D_SHADER_SV_TARGET)
|
|
location = signature_element->semantic_index;
|
|
@@ -6066,36 +5961,18 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler,
|
|
}
|
|
}
|
|
|
|
-static uint32_t spirv_compiler_get_output_array_index(struct spirv_compiler *compiler,
|
|
- const struct signature_element *e)
|
|
-{
|
|
- enum vkd3d_shader_sysval_semantic sysval = e->sysval_semantic;
|
|
- const struct vkd3d_spirv_builtin *builtin;
|
|
-
|
|
- builtin = get_spirv_builtin_for_sysval(compiler, sysval);
|
|
-
|
|
- switch (sysval)
|
|
- {
|
|
- case VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN:
|
|
- case VKD3D_SHADER_SV_TESS_FACTOR_LINEDET:
|
|
- return builtin->member_idx;
|
|
- default:
|
|
- return e->semantic_index;
|
|
- }
|
|
-}
|
|
-
|
|
static void spirv_compiler_emit_store_shader_output(struct spirv_compiler *compiler,
|
|
const struct shader_signature *signature, const struct signature_element *output,
|
|
const struct vkd3d_shader_output_info *output_info,
|
|
uint32_t output_index_id, uint32_t val_id, uint32_t write_mask)
|
|
{
|
|
- uint32_t dst_write_mask, use_mask, uninit_mask, swizzle, mask;
|
|
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
|
- uint32_t type_id, zero_id, ptr_type_id, chain_id, object_id;
|
|
+ uint32_t dst_write_mask, use_mask, uninit_mask, swizzle;
|
|
const struct signature_element *element;
|
|
- unsigned int i, index, array_idx;
|
|
+ uint32_t type_id, zero_id, ptr_type_id;
|
|
enum vsir_data_type data_type;
|
|
uint32_t output_id;
|
|
+ unsigned int i;
|
|
|
|
dst_write_mask = output->mask;
|
|
use_mask = output->used_mask;
|
|
@@ -6149,31 +6026,8 @@ static void spirv_compiler_emit_store_shader_output(struct spirv_compiler *compi
|
|
output_id = vkd3d_spirv_build_op_access_chain1(builder, ptr_type_id, output_id, output_index_id);
|
|
}
|
|
|
|
- if (!output_info->array_element_mask)
|
|
- {
|
|
- spirv_compiler_emit_store(compiler, output_id, dst_write_mask,
|
|
- data_type, SpvStorageClassOutput, write_mask, val_id);
|
|
- return;
|
|
- }
|
|
-
|
|
- type_id = spirv_get_type_id(compiler, data_type, 1);
|
|
- ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassOutput, type_id);
|
|
- mask = output_info->array_element_mask;
|
|
- array_idx = spirv_compiler_get_output_array_index(compiler, output);
|
|
- mask &= (1u << (array_idx * VKD3D_VEC4_SIZE)) - 1;
|
|
- for (i = 0, index = vkd3d_popcount(mask); i < VKD3D_VEC4_SIZE; ++i)
|
|
- {
|
|
- if (!(write_mask & (VKD3DSP_WRITEMASK_0 << i)))
|
|
- continue;
|
|
-
|
|
- chain_id = vkd3d_spirv_build_op_access_chain1(builder,
|
|
- ptr_type_id, output_id, spirv_compiler_get_constant_uint(compiler, index));
|
|
- object_id = spirv_compiler_emit_swizzle(compiler, val_id, write_mask,
|
|
- data_type, VKD3D_SHADER_NO_SWIZZLE, VKD3DSP_WRITEMASK_0 << i);
|
|
- spirv_compiler_emit_store(compiler, chain_id, VKD3DSP_WRITEMASK_0, data_type,
|
|
- SpvStorageClassOutput, VKD3DSP_WRITEMASK_0 << i, object_id);
|
|
- ++index;
|
|
- }
|
|
+ spirv_compiler_emit_store(compiler, output_id, dst_write_mask,
|
|
+ data_type, SpvStorageClassOutput, write_mask, val_id);
|
|
}
|
|
|
|
static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler *compiler)
|
|
@@ -6190,7 +6044,7 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler *
|
|
STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(param_type_id));
|
|
STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(compiler->private_output_variable_write_mask));
|
|
|
|
- is_patch_constant = is_in_fork_or_join_phase(compiler);
|
|
+ is_patch_constant = vsir_opcode_is_fork_or_join_phase(compiler->phase);
|
|
|
|
signature = is_patch_constant ? &compiler->program->patch_constant_signature
|
|
: &compiler->program->output_signature;
|
|
@@ -6224,7 +6078,7 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler *
|
|
param_id[i] = vkd3d_spirv_build_op_load(builder, type_id, param_id[i], SpvMemoryAccessMaskNone);
|
|
}
|
|
|
|
- if (is_in_control_point_phase(compiler))
|
|
+ if (vsir_opcode_is_control_point_phase(compiler->phase))
|
|
output_index_id = spirv_compiler_emit_load_invocation_id(compiler);
|
|
|
|
for (i = 0; i < signature->element_count; ++i)
|
|
@@ -7259,7 +7113,7 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler)
|
|
|
|
vkd3d_spirv_build_op_function_end(builder);
|
|
|
|
- if (is_in_control_point_phase(compiler))
|
|
+ if (vsir_opcode_is_control_point_phase(compiler->phase))
|
|
{
|
|
if (compiler->epilogue_function_id)
|
|
{
|
|
@@ -7296,8 +7150,8 @@ static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler,
|
|
compiler->phase = instruction->opcode;
|
|
spirv_compiler_emit_shader_phase_name(compiler, function_id, NULL);
|
|
|
|
- phase = (instruction->opcode == VSIR_OP_HS_CONTROL_POINT_PHASE)
|
|
- ? &compiler->control_point_phase : &compiler->patch_constant_phase;
|
|
+ phase = vsir_opcode_is_control_point_phase(instruction->opcode)
|
|
+ ? &compiler->control_point_phase : &compiler->patch_constant_phase;
|
|
phase->function_id = function_id;
|
|
/* The insertion location must be set after the label is emitted. */
|
|
phase->function_location = 0;
|
|
@@ -7310,8 +7164,8 @@ static void spirv_compiler_initialise_block(struct spirv_compiler *compiler)
|
|
/* Insertion locations must point immediately after the function's initial label. */
|
|
if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL)
|
|
{
|
|
- struct vkd3d_shader_phase *phase = (compiler->phase == VSIR_OP_HS_CONTROL_POINT_PHASE)
|
|
- ? &compiler->control_point_phase : &compiler->patch_constant_phase;
|
|
+ struct vkd3d_shader_phase *phase = vsir_opcode_is_control_point_phase(compiler->phase)
|
|
+ ? &compiler->control_point_phase : &compiler->patch_constant_phase;
|
|
if (!phase->function_location)
|
|
phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
|
|
}
|
|
@@ -8362,7 +8216,7 @@ static void spirv_compiler_emit_return(struct spirv_compiler *compiler,
|
|
spirv_compiler_end_invocation_interlock(compiler);
|
|
|
|
if (compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY && (is_in_default_phase(compiler)
|
|
- || is_in_control_point_phase(compiler)))
|
|
+ || vsir_opcode_is_control_point_phase(compiler->phase)))
|
|
spirv_compiler_emit_shader_epilogue_invocation(compiler);
|
|
|
|
vkd3d_spirv_build_op_return(builder);
|
|
@@ -10967,9 +10821,6 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
|
|
|| (program->shader_version.type == VKD3D_SHADER_TYPE_HULL && !spirv_compiler_is_opengl_target(compiler)))
|
|
spirv_compiler_emit_tessellator_domain(compiler, program->tess_domain);
|
|
|
|
- if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL)
|
|
- spirv_compiler_emit_shader_signature_outputs(compiler);
|
|
-
|
|
it = vsir_program_iterator(&program->instructions);
|
|
for (ins = vsir_program_iterator_head(&it); ins && result >= 0; ins = vsir_program_iterator_next(&it))
|
|
{
|
|
@@ -11071,8 +10922,9 @@ int spirv_compile(struct vsir_program *program, uint64_t config_flags,
|
|
return ret;
|
|
|
|
VKD3D_ASSERT(program->normalisation_level == VSIR_NORMALISED_SM6);
|
|
- VKD3D_ASSERT(program->has_descriptor_info);
|
|
- VKD3D_ASSERT(program->has_no_modifiers);
|
|
+ VKD3D_ASSERT(program->normalisation_flags.normalised_clip_cull_arrays);
|
|
+ VKD3D_ASSERT(program->normalisation_flags.has_descriptor_info);
|
|
+ VKD3D_ASSERT(program->normalisation_flags.has_no_modifiers);
|
|
|
|
if (!(spirv_compiler = spirv_compiler_create(program, compile_info,
|
|
message_context, config_flags)))
|
|
diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c
|
|
index 4798a75ce90..3eec61864b4 100644
|
|
--- a/libs/vkd3d/libs/vkd3d-shader/tpf.c
|
|
+++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c
|
|
@@ -964,11 +964,6 @@ static void shader_sm4_read_dcl_sampler(struct vkd3d_shader_instruction *ins, ui
|
|
shader_sm4_read_register_space(priv, &tokens, end, &ins->declaration.sampler.range.space);
|
|
}
|
|
|
|
-static bool sm4_parser_is_in_fork_or_join_phase(const struct vkd3d_shader_sm4_parser *sm4)
|
|
-{
|
|
- return sm4->phase == VSIR_OP_HS_FORK_PHASE || sm4->phase == VSIR_OP_HS_JOIN_PHASE;
|
|
-}
|
|
-
|
|
static void shader_sm4_read_dcl_index_range(struct vkd3d_shader_instruction *ins, uint32_t opcode,
|
|
uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv)
|
|
{
|
|
@@ -997,7 +992,7 @@ static void shader_sm4_read_dcl_index_range(struct vkd3d_shader_instruction *ins
|
|
signature = &program->input_signature;
|
|
break;
|
|
case VKD3DSPR_OUTPUT:
|
|
- if (sm4_parser_is_in_fork_or_join_phase(priv))
|
|
+ if (vsir_opcode_is_fork_or_join_phase(priv->phase))
|
|
{
|
|
io_masks = priv->patch_constant_register_masks;
|
|
ranges = &priv->patch_constant_index_ranges;
|
|
@@ -2285,7 +2280,7 @@ static bool register_is_control_point_input(const struct vkd3d_shader_register *
|
|
const struct vkd3d_shader_sm4_parser *priv)
|
|
{
|
|
return reg->type == VKD3DSPR_INCONTROLPOINT || reg->type == VKD3DSPR_OUTCONTROLPOINT
|
|
- || (reg->type == VKD3DSPR_INPUT && (priv->phase == VSIR_OP_HS_CONTROL_POINT_PHASE
|
|
+ || (reg->type == VKD3DSPR_INPUT && (vsir_opcode_is_control_point_phase(priv->phase)
|
|
|| priv->program->shader_version.type == VKD3D_SHADER_TYPE_GEOMETRY));
|
|
}
|
|
|
|
@@ -2319,8 +2314,8 @@ static bool shader_sm4_validate_input_output_register(struct vkd3d_shader_sm4_pa
|
|
masks = priv->input_register_masks;
|
|
break;
|
|
case VKD3DSPR_OUTPUT:
|
|
- masks = sm4_parser_is_in_fork_or_join_phase(priv) ? priv->patch_constant_register_masks
|
|
- : priv->output_register_masks;
|
|
+ masks = vsir_opcode_is_fork_or_join_phase(priv->phase)
|
|
+ ? priv->patch_constant_register_masks : priv->output_register_masks;
|
|
break;
|
|
case VKD3DSPR_COLOROUT:
|
|
case VKD3DSPR_OUTCONTROLPOINT:
|
|
@@ -2661,7 +2656,7 @@ static void shader_sm4_read_instruction(struct vkd3d_shader_sm4_parser *sm4, str
|
|
if (ins->opcode == VSIR_OP_HS_CONTROL_POINT_PHASE || ins->opcode == VSIR_OP_HS_FORK_PHASE
|
|
|| ins->opcode == VSIR_OP_HS_JOIN_PHASE)
|
|
sm4->phase = ins->opcode;
|
|
- sm4->has_control_point_phase |= ins->opcode == VSIR_OP_HS_CONTROL_POINT_PHASE;
|
|
+ sm4->has_control_point_phase |= vsir_opcode_is_control_point_phase(ins->opcode);
|
|
ins->flags = 0;
|
|
ins->coissue = false;
|
|
ins->raw = false;
|
|
diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
|
|
index 6f0520f19f9..68285be0a49 100644
|
|
--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
|
|
+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
|
|
@@ -319,14 +319,21 @@ void vkd3d_string_buffer_release(struct vkd3d_string_buffer_cache *cache, struct
|
|
cache->buffers[cache->count++] = buffer;
|
|
}
|
|
|
|
-void vkd3d_shader_code_from_string_buffer(struct vkd3d_shader_code *code, struct vkd3d_string_buffer *buffer)
|
|
+static char *vkd3d_shader_string_from_string_buffer(struct vkd3d_string_buffer *buffer)
|
|
{
|
|
- code->code = buffer->buffer;
|
|
- code->size = buffer->content_size;
|
|
+ char *s = buffer->buffer;
|
|
|
|
buffer->buffer = NULL;
|
|
buffer->buffer_size = 0;
|
|
buffer->content_size = 0;
|
|
+
|
|
+ return s;
|
|
+}
|
|
+
|
|
+void vkd3d_shader_code_from_string_buffer(struct vkd3d_shader_code *code, struct vkd3d_string_buffer *buffer)
|
|
+{
|
|
+ code->size = buffer->content_size;
|
|
+ code->code = vkd3d_shader_string_from_string_buffer(buffer);
|
|
}
|
|
|
|
void vkd3d_shader_message_context_init(struct vkd3d_shader_message_context *context,
|
|
@@ -347,23 +354,15 @@ void vkd3d_shader_message_context_trace_messages_(const struct vkd3d_shader_mess
|
|
vkd3d_string_buffer_trace_(&context->messages, function);
|
|
}
|
|
|
|
-bool vkd3d_shader_message_context_copy_messages(struct vkd3d_shader_message_context *context, char **out)
|
|
+void vkd3d_shader_string_from_message_context(char **out, struct vkd3d_shader_message_context *context)
|
|
{
|
|
- char *messages;
|
|
-
|
|
if (!out)
|
|
- return true;
|
|
-
|
|
- *out = NULL;
|
|
-
|
|
- if (!context->messages.content_size)
|
|
- return true;
|
|
+ return;
|
|
|
|
- if (!(messages = vkd3d_malloc(context->messages.content_size + 1)))
|
|
- return false;
|
|
- memcpy(messages, context->messages.buffer, context->messages.content_size + 1);
|
|
- *out = messages;
|
|
- return true;
|
|
+ if (context->messages.content_size)
|
|
+ *out = vkd3d_shader_string_from_string_buffer(&context->messages);
|
|
+ else
|
|
+ *out = NULL;
|
|
}
|
|
|
|
void vkd3d_shader_vnote(struct vkd3d_shader_message_context *context, const struct vkd3d_shader_location *location,
|
|
@@ -1677,7 +1676,7 @@ static int vsir_program_scan(struct vsir_program *program, const struct vkd3d_sh
|
|
add_descriptor_info = true;
|
|
}
|
|
|
|
- if (program->has_descriptor_info)
|
|
+ if (program->normalisation_flags.has_descriptor_info)
|
|
add_descriptor_info = false;
|
|
|
|
tessellation_info = vkd3d_find_struct(compile_info->next, SCAN_HULL_SHADER_TESSELLATION_INFO);
|
|
@@ -1687,7 +1686,7 @@ static int vsir_program_scan(struct vsir_program *program, const struct vkd3d_sh
|
|
add_descriptor_info ? &program->descriptors : NULL, combined_sampler_info, message_context);
|
|
|
|
if (add_descriptor_info)
|
|
- program->has_descriptor_info = true;
|
|
+ program->normalisation_flags.has_descriptor_info = true;
|
|
|
|
if (TRACE_ON())
|
|
vsir_program_trace(program);
|
|
@@ -1772,8 +1771,7 @@ int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char
|
|
}
|
|
|
|
vkd3d_shader_message_context_trace_messages(&message_context);
|
|
- if (!vkd3d_shader_message_context_copy_messages(&message_context, messages))
|
|
- ret = VKD3D_ERROR_OUT_OF_MEMORY;
|
|
+ vkd3d_shader_string_from_message_context(messages, &message_context);
|
|
vkd3d_shader_message_context_cleanup(&message_context);
|
|
return ret;
|
|
}
|
|
@@ -1920,8 +1918,7 @@ int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info,
|
|
vkd3d_shader_dump_shader(&dump_data, out->code, out->size, SHADER_DUMP_TYPE_TARGET);
|
|
|
|
vkd3d_shader_message_context_trace_messages(&message_context);
|
|
- if (!vkd3d_shader_message_context_copy_messages(&message_context, messages))
|
|
- ret = VKD3D_ERROR_OUT_OF_MEMORY;
|
|
+ vkd3d_shader_string_from_message_context(messages, &message_context);
|
|
vkd3d_shader_message_context_cleanup(&message_context);
|
|
return ret;
|
|
}
|
|
@@ -2039,9 +2036,7 @@ int vkd3d_shader_parse_input_signature(const struct vkd3d_shader_code *dxbc,
|
|
|
|
ret = shader_parse_input_signature(dxbc, &message_context, &shader_signature);
|
|
vkd3d_shader_message_context_trace_messages(&message_context);
|
|
- if (!vkd3d_shader_message_context_copy_messages(&message_context, messages))
|
|
- ret = VKD3D_ERROR_OUT_OF_MEMORY;
|
|
-
|
|
+ vkd3d_shader_string_from_message_context(messages, &message_context);
|
|
vkd3d_shader_message_context_cleanup(&message_context);
|
|
|
|
if (!vkd3d_shader_signature_from_shader_signature(signature, &shader_signature))
|
|
@@ -2246,8 +2241,7 @@ int vkd3d_shader_preprocess(const struct vkd3d_shader_compile_info *compile_info
|
|
vkd3d_shader_dump_shader(&dump_data, out->code, out->size, SHADER_DUMP_TYPE_PREPROC);
|
|
|
|
vkd3d_shader_message_context_trace_messages(&message_context);
|
|
- if (!vkd3d_shader_message_context_copy_messages(&message_context, messages))
|
|
- ret = VKD3D_ERROR_OUT_OF_MEMORY;
|
|
+ vkd3d_shader_string_from_message_context(messages, &message_context);
|
|
vkd3d_shader_message_context_cleanup(&message_context);
|
|
return ret;
|
|
}
|
|
diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
|
|
index 7e31a77da05..46f62a9e55c 100644
|
|
--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
|
|
+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
|
|
@@ -632,6 +632,16 @@ enum vkd3d_shader_opcode
|
|
|
|
const char *vsir_opcode_get_name(enum vkd3d_shader_opcode op, const char *error);
|
|
|
|
+static inline bool vsir_opcode_is_fork_or_join_phase(enum vkd3d_shader_opcode op)
|
|
+{
|
|
+ return op == VSIR_OP_HS_FORK_PHASE || op == VSIR_OP_HS_JOIN_PHASE;
|
|
+}
|
|
+
|
|
+static inline bool vsir_opcode_is_control_point_phase(enum vkd3d_shader_opcode op)
|
|
+{
|
|
+ return op == VSIR_OP_HS_CONTROL_POINT_PHASE;
|
|
+}
|
|
+
|
|
enum vkd3d_shader_register_type
|
|
{
|
|
VKD3DSPR_TEMP,
|
|
@@ -973,6 +983,13 @@ struct vkd3d_shader_version
|
|
uint8_t minor;
|
|
};
|
|
|
|
+struct vsir_normalisation_flags
|
|
+{
|
|
+ bool has_descriptor_info;
|
|
+ bool has_no_modifiers;
|
|
+ bool normalised_clip_cull_arrays;
|
|
+};
|
|
+
|
|
struct vkd3d_shader_immediate_constant_buffer
|
|
{
|
|
unsigned int register_idx;
|
|
@@ -1156,6 +1173,17 @@ enum vkd3d_shader_input_sysval_semantic
|
|
|
|
#define SIGNATURE_TARGET_LOCATION_UNUSED (~0u)
|
|
|
|
+static inline bool vsir_sysval_semantic_is_tess_factor(enum vkd3d_shader_sysval_semantic sysval_semantic)
|
|
+{
|
|
+ return sysval_semantic >= VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE
|
|
+ && sysval_semantic <= VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN;
|
|
+}
|
|
+
|
|
+static inline bool vsir_sysval_semantic_is_clip_cull(enum vkd3d_shader_sysval_semantic sysval_semantic)
|
|
+{
|
|
+ return sysval_semantic == VKD3D_SHADER_SV_CLIP_DISTANCE || sysval_semantic == VKD3D_SHADER_SV_CULL_DISTANCE;
|
|
+}
|
|
+
|
|
struct signature_element
|
|
{
|
|
/* sort_index is not a property of the signature element, it is just a
|
|
@@ -1179,6 +1207,20 @@ struct signature_element
|
|
unsigned int target_location;
|
|
};
|
|
|
|
+static inline bool vsir_signature_element_is_array(const struct signature_element *element,
|
|
+ const struct vsir_normalisation_flags *flags)
|
|
+{
|
|
+ enum vkd3d_shader_sysval_semantic semantic = element->sysval_semantic;
|
|
+
|
|
+ if (element->register_count > 1)
|
|
+ return true;
|
|
+ if (vsir_sysval_semantic_is_tess_factor(semantic))
|
|
+ return true;
|
|
+ if (flags->normalised_clip_cull_arrays && vsir_sysval_semantic_is_clip_cull(semantic))
|
|
+ return true;
|
|
+ return false;
|
|
+}
|
|
+
|
|
struct shader_signature
|
|
{
|
|
struct signature_element *elements;
|
|
@@ -1186,21 +1228,11 @@ struct shader_signature
|
|
unsigned int element_count;
|
|
};
|
|
|
|
-static inline bool vsir_sysval_semantic_is_tess_factor(enum vkd3d_shader_sysval_semantic sysval_semantic)
|
|
-{
|
|
- return sysval_semantic >= VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE
|
|
- && sysval_semantic <= VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN;
|
|
-}
|
|
-
|
|
-static inline bool vsir_sysval_semantic_is_clip_cull(enum vkd3d_shader_sysval_semantic sysval_semantic)
|
|
-{
|
|
- return sysval_semantic == VKD3D_SHADER_SV_CLIP_DISTANCE || sysval_semantic == VKD3D_SHADER_SV_CULL_DISTANCE;
|
|
-}
|
|
-
|
|
struct signature_element *vsir_signature_find_element_for_reg(const struct shader_signature *signature,
|
|
unsigned int reg_idx, unsigned int write_mask);
|
|
bool vsir_signature_find_sysval(const struct shader_signature *signature,
|
|
enum vkd3d_shader_sysval_semantic sysval, unsigned int semantic_index, unsigned int *element_index);
|
|
+unsigned int vsir_signature_next_location(const struct shader_signature *signature);
|
|
void shader_signature_cleanup(struct shader_signature *signature);
|
|
|
|
struct vsir_features
|
|
@@ -1596,7 +1628,6 @@ struct vsir_program
|
|
struct shader_signature patch_constant_signature;
|
|
|
|
struct vkd3d_shader_scan_descriptor_info1 descriptors;
|
|
- bool has_descriptor_info;
|
|
size_t descriptors_size;
|
|
|
|
unsigned int parameter_count;
|
|
@@ -1615,14 +1646,15 @@ struct vsir_program
|
|
bool has_fog;
|
|
uint8_t diffuse_written_mask;
|
|
enum vsir_control_flow_type cf_type;
|
|
- enum vsir_normalisation_level normalisation_level;
|
|
- bool has_no_modifiers;
|
|
enum vkd3d_tessellator_domain tess_domain;
|
|
enum vkd3d_shader_tessellator_partitioning tess_partitioning;
|
|
enum vkd3d_shader_tessellator_output_primitive tess_output_primitive;
|
|
enum vkd3d_primitive_type input_primitive, output_topology;
|
|
unsigned int vertices_out_count;
|
|
|
|
+ enum vsir_normalisation_level normalisation_level;
|
|
+ struct vsir_normalisation_flags normalisation_flags;
|
|
+
|
|
uint32_t io_dcls[VKD3D_BITMAP_SIZE(VKD3DSPR_COUNT)];
|
|
|
|
struct vsir_features features;
|
|
@@ -1801,7 +1833,6 @@ struct vkd3d_shader_message_context
|
|
};
|
|
|
|
void vkd3d_shader_message_context_cleanup(struct vkd3d_shader_message_context *context);
|
|
-bool vkd3d_shader_message_context_copy_messages(struct vkd3d_shader_message_context *context, char **out);
|
|
void vkd3d_shader_message_context_init(struct vkd3d_shader_message_context *context,
|
|
enum vkd3d_shader_log_level log_level);
|
|
void vkd3d_shader_message_context_trace_messages_(const struct vkd3d_shader_message_context *context,
|
|
@@ -1819,6 +1850,8 @@ void vkd3d_shader_warning(struct vkd3d_shader_message_context *context, const st
|
|
void vkd3d_shader_vwarning(struct vkd3d_shader_message_context *context, const struct vkd3d_shader_location *location,
|
|
enum vkd3d_shader_error error, const char *format, va_list args);
|
|
|
|
+void vkd3d_shader_string_from_message_context(char **out, struct vkd3d_shader_message_context *context);
|
|
+
|
|
uint64_t vkd3d_shader_init_config_flags(void);
|
|
void vkd3d_shader_trace_text_(const char *text, size_t size, const char *function);
|
|
#define vkd3d_shader_trace_text(text, size) \
|
|
diff --git a/libs/vkd3d/libs/vkd3d/device.c b/libs/vkd3d/libs/vkd3d/device.c
|
|
index 6af5e2a5c7d..33628d48609 100644
|
|
--- a/libs/vkd3d/libs/vkd3d/device.c
|
|
+++ b/libs/vkd3d/libs/vkd3d/device.c
|
|
@@ -109,6 +109,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] =
|
|
VK_EXTENSION(EXT_FRAGMENT_SHADER_INTERLOCK, EXT_fragment_shader_interlock),
|
|
VK_EXTENSION(EXT_MUTABLE_DESCRIPTOR_TYPE, EXT_mutable_descriptor_type),
|
|
VK_EXTENSION(EXT_ROBUSTNESS_2, EXT_robustness2),
|
|
+ VK_EXTENSION(EXT_SAMPLER_FILTER_MINMAX, EXT_sampler_filter_minmax),
|
|
VK_EXTENSION(EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION, EXT_shader_demote_to_helper_invocation),
|
|
VK_EXTENSION(EXT_SHADER_STENCIL_EXPORT, EXT_shader_stencil_export),
|
|
VK_EXTENSION(EXT_SHADER_VIEWPORT_INDEX_LAYER, EXT_shader_viewport_index_layer),
|
|
@@ -835,6 +836,7 @@ struct vkd3d_physical_device_info
|
|
/* properties */
|
|
VkPhysicalDeviceDescriptorIndexingPropertiesEXT descriptor_indexing_properties;
|
|
VkPhysicalDeviceMaintenance3Properties maintenance3_properties;
|
|
+ VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT filter_minmax_properties;
|
|
VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT texel_buffer_alignment_properties;
|
|
VkPhysicalDeviceTransformFeedbackPropertiesEXT xfb_properties;
|
|
VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT vertex_divisor_properties;
|
|
@@ -900,6 +902,8 @@ static void vkd3d_chain_physical_device_info_structures(struct vkd3d_physical_de
|
|
vk_prepend_struct(&info->properties2, &info->maintenance3_properties);
|
|
if (vulkan_info->EXT_descriptor_indexing)
|
|
vk_prepend_struct(&info->properties2, &info->descriptor_indexing_properties);
|
|
+ if (vulkan_info->EXT_sampler_filter_minmax)
|
|
+ vk_prepend_struct(&info->properties2, &info->filter_minmax_properties);
|
|
if (vulkan_info->EXT_texel_buffer_alignment)
|
|
vk_prepend_struct(&info->properties2, &info->texel_buffer_alignment_properties);
|
|
if (vulkan_info->EXT_transform_feedback)
|
|
@@ -936,6 +940,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
|
|
info->properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
|
info->maintenance3_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES;
|
|
info->descriptor_indexing_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT;
|
|
+ info->filter_minmax_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT;
|
|
info->texel_buffer_alignment_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT;
|
|
info->xfb_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
|
|
info->vertex_divisor_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT;
|
|
@@ -1017,6 +1022,7 @@ static void vkd3d_trace_physical_device_limits(const struct vkd3d_physical_devic
|
|
const VkPhysicalDeviceLimits *limits = &info->properties2.properties.limits;
|
|
const VkPhysicalDeviceDescriptorIndexingPropertiesEXT *descriptor_indexing;
|
|
const VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT *buffer_alignment;
|
|
+ const VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT *minmax;
|
|
const VkPhysicalDeviceMaintenance3Properties *maintenance3;
|
|
const VkPhysicalDeviceTransformFeedbackPropertiesEXT *xfb;
|
|
|
|
@@ -1196,6 +1202,11 @@ static void vkd3d_trace_physical_device_limits(const struct vkd3d_physical_devic
|
|
TRACE(" maxPerSetDescriptors: %u.\n", maintenance3->maxPerSetDescriptors);
|
|
TRACE(" maxMemoryAllocationSize: %#"PRIx64".\n", maintenance3->maxMemoryAllocationSize);
|
|
|
|
+ minmax = &info->filter_minmax_properties;
|
|
+ TRACE(" VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT:\n");
|
|
+ TRACE(" filterMinmaxSingleComponentFormats: %#x.\n", minmax->filterMinmaxSingleComponentFormats);
|
|
+ TRACE(" filterMinmaxImageComponentMapping: %#x.\n", minmax->filterMinmaxImageComponentMapping);
|
|
+
|
|
buffer_alignment = &info->texel_buffer_alignment_properties;
|
|
TRACE(" VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT:\n");
|
|
TRACE(" storageTexelBufferOffsetAlignmentBytes: %#"PRIx64".\n",
|
|
@@ -1866,6 +1877,12 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device,
|
|
|
|
physical_device_info->formats4444_features.formatA4B4G4R4 = VK_FALSE;
|
|
|
|
+ if (!vulkan_info->EXT_sampler_filter_minmax)
|
|
+ WARN("Sampler min/max reduction filtering is not supported.\n");
|
|
+ else if (!physical_device_info->filter_minmax_properties.filterMinmaxSingleComponentFormats
|
|
+ || !physical_device_info->filter_minmax_properties.filterMinmaxImageComponentMapping)
|
|
+ WARN("Sampler min/max reduction filtering is only partially supported.");
|
|
+
|
|
vulkan_info->texel_buffer_alignment_properties = physical_device_info->texel_buffer_alignment_properties;
|
|
|
|
if (get_spec_version(vk_extensions, vk_extension_count, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME) >= 3)
|
|
diff --git a/libs/vkd3d/libs/vkd3d/resource.c b/libs/vkd3d/libs/vkd3d/resource.c
|
|
index 7946445ad07..f1491cbc2b6 100644
|
|
--- a/libs/vkd3d/libs/vkd3d/resource.c
|
|
+++ b/libs/vkd3d/libs/vkd3d/resource.c
|
|
@@ -3661,6 +3661,24 @@ bool vkd3d_create_raw_buffer_view(struct d3d12_device *device,
|
|
}
|
|
|
|
/* samplers */
|
|
+
|
|
+static VkSamplerReductionModeEXT vk_reduction_mode_from_d3d12(D3D12_FILTER_REDUCTION_TYPE mode)
|
|
+{
|
|
+ switch (mode)
|
|
+ {
|
|
+ case D3D12_FILTER_REDUCTION_TYPE_STANDARD:
|
|
+ case D3D12_FILTER_REDUCTION_TYPE_COMPARISON:
|
|
+ return VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE;
|
|
+ case D3D12_FILTER_REDUCTION_TYPE_MINIMUM:
|
|
+ return VK_SAMPLER_REDUCTION_MODE_MIN;
|
|
+ case D3D12_FILTER_REDUCTION_TYPE_MAXIMUM:
|
|
+ return VK_SAMPLER_REDUCTION_MODE_MAX;
|
|
+ default:
|
|
+ FIXME("Unhandled reduction mode %#x.\n", mode);
|
|
+ return VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE;
|
|
+ }
|
|
+}
|
|
+
|
|
static VkFilter vk_filter_from_d3d12(D3D12_FILTER_TYPE type)
|
|
{
|
|
switch (type)
|
|
@@ -3734,16 +3752,13 @@ static VkResult d3d12_create_sampler(struct d3d12_device *device, D3D12_FILTER f
|
|
D3D12_COMPARISON_FUNC comparison_func, D3D12_STATIC_BORDER_COLOR border_colour,
|
|
float min_lod, float max_lod, VkSampler *vk_sampler)
|
|
{
|
|
+ VkSamplerReductionModeCreateInfoEXT reduction_desc;
|
|
const struct vkd3d_vk_device_procs *vk_procs;
|
|
struct VkSamplerCreateInfo sampler_desc;
|
|
VkResult vr;
|
|
|
|
vk_procs = &device->vk_procs;
|
|
|
|
- if (D3D12_DECODE_FILTER_REDUCTION(filter) == D3D12_FILTER_REDUCTION_TYPE_MINIMUM
|
|
- || D3D12_DECODE_FILTER_REDUCTION(filter) == D3D12_FILTER_REDUCTION_TYPE_MAXIMUM)
|
|
- FIXME("Min/max reduction mode not supported.\n");
|
|
-
|
|
sampler_desc.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
|
sampler_desc.pNext = NULL;
|
|
sampler_desc.flags = 0;
|
|
@@ -3767,6 +3782,21 @@ static VkResult d3d12_create_sampler(struct d3d12_device *device, D3D12_FILTER f
|
|
|| address_w == D3D12_TEXTURE_ADDRESS_MODE_BORDER)
|
|
sampler_desc.borderColor = vk_border_colour_from_d3d12(border_colour);
|
|
|
|
+ reduction_desc.reductionMode = vk_reduction_mode_from_d3d12(D3D12_DECODE_FILTER_REDUCTION(filter));
|
|
+ if (reduction_desc.reductionMode != VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE)
|
|
+ {
|
|
+ if (device->vk_info.EXT_sampler_filter_minmax)
|
|
+ {
|
|
+ reduction_desc.sType = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT;
|
|
+ reduction_desc.pNext = NULL;
|
|
+ vk_prepend_struct(&sampler_desc, &reduction_desc);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ FIXME("Sampler min/max reduction filtering is not supported by the device.\n");
|
|
+ }
|
|
+ }
|
|
+
|
|
if ((vr = VK_CALL(vkCreateSampler(device->vk_device, &sampler_desc, NULL, vk_sampler))) < 0)
|
|
WARN("Failed to create Vulkan sampler, vr %d.\n", vr);
|
|
|
|
diff --git a/libs/vkd3d/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/libs/vkd3d/vkd3d_private.h
|
|
index b80a206294a..0e3d735e332 100644
|
|
--- a/libs/vkd3d/libs/vkd3d/vkd3d_private.h
|
|
+++ b/libs/vkd3d/libs/vkd3d/vkd3d_private.h
|
|
@@ -144,6 +144,7 @@ struct vkd3d_vulkan_info
|
|
bool EXT_fragment_shader_interlock;
|
|
bool EXT_mutable_descriptor_type;
|
|
bool EXT_robustness2;
|
|
+ bool EXT_sampler_filter_minmax;
|
|
bool EXT_shader_demote_to_helper_invocation;
|
|
bool EXT_shader_stencil_export;
|
|
bool EXT_shader_viewport_index_layer;
|
|
--
|
|
2.51.0
|
|
|