summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/file_util.cpp22
-rw-r--r--src/common/thread.cpp9
-rw-r--r--src/core/file_sys/romfs.cpp3
-rw-r--r--src/video_core/engines/shader_header.h55
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp26
-rw-r--r--src/video_core/renderer_opengl/gl_device.h5
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp34
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp211
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h6
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp45
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp17
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp34
-rw-r--r--src/video_core/shader/decode/image.cpp360
-rw-r--r--src/video_core/shader/decode/other.cpp36
-rw-r--r--src/video_core/shader/shader_ir.h4
-rw-r--r--src/video_core/surface.h97
-rw-r--r--src/video_core/texture_cache/surface_base.cpp39
-rw-r--r--src/video_core/texture_cache/surface_base.h15
-rw-r--r--src/video_core/texture_cache/surface_params.cpp34
-rw-r--r--src/video_core/texture_cache/surface_params.h36
-rw-r--r--src/video_core/texture_cache/texture_cache.h6
-rw-r--r--src/yuzu/about_dialog.cpp9
-rw-r--r--src/yuzu/configuration/configure_input_player.ui4
-rw-r--r--src/yuzu/main.cpp8
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) {
530std::optional<std::string> GetCurrentDir() { 531std::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
919bool IOFile::Open(const std::string& filename, const char openmode[], int flags) { 920bool 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
936bool IOFile::Close() { 940bool 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
962bool IOFile::Flush() { 966bool 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
36void SetCurrentThreadName(const char* name) { 33void 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
19enum class AttributeUse : u8 { 22enum 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
28struct Header { 31struct 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
134bool 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
136Device::Device() : base_bindings{BuildBaseBindings()} { 161Device::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
32using Tegra::Engines::ShaderType; 32using Tegra::Engines::ShaderType;
33using Tegra::Shader::Attribute; 33using Tegra::Shader::Attribute;
34using Tegra::Shader::AttributeUse;
35using Tegra::Shader::Header; 34using Tegra::Shader::Header;
36using Tegra::Shader::IpaInterpMode; 35using Tegra::Shader::IpaInterpMode;
37using Tegra::Shader::IpaMode; 36using Tegra::Shader::IpaMode;
38using Tegra::Shader::IpaSampleMode; 37using Tegra::Shader::IpaSampleMode;
38using Tegra::Shader::PixelImap;
39using Tegra::Shader::Register; 39using Tegra::Shader::Register;
40using VideoCommon::Shader::BuildTransformFeedback; 40using VideoCommon::Shader::BuildTransformFeedback;
41using VideoCommon::Shader::Registry; 41using 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;
24using VideoCore::MortonSwizzleMode; 24using VideoCore::MortonSwizzleMode;
25 25
26using VideoCore::Surface::PixelFormat; 26using VideoCore::Surface::PixelFormat;
27using VideoCore::Surface::SurfaceCompression;
28using VideoCore::Surface::SurfaceTarget; 27using VideoCore::Surface::SurfaceTarget;
29using VideoCore::Surface::SurfaceType; 28using VideoCore::Surface::SurfaceType;
30 29
@@ -37,102 +36,100 @@ namespace {
37 36
38struct FormatTuple { 37struct 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
45constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{ 43constexpr 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
132const FormatTuple& GetFormatTuple(PixelFormat pixel_format) { 130const 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
138GLenum GetTextureTarget(const SurfaceTarget& target) { 135GLenum 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
245CachedSurface::CachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params) 242CachedSurface::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
296void CachedSurface::UploadTextureMipmap(u32 level, const std::vector<u8>& staging_buffer) { 301void 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 {
482TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system, 483TextureCacheOpenGL::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,
490TextureCacheOpenGL::~TextureCacheOpenGL() = default; 491TextureCacheOpenGL::~TextureCacheOpenGL() = default;
491 492
492Surface TextureCacheOpenGL::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) { 493Surface 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
496void TextureCacheOpenGL::ImageCopy(Surface& src_surface, Surface& dst_surface, 497void 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
39public: 39public:
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
54protected: 58protected:
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
238bool VKDevice::IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features, 238bool 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 {
35using Sirit::Id; 35using Sirit::Id;
36using Tegra::Engines::ShaderType; 36using Tegra::Engines::ShaderType;
37using Tegra::Shader::Attribute; 37using Tegra::Shader::Attribute;
38using Tegra::Shader::AttributeUse; 38using Tegra::Shader::PixelImap;
39using Tegra::Shader::Register; 39using Tegra::Shader::Register;
40using namespace VideoCommon::Shader; 40using 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
36using Tegra::Texture::SwizzleSource; 36using Tegra::Texture::SwizzleSource;
37using VideoCore::Surface::PixelFormat; 37using VideoCore::Surface::PixelFormat;
38using VideoCore::Surface::SurfaceCompression;
39using VideoCore::Surface::SurfaceTarget; 38using VideoCore::Surface::SurfaceTarget;
40 39
41namespace { 40namespace {
@@ -96,9 +95,10 @@ vk::ImageViewType GetImageViewType(SurfaceTarget target) {
96 return {}; 95 return {};
97} 96}
98 97
99UniqueBuffer CreateBuffer(const VKDevice& device, const SurfaceParams& params) { 98UniqueBuffer 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
111vk::BufferViewCreateInfo GenerateBufferViewCreateInfo(const VKDevice& device, 111vk::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
121vk::ImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceParams& params) { 122vk::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
300vk::BufferImageCopy CachedSurface::GetBufferImageCopy(u32 level) const { 302vk::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
396VKTextureCache::~VKTextureCache() = default; 396VKTextureCache::~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
17namespace VideoCommon::Shader { 18namespace VideoCommon::Shader {
18 19
19using Tegra::Shader::Instruction; 20using Tegra::Shader::Instruction;
20using Tegra::Shader::OpCode; 21using Tegra::Shader::OpCode;
22using Tegra::Shader::PredCondition;
23using Tegra::Shader::StoreType;
24using Tegra::Texture::ComponentType;
25using Tegra::Texture::TextureFormat;
26using Tegra::Texture::TICEntry;
21 27
22namespace { 28namespace {
29
30ComponentType 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
126bool 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
137u32 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
220std::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
23std::size_t GetImageTypeNumCoordinates(Tegra::Shader::ImageType image_type) { 257std::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
274std::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
40u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { 307u32 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
12namespace VideoCommon::Shader { 12namespace VideoCommon::Shader {
13 13
14using std::move;
14using Tegra::Shader::ConditionCode; 15using Tegra::Shader::ConditionCode;
15using Tegra::Shader::Instruction; 16using Tegra::Shader::Instruction;
17using Tegra::Shader::IpaInterpMode;
16using Tegra::Shader::OpCode; 18using Tegra::Shader::OpCode;
19using Tegra::Shader::PixelImap;
17using Tegra::Shader::Register; 20using Tegra::Shader::Register;
18using Tegra::Shader::SystemVariable; 21using Tegra::Shader::SystemVariable;
19 22
23using Index = Tegra::Shader::Attribute::Index;
24
20u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { 25u32 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
507enum 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
514constexpr 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
596constexpr 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
604SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type); 507SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type);
605 508
606bool SurfaceTargetIsLayered(SurfaceTarget target); 509bool 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
19using Tegra::Texture::ConvertFromGuestToHost; 19using Tegra::Texture::ConvertFromGuestToHost;
20using VideoCore::MortonSwizzleMode; 20using VideoCore::MortonSwizzleMode;
21using VideoCore::Surface::SurfaceCompression; 21using VideoCore::Surface::IsPixelFormatASTC;
22using VideoCore::Surface::PixelFormat;
22 23
23StagingCache::StagingCache() = default; 24StagingCache::StagingCache() = default;
24 25
25StagingCache::~StagingCache() = default; 26StagingCache::~StagingCache() = default;
26 27
27SurfaceBaseImpl::SurfaceBaseImpl(GPUVAddr gpu_addr, const SurfaceParams& params) 28SurfaceBaseImpl::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
162protected: 166protected:
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
290protected: 296protected:
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
312std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const { 310std::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
320std::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
328std::size_t SurfaceParams::GetConvertedMipmapSize(u32 level) const { 324std::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
336std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) const { 332std::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
21class FormatLookupTable; 21class FormatLookupTable;
22 22
23using VideoCore::Surface::SurfaceCompression;
24
25class SurfaceParams { 23class SurfaceParams {
26public: 24public:
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
291protected: 291protected:
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
385private: 387private:
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
10AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) { 11AboutDialog::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);