diff options
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 132 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/shader/decode/image.cpp | 66 | ||||
| -rw-r--r-- | src/video_core/shader/node.h | 46 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 9 |
7 files changed, 93 insertions, 188 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 81dfe33a5..b46fcf03d 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -544,7 +544,7 @@ enum class VoteOperation : u64 { | |||
| 544 | Eq = 2, // allThreadsEqualNV | 544 | Eq = 2, // allThreadsEqualNV |
| 545 | }; | 545 | }; |
| 546 | 546 | ||
| 547 | enum class ImageAtomicSize : u64 { | 547 | enum class ImageAtomicOperationType : u64 { |
| 548 | U32 = 0, | 548 | U32 = 0, |
| 549 | S32 = 1, | 549 | S32 = 1, |
| 550 | U64 = 2, | 550 | U64 = 2, |
| @@ -1431,7 +1431,7 @@ union Instruction { | |||
| 1431 | 1431 | ||
| 1432 | union { | 1432 | union { |
| 1433 | BitField<28, 1, u64> is_ba; | 1433 | BitField<28, 1, u64> is_ba; |
| 1434 | BitField<51, 3, ImageAtomicSize> size; | 1434 | BitField<51, 3, ImageAtomicOperationType> operation_type; |
| 1435 | BitField<33, 3, ImageType> image_type; | 1435 | BitField<33, 3, ImageType> image_type; |
| 1436 | BitField<29, 4, ImageAtomicOperation> operation; | 1436 | BitField<29, 4, ImageAtomicOperation> operation; |
| 1437 | BitField<49, 2, OutOfBoundsStore> out_of_bounds_store; | 1437 | BitField<49, 2, OutOfBoundsStore> out_of_bounds_store; |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 70ce6572b..0f3a35f74 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -716,36 +716,20 @@ private: | |||
| 716 | const char* image_type = [&] { | 716 | const char* image_type = [&] { |
| 717 | switch (image.GetType()) { | 717 | switch (image.GetType()) { |
| 718 | case Tegra::Shader::ImageType::Texture1D: | 718 | case Tegra::Shader::ImageType::Texture1D: |
| 719 | return "image1D"; | 719 | return "1D"; |
| 720 | case Tegra::Shader::ImageType::TextureBuffer: | 720 | case Tegra::Shader::ImageType::TextureBuffer: |
| 721 | return "imageBuffer"; | 721 | return "Buffer"; |
| 722 | case Tegra::Shader::ImageType::Texture1DArray: | 722 | case Tegra::Shader::ImageType::Texture1DArray: |
| 723 | return "image1DArray"; | 723 | return "1DArray"; |
| 724 | case Tegra::Shader::ImageType::Texture2D: | 724 | case Tegra::Shader::ImageType::Texture2D: |
| 725 | return "image2D"; | 725 | return "2D"; |
| 726 | case Tegra::Shader::ImageType::Texture2DArray: | 726 | case Tegra::Shader::ImageType::Texture2DArray: |
| 727 | return "image2DArray"; | 727 | return "2DArray"; |
| 728 | case Tegra::Shader::ImageType::Texture3D: | 728 | case Tegra::Shader::ImageType::Texture3D: |
| 729 | return "image3D"; | 729 | return "3D"; |
| 730 | default: | 730 | default: |
| 731 | UNREACHABLE(); | 731 | UNREACHABLE(); |
| 732 | return "image1D"; | 732 | return "1D"; |
| 733 | } | ||
| 734 | }(); | ||
| 735 | |||
| 736 | const auto [type_prefix, format] = [&]() -> std::pair<const char*, const char*> { | ||
| 737 | if (!image.IsSizeKnown()) { | ||
| 738 | return {"", ""}; | ||
| 739 | } | ||
| 740 | switch (image.GetSize()) { | ||
| 741 | case Tegra::Shader::ImageAtomicSize::U32: | ||
| 742 | return {"u", "r32ui, "}; | ||
| 743 | case Tegra::Shader::ImageAtomicSize::S32: | ||
| 744 | return {"i", "r32i, "}; | ||
| 745 | default: | ||
| 746 | UNIMPLEMENTED_MSG("Unimplemented atomic size={}", | ||
| 747 | static_cast<u32>(image.GetSize())); | ||
| 748 | return {"", ""}; | ||
| 749 | } | 733 | } |
| 750 | }(); | 734 | }(); |
| 751 | 735 | ||
| @@ -756,8 +740,12 @@ private: | |||
| 756 | qualifier += " writeonly"; | 740 | qualifier += " writeonly"; |
| 757 | } | 741 | } |
| 758 | 742 | ||
| 759 | code.AddLine("layout (binding = IMAGE_BINDING_{}) {} uniform " | 743 | std::string format; |
| 760 | "{} {};", | 744 | if (image.IsAtomic()) { |
| 745 | format = "r32ui, "; | ||
| 746 | } | ||
| 747 | |||
| 748 | code.AddLine("layout ({}binding = IMAGE_BINDING_{}) {} uniform uimage{} {};", format, | ||
| 761 | image.GetIndex(), qualifier, image_type, GetImage(image)); | 749 | image.GetIndex(), qualifier, image_type, GetImage(image)); |
| 762 | } | 750 | } |
| 763 | if (!images.empty()) { | 751 | if (!images.empty()) { |
| @@ -1225,28 +1213,13 @@ private: | |||
| 1225 | } | 1213 | } |
| 1226 | 1214 | ||
| 1227 | std::string BuildImageValues(Operation operation) { | 1215 | std::string BuildImageValues(Operation operation) { |
| 1216 | constexpr std::array constructors{"uint", "uvec2", "uvec3", "uvec4"}; | ||
| 1228 | const auto meta{std::get<MetaImage>(operation.GetMeta())}; | 1217 | const auto meta{std::get<MetaImage>(operation.GetMeta())}; |
| 1229 | const auto [constructors, type] = [&]() -> std::pair<std::array<const char*, 4>, Type> { | ||
| 1230 | constexpr std::array float_constructors{"float", "vec2", "vec3", "vec4"}; | ||
| 1231 | if (!meta.image.IsSizeKnown()) { | ||
| 1232 | return {float_constructors, Type::Float}; | ||
| 1233 | } | ||
| 1234 | switch (meta.image.GetSize()) { | ||
| 1235 | case Tegra::Shader::ImageAtomicSize::U32: | ||
| 1236 | return {{"uint", "uvec2", "uvec3", "uvec4"}, Type::Uint}; | ||
| 1237 | case Tegra::Shader::ImageAtomicSize::S32: | ||
| 1238 | return {{"int", "ivec2", "ivec3", "ivec4"}, Type::Uint}; | ||
| 1239 | default: | ||
| 1240 | UNIMPLEMENTED_MSG("Unimplemented image size={}", | ||
| 1241 | static_cast<u32>(meta.image.GetSize())); | ||
| 1242 | return {float_constructors, Type::Float}; | ||
| 1243 | } | ||
| 1244 | }(); | ||
| 1245 | 1218 | ||
| 1246 | const std::size_t values_count{meta.values.size()}; | 1219 | const std::size_t values_count{meta.values.size()}; |
| 1247 | std::string expr = fmt::format("{}(", constructors.at(values_count - 1)); | 1220 | std::string expr = fmt::format("{}(", constructors.at(values_count - 1)); |
| 1248 | for (std::size_t i = 0; i < values_count; ++i) { | 1221 | for (std::size_t i = 0; i < values_count; ++i) { |
| 1249 | expr += Visit(meta.values.at(i)).As(type); | 1222 | expr += Visit(meta.values.at(i)).AsUint(); |
| 1250 | if (i + 1 < values_count) { | 1223 | if (i + 1 < values_count) { |
| 1251 | expr += ", "; | 1224 | expr += ", "; |
| 1252 | } | 1225 | } |
| @@ -1255,29 +1228,6 @@ private: | |||
| 1255 | return expr; | 1228 | return expr; |
| 1256 | } | 1229 | } |
| 1257 | 1230 | ||
| 1258 | Expression AtomicImage(Operation operation, const char* opname) { | ||
| 1259 | constexpr std::array constructors{"int(", "ivec2(", "ivec3(", "ivec4("}; | ||
| 1260 | const auto meta{std::get<MetaImage>(operation.GetMeta())}; | ||
| 1261 | ASSERT(meta.values.size() == 1); | ||
| 1262 | ASSERT(meta.image.IsSizeKnown()); | ||
| 1263 | |||
| 1264 | const auto type = [&]() { | ||
| 1265 | switch (const auto size = meta.image.GetSize()) { | ||
| 1266 | case Tegra::Shader::ImageAtomicSize::U32: | ||
| 1267 | return Type::Uint; | ||
| 1268 | case Tegra::Shader::ImageAtomicSize::S32: | ||
| 1269 | return Type::Int; | ||
| 1270 | default: | ||
| 1271 | UNIMPLEMENTED_MSG("Unimplemented image size={}", static_cast<u32>(size)); | ||
| 1272 | return Type::Uint; | ||
| 1273 | } | ||
| 1274 | }(); | ||
| 1275 | |||
| 1276 | return {fmt::format("{}({}, {}, {})", opname, GetImage(meta.image), | ||
| 1277 | BuildIntegerCoordinates(operation), Visit(meta.values[0]).As(type)), | ||
| 1278 | type}; | ||
| 1279 | } | ||
| 1280 | |||
| 1281 | Expression Assign(Operation operation) { | 1231 | Expression Assign(Operation operation) { |
| 1282 | const Node& dest = operation[0]; | 1232 | const Node& dest = operation[0]; |
| 1283 | const Node& src = operation[1]; | 1233 | const Node& src = operation[1]; |
| @@ -1810,7 +1760,7 @@ private: | |||
| 1810 | const auto meta{std::get<MetaImage>(operation.GetMeta())}; | 1760 | const auto meta{std::get<MetaImage>(operation.GetMeta())}; |
| 1811 | return {fmt::format("imageLoad({}, {}){}", GetImage(meta.image), | 1761 | return {fmt::format("imageLoad({}, {}){}", GetImage(meta.image), |
| 1812 | BuildIntegerCoordinates(operation), GetSwizzle(meta.element)), | 1762 | BuildIntegerCoordinates(operation), GetSwizzle(meta.element)), |
| 1813 | Type::Float}; | 1763 | Type::Uint}; |
| 1814 | } | 1764 | } |
| 1815 | 1765 | ||
| 1816 | Expression ImageStore(Operation operation) { | 1766 | Expression ImageStore(Operation operation) { |
| @@ -1820,31 +1770,14 @@ private: | |||
| 1820 | return {}; | 1770 | return {}; |
| 1821 | } | 1771 | } |
| 1822 | 1772 | ||
| 1823 | Expression AtomicImageAdd(Operation operation) { | 1773 | template <const std::string_view& opname> |
| 1824 | return AtomicImage(operation, "imageAtomicAdd"); | 1774 | Expression AtomicImage(Operation operation) { |
| 1825 | } | 1775 | const auto meta{std::get<MetaImage>(operation.GetMeta())}; |
| 1826 | 1776 | ASSERT(meta.values.size() == 1); | |
| 1827 | Expression AtomicImageMin(Operation operation) { | ||
| 1828 | return AtomicImage(operation, "imageAtomicMin"); | ||
| 1829 | } | ||
| 1830 | |||
| 1831 | Expression AtomicImageMax(Operation operation) { | ||
| 1832 | return AtomicImage(operation, "imageAtomicMax"); | ||
| 1833 | } | ||
| 1834 | Expression AtomicImageAnd(Operation operation) { | ||
| 1835 | return AtomicImage(operation, "imageAtomicAnd"); | ||
| 1836 | } | ||
| 1837 | |||
| 1838 | Expression AtomicImageOr(Operation operation) { | ||
| 1839 | return AtomicImage(operation, "imageAtomicOr"); | ||
| 1840 | } | ||
| 1841 | |||
| 1842 | Expression AtomicImageXor(Operation operation) { | ||
| 1843 | return AtomicImage(operation, "imageAtomicXor"); | ||
| 1844 | } | ||
| 1845 | 1777 | ||
| 1846 | Expression AtomicImageExchange(Operation operation) { | 1778 | return {fmt::format("imageAtomic{}({}, {}, {})", opname, GetImage(meta.image), |
| 1847 | return AtomicImage(operation, "imageAtomicExchange"); | 1779 | BuildIntegerCoordinates(operation), Visit(meta.values[0]).AsUint()), |
| 1780 | Type::Uint}; | ||
| 1848 | } | 1781 | } |
| 1849 | 1782 | ||
| 1850 | Expression Branch(Operation operation) { | 1783 | Expression Branch(Operation operation) { |
| @@ -2039,6 +1972,12 @@ private: | |||
| 2039 | Func() = delete; | 1972 | Func() = delete; |
| 2040 | ~Func() = delete; | 1973 | ~Func() = delete; |
| 2041 | 1974 | ||
| 1975 | static constexpr std::string_view Add = "Add"; | ||
| 1976 | static constexpr std::string_view And = "And"; | ||
| 1977 | static constexpr std::string_view Or = "Or"; | ||
| 1978 | static constexpr std::string_view Xor = "Xor"; | ||
| 1979 | static constexpr std::string_view Exchange = "Exchange"; | ||
| 1980 | |||
| 2042 | static constexpr std::string_view ShuffleIndexed = "shuffleNV"; | 1981 | static constexpr std::string_view ShuffleIndexed = "shuffleNV"; |
| 2043 | static constexpr std::string_view ShuffleUp = "shuffleUpNV"; | 1982 | static constexpr std::string_view ShuffleUp = "shuffleUpNV"; |
| 2044 | static constexpr std::string_view ShuffleDown = "shuffleDownNV"; | 1983 | static constexpr std::string_view ShuffleDown = "shuffleDownNV"; |
| @@ -2178,13 +2117,12 @@ private: | |||
| 2178 | 2117 | ||
| 2179 | &GLSLDecompiler::ImageLoad, | 2118 | &GLSLDecompiler::ImageLoad, |
| 2180 | &GLSLDecompiler::ImageStore, | 2119 | &GLSLDecompiler::ImageStore, |
| 2181 | &GLSLDecompiler::AtomicImageAdd, | 2120 | |
| 2182 | &GLSLDecompiler::AtomicImageMin, | 2121 | &GLSLDecompiler::AtomicImage<Func::Add>, |
| 2183 | &GLSLDecompiler::AtomicImageMax, | 2122 | &GLSLDecompiler::AtomicImage<Func::And>, |
| 2184 | &GLSLDecompiler::AtomicImageAnd, | 2123 | &GLSLDecompiler::AtomicImage<Func::Or>, |
| 2185 | &GLSLDecompiler::AtomicImageOr, | 2124 | &GLSLDecompiler::AtomicImage<Func::Xor>, |
| 2186 | &GLSLDecompiler::AtomicImageXor, | 2125 | &GLSLDecompiler::AtomicImage<Func::Exchange>, |
| 2187 | &GLSLDecompiler::AtomicImageExchange, | ||
| 2188 | 2126 | ||
| 2189 | &GLSLDecompiler::Branch, | 2127 | &GLSLDecompiler::Branch, |
| 2190 | &GLSLDecompiler::BranchIndirect, | 2128 | &GLSLDecompiler::BranchIndirect, |
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp index 02b4dd234..6a7012b54 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | |||
| @@ -343,20 +343,17 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn | |||
| 343 | u8 is_bindless{}; | 343 | u8 is_bindless{}; |
| 344 | u8 is_written{}; | 344 | u8 is_written{}; |
| 345 | u8 is_read{}; | 345 | u8 is_read{}; |
| 346 | u8 is_size_known{}; | 346 | u8 is_atomic{}; |
| 347 | u32 size{}; | ||
| 348 | if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) || | 347 | if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) || |
| 349 | !LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless) || | 348 | !LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless) || |
| 350 | !LoadObjectFromPrecompiled(is_written) || !LoadObjectFromPrecompiled(is_read) || | 349 | !LoadObjectFromPrecompiled(is_written) || !LoadObjectFromPrecompiled(is_read) || |
| 351 | !LoadObjectFromPrecompiled(is_size_known) || !LoadObjectFromPrecompiled(size)) { | 350 | !LoadObjectFromPrecompiled(is_atomic)) { |
| 352 | return {}; | 351 | return {}; |
| 353 | } | 352 | } |
| 354 | entry.entries.images.emplace_back( | 353 | entry.entries.images.emplace_back( |
| 355 | static_cast<std::size_t>(offset), static_cast<std::size_t>(index), | 354 | static_cast<std::size_t>(offset), static_cast<std::size_t>(index), |
| 356 | static_cast<Tegra::Shader::ImageType>(type), is_bindless != 0, is_written != 0, | 355 | static_cast<Tegra::Shader::ImageType>(type), is_bindless != 0, is_written != 0, |
| 357 | is_read != 0, | 356 | is_read != 0, is_atomic != 0); |
| 358 | is_size_known ? std::make_optional(static_cast<Tegra::Shader::ImageAtomicSize>(size)) | ||
| 359 | : std::nullopt); | ||
| 360 | } | 357 | } |
| 361 | 358 | ||
| 362 | u32 global_memory_count{}; | 359 | u32 global_memory_count{}; |
| @@ -429,14 +426,13 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std: | |||
| 429 | return false; | 426 | return false; |
| 430 | } | 427 | } |
| 431 | for (const auto& image : entries.images) { | 428 | for (const auto& image : entries.images) { |
| 432 | const u32 size = image.IsSizeKnown() ? static_cast<u32>(image.GetSize()) : 0U; | ||
| 433 | if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) || | 429 | if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) || |
| 434 | !SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) || | 430 | !SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) || |
| 435 | !SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) || | 431 | !SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) || |
| 436 | !SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0)) || | 432 | !SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0)) || |
| 437 | !SaveObjectToPrecompiled(static_cast<u8>(image.IsWritten() ? 1 : 0)) || | 433 | !SaveObjectToPrecompiled(static_cast<u8>(image.IsWritten() ? 1 : 0)) || |
| 438 | !SaveObjectToPrecompiled(static_cast<u8>(image.IsRead() ? 1 : 0)) || | 434 | !SaveObjectToPrecompiled(static_cast<u8>(image.IsRead() ? 1 : 0)) || |
| 439 | !SaveObjectToPrecompiled(image.IsSizeKnown()) || !SaveObjectToPrecompiled(size)) { | 435 | !SaveObjectToPrecompiled(static_cast<u8>(image.IsAtomic() ? 1 : 0))) { |
| 440 | return false; | 436 | return false; |
| 441 | } | 437 | } |
| 442 | } | 438 | } |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 9d31bff43..77fc58f25 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -955,16 +955,6 @@ private: | |||
| 955 | return {}; | 955 | return {}; |
| 956 | } | 956 | } |
| 957 | 957 | ||
| 958 | Id AtomicImageMin(Operation operation) { | ||
| 959 | UNIMPLEMENTED(); | ||
| 960 | return {}; | ||
| 961 | } | ||
| 962 | |||
| 963 | Id AtomicImageMax(Operation operation) { | ||
| 964 | UNIMPLEMENTED(); | ||
| 965 | return {}; | ||
| 966 | } | ||
| 967 | |||
| 968 | Id AtomicImageAnd(Operation operation) { | 958 | Id AtomicImageAnd(Operation operation) { |
| 969 | UNIMPLEMENTED(); | 959 | UNIMPLEMENTED(); |
| 970 | return {}; | 960 | return {}; |
| @@ -1449,8 +1439,6 @@ private: | |||
| 1449 | &SPIRVDecompiler::ImageLoad, | 1439 | &SPIRVDecompiler::ImageLoad, |
| 1450 | &SPIRVDecompiler::ImageStore, | 1440 | &SPIRVDecompiler::ImageStore, |
| 1451 | &SPIRVDecompiler::AtomicImageAdd, | 1441 | &SPIRVDecompiler::AtomicImageAdd, |
| 1452 | &SPIRVDecompiler::AtomicImageMin, | ||
| 1453 | &SPIRVDecompiler::AtomicImageMax, | ||
| 1454 | &SPIRVDecompiler::AtomicImageAnd, | 1442 | &SPIRVDecompiler::AtomicImageAnd, |
| 1455 | &SPIRVDecompiler::AtomicImageOr, | 1443 | &SPIRVDecompiler::AtomicImageOr, |
| 1456 | &SPIRVDecompiler::AtomicImageXor, | 1444 | &SPIRVDecompiler::AtomicImageXor, |
diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp index e611f9f3b..95ec1cdd9 100644 --- a/src/video_core/shader/decode/image.cpp +++ b/src/video_core/shader/decode/image.cpp | |||
| @@ -101,32 +101,35 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { | |||
| 101 | UNIMPLEMENTED_IF(instr.suatom_d.is_ba != 0); | 101 | UNIMPLEMENTED_IF(instr.suatom_d.is_ba != 0); |
| 102 | 102 | ||
| 103 | const OperationCode operation_code = [instr] { | 103 | const OperationCode operation_code = [instr] { |
| 104 | switch (instr.suatom_d.operation) { | 104 | switch (instr.suatom_d.operation_type) { |
| 105 | case Tegra::Shader::ImageAtomicOperation::Add: | 105 | case Tegra::Shader::ImageAtomicOperationType::S32: |
| 106 | return OperationCode::AtomicImageAdd; | 106 | case Tegra::Shader::ImageAtomicOperationType::U32: |
| 107 | case Tegra::Shader::ImageAtomicOperation::Min: | 107 | switch (instr.suatom_d.operation) { |
| 108 | return OperationCode::AtomicImageMin; | 108 | case Tegra::Shader::ImageAtomicOperation::Add: |
| 109 | case Tegra::Shader::ImageAtomicOperation::Max: | 109 | return OperationCode::AtomicImageAdd; |
| 110 | return OperationCode::AtomicImageMax; | 110 | case Tegra::Shader::ImageAtomicOperation::And: |
| 111 | case Tegra::Shader::ImageAtomicOperation::And: | 111 | return OperationCode::AtomicImageAnd; |
| 112 | return OperationCode::AtomicImageAnd; | 112 | case Tegra::Shader::ImageAtomicOperation::Or: |
| 113 | case Tegra::Shader::ImageAtomicOperation::Or: | 113 | return OperationCode::AtomicImageOr; |
| 114 | return OperationCode::AtomicImageOr; | 114 | case Tegra::Shader::ImageAtomicOperation::Xor: |
| 115 | case Tegra::Shader::ImageAtomicOperation::Xor: | 115 | return OperationCode::AtomicImageXor; |
| 116 | return OperationCode::AtomicImageXor; | 116 | case Tegra::Shader::ImageAtomicOperation::Exch: |
| 117 | case Tegra::Shader::ImageAtomicOperation::Exch: | 117 | return OperationCode::AtomicImageExchange; |
| 118 | return OperationCode::AtomicImageExchange; | 118 | } |
| 119 | default: | 119 | default: |
| 120 | UNIMPLEMENTED_MSG("Unimplemented operation={}", | 120 | break; |
| 121 | static_cast<u32>(instr.suatom_d.operation.Value())); | ||
| 122 | return OperationCode::AtomicImageAdd; | ||
| 123 | } | 121 | } |
| 122 | UNIMPLEMENTED_MSG("Unimplemented operation={} type={}", | ||
| 123 | static_cast<u64>(instr.suatom_d.operation.Value()), | ||
| 124 | static_cast<u64>(instr.suatom_d.operation_type.Value())); | ||
| 125 | return OperationCode::AtomicImageAdd; | ||
| 124 | }(); | 126 | }(); |
| 125 | 127 | ||
| 126 | Node value = GetRegister(instr.gpr0); | 128 | Node value = GetRegister(instr.gpr0); |
| 127 | 129 | ||
| 128 | const auto type = instr.suatom_d.image_type; | 130 | const auto type = instr.suatom_d.image_type; |
| 129 | const auto& image{GetImage(instr.image, type, instr.suatom_d.size)}; | 131 | auto& image = GetImage(instr.image, type); |
| 132 | image.MarkAtomic(); | ||
| 130 | 133 | ||
| 131 | MetaImage meta{image, {std::move(value)}}; | 134 | MetaImage meta{image, {std::move(value)}}; |
| 132 | SetRegister(bb, instr.gpr0, Operation(operation_code, meta, GetCoordinates(type))); | 135 | SetRegister(bb, instr.gpr0, Operation(operation_code, meta, GetCoordinates(type))); |
| @@ -139,35 +142,32 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { | |||
| 139 | return pc; | 142 | return pc; |
| 140 | } | 143 | } |
| 141 | 144 | ||
| 142 | Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type, | 145 | Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) { |
| 143 | std::optional<Tegra::Shader::ImageAtomicSize> size) { | ||
| 144 | const auto offset{static_cast<std::size_t>(image.index.Value())}; | 146 | const auto offset{static_cast<std::size_t>(image.index.Value())}; |
| 145 | if (const auto image = TryUseExistingImage(offset, type, size)) { | 147 | if (const auto image = TryUseExistingImage(offset, type)) { |
| 146 | return *image; | 148 | return *image; |
| 147 | } | 149 | } |
| 148 | 150 | ||
| 149 | const std::size_t next_index{used_images.size()}; | 151 | const std::size_t next_index{used_images.size()}; |
| 150 | return used_images.emplace(offset, Image{offset, next_index, type, size}).first->second; | 152 | return used_images.emplace(offset, Image{offset, next_index, type}).first->second; |
| 151 | } | 153 | } |
| 152 | 154 | ||
| 153 | Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type, | 155 | Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type) { |
| 154 | std::optional<Tegra::Shader::ImageAtomicSize> size) { | ||
| 155 | const Node image_register{GetRegister(reg)}; | 156 | const Node image_register{GetRegister(reg)}; |
| 156 | const auto [base_image, cbuf_index, cbuf_offset]{ | 157 | const auto [base_image, cbuf_index, cbuf_offset]{ |
| 157 | TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))}; | 158 | TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))}; |
| 158 | const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)}; | 159 | const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)}; |
| 159 | 160 | ||
| 160 | if (const auto image = TryUseExistingImage(cbuf_key, type, size)) { | 161 | if (const auto image = TryUseExistingImage(cbuf_key, type)) { |
| 161 | return *image; | 162 | return *image; |
| 162 | } | 163 | } |
| 163 | 164 | ||
| 164 | const std::size_t next_index{used_images.size()}; | 165 | const std::size_t next_index{used_images.size()}; |
| 165 | return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type, size}) | 166 | return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type}) |
| 166 | .first->second; | 167 | .first->second; |
| 167 | } | 168 | } |
| 168 | 169 | ||
| 169 | Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type, | 170 | Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type) { |
| 170 | std::optional<Tegra::Shader::ImageAtomicSize> size) { | ||
| 171 | auto it = used_images.find(offset); | 171 | auto it = used_images.find(offset); |
| 172 | if (it == used_images.end()) { | 172 | if (it == used_images.end()) { |
| 173 | return nullptr; | 173 | return nullptr; |
| @@ -175,14 +175,6 @@ Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type, | |||
| 175 | auto& image = it->second; | 175 | auto& image = it->second; |
| 176 | ASSERT(image.GetType() == type); | 176 | ASSERT(image.GetType() == type); |
| 177 | 177 | ||
| 178 | if (size) { | ||
| 179 | // We know the size, if it's known it has to be the same as before, otherwise we can set it. | ||
| 180 | if (image.IsSizeKnown()) { | ||
| 181 | ASSERT(image.GetSize() == size); | ||
| 182 | } else { | ||
| 183 | image.SetSize(*size); | ||
| 184 | } | ||
| 185 | } | ||
| 186 | return ℑ | 178 | return ℑ |
| 187 | } | 179 | } |
| 188 | 180 | ||
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h index e5b75783d..338bab17c 100644 --- a/src/video_core/shader/node.h +++ b/src/video_core/shader/node.h | |||
| @@ -149,11 +149,10 @@ enum class OperationCode { | |||
| 149 | TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 | 149 | TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 |
| 150 | TexelFetch, /// (MetaTexture, int[N], int) -> float4 | 150 | TexelFetch, /// (MetaTexture, int[N], int) -> float4 |
| 151 | 151 | ||
| 152 | ImageLoad, /// (MetaImage, int[N] coords) -> void | 152 | ImageLoad, /// (MetaImage, int[N] coords) -> void |
| 153 | ImageStore, /// (MetaImage, int[N] coords) -> void | 153 | ImageStore, /// (MetaImage, int[N] coords) -> void |
| 154 | |||
| 154 | AtomicImageAdd, /// (MetaImage, int[N] coords) -> void | 155 | AtomicImageAdd, /// (MetaImage, int[N] coords) -> void |
| 155 | AtomicImageMin, /// (MetaImage, int[N] coords) -> void | ||
| 156 | AtomicImageMax, /// (MetaImage, int[N] coords) -> void | ||
| 157 | AtomicImageAnd, /// (MetaImage, int[N] coords) -> void | 156 | AtomicImageAnd, /// (MetaImage, int[N] coords) -> void |
| 158 | AtomicImageOr, /// (MetaImage, int[N] coords) -> void | 157 | AtomicImageOr, /// (MetaImage, int[N] coords) -> void |
| 159 | AtomicImageXor, /// (MetaImage, int[N] coords) -> void | 158 | AtomicImageXor, /// (MetaImage, int[N] coords) -> void |
| @@ -295,21 +294,18 @@ private: | |||
| 295 | 294 | ||
| 296 | class Image final { | 295 | class Image final { |
| 297 | public: | 296 | public: |
| 298 | constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, | 297 | constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type) |
| 299 | std::optional<Tegra::Shader::ImageAtomicSize> size) | 298 | : offset{offset}, index{index}, type{type}, is_bindless{false} {} |
| 300 | : offset{offset}, index{index}, type{type}, is_bindless{false}, size{size} {} | ||
| 301 | 299 | ||
| 302 | constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index, | 300 | constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index, |
| 303 | Tegra::Shader::ImageType type, | 301 | Tegra::Shader::ImageType type) |
| 304 | std::optional<Tegra::Shader::ImageAtomicSize> size) | ||
| 305 | : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type}, | 302 | : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type}, |
| 306 | is_bindless{true}, size{size} {} | 303 | is_bindless{true} {} |
| 307 | 304 | ||
| 308 | constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, | 305 | constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, |
| 309 | bool is_bindless, bool is_written, bool is_read, | 306 | bool is_bindless, bool is_written, bool is_read, bool is_atomic) |
| 310 | std::optional<Tegra::Shader::ImageAtomicSize> size) | ||
| 311 | : offset{offset}, index{index}, type{type}, is_bindless{is_bindless}, | 307 | : offset{offset}, index{index}, type{type}, is_bindless{is_bindless}, |
| 312 | is_written{is_written}, is_read{is_read}, size{size} {} | 308 | is_written{is_written}, is_read{is_read}, is_atomic{is_atomic} {} |
| 313 | 309 | ||
| 314 | void MarkWrite() { | 310 | void MarkWrite() { |
| 315 | is_written = true; | 311 | is_written = true; |
| @@ -319,8 +315,10 @@ public: | |||
| 319 | is_read = true; | 315 | is_read = true; |
| 320 | } | 316 | } |
| 321 | 317 | ||
| 322 | void SetSize(Tegra::Shader::ImageAtomicSize size_) { | 318 | void MarkAtomic() { |
| 323 | size = size_; | 319 | MarkWrite(); |
| 320 | MarkRead(); | ||
| 321 | is_atomic = true; | ||
| 324 | } | 322 | } |
| 325 | 323 | ||
| 326 | constexpr std::size_t GetOffset() const { | 324 | constexpr std::size_t GetOffset() const { |
| @@ -347,21 +345,17 @@ public: | |||
| 347 | return is_read; | 345 | return is_read; |
| 348 | } | 346 | } |
| 349 | 347 | ||
| 350 | constexpr std::pair<u32, u32> GetBindlessCBuf() const { | 348 | constexpr bool IsAtomic() const { |
| 351 | return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)}; | 349 | return is_atomic; |
| 352 | } | ||
| 353 | |||
| 354 | constexpr bool IsSizeKnown() const { | ||
| 355 | return size.has_value(); | ||
| 356 | } | 350 | } |
| 357 | 351 | ||
| 358 | constexpr Tegra::Shader::ImageAtomicSize GetSize() const { | 352 | constexpr std::pair<u32, u32> GetBindlessCBuf() const { |
| 359 | return size.value(); | 353 | return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)}; |
| 360 | } | 354 | } |
| 361 | 355 | ||
| 362 | constexpr bool operator<(const Image& rhs) const { | 356 | constexpr bool operator<(const Image& rhs) const { |
| 363 | return std::tie(offset, index, type, size, is_bindless) < | 357 | return std::tie(offset, index, type, is_bindless) < |
| 364 | std::tie(rhs.offset, rhs.index, rhs.type, rhs.size, rhs.is_bindless); | 358 | std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_bindless); |
| 365 | } | 359 | } |
| 366 | 360 | ||
| 367 | private: | 361 | private: |
| @@ -371,7 +365,7 @@ private: | |||
| 371 | bool is_bindless{}; | 365 | bool is_bindless{}; |
| 372 | bool is_written{}; | 366 | bool is_written{}; |
| 373 | bool is_read{}; | 367 | bool is_read{}; |
| 374 | std::optional<Tegra::Shader::ImageAtomicSize> size{}; | 368 | bool is_atomic{}; |
| 375 | }; | 369 | }; |
| 376 | 370 | ||
| 377 | struct GlobalMemoryBase { | 371 | struct GlobalMemoryBase { |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 6aed9bb84..c3e147eea 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -276,16 +276,13 @@ private: | |||
| 276 | bool is_shadow); | 276 | bool is_shadow); |
| 277 | 277 | ||
| 278 | /// Accesses an image. | 278 | /// Accesses an image. |
| 279 | Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type, | 279 | Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type); |
| 280 | std::optional<Tegra::Shader::ImageAtomicSize> size = {}); | ||
| 281 | 280 | ||
| 282 | /// Access a bindless image sampler. | 281 | /// Access a bindless image sampler. |
| 283 | Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type, | 282 | Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type); |
| 284 | std::optional<Tegra::Shader::ImageAtomicSize> size = {}); | ||
| 285 | 283 | ||
| 286 | /// Tries to access an existing image, updating it's state as needed | 284 | /// Tries to access an existing image, updating it's state as needed |
| 287 | Image* TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type, | 285 | Image* TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type); |
| 288 | std::optional<Tegra::Shader::ImageAtomicSize> size); | ||
| 289 | 286 | ||
| 290 | /// Extracts a sequence of bits from a node | 287 | /// Extracts a sequence of bits from a node |
| 291 | Node BitfieldExtract(Node value, u32 offset, u32 bits); | 288 | Node BitfieldExtract(Node value, u32 offset, u32 bits); |