Module: vkd3d
Branch: master
Commit: f649db23a596c1865bc7f110ca1feb3868451375
URL: https://gitlab.winehq.org/wine/vkd3d/-/commit/f649db23a596c1865bc7f110ca1fe…
Author: Zebediah Figura <zfigura(a)codeweavers.com>
Date: Mon Jul 31 00:45:54 2023 -0500
vkd3d-shader: Introduce a function to build a varying map between sm1 stages.
---
include/vkd3d_shader.h | 31 ++++++++++++++++++++++++++++
libs/vkd3d-shader/vkd3d_shader_main.c | 38 +++++++++++++++++++++++++++++++++++
2 files changed, 69 insertions(+)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h
index 1a4ad6f6..e98aad4f 100644
--- a/include/vkd3d_shader.h
+++ b/include/vkd3d_shader.h
@@ -1743,6 +1743,8 @@ struct vkd3d_shader_next_stage_info
* field is necessary to correctly match inter-stage varyings.
* This mapping may also be necessary under other circumstances where the
* varying interface does not match exactly.
+ *
+ * This mapping may be constructed by vkd3d_shader_build_varying_map().
*/
const struct vkd3d_shader_varying_map *varying_map;
/** The number of registers provided in \ref varying_map. */
@@ -2262,6 +2264,35 @@ VKD3D_SHADER_API int vkd3d_shader_serialize_dxbc(size_t section_count,
*/
VKD3D_SHADER_API void vkd3d_shader_free_scan_signature_info(struct vkd3d_shader_scan_signature_info *info);
+/**
+ * Build a mapping of output varyings in a shader stage to input varyings in
+ * the following shader stage.
+ *
+ * This mapping should be used in struct vkd3d_shader_next_stage_info to
+ * compile the first shader.
+ *
+ * \param output_signature The output signature of the first shader.
+ *
+ * \param input_signature The input signature of the second shader.
+ *
+ * \param count On output, contains the number of entries written into
+ * \ref varyings.
+ *
+ * \param varyings Pointer to an output array of varyings.
+ * This must point to space for N varyings, where N is the number of elements
+ * in the input signature.
+ *
+ * \remark Valid legacy Direct3D pixel shaders have at most 12 varying inputs:
+ * 10 inter-stage varyings, face, and position.
+ * Therefore, in practice, it is safe to call this function with a
+ * pre-allocated array with a fixed size of 12.
+ *
+ * \since 1.9
+ */
+VKD3D_SHADER_API void vkd3d_shader_build_varying_map(const struct vkd3d_shader_signature *output_signature,
+ const struct vkd3d_shader_signature *input_signature,
+ unsigned int *count, struct vkd3d_shader_varying_map *varyings);
+
#endif /* VKD3D_SHADER_NO_PROTOTYPES */
/** Type of vkd3d_shader_get_version(). */
diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c
index e8259181..e6ffb84d 100644
--- a/libs/vkd3d-shader/vkd3d_shader_main.c
+++ b/libs/vkd3d-shader/vkd3d_shader_main.c
@@ -1891,3 +1891,41 @@ void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *ins
vkd3d_free(instructions->icbs[i]);
vkd3d_free(instructions->icbs);
}
+
+void vkd3d_shader_build_varying_map(const struct vkd3d_shader_signature *output_signature,
+ const struct vkd3d_shader_signature *input_signature,
+ unsigned int *ret_count, struct vkd3d_shader_varying_map *varyings)
+{
+ unsigned int count = 0;
+ unsigned int i;
+
+ TRACE("output_signature %p, input_signature %p, ret_count %p, varyings %p.\n",
+ output_signature, input_signature, ret_count, varyings);
+
+ for (i = 0; i < input_signature->element_count; ++i)
+ {
+ const struct vkd3d_shader_signature_element *input_element, *output_element;
+
+ input_element = &input_signature->elements[i];
+
+ if (input_element->sysval_semantic != VKD3D_SHADER_SV_NONE)
+ continue;
+
+ varyings[count].input_register_index = input_element->register_index;
+ varyings[count].input_mask = input_element->mask;
+
+ if ((output_element = vkd3d_shader_find_signature_element(output_signature,
+ input_element->semantic_name, input_element->semantic_index, 0)))
+ {
+ varyings[count].output_signature_index = output_element - output_signature->elements;
+ }
+ else
+ {
+ varyings[count].output_signature_index = output_signature->element_count;
+ }
+
+ ++count;
+ }
+
+ *ret_count = count;
+}
Module: vkd3d
Branch: master
Commit: 11475ef62a47a2e32a4404ea6653dffabdc60a38
URL: https://gitlab.winehq.org/wine/vkd3d/-/commit/11475ef62a47a2e32a4404ea6653d…
Author: Zebediah Figura <zfigura(a)codeweavers.com>
Date: Thu Jul 20 21:52:25 2023 -0500
vkd3d-shader: Implement remapping shader output registers to match the next shader's semantics.
---
include/vkd3d_shader.h | 76 +++++++++++++++++++++++++++++++-
libs/vkd3d-shader/ir.c | 76 +++++++++++++++++++++++++++++++-
libs/vkd3d-shader/spirv.c | 2 +-
libs/vkd3d-shader/vkd3d_shader_private.h | 5 ++-
4 files changed, 155 insertions(+), 4 deletions(-)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h
index d6653d18..1a4ad6f6 100644
--- a/include/vkd3d_shader.h
+++ b/include/vkd3d_shader.h
@@ -90,6 +90,11 @@ enum vkd3d_shader_structure_type
* \since 1.9
*/
VKD3D_SHADER_STRUCTURE_TYPE_SCAN_SIGNATURE_INFO,
+ /**
+ * The structure is a vkd3d_shader_next_stage_info structure.
+ * \since 1.9
+ */
+ VKD3D_SHADER_STRUCTURE_TYPE_NEXT_STAGE_INFO,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_STRUCTURE_TYPE),
};
@@ -1676,6 +1681,74 @@ struct vkd3d_shader_scan_signature_info
struct vkd3d_shader_signature patch_constant;
};
+/**
+ * Describes the mapping of a output varying register in a shader stage,
+ * to an input varying register in the following shader stage.
+ *
+ * This structure is used in struct vkd3d_shader_next_stage_info.
+ */
+struct vkd3d_shader_varying_map
+{
+ /**
+ * The signature index (in the output signature) of the output varying.
+ * If greater than or equal to the number of elements in the output
+ * signature, signifies that the varying is consumed by the next stage but
+ * not written by this one.
+ */
+ unsigned int output_signature_index;
+ /** The register index of the input varying to map this register to. */
+ unsigned int input_register_index;
+ /** The mask consumed by the destination register. */
+ unsigned int input_mask;
+};
+
+/**
+ * A chained structure which describes the next shader in the pipeline.
+ *
+ * This structure is optional, and should only be provided if there is in fact
+ * another shader in the pipeline.
+ * However, depending on the input and output formats, this structure may be
+ * necessary in order to generate shaders which correctly match each other.
+ * If the structure or its individual fields are not provided, vkd3d-shader
+ * will generate shaders which may be correct in isolation, but are not
+ * guaranteed to correctly match each other.
+ *
+ * This structure is passed to vkd3d_shader_compile() and extends
+ * vkd3d_shader_compile_info.
+ *
+ * This structure contains only input parameters.
+ *
+ * \since 1.9
+ */
+struct vkd3d_shader_next_stage_info
+{
+ /** Must be set to VKD3D_SHADER_STRUCTURE_TYPE_NEXT_STAGE_INFO. */
+ enum vkd3d_shader_structure_type type;
+ /** Optional pointer to a structure containing further parameters. */
+ const void *next;
+
+ /**
+ * A mapping of output varyings in this shader stage to input varyings
+ * in the next shader stage.
+ *
+ * This mapping should include exactly one element for each varying
+ * consumed by the next shader stage.
+ * If this shader stage outputs a varying that is not consumed by the next
+ * shader stage, that varying should be absent from this array.
+ *
+ * If this field is absent, vkd3d-shader will map varyings from one stage
+ * to another based on their register index.
+ * For Direct3D shader model 3.0, such a default mapping will be incorrect
+ * unless the registers are allocated in the same order, and hence this
+ * field is necessary to correctly match inter-stage varyings.
+ * This mapping may also be necessary under other circumstances where the
+ * varying interface does not match exactly.
+ */
+ const struct vkd3d_shader_varying_map *varying_map;
+ /** The number of registers provided in \ref varying_map. */
+ unsigned int varying_count;
+};
+
#ifdef LIBVKD3D_SHADER_SOURCE
# define VKD3D_SHADER_API VKD3D_EXPORT
#else
@@ -1748,13 +1821,14 @@ VKD3D_SHADER_API const enum vkd3d_shader_target_type *vkd3d_shader_get_supported
*
* Depending on the source and target types, this function may support the
* following chained structures:
+ * - vkd3d_shader_hlsl_source_info
* - vkd3d_shader_interface_info
+ * - vkd3d_shader_next_stage_info
* - vkd3d_shader_scan_descriptor_info
* - vkd3d_shader_scan_signature_info
* - vkd3d_shader_spirv_domain_shader_target_info
* - vkd3d_shader_spirv_target_info
* - vkd3d_shader_transform_feedback_info
- * - vkd3d_shader_hlsl_source_info
*
* \param compile_info A chained structure containing compilation parameters.
*
diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c
index d74f81af..0ade5a07 100644
--- a/libs/vkd3d-shader/ir.c
+++ b/libs/vkd3d-shader/ir.c
@@ -85,6 +85,75 @@ static void shader_instruction_eliminate_phase_instance_id(struct vkd3d_shader_i
shader_register_eliminate_phase_addressing((struct vkd3d_shader_register *)&ins->dst[i].reg, instance_id);
}
+static const struct vkd3d_shader_varying_map *find_varying_map(
+ const struct vkd3d_shader_next_stage_info *next_stage, unsigned int signature_idx)
+{
+ unsigned int i;
+
+ for (i = 0; i < next_stage->varying_count; ++i)
+ {
+ if (next_stage->varying_map[i].output_signature_index == signature_idx)
+ return &next_stage->varying_map[i];
+ }
+
+ return NULL;
+}
+
+static enum vkd3d_result remap_output_signature(struct vkd3d_shader_parser *parser,
+ const struct vkd3d_shader_compile_info *compile_info)
+{
+ struct shader_signature *signature = &parser->shader_desc.output_signature;
+ const struct vkd3d_shader_next_stage_info *next_stage;
+ unsigned int i;
+
+ if (!(next_stage = vkd3d_find_struct(compile_info->next, NEXT_STAGE_INFO)))
+ return VKD3D_OK;
+
+ for (i = 0; i < signature->element_count; ++i)
+ {
+ const struct vkd3d_shader_varying_map *map = find_varying_map(next_stage, i);
+ struct signature_element *e = &signature->elements[i];
+
+ if (map)
+ {
+ unsigned int input_mask = map->input_mask;
+
+ e->target_location = map->input_register_index;
+
+ /* It is illegal in Vulkan if the next shader uses the same varying
+ * location with a different mask. */
+ if (input_mask && input_mask != e->mask)
+ {
+ vkd3d_shader_parser_error(parser, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED,
+ "Aborting due to not yet implemented feature: "
+ "Output mask %#x does not match input mask %#x.",
+ e->mask, input_mask);
+ return VKD3D_ERROR_NOT_IMPLEMENTED;
+ }
+ }
+ else
+ {
+ vkd3d_shader_parser_error(parser, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED,
+ "Aborting due to not yet implemented feature: "
+ "This stage outputs varyings not consumed by the next stage.");
+ return VKD3D_ERROR_NOT_IMPLEMENTED;
+ }
+ }
+
+ for (i = 0; i < next_stage->varying_count; ++i)
+ {
+ if (next_stage->varying_map[i].output_signature_index >= signature->element_count)
+ {
+ vkd3d_shader_parser_error(parser, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED,
+ "Aborting due to not yet implemented feature: "
+ "The next stage consumes varyings not written by this stage.");
+ return VKD3D_ERROR_NOT_IMPLEMENTED;
+ }
+ }
+
+ return VKD3D_OK;
+}
+
struct hull_flattener
{
struct vkd3d_shader_instruction_array instructions;
@@ -1194,7 +1263,8 @@ static enum vkd3d_result instruction_array_normalise_flat_constants(struct vkd3d
return VKD3D_OK;
}
-enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser)
+enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser,
+ const struct vkd3d_shader_compile_info *compile_info)
{
struct vkd3d_shader_instruction_array *instructions = &parser->instructions;
enum vkd3d_result result = VKD3D_OK;
@@ -1202,6 +1272,10 @@ enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser)
if (parser->shader_desc.is_dxil)
return result;
+ if (parser->shader_version.type != VKD3D_SHADER_TYPE_PIXEL
+ && (result = remap_output_signature(parser, compile_info)) < 0)
+ return result;
+
if (parser->shader_version.type == VKD3D_SHADER_TYPE_HULL
&& (result = instruction_array_flatten_hull_shader_phases(instructions)) >= 0)
{
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c
index 27d95912..28825256 100644
--- a/libs/vkd3d-shader/spirv.c
+++ b/libs/vkd3d-shader/spirv.c
@@ -9542,7 +9542,7 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
compiler->location.column = 0;
compiler->location.line = 1;
- if ((result = vkd3d_shader_normalise(parser)) < 0)
+ if ((result = vkd3d_shader_normalise(parser, compile_info)) < 0)
return result;
instructions = parser->instructions;
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h
index d2a2ffe5..188fe460 100644
--- a/libs/vkd3d-shader/vkd3d_shader_private.h
+++ b/libs/vkd3d-shader/vkd3d_shader_private.h
@@ -168,6 +168,8 @@ enum vkd3d_shader_error
VKD3D_SHADER_WARNING_DXIL_INVALID_BLOCK_LENGTH = 8302,
VKD3D_SHADER_WARNING_DXIL_INVALID_MODULE_LENGTH = 8303,
VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS = 8304,
+
+ VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED = 9000,
};
enum vkd3d_shader_opcode
@@ -1409,6 +1411,7 @@ void dxbc_writer_add_section(struct dxbc_writer *dxbc, uint32_t tag, const void
void dxbc_writer_init(struct dxbc_writer *dxbc);
int dxbc_writer_write(struct dxbc_writer *dxbc, struct vkd3d_shader_code *code);
-enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser);
+enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser,
+ const struct vkd3d_shader_compile_info *compile_info);
#endif /* __VKD3D_SHADER_PRIVATE_H */