diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/file_util.cpp | 22 | ||||
| -rw-r--r-- | src/common/thread.cpp | 9 | ||||
| -rw-r--r-- | src/core/file_sys/romfs.cpp | 3 | ||||
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 8 | ||||
| -rw-r--r-- | src/video_core/shader/decode/image.cpp | 360 | ||||
| -rw-r--r-- | src/video_core/shader/decode/other.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.cpp | 3 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 4 | ||||
| -rw-r--r-- | src/video_core/texture_cache/surface_params.cpp | 6 | ||||
| -rw-r--r-- | src/yuzu/about_dialog.cpp | 9 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input_player.ui | 4 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 8 |
12 files changed, 408 insertions, 40 deletions
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 41167f57a..35eee0096 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <array> | 5 | #include <array> |
| 6 | #include <limits> | ||
| 6 | #include <memory> | 7 | #include <memory> |
| 7 | #include <sstream> | 8 | #include <sstream> |
| 8 | #include <unordered_map> | 9 | #include <unordered_map> |
| @@ -530,11 +531,11 @@ void CopyDir(const std::string& source_path, const std::string& dest_path) { | |||
| 530 | std::optional<std::string> GetCurrentDir() { | 531 | std::optional<std::string> GetCurrentDir() { |
| 531 | // Get the current working directory (getcwd uses malloc) | 532 | // Get the current working directory (getcwd uses malloc) |
| 532 | #ifdef _WIN32 | 533 | #ifdef _WIN32 |
| 533 | wchar_t* dir; | 534 | wchar_t* dir = _wgetcwd(nullptr, 0); |
| 534 | if (!(dir = _wgetcwd(nullptr, 0))) { | 535 | if (!dir) { |
| 535 | #else | 536 | #else |
| 536 | char* dir; | 537 | char* dir = getcwd(nullptr, 0); |
| 537 | if (!(dir = getcwd(nullptr, 0))) { | 538 | if (!dir) { |
| 538 | #endif | 539 | #endif |
| 539 | LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: {}", GetLastErrorMsg()); | 540 | LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: {}", GetLastErrorMsg()); |
| 540 | return {}; | 541 | return {}; |
| @@ -918,19 +919,22 @@ void IOFile::Swap(IOFile& other) noexcept { | |||
| 918 | 919 | ||
| 919 | bool IOFile::Open(const std::string& filename, const char openmode[], int flags) { | 920 | bool IOFile::Open(const std::string& filename, const char openmode[], int flags) { |
| 920 | Close(); | 921 | Close(); |
| 922 | bool m_good; | ||
| 921 | #ifdef _WIN32 | 923 | #ifdef _WIN32 |
| 922 | if (flags != 0) { | 924 | if (flags != 0) { |
| 923 | m_file = _wfsopen(Common::UTF8ToUTF16W(filename).c_str(), | 925 | m_file = _wfsopen(Common::UTF8ToUTF16W(filename).c_str(), |
| 924 | Common::UTF8ToUTF16W(openmode).c_str(), flags); | 926 | Common::UTF8ToUTF16W(openmode).c_str(), flags); |
| 927 | m_good = m_file != nullptr; | ||
| 925 | } else { | 928 | } else { |
| 926 | _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(), | 929 | m_good = _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(), |
| 927 | Common::UTF8ToUTF16W(openmode).c_str()); | 930 | Common::UTF8ToUTF16W(openmode).c_str()) == 0; |
| 928 | } | 931 | } |
| 929 | #else | 932 | #else |
| 930 | m_file = fopen(filename.c_str(), openmode); | 933 | m_file = std::fopen(filename.c_str(), openmode); |
| 934 | m_good = m_file != nullptr; | ||
| 931 | #endif | 935 | #endif |
| 932 | 936 | ||
| 933 | return IsOpen(); | 937 | return m_good; |
| 934 | } | 938 | } |
| 935 | 939 | ||
| 936 | bool IOFile::Close() { | 940 | bool IOFile::Close() { |
| @@ -956,7 +960,7 @@ u64 IOFile::Tell() const { | |||
| 956 | if (IsOpen()) | 960 | if (IsOpen()) |
| 957 | return ftello(m_file); | 961 | return ftello(m_file); |
| 958 | 962 | ||
| 959 | return -1; | 963 | return std::numeric_limits<u64>::max(); |
| 960 | } | 964 | } |
| 961 | 965 | ||
| 962 | bool IOFile::Flush() { | 966 | bool IOFile::Flush() { |
diff --git a/src/common/thread.cpp b/src/common/thread.cpp index fe7a420cc..0cd2d10bf 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp | |||
| @@ -28,11 +28,8 @@ namespace Common { | |||
| 28 | #ifdef _MSC_VER | 28 | #ifdef _MSC_VER |
| 29 | 29 | ||
| 30 | // Sets the debugger-visible name of the current thread. | 30 | // Sets the debugger-visible name of the current thread. |
| 31 | // Uses undocumented (actually, it is now documented) trick. | 31 | // Uses trick documented in: |
| 32 | // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp | 32 | // https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code |
| 33 | |||
| 34 | // This is implemented much nicer in upcoming msvc++, see: | ||
| 35 | // http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx | ||
| 36 | void SetCurrentThreadName(const char* name) { | 33 | void SetCurrentThreadName(const char* name) { |
| 37 | static const DWORD MS_VC_EXCEPTION = 0x406D1388; | 34 | static const DWORD MS_VC_EXCEPTION = 0x406D1388; |
| 38 | 35 | ||
| @@ -47,7 +44,7 @@ void SetCurrentThreadName(const char* name) { | |||
| 47 | 44 | ||
| 48 | info.dwType = 0x1000; | 45 | info.dwType = 0x1000; |
| 49 | info.szName = name; | 46 | info.szName = name; |
| 50 | info.dwThreadID = -1; // dwThreadID; | 47 | info.dwThreadID = std::numeric_limits<DWORD>::max(); |
| 51 | info.dwFlags = 0; | 48 | info.dwFlags = 0; |
| 52 | 49 | ||
| 53 | __try { | 50 | __try { |
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp index c909d1ce4..120032134 100644 --- a/src/core/file_sys/romfs.cpp +++ b/src/core/file_sys/romfs.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "common/string_util.h" | ||
| 8 | #include "common/swap.h" | 9 | #include "common/swap.h" |
| 9 | #include "core/file_sys/fsmitm_romfsbuild.h" | 10 | #include "core/file_sys/fsmitm_romfsbuild.h" |
| 10 | #include "core/file_sys/romfs.h" | 11 | #include "core/file_sys/romfs.h" |
| @@ -126,7 +127,7 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) { | |||
| 126 | return out->GetSubdirectories().front(); | 127 | return out->GetSubdirectories().front(); |
| 127 | 128 | ||
| 128 | while (out->GetSubdirectories().size() == 1 && out->GetFiles().empty()) { | 129 | while (out->GetSubdirectories().size() == 1 && out->GetFiles().empty()) { |
| 129 | if (out->GetSubdirectories().front()->GetName() == "data" && | 130 | if (Common::ToLower(out->GetSubdirectories().front()->GetName()) == "data" && |
| 130 | type == RomFSExtractionType::Truncated) | 131 | type == RomFSExtractionType::Truncated) |
| 131 | break; | 132 | break; |
| 132 | out = out->GetSubdirectories().front(); | 133 | out = out->GetSubdirectories().front(); |
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 930b605af..498936f0c 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -1712,6 +1712,7 @@ public: | |||
| 1712 | BRK, | 1712 | BRK, |
| 1713 | DEPBAR, | 1713 | DEPBAR, |
| 1714 | VOTE, | 1714 | VOTE, |
| 1715 | VOTE_VTG, | ||
| 1715 | SHFL, | 1716 | SHFL, |
| 1716 | FSWZADD, | 1717 | FSWZADD, |
| 1717 | BFE_C, | 1718 | BFE_C, |
| @@ -1758,6 +1759,7 @@ public: | |||
| 1758 | IPA, | 1759 | IPA, |
| 1759 | OUT_R, // Emit vertex/primitive | 1760 | OUT_R, // Emit vertex/primitive |
| 1760 | ISBERD, | 1761 | ISBERD, |
| 1762 | BAR, | ||
| 1761 | MEMBAR, | 1763 | MEMBAR, |
| 1762 | VMAD, | 1764 | VMAD, |
| 1763 | VSETP, | 1765 | VSETP, |
| @@ -1842,7 +1844,7 @@ public: | |||
| 1842 | MOV_C, | 1844 | MOV_C, |
| 1843 | MOV_R, | 1845 | MOV_R, |
| 1844 | MOV_IMM, | 1846 | MOV_IMM, |
| 1845 | MOV_SYS, | 1847 | S2R, |
| 1846 | MOV32_IMM, | 1848 | MOV32_IMM, |
| 1847 | SHL_C, | 1849 | SHL_C, |
| 1848 | SHL_R, | 1850 | SHL_R, |
| @@ -2026,6 +2028,7 @@ private: | |||
| 2026 | INST("111000110000----", Id::EXIT, Type::Flow, "EXIT"), | 2028 | INST("111000110000----", Id::EXIT, Type::Flow, "EXIT"), |
| 2027 | INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"), | 2029 | INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"), |
| 2028 | INST("0101000011011---", Id::VOTE, Type::Warp, "VOTE"), | 2030 | INST("0101000011011---", Id::VOTE, Type::Warp, "VOTE"), |
| 2031 | INST("0101000011100---", Id::VOTE_VTG, Type::Warp, "VOTE_VTG"), | ||
| 2029 | INST("1110111100010---", Id::SHFL, Type::Warp, "SHFL"), | 2032 | INST("1110111100010---", Id::SHFL, Type::Warp, "SHFL"), |
| 2030 | INST("0101000011111---", Id::FSWZADD, Type::Warp, "FSWZADD"), | 2033 | INST("0101000011111---", Id::FSWZADD, Type::Warp, "FSWZADD"), |
| 2031 | INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), | 2034 | INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), |
| @@ -2063,6 +2066,7 @@ private: | |||
| 2063 | INST("11100000--------", Id::IPA, Type::Trivial, "IPA"), | 2066 | INST("11100000--------", Id::IPA, Type::Trivial, "IPA"), |
| 2064 | INST("1111101111100---", Id::OUT_R, Type::Trivial, "OUT_R"), | 2067 | INST("1111101111100---", Id::OUT_R, Type::Trivial, "OUT_R"), |
| 2065 | INST("1110111111010---", Id::ISBERD, Type::Trivial, "ISBERD"), | 2068 | INST("1110111111010---", Id::ISBERD, Type::Trivial, "ISBERD"), |
| 2069 | INST("1111000010101---", Id::BAR, Type::Trivial, "BAR"), | ||
| 2066 | INST("1110111110011---", Id::MEMBAR, Type::Trivial, "MEMBAR"), | 2070 | INST("1110111110011---", Id::MEMBAR, Type::Trivial, "MEMBAR"), |
| 2067 | INST("01011111--------", Id::VMAD, Type::Video, "VMAD"), | 2071 | INST("01011111--------", Id::VMAD, Type::Video, "VMAD"), |
| 2068 | INST("0101000011110---", Id::VSETP, Type::Video, "VSETP"), | 2072 | INST("0101000011110---", Id::VSETP, Type::Video, "VSETP"), |
| @@ -2134,7 +2138,7 @@ private: | |||
| 2134 | INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"), | 2138 | INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"), |
| 2135 | INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"), | 2139 | INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"), |
| 2136 | INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"), | 2140 | INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"), |
| 2137 | INST("1111000011001---", Id::MOV_SYS, Type::Trivial, "MOV_SYS"), | 2141 | INST("1111000011001---", Id::S2R, Type::Trivial, "S2R"), |
| 2138 | INST("000000010000----", Id::MOV32_IMM, Type::ArithmeticImmediate, "MOV32_IMM"), | 2142 | INST("000000010000----", Id::MOV32_IMM, Type::ArithmeticImmediate, "MOV32_IMM"), |
| 2139 | INST("0100110001100---", Id::FMNMX_C, Type::Arithmetic, "FMNMX_C"), | 2143 | INST("0100110001100---", Id::FMNMX_C, Type::Arithmetic, "FMNMX_C"), |
| 2140 | INST("0101110001100---", Id::FMNMX_R, Type::Arithmetic, "FMNMX_R"), | 2144 | INST("0101110001100---", Id::FMNMX_R, Type::Arithmetic, "FMNMX_R"), |
diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp index d2fe4ec5d..0dd7a1196 100644 --- a/src/video_core/shader/decode/image.cpp +++ b/src/video_core/shader/decode/image.cpp | |||
| @@ -13,13 +13,247 @@ | |||
| 13 | #include "video_core/engines/shader_bytecode.h" | 13 | #include "video_core/engines/shader_bytecode.h" |
| 14 | #include "video_core/shader/node_helper.h" | 14 | #include "video_core/shader/node_helper.h" |
| 15 | #include "video_core/shader/shader_ir.h" | 15 | #include "video_core/shader/shader_ir.h" |
| 16 | #include "video_core/textures/texture.h" | ||
| 16 | 17 | ||
| 17 | namespace VideoCommon::Shader { | 18 | namespace VideoCommon::Shader { |
| 18 | 19 | ||
| 19 | using Tegra::Shader::Instruction; | 20 | using Tegra::Shader::Instruction; |
| 20 | using Tegra::Shader::OpCode; | 21 | using Tegra::Shader::OpCode; |
| 22 | using Tegra::Shader::PredCondition; | ||
| 23 | using Tegra::Shader::StoreType; | ||
| 24 | using Tegra::Texture::ComponentType; | ||
| 25 | using Tegra::Texture::TextureFormat; | ||
| 26 | using Tegra::Texture::TICEntry; | ||
| 21 | 27 | ||
| 22 | namespace { | 28 | namespace { |
| 29 | |||
| 30 | ComponentType GetComponentType(Tegra::Engines::SamplerDescriptor descriptor, | ||
| 31 | std::size_t component) { | ||
| 32 | const TextureFormat format{descriptor.format}; | ||
| 33 | switch (format) { | ||
| 34 | case TextureFormat::R16_G16_B16_A16: | ||
| 35 | case TextureFormat::R32_G32_B32_A32: | ||
| 36 | case TextureFormat::R32_G32_B32: | ||
| 37 | case TextureFormat::R32_G32: | ||
| 38 | case TextureFormat::R16_G16: | ||
| 39 | case TextureFormat::R32: | ||
| 40 | case TextureFormat::R16: | ||
| 41 | case TextureFormat::R8: | ||
| 42 | case TextureFormat::R1: | ||
| 43 | if (component == 0) { | ||
| 44 | return descriptor.r_type; | ||
| 45 | } | ||
| 46 | if (component == 1) { | ||
| 47 | return descriptor.g_type; | ||
| 48 | } | ||
| 49 | if (component == 2) { | ||
| 50 | return descriptor.b_type; | ||
| 51 | } | ||
| 52 | if (component == 3) { | ||
| 53 | return descriptor.a_type; | ||
| 54 | } | ||
| 55 | break; | ||
| 56 | case TextureFormat::A8R8G8B8: | ||
| 57 | if (component == 0) { | ||
| 58 | return descriptor.a_type; | ||
| 59 | } | ||
| 60 | if (component == 1) { | ||
| 61 | return descriptor.r_type; | ||
| 62 | } | ||
| 63 | if (component == 2) { | ||
| 64 | return descriptor.g_type; | ||
| 65 | } | ||
| 66 | if (component == 3) { | ||
| 67 | return descriptor.b_type; | ||
| 68 | } | ||
| 69 | break; | ||
| 70 | case TextureFormat::A2B10G10R10: | ||
| 71 | case TextureFormat::A4B4G4R4: | ||
| 72 | case TextureFormat::A5B5G5R1: | ||
| 73 | case TextureFormat::A1B5G5R5: | ||
| 74 | if (component == 0) { | ||
| 75 | return descriptor.a_type; | ||
| 76 | } | ||
| 77 | if (component == 1) { | ||
| 78 | return descriptor.b_type; | ||
| 79 | } | ||
| 80 | if (component == 2) { | ||
| 81 | return descriptor.g_type; | ||
| 82 | } | ||
| 83 | if (component == 3) { | ||
| 84 | return descriptor.r_type; | ||
| 85 | } | ||
| 86 | break; | ||
| 87 | case TextureFormat::R32_B24G8: | ||
| 88 | if (component == 0) { | ||
| 89 | return descriptor.r_type; | ||
| 90 | } | ||
| 91 | if (component == 1) { | ||
| 92 | return descriptor.b_type; | ||
| 93 | } | ||
| 94 | if (component == 2) { | ||
| 95 | return descriptor.g_type; | ||
| 96 | } | ||
| 97 | break; | ||
| 98 | case TextureFormat::B5G6R5: | ||
| 99 | case TextureFormat::B6G5R5: | ||
| 100 | if (component == 0) { | ||
| 101 | return descriptor.b_type; | ||
| 102 | } | ||
| 103 | if (component == 1) { | ||
| 104 | return descriptor.g_type; | ||
| 105 | } | ||
| 106 | if (component == 2) { | ||
| 107 | return descriptor.r_type; | ||
| 108 | } | ||
| 109 | break; | ||
| 110 | case TextureFormat::G8R24: | ||
| 111 | case TextureFormat::G24R8: | ||
| 112 | case TextureFormat::G8R8: | ||
| 113 | case TextureFormat::G4R4: | ||
| 114 | if (component == 0) { | ||
| 115 | return descriptor.g_type; | ||
| 116 | } | ||
| 117 | if (component == 1) { | ||
| 118 | return descriptor.r_type; | ||
| 119 | } | ||
| 120 | break; | ||
| 121 | } | ||
| 122 | UNIMPLEMENTED_MSG("texture format not implement={}", format); | ||
| 123 | return ComponentType::FLOAT; | ||
| 124 | } | ||
| 125 | |||
| 126 | bool IsComponentEnabled(std::size_t component_mask, std::size_t component) { | ||
| 127 | constexpr u8 R = 0b0001; | ||
| 128 | constexpr u8 G = 0b0010; | ||
| 129 | constexpr u8 B = 0b0100; | ||
| 130 | constexpr u8 A = 0b1000; | ||
| 131 | constexpr std::array<u8, 16> mask = { | ||
| 132 | 0, (R), (G), (R | G), (B), (R | B), (G | B), (R | G | B), | ||
| 133 | (A), (R | A), (G | A), (R | G | A), (B | A), (R | B | A), (G | B | A), (R | G | B | A)}; | ||
| 134 | return std::bitset<4>{mask.at(component_mask)}.test(component); | ||
| 135 | } | ||
| 136 | |||
| 137 | u32 GetComponentSize(TextureFormat format, std::size_t component) { | ||
| 138 | switch (format) { | ||
| 139 | case TextureFormat::R32_G32_B32_A32: | ||
| 140 | return 32; | ||
| 141 | case TextureFormat::R16_G16_B16_A16: | ||
| 142 | return 16; | ||
| 143 | case TextureFormat::R32_G32_B32: | ||
| 144 | return component <= 2 ? 32 : 0; | ||
| 145 | case TextureFormat::R32_G32: | ||
| 146 | return component <= 1 ? 32 : 0; | ||
| 147 | case TextureFormat::R16_G16: | ||
| 148 | return component <= 1 ? 16 : 0; | ||
| 149 | case TextureFormat::R32: | ||
| 150 | return component == 0 ? 32 : 0; | ||
| 151 | case TextureFormat::R16: | ||
| 152 | return component == 0 ? 16 : 0; | ||
| 153 | case TextureFormat::R8: | ||
| 154 | return component == 0 ? 8 : 0; | ||
| 155 | case TextureFormat::R1: | ||
| 156 | return component == 0 ? 1 : 0; | ||
| 157 | case TextureFormat::A8R8G8B8: | ||
| 158 | return 8; | ||
| 159 | case TextureFormat::A2B10G10R10: | ||
| 160 | return (component == 3 || component == 2 || component == 1) ? 10 : 2; | ||
| 161 | case TextureFormat::A4B4G4R4: | ||
| 162 | return 4; | ||
| 163 | case TextureFormat::A5B5G5R1: | ||
| 164 | return (component == 0 || component == 1 || component == 2) ? 5 : 1; | ||
| 165 | case TextureFormat::A1B5G5R5: | ||
| 166 | return (component == 1 || component == 2 || component == 3) ? 5 : 1; | ||
| 167 | case TextureFormat::R32_B24G8: | ||
| 168 | if (component == 0) { | ||
| 169 | return 32; | ||
| 170 | } | ||
| 171 | if (component == 1) { | ||
| 172 | return 24; | ||
| 173 | } | ||
| 174 | if (component == 2) { | ||
| 175 | return 8; | ||
| 176 | } | ||
| 177 | return 0; | ||
| 178 | case TextureFormat::B5G6R5: | ||
| 179 | if (component == 0 || component == 2) { | ||
| 180 | return 5; | ||
| 181 | } | ||
| 182 | if (component == 1) { | ||
| 183 | return 6; | ||
| 184 | } | ||
| 185 | return 0; | ||
| 186 | case TextureFormat::B6G5R5: | ||
| 187 | if (component == 1 || component == 2) { | ||
| 188 | return 5; | ||
| 189 | } | ||
| 190 | if (component == 0) { | ||
| 191 | return 6; | ||
| 192 | } | ||
| 193 | return 0; | ||
| 194 | case TextureFormat::G8R24: | ||
| 195 | if (component == 0) { | ||
| 196 | return 8; | ||
| 197 | } | ||
| 198 | if (component == 1) { | ||
| 199 | return 24; | ||
| 200 | } | ||
| 201 | return 0; | ||
| 202 | case TextureFormat::G24R8: | ||
| 203 | if (component == 0) { | ||
| 204 | return 8; | ||
| 205 | } | ||
| 206 | if (component == 1) { | ||
| 207 | return 24; | ||
| 208 | } | ||
| 209 | return 0; | ||
| 210 | case TextureFormat::G8R8: | ||
| 211 | return (component == 0 || component == 1) ? 8 : 0; | ||
| 212 | case TextureFormat::G4R4: | ||
| 213 | return (component == 0 || component == 1) ? 4 : 0; | ||
| 214 | default: | ||
| 215 | UNIMPLEMENTED_MSG("texture format not implement={}", format); | ||
| 216 | return 0; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | std::size_t GetImageComponentMask(TextureFormat format) { | ||
| 221 | constexpr u8 R = 0b0001; | ||
| 222 | constexpr u8 G = 0b0010; | ||
| 223 | constexpr u8 B = 0b0100; | ||
| 224 | constexpr u8 A = 0b1000; | ||
| 225 | switch (format) { | ||
| 226 | case TextureFormat::R32_G32_B32_A32: | ||
| 227 | case TextureFormat::R16_G16_B16_A16: | ||
| 228 | case TextureFormat::A8R8G8B8: | ||
| 229 | case TextureFormat::A2B10G10R10: | ||
| 230 | case TextureFormat::A4B4G4R4: | ||
| 231 | case TextureFormat::A5B5G5R1: | ||
| 232 | case TextureFormat::A1B5G5R5: | ||
| 233 | return std::size_t{R | G | B | A}; | ||
| 234 | case TextureFormat::R32_G32_B32: | ||
| 235 | case TextureFormat::R32_B24G8: | ||
| 236 | case TextureFormat::B5G6R5: | ||
| 237 | case TextureFormat::B6G5R5: | ||
| 238 | return std::size_t{R | G | B}; | ||
| 239 | case TextureFormat::R32_G32: | ||
| 240 | case TextureFormat::R16_G16: | ||
| 241 | case TextureFormat::G8R24: | ||
| 242 | case TextureFormat::G24R8: | ||
| 243 | case TextureFormat::G8R8: | ||
| 244 | case TextureFormat::G4R4: | ||
| 245 | return std::size_t{R | G}; | ||
| 246 | case TextureFormat::R32: | ||
| 247 | case TextureFormat::R16: | ||
| 248 | case TextureFormat::R8: | ||
| 249 | case TextureFormat::R1: | ||
| 250 | return std::size_t{R}; | ||
| 251 | default: | ||
| 252 | UNIMPLEMENTED_MSG("texture format not implement={}", format); | ||
| 253 | return std::size_t{R | G | B | A}; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 23 | std::size_t GetImageTypeNumCoordinates(Tegra::Shader::ImageType image_type) { | 257 | std::size_t GetImageTypeNumCoordinates(Tegra::Shader::ImageType image_type) { |
| 24 | switch (image_type) { | 258 | switch (image_type) { |
| 25 | case Tegra::Shader::ImageType::Texture1D: | 259 | case Tegra::Shader::ImageType::Texture1D: |
| @@ -37,6 +271,39 @@ std::size_t GetImageTypeNumCoordinates(Tegra::Shader::ImageType image_type) { | |||
| 37 | } | 271 | } |
| 38 | } // Anonymous namespace | 272 | } // Anonymous namespace |
| 39 | 273 | ||
| 274 | std::pair<Node, bool> ShaderIR::GetComponentValue(ComponentType component_type, u32 component_size, | ||
| 275 | Node original_value) { | ||
| 276 | switch (component_type) { | ||
| 277 | case ComponentType::SNORM: { | ||
| 278 | // range [-1.0, 1.0] | ||
| 279 | auto cnv_value = Operation(OperationCode::FMul, original_value, | ||
| 280 | Immediate(static_cast<float>(1 << component_size) / 2.f - 1.f)); | ||
| 281 | cnv_value = Operation(OperationCode::ICastFloat, std::move(cnv_value)); | ||
| 282 | return {BitfieldExtract(std::move(cnv_value), 0, component_size), true}; | ||
| 283 | } | ||
| 284 | case ComponentType::SINT: | ||
| 285 | case ComponentType::UNORM: { | ||
| 286 | bool is_signed = component_type == ComponentType::SINT; | ||
| 287 | // range [0.0, 1.0] | ||
| 288 | auto cnv_value = Operation(OperationCode::FMul, original_value, | ||
| 289 | Immediate(static_cast<float>(1 << component_size) - 1.f)); | ||
| 290 | return {SignedOperation(OperationCode::ICastFloat, is_signed, std::move(cnv_value)), | ||
| 291 | is_signed}; | ||
| 292 | } | ||
| 293 | case ComponentType::UINT: // range [0, (1 << component_size) - 1] | ||
| 294 | return {std::move(original_value), false}; | ||
| 295 | case ComponentType::FLOAT: | ||
| 296 | if (component_size == 16) { | ||
| 297 | return {Operation(OperationCode::HCastFloat, original_value), true}; | ||
| 298 | } else { | ||
| 299 | return {std::move(original_value), true}; | ||
| 300 | } | ||
| 301 | default: | ||
| 302 | UNIMPLEMENTED_MSG("Unimplement component type={}", component_type); | ||
| 303 | return {std::move(original_value), true}; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 40 | u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { | 307 | u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { |
| 41 | const Instruction instr = {program_code[pc]}; | 308 | const Instruction instr = {program_code[pc]}; |
| 42 | const auto opcode = OpCode::Decode(instr); | 309 | const auto opcode = OpCode::Decode(instr); |
| @@ -53,7 +320,6 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { | |||
| 53 | 320 | ||
| 54 | switch (opcode->get().GetId()) { | 321 | switch (opcode->get().GetId()) { |
| 55 | case OpCode::Id::SULD: { | 322 | case OpCode::Id::SULD: { |
| 56 | UNIMPLEMENTED_IF(instr.suldst.mode != Tegra::Shader::SurfaceDataMode::P); | ||
| 57 | UNIMPLEMENTED_IF(instr.suldst.out_of_bounds_store != | 323 | UNIMPLEMENTED_IF(instr.suldst.out_of_bounds_store != |
| 58 | Tegra::Shader::OutOfBoundsStore::Ignore); | 324 | Tegra::Shader::OutOfBoundsStore::Ignore); |
| 59 | 325 | ||
| @@ -62,17 +328,89 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { | |||
| 62 | : GetBindlessImage(instr.gpr39, type)}; | 328 | : GetBindlessImage(instr.gpr39, type)}; |
| 63 | image.MarkRead(); | 329 | image.MarkRead(); |
| 64 | 330 | ||
| 65 | u32 indexer = 0; | 331 | if (instr.suldst.mode == Tegra::Shader::SurfaceDataMode::P) { |
| 66 | for (u32 element = 0; element < 4; ++element) { | 332 | u32 indexer = 0; |
| 67 | if (!instr.suldst.IsComponentEnabled(element)) { | 333 | for (u32 element = 0; element < 4; ++element) { |
| 68 | continue; | 334 | if (!instr.suldst.IsComponentEnabled(element)) { |
| 335 | continue; | ||
| 336 | } | ||
| 337 | MetaImage meta{image, {}, element}; | ||
| 338 | Node value = Operation(OperationCode::ImageLoad, meta, GetCoordinates(type)); | ||
| 339 | SetTemporary(bb, indexer++, std::move(value)); | ||
| 340 | } | ||
| 341 | for (u32 i = 0; i < indexer; ++i) { | ||
| 342 | SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i)); | ||
| 343 | } | ||
| 344 | } else if (instr.suldst.mode == Tegra::Shader::SurfaceDataMode::D_BA) { | ||
| 345 | UNIMPLEMENTED_IF(instr.suldst.GetStoreDataLayout() != StoreType::Bits32 && | ||
| 346 | instr.suldst.GetStoreDataLayout() != StoreType::Bits64); | ||
| 347 | |||
| 348 | auto descriptor = [this, instr] { | ||
| 349 | std::optional<Tegra::Engines::SamplerDescriptor> descriptor; | ||
| 350 | if (instr.suldst.is_immediate) { | ||
| 351 | descriptor = | ||
| 352 | registry.ObtainBoundSampler(static_cast<u32>(instr.image.index.Value())); | ||
| 353 | } else { | ||
| 354 | const Node image_register = GetRegister(instr.gpr39); | ||
| 355 | const auto [base_image, buffer, offset] = TrackCbuf( | ||
| 356 | image_register, global_code, static_cast<s64>(global_code.size())); | ||
| 357 | descriptor = registry.ObtainBindlessSampler(buffer, offset); | ||
| 358 | } | ||
| 359 | if (!descriptor) { | ||
| 360 | UNREACHABLE_MSG("Failed to obtain image descriptor"); | ||
| 361 | } | ||
| 362 | return *descriptor; | ||
| 363 | }(); | ||
| 364 | |||
| 365 | const auto comp_mask = GetImageComponentMask(descriptor.format); | ||
| 366 | |||
| 367 | switch (instr.suldst.GetStoreDataLayout()) { | ||
| 368 | case StoreType::Bits32: | ||
| 369 | case StoreType::Bits64: { | ||
| 370 | u32 indexer = 0; | ||
| 371 | u32 shifted_counter = 0; | ||
| 372 | Node value = Immediate(0); | ||
| 373 | for (u32 element = 0; element < 4; ++element) { | ||
| 374 | if (!IsComponentEnabled(comp_mask, element)) { | ||
| 375 | continue; | ||
| 376 | } | ||
| 377 | const auto component_type = GetComponentType(descriptor, element); | ||
| 378 | const auto component_size = GetComponentSize(descriptor.format, element); | ||
| 379 | MetaImage meta{image, {}, element}; | ||
| 380 | |||
| 381 | auto [converted_value, is_signed] = GetComponentValue( | ||
| 382 | component_type, component_size, | ||
| 383 | Operation(OperationCode::ImageLoad, meta, GetCoordinates(type))); | ||
| 384 | |||
| 385 | // shift element to correct position | ||
| 386 | const auto shifted = shifted_counter; | ||
| 387 | if (shifted > 0) { | ||
| 388 | converted_value = | ||
| 389 | SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, | ||
| 390 | std::move(converted_value), Immediate(shifted)); | ||
| 391 | } | ||
| 392 | shifted_counter += component_size; | ||
| 393 | |||
| 394 | // add value into result | ||
| 395 | value = Operation(OperationCode::UBitwiseOr, value, std::move(converted_value)); | ||
| 396 | |||
| 397 | // if we shifted enough for 1 byte -> we save it into temp | ||
| 398 | if (shifted_counter >= 32) { | ||
| 399 | SetTemporary(bb, indexer++, std::move(value)); | ||
| 400 | // reset counter and value to prepare pack next byte | ||
| 401 | value = Immediate(0); | ||
| 402 | shifted_counter = 0; | ||
| 403 | } | ||
| 404 | } | ||
| 405 | for (u32 i = 0; i < indexer; ++i) { | ||
| 406 | SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i)); | ||
| 407 | } | ||
| 408 | break; | ||
| 409 | } | ||
| 410 | default: | ||
| 411 | UNREACHABLE(); | ||
| 412 | break; | ||
| 69 | } | 413 | } |
| 70 | MetaImage meta{image, {}, element}; | ||
| 71 | Node value = Operation(OperationCode::ImageLoad, meta, GetCoordinates(type)); | ||
| 72 | SetTemporary(bb, indexer++, std::move(value)); | ||
| 73 | } | ||
| 74 | for (u32 i = 0; i < indexer; ++i) { | ||
| 75 | SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i)); | ||
| 76 | } | 414 | } |
| 77 | break; | 415 | break; |
| 78 | } | 416 | } |
diff --git a/src/video_core/shader/decode/other.cpp b/src/video_core/shader/decode/other.cpp index e6edec459..d4f95b18c 100644 --- a/src/video_core/shader/decode/other.cpp +++ b/src/video_core/shader/decode/other.cpp | |||
| @@ -71,18 +71,24 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { | |||
| 71 | bb.push_back(Operation(OperationCode::Discard)); | 71 | bb.push_back(Operation(OperationCode::Discard)); |
| 72 | break; | 72 | break; |
| 73 | } | 73 | } |
| 74 | case OpCode::Id::MOV_SYS: { | 74 | case OpCode::Id::S2R: { |
| 75 | const Node value = [this, instr] { | 75 | const Node value = [this, instr] { |
| 76 | switch (instr.sys20) { | 76 | switch (instr.sys20) { |
| 77 | case SystemVariable::LaneId: | 77 | case SystemVariable::LaneId: |
| 78 | LOG_WARNING(HW_GPU, "MOV_SYS instruction with LaneId is incomplete"); | 78 | LOG_WARNING(HW_GPU, "S2R instruction with LaneId is incomplete"); |
| 79 | return Immediate(0U); | 79 | return Immediate(0U); |
| 80 | case SystemVariable::InvocationId: | 80 | case SystemVariable::InvocationId: |
| 81 | return Operation(OperationCode::InvocationId); | 81 | return Operation(OperationCode::InvocationId); |
| 82 | case SystemVariable::Ydirection: | 82 | case SystemVariable::Ydirection: |
| 83 | return Operation(OperationCode::YNegate); | 83 | return Operation(OperationCode::YNegate); |
| 84 | case SystemVariable::InvocationInfo: | 84 | case SystemVariable::InvocationInfo: |
| 85 | LOG_WARNING(HW_GPU, "MOV_SYS instruction with InvocationInfo is incomplete"); | 85 | LOG_WARNING(HW_GPU, "S2R instruction with InvocationInfo is incomplete"); |
| 86 | return Immediate(0U); | ||
| 87 | case SystemVariable::WscaleFactorXY: | ||
| 88 | UNIMPLEMENTED_MSG("S2R WscaleFactorXY is not implemented"); | ||
| 89 | return Immediate(0U); | ||
| 90 | case SystemVariable::WscaleFactorZ: | ||
| 91 | UNIMPLEMENTED_MSG("S2R WscaleFactorZ is not implemented"); | ||
| 86 | return Immediate(0U); | 92 | return Immediate(0U); |
| 87 | case SystemVariable::Tid: { | 93 | case SystemVariable::Tid: { |
| 88 | Node value = Immediate(0); | 94 | Node value = Immediate(0); |
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp index baf7188d2..8852c8a1b 100644 --- a/src/video_core/shader/shader_ir.cpp +++ b/src/video_core/shader/shader_ir.cpp | |||
| @@ -359,6 +359,9 @@ Node ShaderIR::GetConditionCode(Tegra::Shader::ConditionCode cc) const { | |||
| 359 | switch (cc) { | 359 | switch (cc) { |
| 360 | case Tegra::Shader::ConditionCode::NEU: | 360 | case Tegra::Shader::ConditionCode::NEU: |
| 361 | return GetInternalFlag(InternalFlag::Zero, true); | 361 | return GetInternalFlag(InternalFlag::Zero, true); |
| 362 | case Tegra::Shader::ConditionCode::FCSM_TR: | ||
| 363 | UNIMPLEMENTED_MSG("EXIT.FCSM_TR is not implemented"); | ||
| 364 | return MakeNode<PredicateNode>(Pred::NeverExecute, false); | ||
| 362 | default: | 365 | default: |
| 363 | UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc)); | 366 | UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc)); |
| 364 | return MakeNode<PredicateNode>(Pred::NeverExecute, false); | 367 | return MakeNode<PredicateNode>(Pred::NeverExecute, false); |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 80fc9b82c..ca6c976c9 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -312,6 +312,10 @@ private: | |||
| 312 | /// Conditionally saturates a half float pair | 312 | /// Conditionally saturates a half float pair |
| 313 | Node GetSaturatedHalfFloat(Node value, bool saturate = true); | 313 | Node GetSaturatedHalfFloat(Node value, bool saturate = true); |
| 314 | 314 | ||
| 315 | /// Get image component value by type and size | ||
| 316 | std::pair<Node, bool> GetComponentValue(Tegra::Texture::ComponentType component_type, | ||
| 317 | u32 component_size, Node original_value); | ||
| 318 | |||
| 315 | /// Returns a predicate comparing two floats | 319 | /// Returns a predicate comparing two floats |
| 316 | Node GetPredicateComparisonFloat(Tegra::Shader::PredCondition condition, Node op_a, Node op_b); | 320 | Node GetPredicateComparisonFloat(Tegra::Shader::PredCondition condition, Node op_a, Node op_b); |
| 317 | /// Returns a predicate comparing two integers | 321 | /// Returns a predicate comparing two integers |
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index 47b2aafbd..6f3ef45be 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp | |||
| @@ -113,10 +113,8 @@ SurfaceParams SurfaceParams::CreateForTexture(const FormatLookupTable& lookup_ta | |||
| 113 | params.height = tic.Height(); | 113 | params.height = tic.Height(); |
| 114 | params.depth = tic.Depth(); | 114 | params.depth = tic.Depth(); |
| 115 | params.pitch = params.is_tiled ? 0 : tic.Pitch(); | 115 | params.pitch = params.is_tiled ? 0 : tic.Pitch(); |
| 116 | if (params.target == SurfaceTarget::Texture2D && params.depth > 1) { | 116 | if (params.target == SurfaceTarget::TextureCubemap || |
| 117 | params.depth = 1; | 117 | params.target == SurfaceTarget::TextureCubeArray) { |
| 118 | } else if (params.target == SurfaceTarget::TextureCubemap || | ||
| 119 | params.target == SurfaceTarget::TextureCubeArray) { | ||
| 120 | params.depth *= 6; | 118 | params.depth *= 6; |
| 121 | } | 119 | } |
| 122 | params.num_levels = tic.max_mip_level + 1; | 120 | params.num_levels = tic.max_mip_level + 1; |
diff --git a/src/yuzu/about_dialog.cpp b/src/yuzu/about_dialog.cpp index d39b3f07a..695b2ef5f 100644 --- a/src/yuzu/about_dialog.cpp +++ b/src/yuzu/about_dialog.cpp | |||
| @@ -3,15 +3,22 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <QIcon> | 5 | #include <QIcon> |
| 6 | #include <fmt/format.h> | ||
| 6 | #include "common/scm_rev.h" | 7 | #include "common/scm_rev.h" |
| 7 | #include "ui_aboutdialog.h" | 8 | #include "ui_aboutdialog.h" |
| 8 | #include "yuzu/about_dialog.h" | 9 | #include "yuzu/about_dialog.h" |
| 9 | 10 | ||
| 10 | AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) { | 11 | AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) { |
| 12 | const auto build_id = std::string(Common::g_build_id); | ||
| 13 | const auto fmt = std::string(Common::g_title_bar_format_idle); | ||
| 14 | const auto yuzu_build_version = | ||
| 15 | fmt::format(fmt.empty() ? "yuzu Development Build" : fmt, std::string{}, std::string{}, | ||
| 16 | std::string{}, std::string{}, std::string{}, build_id); | ||
| 17 | |||
| 11 | ui->setupUi(this); | 18 | ui->setupUi(this); |
| 12 | ui->labelLogo->setPixmap(QIcon::fromTheme(QStringLiteral("yuzu")).pixmap(200)); | 19 | ui->labelLogo->setPixmap(QIcon::fromTheme(QStringLiteral("yuzu")).pixmap(200)); |
| 13 | ui->labelBuildInfo->setText(ui->labelBuildInfo->text().arg( | 20 | ui->labelBuildInfo->setText(ui->labelBuildInfo->text().arg( |
| 14 | QString::fromUtf8(Common::g_build_fullname), QString::fromUtf8(Common::g_scm_branch), | 21 | QString::fromStdString(yuzu_build_version), QString::fromUtf8(Common::g_scm_branch), |
| 15 | QString::fromUtf8(Common::g_scm_desc), QString::fromUtf8(Common::g_build_date).left(10))); | 22 | QString::fromUtf8(Common::g_scm_desc), QString::fromUtf8(Common::g_build_date).left(10))); |
| 16 | } | 23 | } |
| 17 | 24 | ||
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index c3a1b68f0..4b37746a1 100644 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui | |||
| @@ -927,7 +927,7 @@ | |||
| 927 | </item> | 927 | </item> |
| 928 | </layout> | 928 | </layout> |
| 929 | </item> | 929 | </item> |
| 930 | <item row="2" column="0"> | 930 | <item row="0" column="2"> |
| 931 | <layout class="QVBoxLayout" name="buttonShoulderButtonsSLVerticalLayout"> | 931 | <layout class="QVBoxLayout" name="buttonShoulderButtonsSLVerticalLayout"> |
| 932 | <item> | 932 | <item> |
| 933 | <layout class="QHBoxLayout" name="buttonShoulderButtonsSLHorizontalLayout"> | 933 | <layout class="QHBoxLayout" name="buttonShoulderButtonsSLHorizontalLayout"> |
| @@ -949,7 +949,7 @@ | |||
| 949 | </item> | 949 | </item> |
| 950 | </layout> | 950 | </layout> |
| 951 | </item> | 951 | </item> |
| 952 | <item row="2" column="1"> | 952 | <item row="1" column="2"> |
| 953 | <layout class="QVBoxLayout" name="buttonShoulderButtonsSRVerticalLayout"> | 953 | <layout class="QVBoxLayout" name="buttonShoulderButtonsSRVerticalLayout"> |
| 954 | <item> | 954 | <item> |
| 955 | <layout class="QHBoxLayout" name="buttonShoulderButtonsSRHorizontalLayout"> | 955 | <layout class="QHBoxLayout" name="buttonShoulderButtonsSRHorizontalLayout"> |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 940f24dc8..1717e06f9 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -205,7 +205,13 @@ GMainWindow::GMainWindow() | |||
| 205 | ConnectMenuEvents(); | 205 | ConnectMenuEvents(); |
| 206 | ConnectWidgetEvents(); | 206 | ConnectWidgetEvents(); |
| 207 | 207 | ||
| 208 | LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch, | 208 | const auto build_id = std::string(Common::g_build_id); |
| 209 | const auto fmt = std::string(Common::g_title_bar_format_idle); | ||
| 210 | const auto yuzu_build_version = | ||
| 211 | fmt::format(fmt.empty() ? "yuzu Development Build" : fmt, std::string{}, std::string{}, | ||
| 212 | std::string{}, std::string{}, std::string{}, build_id); | ||
| 213 | |||
| 214 | LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", yuzu_build_version, Common::g_scm_branch, | ||
| 209 | Common::g_scm_desc); | 215 | Common::g_scm_desc); |
| 210 | #ifdef ARCHITECTURE_x86_64 | 216 | #ifdef ARCHITECTURE_x86_64 |
| 211 | LOG_INFO(Frontend, "Host CPU: {}", Common::GetCPUCaps().cpu_string); | 217 | LOG_INFO(Frontend, "Host CPU: {}", Common::GetCPUCaps().cpu_string); |