From: Zebediah Figura zfigura@codeweavers.com
--- configure.ac | 1 + include/private/vkd3d_common.h | 13 +++++++++ include/vkd3d_shader.h | 35 ++++++++++++++++++++++ libs/vkd3d-shader/vkd3d_shader_main.c | 42 +++++++++++++++++++++++++++ 4 files changed, 91 insertions(+)
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 d4ad2d07..6f1eaf15 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -1717,6 +1717,8 @@ struct vkd3d_shader_next_stage_info * A mapping of output varying registers in this shader stage to input * varying registers in the next shader stage. * + * This mapping should be constructed by vkd3d_shader_build_varying_map(). + * * If absent, vkd3d-shader will map registers directly based on their * register index. * @@ -2243,6 +2245,39 @@ 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. + * + * This function should be called twice: once, with an input count of zero, in + * order to retrieve the necessary size of the varyings map, and again, with an + * input count containing the actual number of varyings to retrieve. + * + * \remark In practice, since register indices are assigned (from scanning) + * according to the actual Direct3D register index, it is safe to assume that + * the highest register index for a legacy Direct3D shader is no higher than 11, + * and hence one may simply call this function with a pre-allocated array of 12 + * varyings. + * + * \param output_signature The output signature of the first shader. + * + * \param input_signature The input signature of the second shader. + * + * \param count On input, this should point to an integer describing the + * allocated size, in elements, of the \ref varyings array. On output, contains + * the number of entries required. + * + * \param varyings Pointer to an output array of varyings. + * + * \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..0f2f3b7e 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1891,3 +1891,45 @@ 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 *count, struct vkd3d_shader_varying_map *varyings) +{ + uint32_t unused_register_mask = ~0u; + unsigned int i; + + TRACE("output_signature %p, input_signature %p, count %u, varyings %p.\n", + output_signature, input_signature, *count, varyings); + + for (i = 0; i < input_signature->element_count; ++i) + { + unsigned int register_index = input_signature->elements[i].register_index; + + if (register_index < 32) + bitmap_clear(&unused_register_mask, register_index); + } + + for (i = 0; i < output_signature->element_count; ++i) + { + const struct vkd3d_shader_signature_element *input_element, *output_element; + unsigned int output_reg; + + output_element = &output_signature->elements[i]; + output_reg = output_element->register_index; + if ((input_element = vkd3d_shader_find_signature_element(input_signature, + output_element->semantic_name, output_element->semantic_index, 0))) + { + varyings[output_reg].dst_index = input_element->register_index; + varyings[output_reg].dst_mask = input_element->mask; + } + else + { + varyings[output_reg].dst_mask = 0; + if (unused_register_mask) + varyings[output_reg].dst_index = vkd3d_bit_scan(&unused_register_mask); + else + ERR("No unused register index available.\n"); + } + } +}