From: Zebediah Figura zfigura@codeweavers.com
--- configure.ac | 1 + include/private/vkd3d_common.h | 13 +++++++++ include/vkd3d_shader.h | 50 +++++++++++++++++++++++++++++++++- libs/vkd3d-shader/spirv.c | 50 ++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac index b58c2f4d..4a5e1f05 100644 --- a/configure.ac +++ b/configure.ac @@ -138,6 +138,7 @@ AS_IF([test "x$with_xcb" != "xno"],
dnl Check for functions VKD3D_CHECK_FUNC([HAVE_BUILTIN_CLZ], [__builtin_clz], [__builtin_clz(0)]) +VKD3D_CHECK_FUNC([HAVE_BUILTIN_FFS], [__builtin_ffs], [__builtin_ffs(1)]) VKD3D_CHECK_FUNC([HAVE_BUILTIN_POPCOUNT], [__builtin_popcount], [__builtin_popcount(0)]) VKD3D_CHECK_FUNC([HAVE_BUILTIN_ADD_OVERFLOW], [__builtin_add_overflow], [__builtin_add_overflow(0, 0, (int *)0)]) VKD3D_CHECK_FUNC([HAVE_SYNC_ADD_AND_FETCH], [__sync_add_and_fetch], [__sync_add_and_fetch((int *)0, 0)]) diff --git a/include/private/vkd3d_common.h b/include/private/vkd3d_common.h index f3242272..7098ff54 100644 --- a/include/private/vkd3d_common.h +++ b/include/private/vkd3d_common.h @@ -148,6 +148,19 @@ static inline unsigned int vkd3d_log2i(unsigned int x) #endif }
+static inline int vkd3d_bit_scan(unsigned int *x) +{ + int bit_offset; +#ifdef HAVE_BUILTIN_FFS + bit_offset = __builtin_ffs(*x) - 1; +#else + for (bit_offset = 0; bit_offset < 32; bit_offset++) + if (*x & (1u << bit_offset)) break; +#endif + *x ^= 1u << bit_offset; + return bit_offset; +} + static inline void *vkd3d_memmem( const void *haystack, size_t haystack_len, const void *needle, size_t needle_len) { const char *str = haystack; diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 8133d240..cd569ce9 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), }; @@ -1659,6 +1664,48 @@ struct vkd3d_shader_scan_signature_info struct vkd3d_shader_signature patch_constant; };
+/** + * 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. + * + * For example, when compiling legacy Direct3D bytecode to SPIR-V, vkd3d-shader + * needs to assign a mapping of Direct3D usages to SPIR-V varying locations, + * and because legacy Direct3D bytecode need not specify locations in the same + * order between stages (unlike e.g. TPF) vkd3d-shader needs to know that + * mapping when compiling linked stages. + * + * This structure should be provided when compiling from + * VKD3D_SHADER_SOURCE_D3D_BYTECODE. + * + * 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; + + /** + * The input signature of the next shader. + * This should be generated by vkd3d-shader, using + * struct vkd3d_shader_scan_signature_info. + */ + const struct vkd3d_shader_signature *input_signature; +}; + #ifdef LIBVKD3D_SHADER_SOURCE # define VKD3D_SHADER_API VKD3D_EXPORT #else @@ -1731,13 +1778,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/spirv.c b/libs/vkd3d-shader/spirv.c index dcf957ea..5158dec5 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -9455,6 +9455,53 @@ static void spirv_compiler_emit_sm1_constant_buffer(struct spirv_compiler *compi spirv_compiler_emit_constant_buffer(compiler, count, &range, ®); }
+/* Find the output semantic register index matching the next shader, or + * find an unused register index if the next shader doesn't consume this + * semantic. */ +static unsigned int get_output_semantic_register_index(const struct vkd3d_shader_signature *ps_signature, + const char *name, unsigned int index, uint32_t *output_register_mask) +{ + struct vkd3d_shader_signature_element *element; + + if ((element = vkd3d_shader_find_signature_element(ps_signature, name, index, 0))) + return element->register_index; + + if (*output_register_mask) + return vkd3d_bit_scan(output_register_mask); + + ERR("No unused register index available.\n"); + return ~0u; +} + +static void remap_output_signature(struct shader_signature *signature, + const struct vkd3d_shader_compile_info *compile_info) +{ + const struct vkd3d_shader_next_stage_info *next_stage_info; + const struct vkd3d_shader_signature *ps_signature; + uint32_t output_register_mask = ~0u; + unsigned int i; + + if (!(next_stage_info = vkd3d_find_struct(compile_info->next, NEXT_STAGE_INFO)) + || !(ps_signature = next_stage_info->input_signature)) + return; + + for (i = 0; i < ps_signature->element_count; ++i) + { + unsigned int register_index = ps_signature->elements[i].register_index; + + if (register_index < 32) + bitmap_clear(&output_register_mask, register_index); + } + + for (i = 0; i < signature->element_count; ++i) + { + struct signature_element *e = &signature->elements[i]; + + e->register_index = get_output_semantic_register_index(ps_signature, + e->semantic_name, e->semantic_index, &output_register_mask); + } +} + static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_parser *parser, struct vkd3d_shader_code *spirv) @@ -9486,6 +9533,9 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, instructions = parser->instructions; memset(&parser->instructions, 0, sizeof(parser->instructions));
+ if (parser->shader_version.major < 4 && parser->shader_version.type == VKD3D_SHADER_TYPE_VERTEX) + remap_output_signature(&shader_desc->output_signature, compile_info); + compiler->input_signature = shader_desc->input_signature; compiler->output_signature = shader_desc->output_signature; compiler->patch_constant_signature = shader_desc->patch_constant_signature;