diff options
Diffstat (limited to 'src')
25 files changed, 716 insertions, 406 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_header.h b/src/video_core/engines/shader_header.h index bc80661d8..72e2a33d5 100644 --- a/src/video_core/engines/shader_header.h +++ b/src/video_core/engines/shader_header.h | |||
| @@ -4,6 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 8 | #include <optional> | ||
| 9 | |||
| 7 | #include "common/bit_field.h" | 10 | #include "common/bit_field.h" |
| 8 | #include "common/common_funcs.h" | 11 | #include "common/common_funcs.h" |
| 9 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| @@ -16,7 +19,7 @@ enum class OutputTopology : u32 { | |||
| 16 | TriangleStrip = 7, | 19 | TriangleStrip = 7, |
| 17 | }; | 20 | }; |
| 18 | 21 | ||
| 19 | enum class AttributeUse : u8 { | 22 | enum class PixelImap : u8 { |
| 20 | Unused = 0, | 23 | Unused = 0, |
| 21 | Constant = 1, | 24 | Constant = 1, |
| 22 | Perspective = 2, | 25 | Perspective = 2, |
| @@ -24,7 +27,7 @@ enum class AttributeUse : u8 { | |||
| 24 | }; | 27 | }; |
| 25 | 28 | ||
| 26 | // Documentation in: | 29 | // Documentation in: |
| 27 | // http://download.nvidia.com/open-gpu-doc/Shader-Program-Header/1/Shader-Program-Header.html#ImapTexture | 30 | // http://download.nvidia.com/open-gpu-doc/Shader-Program-Header/1/Shader-Program-Header.html |
| 28 | struct Header { | 31 | struct Header { |
| 29 | union { | 32 | union { |
| 30 | BitField<0, 5, u32> sph_type; | 33 | BitField<0, 5, u32> sph_type; |
| @@ -59,8 +62,8 @@ struct Header { | |||
| 59 | union { | 62 | union { |
| 60 | BitField<0, 12, u32> max_output_vertices; | 63 | BitField<0, 12, u32> max_output_vertices; |
| 61 | BitField<12, 8, u32> store_req_start; // NOTE: not used by geometry shaders. | 64 | BitField<12, 8, u32> store_req_start; // NOTE: not used by geometry shaders. |
| 62 | BitField<24, 4, u32> reserved; | 65 | BitField<20, 4, u32> reserved; |
| 63 | BitField<12, 8, u32> store_req_end; // NOTE: not used by geometry shaders. | 66 | BitField<24, 8, u32> store_req_end; // NOTE: not used by geometry shaders. |
| 64 | } common4{}; | 67 | } common4{}; |
| 65 | 68 | ||
| 66 | union { | 69 | union { |
| @@ -93,17 +96,20 @@ struct Header { | |||
| 93 | struct { | 96 | struct { |
| 94 | INSERT_UNION_PADDING_BYTES(3); // ImapSystemValuesA | 97 | INSERT_UNION_PADDING_BYTES(3); // ImapSystemValuesA |
| 95 | INSERT_UNION_PADDING_BYTES(1); // ImapSystemValuesB | 98 | INSERT_UNION_PADDING_BYTES(1); // ImapSystemValuesB |
| 99 | |||
| 96 | union { | 100 | union { |
| 97 | BitField<0, 2, AttributeUse> x; | 101 | BitField<0, 2, PixelImap> x; |
| 98 | BitField<2, 2, AttributeUse> y; | 102 | BitField<2, 2, PixelImap> y; |
| 99 | BitField<4, 2, AttributeUse> w; | 103 | BitField<4, 2, PixelImap> z; |
| 100 | BitField<6, 2, AttributeUse> z; | 104 | BitField<6, 2, PixelImap> w; |
| 101 | u8 raw; | 105 | u8 raw; |
| 102 | } imap_generic_vector[32]; | 106 | } imap_generic_vector[32]; |
| 107 | |||
| 103 | INSERT_UNION_PADDING_BYTES(2); // ImapColor | 108 | INSERT_UNION_PADDING_BYTES(2); // ImapColor |
| 104 | INSERT_UNION_PADDING_BYTES(2); // ImapSystemValuesC | 109 | INSERT_UNION_PADDING_BYTES(2); // ImapSystemValuesC |
| 105 | INSERT_UNION_PADDING_BYTES(10); // ImapFixedFncTexture[10] | 110 | INSERT_UNION_PADDING_BYTES(10); // ImapFixedFncTexture[10] |
| 106 | INSERT_UNION_PADDING_BYTES(2); // ImapReserved | 111 | INSERT_UNION_PADDING_BYTES(2); // ImapReserved |
| 112 | |||
| 107 | struct { | 113 | struct { |
| 108 | u32 target; | 114 | u32 target; |
| 109 | union { | 115 | union { |
| @@ -112,31 +118,30 @@ struct Header { | |||
| 112 | BitField<2, 30, u32> reserved; | 118 | BitField<2, 30, u32> reserved; |
| 113 | }; | 119 | }; |
| 114 | } omap; | 120 | } omap; |
| 121 | |||
| 115 | bool IsColorComponentOutputEnabled(u32 render_target, u32 component) const { | 122 | bool IsColorComponentOutputEnabled(u32 render_target, u32 component) const { |
| 116 | const u32 bit = render_target * 4 + component; | 123 | const u32 bit = render_target * 4 + component; |
| 117 | return omap.target & (1 << bit); | 124 | return omap.target & (1 << bit); |
| 118 | } | 125 | } |
| 119 | AttributeUse GetAttributeIndexUse(u32 attribute, u32 index) const { | 126 | |
| 120 | return static_cast<AttributeUse>( | 127 | PixelImap GetPixelImap(u32 attribute) const { |
| 121 | (imap_generic_vector[attribute].raw >> (index * 2)) & 0x03); | 128 | const auto get_index = [this, attribute](u32 index) { |
| 122 | } | 129 | return static_cast<PixelImap>( |
| 123 | AttributeUse GetAttributeUse(u32 attribute) const { | 130 | (imap_generic_vector[attribute].raw >> (index * 2)) & 3); |
| 124 | AttributeUse result = AttributeUse::Unused; | 131 | }; |
| 125 | for (u32 i = 0; i < 4; i++) { | 132 | |
| 126 | const auto index = GetAttributeIndexUse(attribute, i); | 133 | std::optional<PixelImap> result; |
| 127 | if (index == AttributeUse::Unused) { | 134 | for (u32 component = 0; component < 4; ++component) { |
| 128 | continue; | 135 | const PixelImap index = get_index(component); |
| 129 | } | 136 | if (index == PixelImap::Unused) { |
| 130 | if (result == AttributeUse::Unused || result == index) { | ||
| 131 | result = index; | ||
| 132 | continue; | 137 | continue; |
| 133 | } | 138 | } |
| 134 | LOG_CRITICAL(HW_GPU, "Generic Attribute Conflict in Interpolation Mode"); | 139 | if (result && result != index) { |
| 135 | if (index == AttributeUse::Perspective) { | 140 | LOG_CRITICAL(HW_GPU, "Generic attribute conflict in interpolation mode"); |
| 136 | result = index; | ||
| 137 | } | 141 | } |
| 142 | result = index; | ||
| 138 | } | 143 | } |
| 139 | return result; | 144 | return result.value_or(PixelImap::Unused); |
| 140 | } | 145 | } |
| 141 | } ps; | 146 | } ps; |
| 142 | 147 | ||
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 1a2e2a9f7..c286502ba 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp | |||
| @@ -131,6 +131,31 @@ std::array<Device::BaseBindings, Tegra::Engines::MaxShaderTypes> BuildBaseBindin | |||
| 131 | return bindings; | 131 | return bindings; |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | bool IsASTCSupported() { | ||
| 135 | static constexpr std::array formats = { | ||
| 136 | GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, | ||
| 137 | GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, | ||
| 138 | GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, | ||
| 139 | GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, | ||
| 140 | GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, | ||
| 141 | GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, | ||
| 142 | GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, | ||
| 143 | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, | ||
| 144 | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, | ||
| 145 | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, | ||
| 146 | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, | ||
| 147 | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, | ||
| 148 | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, | ||
| 149 | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, | ||
| 150 | }; | ||
| 151 | return std::find_if_not(formats.begin(), formats.end(), [](GLenum format) { | ||
| 152 | GLint supported; | ||
| 153 | glGetInternalformativ(GL_TEXTURE_2D, format, GL_INTERNALFORMAT_SUPPORTED, 1, | ||
| 154 | &supported); | ||
| 155 | return supported == GL_TRUE; | ||
| 156 | }) == formats.end(); | ||
| 157 | } | ||
| 158 | |||
| 134 | } // Anonymous namespace | 159 | } // Anonymous namespace |
| 135 | 160 | ||
| 136 | Device::Device() : base_bindings{BuildBaseBindings()} { | 161 | Device::Device() : base_bindings{BuildBaseBindings()} { |
| @@ -152,6 +177,7 @@ Device::Device() : base_bindings{BuildBaseBindings()} { | |||
| 152 | has_shader_ballot = GLAD_GL_ARB_shader_ballot; | 177 | has_shader_ballot = GLAD_GL_ARB_shader_ballot; |
| 153 | has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array; | 178 | has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array; |
| 154 | has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted"); | 179 | has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted"); |
| 180 | has_astc = IsASTCSupported(); | ||
| 155 | has_variable_aoffi = TestVariableAoffi(); | 181 | has_variable_aoffi = TestVariableAoffi(); |
| 156 | has_component_indexing_bug = is_amd; | 182 | has_component_indexing_bug = is_amd; |
| 157 | has_precise_bug = TestPreciseBug(); | 183 | has_precise_bug = TestPreciseBug(); |
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index d73b099d0..a55050cb5 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h | |||
| @@ -64,6 +64,10 @@ public: | |||
| 64 | return has_image_load_formatted; | 64 | return has_image_load_formatted; |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | bool HasASTC() const { | ||
| 68 | return has_astc; | ||
| 69 | } | ||
| 70 | |||
| 67 | bool HasVariableAoffi() const { | 71 | bool HasVariableAoffi() const { |
| 68 | return has_variable_aoffi; | 72 | return has_variable_aoffi; |
| 69 | } | 73 | } |
| @@ -97,6 +101,7 @@ private: | |||
| 97 | bool has_shader_ballot{}; | 101 | bool has_shader_ballot{}; |
| 98 | bool has_vertex_viewport_layer{}; | 102 | bool has_vertex_viewport_layer{}; |
| 99 | bool has_image_load_formatted{}; | 103 | bool has_image_load_formatted{}; |
| 104 | bool has_astc{}; | ||
| 100 | bool has_variable_aoffi{}; | 105 | bool has_variable_aoffi{}; |
| 101 | bool has_component_indexing_bug{}; | 106 | bool has_component_indexing_bug{}; |
| 102 | bool has_precise_bug{}; | 107 | bool has_precise_bug{}; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 31add708f..346feeb2f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -386,11 +386,14 @@ void RasterizerOpenGL::ConfigureClearFramebuffer(bool using_color_fb, bool using | |||
| 386 | texture_cache.GuardRenderTargets(true); | 386 | texture_cache.GuardRenderTargets(true); |
| 387 | View color_surface; | 387 | View color_surface; |
| 388 | if (using_color_fb) { | 388 | if (using_color_fb) { |
| 389 | color_surface = texture_cache.GetColorBufferSurface(regs.clear_buffers.RT, false); | 389 | const std::size_t index = regs.clear_buffers.RT; |
| 390 | color_surface = texture_cache.GetColorBufferSurface(index, true); | ||
| 391 | texture_cache.MarkColorBufferInUse(index); | ||
| 390 | } | 392 | } |
| 391 | View depth_surface; | 393 | View depth_surface; |
| 392 | if (using_depth_fb || using_stencil_fb) { | 394 | if (using_depth_fb || using_stencil_fb) { |
| 393 | depth_surface = texture_cache.GetDepthBufferSurface(false); | 395 | depth_surface = texture_cache.GetDepthBufferSurface(true); |
| 396 | texture_cache.MarkDepthBufferInUse(); | ||
| 394 | } | 397 | } |
| 395 | texture_cache.GuardRenderTargets(false); | 398 | texture_cache.GuardRenderTargets(false); |
| 396 | 399 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index c7d24cf14..160ae4340 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -31,11 +31,11 @@ namespace { | |||
| 31 | 31 | ||
| 32 | using Tegra::Engines::ShaderType; | 32 | using Tegra::Engines::ShaderType; |
| 33 | using Tegra::Shader::Attribute; | 33 | using Tegra::Shader::Attribute; |
| 34 | using Tegra::Shader::AttributeUse; | ||
| 35 | using Tegra::Shader::Header; | 34 | using Tegra::Shader::Header; |
| 36 | using Tegra::Shader::IpaInterpMode; | 35 | using Tegra::Shader::IpaInterpMode; |
| 37 | using Tegra::Shader::IpaMode; | 36 | using Tegra::Shader::IpaMode; |
| 38 | using Tegra::Shader::IpaSampleMode; | 37 | using Tegra::Shader::IpaSampleMode; |
| 38 | using Tegra::Shader::PixelImap; | ||
| 39 | using Tegra::Shader::Register; | 39 | using Tegra::Shader::Register; |
| 40 | using VideoCommon::Shader::BuildTransformFeedback; | 40 | using VideoCommon::Shader::BuildTransformFeedback; |
| 41 | using VideoCommon::Shader::Registry; | 41 | using VideoCommon::Shader::Registry; |
| @@ -702,20 +702,19 @@ private: | |||
| 702 | code.AddNewLine(); | 702 | code.AddNewLine(); |
| 703 | } | 703 | } |
| 704 | 704 | ||
| 705 | std::string GetInputFlags(AttributeUse attribute) { | 705 | const char* GetInputFlags(PixelImap attribute) { |
| 706 | switch (attribute) { | 706 | switch (attribute) { |
| 707 | case AttributeUse::Perspective: | 707 | case PixelImap::Perspective: |
| 708 | // Default, Smooth | 708 | return "smooth"; |
| 709 | return {}; | 709 | case PixelImap::Constant: |
| 710 | case AttributeUse::Constant: | 710 | return "flat"; |
| 711 | return "flat "; | 711 | case PixelImap::ScreenLinear: |
| 712 | case AttributeUse::ScreenLinear: | 712 | return "noperspective"; |
| 713 | return "noperspective "; | 713 | case PixelImap::Unused: |
| 714 | default: | 714 | break; |
| 715 | case AttributeUse::Unused: | ||
| 716 | UNIMPLEMENTED_MSG("Unknown attribute usage index={}", static_cast<u32>(attribute)); | ||
| 717 | return {}; | ||
| 718 | } | 715 | } |
| 716 | UNIMPLEMENTED_MSG("Unknown attribute usage index={}", static_cast<int>(attribute)); | ||
| 717 | return {}; | ||
| 719 | } | 718 | } |
| 720 | 719 | ||
| 721 | void DeclareInputAttributes() { | 720 | void DeclareInputAttributes() { |
| @@ -749,8 +748,8 @@ private: | |||
| 749 | 748 | ||
| 750 | std::string suffix; | 749 | std::string suffix; |
| 751 | if (stage == ShaderType::Fragment) { | 750 | if (stage == ShaderType::Fragment) { |
| 752 | const auto input_mode{header.ps.GetAttributeUse(location)}; | 751 | const auto input_mode{header.ps.GetPixelImap(location)}; |
| 753 | if (skip_unused && input_mode == AttributeUse::Unused) { | 752 | if (input_mode == PixelImap::Unused) { |
| 754 | return; | 753 | return; |
| 755 | } | 754 | } |
| 756 | suffix = GetInputFlags(input_mode); | 755 | suffix = GetInputFlags(input_mode); |
| @@ -927,7 +926,7 @@ private: | |||
| 927 | const u32 address{generic_base + index * generic_stride + element * element_stride}; | 926 | const u32 address{generic_base + index * generic_stride + element * element_stride}; |
| 928 | 927 | ||
| 929 | const bool declared = stage != ShaderType::Fragment || | 928 | const bool declared = stage != ShaderType::Fragment || |
| 930 | header.ps.GetAttributeUse(index) != AttributeUse::Unused; | 929 | header.ps.GetPixelImap(index) != PixelImap::Unused; |
| 931 | const std::string value = | 930 | const std::string value = |
| 932 | declared ? ReadAttribute(attribute, element).AsFloat() : "0.0f"; | 931 | declared ? ReadAttribute(attribute, element).AsFloat() : "0.0f"; |
| 933 | code.AddLine("case 0x{:X}U: return {};", address, value); | 932 | code.AddLine("case 0x{:X}U: return {};", address, value); |
| @@ -1142,8 +1141,7 @@ private: | |||
| 1142 | GetSwizzle(element)), | 1141 | GetSwizzle(element)), |
| 1143 | Type::Float}; | 1142 | Type::Float}; |
| 1144 | case ShaderType::Fragment: | 1143 | case ShaderType::Fragment: |
| 1145 | return {element == 3 ? "1.0f" : ("gl_FragCoord"s + GetSwizzle(element)), | 1144 | return {"gl_FragCoord"s + GetSwizzle(element), Type::Float}; |
| 1146 | Type::Float}; | ||
| 1147 | default: | 1145 | default: |
| 1148 | UNREACHABLE(); | 1146 | UNREACHABLE(); |
| 1149 | } | 1147 | } |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index f424e3000..36590a6d0 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -24,7 +24,6 @@ using Tegra::Texture::SwizzleSource; | |||
| 24 | using VideoCore::MortonSwizzleMode; | 24 | using VideoCore::MortonSwizzleMode; |
| 25 | 25 | ||
| 26 | using VideoCore::Surface::PixelFormat; | 26 | using VideoCore::Surface::PixelFormat; |
| 27 | using VideoCore::Surface::SurfaceCompression; | ||
| 28 | using VideoCore::Surface::SurfaceTarget; | 27 | using VideoCore::Surface::SurfaceTarget; |
| 29 | using VideoCore::Surface::SurfaceType; | 28 | using VideoCore::Surface::SurfaceType; |
| 30 | 29 | ||
| @@ -37,102 +36,100 @@ namespace { | |||
| 37 | 36 | ||
| 38 | struct FormatTuple { | 37 | struct FormatTuple { |
| 39 | GLint internal_format; | 38 | GLint internal_format; |
| 40 | GLenum format; | 39 | GLenum format = GL_NONE; |
| 41 | GLenum type; | 40 | GLenum type = GL_NONE; |
| 42 | bool compressed; | ||
| 43 | }; | 41 | }; |
| 44 | 42 | ||
| 45 | constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{ | 43 | constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{ |
| 46 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // ABGR8U | 44 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV}, // ABGR8U |
| 47 | {GL_RGBA8_SNORM, GL_RGBA, GL_BYTE, false}, // ABGR8S | 45 | {GL_RGBA8_SNORM, GL_RGBA, GL_BYTE}, // ABGR8S |
| 48 | {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, false}, // ABGR8UI | 46 | {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE}, // ABGR8UI |
| 49 | {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false}, // B5G6R5U | 47 | {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV}, // B5G6R5U |
| 50 | {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false}, // A2B10G10R10U | 48 | {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}, // A2B10G10R10U |
| 51 | {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false}, // A1B5G5R5U | 49 | {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, // A1B5G5R5U |
| 52 | {GL_R8, GL_RED, GL_UNSIGNED_BYTE, false}, // R8U | 50 | {GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // R8U |
| 53 | {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, false}, // R8UI | 51 | {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE}, // R8UI |
| 54 | {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, false}, // RGBA16F | 52 | {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT}, // RGBA16F |
| 55 | {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, false}, // RGBA16U | 53 | {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT}, // RGBA16U |
| 56 | {GL_RGBA16_SNORM, GL_RGBA, GL_SHORT, false}, // RGBA16S | 54 | {GL_RGBA16_SNORM, GL_RGBA, GL_SHORT}, // RGBA16S |
| 57 | {GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, false}, // RGBA16UI | 55 | {GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT}, // RGBA16UI |
| 58 | {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, false}, // R11FG11FB10F | 56 | {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV}, // R11FG11FB10F |
| 59 | {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, false}, // RGBA32UI | 57 | {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT}, // RGBA32UI |
| 60 | {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT1 | 58 | {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT}, // DXT1 |
| 61 | {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT23 | 59 | {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT}, // DXT23 |
| 62 | {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT45 | 60 | {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT}, // DXT45 |
| 63 | {GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_INT_8_8_8_8, true}, // DXN1 | 61 | {GL_COMPRESSED_RED_RGTC1}, // DXN1 |
| 64 | {GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, true}, // DXN2UNORM | 62 | {GL_COMPRESSED_RG_RGTC2}, // DXN2UNORM |
| 65 | {GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, true}, // DXN2SNORM | 63 | {GL_COMPRESSED_SIGNED_RG_RGTC2}, // DXN2SNORM |
| 66 | {GL_COMPRESSED_RGBA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // BC7U | 64 | {GL_COMPRESSED_RGBA_BPTC_UNORM}, // BC7U |
| 67 | {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true}, // BC6H_UF16 | 65 | {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT}, // BC6H_UF16 |
| 68 | {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true}, // BC6H_SF16 | 66 | {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT}, // BC6H_SF16 |
| 69 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_4X4 | 67 | {GL_COMPRESSED_RGBA_ASTC_4x4_KHR}, // ASTC_2D_4X4 |
| 70 | {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, false}, // BGRA8 | 68 | {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE}, // BGRA8 |
| 71 | {GL_RGBA32F, GL_RGBA, GL_FLOAT, false}, // RGBA32F | 69 | {GL_RGBA32F, GL_RGBA, GL_FLOAT}, // RGBA32F |
| 72 | {GL_RG32F, GL_RG, GL_FLOAT, false}, // RG32F | 70 | {GL_RG32F, GL_RG, GL_FLOAT}, // RG32F |
| 73 | {GL_R32F, GL_RED, GL_FLOAT, false}, // R32F | 71 | {GL_R32F, GL_RED, GL_FLOAT}, // R32F |
| 74 | {GL_R16F, GL_RED, GL_HALF_FLOAT, false}, // R16F | 72 | {GL_R16F, GL_RED, GL_HALF_FLOAT}, // R16F |
| 75 | {GL_R16, GL_RED, GL_UNSIGNED_SHORT, false}, // R16U | 73 | {GL_R16, GL_RED, GL_UNSIGNED_SHORT}, // R16U |
| 76 | {GL_R16_SNORM, GL_RED, GL_SHORT, false}, // R16S | 74 | {GL_R16_SNORM, GL_RED, GL_SHORT}, // R16S |
| 77 | {GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT, false}, // R16UI | 75 | {GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT}, // R16UI |
| 78 | {GL_R16I, GL_RED_INTEGER, GL_SHORT, false}, // R16I | 76 | {GL_R16I, GL_RED_INTEGER, GL_SHORT}, // R16I |
| 79 | {GL_RG16, GL_RG, GL_UNSIGNED_SHORT, false}, // RG16 | 77 | {GL_RG16, GL_RG, GL_UNSIGNED_SHORT}, // RG16 |
| 80 | {GL_RG16F, GL_RG, GL_HALF_FLOAT, false}, // RG16F | 78 | {GL_RG16F, GL_RG, GL_HALF_FLOAT}, // RG16F |
| 81 | {GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT, false}, // RG16UI | 79 | {GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT}, // RG16UI |
| 82 | {GL_RG16I, GL_RG_INTEGER, GL_SHORT, false}, // RG16I | 80 | {GL_RG16I, GL_RG_INTEGER, GL_SHORT}, // RG16I |
| 83 | {GL_RG16_SNORM, GL_RG, GL_SHORT, false}, // RG16S | 81 | {GL_RG16_SNORM, GL_RG, GL_SHORT}, // RG16S |
| 84 | {GL_RGB32F, GL_RGB, GL_FLOAT, false}, // RGB32F | 82 | {GL_RGB32F, GL_RGB, GL_FLOAT}, // RGB32F |
| 85 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // RGBA8_SRGB | 83 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV}, // RGBA8_SRGB |
| 86 | {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, false}, // RG8U | 84 | {GL_RG8, GL_RG, GL_UNSIGNED_BYTE}, // RG8U |
| 87 | {GL_RG8_SNORM, GL_RG, GL_BYTE, false}, // RG8S | 85 | {GL_RG8_SNORM, GL_RG, GL_BYTE}, // RG8S |
| 88 | {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, false}, // RG32UI | 86 | {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT}, // RG32UI |
| 89 | {GL_RGB16F, GL_RGBA, GL_HALF_FLOAT, false}, // RGBX16F | 87 | {GL_RGB16F, GL_RGBA, GL_HALF_FLOAT}, // RGBX16F |
| 90 | {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, false}, // R32UI | 88 | {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT}, // R32UI |
| 91 | {GL_R32I, GL_RED_INTEGER, GL_INT, false}, // R32I | 89 | {GL_R32I, GL_RED_INTEGER, GL_INT}, // R32I |
| 92 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_8X8 | 90 | {GL_COMPRESSED_RGBA_ASTC_8x8_KHR}, // ASTC_2D_8X8 |
| 93 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_8X5 | 91 | {GL_COMPRESSED_RGBA_ASTC_8x5_KHR}, // ASTC_2D_8X5 |
| 94 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_5X4 | 92 | {GL_COMPRESSED_RGBA_ASTC_5x4_KHR}, // ASTC_2D_5X4 |
| 95 | {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE, false}, // BGRA8 | 93 | {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE}, // BGRA8 |
| 96 | // Compressed sRGB formats | 94 | // Compressed sRGB formats |
| 97 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT1_SRGB | 95 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT}, // DXT1_SRGB |
| 98 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT23_SRGB | 96 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT}, // DXT23_SRGB |
| 99 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT45_SRGB | 97 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}, // DXT45_SRGB |
| 100 | {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // BC7U_SRGB | 98 | {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM}, // BC7U_SRGB |
| 101 | {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, false}, // R4G4B4A4U | 99 | {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV}, // R4G4B4A4U |
| 102 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_4X4_SRGB | 100 | {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR}, // ASTC_2D_4X4_SRGB |
| 103 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_8X8_SRGB | 101 | {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR}, // ASTC_2D_8X8_SRGB |
| 104 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_8X5_SRGB | 102 | {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR}, // ASTC_2D_8X5_SRGB |
| 105 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_5X4_SRGB | 103 | {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR}, // ASTC_2D_5X4_SRGB |
| 106 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_5X5 | 104 | {GL_COMPRESSED_RGBA_ASTC_5x5_KHR}, // ASTC_2D_5X5 |
| 107 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_5X5_SRGB | 105 | {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR}, // ASTC_2D_5X5_SRGB |
| 108 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_10X8 | 106 | {GL_COMPRESSED_RGBA_ASTC_10x8_KHR}, // ASTC_2D_10X8 |
| 109 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_10X8_SRGB | 107 | {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR}, // ASTC_2D_10X8_SRGB |
| 110 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_6X6 | 108 | {GL_COMPRESSED_RGBA_ASTC_6x6_KHR}, // ASTC_2D_6X6 |
| 111 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_6X6_SRGB | 109 | {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR}, // ASTC_2D_6X6_SRGB |
| 112 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_10X10 | 110 | {GL_COMPRESSED_RGBA_ASTC_10x10_KHR}, // ASTC_2D_10X10 |
| 113 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_10X10_SRGB | 111 | {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR}, // ASTC_2D_10X10_SRGB |
| 114 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_12X12 | 112 | {GL_COMPRESSED_RGBA_ASTC_12x12_KHR}, // ASTC_2D_12X12 |
| 115 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_12X12_SRGB | 113 | {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR}, // ASTC_2D_12X12_SRGB |
| 116 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_8X6 | 114 | {GL_COMPRESSED_RGBA_ASTC_8x6_KHR}, // ASTC_2D_8X6 |
| 117 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_8X6_SRGB | 115 | {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR}, // ASTC_2D_8X6_SRGB |
| 118 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_6X5 | 116 | {GL_COMPRESSED_RGBA_ASTC_6x5_KHR}, // ASTC_2D_6X5 |
| 119 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_6X5_SRGB | 117 | {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR}, // ASTC_2D_6X5_SRGB |
| 120 | {GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, false}, // E5B9G9R9F | 118 | {GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV}, // E5B9G9R9F |
| 121 | 119 | ||
| 122 | // Depth formats | 120 | // Depth formats |
| 123 | {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, false}, // Z32F | 121 | {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}, // Z32F |
| 124 | {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, false}, // Z16 | 122 | {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // Z16 |
| 125 | 123 | ||
| 126 | // DepthStencil formats | 124 | // DepthStencil formats |
| 127 | {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, false}, // Z24S8 | 125 | {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // Z24S8 |
| 128 | {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, false}, // S8Z24 | 126 | {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // S8Z24 |
| 129 | {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, false}, // Z32FS8 | 127 | {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV}, // Z32FS8 |
| 130 | }}; | 128 | }}; |
| 131 | 129 | ||
| 132 | const FormatTuple& GetFormatTuple(PixelFormat pixel_format) { | 130 | const FormatTuple& GetFormatTuple(PixelFormat pixel_format) { |
| 133 | ASSERT(static_cast<std::size_t>(pixel_format) < tex_format_tuples.size()); | 131 | ASSERT(static_cast<std::size_t>(pixel_format) < tex_format_tuples.size()); |
| 134 | const auto& format{tex_format_tuples[static_cast<std::size_t>(pixel_format)]}; | 132 | return tex_format_tuples[static_cast<std::size_t>(pixel_format)]; |
| 135 | return format; | ||
| 136 | } | 133 | } |
| 137 | 134 | ||
| 138 | GLenum GetTextureTarget(const SurfaceTarget& target) { | 135 | GLenum GetTextureTarget(const SurfaceTarget& target) { |
| @@ -242,13 +239,20 @@ OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum inte | |||
| 242 | 239 | ||
| 243 | } // Anonymous namespace | 240 | } // Anonymous namespace |
| 244 | 241 | ||
| 245 | CachedSurface::CachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params) | 242 | CachedSurface::CachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params, |
| 246 | : VideoCommon::SurfaceBase<View>(gpu_addr, params) { | 243 | bool is_astc_supported) |
| 247 | const auto& tuple{GetFormatTuple(params.pixel_format)}; | 244 | : VideoCommon::SurfaceBase<View>(gpu_addr, params, is_astc_supported) { |
| 248 | internal_format = tuple.internal_format; | 245 | if (is_converted) { |
| 249 | format = tuple.format; | 246 | internal_format = params.srgb_conversion ? GL_SRGB8_ALPHA8 : GL_RGBA8; |
| 250 | type = tuple.type; | 247 | format = GL_RGBA; |
| 251 | is_compressed = tuple.compressed; | 248 | type = GL_UNSIGNED_BYTE; |
| 249 | } else { | ||
| 250 | const auto& tuple{GetFormatTuple(params.pixel_format)}; | ||
| 251 | internal_format = tuple.internal_format; | ||
| 252 | format = tuple.format; | ||
| 253 | type = tuple.type; | ||
| 254 | is_compressed = params.IsCompressed(); | ||
| 255 | } | ||
| 252 | target = GetTextureTarget(params.target); | 256 | target = GetTextureTarget(params.target); |
| 253 | texture = CreateTexture(params, target, internal_format, texture_buffer); | 257 | texture = CreateTexture(params, target, internal_format, texture_buffer); |
| 254 | DecorateSurfaceName(); | 258 | DecorateSurfaceName(); |
| @@ -264,7 +268,7 @@ void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) { | |||
| 264 | 268 | ||
| 265 | if (params.IsBuffer()) { | 269 | if (params.IsBuffer()) { |
| 266 | glGetNamedBufferSubData(texture_buffer.handle, 0, | 270 | glGetNamedBufferSubData(texture_buffer.handle, 0, |
| 267 | static_cast<GLsizeiptr>(params.GetHostSizeInBytes()), | 271 | static_cast<GLsizeiptr>(params.GetHostSizeInBytes(false)), |
| 268 | staging_buffer.data()); | 272 | staging_buffer.data()); |
| 269 | return; | 273 | return; |
| 270 | } | 274 | } |
| @@ -272,9 +276,10 @@ void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) { | |||
| 272 | SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); }); | 276 | SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); }); |
| 273 | 277 | ||
| 274 | for (u32 level = 0; level < params.emulated_levels; ++level) { | 278 | for (u32 level = 0; level < params.emulated_levels; ++level) { |
| 275 | glPixelStorei(GL_PACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level))); | 279 | glPixelStorei(GL_PACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level, is_converted))); |
| 276 | glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); | 280 | glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); |
| 277 | const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level); | 281 | const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level, is_converted); |
| 282 | |||
| 278 | u8* const mip_data = staging_buffer.data() + mip_offset; | 283 | u8* const mip_data = staging_buffer.data() + mip_offset; |
| 279 | const GLsizei size = static_cast<GLsizei>(params.GetHostMipmapSize(level)); | 284 | const GLsizei size = static_cast<GLsizei>(params.GetHostMipmapSize(level)); |
| 280 | if (is_compressed) { | 285 | if (is_compressed) { |
| @@ -294,14 +299,10 @@ void CachedSurface::UploadTexture(const std::vector<u8>& staging_buffer) { | |||
| 294 | } | 299 | } |
| 295 | 300 | ||
| 296 | void CachedSurface::UploadTextureMipmap(u32 level, const std::vector<u8>& staging_buffer) { | 301 | void CachedSurface::UploadTextureMipmap(u32 level, const std::vector<u8>& staging_buffer) { |
| 297 | glPixelStorei(GL_UNPACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level))); | 302 | glPixelStorei(GL_UNPACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level, is_converted))); |
| 298 | glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); | 303 | glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); |
| 299 | 304 | ||
| 300 | auto compression_type = params.GetCompressionType(); | 305 | const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level, is_converted); |
| 301 | |||
| 302 | const std::size_t mip_offset = compression_type == SurfaceCompression::Converted | ||
| 303 | ? params.GetConvertedMipmapOffset(level) | ||
| 304 | : params.GetHostMipmapLevelOffset(level); | ||
| 305 | const u8* buffer{staging_buffer.data() + mip_offset}; | 306 | const u8* buffer{staging_buffer.data() + mip_offset}; |
| 306 | if (is_compressed) { | 307 | if (is_compressed) { |
| 307 | const auto image_size{static_cast<GLsizei>(params.GetHostMipmapSize(level))}; | 308 | const auto image_size{static_cast<GLsizei>(params.GetHostMipmapSize(level))}; |
| @@ -482,7 +483,7 @@ OGLTextureView CachedSurfaceView::CreateTextureView() const { | |||
| 482 | TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system, | 483 | TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system, |
| 483 | VideoCore::RasterizerInterface& rasterizer, | 484 | VideoCore::RasterizerInterface& rasterizer, |
| 484 | const Device& device, StateTracker& state_tracker) | 485 | const Device& device, StateTracker& state_tracker) |
| 485 | : TextureCacheBase{system, rasterizer}, state_tracker{state_tracker} { | 486 | : TextureCacheBase{system, rasterizer, device.HasASTC()}, state_tracker{state_tracker} { |
| 486 | src_framebuffer.Create(); | 487 | src_framebuffer.Create(); |
| 487 | dst_framebuffer.Create(); | 488 | dst_framebuffer.Create(); |
| 488 | } | 489 | } |
| @@ -490,7 +491,7 @@ TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system, | |||
| 490 | TextureCacheOpenGL::~TextureCacheOpenGL() = default; | 491 | TextureCacheOpenGL::~TextureCacheOpenGL() = default; |
| 491 | 492 | ||
| 492 | Surface TextureCacheOpenGL::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) { | 493 | Surface TextureCacheOpenGL::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) { |
| 493 | return std::make_shared<CachedSurface>(gpu_addr, params); | 494 | return std::make_shared<CachedSurface>(gpu_addr, params, is_astc_supported); |
| 494 | } | 495 | } |
| 495 | 496 | ||
| 496 | void TextureCacheOpenGL::ImageCopy(Surface& src_surface, Surface& dst_surface, | 497 | void TextureCacheOpenGL::ImageCopy(Surface& src_surface, Surface& dst_surface, |
| @@ -596,7 +597,7 @@ void TextureCacheOpenGL::BufferCopy(Surface& src_surface, Surface& dst_surface) | |||
| 596 | 597 | ||
| 597 | glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle); | 598 | glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle); |
| 598 | 599 | ||
| 599 | if (source_format.compressed) { | 600 | if (src_surface->IsCompressed()) { |
| 600 | glGetCompressedTextureImage(src_surface->GetTexture(), 0, static_cast<GLsizei>(source_size), | 601 | glGetCompressedTextureImage(src_surface->GetTexture(), 0, static_cast<GLsizei>(source_size), |
| 601 | nullptr); | 602 | nullptr); |
| 602 | } else { | 603 | } else { |
| @@ -610,7 +611,7 @@ void TextureCacheOpenGL::BufferCopy(Surface& src_surface, Surface& dst_surface) | |||
| 610 | const GLsizei width = static_cast<GLsizei>(dst_params.width); | 611 | const GLsizei width = static_cast<GLsizei>(dst_params.width); |
| 611 | const GLsizei height = static_cast<GLsizei>(dst_params.height); | 612 | const GLsizei height = static_cast<GLsizei>(dst_params.height); |
| 612 | const GLsizei depth = static_cast<GLsizei>(dst_params.depth); | 613 | const GLsizei depth = static_cast<GLsizei>(dst_params.depth); |
| 613 | if (dest_format.compressed) { | 614 | if (dst_surface->IsCompressed()) { |
| 614 | LOG_CRITICAL(HW_GPU, "Compressed buffer copy is unimplemented!"); | 615 | LOG_CRITICAL(HW_GPU, "Compressed buffer copy is unimplemented!"); |
| 615 | UNREACHABLE(); | 616 | UNREACHABLE(); |
| 616 | } else { | 617 | } else { |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 6658c6ffd..02d9981a1 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h | |||
| @@ -37,7 +37,7 @@ class CachedSurface final : public VideoCommon::SurfaceBase<View> { | |||
| 37 | friend CachedSurfaceView; | 37 | friend CachedSurfaceView; |
| 38 | 38 | ||
| 39 | public: | 39 | public: |
| 40 | explicit CachedSurface(GPUVAddr gpu_addr, const SurfaceParams& params); | 40 | explicit CachedSurface(GPUVAddr gpu_addr, const SurfaceParams& params, bool is_astc_supported); |
| 41 | ~CachedSurface(); | 41 | ~CachedSurface(); |
| 42 | 42 | ||
| 43 | void UploadTexture(const std::vector<u8>& staging_buffer) override; | 43 | void UploadTexture(const std::vector<u8>& staging_buffer) override; |
| @@ -51,6 +51,10 @@ public: | |||
| 51 | return texture.handle; | 51 | return texture.handle; |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | bool IsCompressed() const { | ||
| 55 | return is_compressed; | ||
| 56 | } | ||
| 57 | |||
| 54 | protected: | 58 | protected: |
| 55 | void DecorateSurfaceName() override; | 59 | void DecorateSurfaceName() override; |
| 56 | 60 | ||
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index 28d2fbc4f..7aafb5e59 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp | |||
| @@ -237,18 +237,21 @@ void VKDevice::ReportLoss() const { | |||
| 237 | 237 | ||
| 238 | bool VKDevice::IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features, | 238 | bool VKDevice::IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features, |
| 239 | const vk::DispatchLoaderDynamic& dldi) const { | 239 | const vk::DispatchLoaderDynamic& dldi) const { |
| 240 | // Disable for now to avoid converting ASTC twice. | ||
| 241 | return false; | ||
| 242 | static constexpr std::array astc_formats = { | 240 | static constexpr std::array astc_formats = { |
| 243 | vk::Format::eAstc4x4SrgbBlock, vk::Format::eAstc8x8SrgbBlock, | 241 | vk::Format::eAstc4x4UnormBlock, vk::Format::eAstc4x4SrgbBlock, |
| 244 | vk::Format::eAstc8x5SrgbBlock, vk::Format::eAstc5x4SrgbBlock, | 242 | vk::Format::eAstc5x4UnormBlock, vk::Format::eAstc5x4SrgbBlock, |
| 245 | vk::Format::eAstc5x5UnormBlock, vk::Format::eAstc5x5SrgbBlock, | 243 | vk::Format::eAstc5x5UnormBlock, vk::Format::eAstc5x5SrgbBlock, |
| 246 | vk::Format::eAstc10x8UnormBlock, vk::Format::eAstc10x8SrgbBlock, | 244 | vk::Format::eAstc6x5UnormBlock, vk::Format::eAstc6x5SrgbBlock, |
| 247 | vk::Format::eAstc6x6UnormBlock, vk::Format::eAstc6x6SrgbBlock, | 245 | vk::Format::eAstc6x6UnormBlock, vk::Format::eAstc6x6SrgbBlock, |
| 248 | vk::Format::eAstc10x10UnormBlock, vk::Format::eAstc10x10SrgbBlock, | 246 | vk::Format::eAstc8x5UnormBlock, vk::Format::eAstc8x5SrgbBlock, |
| 249 | vk::Format::eAstc12x12UnormBlock, vk::Format::eAstc12x12SrgbBlock, | ||
| 250 | vk::Format::eAstc8x6UnormBlock, vk::Format::eAstc8x6SrgbBlock, | 247 | vk::Format::eAstc8x6UnormBlock, vk::Format::eAstc8x6SrgbBlock, |
| 251 | vk::Format::eAstc6x5UnormBlock, vk::Format::eAstc6x5SrgbBlock}; | 248 | vk::Format::eAstc8x8UnormBlock, vk::Format::eAstc8x8SrgbBlock, |
| 249 | vk::Format::eAstc10x5UnormBlock, vk::Format::eAstc10x5SrgbBlock, | ||
| 250 | vk::Format::eAstc10x6UnormBlock, vk::Format::eAstc10x6SrgbBlock, | ||
| 251 | vk::Format::eAstc10x8UnormBlock, vk::Format::eAstc10x8SrgbBlock, | ||
| 252 | vk::Format::eAstc10x10UnormBlock, vk::Format::eAstc10x10SrgbBlock, | ||
| 253 | vk::Format::eAstc12x10UnormBlock, vk::Format::eAstc12x10SrgbBlock, | ||
| 254 | vk::Format::eAstc12x12UnormBlock, vk::Format::eAstc12x12SrgbBlock}; | ||
| 252 | if (!features.textureCompressionASTC_LDR) { | 255 | if (!features.textureCompressionASTC_LDR) { |
| 253 | return false; | 256 | return false; |
| 254 | } | 257 | } |
| @@ -572,24 +575,34 @@ std::unordered_map<vk::Format, vk::FormatProperties> VKDevice::GetFormatProperti | |||
| 572 | vk::Format::eBc2SrgbBlock, | 575 | vk::Format::eBc2SrgbBlock, |
| 573 | vk::Format::eBc3SrgbBlock, | 576 | vk::Format::eBc3SrgbBlock, |
| 574 | vk::Format::eBc7SrgbBlock, | 577 | vk::Format::eBc7SrgbBlock, |
| 578 | vk::Format::eAstc4x4UnormBlock, | ||
| 575 | vk::Format::eAstc4x4SrgbBlock, | 579 | vk::Format::eAstc4x4SrgbBlock, |
| 576 | vk::Format::eAstc8x8SrgbBlock, | 580 | vk::Format::eAstc5x4UnormBlock, |
| 577 | vk::Format::eAstc8x5SrgbBlock, | ||
| 578 | vk::Format::eAstc5x4SrgbBlock, | 581 | vk::Format::eAstc5x4SrgbBlock, |
| 579 | vk::Format::eAstc5x5UnormBlock, | 582 | vk::Format::eAstc5x5UnormBlock, |
| 580 | vk::Format::eAstc5x5SrgbBlock, | 583 | vk::Format::eAstc5x5SrgbBlock, |
| 581 | vk::Format::eAstc10x8UnormBlock, | 584 | vk::Format::eAstc6x5UnormBlock, |
| 582 | vk::Format::eAstc10x8SrgbBlock, | 585 | vk::Format::eAstc6x5SrgbBlock, |
| 583 | vk::Format::eAstc6x6UnormBlock, | 586 | vk::Format::eAstc6x6UnormBlock, |
| 584 | vk::Format::eAstc6x6SrgbBlock, | 587 | vk::Format::eAstc6x6SrgbBlock, |
| 588 | vk::Format::eAstc8x5UnormBlock, | ||
| 589 | vk::Format::eAstc8x5SrgbBlock, | ||
| 590 | vk::Format::eAstc8x6UnormBlock, | ||
| 591 | vk::Format::eAstc8x6SrgbBlock, | ||
| 592 | vk::Format::eAstc8x8UnormBlock, | ||
| 593 | vk::Format::eAstc8x8SrgbBlock, | ||
| 594 | vk::Format::eAstc10x5UnormBlock, | ||
| 595 | vk::Format::eAstc10x5SrgbBlock, | ||
| 596 | vk::Format::eAstc10x6UnormBlock, | ||
| 597 | vk::Format::eAstc10x6SrgbBlock, | ||
| 598 | vk::Format::eAstc10x8UnormBlock, | ||
| 599 | vk::Format::eAstc10x8SrgbBlock, | ||
| 585 | vk::Format::eAstc10x10UnormBlock, | 600 | vk::Format::eAstc10x10UnormBlock, |
| 586 | vk::Format::eAstc10x10SrgbBlock, | 601 | vk::Format::eAstc10x10SrgbBlock, |
| 602 | vk::Format::eAstc12x10UnormBlock, | ||
| 603 | vk::Format::eAstc12x10SrgbBlock, | ||
| 587 | vk::Format::eAstc12x12UnormBlock, | 604 | vk::Format::eAstc12x12UnormBlock, |
| 588 | vk::Format::eAstc12x12SrgbBlock, | 605 | vk::Format::eAstc12x12SrgbBlock, |
| 589 | vk::Format::eAstc8x6UnormBlock, | ||
| 590 | vk::Format::eAstc8x6SrgbBlock, | ||
| 591 | vk::Format::eAstc6x5UnormBlock, | ||
| 592 | vk::Format::eAstc6x5SrgbBlock, | ||
| 593 | vk::Format::eE5B9G9R9UfloatPack32}; | 606 | vk::Format::eE5B9G9R9UfloatPack32}; |
| 594 | std::unordered_map<vk::Format, vk::FormatProperties> format_properties; | 607 | std::unordered_map<vk::Format, vk::FormatProperties> format_properties; |
| 595 | for (const auto format : formats) { | 608 | for (const auto format : formats) { |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index d67f08cf9..b9f9e2714 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -35,7 +35,7 @@ namespace { | |||
| 35 | using Sirit::Id; | 35 | using Sirit::Id; |
| 36 | using Tegra::Engines::ShaderType; | 36 | using Tegra::Engines::ShaderType; |
| 37 | using Tegra::Shader::Attribute; | 37 | using Tegra::Shader::Attribute; |
| 38 | using Tegra::Shader::AttributeUse; | 38 | using Tegra::Shader::PixelImap; |
| 39 | using Tegra::Shader::Register; | 39 | using Tegra::Shader::Register; |
| 40 | using namespace VideoCommon::Shader; | 40 | using namespace VideoCommon::Shader; |
| 41 | 41 | ||
| @@ -752,16 +752,16 @@ private: | |||
| 752 | if (stage != ShaderType::Fragment) { | 752 | if (stage != ShaderType::Fragment) { |
| 753 | continue; | 753 | continue; |
| 754 | } | 754 | } |
| 755 | switch (header.ps.GetAttributeUse(location)) { | 755 | switch (header.ps.GetPixelImap(location)) { |
| 756 | case AttributeUse::Constant: | 756 | case PixelImap::Constant: |
| 757 | Decorate(id, spv::Decoration::Flat); | 757 | Decorate(id, spv::Decoration::Flat); |
| 758 | break; | 758 | break; |
| 759 | case AttributeUse::ScreenLinear: | 759 | case PixelImap::Perspective: |
| 760 | Decorate(id, spv::Decoration::NoPerspective); | ||
| 761 | break; | ||
| 762 | case AttributeUse::Perspective: | ||
| 763 | // Default | 760 | // Default |
| 764 | break; | 761 | break; |
| 762 | case PixelImap::ScreenLinear: | ||
| 763 | Decorate(id, spv::Decoration::NoPerspective); | ||
| 764 | break; | ||
| 765 | default: | 765 | default: |
| 766 | UNREACHABLE_MSG("Unused attribute being fetched"); | 766 | UNREACHABLE_MSG("Unused attribute being fetched"); |
| 767 | } | 767 | } |
| @@ -1145,9 +1145,6 @@ private: | |||
| 1145 | switch (attribute) { | 1145 | switch (attribute) { |
| 1146 | case Attribute::Index::Position: { | 1146 | case Attribute::Index::Position: { |
| 1147 | if (stage == ShaderType::Fragment) { | 1147 | if (stage == ShaderType::Fragment) { |
| 1148 | if (element == 3) { | ||
| 1149 | return {Constant(t_float, 1.0f), Type::Float}; | ||
| 1150 | } | ||
| 1151 | return {OpLoad(t_float, AccessElement(t_in_float, frag_coord, element)), | 1148 | return {OpLoad(t_float, AccessElement(t_in_float, frag_coord, element)), |
| 1152 | Type::Float}; | 1149 | Type::Float}; |
| 1153 | } | 1150 | } |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 26175921b..5b9b39670 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -35,7 +35,6 @@ using VideoCore::MortonSwizzleMode; | |||
| 35 | 35 | ||
| 36 | using Tegra::Texture::SwizzleSource; | 36 | using Tegra::Texture::SwizzleSource; |
| 37 | using VideoCore::Surface::PixelFormat; | 37 | using VideoCore::Surface::PixelFormat; |
| 38 | using VideoCore::Surface::SurfaceCompression; | ||
| 39 | using VideoCore::Surface::SurfaceTarget; | 38 | using VideoCore::Surface::SurfaceTarget; |
| 40 | 39 | ||
| 41 | namespace { | 40 | namespace { |
| @@ -96,9 +95,10 @@ vk::ImageViewType GetImageViewType(SurfaceTarget target) { | |||
| 96 | return {}; | 95 | return {}; |
| 97 | } | 96 | } |
| 98 | 97 | ||
| 99 | UniqueBuffer CreateBuffer(const VKDevice& device, const SurfaceParams& params) { | 98 | UniqueBuffer CreateBuffer(const VKDevice& device, const SurfaceParams& params, |
| 99 | std::size_t host_memory_size) { | ||
| 100 | // TODO(Rodrigo): Move texture buffer creation to the buffer cache | 100 | // TODO(Rodrigo): Move texture buffer creation to the buffer cache |
| 101 | const vk::BufferCreateInfo buffer_ci({}, params.GetHostSizeInBytes(), | 101 | const vk::BufferCreateInfo buffer_ci({}, host_memory_size, |
| 102 | vk::BufferUsageFlagBits::eUniformTexelBuffer | | 102 | vk::BufferUsageFlagBits::eUniformTexelBuffer | |
| 103 | vk::BufferUsageFlagBits::eTransferSrc | | 103 | vk::BufferUsageFlagBits::eTransferSrc | |
| 104 | vk::BufferUsageFlagBits::eTransferDst, | 104 | vk::BufferUsageFlagBits::eTransferDst, |
| @@ -110,12 +110,13 @@ UniqueBuffer CreateBuffer(const VKDevice& device, const SurfaceParams& params) { | |||
| 110 | 110 | ||
| 111 | vk::BufferViewCreateInfo GenerateBufferViewCreateInfo(const VKDevice& device, | 111 | vk::BufferViewCreateInfo GenerateBufferViewCreateInfo(const VKDevice& device, |
| 112 | const SurfaceParams& params, | 112 | const SurfaceParams& params, |
| 113 | vk::Buffer buffer) { | 113 | vk::Buffer buffer, |
| 114 | std::size_t host_memory_size) { | ||
| 114 | ASSERT(params.IsBuffer()); | 115 | ASSERT(params.IsBuffer()); |
| 115 | 116 | ||
| 116 | const auto format = | 117 | const auto format = |
| 117 | MaxwellToVK::SurfaceFormat(device, FormatType::Buffer, params.pixel_format).format; | 118 | MaxwellToVK::SurfaceFormat(device, FormatType::Buffer, params.pixel_format).format; |
| 118 | return vk::BufferViewCreateInfo({}, buffer, format, 0, params.GetHostSizeInBytes()); | 119 | return vk::BufferViewCreateInfo({}, buffer, format, 0, host_memory_size); |
| 119 | } | 120 | } |
| 120 | 121 | ||
| 121 | vk::ImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceParams& params) { | 122 | vk::ImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceParams& params) { |
| @@ -169,14 +170,15 @@ CachedSurface::CachedSurface(Core::System& system, const VKDevice& device, | |||
| 169 | VKResourceManager& resource_manager, VKMemoryManager& memory_manager, | 170 | VKResourceManager& resource_manager, VKMemoryManager& memory_manager, |
| 170 | VKScheduler& scheduler, VKStagingBufferPool& staging_pool, | 171 | VKScheduler& scheduler, VKStagingBufferPool& staging_pool, |
| 171 | GPUVAddr gpu_addr, const SurfaceParams& params) | 172 | GPUVAddr gpu_addr, const SurfaceParams& params) |
| 172 | : SurfaceBase<View>{gpu_addr, params}, system{system}, device{device}, | 173 | : SurfaceBase<View>{gpu_addr, params, device.IsOptimalAstcSupported()}, system{system}, |
| 173 | resource_manager{resource_manager}, memory_manager{memory_manager}, scheduler{scheduler}, | 174 | device{device}, resource_manager{resource_manager}, |
| 174 | staging_pool{staging_pool} { | 175 | memory_manager{memory_manager}, scheduler{scheduler}, staging_pool{staging_pool} { |
| 175 | if (params.IsBuffer()) { | 176 | if (params.IsBuffer()) { |
| 176 | buffer = CreateBuffer(device, params); | 177 | buffer = CreateBuffer(device, params, host_memory_size); |
| 177 | commit = memory_manager.Commit(*buffer, false); | 178 | commit = memory_manager.Commit(*buffer, false); |
| 178 | 179 | ||
| 179 | const auto buffer_view_ci = GenerateBufferViewCreateInfo(device, params, *buffer); | 180 | const auto buffer_view_ci = |
| 181 | GenerateBufferViewCreateInfo(device, params, *buffer, host_memory_size); | ||
| 180 | format = buffer_view_ci.format; | 182 | format = buffer_view_ci.format; |
| 181 | 183 | ||
| 182 | const auto dev = device.GetLogical(); | 184 | const auto dev = device.GetLogical(); |
| @@ -255,7 +257,7 @@ void CachedSurface::UploadBuffer(const std::vector<u8>& staging_buffer) { | |||
| 255 | std::memcpy(src_buffer.commit->Map(host_memory_size), staging_buffer.data(), host_memory_size); | 257 | std::memcpy(src_buffer.commit->Map(host_memory_size), staging_buffer.data(), host_memory_size); |
| 256 | 258 | ||
| 257 | scheduler.Record([src_buffer = *src_buffer.handle, dst_buffer = *buffer, | 259 | scheduler.Record([src_buffer = *src_buffer.handle, dst_buffer = *buffer, |
| 258 | size = params.GetHostSizeInBytes()](auto cmdbuf, auto& dld) { | 260 | size = host_memory_size](auto cmdbuf, auto& dld) { |
| 259 | const vk::BufferCopy copy(0, 0, size); | 261 | const vk::BufferCopy copy(0, 0, size); |
| 260 | cmdbuf.copyBuffer(src_buffer, dst_buffer, {copy}, dld); | 262 | cmdbuf.copyBuffer(src_buffer, dst_buffer, {copy}, dld); |
| 261 | 263 | ||
| @@ -299,10 +301,7 @@ void CachedSurface::UploadImage(const std::vector<u8>& staging_buffer) { | |||
| 299 | 301 | ||
| 300 | vk::BufferImageCopy CachedSurface::GetBufferImageCopy(u32 level) const { | 302 | vk::BufferImageCopy CachedSurface::GetBufferImageCopy(u32 level) const { |
| 301 | const u32 vk_depth = params.target == SurfaceTarget::Texture3D ? params.GetMipDepth(level) : 1; | 303 | const u32 vk_depth = params.target == SurfaceTarget::Texture3D ? params.GetMipDepth(level) : 1; |
| 302 | const auto compression_type = params.GetCompressionType(); | 304 | const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level, is_converted); |
| 303 | const std::size_t mip_offset = compression_type == SurfaceCompression::Converted | ||
| 304 | ? params.GetConvertedMipmapOffset(level) | ||
| 305 | : params.GetHostMipmapLevelOffset(level); | ||
| 306 | 305 | ||
| 307 | return vk::BufferImageCopy( | 306 | return vk::BufferImageCopy( |
| 308 | mip_offset, 0, 0, | 307 | mip_offset, 0, 0, |
| @@ -390,8 +389,9 @@ VKTextureCache::VKTextureCache(Core::System& system, VideoCore::RasterizerInterf | |||
| 390 | const VKDevice& device, VKResourceManager& resource_manager, | 389 | const VKDevice& device, VKResourceManager& resource_manager, |
| 391 | VKMemoryManager& memory_manager, VKScheduler& scheduler, | 390 | VKMemoryManager& memory_manager, VKScheduler& scheduler, |
| 392 | VKStagingBufferPool& staging_pool) | 391 | VKStagingBufferPool& staging_pool) |
| 393 | : TextureCache(system, rasterizer), device{device}, resource_manager{resource_manager}, | 392 | : TextureCache(system, rasterizer, device.IsOptimalAstcSupported()), device{device}, |
| 394 | memory_manager{memory_manager}, scheduler{scheduler}, staging_pool{staging_pool} {} | 393 | resource_manager{resource_manager}, memory_manager{memory_manager}, scheduler{scheduler}, |
| 394 | staging_pool{staging_pool} {} | ||
| 395 | 395 | ||
| 396 | VKTextureCache::~VKTextureCache() = default; | 396 | VKTextureCache::~VKTextureCache() = default; |
| 397 | 397 | ||
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 8262d4d4b..d4f95b18c 100644 --- a/src/video_core/shader/decode/other.cpp +++ b/src/video_core/shader/decode/other.cpp | |||
| @@ -11,12 +11,17 @@ | |||
| 11 | 11 | ||
| 12 | namespace VideoCommon::Shader { | 12 | namespace VideoCommon::Shader { |
| 13 | 13 | ||
| 14 | using std::move; | ||
| 14 | using Tegra::Shader::ConditionCode; | 15 | using Tegra::Shader::ConditionCode; |
| 15 | using Tegra::Shader::Instruction; | 16 | using Tegra::Shader::Instruction; |
| 17 | using Tegra::Shader::IpaInterpMode; | ||
| 16 | using Tegra::Shader::OpCode; | 18 | using Tegra::Shader::OpCode; |
| 19 | using Tegra::Shader::PixelImap; | ||
| 17 | using Tegra::Shader::Register; | 20 | using Tegra::Shader::Register; |
| 18 | using Tegra::Shader::SystemVariable; | 21 | using Tegra::Shader::SystemVariable; |
| 19 | 22 | ||
| 23 | using Index = Tegra::Shader::Attribute::Index; | ||
| 24 | |||
| 20 | u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { | 25 | u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { |
| 21 | const Instruction instr = {program_code[pc]}; | 26 | const Instruction instr = {program_code[pc]}; |
| 22 | const auto opcode = OpCode::Decode(instr); | 27 | const auto opcode = OpCode::Decode(instr); |
| @@ -219,27 +224,28 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { | |||
| 219 | } | 224 | } |
| 220 | case OpCode::Id::IPA: { | 225 | case OpCode::Id::IPA: { |
| 221 | const bool is_physical = instr.ipa.idx && instr.gpr8.Value() != 0xff; | 226 | const bool is_physical = instr.ipa.idx && instr.gpr8.Value() != 0xff; |
| 222 | |||
| 223 | const auto attribute = instr.attribute.fmt28; | 227 | const auto attribute = instr.attribute.fmt28; |
| 224 | const Tegra::Shader::IpaMode input_mode{instr.ipa.interp_mode.Value(), | 228 | const Index index = attribute.index; |
| 225 | instr.ipa.sample_mode.Value()}; | ||
| 226 | 229 | ||
| 227 | Node value = is_physical ? GetPhysicalInputAttribute(instr.gpr8) | 230 | Node value = is_physical ? GetPhysicalInputAttribute(instr.gpr8) |
| 228 | : GetInputAttribute(attribute.index, attribute.element); | 231 | : GetInputAttribute(index, attribute.element); |
| 229 | const Tegra::Shader::Attribute::Index index = attribute.index.Value(); | 232 | |
| 230 | const bool is_generic = index >= Tegra::Shader::Attribute::Index::Attribute_0 && | 233 | // Code taken from Ryujinx. |
| 231 | index <= Tegra::Shader::Attribute::Index::Attribute_31; | 234 | if (index >= Index::Attribute_0 && index <= Index::Attribute_31) { |
| 232 | if (is_generic || is_physical) { | 235 | const u32 location = static_cast<u32>(index) - static_cast<u32>(Index::Attribute_0); |
| 233 | // TODO(Blinkhawk): There are cases where a perspective attribute use PASS. | 236 | if (header.ps.GetPixelImap(location) == PixelImap::Perspective) { |
| 234 | // In theory by setting them as perspective, OpenGL does the perspective correction. | 237 | Node position_w = GetInputAttribute(Index::Position, 3); |
| 235 | // A way must figured to reverse the last step of it. | 238 | value = Operation(OperationCode::FMul, move(value), move(position_w)); |
| 236 | if (input_mode.interpolation_mode == Tegra::Shader::IpaInterpMode::Multiply) { | ||
| 237 | value = Operation(OperationCode::FMul, PRECISE, value, GetRegister(instr.gpr20)); | ||
| 238 | } | 239 | } |
| 239 | } | 240 | } |
| 240 | value = GetSaturatedFloat(value, instr.ipa.saturate); | ||
| 241 | 241 | ||
| 242 | SetRegister(bb, instr.gpr0, value); | 242 | if (instr.ipa.interp_mode == IpaInterpMode::Multiply) { |
| 243 | value = Operation(OperationCode::FMul, move(value), GetRegister(instr.gpr20)); | ||
| 244 | } | ||
| 245 | |||
| 246 | value = GetSaturatedFloat(move(value), instr.ipa.saturate); | ||
| 247 | |||
| 248 | SetRegister(bb, instr.gpr0, move(value)); | ||
| 243 | break; | 249 | break; |
| 244 | } | 250 | } |
| 245 | case OpCode::Id::OUT_R: { | 251 | case OpCode::Id::OUT_R: { |
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/surface.h b/src/video_core/surface.h index ae8817465..e0acd44d3 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h | |||
| @@ -504,103 +504,6 @@ static constexpr u32 GetBytesPerPixel(PixelFormat pixel_format) { | |||
| 504 | return GetFormatBpp(pixel_format) / CHAR_BIT; | 504 | return GetFormatBpp(pixel_format) / CHAR_BIT; |
| 505 | } | 505 | } |
| 506 | 506 | ||
| 507 | enum class SurfaceCompression { | ||
| 508 | None, // Not compressed | ||
| 509 | Compressed, // Texture is compressed | ||
| 510 | Converted, // Texture is converted before upload or after download | ||
| 511 | Rearranged, // Texture is swizzled before upload or after download | ||
| 512 | }; | ||
| 513 | |||
| 514 | constexpr std::array<SurfaceCompression, MaxPixelFormat> compression_type_table = {{ | ||
| 515 | SurfaceCompression::None, // ABGR8U | ||
| 516 | SurfaceCompression::None, // ABGR8S | ||
| 517 | SurfaceCompression::None, // ABGR8UI | ||
| 518 | SurfaceCompression::None, // B5G6R5U | ||
| 519 | SurfaceCompression::None, // A2B10G10R10U | ||
| 520 | SurfaceCompression::None, // A1B5G5R5U | ||
| 521 | SurfaceCompression::None, // R8U | ||
| 522 | SurfaceCompression::None, // R8UI | ||
| 523 | SurfaceCompression::None, // RGBA16F | ||
| 524 | SurfaceCompression::None, // RGBA16U | ||
| 525 | SurfaceCompression::None, // RGBA16S | ||
| 526 | SurfaceCompression::None, // RGBA16UI | ||
| 527 | SurfaceCompression::None, // R11FG11FB10F | ||
| 528 | SurfaceCompression::None, // RGBA32UI | ||
| 529 | SurfaceCompression::Compressed, // DXT1 | ||
| 530 | SurfaceCompression::Compressed, // DXT23 | ||
| 531 | SurfaceCompression::Compressed, // DXT45 | ||
| 532 | SurfaceCompression::Compressed, // DXN1 | ||
| 533 | SurfaceCompression::Compressed, // DXN2UNORM | ||
| 534 | SurfaceCompression::Compressed, // DXN2SNORM | ||
| 535 | SurfaceCompression::Compressed, // BC7U | ||
| 536 | SurfaceCompression::Compressed, // BC6H_UF16 | ||
| 537 | SurfaceCompression::Compressed, // BC6H_SF16 | ||
| 538 | SurfaceCompression::Converted, // ASTC_2D_4X4 | ||
| 539 | SurfaceCompression::None, // BGRA8 | ||
| 540 | SurfaceCompression::None, // RGBA32F | ||
| 541 | SurfaceCompression::None, // RG32F | ||
| 542 | SurfaceCompression::None, // R32F | ||
| 543 | SurfaceCompression::None, // R16F | ||
| 544 | SurfaceCompression::None, // R16U | ||
| 545 | SurfaceCompression::None, // R16S | ||
| 546 | SurfaceCompression::None, // R16UI | ||
| 547 | SurfaceCompression::None, // R16I | ||
| 548 | SurfaceCompression::None, // RG16 | ||
| 549 | SurfaceCompression::None, // RG16F | ||
| 550 | SurfaceCompression::None, // RG16UI | ||
| 551 | SurfaceCompression::None, // RG16I | ||
| 552 | SurfaceCompression::None, // RG16S | ||
| 553 | SurfaceCompression::None, // RGB32F | ||
| 554 | SurfaceCompression::None, // RGBA8_SRGB | ||
| 555 | SurfaceCompression::None, // RG8U | ||
| 556 | SurfaceCompression::None, // RG8S | ||
| 557 | SurfaceCompression::None, // RG32UI | ||
| 558 | SurfaceCompression::None, // RGBX16F | ||
| 559 | SurfaceCompression::None, // R32UI | ||
| 560 | SurfaceCompression::None, // R32I | ||
| 561 | SurfaceCompression::Converted, // ASTC_2D_8X8 | ||
| 562 | SurfaceCompression::Converted, // ASTC_2D_8X5 | ||
| 563 | SurfaceCompression::Converted, // ASTC_2D_5X4 | ||
| 564 | SurfaceCompression::None, // BGRA8_SRGB | ||
| 565 | SurfaceCompression::Compressed, // DXT1_SRGB | ||
| 566 | SurfaceCompression::Compressed, // DXT23_SRGB | ||
| 567 | SurfaceCompression::Compressed, // DXT45_SRGB | ||
| 568 | SurfaceCompression::Compressed, // BC7U_SRGB | ||
| 569 | SurfaceCompression::None, // R4G4B4A4U | ||
| 570 | SurfaceCompression::Converted, // ASTC_2D_4X4_SRGB | ||
| 571 | SurfaceCompression::Converted, // ASTC_2D_8X8_SRGB | ||
| 572 | SurfaceCompression::Converted, // ASTC_2D_8X5_SRGB | ||
| 573 | SurfaceCompression::Converted, // ASTC_2D_5X4_SRGB | ||
| 574 | SurfaceCompression::Converted, // ASTC_2D_5X5 | ||
| 575 | SurfaceCompression::Converted, // ASTC_2D_5X5_SRGB | ||
| 576 | SurfaceCompression::Converted, // ASTC_2D_10X8 | ||
| 577 | SurfaceCompression::Converted, // ASTC_2D_10X8_SRGB | ||
| 578 | SurfaceCompression::Converted, // ASTC_2D_6X6 | ||
| 579 | SurfaceCompression::Converted, // ASTC_2D_6X6_SRGB | ||
| 580 | SurfaceCompression::Converted, // ASTC_2D_10X10 | ||
| 581 | SurfaceCompression::Converted, // ASTC_2D_10X10_SRGB | ||
| 582 | SurfaceCompression::Converted, // ASTC_2D_12X12 | ||
| 583 | SurfaceCompression::Converted, // ASTC_2D_12X12_SRGB | ||
| 584 | SurfaceCompression::Converted, // ASTC_2D_8X6 | ||
| 585 | SurfaceCompression::Converted, // ASTC_2D_8X6_SRGB | ||
| 586 | SurfaceCompression::Converted, // ASTC_2D_6X5 | ||
| 587 | SurfaceCompression::Converted, // ASTC_2D_6X5_SRGB | ||
| 588 | SurfaceCompression::None, // E5B9G9R9F | ||
| 589 | SurfaceCompression::None, // Z32F | ||
| 590 | SurfaceCompression::None, // Z16 | ||
| 591 | SurfaceCompression::None, // Z24S8 | ||
| 592 | SurfaceCompression::Rearranged, // S8Z24 | ||
| 593 | SurfaceCompression::None, // Z32FS8 | ||
| 594 | }}; | ||
| 595 | |||
| 596 | constexpr SurfaceCompression GetFormatCompressionType(PixelFormat format) { | ||
| 597 | if (format == PixelFormat::Invalid) { | ||
| 598 | return SurfaceCompression::None; | ||
| 599 | } | ||
| 600 | DEBUG_ASSERT(static_cast<std::size_t>(format) < compression_type_table.size()); | ||
| 601 | return compression_type_table[static_cast<std::size_t>(format)]; | ||
| 602 | } | ||
| 603 | |||
| 604 | SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type); | 507 | SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type); |
| 605 | 508 | ||
| 606 | bool SurfaceTargetIsLayered(SurfaceTarget target); | 509 | bool SurfaceTargetIsLayered(SurfaceTarget target); |
diff --git a/src/video_core/texture_cache/surface_base.cpp b/src/video_core/texture_cache/surface_base.cpp index 002df414f..6fe815135 100644 --- a/src/video_core/texture_cache/surface_base.cpp +++ b/src/video_core/texture_cache/surface_base.cpp | |||
| @@ -18,15 +18,20 @@ MICROPROFILE_DEFINE(GPU_Flush_Texture, "GPU", "Texture Flush", MP_RGB(128, 192, | |||
| 18 | 18 | ||
| 19 | using Tegra::Texture::ConvertFromGuestToHost; | 19 | using Tegra::Texture::ConvertFromGuestToHost; |
| 20 | using VideoCore::MortonSwizzleMode; | 20 | using VideoCore::MortonSwizzleMode; |
| 21 | using VideoCore::Surface::SurfaceCompression; | 21 | using VideoCore::Surface::IsPixelFormatASTC; |
| 22 | using VideoCore::Surface::PixelFormat; | ||
| 22 | 23 | ||
| 23 | StagingCache::StagingCache() = default; | 24 | StagingCache::StagingCache() = default; |
| 24 | 25 | ||
| 25 | StagingCache::~StagingCache() = default; | 26 | StagingCache::~StagingCache() = default; |
| 26 | 27 | ||
| 27 | SurfaceBaseImpl::SurfaceBaseImpl(GPUVAddr gpu_addr, const SurfaceParams& params) | 28 | SurfaceBaseImpl::SurfaceBaseImpl(GPUVAddr gpu_addr, const SurfaceParams& params, |
| 28 | : params{params}, host_memory_size{params.GetHostSizeInBytes()}, gpu_addr{gpu_addr}, | 29 | bool is_astc_supported) |
| 29 | mipmap_sizes(params.num_levels), mipmap_offsets(params.num_levels) { | 30 | : params{params}, gpu_addr{gpu_addr}, mipmap_sizes(params.num_levels), |
| 31 | mipmap_offsets(params.num_levels) { | ||
| 32 | is_converted = IsPixelFormatASTC(params.pixel_format) && !is_astc_supported; | ||
| 33 | host_memory_size = params.GetHostSizeInBytes(is_converted); | ||
| 34 | |||
| 30 | std::size_t offset = 0; | 35 | std::size_t offset = 0; |
| 31 | for (u32 level = 0; level < params.num_levels; ++level) { | 36 | for (u32 level = 0; level < params.num_levels; ++level) { |
| 32 | const std::size_t mipmap_size{params.GetGuestMipmapSize(level)}; | 37 | const std::size_t mipmap_size{params.GetGuestMipmapSize(level)}; |
| @@ -164,7 +169,7 @@ void SurfaceBaseImpl::SwizzleFunc(MortonSwizzleMode mode, u8* memory, const Surf | |||
| 164 | 169 | ||
| 165 | std::size_t guest_offset{mipmap_offsets[level]}; | 170 | std::size_t guest_offset{mipmap_offsets[level]}; |
| 166 | if (params.is_layered) { | 171 | if (params.is_layered) { |
| 167 | std::size_t host_offset{0}; | 172 | std::size_t host_offset = 0; |
| 168 | const std::size_t guest_stride = layer_size; | 173 | const std::size_t guest_stride = layer_size; |
| 169 | const std::size_t host_stride = params.GetHostLayerSize(level); | 174 | const std::size_t host_stride = params.GetHostLayerSize(level); |
| 170 | for (u32 layer = 0; layer < params.depth; ++layer) { | 175 | for (u32 layer = 0; layer < params.depth; ++layer) { |
| @@ -206,7 +211,7 @@ void SurfaceBaseImpl::LoadBuffer(Tegra::MemoryManager& memory_manager, | |||
| 206 | ASSERT_MSG(params.block_width == 0, "Block width is defined as {} on texture target {}", | 211 | ASSERT_MSG(params.block_width == 0, "Block width is defined as {} on texture target {}", |
| 207 | params.block_width, static_cast<u32>(params.target)); | 212 | params.block_width, static_cast<u32>(params.target)); |
| 208 | for (u32 level = 0; level < params.num_levels; ++level) { | 213 | for (u32 level = 0; level < params.num_levels; ++level) { |
| 209 | const std::size_t host_offset{params.GetHostMipmapLevelOffset(level)}; | 214 | const std::size_t host_offset{params.GetHostMipmapLevelOffset(level, false)}; |
| 210 | SwizzleFunc(MortonSwizzleMode::MortonToLinear, host_ptr, params, | 215 | SwizzleFunc(MortonSwizzleMode::MortonToLinear, host_ptr, params, |
| 211 | staging_buffer.data() + host_offset, level); | 216 | staging_buffer.data() + host_offset, level); |
| 212 | } | 217 | } |
| @@ -219,7 +224,7 @@ void SurfaceBaseImpl::LoadBuffer(Tegra::MemoryManager& memory_manager, | |||
| 219 | const u32 height{(params.height + block_height - 1) / block_height}; | 224 | const u32 height{(params.height + block_height - 1) / block_height}; |
| 220 | const u32 copy_size{width * bpp}; | 225 | const u32 copy_size{width * bpp}; |
| 221 | if (params.pitch == copy_size) { | 226 | if (params.pitch == copy_size) { |
| 222 | std::memcpy(staging_buffer.data(), host_ptr, params.GetHostSizeInBytes()); | 227 | std::memcpy(staging_buffer.data(), host_ptr, params.GetHostSizeInBytes(false)); |
| 223 | } else { | 228 | } else { |
| 224 | const u8* start{host_ptr}; | 229 | const u8* start{host_ptr}; |
| 225 | u8* write_to{staging_buffer.data()}; | 230 | u8* write_to{staging_buffer.data()}; |
| @@ -231,19 +236,15 @@ void SurfaceBaseImpl::LoadBuffer(Tegra::MemoryManager& memory_manager, | |||
| 231 | } | 236 | } |
| 232 | } | 237 | } |
| 233 | 238 | ||
| 234 | auto compression_type = params.GetCompressionType(); | 239 | if (!is_converted && params.pixel_format != PixelFormat::S8Z24) { |
| 235 | if (compression_type == SurfaceCompression::None || | ||
| 236 | compression_type == SurfaceCompression::Compressed) | ||
| 237 | return; | 240 | return; |
| 241 | } | ||
| 238 | 242 | ||
| 239 | for (u32 level_up = params.num_levels; level_up > 0; --level_up) { | 243 | for (u32 level = params.num_levels; level--;) { |
| 240 | const u32 level = level_up - 1; | 244 | const std::size_t in_host_offset{params.GetHostMipmapLevelOffset(level, false)}; |
| 241 | const std::size_t in_host_offset{params.GetHostMipmapLevelOffset(level)}; | 245 | const std::size_t out_host_offset{params.GetHostMipmapLevelOffset(level, is_converted)}; |
| 242 | const std::size_t out_host_offset = compression_type == SurfaceCompression::Rearranged | 246 | u8* const in_buffer = staging_buffer.data() + in_host_offset; |
| 243 | ? in_host_offset | 247 | u8* const out_buffer = staging_buffer.data() + out_host_offset; |
| 244 | : params.GetConvertedMipmapOffset(level); | ||
| 245 | u8* in_buffer = staging_buffer.data() + in_host_offset; | ||
| 246 | u8* out_buffer = staging_buffer.data() + out_host_offset; | ||
| 247 | ConvertFromGuestToHost(in_buffer, out_buffer, params.pixel_format, | 248 | ConvertFromGuestToHost(in_buffer, out_buffer, params.pixel_format, |
| 248 | params.GetMipWidth(level), params.GetMipHeight(level), | 249 | params.GetMipWidth(level), params.GetMipHeight(level), |
| 249 | params.GetMipDepth(level), true, true); | 250 | params.GetMipDepth(level), true, true); |
| @@ -273,7 +274,7 @@ void SurfaceBaseImpl::FlushBuffer(Tegra::MemoryManager& memory_manager, | |||
| 273 | if (params.is_tiled) { | 274 | if (params.is_tiled) { |
| 274 | ASSERT_MSG(params.block_width == 0, "Block width is defined as {}", params.block_width); | 275 | ASSERT_MSG(params.block_width == 0, "Block width is defined as {}", params.block_width); |
| 275 | for (u32 level = 0; level < params.num_levels; ++level) { | 276 | for (u32 level = 0; level < params.num_levels; ++level) { |
| 276 | const std::size_t host_offset{params.GetHostMipmapLevelOffset(level)}; | 277 | const std::size_t host_offset{params.GetHostMipmapLevelOffset(level, false)}; |
| 277 | SwizzleFunc(MortonSwizzleMode::LinearToMorton, host_ptr, params, | 278 | SwizzleFunc(MortonSwizzleMode::LinearToMorton, host_ptr, params, |
| 278 | staging_buffer.data() + host_offset, level); | 279 | staging_buffer.data() + host_offset, level); |
| 279 | } | 280 | } |
diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h index 5f79bb0aa..d7882a031 100644 --- a/src/video_core/texture_cache/surface_base.h +++ b/src/video_core/texture_cache/surface_base.h | |||
| @@ -131,6 +131,10 @@ public: | |||
| 131 | return !params.is_tiled; | 131 | return !params.is_tiled; |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | bool IsConverted() const { | ||
| 135 | return is_converted; | ||
| 136 | } | ||
| 137 | |||
| 134 | bool MatchFormat(VideoCore::Surface::PixelFormat pixel_format) const { | 138 | bool MatchFormat(VideoCore::Surface::PixelFormat pixel_format) const { |
| 135 | return params.pixel_format == pixel_format; | 139 | return params.pixel_format == pixel_format; |
| 136 | } | 140 | } |
| @@ -160,7 +164,8 @@ public: | |||
| 160 | } | 164 | } |
| 161 | 165 | ||
| 162 | protected: | 166 | protected: |
| 163 | explicit SurfaceBaseImpl(GPUVAddr gpu_addr, const SurfaceParams& params); | 167 | explicit SurfaceBaseImpl(GPUVAddr gpu_addr, const SurfaceParams& params, |
| 168 | bool is_astc_supported); | ||
| 164 | ~SurfaceBaseImpl() = default; | 169 | ~SurfaceBaseImpl() = default; |
| 165 | 170 | ||
| 166 | virtual void DecorateSurfaceName() = 0; | 171 | virtual void DecorateSurfaceName() = 0; |
| @@ -168,12 +173,13 @@ protected: | |||
| 168 | const SurfaceParams params; | 173 | const SurfaceParams params; |
| 169 | std::size_t layer_size; | 174 | std::size_t layer_size; |
| 170 | std::size_t guest_memory_size; | 175 | std::size_t guest_memory_size; |
| 171 | const std::size_t host_memory_size; | 176 | std::size_t host_memory_size; |
| 172 | GPUVAddr gpu_addr{}; | 177 | GPUVAddr gpu_addr{}; |
| 173 | CacheAddr cache_addr{}; | 178 | CacheAddr cache_addr{}; |
| 174 | CacheAddr cache_addr_end{}; | 179 | CacheAddr cache_addr_end{}; |
| 175 | VAddr cpu_addr{}; | 180 | VAddr cpu_addr{}; |
| 176 | bool is_continuous{}; | 181 | bool is_continuous{}; |
| 182 | bool is_converted{}; | ||
| 177 | 183 | ||
| 178 | std::vector<std::size_t> mipmap_sizes; | 184 | std::vector<std::size_t> mipmap_sizes; |
| 179 | std::vector<std::size_t> mipmap_offsets; | 185 | std::vector<std::size_t> mipmap_offsets; |
| @@ -288,8 +294,9 @@ public: | |||
| 288 | } | 294 | } |
| 289 | 295 | ||
| 290 | protected: | 296 | protected: |
| 291 | explicit SurfaceBase(const GPUVAddr gpu_addr, const SurfaceParams& params) | 297 | explicit SurfaceBase(const GPUVAddr gpu_addr, const SurfaceParams& params, |
| 292 | : SurfaceBaseImpl(gpu_addr, params) {} | 298 | bool is_astc_supported) |
| 299 | : SurfaceBaseImpl(gpu_addr, params, is_astc_supported) {} | ||
| 293 | 300 | ||
| 294 | ~SurfaceBase() = default; | 301 | ~SurfaceBase() = default; |
| 295 | 302 | ||
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index 9931c5ef7..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; |
| @@ -309,28 +307,26 @@ std::size_t SurfaceParams::GetGuestMipmapLevelOffset(u32 level) const { | |||
| 309 | return offset; | 307 | return offset; |
| 310 | } | 308 | } |
| 311 | 309 | ||
| 312 | std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const { | 310 | std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level, bool is_converted) const { |
| 313 | std::size_t offset = 0; | ||
| 314 | for (u32 i = 0; i < level; i++) { | ||
| 315 | offset += GetInnerMipmapMemorySize(i, true, false) * GetNumLayers(); | ||
| 316 | } | ||
| 317 | return offset; | ||
| 318 | } | ||
| 319 | |||
| 320 | std::size_t SurfaceParams::GetConvertedMipmapOffset(u32 level) const { | ||
| 321 | std::size_t offset = 0; | 311 | std::size_t offset = 0; |
| 322 | for (u32 i = 0; i < level; i++) { | 312 | if (is_converted) { |
| 323 | offset += GetConvertedMipmapSize(i); | 313 | for (u32 i = 0; i < level; ++i) { |
| 314 | offset += GetConvertedMipmapSize(i) * GetNumLayers(); | ||
| 315 | } | ||
| 316 | } else { | ||
| 317 | for (u32 i = 0; i < level; ++i) { | ||
| 318 | offset += GetInnerMipmapMemorySize(i, true, false) * GetNumLayers(); | ||
| 319 | } | ||
| 324 | } | 320 | } |
| 325 | return offset; | 321 | return offset; |
| 326 | } | 322 | } |
| 327 | 323 | ||
| 328 | std::size_t SurfaceParams::GetConvertedMipmapSize(u32 level) const { | 324 | std::size_t SurfaceParams::GetConvertedMipmapSize(u32 level) const { |
| 329 | constexpr std::size_t rgba8_bpp = 4ULL; | 325 | constexpr std::size_t rgba8_bpp = 4ULL; |
| 330 | const std::size_t width_t = GetMipWidth(level); | 326 | const std::size_t mip_width = GetMipWidth(level); |
| 331 | const std::size_t height_t = GetMipHeight(level); | 327 | const std::size_t mip_height = GetMipHeight(level); |
| 332 | const std::size_t depth_t = is_layered ? depth : GetMipDepth(level); | 328 | const std::size_t mip_depth = is_layered ? 1 : GetMipDepth(level); |
| 333 | return width_t * height_t * depth_t * rgba8_bpp; | 329 | return mip_width * mip_height * mip_depth * rgba8_bpp; |
| 334 | } | 330 | } |
| 335 | 331 | ||
| 336 | std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) const { | 332 | std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) const { |
diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h index 995cc3818..24957df8d 100644 --- a/src/video_core/texture_cache/surface_params.h +++ b/src/video_core/texture_cache/surface_params.h | |||
| @@ -20,8 +20,6 @@ namespace VideoCommon { | |||
| 20 | 20 | ||
| 21 | class FormatLookupTable; | 21 | class FormatLookupTable; |
| 22 | 22 | ||
| 23 | using VideoCore::Surface::SurfaceCompression; | ||
| 24 | |||
| 25 | class SurfaceParams { | 23 | class SurfaceParams { |
| 26 | public: | 24 | public: |
| 27 | /// Creates SurfaceCachedParams from a texture configuration. | 25 | /// Creates SurfaceCachedParams from a texture configuration. |
| @@ -67,16 +65,14 @@ public: | |||
| 67 | return GetInnerMemorySize(false, false, false); | 65 | return GetInnerMemorySize(false, false, false); |
| 68 | } | 66 | } |
| 69 | 67 | ||
| 70 | std::size_t GetHostSizeInBytes() const { | 68 | std::size_t GetHostSizeInBytes(bool is_converted) const { |
| 71 | std::size_t host_size_in_bytes; | 69 | if (!is_converted) { |
| 72 | if (GetCompressionType() == SurfaceCompression::Converted) { | 70 | return GetInnerMemorySize(true, false, false); |
| 73 | // ASTC is uncompressed in software, in emulated as RGBA8 | 71 | } |
| 74 | host_size_in_bytes = 0; | 72 | // ASTC is uncompressed in software, in emulated as RGBA8 |
| 75 | for (u32 level = 0; level < num_levels; ++level) { | 73 | std::size_t host_size_in_bytes = 0; |
| 76 | host_size_in_bytes += GetConvertedMipmapSize(level); | 74 | for (u32 level = 0; level < num_levels; ++level) { |
| 77 | } | 75 | host_size_in_bytes += GetConvertedMipmapSize(level) * GetNumLayers(); |
| 78 | } else { | ||
| 79 | host_size_in_bytes = GetInnerMemorySize(true, false, false); | ||
| 80 | } | 76 | } |
| 81 | return host_size_in_bytes; | 77 | return host_size_in_bytes; |
| 82 | } | 78 | } |
| @@ -107,9 +103,8 @@ public: | |||
| 107 | u32 GetMipBlockDepth(u32 level) const; | 103 | u32 GetMipBlockDepth(u32 level) const; |
| 108 | 104 | ||
| 109 | /// Returns the best possible row/pitch alignment for the surface. | 105 | /// Returns the best possible row/pitch alignment for the surface. |
| 110 | u32 GetRowAlignment(u32 level) const { | 106 | u32 GetRowAlignment(u32 level, bool is_converted) const { |
| 111 | const u32 bpp = | 107 | const u32 bpp = is_converted ? 4 : GetBytesPerPixel(); |
| 112 | GetCompressionType() == SurfaceCompression::Converted ? 4 : GetBytesPerPixel(); | ||
| 113 | return 1U << Common::CountTrailingZeroes32(GetMipWidth(level) * bpp); | 108 | return 1U << Common::CountTrailingZeroes32(GetMipWidth(level) * bpp); |
| 114 | } | 109 | } |
| 115 | 110 | ||
| @@ -117,11 +112,7 @@ public: | |||
| 117 | std::size_t GetGuestMipmapLevelOffset(u32 level) const; | 112 | std::size_t GetGuestMipmapLevelOffset(u32 level) const; |
| 118 | 113 | ||
| 119 | /// Returns the offset in bytes in host memory (linear) of a given mipmap level. | 114 | /// Returns the offset in bytes in host memory (linear) of a given mipmap level. |
| 120 | std::size_t GetHostMipmapLevelOffset(u32 level) const; | 115 | std::size_t GetHostMipmapLevelOffset(u32 level, bool is_converted) const; |
| 121 | |||
| 122 | /// Returns the offset in bytes in host memory (linear) of a given mipmap level | ||
| 123 | /// for a texture that is converted in host gpu. | ||
| 124 | std::size_t GetConvertedMipmapOffset(u32 level) const; | ||
| 125 | 116 | ||
| 126 | /// Returns the size in bytes in guest memory of a given mipmap level. | 117 | /// Returns the size in bytes in guest memory of a given mipmap level. |
| 127 | std::size_t GetGuestMipmapSize(u32 level) const { | 118 | std::size_t GetGuestMipmapSize(u32 level) const { |
| @@ -196,11 +187,6 @@ public: | |||
| 196 | pixel_format < VideoCore::Surface::PixelFormat::MaxDepthStencilFormat; | 187 | pixel_format < VideoCore::Surface::PixelFormat::MaxDepthStencilFormat; |
| 197 | } | 188 | } |
| 198 | 189 | ||
| 199 | /// Returns how the compression should be handled for this texture. | ||
| 200 | SurfaceCompression GetCompressionType() const { | ||
| 201 | return VideoCore::Surface::GetFormatCompressionType(pixel_format); | ||
| 202 | } | ||
| 203 | |||
| 204 | /// Returns is the surface is a TextureBuffer type of surface. | 190 | /// Returns is the surface is a TextureBuffer type of surface. |
| 205 | bool IsBuffer() const { | 191 | bool IsBuffer() const { |
| 206 | return target == VideoCore::Surface::SurfaceTarget::TextureBuffer; | 192 | return target == VideoCore::Surface::SurfaceTarget::TextureBuffer; |
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 6cdbe63d0..c8f8d659d 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -289,8 +289,9 @@ public: | |||
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | protected: | 291 | protected: |
| 292 | TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer) | 292 | explicit TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer, |
| 293 | : system{system}, rasterizer{rasterizer} { | 293 | bool is_astc_supported) |
| 294 | : system{system}, is_astc_supported{is_astc_supported}, rasterizer{rasterizer} { | ||
| 294 | for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { | 295 | for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { |
| 295 | SetEmptyColorBuffer(i); | 296 | SetEmptyColorBuffer(i); |
| 296 | } | 297 | } |
| @@ -381,6 +382,7 @@ protected: | |||
| 381 | } | 382 | } |
| 382 | 383 | ||
| 383 | Core::System& system; | 384 | Core::System& system; |
| 385 | const bool is_astc_supported; | ||
| 384 | 386 | ||
| 385 | private: | 387 | private: |
| 386 | enum class RecycleStrategy : u32 { | 388 | enum class RecycleStrategy : u32 { |
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); |