From abb33d4aecd7748cd4b2e377f8c6fe18df58e67c Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 19 Dec 2019 01:41:22 -0300 Subject: [PATCH 1/4] vk_shader_decompiler: Update sirit and implement Texture AOFFI --- externals/sirit | 2 +- .../renderer_vulkan/vk_shader_decompiler.cpp | 56 +++++++++++-------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/externals/sirit b/externals/sirit index 12f40a8032..9f4d057aa2 160000 --- a/externals/sirit +++ b/externals/sirit @@ -1 +1 @@ -Subproject commit 12f40a80324d7c154f19f25c448a5ce27d38cd18 +Subproject commit 9f4d057aa28c4e9509bdc767afb27b4aee303b7e diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 6227bc70be..93e2704b4d 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -1555,26 +1555,11 @@ private: Expression Texture(Operation operation) { const auto& meta = std::get(operation.GetMeta()); - UNIMPLEMENTED_IF(!meta.aoffi.empty()); const bool can_implicit = stage == ShaderType::Fragment; const Id sampler = GetTextureSampler(operation); const Id coords = GetCoordinates(operation, Type::Float); - if (meta.depth_compare) { - // Depth sampling - UNIMPLEMENTED_IF(meta.bias); - const Id dref = AsFloat(Visit(meta.depth_compare)); - if (can_implicit) { - return {OpImageSampleDrefImplicitLod(t_float, sampler, coords, dref, {}), - Type::Float}; - } else { - return {OpImageSampleDrefExplicitLod(t_float, sampler, coords, dref, - spv::ImageOperandsMask::Lod, v_float_zero), - Type::Float}; - } - } - std::vector operands; spv::ImageOperandsMask mask{}; if (meta.bias) { @@ -1582,13 +1567,36 @@ private: operands.push_back(AsFloat(Visit(meta.bias))); } + if (!can_implicit) { + mask = mask | spv::ImageOperandsMask::Lod; + operands.push_back(v_float_zero); + } + + if (!meta.aoffi.empty()) { + mask = mask | spv::ImageOperandsMask::Offset; + operands.push_back(GetOffsetCoordinates(operation)); + } + + if (meta.depth_compare) { + // Depth sampling + UNIMPLEMENTED_IF(meta.bias); + const Id dref = AsFloat(Visit(meta.depth_compare)); + if (can_implicit) { + return { + OpImageSampleDrefImplicitLod(t_float, sampler, coords, dref, mask, operands), + Type::Float}; + } else { + return { + OpImageSampleDrefExplicitLod(t_float, sampler, coords, dref, mask, operands), + Type::Float}; + } + } + Id texture; if (can_implicit) { texture = OpImageSampleImplicitLod(t_float4, sampler, coords, mask, operands); } else { - texture = OpImageSampleExplicitLod(t_float4, sampler, coords, - mask | spv::ImageOperandsMask::Lod, v_float_zero, - operands); + texture = OpImageSampleExplicitLod(t_float4, sampler, coords, mask, operands); } return GetTextureElement(operation, texture, Type::Float); } @@ -1601,7 +1609,8 @@ private: const Id lod = AsFloat(Visit(meta.lod)); spv::ImageOperandsMask mask = spv::ImageOperandsMask::Lod; - std::vector operands; + std::vector operands{lod}; + if (!meta.aoffi.empty()) { mask = mask | spv::ImageOperandsMask::Offset; operands.push_back(GetOffsetCoordinates(operation)); @@ -1609,11 +1618,10 @@ private: if (meta.sampler.IsShadow()) { const Id dref = AsFloat(Visit(meta.depth_compare)); - return { - OpImageSampleDrefExplicitLod(t_float, sampler, coords, dref, mask, lod, operands), - Type::Float}; + return {OpImageSampleDrefExplicitLod(t_float, sampler, coords, dref, mask, operands), + Type::Float}; } - const Id texture = OpImageSampleExplicitLod(t_float4, sampler, coords, mask, lod, operands); + const Id texture = OpImageSampleExplicitLod(t_float4, sampler, coords, mask, operands); return GetTextureElement(operation, texture, Type::Float); } @@ -1722,7 +1730,7 @@ private: const std::vector grad = {dx, dy}; static constexpr auto mask = spv::ImageOperandsMask::Grad; - const Id texture = OpImageSampleImplicitLod(t_float4, sampler, coords, mask, grad); + const Id texture = OpImageSampleExplicitLod(t_float4, sampler, coords, mask, grad); return GetTextureElement(operation, texture, Type::Float); } From 485c21eac3adbc29258da09a16cc8067aaa9b366 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 19 Dec 2019 01:43:29 -0300 Subject: [PATCH 2/4] vk_shader_decompiler: Normalize output fragment attachments Some games write from fragment shaders to an unexistant framebuffer attachment or they don't write to one when it exists in the framebuffer. Fix this by skipping writes or adding zeroes. --- .../renderer_vulkan/vk_shader_decompiler.cpp | 21 ++++++++----------- .../renderer_vulkan/vk_shader_decompiler.h | 3 +++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 93e2704b4d..c84f9e4beb 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -543,7 +543,7 @@ private: } for (u32 rt = 0; rt < static_cast(frag_colors.size()); ++rt) { - if (!IsRenderTargetUsed(rt)) { + if (!specialization.enabled_rendertargets[rt]) { continue; } @@ -1868,12 +1868,18 @@ private: // rendertargets/components are skipped in the register assignment. u32 current_reg = 0; for (u32 rt = 0; rt < Maxwell::NumRenderTargets; ++rt) { + if (!specialization.enabled_rendertargets[rt]) { + // Skip rendertargets that are not enabled + continue; + } // TODO(Subv): Figure out how dual-source blending is configured in the Switch. for (u32 component = 0; component < 4; ++component) { + const Id pointer = AccessElement(t_out_float, frag_colors.at(rt), component); if (header.ps.IsColorComponentOutputEnabled(rt, component)) { - OpStore(AccessElement(t_out_float, frag_colors.at(rt), component), - SafeGetRegister(current_reg)); + OpStore(pointer, SafeGetRegister(current_reg)); ++current_reg; + } else { + OpStore(pointer, component == 3 ? v_float_one : v_float_zero); } } } @@ -2003,15 +2009,6 @@ private: return DeclareBuiltIn(builtin, spv::StorageClass::Input, type, std::move(name)); } - bool IsRenderTargetUsed(u32 rt) const { - for (u32 component = 0; component < 4; ++component) { - if (header.ps.IsColorComponentOutputEnabled(rt, component)) { - return true; - } - } - return false; - } - template Id AccessElement(Id pointer_type, Id composite, Args... elements_) { std::vector members; diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.h b/src/video_core/renderer_vulkan/vk_shader_decompiler.h index 2b01321b6d..415801b6c5 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.h +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.h @@ -101,6 +101,9 @@ struct Specialization final { Maxwell::TessellationSpacing spacing{}; bool clockwise{}; } tessellation; + + // Fragment specific + std::bitset<8> enabled_rendertargets; }; // Old gcc versions don't consider this trivially copyable. // static_assert(std::is_trivially_copyable_v); From de918ebeb0171010d15d68281f45356898ef8c78 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 19 Dec 2019 01:45:09 -0300 Subject: [PATCH 3/4] vk_shader_decompiler: Skip NDC correction when it is native Avoid changing gl_Position when the NDC used by the game is [0, 1] (Vulkan's native). --- src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | 2 +- src/video_core/renderer_vulkan/vk_shader_decompiler.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index c84f9e4beb..6c7f73d481 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -1841,7 +1841,7 @@ private: } void PreExit() { - if (stage == ShaderType::Vertex) { + if (stage == ShaderType::Vertex && specialization.ndc_minus_one_to_one) { const u32 position_index = out_indices.position.value(); const Id z_pointer = AccessElement(t_out_float, out_vertex, position_index, 2U); const Id w_pointer = AccessElement(t_out_float, out_vertex, position_index, 3U); diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.h b/src/video_core/renderer_vulkan/vk_shader_decompiler.h index 415801b6c5..10794be1c0 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.h +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.h @@ -94,6 +94,7 @@ struct Specialization final { Maxwell::PrimitiveTopology primitive_topology{}; std::optional point_size{}; std::array attribute_types{}; + bool ndc_minus_one_to_one{}; // Tessellation specific struct { From 2a63b3bdb920a48a341f624361730f5c148fafe7 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 19 Dec 2019 01:46:20 -0300 Subject: [PATCH 4/4] vk_shader_decompiler: Fix full decompilation When full decompilation was enabled, labels were not being inserted and instructions were misused. Fix these bugs. --- src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 6c7f73d481..8331459713 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -2594,7 +2594,7 @@ public: const Id target = decomp.Constant(decomp.t_uint, expr.value); Id gpr = decomp.OpLoad(decomp.t_float, decomp.registers.at(expr.gpr)); gpr = decomp.OpBitcast(decomp.t_uint, gpr); - return decomp.OpLogicalEqual(decomp.t_uint, gpr, target); + return decomp.OpIEqual(decomp.t_bool, gpr, target); } Id Visit(const Expr& node) { @@ -2664,11 +2664,11 @@ public: const Id loop_label = decomp.OpLabel(); const Id endloop_label = decomp.OpLabel(); const Id loop_start_block = decomp.OpLabel(); - const Id loop_end_block = decomp.OpLabel(); + const Id loop_continue_block = decomp.OpLabel(); current_loop_exit = endloop_label; decomp.OpBranch(loop_label); decomp.AddLabel(loop_label); - decomp.OpLoopMerge(endloop_label, loop_end_block, spv::LoopControlMask::MaskNone); + decomp.OpLoopMerge(endloop_label, loop_continue_block, spv::LoopControlMask::MaskNone); decomp.OpBranch(loop_start_block); decomp.AddLabel(loop_start_block); ASTNode current = ast.nodes.GetFirst(); @@ -2676,6 +2676,8 @@ public: Visit(current); current = current->GetNext(); } + decomp.OpBranch(loop_continue_block); + decomp.AddLabel(loop_continue_block); ExprDecompiler expr_parser{decomp}; const Id condition = expr_parser.Visit(ast.condition); decomp.OpBranchConditional(condition, loop_label, endloop_label);