From a08e493a3a4a8a623b82f9414019a8dc5da6d37b Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Wed, 16 Jun 2021 16:52:00 +0200 Subject: [PATCH] vkd3d-shader: Add interface for shader workarounds. Don't really have much of a choice for the short term. :\ Signed-off-by: Hans-Kristian Arntzen --- include/vkd3d_shader.h | 27 +++++++++++++++++++++++++++ libs/vkd3d-shader/spirv.c | 22 ++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 61c1ee17..d902f5b2 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -284,6 +284,32 @@ enum vkd3d_shader_target_extension VKD3D_SHADER_TARGET_EXTENSION_READ_STORAGE_IMAGE_WITHOUT_FORMAT }; +enum vkd3d_shader_quirk +{ + /* If sample or sample_b is used in control flow, force LOD 0.0 (which game should expect anyway). + * Works around specific, questionable shaders which rely on this to give sensible results, + * since LOD can become garbage on certain implementations, and even on native drivers + * the result is implementation defined. + * Outside of making this edge case well-defined in Vulkan or hacking driver compilers, + * this is the pragmatic solution. + * Hoisting gradients is not possible in all cases, + * and would not be worth it until it's a widespread problem. */ + VKD3D_SHADER_QUIRK_FORCE_EXPLICIT_LOD_IN_CONTROL_FLOW = (1 << 0) +}; + +struct vkd3d_shader_quirk_hash +{ + vkd3d_shader_hash_t shader_hash; + uint32_t quirks; +}; + +struct vkd3d_shader_quirk_info +{ + const struct vkd3d_shader_quirk_hash *hashes; + unsigned int num_hashes; + uint32_t default_quirks; +}; + struct vkd3d_shader_compile_arguments { enum vkd3d_shader_target target; @@ -299,6 +325,7 @@ struct vkd3d_shader_compile_arguments unsigned int output_swizzle_count; uint64_t config_flags; + const struct vkd3d_shader_quirk_info *quirks; }; enum vkd3d_tessellator_output_primitive diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index adb9f75f..f0154272 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2241,6 +2241,7 @@ struct vkd3d_dxbc_compiler struct vkd3d_spirv_builder spirv_builder; uint32_t options; + uint32_t quirks; struct rb_tree symbol_table; uint32_t temp_id; @@ -2350,6 +2351,21 @@ struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader compiler->shader_version = *shader_version; compiler->descriptor_qa_shader_hash = shader_hash; + if (compile_args && compile_args->quirks) + { + for (i = 0; i < compile_args->quirks->num_hashes; i++) + { + if (compile_args->quirks->hashes[i].shader_hash == shader_hash) + { + compiler->quirks = compile_args->quirks->hashes[i].quirks; + break; + } + } + + if (i == compile_args->quirks->num_hashes) + compiler->quirks = compile_args->quirks->default_quirks; + } + max_element_count = max(output_signature->element_count, patch_constant_signature->element_count); if (!(compiler->output_info = vkd3d_calloc(max_element_count, sizeof(*compiler->output_info)))) { @@ -9023,6 +9039,12 @@ static void vkd3d_dxbc_compiler_emit_lod(struct vkd3d_dxbc_compiler *compiler, dst, val_id, image.sampled_type, resource->swizzle); } +static bool vkd3d_dxbc_compiler_has_quirk(struct vkd3d_dxbc_compiler *compiler, + enum vkd3d_shader_quirk quirk) +{ + return !!(compiler->quirks & quirk); +} + static void vkd3d_dxbc_compiler_emit_sample(struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_instruction *instruction) {