diff options
| author | 2019-12-26 21:43:44 -0500 | |
|---|---|---|
| committer | 2019-12-26 21:43:44 -0500 | |
| commit | 8a76f816a4586444903180f12a0408a1ae82a82d (patch) | |
| tree | a92b35863fe491f3e9b8412df7b33c6dc978a07c /src | |
| parent | Merge pull request #3244 from ReinUsesLisp/vk-fps (diff) | |
| parent | shader/texture: Implement TLD4.PTP (diff) | |
| download | yuzu-8a76f816a4586444903180f12a0408a1ae82a82d.tar.gz yuzu-8a76f816a4586444903180f12a0408a1ae82a82d.tar.xz yuzu-8a76f816a4586444903180f12a0408a1ae82a82d.zip | |
Merge pull request #3228 from ReinUsesLisp/ptp
shader/texture: Implement AOFFI and PTP for TLD4 and TLD4S
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 12 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 90 | ||||
| -rw-r--r-- | src/video_core/shader/decode/texture.cpp | 108 | ||||
| -rw-r--r-- | src/video_core/shader/node.h | 1 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 5 |
5 files changed, 142 insertions, 74 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index dfb12cd2d..412ca5551 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -1239,7 +1239,7 @@ union Instruction { | |||
| 1239 | BitField<35, 1, u64> ndv_flag; | 1239 | BitField<35, 1, u64> ndv_flag; |
| 1240 | BitField<49, 1, u64> nodep_flag; | 1240 | BitField<49, 1, u64> nodep_flag; |
| 1241 | BitField<50, 1, u64> dc_flag; | 1241 | BitField<50, 1, u64> dc_flag; |
| 1242 | BitField<54, 2, u64> info; | 1242 | BitField<54, 2, u64> offset_mode; |
| 1243 | BitField<56, 2, u64> component; | 1243 | BitField<56, 2, u64> component; |
| 1244 | 1244 | ||
| 1245 | bool UsesMiscMode(TextureMiscMode mode) const { | 1245 | bool UsesMiscMode(TextureMiscMode mode) const { |
| @@ -1251,9 +1251,9 @@ union Instruction { | |||
| 1251 | case TextureMiscMode::DC: | 1251 | case TextureMiscMode::DC: |
| 1252 | return dc_flag != 0; | 1252 | return dc_flag != 0; |
| 1253 | case TextureMiscMode::AOFFI: | 1253 | case TextureMiscMode::AOFFI: |
| 1254 | return info == 1; | 1254 | return offset_mode == 1; |
| 1255 | case TextureMiscMode::PTP: | 1255 | case TextureMiscMode::PTP: |
| 1256 | return info == 2; | 1256 | return offset_mode == 2; |
| 1257 | default: | 1257 | default: |
| 1258 | break; | 1258 | break; |
| 1259 | } | 1259 | } |
| @@ -1265,7 +1265,7 @@ union Instruction { | |||
| 1265 | BitField<35, 1, u64> ndv_flag; | 1265 | BitField<35, 1, u64> ndv_flag; |
| 1266 | BitField<49, 1, u64> nodep_flag; | 1266 | BitField<49, 1, u64> nodep_flag; |
| 1267 | BitField<50, 1, u64> dc_flag; | 1267 | BitField<50, 1, u64> dc_flag; |
| 1268 | BitField<33, 2, u64> info; | 1268 | BitField<33, 2, u64> offset_mode; |
| 1269 | BitField<37, 2, u64> component; | 1269 | BitField<37, 2, u64> component; |
| 1270 | 1270 | ||
| 1271 | bool UsesMiscMode(TextureMiscMode mode) const { | 1271 | bool UsesMiscMode(TextureMiscMode mode) const { |
| @@ -1277,9 +1277,9 @@ union Instruction { | |||
| 1277 | case TextureMiscMode::DC: | 1277 | case TextureMiscMode::DC: |
| 1278 | return dc_flag != 0; | 1278 | return dc_flag != 0; |
| 1279 | case TextureMiscMode::AOFFI: | 1279 | case TextureMiscMode::AOFFI: |
| 1280 | return info == 1; | 1280 | return offset_mode == 1; |
| 1281 | case TextureMiscMode::PTP: | 1281 | case TextureMiscMode::PTP: |
| 1282 | return info == 2; | 1282 | return offset_mode == 2; |
| 1283 | default: | 1283 | default: |
| 1284 | break; | 1284 | break; |
| 1285 | } | 1285 | } |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 0389c2143..a311dbcfe 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -48,10 +48,10 @@ class ExprDecompiler; | |||
| 48 | 48 | ||
| 49 | enum class Type { Void, Bool, Bool2, Float, Int, Uint, HalfFloat }; | 49 | enum class Type { Void, Bool, Bool2, Float, Int, Uint, HalfFloat }; |
| 50 | 50 | ||
| 51 | struct TextureAoffi {}; | 51 | struct TextureOffset {}; |
| 52 | struct TextureDerivates {}; | 52 | struct TextureDerivates {}; |
| 53 | using TextureArgument = std::pair<Type, Node>; | 53 | using TextureArgument = std::pair<Type, Node>; |
| 54 | using TextureIR = std::variant<TextureAoffi, TextureDerivates, TextureArgument>; | 54 | using TextureIR = std::variant<TextureOffset, TextureDerivates, TextureArgument>; |
| 55 | 55 | ||
| 56 | constexpr u32 MAX_CONSTBUFFER_ELEMENTS = | 56 | constexpr u32 MAX_CONSTBUFFER_ELEMENTS = |
| 57 | static_cast<u32>(Maxwell::MaxConstBufferSize) / (4 * sizeof(float)); | 57 | static_cast<u32>(Maxwell::MaxConstBufferSize) / (4 * sizeof(float)); |
| @@ -1077,7 +1077,7 @@ private: | |||
| 1077 | } | 1077 | } |
| 1078 | 1078 | ||
| 1079 | std::string GenerateTexture(Operation operation, const std::string& function_suffix, | 1079 | std::string GenerateTexture(Operation operation, const std::string& function_suffix, |
| 1080 | const std::vector<TextureIR>& extras, bool sepparate_dc = false) { | 1080 | const std::vector<TextureIR>& extras, bool separate_dc = false) { |
| 1081 | constexpr std::array coord_constructors = {"float", "vec2", "vec3", "vec4"}; | 1081 | constexpr std::array coord_constructors = {"float", "vec2", "vec3", "vec4"}; |
| 1082 | 1082 | ||
| 1083 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); | 1083 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); |
| @@ -1090,10 +1090,12 @@ private: | |||
| 1090 | std::string expr = "texture" + function_suffix; | 1090 | std::string expr = "texture" + function_suffix; |
| 1091 | if (!meta->aoffi.empty()) { | 1091 | if (!meta->aoffi.empty()) { |
| 1092 | expr += "Offset"; | 1092 | expr += "Offset"; |
| 1093 | } else if (!meta->ptp.empty()) { | ||
| 1094 | expr += "Offsets"; | ||
| 1093 | } | 1095 | } |
| 1094 | expr += '(' + GetSampler(meta->sampler) + ", "; | 1096 | expr += '(' + GetSampler(meta->sampler) + ", "; |
| 1095 | expr += coord_constructors.at(count + (has_array ? 1 : 0) + | 1097 | expr += coord_constructors.at(count + (has_array ? 1 : 0) + |
| 1096 | (has_shadow && !sepparate_dc ? 1 : 0) - 1); | 1098 | (has_shadow && !separate_dc ? 1 : 0) - 1); |
| 1097 | expr += '('; | 1099 | expr += '('; |
| 1098 | for (std::size_t i = 0; i < count; ++i) { | 1100 | for (std::size_t i = 0; i < count; ++i) { |
| 1099 | expr += Visit(operation[i]).AsFloat(); | 1101 | expr += Visit(operation[i]).AsFloat(); |
| @@ -1106,7 +1108,7 @@ private: | |||
| 1106 | expr += ", float(" + Visit(meta->array).AsInt() + ')'; | 1108 | expr += ", float(" + Visit(meta->array).AsInt() + ')'; |
| 1107 | } | 1109 | } |
| 1108 | if (has_shadow) { | 1110 | if (has_shadow) { |
| 1109 | if (sepparate_dc) { | 1111 | if (separate_dc) { |
| 1110 | expr += "), " + Visit(meta->depth_compare).AsFloat(); | 1112 | expr += "), " + Visit(meta->depth_compare).AsFloat(); |
| 1111 | } else { | 1113 | } else { |
| 1112 | expr += ", " + Visit(meta->depth_compare).AsFloat() + ')'; | 1114 | expr += ", " + Visit(meta->depth_compare).AsFloat() + ')'; |
| @@ -1118,8 +1120,12 @@ private: | |||
| 1118 | for (const auto& variant : extras) { | 1120 | for (const auto& variant : extras) { |
| 1119 | if (const auto argument = std::get_if<TextureArgument>(&variant)) { | 1121 | if (const auto argument = std::get_if<TextureArgument>(&variant)) { |
| 1120 | expr += GenerateTextureArgument(*argument); | 1122 | expr += GenerateTextureArgument(*argument); |
| 1121 | } else if (std::holds_alternative<TextureAoffi>(variant)) { | 1123 | } else if (std::holds_alternative<TextureOffset>(variant)) { |
| 1122 | expr += GenerateTextureAoffi(meta->aoffi); | 1124 | if (!meta->aoffi.empty()) { |
| 1125 | expr += GenerateTextureAoffi(meta->aoffi); | ||
| 1126 | } else if (!meta->ptp.empty()) { | ||
| 1127 | expr += GenerateTexturePtp(meta->ptp); | ||
| 1128 | } | ||
| 1123 | } else if (std::holds_alternative<TextureDerivates>(variant)) { | 1129 | } else if (std::holds_alternative<TextureDerivates>(variant)) { |
| 1124 | expr += GenerateTextureDerivates(meta->derivates); | 1130 | expr += GenerateTextureDerivates(meta->derivates); |
| 1125 | } else { | 1131 | } else { |
| @@ -1160,6 +1166,20 @@ private: | |||
| 1160 | return expr; | 1166 | return expr; |
| 1161 | } | 1167 | } |
| 1162 | 1168 | ||
| 1169 | std::string ReadTextureOffset(const Node& value) { | ||
| 1170 | if (const auto immediate = std::get_if<ImmediateNode>(&*value)) { | ||
| 1171 | // Inline the string as an immediate integer in GLSL (AOFFI arguments are required | ||
| 1172 | // to be constant by the standard). | ||
| 1173 | return std::to_string(static_cast<s32>(immediate->GetValue())); | ||
| 1174 | } else if (device.HasVariableAoffi()) { | ||
| 1175 | // Avoid using variable AOFFI on unsupported devices. | ||
| 1176 | return Visit(value).AsInt(); | ||
| 1177 | } else { | ||
| 1178 | // Insert 0 on devices not supporting variable AOFFI. | ||
| 1179 | return "0"; | ||
| 1180 | } | ||
| 1181 | } | ||
| 1182 | |||
| 1163 | std::string GenerateTextureAoffi(const std::vector<Node>& aoffi) { | 1183 | std::string GenerateTextureAoffi(const std::vector<Node>& aoffi) { |
| 1164 | if (aoffi.empty()) { | 1184 | if (aoffi.empty()) { |
| 1165 | return {}; | 1185 | return {}; |
| @@ -1170,18 +1190,7 @@ private: | |||
| 1170 | expr += '('; | 1190 | expr += '('; |
| 1171 | 1191 | ||
| 1172 | for (std::size_t index = 0; index < aoffi.size(); ++index) { | 1192 | for (std::size_t index = 0; index < aoffi.size(); ++index) { |
| 1173 | const auto operand{aoffi.at(index)}; | 1193 | expr += ReadTextureOffset(aoffi.at(index)); |
| 1174 | if (const auto immediate = std::get_if<ImmediateNode>(&*operand)) { | ||
| 1175 | // Inline the string as an immediate integer in GLSL (AOFFI arguments are required | ||
| 1176 | // to be constant by the standard). | ||
| 1177 | expr += std::to_string(static_cast<s32>(immediate->GetValue())); | ||
| 1178 | } else if (device.HasVariableAoffi()) { | ||
| 1179 | // Avoid using variable AOFFI on unsupported devices. | ||
| 1180 | expr += Visit(operand).AsInt(); | ||
| 1181 | } else { | ||
| 1182 | // Insert 0 on devices not supporting variable AOFFI. | ||
| 1183 | expr += '0'; | ||
| 1184 | } | ||
| 1185 | if (index + 1 < aoffi.size()) { | 1194 | if (index + 1 < aoffi.size()) { |
| 1186 | expr += ", "; | 1195 | expr += ", "; |
| 1187 | } | 1196 | } |
| @@ -1191,6 +1200,20 @@ private: | |||
| 1191 | return expr; | 1200 | return expr; |
| 1192 | } | 1201 | } |
| 1193 | 1202 | ||
| 1203 | std::string GenerateTexturePtp(const std::vector<Node>& ptp) { | ||
| 1204 | static constexpr std::size_t num_vectors = 4; | ||
| 1205 | ASSERT(ptp.size() == num_vectors * 2); | ||
| 1206 | |||
| 1207 | std::string expr = ", ivec2[]("; | ||
| 1208 | for (std::size_t vector = 0; vector < num_vectors; ++vector) { | ||
| 1209 | const bool has_next = vector + 1 < num_vectors; | ||
| 1210 | expr += fmt::format("ivec2({}, {}){}", ReadTextureOffset(ptp.at(vector * 2)), | ||
| 1211 | ReadTextureOffset(ptp.at(vector * 2 + 1)), has_next ? ", " : ""); | ||
| 1212 | } | ||
| 1213 | expr += ')'; | ||
| 1214 | return expr; | ||
| 1215 | } | ||
| 1216 | |||
| 1194 | std::string GenerateTextureDerivates(const std::vector<Node>& derivates) { | 1217 | std::string GenerateTextureDerivates(const std::vector<Node>& derivates) { |
| 1195 | if (derivates.empty()) { | 1218 | if (derivates.empty()) { |
| 1196 | return {}; | 1219 | return {}; |
| @@ -1689,7 +1712,7 @@ private: | |||
| 1689 | ASSERT(meta); | 1712 | ASSERT(meta); |
| 1690 | 1713 | ||
| 1691 | std::string expr = GenerateTexture( | 1714 | std::string expr = GenerateTexture( |
| 1692 | operation, "", {TextureAoffi{}, TextureArgument{Type::Float, meta->bias}}); | 1715 | operation, "", {TextureOffset{}, TextureArgument{Type::Float, meta->bias}}); |
| 1693 | if (meta->sampler.IsShadow()) { | 1716 | if (meta->sampler.IsShadow()) { |
| 1694 | expr = "vec4(" + expr + ')'; | 1717 | expr = "vec4(" + expr + ')'; |
| 1695 | } | 1718 | } |
| @@ -1701,7 +1724,7 @@ private: | |||
| 1701 | ASSERT(meta); | 1724 | ASSERT(meta); |
| 1702 | 1725 | ||
| 1703 | std::string expr = GenerateTexture( | 1726 | std::string expr = GenerateTexture( |
| 1704 | operation, "Lod", {TextureArgument{Type::Float, meta->lod}, TextureAoffi{}}); | 1727 | operation, "Lod", {TextureArgument{Type::Float, meta->lod}, TextureOffset{}}); |
| 1705 | if (meta->sampler.IsShadow()) { | 1728 | if (meta->sampler.IsShadow()) { |
| 1706 | expr = "vec4(" + expr + ')'; | 1729 | expr = "vec4(" + expr + ')'; |
| 1707 | } | 1730 | } |
| @@ -1709,21 +1732,19 @@ private: | |||
| 1709 | } | 1732 | } |
| 1710 | 1733 | ||
| 1711 | Expression TextureGather(Operation operation) { | 1734 | Expression TextureGather(Operation operation) { |
| 1712 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); | 1735 | const auto& meta = std::get<MetaTexture>(operation.GetMeta()); |
| 1713 | ASSERT(meta); | ||
| 1714 | 1736 | ||
| 1715 | const auto type = meta->sampler.IsShadow() ? Type::Float : Type::Int; | 1737 | const auto type = meta.sampler.IsShadow() ? Type::Float : Type::Int; |
| 1716 | if (meta->sampler.IsShadow()) { | 1738 | const bool separate_dc = meta.sampler.IsShadow(); |
| 1717 | return {GenerateTexture(operation, "Gather", {TextureAoffi{}}, true) + | 1739 | |
| 1718 | GetSwizzle(meta->element), | 1740 | std::vector<TextureIR> ir; |
| 1719 | Type::Float}; | 1741 | if (meta.sampler.IsShadow()) { |
| 1742 | ir = {TextureOffset{}}; | ||
| 1720 | } else { | 1743 | } else { |
| 1721 | return {GenerateTexture(operation, "Gather", | 1744 | ir = {TextureOffset{}, TextureArgument{type, meta.component}}; |
| 1722 | {TextureAoffi{}, TextureArgument{type, meta->component}}, | ||
| 1723 | false) + | ||
| 1724 | GetSwizzle(meta->element), | ||
| 1725 | Type::Float}; | ||
| 1726 | } | 1745 | } |
| 1746 | return {GenerateTexture(operation, "Gather", ir, separate_dc) + GetSwizzle(meta.element), | ||
| 1747 | Type::Float}; | ||
| 1727 | } | 1748 | } |
| 1728 | 1749 | ||
| 1729 | Expression TextureQueryDimensions(Operation operation) { | 1750 | Expression TextureQueryDimensions(Operation operation) { |
| @@ -1794,7 +1815,8 @@ private: | |||
| 1794 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); | 1815 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); |
| 1795 | ASSERT(meta); | 1816 | ASSERT(meta); |
| 1796 | 1817 | ||
| 1797 | std::string expr = GenerateTexture(operation, "Grad", {TextureDerivates{}, TextureAoffi{}}); | 1818 | std::string expr = |
| 1819 | GenerateTexture(operation, "Grad", {TextureDerivates{}, TextureOffset{}}); | ||
| 1798 | return {std::move(expr) + GetSwizzle(meta->element), Type::Float}; | 1820 | return {std::move(expr) + GetSwizzle(meta->element), Type::Float}; |
| 1799 | } | 1821 | } |
| 1800 | 1822 | ||
diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp index dff01a541..4b14cdf58 100644 --- a/src/video_core/shader/decode/texture.cpp +++ b/src/video_core/shader/decode/texture.cpp | |||
| @@ -89,59 +89,62 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { | |||
| 89 | [[fallthrough]]; | 89 | [[fallthrough]]; |
| 90 | } | 90 | } |
| 91 | case OpCode::Id::TLD4: { | 91 | case OpCode::Id::TLD4: { |
| 92 | ASSERT(instr.tld4.array == 0); | ||
| 93 | UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(TextureMiscMode::NDV), | 92 | UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(TextureMiscMode::NDV), |
| 94 | "NDV is not implemented"); | 93 | "NDV is not implemented"); |
| 95 | UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(TextureMiscMode::PTP), | ||
| 96 | "PTP is not implemented"); | ||
| 97 | |||
| 98 | const auto texture_type = instr.tld4.texture_type.Value(); | 94 | const auto texture_type = instr.tld4.texture_type.Value(); |
| 99 | const bool depth_compare = is_bindless ? instr.tld4_b.UsesMiscMode(TextureMiscMode::DC) | 95 | const bool depth_compare = is_bindless ? instr.tld4_b.UsesMiscMode(TextureMiscMode::DC) |
| 100 | : instr.tld4.UsesMiscMode(TextureMiscMode::DC); | 96 | : instr.tld4.UsesMiscMode(TextureMiscMode::DC); |
| 101 | const bool is_array = instr.tld4.array != 0; | 97 | const bool is_array = instr.tld4.array != 0; |
| 102 | const bool is_aoffi = is_bindless ? instr.tld4_b.UsesMiscMode(TextureMiscMode::AOFFI) | 98 | const bool is_aoffi = is_bindless ? instr.tld4_b.UsesMiscMode(TextureMiscMode::AOFFI) |
| 103 | : instr.tld4.UsesMiscMode(TextureMiscMode::AOFFI); | 99 | : instr.tld4.UsesMiscMode(TextureMiscMode::AOFFI); |
| 104 | WriteTexInstructionFloat( | 100 | const bool is_ptp = is_bindless ? instr.tld4_b.UsesMiscMode(TextureMiscMode::PTP) |
| 105 | bb, instr, | 101 | : instr.tld4.UsesMiscMode(TextureMiscMode::PTP); |
| 106 | GetTld4Code(instr, texture_type, depth_compare, is_array, is_aoffi, is_bindless)); | 102 | WriteTexInstructionFloat(bb, instr, |
| 103 | GetTld4Code(instr, texture_type, depth_compare, is_array, is_aoffi, | ||
| 104 | is_ptp, is_bindless)); | ||
| 107 | break; | 105 | break; |
| 108 | } | 106 | } |
| 109 | case OpCode::Id::TLD4S: { | 107 | case OpCode::Id::TLD4S: { |
| 110 | const bool uses_aoffi = instr.tld4s.UsesMiscMode(TextureMiscMode::AOFFI); | 108 | constexpr std::size_t num_coords = 2; |
| 111 | UNIMPLEMENTED_IF_MSG(uses_aoffi, "AOFFI is not implemented"); | 109 | const bool is_aoffi = instr.tld4s.UsesMiscMode(TextureMiscMode::AOFFI); |
| 112 | 110 | const bool is_depth_compare = instr.tld4s.UsesMiscMode(TextureMiscMode::DC); | |
| 113 | const bool depth_compare = instr.tld4s.UsesMiscMode(TextureMiscMode::DC); | ||
| 114 | const Node op_a = GetRegister(instr.gpr8); | 111 | const Node op_a = GetRegister(instr.gpr8); |
| 115 | const Node op_b = GetRegister(instr.gpr20); | 112 | const Node op_b = GetRegister(instr.gpr20); |
| 116 | 113 | ||
| 117 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. | 114 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. |
| 118 | std::vector<Node> coords; | 115 | std::vector<Node> coords; |
| 119 | Node dc_reg; | 116 | std::vector<Node> aoffi; |
| 120 | if (depth_compare) { | 117 | Node depth_compare; |
| 118 | if (is_depth_compare) { | ||
| 121 | // Note: TLD4S coordinate encoding works just like TEXS's | 119 | // Note: TLD4S coordinate encoding works just like TEXS's |
| 122 | const Node op_y = GetRegister(instr.gpr8.Value() + 1); | 120 | const Node op_y = GetRegister(instr.gpr8.Value() + 1); |
| 123 | coords.push_back(op_a); | 121 | coords.push_back(op_a); |
| 124 | coords.push_back(op_y); | 122 | coords.push_back(op_y); |
| 125 | dc_reg = uses_aoffi ? GetRegister(instr.gpr20.Value() + 1) : op_b; | 123 | if (is_aoffi) { |
| 124 | aoffi = GetAoffiCoordinates(op_b, num_coords, true); | ||
| 125 | depth_compare = GetRegister(instr.gpr20.Value() + 1); | ||
| 126 | } else { | ||
| 127 | depth_compare = op_b; | ||
| 128 | } | ||
| 126 | } else { | 129 | } else { |
| 130 | // There's no depth compare | ||
| 127 | coords.push_back(op_a); | 131 | coords.push_back(op_a); |
| 128 | if (uses_aoffi) { | 132 | if (is_aoffi) { |
| 129 | const Node op_y = GetRegister(instr.gpr8.Value() + 1); | 133 | coords.push_back(GetRegister(instr.gpr8.Value() + 1)); |
| 130 | coords.push_back(op_y); | 134 | aoffi = GetAoffiCoordinates(op_b, num_coords, true); |
| 131 | } else { | 135 | } else { |
| 132 | coords.push_back(op_b); | 136 | coords.push_back(op_b); |
| 133 | } | 137 | } |
| 134 | dc_reg = {}; | ||
| 135 | } | 138 | } |
| 136 | const Node component = Immediate(static_cast<u32>(instr.tld4s.component)); | 139 | const Node component = Immediate(static_cast<u32>(instr.tld4s.component)); |
| 137 | 140 | ||
| 138 | const SamplerInfo info{TextureType::Texture2D, false, depth_compare}; | 141 | const SamplerInfo info{TextureType::Texture2D, false, is_depth_compare}; |
| 139 | const Sampler& sampler = *GetSampler(instr.sampler, info); | 142 | const Sampler& sampler = *GetSampler(instr.sampler, info); |
| 140 | 143 | ||
| 141 | Node4 values; | 144 | Node4 values; |
| 142 | for (u32 element = 0; element < values.size(); ++element) { | 145 | for (u32 element = 0; element < values.size(); ++element) { |
| 143 | auto coords_copy = coords; | 146 | auto coords_copy = coords; |
| 144 | MetaTexture meta{sampler, {}, dc_reg, {}, {}, {}, {}, component, element}; | 147 | MetaTexture meta{sampler, {}, depth_compare, aoffi, {}, {}, {}, {}, component, element}; |
| 145 | values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy)); | 148 | values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy)); |
| 146 | } | 149 | } |
| 147 | 150 | ||
| @@ -190,7 +193,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { | |||
| 190 | } | 193 | } |
| 191 | 194 | ||
| 192 | for (u32 element = 0; element < values.size(); ++element) { | 195 | for (u32 element = 0; element < values.size(); ++element) { |
| 193 | MetaTexture meta{*sampler, {}, {}, {}, derivates, {}, {}, {}, element}; | 196 | MetaTexture meta{*sampler, {}, {}, {}, {}, derivates, {}, {}, {}, element}; |
| 194 | values[element] = Operation(OperationCode::TextureGradient, std::move(meta), coords); | 197 | values[element] = Operation(OperationCode::TextureGradient, std::move(meta), coords); |
| 195 | } | 198 | } |
| 196 | 199 | ||
| @@ -230,7 +233,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { | |||
| 230 | if (!instr.txq.IsComponentEnabled(element)) { | 233 | if (!instr.txq.IsComponentEnabled(element)) { |
| 231 | continue; | 234 | continue; |
| 232 | } | 235 | } |
| 233 | MetaTexture meta{*sampler, {}, {}, {}, {}, {}, {}, {}, element}; | 236 | MetaTexture meta{*sampler, {}, {}, {}, {}, {}, {}, {}, {}, element}; |
| 234 | const Node value = | 237 | const Node value = |
| 235 | Operation(OperationCode::TextureQueryDimensions, meta, | 238 | Operation(OperationCode::TextureQueryDimensions, meta, |
| 236 | GetRegister(instr.gpr8.Value() + (is_bindless ? 1 : 0))); | 239 | GetRegister(instr.gpr8.Value() + (is_bindless ? 1 : 0))); |
| @@ -299,7 +302,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { | |||
| 299 | continue; | 302 | continue; |
| 300 | } | 303 | } |
| 301 | auto params = coords; | 304 | auto params = coords; |
| 302 | MetaTexture meta{*sampler, {}, {}, {}, {}, {}, {}, {}, element}; | 305 | MetaTexture meta{*sampler, {}, {}, {}, {}, {}, {}, {}, {}, element}; |
| 303 | const Node value = Operation(OperationCode::TextureQueryLod, meta, std::move(params)); | 306 | const Node value = Operation(OperationCode::TextureQueryLod, meta, std::move(params)); |
| 304 | SetTemporary(bb, indexer++, value); | 307 | SetTemporary(bb, indexer++, value); |
| 305 | } | 308 | } |
| @@ -367,7 +370,7 @@ const Sampler* ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler, | |||
| 367 | if (it != used_samplers.end()) { | 370 | if (it != used_samplers.end()) { |
| 368 | ASSERT(!it->IsBindless() && it->GetType() == info.type && it->IsArray() == info.is_array && | 371 | ASSERT(!it->IsBindless() && it->GetType() == info.type && it->IsArray() == info.is_array && |
| 369 | it->IsShadow() == info.is_shadow && it->IsBuffer() == info.is_buffer); | 372 | it->IsShadow() == info.is_shadow && it->IsBuffer() == info.is_buffer); |
| 370 | return &(*it); | 373 | return &*it; |
| 371 | } | 374 | } |
| 372 | 375 | ||
| 373 | // Otherwise create a new mapping for this sampler | 376 | // Otherwise create a new mapping for this sampler |
| @@ -397,7 +400,7 @@ const Sampler* ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg, | |||
| 397 | if (it != used_samplers.end()) { | 400 | if (it != used_samplers.end()) { |
| 398 | ASSERT(it->IsBindless() && it->GetType() == info.type && it->IsArray() == info.is_array && | 401 | ASSERT(it->IsBindless() && it->GetType() == info.type && it->IsArray() == info.is_array && |
| 399 | it->IsShadow() == info.is_shadow); | 402 | it->IsShadow() == info.is_shadow); |
| 400 | return &(*it); | 403 | return &*it; |
| 401 | } | 404 | } |
| 402 | 405 | ||
| 403 | // Otherwise create a new mapping for this sampler | 406 | // Otherwise create a new mapping for this sampler |
| @@ -538,7 +541,7 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, | |||
| 538 | 541 | ||
| 539 | for (u32 element = 0; element < values.size(); ++element) { | 542 | for (u32 element = 0; element < values.size(); ++element) { |
| 540 | auto copy_coords = coords; | 543 | auto copy_coords = coords; |
| 541 | MetaTexture meta{*sampler, array, depth_compare, aoffi, {}, bias, lod, {}, element}; | 544 | MetaTexture meta{*sampler, array, depth_compare, aoffi, {}, {}, bias, lod, {}, element}; |
| 542 | values[element] = Operation(read_method, meta, std::move(copy_coords)); | 545 | values[element] = Operation(read_method, meta, std::move(copy_coords)); |
| 543 | } | 546 | } |
| 544 | 547 | ||
| @@ -635,7 +638,9 @@ Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, | |||
| 635 | } | 638 | } |
| 636 | 639 | ||
| 637 | Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare, | 640 | Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare, |
| 638 | bool is_array, bool is_aoffi, bool is_bindless) { | 641 | bool is_array, bool is_aoffi, bool is_ptp, bool is_bindless) { |
| 642 | ASSERT_MSG(!(is_aoffi && is_ptp), "AOFFI and PTP can't be enabled at the same time"); | ||
| 643 | |||
| 639 | const std::size_t coord_count = GetCoordCount(texture_type); | 644 | const std::size_t coord_count = GetCoordCount(texture_type); |
| 640 | 645 | ||
| 641 | // If enabled arrays index is always stored in the gpr8 field | 646 | // If enabled arrays index is always stored in the gpr8 field |
| @@ -661,12 +666,15 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de | |||
| 661 | return values; | 666 | return values; |
| 662 | } | 667 | } |
| 663 | 668 | ||
| 664 | std::vector<Node> aoffi; | 669 | std::vector<Node> aoffi, ptp; |
| 665 | if (is_aoffi) { | 670 | if (is_aoffi) { |
| 666 | aoffi = GetAoffiCoordinates(GetRegister(parameter_register++), coord_count, true); | 671 | aoffi = GetAoffiCoordinates(GetRegister(parameter_register++), coord_count, true); |
| 672 | } else if (is_ptp) { | ||
| 673 | ptp = GetPtpCoordinates( | ||
| 674 | {GetRegister(parameter_register++), GetRegister(parameter_register++)}); | ||
| 667 | } | 675 | } |
| 668 | 676 | ||
| 669 | Node dc{}; | 677 | Node dc; |
| 670 | if (depth_compare) { | 678 | if (depth_compare) { |
| 671 | dc = GetRegister(parameter_register++); | 679 | dc = GetRegister(parameter_register++); |
| 672 | } | 680 | } |
| @@ -676,8 +684,8 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de | |||
| 676 | 684 | ||
| 677 | for (u32 element = 0; element < values.size(); ++element) { | 685 | for (u32 element = 0; element < values.size(); ++element) { |
| 678 | auto coords_copy = coords; | 686 | auto coords_copy = coords; |
| 679 | MetaTexture meta{*sampler, GetRegister(array_register), dc, aoffi, {}, {}, {}, component, | 687 | MetaTexture meta{ |
| 680 | element}; | 688 | *sampler, GetRegister(array_register), dc, aoffi, ptp, {}, {}, {}, component, element}; |
| 681 | values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy)); | 689 | values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy)); |
| 682 | } | 690 | } |
| 683 | 691 | ||
| @@ -710,7 +718,7 @@ Node4 ShaderIR::GetTldCode(Tegra::Shader::Instruction instr) { | |||
| 710 | Node4 values; | 718 | Node4 values; |
| 711 | for (u32 element = 0; element < values.size(); ++element) { | 719 | for (u32 element = 0; element < values.size(); ++element) { |
| 712 | auto coords_copy = coords; | 720 | auto coords_copy = coords; |
| 713 | MetaTexture meta{sampler, array_register, {}, {}, {}, {}, lod, {}, element}; | 721 | MetaTexture meta{sampler, array_register, {}, {}, {}, {}, {}, lod, {}, element}; |
| 714 | values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy)); | 722 | values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy)); |
| 715 | } | 723 | } |
| 716 | 724 | ||
| @@ -760,7 +768,7 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is | |||
| 760 | Node4 values; | 768 | Node4 values; |
| 761 | for (u32 element = 0; element < values.size(); ++element) { | 769 | for (u32 element = 0; element < values.size(); ++element) { |
| 762 | auto coords_copy = coords; | 770 | auto coords_copy = coords; |
| 763 | MetaTexture meta{sampler, array, {}, {}, {}, {}, lod, {}, element}; | 771 | MetaTexture meta{sampler, array, {}, {}, {}, {}, {}, lod, {}, element}; |
| 764 | values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy)); | 772 | values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy)); |
| 765 | } | 773 | } |
| 766 | return values; | 774 | return values; |
| @@ -825,4 +833,38 @@ std::vector<Node> ShaderIR::GetAoffiCoordinates(Node aoffi_reg, std::size_t coor | |||
| 825 | return aoffi; | 833 | return aoffi; |
| 826 | } | 834 | } |
| 827 | 835 | ||
| 836 | std::vector<Node> ShaderIR::GetPtpCoordinates(std::array<Node, 2> ptp_regs) { | ||
| 837 | static constexpr u32 num_entries = 8; | ||
| 838 | |||
| 839 | std::vector<Node> ptp; | ||
| 840 | ptp.reserve(num_entries); | ||
| 841 | |||
| 842 | const auto global_size = static_cast<s64>(global_code.size()); | ||
| 843 | const std::optional low = TrackImmediate(ptp_regs[0], global_code, global_size); | ||
| 844 | const std::optional high = TrackImmediate(ptp_regs[1], global_code, global_size); | ||
| 845 | if (!low || !high) { | ||
| 846 | for (u32 entry = 0; entry < num_entries; ++entry) { | ||
| 847 | const u32 reg = entry / 4; | ||
| 848 | const u32 offset = entry % 4; | ||
| 849 | const Node value = BitfieldExtract(ptp_regs[reg], offset * 8, 6); | ||
| 850 | const Node condition = | ||
| 851 | Operation(OperationCode::LogicalIGreaterEqual, value, Immediate(32)); | ||
| 852 | const Node negative = Operation(OperationCode::IAdd, value, Immediate(-64)); | ||
| 853 | ptp.push_back(Operation(OperationCode::Select, condition, negative, value)); | ||
| 854 | } | ||
| 855 | return ptp; | ||
| 856 | } | ||
| 857 | |||
| 858 | const u64 immediate = (static_cast<u64>(*high) << 32) | static_cast<u64>(*low); | ||
| 859 | for (u32 entry = 0; entry < num_entries; ++entry) { | ||
| 860 | s32 value = (immediate >> (entry * 8)) & 0b111111; | ||
| 861 | if (value >= 32) { | ||
| 862 | value -= 64; | ||
| 863 | } | ||
| 864 | ptp.push_back(Immediate(value)); | ||
| 865 | } | ||
| 866 | |||
| 867 | return ptp; | ||
| 868 | } | ||
| 869 | |||
| 828 | } // namespace VideoCommon::Shader | 870 | } // namespace VideoCommon::Shader |
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h index abd40f582..4d2f4d6a8 100644 --- a/src/video_core/shader/node.h +++ b/src/video_core/shader/node.h | |||
| @@ -374,6 +374,7 @@ struct MetaTexture { | |||
| 374 | Node array; | 374 | Node array; |
| 375 | Node depth_compare; | 375 | Node depth_compare; |
| 376 | std::vector<Node> aoffi; | 376 | std::vector<Node> aoffi; |
| 377 | std::vector<Node> ptp; | ||
| 377 | std::vector<Node> derivates; | 378 | std::vector<Node> derivates; |
| 378 | Node bias; | 379 | Node bias; |
| 379 | Node lod; | 380 | Node lod; |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 04ae5f822..baed06ccd 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -350,7 +350,8 @@ private: | |||
| 350 | bool is_array); | 350 | bool is_array); |
| 351 | 351 | ||
| 352 | Node4 GetTld4Code(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, | 352 | Node4 GetTld4Code(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, |
| 353 | bool depth_compare, bool is_array, bool is_aoffi, bool is_bindless); | 353 | bool depth_compare, bool is_array, bool is_aoffi, bool is_ptp, |
| 354 | bool is_bindless); | ||
| 354 | 355 | ||
| 355 | Node4 GetTldCode(Tegra::Shader::Instruction instr); | 356 | Node4 GetTldCode(Tegra::Shader::Instruction instr); |
| 356 | 357 | ||
| @@ -363,6 +364,8 @@ private: | |||
| 363 | 364 | ||
| 364 | std::vector<Node> GetAoffiCoordinates(Node aoffi_reg, std::size_t coord_count, bool is_tld4); | 365 | std::vector<Node> GetAoffiCoordinates(Node aoffi_reg, std::size_t coord_count, bool is_tld4); |
| 365 | 366 | ||
| 367 | std::vector<Node> GetPtpCoordinates(std::array<Node, 2> ptp_regs); | ||
| 368 | |||
| 366 | Node4 GetTextureCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, | 369 | Node4 GetTextureCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, |
| 367 | Tegra::Shader::TextureProcessMode process_mode, std::vector<Node> coords, | 370 | Tegra::Shader::TextureProcessMode process_mode, std::vector<Node> coords, |
| 368 | Node array, Node depth_compare, u32 bias_offset, std::vector<Node> aoffi, | 371 | Node array, Node depth_compare, u32 bias_offset, std::vector<Node> aoffi, |