summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/engines/shader_bytecode.h12
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp84
-rw-r--r--src/video_core/shader/decode/texture.cpp74
-rw-r--r--src/video_core/shader/node.h1
-rw-r--r--src/video_core/shader/shader_ir.h5
5 files changed, 120 insertions, 56 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index d6a2cc8b8..1cb0ac0c2 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 6b4b8ff67..83a6769ae 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
49enum class Type { Void, Bool, Bool2, Float, Int, Uint, HalfFloat }; 49enum class Type { Void, Bool, Bool2, Float, Int, Uint, HalfFloat };
50 50
51struct TextureAoffi {}; 51struct TextureOffset {};
52struct TextureDerivates {}; 52struct TextureDerivates {};
53using TextureArgument = std::pair<Type, Node>; 53using TextureArgument = std::pair<Type, Node>;
54using TextureIR = std::variant<TextureAoffi, TextureDerivates, TextureArgument>; 54using TextureIR = std::variant<TextureOffset, TextureDerivates, TextureArgument>;
55 55
56constexpr u32 MAX_CONSTBUFFER_ELEMENTS = 56constexpr u32 MAX_CONSTBUFFER_ELEMENTS =
57 static_cast<u32>(Maxwell::MaxConstBufferSize) / (4 * sizeof(float)); 57 static_cast<u32>(Maxwell::MaxConstBufferSize) / (4 * sizeof(float));
@@ -1089,6 +1089,8 @@ private:
1089 std::string expr = "texture" + function_suffix; 1089 std::string expr = "texture" + function_suffix;
1090 if (!meta->aoffi.empty()) { 1090 if (!meta->aoffi.empty()) {
1091 expr += "Offset"; 1091 expr += "Offset";
1092 } else if (!meta->ptp.empty()) {
1093 expr += "Offsets";
1092 } 1094 }
1093 expr += '(' + GetSampler(meta->sampler) + ", "; 1095 expr += '(' + GetSampler(meta->sampler) + ", ";
1094 expr += coord_constructors.at(count + (has_array ? 1 : 0) + 1096 expr += coord_constructors.at(count + (has_array ? 1 : 0) +
@@ -1117,8 +1119,12 @@ private:
1117 for (const auto& variant : extras) { 1119 for (const auto& variant : extras) {
1118 if (const auto argument = std::get_if<TextureArgument>(&variant)) { 1120 if (const auto argument = std::get_if<TextureArgument>(&variant)) {
1119 expr += GenerateTextureArgument(*argument); 1121 expr += GenerateTextureArgument(*argument);
1120 } else if (std::holds_alternative<TextureAoffi>(variant)) { 1122 } else if (std::holds_alternative<TextureOffset>(variant)) {
1121 expr += GenerateTextureAoffi(meta->aoffi); 1123 if (!meta->aoffi.empty()) {
1124 expr += GenerateTextureAoffi(meta->aoffi);
1125 } else if (!meta->ptp.empty()) {
1126 expr += GenerateTexturePtp(meta->ptp);
1127 }
1122 } else if (std::holds_alternative<TextureDerivates>(variant)) { 1128 } else if (std::holds_alternative<TextureDerivates>(variant)) {
1123 expr += GenerateTextureDerivates(meta->derivates); 1129 expr += GenerateTextureDerivates(meta->derivates);
1124 } else { 1130 } else {
@@ -1159,6 +1165,20 @@ private:
1159 return expr; 1165 return expr;
1160 } 1166 }
1161 1167
1168 std::string ReadTextureOffset(const Node& value) {
1169 if (const auto immediate = std::get_if<ImmediateNode>(&*value)) {
1170 // Inline the string as an immediate integer in GLSL (AOFFI arguments are required
1171 // to be constant by the standard).
1172 return std::to_string(static_cast<s32>(immediate->GetValue()));
1173 } else if (device.HasVariableAoffi()) {
1174 // Avoid using variable AOFFI on unsupported devices.
1175 return Visit(value).AsInt();
1176 } else {
1177 // Insert 0 on devices not supporting variable AOFFI.
1178 return "0";
1179 }
1180 }
1181
1162 std::string GenerateTextureAoffi(const std::vector<Node>& aoffi) { 1182 std::string GenerateTextureAoffi(const std::vector<Node>& aoffi) {
1163 if (aoffi.empty()) { 1183 if (aoffi.empty()) {
1164 return {}; 1184 return {};
@@ -1169,18 +1189,7 @@ private:
1169 expr += '('; 1189 expr += '(';
1170 1190
1171 for (std::size_t index = 0; index < aoffi.size(); ++index) { 1191 for (std::size_t index = 0; index < aoffi.size(); ++index) {
1172 const auto operand{aoffi.at(index)}; 1192 expr += ReadTextureOffset(aoffi.at(index));
1173 if (const auto immediate = std::get_if<ImmediateNode>(&*operand)) {
1174 // Inline the string as an immediate integer in GLSL (AOFFI arguments are required
1175 // to be constant by the standard).
1176 expr += std::to_string(static_cast<s32>(immediate->GetValue()));
1177 } else if (device.HasVariableAoffi()) {
1178 // Avoid using variable AOFFI on unsupported devices.
1179 expr += Visit(operand).AsInt();
1180 } else {
1181 // Insert 0 on devices not supporting variable AOFFI.
1182 expr += '0';
1183 }
1184 if (index + 1 < aoffi.size()) { 1193 if (index + 1 < aoffi.size()) {
1185 expr += ", "; 1194 expr += ", ";
1186 } 1195 }
@@ -1190,6 +1199,20 @@ private:
1190 return expr; 1199 return expr;
1191 } 1200 }
1192 1201
1202 std::string GenerateTexturePtp(const std::vector<Node>& ptp) {
1203 static constexpr std::size_t num_vectors = 4;
1204 ASSERT(ptp.size() == num_vectors * 2);
1205
1206 std::string expr = ", ivec2[](";
1207 for (std::size_t vector = 0; vector < num_vectors; ++vector) {
1208 const bool has_next = vector + 1 < num_vectors;
1209 expr += fmt::format("ivec2({}, {}){}", ReadTextureOffset(ptp.at(vector * 2)),
1210 ReadTextureOffset(ptp.at(vector * 2 + 1)), has_next ? ", " : "");
1211 }
1212 expr += ')';
1213 return expr;
1214 }
1215
1193 std::string GenerateTextureDerivates(const std::vector<Node>& derivates) { 1216 std::string GenerateTextureDerivates(const std::vector<Node>& derivates) {
1194 if (derivates.empty()) { 1217 if (derivates.empty()) {
1195 return {}; 1218 return {};
@@ -1688,7 +1711,7 @@ private:
1688 ASSERT(meta); 1711 ASSERT(meta);
1689 1712
1690 std::string expr = GenerateTexture( 1713 std::string expr = GenerateTexture(
1691 operation, "", {TextureAoffi{}, TextureArgument{Type::Float, meta->bias}}); 1714 operation, "", {TextureOffset{}, TextureArgument{Type::Float, meta->bias}});
1692 if (meta->sampler.IsShadow()) { 1715 if (meta->sampler.IsShadow()) {
1693 expr = "vec4(" + expr + ')'; 1716 expr = "vec4(" + expr + ')';
1694 } 1717 }
@@ -1700,7 +1723,7 @@ private:
1700 ASSERT(meta); 1723 ASSERT(meta);
1701 1724
1702 std::string expr = GenerateTexture( 1725 std::string expr = GenerateTexture(
1703 operation, "Lod", {TextureArgument{Type::Float, meta->lod}, TextureAoffi{}}); 1726 operation, "Lod", {TextureArgument{Type::Float, meta->lod}, TextureOffset{}});
1704 if (meta->sampler.IsShadow()) { 1727 if (meta->sampler.IsShadow()) {
1705 expr = "vec4(" + expr + ')'; 1728 expr = "vec4(" + expr + ')';
1706 } 1729 }
@@ -1708,21 +1731,19 @@ private:
1708 } 1731 }
1709 1732
1710 Expression TextureGather(Operation operation) { 1733 Expression TextureGather(Operation operation) {
1711 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1734 const auto& meta = std::get<MetaTexture>(operation.GetMeta());
1712 ASSERT(meta);
1713 1735
1714 const auto type = meta->sampler.IsShadow() ? Type::Float : Type::Int; 1736 const auto type = meta.sampler.IsShadow() ? Type::Float : Type::Int;
1715 if (meta->sampler.IsShadow()) { 1737 const bool separate_dc = meta.sampler.IsShadow();
1716 return {GenerateTexture(operation, "Gather", {TextureAoffi{}}, true) + 1738
1717 GetSwizzle(meta->element), 1739 std::vector<TextureIR> ir;
1718 Type::Float}; 1740 if (meta.sampler.IsShadow()) {
1741 ir = {TextureOffset{}};
1719 } else { 1742 } else {
1720 return {GenerateTexture(operation, "Gather", 1743 ir = {TextureOffset{}, TextureArgument{type, meta.component}};
1721 {TextureAoffi{}, TextureArgument{type, meta->component}},
1722 false) +
1723 GetSwizzle(meta->element),
1724 Type::Float};
1725 } 1744 }
1745 return {GenerateTexture(operation, "Gather", ir, separate_dc) + GetSwizzle(meta.element),
1746 Type::Float};
1726 } 1747 }
1727 1748
1728 Expression TextureQueryDimensions(Operation operation) { 1749 Expression TextureQueryDimensions(Operation operation) {
@@ -1793,7 +1814,8 @@ private:
1793 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1814 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
1794 ASSERT(meta); 1815 ASSERT(meta);
1795 1816
1796 std::string expr = GenerateTexture(operation, "Grad", {TextureDerivates{}, TextureAoffi{}}); 1817 std::string expr =
1818 GenerateTexture(operation, "Grad", {TextureDerivates{}, TextureOffset{}});
1797 return {std::move(expr) + GetSwizzle(meta->element), Type::Float}; 1819 return {std::move(expr) + GetSwizzle(meta->element), Type::Float};
1798 } 1820 }
1799 1821
diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp
index 6b6458993..dd8ff851e 100644
--- a/src/video_core/shader/decode/texture.cpp
+++ b/src/video_core/shader/decode/texture.cpp
@@ -91,18 +91,17 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
91 case OpCode::Id::TLD4: { 91 case OpCode::Id::TLD4: {
92 UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(TextureMiscMode::NDV), 92 UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(TextureMiscMode::NDV),
93 "NDV is not implemented"); 93 "NDV is not implemented");
94 UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(TextureMiscMode::PTP),
95 "PTP is not implemented");
96
97 const auto texture_type = instr.tld4.texture_type.Value(); 94 const auto texture_type = instr.tld4.texture_type.Value();
98 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)
99 : instr.tld4.UsesMiscMode(TextureMiscMode::DC); 96 : instr.tld4.UsesMiscMode(TextureMiscMode::DC);
100 const bool is_array = instr.tld4.array != 0; 97 const bool is_array = instr.tld4.array != 0;
101 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)
102 : instr.tld4.UsesMiscMode(TextureMiscMode::AOFFI); 99 : instr.tld4.UsesMiscMode(TextureMiscMode::AOFFI);
103 WriteTexInstructionFloat( 100 const bool is_ptp = is_bindless ? instr.tld4_b.UsesMiscMode(TextureMiscMode::PTP)
104 bb, instr, 101 : instr.tld4.UsesMiscMode(TextureMiscMode::PTP);
105 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));
106 break; 105 break;
107 } 106 }
108 case OpCode::Id::TLD4S: { 107 case OpCode::Id::TLD4S: {
@@ -145,7 +144,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
145 Node4 values; 144 Node4 values;
146 for (u32 element = 0; element < values.size(); ++element) { 145 for (u32 element = 0; element < values.size(); ++element) {
147 auto coords_copy = coords; 146 auto coords_copy = coords;
148 MetaTexture meta{sampler, {}, depth_compare, aoffi, {}, {}, {}, component, element}; 147 MetaTexture meta{sampler, {}, depth_compare, aoffi, {}, {}, {}, {}, component, element};
149 values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy)); 148 values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy));
150 } 149 }
151 150
@@ -194,7 +193,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
194 } 193 }
195 194
196 for (u32 element = 0; element < values.size(); ++element) { 195 for (u32 element = 0; element < values.size(); ++element) {
197 MetaTexture meta{*sampler, {}, {}, {}, derivates, {}, {}, {}, element}; 196 MetaTexture meta{*sampler, {}, {}, {}, {}, derivates, {}, {}, {}, element};
198 values[element] = Operation(OperationCode::TextureGradient, std::move(meta), coords); 197 values[element] = Operation(OperationCode::TextureGradient, std::move(meta), coords);
199 } 198 }
200 199
@@ -234,7 +233,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
234 if (!instr.txq.IsComponentEnabled(element)) { 233 if (!instr.txq.IsComponentEnabled(element)) {
235 continue; 234 continue;
236 } 235 }
237 MetaTexture meta{*sampler, {}, {}, {}, {}, {}, {}, {}, element}; 236 MetaTexture meta{*sampler, {}, {}, {}, {}, {}, {}, {}, {}, element};
238 const Node value = 237 const Node value =
239 Operation(OperationCode::TextureQueryDimensions, meta, 238 Operation(OperationCode::TextureQueryDimensions, meta,
240 GetRegister(instr.gpr8.Value() + (is_bindless ? 1 : 0))); 239 GetRegister(instr.gpr8.Value() + (is_bindless ? 1 : 0)));
@@ -303,7 +302,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
303 continue; 302 continue;
304 } 303 }
305 auto params = coords; 304 auto params = coords;
306 MetaTexture meta{*sampler, {}, {}, {}, {}, {}, {}, {}, element}; 305 MetaTexture meta{*sampler, {}, {}, {}, {}, {}, {}, {}, {}, element};
307 const Node value = Operation(OperationCode::TextureQueryLod, meta, std::move(params)); 306 const Node value = Operation(OperationCode::TextureQueryLod, meta, std::move(params));
308 SetTemporary(bb, indexer++, value); 307 SetTemporary(bb, indexer++, value);
309 } 308 }
@@ -542,7 +541,7 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
542 541
543 for (u32 element = 0; element < values.size(); ++element) { 542 for (u32 element = 0; element < values.size(); ++element) {
544 auto copy_coords = coords; 543 auto copy_coords = coords;
545 MetaTexture meta{*sampler, array, depth_compare, aoffi, {}, bias, lod, {}, element}; 544 MetaTexture meta{*sampler, array, depth_compare, aoffi, {}, {}, bias, lod, {}, element};
546 values[element] = Operation(read_method, meta, std::move(copy_coords)); 545 values[element] = Operation(read_method, meta, std::move(copy_coords));
547 } 546 }
548 547
@@ -639,7 +638,9 @@ Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type,
639} 638}
640 639
641Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare, 640Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare,
642 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
643 const std::size_t coord_count = GetCoordCount(texture_type); 644 const std::size_t coord_count = GetCoordCount(texture_type);
644 645
645 // If enabled arrays index is always stored in the gpr8 field 646 // If enabled arrays index is always stored in the gpr8 field
@@ -665,12 +666,15 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de
665 return values; 666 return values;
666 } 667 }
667 668
668 std::vector<Node> aoffi; 669 std::vector<Node> aoffi, ptp;
669 if (is_aoffi) { 670 if (is_aoffi) {
670 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++)});
671 } 675 }
672 676
673 Node dc{}; 677 Node dc;
674 if (depth_compare) { 678 if (depth_compare) {
675 dc = GetRegister(parameter_register++); 679 dc = GetRegister(parameter_register++);
676 } 680 }
@@ -680,8 +684,8 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de
680 684
681 for (u32 element = 0; element < values.size(); ++element) { 685 for (u32 element = 0; element < values.size(); ++element) {
682 auto coords_copy = coords; 686 auto coords_copy = coords;
683 MetaTexture meta{*sampler, GetRegister(array_register), dc, aoffi, {}, {}, {}, component, 687 MetaTexture meta{
684 element}; 688 *sampler, GetRegister(array_register), dc, aoffi, ptp, {}, {}, {}, component, element};
685 values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy)); 689 values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy));
686 } 690 }
687 691
@@ -714,7 +718,7 @@ Node4 ShaderIR::GetTldCode(Tegra::Shader::Instruction instr) {
714 Node4 values; 718 Node4 values;
715 for (u32 element = 0; element < values.size(); ++element) { 719 for (u32 element = 0; element < values.size(); ++element) {
716 auto coords_copy = coords; 720 auto coords_copy = coords;
717 MetaTexture meta{sampler, array_register, {}, {}, {}, {}, lod, {}, element}; 721 MetaTexture meta{sampler, array_register, {}, {}, {}, {}, {}, lod, {}, element};
718 values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy)); 722 values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy));
719 } 723 }
720 724
@@ -759,7 +763,7 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is
759 Node4 values; 763 Node4 values;
760 for (u32 element = 0; element < values.size(); ++element) { 764 for (u32 element = 0; element < values.size(); ++element) {
761 auto coords_copy = coords; 765 auto coords_copy = coords;
762 MetaTexture meta{sampler, array, {}, {}, {}, {}, lod, {}, element}; 766 MetaTexture meta{sampler, array, {}, {}, {}, {}, {}, lod, {}, element};
763 values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy)); 767 values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy));
764 } 768 }
765 return values; 769 return values;
@@ -824,4 +828,38 @@ std::vector<Node> ShaderIR::GetAoffiCoordinates(Node aoffi_reg, std::size_t coor
824 return aoffi; 828 return aoffi;
825} 829}
826 830
831std::vector<Node> ShaderIR::GetPtpCoordinates(std::array<Node, 2> ptp_regs) {
832 static constexpr u32 num_entries = 8;
833
834 std::vector<Node> ptp;
835 ptp.reserve(num_entries);
836
837 const auto global_size = static_cast<s64>(global_code.size());
838 const std::optional low = TrackImmediate(ptp_regs[0], global_code, global_size);
839 const std::optional high = TrackImmediate(ptp_regs[1], global_code, global_size);
840 if (!low || !high) {
841 for (u32 entry = 0; entry < num_entries; ++entry) {
842 const u32 reg = entry / 4;
843 const u32 offset = entry % 4;
844 const Node value = BitfieldExtract(ptp_regs[reg], offset * 8, 6);
845 const Node condition =
846 Operation(OperationCode::LogicalIGreaterEqual, value, Immediate(32));
847 const Node negative = Operation(OperationCode::IAdd, value, Immediate(-64));
848 ptp.push_back(Operation(OperationCode::Select, condition, negative, value));
849 }
850 return ptp;
851 }
852
853 const u64 immediate = (static_cast<u64>(*high) << 32) | static_cast<u64>(*low);
854 for (u32 entry = 0; entry < num_entries; ++entry) {
855 s32 value = (immediate >> (entry * 8)) & 0b111111;
856 if (value >= 32) {
857 value -= 64;
858 }
859 ptp.push_back(Immediate(value));
860 }
861
862 return ptp;
863}
864
827} // namespace VideoCommon::Shader 865} // 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,