From b87e6f383848221ed087fbc1763cf7749248c106 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:07:05 -0700 Subject: [PATCH] vulkan: Emulate depth clip control when extension is not available. (#762) --- .../backend/spirv/emit_spirv_special.cpp | 16 ++++++++++++++- src/shader_recompiler/runtime_info.h | 3 ++- .../renderer_vulkan/vk_graphics_pipeline.cpp | 2 +- .../renderer_vulkan/vk_instance.cpp | 2 +- src/video_core/renderer_vulkan/vk_instance.h | 6 ++++++ .../renderer_vulkan/vk_pipeline_cache.cpp | 20 +++++++++++-------- .../renderer_vulkan/vk_pipeline_cache.h | 1 + 7 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp index 3ed89692..283c9b16 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp @@ -10,7 +10,21 @@ void EmitPrologue(EmitContext& ctx) { ctx.DefineBufferOffsets(); } -void EmitEpilogue(EmitContext& ctx) {} +void ConvertDepthMode(EmitContext& ctx) { + const Id type{ctx.F32[1]}; + const Id position{ctx.OpLoad(ctx.F32[4], ctx.output_position)}; + const Id z{ctx.OpCompositeExtract(type, position, 2u)}; + const Id w{ctx.OpCompositeExtract(type, position, 3u)}; + const Id screen_depth{ctx.OpFMul(type, ctx.OpFAdd(type, z, w), ctx.Constant(type, 0.5f))}; + const Id vector{ctx.OpCompositeInsert(ctx.F32[4], screen_depth, position, 2u)}; + ctx.OpStore(ctx.output_position, vector); +} + +void EmitEpilogue(EmitContext& ctx) { + if (ctx.stage == Stage::Vertex && ctx.runtime_info.vs_info.emulate_depth_negative_one_to_one) { + ConvertDepthMode(ctx); + } +} void EmitDiscard(EmitContext& ctx) { ctx.OpDemoteToHelperInvocationEXT(); diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index 37fd64bb..776fd90a 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -63,9 +63,10 @@ using VsOutputMap = std::array; struct VertexRuntimeInfo { boost::container::static_vector outputs; + bool emulate_depth_negative_one_to_one{}; bool operator==(const VertexRuntimeInfo& other) const noexcept { - return true; + return emulate_depth_negative_one_to_one == other.emulate_depth_negative_one_to_one; } }; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 1ab65737..f03e5d5d 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -125,7 +125,7 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul }; const vk::PipelineViewportStateCreateInfo viewport_info = { - .pNext = &clip_control, + .pNext = instance.IsDepthClipControlSupported() ? &clip_control : nullptr, .viewportCount = 1, .pViewports = &viewport, .scissorCount = 1, diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 56ab229c..395f7198 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -207,7 +207,7 @@ bool Instance::CreateDevice() { external_memory_host = add_extension(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME); custom_border_color = add_extension(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); add_extension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); - const bool depth_clip_control = add_extension(VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME); + depth_clip_control = add_extension(VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME); add_extension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME); workgroup_memory_explicit_layout = add_extension(VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME); diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index ee36d23e..52310955 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -117,6 +117,11 @@ public: return external_memory_host; } + /// Returns true when VK_EXT_depth_clip_control is supported + bool IsDepthClipControlSupported() const { + return depth_clip_control; + } + /// Returns true when VK_EXT_color_write_enable is supported bool IsColorWriteEnableSupported() const { return color_write_en; @@ -257,6 +262,7 @@ private: bool fragment_shader_barycentric{}; bool shader_stencil_export{}; bool external_memory_host{}; + bool depth_clip_control{}; bool workgroup_memory_explicit_layout{}; bool color_write_en{}; bool vertex_input_dynamic_state{}; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 364c2b4f..6a8e0f13 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -69,28 +69,32 @@ void GatherVertexOutputs(Shader::VertexRuntimeInfo& info, : (ctl.IsCullDistEnabled(7) ? VsOutput::CullDist7 : VsOutput::None)); } -Shader::RuntimeInfo BuildRuntimeInfo(Shader::Stage stage, const GraphicsPipelineKey& key, - const AmdGpu::Liverpool::Regs& regs) { +Shader::RuntimeInfo PipelineCache::BuildRuntimeInfo(Shader::Stage stage) { auto info = Shader::RuntimeInfo{stage}; + const auto& regs = liverpool->regs; switch (stage) { case Shader::Stage::Vertex: { info.num_user_data = regs.vs_program.settings.num_user_regs; info.num_input_vgprs = regs.vs_program.settings.vgpr_comp_cnt; GatherVertexOutputs(info.vs_info, regs.vs_output_control); + info.vs_info.emulate_depth_negative_one_to_one = + !instance.IsDepthClipControlSupported() && + regs.clipper_control.clip_space == Liverpool::ClipSpace::MinusWToW; break; } case Shader::Stage::Fragment: { info.num_user_data = regs.ps_program.settings.num_user_regs; - std::ranges::transform(key.mrt_swizzles, info.fs_info.mrt_swizzles.begin(), + std::ranges::transform(graphics_key.mrt_swizzles, info.fs_info.mrt_swizzles.begin(), [](Liverpool::ColorBuffer::SwapMode mode) { return static_cast(mode); }); + const auto& ps_inputs = regs.ps_inputs; for (u32 i = 0; i < regs.num_interp; i++) { info.fs_info.inputs.push_back({ - .param_index = u8(regs.ps_inputs[i].input_offset.Value()), - .is_default = bool(regs.ps_inputs[i].use_default), - .is_flat = bool(regs.ps_inputs[i].flat_shade), - .default_value = u8(regs.ps_inputs[i].default_value), + .param_index = u8(ps_inputs[i].input_offset.Value()), + .is_default = bool(ps_inputs[i].use_default), + .is_flat = bool(ps_inputs[i].flat_shade), + .default_value = u8(ps_inputs[i].default_value), }); } break; @@ -327,7 +331,7 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, std::tuple PipelineCache::GetProgram( Shader::Stage stage, Shader::ShaderParams params, u32& binding) { - const auto runtime_info = BuildRuntimeInfo(stage, graphics_key, liverpool->regs); + const auto runtime_info = BuildRuntimeInfo(stage); auto [it_pgm, new_program] = program_cache.try_emplace(params.hash); if (new_program) { Program* program = program_pool.Create(stage, params); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index 26130994..96e2cd04 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -60,6 +60,7 @@ private: std::string_view ext); vk::ShaderModule CompileModule(Shader::Info& info, const Shader::RuntimeInfo& runtime_info, std::span code, size_t perm_idx, u32& binding); + Shader::RuntimeInfo BuildRuntimeInfo(Shader::Stage stage); private: const Instance& instance;