diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/video_core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 66 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 70 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | 7 | ||||
| -rw-r--r-- | src/video_core/shader/decode.cpp | 1 | ||||
| -rw-r--r-- | src/video_core/shader/decode/image.cpp | 89 | ||||
| -rw-r--r-- | src/video_core/shader/node.h | 42 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 9 |
9 files changed, 283 insertions, 3 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 198b3fe07..8ae05137b 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -44,6 +44,7 @@ add_custom_command(OUTPUT scm_rev.cpp | |||
| 44 | "${VIDEO_CORE}/shader/decode/half_set.cpp" | 44 | "${VIDEO_CORE}/shader/decode/half_set.cpp" |
| 45 | "${VIDEO_CORE}/shader/decode/half_set_predicate.cpp" | 45 | "${VIDEO_CORE}/shader/decode/half_set_predicate.cpp" |
| 46 | "${VIDEO_CORE}/shader/decode/hfma2.cpp" | 46 | "${VIDEO_CORE}/shader/decode/hfma2.cpp" |
| 47 | "${VIDEO_CORE}/shader/decode/image.cpp" | ||
| 47 | "${VIDEO_CORE}/shader/decode/integer_set.cpp" | 48 | "${VIDEO_CORE}/shader/decode/integer_set.cpp" |
| 48 | "${VIDEO_CORE}/shader/decode/integer_set_predicate.cpp" | 49 | "${VIDEO_CORE}/shader/decode/integer_set_predicate.cpp" |
| 49 | "${VIDEO_CORE}/shader/decode/memory.cpp" | 50 | "${VIDEO_CORE}/shader/decode/memory.cpp" |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 9d43f03d2..6839abe71 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -90,6 +90,7 @@ add_library(video_core STATIC | |||
| 90 | shader/decode/conversion.cpp | 90 | shader/decode/conversion.cpp |
| 91 | shader/decode/memory.cpp | 91 | shader/decode/memory.cpp |
| 92 | shader/decode/texture.cpp | 92 | shader/decode/texture.cpp |
| 93 | shader/decode/image.cpp | ||
| 93 | shader/decode/float_set_predicate.cpp | 94 | shader/decode/float_set_predicate.cpp |
| 94 | shader/decode/integer_set_predicate.cpp | 95 | shader/decode/integer_set_predicate.cpp |
| 95 | shader/decode/half_set_predicate.cpp | 96 | shader/decode/half_set_predicate.cpp |
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 5b32e1249..54a1a04f9 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -126,6 +126,15 @@ union Sampler { | |||
| 126 | u64 value{}; | 126 | u64 value{}; |
| 127 | }; | 127 | }; |
| 128 | 128 | ||
| 129 | union Image { | ||
| 130 | Image() = default; | ||
| 131 | |||
| 132 | constexpr explicit Image(u64 value) : value{value} {} | ||
| 133 | |||
| 134 | BitField<36, 13, u64> index; | ||
| 135 | u64 value; | ||
| 136 | }; | ||
| 137 | |||
| 129 | } // namespace Tegra::Shader | 138 | } // namespace Tegra::Shader |
| 130 | 139 | ||
| 131 | namespace std { | 140 | namespace std { |
| @@ -344,6 +353,26 @@ enum class TextureMiscMode : u64 { | |||
| 344 | PTP, | 353 | PTP, |
| 345 | }; | 354 | }; |
| 346 | 355 | ||
| 356 | enum class SurfaceDataMode : u64 { | ||
| 357 | P = 0, | ||
| 358 | D_BA = 1, | ||
| 359 | }; | ||
| 360 | |||
| 361 | enum class OutOfBoundsStore : u64 { | ||
| 362 | Ignore = 0, | ||
| 363 | Clamp = 1, | ||
| 364 | Trap = 2, | ||
| 365 | }; | ||
| 366 | |||
| 367 | enum class ImageType : u64 { | ||
| 368 | Texture1D = 0, | ||
| 369 | TextureBuffer = 1, | ||
| 370 | Texture1DArray = 2, | ||
| 371 | Texture2D = 3, | ||
| 372 | Texture2DArray = 4, | ||
| 373 | Texture3D = 5, | ||
| 374 | }; | ||
| 375 | |||
| 347 | enum class IsberdMode : u64 { | 376 | enum class IsberdMode : u64 { |
| 348 | None = 0, | 377 | None = 0, |
| 349 | Patch = 1, | 378 | Patch = 1, |
| @@ -398,7 +427,7 @@ enum class LmemLoadCacheManagement : u64 { | |||
| 398 | CV = 3, | 427 | CV = 3, |
| 399 | }; | 428 | }; |
| 400 | 429 | ||
| 401 | enum class LmemStoreCacheManagement : u64 { | 430 | enum class StoreCacheManagement : u64 { |
| 402 | Default = 0, | 431 | Default = 0, |
| 403 | CG = 1, | 432 | CG = 1, |
| 404 | CS = 2, | 433 | CS = 2, |
| @@ -811,7 +840,7 @@ union Instruction { | |||
| 811 | } ld_l; | 840 | } ld_l; |
| 812 | 841 | ||
| 813 | union { | 842 | union { |
| 814 | BitField<44, 2, LmemStoreCacheManagement> cache_management; | 843 | BitField<44, 2, StoreCacheManagement> cache_management; |
| 815 | } st_l; | 844 | } st_l; |
| 816 | 845 | ||
| 817 | union { | 846 | union { |
| @@ -1295,6 +1324,35 @@ union Instruction { | |||
| 1295 | } tlds; | 1324 | } tlds; |
| 1296 | 1325 | ||
| 1297 | union { | 1326 | union { |
| 1327 | BitField<24, 2, StoreCacheManagement> cache_management; | ||
| 1328 | BitField<33, 3, ImageType> image_type; | ||
| 1329 | BitField<49, 2, OutOfBoundsStore> out_of_bounds_store; | ||
| 1330 | BitField<51, 1, u64> is_immediate; | ||
| 1331 | BitField<52, 1, SurfaceDataMode> mode; | ||
| 1332 | |||
| 1333 | BitField<20, 3, StoreType> store_data_layout; | ||
| 1334 | BitField<20, 4, u64> component_mask_selector; | ||
| 1335 | |||
| 1336 | bool IsComponentEnabled(std::size_t component) const { | ||
| 1337 | ASSERT(mode == SurfaceDataMode::P); | ||
| 1338 | constexpr u8 R = 0b0001; | ||
| 1339 | constexpr u8 G = 0b0010; | ||
| 1340 | constexpr u8 B = 0b0100; | ||
| 1341 | constexpr u8 A = 0b1000; | ||
| 1342 | constexpr std::array<u8, 16> mask = { | ||
| 1343 | 0, (R), (G), (R | G), (B), (R | B), | ||
| 1344 | (G | B), (R | G | B), (A), (R | A), (G | A), (R | G | A), | ||
| 1345 | (B | A), (R | B | A), (G | B | A), (R | G | B | A)}; | ||
| 1346 | return std::bitset<4>{mask.at(component_mask_selector)}.test(component); | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | StoreType GetStoreDataLayout() const { | ||
| 1350 | ASSERT(mode == SurfaceDataMode::D_BA); | ||
| 1351 | return store_data_layout; | ||
| 1352 | } | ||
| 1353 | } sust; | ||
| 1354 | |||
| 1355 | union { | ||
| 1298 | BitField<20, 24, u64> target; | 1356 | BitField<20, 24, u64> target; |
| 1299 | BitField<5, 1, u64> constant_buffer; | 1357 | BitField<5, 1, u64> constant_buffer; |
| 1300 | 1358 | ||
| @@ -1385,6 +1443,7 @@ union Instruction { | |||
| 1385 | 1443 | ||
| 1386 | Attribute attribute; | 1444 | Attribute attribute; |
| 1387 | Sampler sampler; | 1445 | Sampler sampler; |
| 1446 | Image image; | ||
| 1388 | 1447 | ||
| 1389 | u64 value; | 1448 | u64 value; |
| 1390 | }; | 1449 | }; |
| @@ -1428,6 +1487,7 @@ public: | |||
| 1428 | TLD4S, // Texture Load 4 with scalar / non - vec4 source / destinations | 1487 | TLD4S, // Texture Load 4 with scalar / non - vec4 source / destinations |
| 1429 | TMML_B, // Texture Mip Map Level | 1488 | TMML_B, // Texture Mip Map Level |
| 1430 | TMML, // Texture Mip Map Level | 1489 | TMML, // Texture Mip Map Level |
| 1490 | SUST, // Surface Store | ||
| 1431 | EXIT, | 1491 | EXIT, |
| 1432 | IPA, | 1492 | IPA, |
| 1433 | OUT_R, // Emit vertex/primitive | 1493 | OUT_R, // Emit vertex/primitive |
| @@ -1558,6 +1618,7 @@ public: | |||
| 1558 | Synch, | 1618 | Synch, |
| 1559 | Memory, | 1619 | Memory, |
| 1560 | Texture, | 1620 | Texture, |
| 1621 | Image, | ||
| 1561 | FloatSet, | 1622 | FloatSet, |
| 1562 | FloatSetPredicate, | 1623 | FloatSetPredicate, |
| 1563 | IntegerSet, | 1624 | IntegerSet, |
| @@ -1703,6 +1764,7 @@ private: | |||
| 1703 | INST("1101111100------", Id::TLD4S, Type::Texture, "TLD4S"), | 1764 | INST("1101111100------", Id::TLD4S, Type::Texture, "TLD4S"), |
| 1704 | INST("110111110110----", Id::TMML_B, Type::Texture, "TMML_B"), | 1765 | INST("110111110110----", Id::TMML_B, Type::Texture, "TMML_B"), |
| 1705 | INST("1101111101011---", Id::TMML, Type::Texture, "TMML"), | 1766 | INST("1101111101011---", Id::TMML, Type::Texture, "TMML"), |
| 1767 | INST("11101011001-----", Id::SUST, Type::Image, "SUST"), | ||
| 1706 | INST("11100000--------", Id::IPA, Type::Trivial, "IPA"), | 1768 | INST("11100000--------", Id::IPA, Type::Trivial, "IPA"), |
| 1707 | INST("1111101111100---", Id::OUT_R, Type::Trivial, "OUT_R"), | 1769 | INST("1111101111100---", Id::OUT_R, Type::Trivial, "OUT_R"), |
| 1708 | INST("1110111111010---", Id::ISBERD, Type::Trivial, "ISBERD"), | 1770 | INST("1110111111010---", Id::ISBERD, Type::Trivial, "ISBERD"), |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index ece386cdc..2ae2f1db2 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -180,6 +180,7 @@ public: | |||
| 180 | DeclareGlobalMemory(); | 180 | DeclareGlobalMemory(); |
| 181 | DeclareSamplers(); | 181 | DeclareSamplers(); |
| 182 | DeclarePhysicalAttributeReader(); | 182 | DeclarePhysicalAttributeReader(); |
| 183 | DeclareImages(); | ||
| 183 | 184 | ||
| 184 | code.AddLine("void execute_{}() {{", suffix); | 185 | code.AddLine("void execute_{}() {{", suffix); |
| 185 | ++code.scope; | 186 | ++code.scope; |
| @@ -531,6 +532,36 @@ private: | |||
| 531 | code.AddNewLine(); | 532 | code.AddNewLine(); |
| 532 | } | 533 | } |
| 533 | 534 | ||
| 535 | void DeclareImages() { | ||
| 536 | const auto& images{ir.GetImages()}; | ||
| 537 | for (const auto& image : images) { | ||
| 538 | const std::string image_type = [&]() { | ||
| 539 | switch (image.GetType()) { | ||
| 540 | case Tegra::Shader::ImageType::Texture1D: | ||
| 541 | return "image1D"; | ||
| 542 | case Tegra::Shader::ImageType::TextureBuffer: | ||
| 543 | return "bufferImage"; | ||
| 544 | case Tegra::Shader::ImageType::Texture1DArray: | ||
| 545 | return "image1DArray"; | ||
| 546 | case Tegra::Shader::ImageType::Texture2D: | ||
| 547 | return "image2D"; | ||
| 548 | case Tegra::Shader::ImageType::Texture2DArray: | ||
| 549 | return "image2DArray"; | ||
| 550 | case Tegra::Shader::ImageType::Texture3D: | ||
| 551 | return "image3D"; | ||
| 552 | default: | ||
| 553 | UNREACHABLE(); | ||
| 554 | return "image1D"; | ||
| 555 | } | ||
| 556 | }(); | ||
| 557 | code.AddLine("layout (binding = IMAGE_BINDING_" + std::to_string(image.GetIndex()) + | ||
| 558 | ") coherent volatile writeonly uniform " + image_type + ' ' + | ||
| 559 | GetImage(image) + ';'); | ||
| 560 | } | ||
| 561 | if (!images.empty()) | ||
| 562 | code.AddNewLine(); | ||
| 563 | } | ||
| 564 | |||
| 534 | void VisitBlock(const NodeBlock& bb) { | 565 | void VisitBlock(const NodeBlock& bb) { |
| 535 | for (const auto& node : bb) { | 566 | for (const auto& node : bb) { |
| 536 | if (const std::string expr = Visit(node); !expr.empty()) { | 567 | if (const std::string expr = Visit(node); !expr.empty()) { |
| @@ -1478,6 +1509,39 @@ private: | |||
| 1478 | return tmp; | 1509 | return tmp; |
| 1479 | } | 1510 | } |
| 1480 | 1511 | ||
| 1512 | std::string ImageStore(Operation operation) { | ||
| 1513 | constexpr std::array<const char*, 4> constructors{"int(", "ivec2(", "ivec3(", "ivec4("}; | ||
| 1514 | const auto meta{std::get<MetaImage>(operation.GetMeta())}; | ||
| 1515 | |||
| 1516 | std::string expr = "imageStore("; | ||
| 1517 | expr += GetImage(meta.image); | ||
| 1518 | expr += ", "; | ||
| 1519 | |||
| 1520 | const std::size_t coords_count{operation.GetOperandsCount()}; | ||
| 1521 | expr += constructors.at(coords_count - 1); | ||
| 1522 | for (std::size_t i = 0; i < coords_count; ++i) { | ||
| 1523 | expr += VisitOperand(operation, i, Type::Int); | ||
| 1524 | if (i + 1 < coords_count) { | ||
| 1525 | expr += ", "; | ||
| 1526 | } | ||
| 1527 | } | ||
| 1528 | expr += "), "; | ||
| 1529 | |||
| 1530 | const std::size_t values_count{meta.values.size()}; | ||
| 1531 | UNIMPLEMENTED_IF(values_count != 4); | ||
| 1532 | expr += "vec4("; | ||
| 1533 | for (std::size_t i = 0; i < values_count; ++i) { | ||
| 1534 | expr += Visit(meta.values.at(i)); | ||
| 1535 | if (i + 1 < values_count) { | ||
| 1536 | expr += ", "; | ||
| 1537 | } | ||
| 1538 | } | ||
| 1539 | expr += "));"; | ||
| 1540 | |||
| 1541 | code.AddLine(expr); | ||
| 1542 | return {}; | ||
| 1543 | } | ||
| 1544 | |||
| 1481 | std::string Branch(Operation operation) { | 1545 | std::string Branch(Operation operation) { |
| 1482 | const auto target = std::get_if<ImmediateNode>(&*operation[0]); | 1546 | const auto target = std::get_if<ImmediateNode>(&*operation[0]); |
| 1483 | UNIMPLEMENTED_IF(!target); | 1547 | UNIMPLEMENTED_IF(!target); |
| @@ -1718,6 +1782,8 @@ private: | |||
| 1718 | &GLSLDecompiler::TextureQueryLod, | 1782 | &GLSLDecompiler::TextureQueryLod, |
| 1719 | &GLSLDecompiler::TexelFetch, | 1783 | &GLSLDecompiler::TexelFetch, |
| 1720 | 1784 | ||
| 1785 | &GLSLDecompiler::ImageStore, | ||
| 1786 | |||
| 1721 | &GLSLDecompiler::Branch, | 1787 | &GLSLDecompiler::Branch, |
| 1722 | &GLSLDecompiler::PushFlowStack, | 1788 | &GLSLDecompiler::PushFlowStack, |
| 1723 | &GLSLDecompiler::PopFlowStack, | 1789 | &GLSLDecompiler::PopFlowStack, |
| @@ -1786,6 +1852,10 @@ private: | |||
| 1786 | return GetDeclarationWithSuffix(static_cast<u32>(sampler.GetIndex()), "sampler"); | 1852 | return GetDeclarationWithSuffix(static_cast<u32>(sampler.GetIndex()), "sampler"); |
| 1787 | } | 1853 | } |
| 1788 | 1854 | ||
| 1855 | std::string GetImage(const Image& image) const { | ||
| 1856 | return GetDeclarationWithSuffix(static_cast<u32>(image.GetIndex()), "image"); | ||
| 1857 | } | ||
| 1858 | |||
| 1789 | void EmitIfdefIsBuffer(const Sampler& sampler) { | 1859 | void EmitIfdefIsBuffer(const Sampler& sampler) { |
| 1790 | code.AddLine(fmt::format("#ifdef SAMPLER_{}_IS_BUFFER", sampler.GetIndex())); | 1860 | code.AddLine(fmt::format("#ifdef SAMPLER_{}_IS_BUFFER", sampler.GetIndex())); |
| 1791 | } | 1861 | } |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 33ad9764a..97ce214b1 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -935,6 +935,11 @@ private: | |||
| 935 | return {}; | 935 | return {}; |
| 936 | } | 936 | } |
| 937 | 937 | ||
| 938 | Id ImageStore(Operation operation) { | ||
| 939 | UNIMPLEMENTED(); | ||
| 940 | return {}; | ||
| 941 | } | ||
| 942 | |||
| 938 | Id Branch(Operation operation) { | 943 | Id Branch(Operation operation) { |
| 939 | const auto target = std::get_if<ImmediateNode>(&*operation[0]); | 944 | const auto target = std::get_if<ImmediateNode>(&*operation[0]); |
| 940 | UNIMPLEMENTED_IF(!target); | 945 | UNIMPLEMENTED_IF(!target); |
| @@ -1326,6 +1331,8 @@ private: | |||
| 1326 | &SPIRVDecompiler::TextureQueryLod, | 1331 | &SPIRVDecompiler::TextureQueryLod, |
| 1327 | &SPIRVDecompiler::TexelFetch, | 1332 | &SPIRVDecompiler::TexelFetch, |
| 1328 | 1333 | ||
| 1334 | &SPIRVDecompiler::ImageStore, | ||
| 1335 | |||
| 1329 | &SPIRVDecompiler::Branch, | 1336 | &SPIRVDecompiler::Branch, |
| 1330 | &SPIRVDecompiler::PushFlowStack, | 1337 | &SPIRVDecompiler::PushFlowStack, |
| 1331 | &SPIRVDecompiler::PopFlowStack, | 1338 | &SPIRVDecompiler::PopFlowStack, |
diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp index a0554c97e..2c9ff28f2 100644 --- a/src/video_core/shader/decode.cpp +++ b/src/video_core/shader/decode.cpp | |||
| @@ -169,6 +169,7 @@ u32 ShaderIR::DecodeInstr(NodeBlock& bb, u32 pc) { | |||
| 169 | {OpCode::Type::Conversion, &ShaderIR::DecodeConversion}, | 169 | {OpCode::Type::Conversion, &ShaderIR::DecodeConversion}, |
| 170 | {OpCode::Type::Memory, &ShaderIR::DecodeMemory}, | 170 | {OpCode::Type::Memory, &ShaderIR::DecodeMemory}, |
| 171 | {OpCode::Type::Texture, &ShaderIR::DecodeTexture}, | 171 | {OpCode::Type::Texture, &ShaderIR::DecodeTexture}, |
| 172 | {OpCode::Type::Image, &ShaderIR::DecodeImage}, | ||
| 172 | {OpCode::Type::FloatSetPredicate, &ShaderIR::DecodeFloatSetPredicate}, | 173 | {OpCode::Type::FloatSetPredicate, &ShaderIR::DecodeFloatSetPredicate}, |
| 173 | {OpCode::Type::IntegerSetPredicate, &ShaderIR::DecodeIntegerSetPredicate}, | 174 | {OpCode::Type::IntegerSetPredicate, &ShaderIR::DecodeIntegerSetPredicate}, |
| 174 | {OpCode::Type::HalfSetPredicate, &ShaderIR::DecodeHalfSetPredicate}, | 175 | {OpCode::Type::HalfSetPredicate, &ShaderIR::DecodeHalfSetPredicate}, |
diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp new file mode 100644 index 000000000..66fdf5714 --- /dev/null +++ b/src/video_core/shader/decode/image.cpp | |||
| @@ -0,0 +1,89 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | |||
| 7 | #include "common/assert.h" | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "video_core/engines/shader_bytecode.h" | ||
| 10 | #include "video_core/shader/shader_ir.h" | ||
| 11 | |||
| 12 | namespace VideoCommon::Shader { | ||
| 13 | |||
| 14 | using Tegra::Shader::Instruction; | ||
| 15 | using Tegra::Shader::OpCode; | ||
| 16 | |||
| 17 | namespace { | ||
| 18 | std::size_t GetImageTypeNumCoordinates(Tegra::Shader::ImageType image_type) { | ||
| 19 | switch (image_type) { | ||
| 20 | case Tegra::Shader::ImageType::Texture1D: | ||
| 21 | case Tegra::Shader::ImageType::TextureBuffer: | ||
| 22 | return 1; | ||
| 23 | case Tegra::Shader::ImageType::Texture1DArray: | ||
| 24 | case Tegra::Shader::ImageType::Texture2D: | ||
| 25 | return 2; | ||
| 26 | case Tegra::Shader::ImageType::Texture2DArray: | ||
| 27 | case Tegra::Shader::ImageType::Texture3D: | ||
| 28 | return 3; | ||
| 29 | } | ||
| 30 | UNREACHABLE(); | ||
| 31 | return 1; | ||
| 32 | } | ||
| 33 | } // Anonymous namespace | ||
| 34 | |||
| 35 | u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { | ||
| 36 | const Instruction instr = {program_code[pc]}; | ||
| 37 | const auto opcode = OpCode::Decode(instr); | ||
| 38 | |||
| 39 | switch (opcode->get().GetId()) { | ||
| 40 | case OpCode::Id::SUST: { | ||
| 41 | UNIMPLEMENTED_IF(instr.sust.mode != Tegra::Shader::SurfaceDataMode::P); | ||
| 42 | UNIMPLEMENTED_IF(instr.sust.image_type == Tegra::Shader::ImageType::TextureBuffer); | ||
| 43 | UNIMPLEMENTED_IF(instr.sust.out_of_bounds_store != Tegra::Shader::OutOfBoundsStore::Ignore); | ||
| 44 | UNIMPLEMENTED_IF(instr.sust.component_mask_selector != 0xf); // Ensure we have an RGBA store | ||
| 45 | |||
| 46 | std::vector<Node> values; | ||
| 47 | constexpr std::size_t hardcoded_size{4}; | ||
| 48 | for (std::size_t i = 0; i < hardcoded_size; ++i) { | ||
| 49 | values.push_back(GetRegister(instr.gpr0.Value() + i)); | ||
| 50 | } | ||
| 51 | |||
| 52 | std::vector<Node> coords; | ||
| 53 | const std::size_t num_coords{GetImageTypeNumCoordinates(instr.sust.image_type)}; | ||
| 54 | for (std::size_t i = 0; i < num_coords; ++i) { | ||
| 55 | coords.push_back(GetRegister(instr.gpr8.Value() + i)); | ||
| 56 | } | ||
| 57 | |||
| 58 | ASSERT(instr.sust.is_immediate); | ||
| 59 | const auto& image{GetImage(instr.image, instr.sust.image_type)}; | ||
| 60 | MetaImage meta{image, values}; | ||
| 61 | const Node store{Operation(OperationCode::ImageStore, meta, std::move(coords))}; | ||
| 62 | bb.push_back(store); | ||
| 63 | break; | ||
| 64 | } | ||
| 65 | default: | ||
| 66 | UNIMPLEMENTED_MSG("Unhandled conversion instruction: {}", opcode->get().GetName()); | ||
| 67 | } | ||
| 68 | |||
| 69 | return pc; | ||
| 70 | } | ||
| 71 | |||
| 72 | const Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) { | ||
| 73 | const auto offset{static_cast<std::size_t>(image.index.Value())}; | ||
| 74 | |||
| 75 | // If this image has already been used, return the existing mapping. | ||
| 76 | const auto itr{std::find_if(used_images.begin(), used_images.end(), | ||
| 77 | [=](const Image& entry) { return entry.GetOffset() == offset; })}; | ||
| 78 | if (itr != used_images.end()) { | ||
| 79 | ASSERT(itr->GetType() == type); | ||
| 80 | return *itr; | ||
| 81 | } | ||
| 82 | |||
| 83 | // Otherwise create a new mapping for this image. | ||
| 84 | const std::size_t next_index{used_images.size()}; | ||
| 85 | const Image entry{offset, next_index, type}; | ||
| 86 | return *used_images.emplace(entry).first; | ||
| 87 | } | ||
| 88 | |||
| 89 | } // namespace VideoCommon::Shader | ||
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h index 3cfb911bb..8b8d83ae7 100644 --- a/src/video_core/shader/node.h +++ b/src/video_core/shader/node.h | |||
| @@ -146,6 +146,8 @@ enum class OperationCode { | |||
| 146 | TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 | 146 | TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 |
| 147 | TexelFetch, /// (MetaTexture, int[N], int) -> float4 | 147 | TexelFetch, /// (MetaTexture, int[N], int) -> float4 |
| 148 | 148 | ||
| 149 | ImageStore, /// (MetaImage, float[N] coords) -> void | ||
| 150 | |||
| 149 | Branch, /// (uint branch_target) -> void | 151 | Branch, /// (uint branch_target) -> void |
| 150 | PushFlowStack, /// (uint branch_target) -> void | 152 | PushFlowStack, /// (uint branch_target) -> void |
| 151 | PopFlowStack, /// () -> void | 153 | PopFlowStack, /// () -> void |
| @@ -263,6 +265,39 @@ private: | |||
| 263 | bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not. | 265 | bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not. |
| 264 | }; | 266 | }; |
| 265 | 267 | ||
| 268 | class Image { | ||
| 269 | public: | ||
| 270 | explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type) | ||
| 271 | : offset{offset}, index{index}, type{type}, is_bindless{false} {} | ||
| 272 | |||
| 273 | std::size_t GetOffset() const { | ||
| 274 | return offset; | ||
| 275 | } | ||
| 276 | |||
| 277 | std::size_t GetIndex() const { | ||
| 278 | return index; | ||
| 279 | } | ||
| 280 | |||
| 281 | Tegra::Shader::ImageType GetType() const { | ||
| 282 | return type; | ||
| 283 | } | ||
| 284 | |||
| 285 | bool IsBindless() const { | ||
| 286 | return is_bindless; | ||
| 287 | } | ||
| 288 | |||
| 289 | bool operator<(const Image& rhs) const { | ||
| 290 | return std::tie(offset, index, type, is_bindless) < | ||
| 291 | std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_bindless); | ||
| 292 | } | ||
| 293 | |||
| 294 | private: | ||
| 295 | std::size_t offset{}; | ||
| 296 | std::size_t index{}; | ||
| 297 | Tegra::Shader::ImageType type{}; | ||
| 298 | bool is_bindless{}; | ||
| 299 | }; | ||
| 300 | |||
| 266 | struct GlobalMemoryBase { | 301 | struct GlobalMemoryBase { |
| 267 | u32 cbuf_index{}; | 302 | u32 cbuf_index{}; |
| 268 | u32 cbuf_offset{}; | 303 | u32 cbuf_offset{}; |
| @@ -289,8 +324,13 @@ struct MetaTexture { | |||
| 289 | u32 element{}; | 324 | u32 element{}; |
| 290 | }; | 325 | }; |
| 291 | 326 | ||
| 327 | struct MetaImage { | ||
| 328 | const Image& image; | ||
| 329 | std::vector<Node> values; | ||
| 330 | }; | ||
| 331 | |||
| 292 | /// Parameters that modify an operation but are not part of any particular operand | 332 | /// Parameters that modify an operation but are not part of any particular operand |
| 293 | using Meta = std::variant<MetaArithmetic, MetaTexture, MetaStackClass, Tegra::Shader::HalfType>; | 333 | using Meta = std::variant<MetaArithmetic, MetaTexture, MetaImage, MetaStackClass, Tegra::Shader::HalfType>; |
| 294 | 334 | ||
| 295 | /// Holds any kind of operation that can be done in the IR | 335 | /// Holds any kind of operation that can be done in the IR |
| 296 | class OperationNode final { | 336 | class OperationNode final { |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 1b84c0672..c7f264371 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -104,6 +104,10 @@ public: | |||
| 104 | return used_samplers; | 104 | return used_samplers; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | const std::set<Image>& GetImages() const { | ||
| 108 | return used_images; | ||
| 109 | } | ||
| 110 | |||
| 107 | const std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances>& GetClipDistances() | 111 | const std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances>& GetClipDistances() |
| 108 | const { | 112 | const { |
| 109 | return used_clip_distances; | 113 | return used_clip_distances; |
| @@ -154,6 +158,7 @@ private: | |||
| 154 | u32 DecodeConversion(NodeBlock& bb, u32 pc); | 158 | u32 DecodeConversion(NodeBlock& bb, u32 pc); |
| 155 | u32 DecodeMemory(NodeBlock& bb, u32 pc); | 159 | u32 DecodeMemory(NodeBlock& bb, u32 pc); |
| 156 | u32 DecodeTexture(NodeBlock& bb, u32 pc); | 160 | u32 DecodeTexture(NodeBlock& bb, u32 pc); |
| 161 | u32 DecodeImage(NodeBlock& bb, u32 pc); | ||
| 157 | u32 DecodeFloatSetPredicate(NodeBlock& bb, u32 pc); | 162 | u32 DecodeFloatSetPredicate(NodeBlock& bb, u32 pc); |
| 158 | u32 DecodeIntegerSetPredicate(NodeBlock& bb, u32 pc); | 163 | u32 DecodeIntegerSetPredicate(NodeBlock& bb, u32 pc); |
| 159 | u32 DecodeHalfSetPredicate(NodeBlock& bb, u32 pc); | 164 | u32 DecodeHalfSetPredicate(NodeBlock& bb, u32 pc); |
| @@ -254,6 +259,9 @@ private: | |||
| 254 | Tegra::Shader::TextureType type, bool is_array, | 259 | Tegra::Shader::TextureType type, bool is_array, |
| 255 | bool is_shadow); | 260 | bool is_shadow); |
| 256 | 261 | ||
| 262 | /// Accesses an image. | ||
| 263 | const Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type); | ||
| 264 | |||
| 257 | /// Extracts a sequence of bits from a node | 265 | /// Extracts a sequence of bits from a node |
| 258 | Node BitfieldExtract(Node value, u32 offset, u32 bits); | 266 | Node BitfieldExtract(Node value, u32 offset, u32 bits); |
| 259 | 267 | ||
| @@ -329,6 +337,7 @@ private: | |||
| 329 | std::set<Tegra::Shader::Attribute::Index> used_output_attributes; | 337 | std::set<Tegra::Shader::Attribute::Index> used_output_attributes; |
| 330 | std::map<u32, ConstBuffer> used_cbufs; | 338 | std::map<u32, ConstBuffer> used_cbufs; |
| 331 | std::set<Sampler> used_samplers; | 339 | std::set<Sampler> used_samplers; |
| 340 | std::set<Image> used_images; | ||
| 332 | std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; | 341 | std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; |
| 333 | std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory; | 342 | std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory; |
| 334 | bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes | 343 | bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes |