summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/file_sys/system_archive/ng_word.cpp42
-rw-r--r--src/core/file_sys/system_archive/ng_word.h13
-rw-r--r--src/core/file_sys/system_archive/system_archive.cpp90
-rw-r--r--src/core/file_sys/system_archive/system_archive.h14
-rw-r--r--src/core/file_sys/vfs_vector.cpp1
-rw-r--r--src/core/file_sys/vfs_vector.h53
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp10
-rw-r--r--src/core/hle/service/ldr/ldr.cpp10
-rw-r--r--src/core/memory.cpp8
-rw-r--r--src/video_core/engines/shader_bytecode.h3
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp116
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h6
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp70
-rw-r--r--src/video_core/surface.h552
-rw-r--r--src/yuzu/game_list_worker.cpp105
16 files changed, 696 insertions, 401 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 73aec8ab0..882c9ab59 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -63,6 +63,10 @@ add_library(core STATIC
63 file_sys/sdmc_factory.h 63 file_sys/sdmc_factory.h
64 file_sys/submission_package.cpp 64 file_sys/submission_package.cpp
65 file_sys/submission_package.h 65 file_sys/submission_package.h
66 file_sys/system_archive/ng_word.cpp
67 file_sys/system_archive/ng_word.h
68 file_sys/system_archive/system_archive.cpp
69 file_sys/system_archive/system_archive.h
66 file_sys/vfs.cpp 70 file_sys/vfs.cpp
67 file_sys/vfs.h 71 file_sys/vfs.h
68 file_sys/vfs_concat.cpp 72 file_sys/vfs_concat.cpp
diff --git a/src/core/file_sys/system_archive/ng_word.cpp b/src/core/file_sys/system_archive/ng_word.cpp
new file mode 100644
index 000000000..a24f1e496
--- /dev/null
+++ b/src/core/file_sys/system_archive/ng_word.cpp
@@ -0,0 +1,42 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <fmt/format.h>
6#include "common/common_types.h"
7#include "core/file_sys/system_archive/ng_word.h"
8#include "core/file_sys/vfs_vector.h"
9
10namespace FileSys::SystemArchive {
11
12namespace NgWord1Data {
13
14constexpr std::size_t NUMBER_WORD_TXT_FILES = 0x10;
15
16// Should this archive replacement mysteriously not work on a future game, consider updating.
17constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x19}; // 5.1.0 System Version
18
19constexpr std::array<u8, 30> WORD_TXT{
20 0xFE, 0xFF, 0x00, 0x5E, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x79, 0x00, 0x62, 0x00,
21 0x61, 0x00, 0x64, 0x00, 0x77, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x64, 0x00, 0x24, 0x00, 0x0A,
22}; // "^verybadword$" in UTF-16
23
24} // namespace NgWord1Data
25
26VirtualDir NgWord1() {
27 std::vector<VirtualFile> files(NgWord1Data::NUMBER_WORD_TXT_FILES);
28
29 for (std::size_t i = 0; i < files.size(); ++i) {
30 files[i] = std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
31 NgWord1Data::WORD_TXT, fmt::format("{}.txt", i));
32 }
33
34 files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
35 NgWord1Data::WORD_TXT, "common.txt"));
36 files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::VERSION_DAT.size()>>(
37 NgWord1Data::VERSION_DAT, "version.dat"));
38
39 return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data");
40}
41
42} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/system_archive/ng_word.h b/src/core/file_sys/system_archive/ng_word.h
new file mode 100644
index 000000000..f4bc67344
--- /dev/null
+++ b/src/core/file_sys/system_archive/ng_word.h
@@ -0,0 +1,13 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/file_sys/vfs_types.h"
8
9namespace FileSys::SystemArchive {
10
11VirtualDir NgWord1();
12
13} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/system_archive/system_archive.cpp b/src/core/file_sys/system_archive/system_archive.cpp
new file mode 100644
index 000000000..d3883267c
--- /dev/null
+++ b/src/core/file_sys/system_archive/system_archive.cpp
@@ -0,0 +1,90 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/logging/log.h"
6#include "core/file_sys/romfs.h"
7#include "core/file_sys/system_archive/ng_word.h"
8#include "core/file_sys/system_archive/system_archive.h"
9
10namespace FileSys::SystemArchive {
11
12constexpr u64 SYSTEM_ARCHIVE_BASE_TITLE_ID = 0x0100000000000800;
13constexpr std::size_t SYSTEM_ARCHIVE_COUNT = 0x28;
14
15using SystemArchiveSupplier = VirtualDir (*)();
16
17struct SystemArchiveDescriptor {
18 u64 title_id;
19 const char* name;
20 SystemArchiveSupplier supplier;
21};
22
23constexpr std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHIVES{{
24 {0x0100000000000800, "CertStore", nullptr},
25 {0x0100000000000801, "ErrorMessage", nullptr},
26 {0x0100000000000802, "MiiModel", nullptr},
27 {0x0100000000000803, "BrowserDll", nullptr},
28 {0x0100000000000804, "Help", nullptr},
29 {0x0100000000000805, "SharedFont", nullptr},
30 {0x0100000000000806, "NgWord", &NgWord1},
31 {0x0100000000000807, "SsidList", nullptr},
32 {0x0100000000000808, "Dictionary", nullptr},
33 {0x0100000000000809, "SystemVersion", nullptr},
34 {0x010000000000080A, "AvatarImage", nullptr},
35 {0x010000000000080B, "LocalNews", nullptr},
36 {0x010000000000080C, "Eula", nullptr},
37 {0x010000000000080D, "UrlBlackList", nullptr},
38 {0x010000000000080E, "TimeZoneBinary", nullptr},
39 {0x010000000000080F, "CertStoreCruiser", nullptr},
40 {0x0100000000000810, "FontNintendoExtension", nullptr},
41 {0x0100000000000811, "FontStandard", nullptr},
42 {0x0100000000000812, "FontKorean", nullptr},
43 {0x0100000000000813, "FontChineseTraditional", nullptr},
44 {0x0100000000000814, "FontChineseSimple", nullptr},
45 {0x0100000000000815, "FontBfcpx", nullptr},
46 {0x0100000000000816, "SystemUpdate", nullptr},
47 {0x0100000000000817, "0100000000000817", nullptr},
48 {0x0100000000000818, "FirmwareDebugSettings", nullptr},
49 {0x0100000000000819, "BootImagePackage", nullptr},
50 {0x010000000000081A, "BootImagePackageSafe", nullptr},
51 {0x010000000000081B, "BootImagePackageExFat", nullptr},
52 {0x010000000000081C, "BootImagePackageExFatSafe", nullptr},
53 {0x010000000000081D, "FatalMessage", nullptr},
54 {0x010000000000081E, "ControllerIcon", nullptr},
55 {0x010000000000081F, "PlatformConfigIcosa", nullptr},
56 {0x0100000000000820, "PlatformConfigCopper", nullptr},
57 {0x0100000000000821, "PlatformConfigHoag", nullptr},
58 {0x0100000000000822, "ControllerFirmware", nullptr},
59 {0x0100000000000823, "NgWord2", nullptr},
60 {0x0100000000000824, "PlatformConfigIcosaMariko", nullptr},
61 {0x0100000000000825, "ApplicationBlackList", nullptr},
62 {0x0100000000000826, "RebootlessSystemUpdateVersion", nullptr},
63 {0x0100000000000827, "ContentActionTable", nullptr},
64}};
65
66VirtualFile SynthesizeSystemArchive(const u64 title_id) {
67 if (title_id < SYSTEM_ARCHIVES.front().title_id || title_id > SYSTEM_ARCHIVES.back().title_id)
68 return nullptr;
69
70 const auto& desc = SYSTEM_ARCHIVES[title_id - SYSTEM_ARCHIVE_BASE_TITLE_ID];
71
72 LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, desc.title_id);
73
74 if (desc.supplier == nullptr)
75 return nullptr;
76
77 const auto dir = desc.supplier();
78
79 if (dir == nullptr)
80 return nullptr;
81
82 const auto romfs = CreateRomFS(dir);
83
84 if (romfs == nullptr)
85 return nullptr;
86
87 LOG_INFO(Service_FS, " - System archive generation successful!");
88 return romfs;
89}
90} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/system_archive/system_archive.h b/src/core/file_sys/system_archive/system_archive.h
new file mode 100644
index 000000000..724a8eb17
--- /dev/null
+++ b/src/core/file_sys/system_archive/system_archive.h
@@ -0,0 +1,14 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "core/file_sys/vfs_types.h"
9
10namespace FileSys::SystemArchive {
11
12VirtualFile SynthesizeSystemArchive(u64 title_id);
13
14} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp
index 808f31e81..515626658 100644
--- a/src/core/file_sys/vfs_vector.cpp
+++ b/src/core/file_sys/vfs_vector.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cstring>
7#include <utility> 6#include <utility>
8#include "core/file_sys/vfs_vector.h" 7#include "core/file_sys/vfs_vector.h"
9 8
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
index 3e3f790c3..ac36cb2ee 100644
--- a/src/core/file_sys/vfs_vector.h
+++ b/src/core/file_sys/vfs_vector.h
@@ -4,10 +4,63 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstring>
7#include "core/file_sys/vfs.h" 8#include "core/file_sys/vfs.h"
8 9
9namespace FileSys { 10namespace FileSys {
10 11
12// An implementation of VfsFile that is backed by a statically-sized array
13template <std::size_t size>
14class ArrayVfsFile : public VfsFile {
15public:
16 ArrayVfsFile(std::array<u8, size> data, std::string name = "", VirtualDir parent = nullptr)
17 : data(data), name(std::move(name)), parent(std::move(parent)) {}
18
19 std::string GetName() const override {
20 return name;
21 }
22
23 std::size_t GetSize() const override {
24 return size;
25 }
26
27 bool Resize(std::size_t new_size) override {
28 return false;
29 }
30
31 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override {
32 return parent;
33 }
34
35 bool IsWritable() const override {
36 return false;
37 }
38
39 bool IsReadable() const override {
40 return true;
41 }
42
43 std::size_t Read(u8* data_, std::size_t length, std::size_t offset) const override {
44 const auto read = std::min(length, size - offset);
45 std::memcpy(data_, data.data() + offset, read);
46 return read;
47 }
48
49 std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override {
50 return 0;
51 }
52
53 bool Rename(std::string_view name) override {
54 this->name = name;
55 return true;
56 }
57
58private:
59 std::array<u8, size> data;
60 std::string name;
61 VirtualDir parent;
62};
63
11// An implementation of VfsFile that is backed by a vector optionally supplied upon construction 64// An implementation of VfsFile that is backed by a vector optionally supplied upon construction
12class VectorVfsFile : public VfsFile { 65class VectorVfsFile : public VfsFile {
13public: 66public:
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 694ec40ec..d2ffd5776 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -20,6 +20,7 @@
20#include "core/file_sys/nca_metadata.h" 20#include "core/file_sys/nca_metadata.h"
21#include "core/file_sys/patch_manager.h" 21#include "core/file_sys/patch_manager.h"
22#include "core/file_sys/savedata_factory.h" 22#include "core/file_sys/savedata_factory.h"
23#include "core/file_sys/system_archive/system_archive.h"
23#include "core/file_sys/vfs.h" 24#include "core/file_sys/vfs.h"
24#include "core/hle/ipc_helpers.h" 25#include "core/hle/ipc_helpers.h"
25#include "core/hle/kernel/process.h" 26#include "core/hle/kernel/process.h"
@@ -831,6 +832,15 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
831 auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data); 832 auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
832 833
833 if (data.Failed()) { 834 if (data.Failed()) {
835 const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
836
837 if (archive != nullptr) {
838 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
839 rb.Push(RESULT_SUCCESS);
840 rb.PushIpcInterface(std::make_shared<IStorage>(archive));
841 return;
842 }
843
834 // TODO(DarkLordZach): Find the right error code to use here 844 // TODO(DarkLordZach): Find the right error code to use here
835 LOG_ERROR(Service_FS, 845 LOG_ERROR(Service_FS,
836 "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id, 846 "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index ca119dd3a..453d90a22 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -335,10 +335,7 @@ public:
335 vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size, 335 vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size,
336 Kernel::VMAPermission::ReadWrite); 336 Kernel::VMAPermission::ReadWrite);
337 337
338 Core::System::GetInstance().ArmInterface(0).ClearInstructionCache(); 338 Core::System::GetInstance().InvalidateCpuInstructionCaches();
339 Core::System::GetInstance().ArmInterface(1).ClearInstructionCache();
340 Core::System::GetInstance().ArmInterface(2).ClearInstructionCache();
341 Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
342 339
343 nro.insert_or_assign(*map_address, NROInfo{hash, nro_size + bss_size}); 340 nro.insert_or_assign(*map_address, NROInfo{hash, nro_size + bss_size});
344 341
@@ -391,10 +388,7 @@ public:
391 Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS); 388 Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
392 ASSERT(process->UnmapMemory(mapped_addr, 0, nro_size) == RESULT_SUCCESS); 389 ASSERT(process->UnmapMemory(mapped_addr, 0, nro_size) == RESULT_SUCCESS);
393 390
394 Core::System::GetInstance().ArmInterface(0).ClearInstructionCache(); 391 Core::System::GetInstance().InvalidateCpuInstructionCaches();
395 Core::System::GetInstance().ArmInterface(1).ClearInstructionCache();
396 Core::System::GetInstance().ArmInterface(2).ClearInstructionCache();
397 Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
398 392
399 nro.erase(iter); 393 nro.erase(iter);
400 IPC::ResponseBuilder rb{ctx, 2}; 394 IPC::ResponseBuilder rb{ctx, 2};
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 70abd856a..41fd2a6a0 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -53,6 +53,14 @@ void PageTable::Resize(std::size_t address_space_width_in_bits) {
53 53
54 pointers.resize(num_page_table_entries); 54 pointers.resize(num_page_table_entries);
55 attributes.resize(num_page_table_entries); 55 attributes.resize(num_page_table_entries);
56
57 // The default is a 39-bit address space, which causes an initial 1GB allocation size. If the
58 // vector size is subsequently decreased (via resize), the vector might not automatically
59 // actually reallocate/resize its underlying allocation, which wastes up to ~800 MB for
60 // 36-bit titles. Call shrink_to_fit to reduce capacity to what's actually in use.
61
62 pointers.shrink_to_fit();
63 attributes.shrink_to_fit();
56} 64}
57 65
58static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) { 66static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) {
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index b9faaf8e0..5ea094e64 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -1049,6 +1049,7 @@ union Instruction {
1049 BitField<49, 1, u64> nodep_flag; 1049 BitField<49, 1, u64> nodep_flag;
1050 BitField<50, 3, u64> component_mask_selector; 1050 BitField<50, 3, u64> component_mask_selector;
1051 BitField<53, 4, u64> texture_info; 1051 BitField<53, 4, u64> texture_info;
1052 BitField<60, 1, u64> fp32_flag;
1052 1053
1053 TextureType GetTextureType() const { 1054 TextureType GetTextureType() const {
1054 // The TEXS instruction has a weird encoding for the texture type. 1055 // The TEXS instruction has a weird encoding for the texture type.
@@ -1549,7 +1550,7 @@ private:
1549 INST("1110111011011---", Id::STG, Type::Memory, "STG"), 1550 INST("1110111011011---", Id::STG, Type::Memory, "STG"),
1550 INST("110000----111---", Id::TEX, Type::Memory, "TEX"), 1551 INST("110000----111---", Id::TEX, Type::Memory, "TEX"),
1551 INST("1101111101001---", Id::TXQ, Type::Memory, "TXQ"), 1552 INST("1101111101001---", Id::TXQ, Type::Memory, "TXQ"),
1552 INST("1101100---------", Id::TEXS, Type::Memory, "TEXS"), 1553 INST("1101-00---------", Id::TEXS, Type::Memory, "TEXS"),
1553 INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"), 1554 INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"),
1554 INST("110010----111---", Id::TLD4, Type::Memory, "TLD4"), 1555 INST("110010----111---", Id::TLD4, Type::Memory, "TLD4"),
1555 INST("1101111100------", Id::TLD4S, Type::Memory, "TLD4S"), 1556 INST("1101111100------", Id::TLD4S, Type::Memory, "TLD4S"),
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 9e93bd609..2b29fc45f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -79,6 +79,26 @@ struct DrawParameters {
79 } 79 }
80}; 80};
81 81
82struct FramebufferCacheKey {
83 bool is_single_buffer = false;
84 bool stencil_enable = false;
85
86 std::array<GLenum, Maxwell::NumRenderTargets> color_attachments{};
87 std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> colors{};
88 u32 colors_count = 0;
89
90 GLuint zeta = 0;
91
92 auto Tie() const {
93 return std::tie(is_single_buffer, stencil_enable, color_attachments, colors, colors_count,
94 zeta);
95 }
96
97 bool operator<(const FramebufferCacheKey& rhs) const {
98 return Tie() < rhs.Tie();
99 }
100};
101
82RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info) 102RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info)
83 : res_cache{*this}, shader_cache{*this}, emu_window{window}, screen_info{info}, 103 : res_cache{*this}, shader_cache{*this}, emu_window{window}, screen_info{info},
84 buffer_cache(*this, STREAM_BUFFER_SIZE) { 104 buffer_cache(*this, STREAM_BUFFER_SIZE) {
@@ -90,9 +110,6 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
90 110
91 OpenGLState::ApplyDefaultState(); 111 OpenGLState::ApplyDefaultState();
92 112
93 // Create render framebuffer
94 framebuffer.Create();
95
96 shader_program_manager = std::make_unique<GLShader::ProgramManager>(); 113 shader_program_manager = std::make_unique<GLShader::ProgramManager>();
97 state.draw.shader_program = 0; 114 state.draw.shader_program = 0;
98 state.Apply(); 115 state.Apply();
@@ -361,6 +378,44 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
361 SyncClipEnabled(clip_distances); 378 SyncClipEnabled(clip_distances);
362} 379}
363 380
381void RasterizerOpenGL::SetupCachedFramebuffer(const FramebufferCacheKey& fbkey,
382 OpenGLState& current_state) {
383 const auto [entry, is_cache_miss] = framebuffer_cache.try_emplace(fbkey);
384 auto& framebuffer = entry->second;
385
386 if (is_cache_miss)
387 framebuffer.Create();
388
389 current_state.draw.draw_framebuffer = framebuffer.handle;
390 current_state.ApplyFramebufferState();
391
392 if (!is_cache_miss)
393 return;
394
395 if (fbkey.is_single_buffer) {
396 if (fbkey.color_attachments[0] != GL_NONE) {
397 glFramebufferTexture(GL_DRAW_FRAMEBUFFER, fbkey.color_attachments[0], fbkey.colors[0],
398 0);
399 }
400 glDrawBuffer(fbkey.color_attachments[0]);
401 } else {
402 for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
403 if (fbkey.colors[index]) {
404 glFramebufferTexture(GL_DRAW_FRAMEBUFFER,
405 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index),
406 fbkey.colors[index], 0);
407 }
408 }
409 glDrawBuffers(fbkey.colors_count, fbkey.color_attachments.data());
410 }
411
412 if (fbkey.zeta) {
413 GLenum zeta_attachment =
414 fbkey.stencil_enable ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT;
415 glFramebufferTexture(GL_DRAW_FRAMEBUFFER, zeta_attachment, fbkey.zeta, 0);
416 }
417}
418
364std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { 419std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
365 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 420 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
366 421
@@ -444,10 +499,10 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
444 UNIMPLEMENTED_IF(regs.rt_separate_frag_data != 0); 499 UNIMPLEMENTED_IF(regs.rt_separate_frag_data != 0);
445 500
446 // Bind the framebuffer surfaces 501 // Bind the framebuffer surfaces
447 current_state.draw.draw_framebuffer = framebuffer.handle;
448 current_state.ApplyFramebufferState();
449 current_state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0; 502 current_state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0;
450 503
504 FramebufferCacheKey fbkey;
505
451 if (using_color_fb) { 506 if (using_color_fb) {
452 if (single_color_target) { 507 if (single_color_target) {
453 // Used when just a single color attachment is enabled, e.g. for clearing a color buffer 508 // Used when just a single color attachment is enabled, e.g. for clearing a color buffer
@@ -463,14 +518,12 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
463 state.framebuffer_srgb.enabled |= color_surface->GetSurfaceParams().srgb_conversion; 518 state.framebuffer_srgb.enabled |= color_surface->GetSurfaceParams().srgb_conversion;
464 } 519 }
465 520
466 glFramebufferTexture2D( 521 fbkey.is_single_buffer = true;
467 GL_DRAW_FRAMEBUFFER, 522 fbkey.color_attachments[0] =
468 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target), GL_TEXTURE_2D, 523 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target);
469 color_surface != nullptr ? color_surface->Texture().handle : 0, 0); 524 fbkey.colors[0] = color_surface != nullptr ? color_surface->Texture().handle : 0;
470 glDrawBuffer(GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target));
471 } else { 525 } else {
472 // Multiple color attachments are enabled 526 // Multiple color attachments are enabled
473 std::array<GLenum, Maxwell::NumRenderTargets> buffers;
474 for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { 527 for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
475 Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents); 528 Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents);
476 529
@@ -485,22 +538,17 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
485 color_surface->GetSurfaceParams().srgb_conversion; 538 color_surface->GetSurfaceParams().srgb_conversion;
486 } 539 }
487 540
488 buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); 541 fbkey.color_attachments[index] =
489 glFramebufferTexture2D( 542 GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index);
490 GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), 543 fbkey.colors[index] =
491 GL_TEXTURE_2D, color_surface != nullptr ? color_surface->Texture().handle : 0, 544 color_surface != nullptr ? color_surface->Texture().handle : 0;
492 0);
493 } 545 }
494 glDrawBuffers(regs.rt_control.count, buffers.data()); 546 fbkey.is_single_buffer = false;
547 fbkey.colors_count = regs.rt_control.count;
495 } 548 }
496 } else { 549 } else {
497 // No color attachments are enabled - zero out all of them 550 // No color attachments are enabled - leave them as zero
498 for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { 551 fbkey.is_single_buffer = true;
499 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
500 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D,
501 0, 0);
502 }
503 glDrawBuffer(GL_NONE);
504 } 552 }
505 553
506 if (depth_surface) { 554 if (depth_surface) {
@@ -508,22 +556,12 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
508 // the shader doesn't actually write to it. 556 // the shader doesn't actually write to it.
509 depth_surface->MarkAsModified(true, res_cache); 557 depth_surface->MarkAsModified(true, res_cache);
510 558
511 if (regs.stencil_enable) { 559 fbkey.zeta = depth_surface->Texture().handle;
512 // Attach both depth and stencil 560 fbkey.stencil_enable = regs.stencil_enable;
513 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
514 depth_surface->Texture().handle, 0);
515 } else {
516 // Attach depth
517 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
518 depth_surface->Texture().handle, 0);
519 // Clear stencil attachment
520 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
521 }
522 } else {
523 // Clear both depth and stencil attachment
524 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
525 0);
526 } 561 }
562
563 SetupCachedFramebuffer(fbkey, current_state);
564
527 SyncViewport(current_state); 565 SyncViewport(current_state);
528} 566}
529 567
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 988fa3e27..8a891ffc7 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -40,6 +40,7 @@ namespace OpenGL {
40 40
41struct ScreenInfo; 41struct ScreenInfo;
42struct DrawParameters; 42struct DrawParameters;
43struct FramebufferCacheKey;
43 44
44class RasterizerOpenGL : public VideoCore::RasterizerInterface { 45class RasterizerOpenGL : public VideoCore::RasterizerInterface {
45public: 46public:
@@ -195,11 +196,12 @@ private:
195 OGLVertexArray> 196 OGLVertexArray>
196 vertex_array_cache; 197 vertex_array_cache;
197 198
199 std::map<FramebufferCacheKey, OGLFramebuffer> framebuffer_cache;
200
198 std::array<SamplerInfo, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_samplers; 201 std::array<SamplerInfo, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_samplers;
199 202
200 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; 203 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
201 OGLBufferCache buffer_cache; 204 OGLBufferCache buffer_cache;
202 OGLFramebuffer framebuffer;
203 PrimitiveAssembler primitive_assembler{buffer_cache}; 205 PrimitiveAssembler primitive_assembler{buffer_cache};
204 GLint uniform_buffer_alignment; 206 GLint uniform_buffer_alignment;
205 207
@@ -214,6 +216,8 @@ private:
214 216
215 void SetupShaders(GLenum primitive_mode); 217 void SetupShaders(GLenum primitive_mode);
216 218
219 void SetupCachedFramebuffer(const FramebufferCacheKey& fbkey, OpenGLState& current_state);
220
217 enum class AccelDraw { Disabled, Arrays, Indexed }; 221 enum class AccelDraw { Disabled, Arrays, Indexed };
218 AccelDraw accelerate_draw = AccelDraw::Disabled; 222 AccelDraw accelerate_draw = AccelDraw::Disabled;
219 223
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 8d68156bf..4fc09cac6 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -50,6 +50,14 @@ public:
50 using std::runtime_error::runtime_error; 50 using std::runtime_error::runtime_error;
51}; 51};
52 52
53/// Generates code to use for a swizzle operation.
54static std::string GetSwizzle(u64 elem) {
55 ASSERT(elem <= 3);
56 std::string swizzle = ".";
57 swizzle += "xyzw"[elem];
58 return swizzle;
59}
60
53/// Translate topology 61/// Translate topology
54static std::string GetTopologyName(Tegra::Shader::OutputTopology topology) { 62static std::string GetTopologyName(Tegra::Shader::OutputTopology topology) {
55 switch (topology) { 63 switch (topology) {
@@ -1004,14 +1012,6 @@ private:
1004 } 1012 }
1005 } 1013 }
1006 1014
1007 /// Generates code to use for a swizzle operation.
1008 static std::string GetSwizzle(u64 elem) {
1009 ASSERT(elem <= 3);
1010 std::string swizzle = ".";
1011 swizzle += "xyzw"[elem];
1012 return swizzle;
1013 }
1014
1015 ShaderWriter& shader; 1015 ShaderWriter& shader;
1016 ShaderWriter& declarations; 1016 ShaderWriter& declarations;
1017 std::vector<GLSLRegister> regs; 1017 std::vector<GLSLRegister> regs;
@@ -1343,7 +1343,7 @@ private:
1343 regs.SetRegisterToInteger(dest, true, 0, result, 1, 1); 1343 regs.SetRegisterToInteger(dest, true, 0, result, 1, 1);
1344 } 1344 }
1345 1345
1346 void WriteTexsInstruction(const Instruction& instr, const std::string& texture) { 1346 void WriteTexsInstructionFloat(const Instruction& instr, const std::string& texture) {
1347 // TEXS has two destination registers and a swizzle. The first two elements in the swizzle 1347 // TEXS has two destination registers and a swizzle. The first two elements in the swizzle
1348 // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1 1348 // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1
1349 1349
@@ -1368,6 +1368,38 @@ private:
1368 } 1368 }
1369 } 1369 }
1370 1370
1371 void WriteTexsInstructionHalfFloat(const Instruction& instr, const std::string& texture) {
1372 // TEXS.F16 destionation registers are packed in two registers in pairs (just like any half
1373 // float instruction).
1374
1375 std::array<std::string, 4> components;
1376 u32 written_components = 0;
1377
1378 for (u32 component = 0; component < 4; ++component) {
1379 if (!instr.texs.IsComponentEnabled(component))
1380 continue;
1381 components[written_components++] = texture + GetSwizzle(component);
1382 }
1383 if (written_components == 0)
1384 return;
1385
1386 const auto BuildComponent = [&](std::string low, std::string high, bool high_enabled) {
1387 return "vec2(" + low + ", " + (high_enabled ? high : "0") + ')';
1388 };
1389
1390 regs.SetRegisterToHalfFloat(
1391 instr.gpr0, 0, BuildComponent(components[0], components[1], written_components > 1),
1392 Tegra::Shader::HalfMerge::H0_H1, 1, 1);
1393
1394 if (written_components > 2) {
1395 ASSERT(instr.texs.HasTwoDestinations());
1396 regs.SetRegisterToHalfFloat(
1397 instr.gpr28, 0,
1398 BuildComponent(components[2], components[3], written_components > 3),
1399 Tegra::Shader::HalfMerge::H0_H1, 1, 1);
1400 }
1401 }
1402
1371 static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) { 1403 static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) {
1372 switch (texture_type) { 1404 switch (texture_type) {
1373 case Tegra::Shader::TextureType::Texture1D: 1405 case Tegra::Shader::TextureType::Texture1D:
@@ -2766,24 +2798,27 @@ private:
2766 const bool depth_compare = 2798 const bool depth_compare =
2767 instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); 2799 instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
2768 const auto process_mode = instr.texs.GetTextureProcessMode(); 2800 const auto process_mode = instr.texs.GetTextureProcessMode();
2801
2769 UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2802 UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2770 "NODEP is not implemented"); 2803 "NODEP is not implemented");
2771 2804
2772 const auto scope = shader.Scope(); 2805 const auto scope = shader.Scope();
2773 2806
2774 const auto [coord, texture] = 2807 auto [coord, texture] =
2775 GetTEXSCode(instr, texture_type, process_mode, depth_compare, is_array); 2808 GetTEXSCode(instr, texture_type, process_mode, depth_compare, is_array);
2776 2809
2777 shader.AddLine(coord); 2810 shader.AddLine(coord);
2778 2811
2779 if (!depth_compare) { 2812 if (depth_compare) {
2780 shader.AddLine("vec4 texture_tmp = " + texture + ';'); 2813 texture = "vec4(" + texture + ')';
2814 }
2815 shader.AddLine("vec4 texture_tmp = " + texture + ';');
2781 2816
2817 if (instr.texs.fp32_flag) {
2818 WriteTexsInstructionFloat(instr, "texture_tmp");
2782 } else { 2819 } else {
2783 shader.AddLine("vec4 texture_tmp = vec4(" + texture + ");"); 2820 WriteTexsInstructionHalfFloat(instr, "texture_tmp");
2784 } 2821 }
2785
2786 WriteTexsInstruction(instr, "texture_tmp");
2787 break; 2822 break;
2788 } 2823 }
2789 case OpCode::Id::TLDS: { 2824 case OpCode::Id::TLDS: {
@@ -2842,7 +2877,7 @@ private:
2842 } 2877 }
2843 }(); 2878 }();
2844 2879
2845 WriteTexsInstruction(instr, texture); 2880 WriteTexsInstructionFloat(instr, texture);
2846 break; 2881 break;
2847 } 2882 }
2848 case OpCode::Id::TLD4: { 2883 case OpCode::Id::TLD4: {
@@ -2940,7 +2975,8 @@ private:
2940 if (depth_compare) { 2975 if (depth_compare) {
2941 texture = "vec4(" + texture + ')'; 2976 texture = "vec4(" + texture + ')';
2942 } 2977 }
2943 WriteTexsInstruction(instr, texture); 2978
2979 WriteTexsInstructionFloat(instr, texture);
2944 break; 2980 break;
2945 } 2981 }
2946 case OpCode::Id::TXQ: { 2982 case OpCode::Id::TXQ: {
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 0dd3eb2e4..e23cfecbc 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -125,6 +125,75 @@ enum class SurfaceTarget {
125 TextureCubeArray, 125 TextureCubeArray,
126}; 126};
127 127
128constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
129 1, // ABGR8U
130 1, // ABGR8S
131 1, // ABGR8UI
132 1, // B5G6R5U
133 1, // A2B10G10R10U
134 1, // A1B5G5R5U
135 1, // R8U
136 1, // R8UI
137 1, // RGBA16F
138 1, // RGBA16U
139 1, // RGBA16UI
140 1, // R11FG11FB10F
141 1, // RGBA32UI
142 4, // DXT1
143 4, // DXT23
144 4, // DXT45
145 4, // DXN1
146 4, // DXN2UNORM
147 4, // DXN2SNORM
148 4, // BC7U
149 4, // BC6H_UF16
150 4, // BC6H_SF16
151 4, // ASTC_2D_4X4
152 1, // G8R8U
153 1, // G8R8S
154 1, // BGRA8
155 1, // RGBA32F
156 1, // RG32F
157 1, // R32F
158 1, // R16F
159 1, // R16U
160 1, // R16S
161 1, // R16UI
162 1, // R16I
163 1, // RG16
164 1, // RG16F
165 1, // RG16UI
166 1, // RG16I
167 1, // RG16S
168 1, // RGB32F
169 1, // RGBA8_SRGB
170 1, // RG8U
171 1, // RG8S
172 1, // RG32UI
173 1, // R32UI
174 4, // ASTC_2D_8X8
175 4, // ASTC_2D_8X5
176 4, // ASTC_2D_5X4
177 1, // BGRA8_SRGB
178 4, // DXT1_SRGB
179 4, // DXT23_SRGB
180 4, // DXT45_SRGB
181 4, // BC7U_SRGB
182 4, // ASTC_2D_4X4_SRGB
183 4, // ASTC_2D_8X8_SRGB
184 4, // ASTC_2D_8X5_SRGB
185 4, // ASTC_2D_5X4_SRGB
186 4, // ASTC_2D_5X5
187 4, // ASTC_2D_5X5_SRGB
188 4, // ASTC_2D_10X8
189 4, // ASTC_2D_10X8_SRGB
190 1, // Z32F
191 1, // Z16
192 1, // Z24S8
193 1, // S8Z24
194 1, // Z32FS8
195}};
196
128/** 197/**
129 * Gets the compression factor for the specified PixelFormat. This applies to just the 198 * Gets the compression factor for the specified PixelFormat. This applies to just the
130 * "compressed width" and "compressed height", not the overall compression factor of a 199 * "compressed width" and "compressed height", not the overall compression factor of a
@@ -135,304 +204,237 @@ static constexpr u32 GetCompressionFactor(PixelFormat format) {
135 if (format == PixelFormat::Invalid) 204 if (format == PixelFormat::Invalid)
136 return 0; 205 return 0;
137 206
138 constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
139 1, // ABGR8U
140 1, // ABGR8S
141 1, // ABGR8UI
142 1, // B5G6R5U
143 1, // A2B10G10R10U
144 1, // A1B5G5R5U
145 1, // R8U
146 1, // R8UI
147 1, // RGBA16F
148 1, // RGBA16U
149 1, // RGBA16UI
150 1, // R11FG11FB10F
151 1, // RGBA32UI
152 4, // DXT1
153 4, // DXT23
154 4, // DXT45
155 4, // DXN1
156 4, // DXN2UNORM
157 4, // DXN2SNORM
158 4, // BC7U
159 4, // BC6H_UF16
160 4, // BC6H_SF16
161 4, // ASTC_2D_4X4
162 1, // G8R8U
163 1, // G8R8S
164 1, // BGRA8
165 1, // RGBA32F
166 1, // RG32F
167 1, // R32F
168 1, // R16F
169 1, // R16U
170 1, // R16S
171 1, // R16UI
172 1, // R16I
173 1, // RG16
174 1, // RG16F
175 1, // RG16UI
176 1, // RG16I
177 1, // RG16S
178 1, // RGB32F
179 1, // RGBA8_SRGB
180 1, // RG8U
181 1, // RG8S
182 1, // RG32UI
183 1, // R32UI
184 4, // ASTC_2D_8X8
185 4, // ASTC_2D_8X5
186 4, // ASTC_2D_5X4
187 1, // BGRA8_SRGB
188 4, // DXT1_SRGB
189 4, // DXT23_SRGB
190 4, // DXT45_SRGB
191 4, // BC7U_SRGB
192 4, // ASTC_2D_4X4_SRGB
193 4, // ASTC_2D_8X8_SRGB
194 4, // ASTC_2D_8X5_SRGB
195 4, // ASTC_2D_5X4_SRGB
196 4, // ASTC_2D_5X5
197 4, // ASTC_2D_5X5_SRGB
198 4, // ASTC_2D_10X8
199 4, // ASTC_2D_10X8_SRGB
200 1, // Z32F
201 1, // Z16
202 1, // Z24S8
203 1, // S8Z24
204 1, // Z32FS8
205 }};
206
207 ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size()); 207 ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
208 return compression_factor_table[static_cast<std::size_t>(format)]; 208 return compression_factor_table[static_cast<std::size_t>(format)];
209} 209}
210 210
211constexpr std::array<u32, MaxPixelFormat> block_width_table = {{
212 1, // ABGR8U
213 1, // ABGR8S
214 1, // ABGR8UI
215 1, // B5G6R5U
216 1, // A2B10G10R10U
217 1, // A1B5G5R5U
218 1, // R8U
219 1, // R8UI
220 1, // RGBA16F
221 1, // RGBA16U
222 1, // RGBA16UI
223 1, // R11FG11FB10F
224 1, // RGBA32UI
225 4, // DXT1
226 4, // DXT23
227 4, // DXT45
228 4, // DXN1
229 4, // DXN2UNORM
230 4, // DXN2SNORM
231 4, // BC7U
232 4, // BC6H_UF16
233 4, // BC6H_SF16
234 4, // ASTC_2D_4X4
235 1, // G8R8U
236 1, // G8R8S
237 1, // BGRA8
238 1, // RGBA32F
239 1, // RG32F
240 1, // R32F
241 1, // R16F
242 1, // R16U
243 1, // R16S
244 1, // R16UI
245 1, // R16I
246 1, // RG16
247 1, // RG16F
248 1, // RG16UI
249 1, // RG16I
250 1, // RG16S
251 1, // RGB32F
252 1, // RGBA8_SRGB
253 1, // RG8U
254 1, // RG8S
255 1, // RG32UI
256 1, // R32UI
257 8, // ASTC_2D_8X8
258 8, // ASTC_2D_8X5
259 5, // ASTC_2D_5X4
260 1, // BGRA8_SRGB
261 4, // DXT1_SRGB
262 4, // DXT23_SRGB
263 4, // DXT45_SRGB
264 4, // BC7U_SRGB
265 4, // ASTC_2D_4X4_SRGB
266 8, // ASTC_2D_8X8_SRGB
267 8, // ASTC_2D_8X5_SRGB
268 5, // ASTC_2D_5X4_SRGB
269 5, // ASTC_2D_5X5
270 5, // ASTC_2D_5X5_SRGB
271 10, // ASTC_2D_10X8
272 10, // ASTC_2D_10X8_SRGB
273 1, // Z32F
274 1, // Z16
275 1, // Z24S8
276 1, // S8Z24
277 1, // Z32FS8
278}};
279
211static constexpr u32 GetDefaultBlockWidth(PixelFormat format) { 280static constexpr u32 GetDefaultBlockWidth(PixelFormat format) {
212 if (format == PixelFormat::Invalid) 281 if (format == PixelFormat::Invalid)
213 return 0; 282 return 0;
214 constexpr std::array<u32, MaxPixelFormat> block_width_table = {{ 283
215 1, // ABGR8U
216 1, // ABGR8S
217 1, // ABGR8UI
218 1, // B5G6R5U
219 1, // A2B10G10R10U
220 1, // A1B5G5R5U
221 1, // R8U
222 1, // R8UI
223 1, // RGBA16F
224 1, // RGBA16U
225 1, // RGBA16UI
226 1, // R11FG11FB10F
227 1, // RGBA32UI
228 4, // DXT1
229 4, // DXT23
230 4, // DXT45
231 4, // DXN1
232 4, // DXN2UNORM
233 4, // DXN2SNORM
234 4, // BC7U
235 4, // BC6H_UF16
236 4, // BC6H_SF16
237 4, // ASTC_2D_4X4
238 1, // G8R8U
239 1, // G8R8S
240 1, // BGRA8
241 1, // RGBA32F
242 1, // RG32F
243 1, // R32F
244 1, // R16F
245 1, // R16U
246 1, // R16S
247 1, // R16UI
248 1, // R16I
249 1, // RG16
250 1, // RG16F
251 1, // RG16UI
252 1, // RG16I
253 1, // RG16S
254 1, // RGB32F
255 1, // RGBA8_SRGB
256 1, // RG8U
257 1, // RG8S
258 1, // RG32UI
259 1, // R32UI
260 8, // ASTC_2D_8X8
261 8, // ASTC_2D_8X5
262 5, // ASTC_2D_5X4
263 1, // BGRA8_SRGB
264 4, // DXT1_SRGB
265 4, // DXT23_SRGB
266 4, // DXT45_SRGB
267 4, // BC7U_SRGB
268 4, // ASTC_2D_4X4_SRGB
269 8, // ASTC_2D_8X8_SRGB
270 8, // ASTC_2D_8X5_SRGB
271 5, // ASTC_2D_5X4_SRGB
272 5, // ASTC_2D_5X5
273 5, // ASTC_2D_5X5_SRGB
274 10, // ASTC_2D_10X8
275 10, // ASTC_2D_10X8_SRGB
276 1, // Z32F
277 1, // Z16
278 1, // Z24S8
279 1, // S8Z24
280 1, // Z32FS8
281 }};
282 ASSERT(static_cast<std::size_t>(format) < block_width_table.size()); 284 ASSERT(static_cast<std::size_t>(format) < block_width_table.size());
283 return block_width_table[static_cast<std::size_t>(format)]; 285 return block_width_table[static_cast<std::size_t>(format)];
284} 286}
285 287
288constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
289 1, // ABGR8U
290 1, // ABGR8S
291 1, // ABGR8UI
292 1, // B5G6R5U
293 1, // A2B10G10R10U
294 1, // A1B5G5R5U
295 1, // R8U
296 1, // R8UI
297 1, // RGBA16F
298 1, // RGBA16U
299 1, // RGBA16UI
300 1, // R11FG11FB10F
301 1, // RGBA32UI
302 4, // DXT1
303 4, // DXT23
304 4, // DXT45
305 4, // DXN1
306 4, // DXN2UNORM
307 4, // DXN2SNORM
308 4, // BC7U
309 4, // BC6H_UF16
310 4, // BC6H_SF16
311 4, // ASTC_2D_4X4
312 1, // G8R8U
313 1, // G8R8S
314 1, // BGRA8
315 1, // RGBA32F
316 1, // RG32F
317 1, // R32F
318 1, // R16F
319 1, // R16U
320 1, // R16S
321 1, // R16UI
322 1, // R16I
323 1, // RG16
324 1, // RG16F
325 1, // RG16UI
326 1, // RG16I
327 1, // RG16S
328 1, // RGB32F
329 1, // RGBA8_SRGB
330 1, // RG8U
331 1, // RG8S
332 1, // RG32UI
333 1, // R32UI
334 8, // ASTC_2D_8X8
335 5, // ASTC_2D_8X5
336 4, // ASTC_2D_5X4
337 1, // BGRA8_SRGB
338 4, // DXT1_SRGB
339 4, // DXT23_SRGB
340 4, // DXT45_SRGB
341 4, // BC7U_SRGB
342 4, // ASTC_2D_4X4_SRGB
343 8, // ASTC_2D_8X8_SRGB
344 5, // ASTC_2D_8X5_SRGB
345 4, // ASTC_2D_5X4_SRGB
346 5, // ASTC_2D_5X5
347 5, // ASTC_2D_5X5_SRGB
348 8, // ASTC_2D_10X8
349 8, // ASTC_2D_10X8_SRGB
350 1, // Z32F
351 1, // Z16
352 1, // Z24S8
353 1, // S8Z24
354 1, // Z32FS8
355}};
356
286static constexpr u32 GetDefaultBlockHeight(PixelFormat format) { 357static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
287 if (format == PixelFormat::Invalid) 358 if (format == PixelFormat::Invalid)
288 return 0; 359 return 0;
289 360
290 constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
291 1, // ABGR8U
292 1, // ABGR8S
293 1, // ABGR8UI
294 1, // B5G6R5U
295 1, // A2B10G10R10U
296 1, // A1B5G5R5U
297 1, // R8U
298 1, // R8UI
299 1, // RGBA16F
300 1, // RGBA16U
301 1, // RGBA16UI
302 1, // R11FG11FB10F
303 1, // RGBA32UI
304 4, // DXT1
305 4, // DXT23
306 4, // DXT45
307 4, // DXN1
308 4, // DXN2UNORM
309 4, // DXN2SNORM
310 4, // BC7U
311 4, // BC6H_UF16
312 4, // BC6H_SF16
313 4, // ASTC_2D_4X4
314 1, // G8R8U
315 1, // G8R8S
316 1, // BGRA8
317 1, // RGBA32F
318 1, // RG32F
319 1, // R32F
320 1, // R16F
321 1, // R16U
322 1, // R16S
323 1, // R16UI
324 1, // R16I
325 1, // RG16
326 1, // RG16F
327 1, // RG16UI
328 1, // RG16I
329 1, // RG16S
330 1, // RGB32F
331 1, // RGBA8_SRGB
332 1, // RG8U
333 1, // RG8S
334 1, // RG32UI
335 1, // R32UI
336 8, // ASTC_2D_8X8
337 5, // ASTC_2D_8X5
338 4, // ASTC_2D_5X4
339 1, // BGRA8_SRGB
340 4, // DXT1_SRGB
341 4, // DXT23_SRGB
342 4, // DXT45_SRGB
343 4, // BC7U_SRGB
344 4, // ASTC_2D_4X4_SRGB
345 8, // ASTC_2D_8X8_SRGB
346 5, // ASTC_2D_8X5_SRGB
347 4, // ASTC_2D_5X4_SRGB
348 5, // ASTC_2D_5X5
349 5, // ASTC_2D_5X5_SRGB
350 8, // ASTC_2D_10X8
351 8, // ASTC_2D_10X8_SRGB
352 1, // Z32F
353 1, // Z16
354 1, // Z24S8
355 1, // S8Z24
356 1, // Z32FS8
357 }};
358
359 ASSERT(static_cast<std::size_t>(format) < block_height_table.size()); 361 ASSERT(static_cast<std::size_t>(format) < block_height_table.size());
360 return block_height_table[static_cast<std::size_t>(format)]; 362 return block_height_table[static_cast<std::size_t>(format)];
361} 363}
362 364
365constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
366 32, // ABGR8U
367 32, // ABGR8S
368 32, // ABGR8UI
369 16, // B5G6R5U
370 32, // A2B10G10R10U
371 16, // A1B5G5R5U
372 8, // R8U
373 8, // R8UI
374 64, // RGBA16F
375 64, // RGBA16U
376 64, // RGBA16UI
377 32, // R11FG11FB10F
378 128, // RGBA32UI
379 64, // DXT1
380 128, // DXT23
381 128, // DXT45
382 64, // DXN1
383 128, // DXN2UNORM
384 128, // DXN2SNORM
385 128, // BC7U
386 128, // BC6H_UF16
387 128, // BC6H_SF16
388 128, // ASTC_2D_4X4
389 16, // G8R8U
390 16, // G8R8S
391 32, // BGRA8
392 128, // RGBA32F
393 64, // RG32F
394 32, // R32F
395 16, // R16F
396 16, // R16U
397 16, // R16S
398 16, // R16UI
399 16, // R16I
400 32, // RG16
401 32, // RG16F
402 32, // RG16UI
403 32, // RG16I
404 32, // RG16S
405 96, // RGB32F
406 32, // RGBA8_SRGB
407 16, // RG8U
408 16, // RG8S
409 64, // RG32UI
410 32, // R32UI
411 128, // ASTC_2D_8X8
412 128, // ASTC_2D_8X5
413 128, // ASTC_2D_5X4
414 32, // BGRA8_SRGB
415 64, // DXT1_SRGB
416 128, // DXT23_SRGB
417 128, // DXT45_SRGB
418 128, // BC7U
419 128, // ASTC_2D_4X4_SRGB
420 128, // ASTC_2D_8X8_SRGB
421 128, // ASTC_2D_8X5_SRGB
422 128, // ASTC_2D_5X4_SRGB
423 128, // ASTC_2D_5X5
424 128, // ASTC_2D_5X5_SRGB
425 128, // ASTC_2D_10X8
426 128, // ASTC_2D_10X8_SRGB
427 32, // Z32F
428 16, // Z16
429 32, // Z24S8
430 32, // S8Z24
431 64, // Z32FS8
432}};
433
363static constexpr u32 GetFormatBpp(PixelFormat format) { 434static constexpr u32 GetFormatBpp(PixelFormat format) {
364 if (format == PixelFormat::Invalid) 435 if (format == PixelFormat::Invalid)
365 return 0; 436 return 0;
366 437
367 constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
368 32, // ABGR8U
369 32, // ABGR8S
370 32, // ABGR8UI
371 16, // B5G6R5U
372 32, // A2B10G10R10U
373 16, // A1B5G5R5U
374 8, // R8U
375 8, // R8UI
376 64, // RGBA16F
377 64, // RGBA16U
378 64, // RGBA16UI
379 32, // R11FG11FB10F
380 128, // RGBA32UI
381 64, // DXT1
382 128, // DXT23
383 128, // DXT45
384 64, // DXN1
385 128, // DXN2UNORM
386 128, // DXN2SNORM
387 128, // BC7U
388 128, // BC6H_UF16
389 128, // BC6H_SF16
390 128, // ASTC_2D_4X4
391 16, // G8R8U
392 16, // G8R8S
393 32, // BGRA8
394 128, // RGBA32F
395 64, // RG32F
396 32, // R32F
397 16, // R16F
398 16, // R16U
399 16, // R16S
400 16, // R16UI
401 16, // R16I
402 32, // RG16
403 32, // RG16F
404 32, // RG16UI
405 32, // RG16I
406 32, // RG16S
407 96, // RGB32F
408 32, // RGBA8_SRGB
409 16, // RG8U
410 16, // RG8S
411 64, // RG32UI
412 32, // R32UI
413 128, // ASTC_2D_8X8
414 128, // ASTC_2D_8X5
415 128, // ASTC_2D_5X4
416 32, // BGRA8_SRGB
417 64, // DXT1_SRGB
418 128, // DXT23_SRGB
419 128, // DXT45_SRGB
420 128, // BC7U
421 128, // ASTC_2D_4X4_SRGB
422 128, // ASTC_2D_8X8_SRGB
423 128, // ASTC_2D_8X5_SRGB
424 128, // ASTC_2D_5X4_SRGB
425 128, // ASTC_2D_5X5
426 128, // ASTC_2D_5X5_SRGB
427 128, // ASTC_2D_10X8
428 128, // ASTC_2D_10X8_SRGB
429 32, // Z32F
430 16, // Z16
431 32, // Z24S8
432 32, // S8Z24
433 64, // Z32FS8
434 }};
435
436 ASSERT(static_cast<std::size_t>(format) < bpp_table.size()); 438 ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
437 return bpp_table[static_cast<std::size_t>(format)]; 439 return bpp_table[static_cast<std::size_t>(format)];
438} 440}
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 1edc60df7..9fd074223 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -86,6 +86,35 @@ QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager,
86 out.chop(1); 86 out.chop(1);
87 return out; 87 return out;
88} 88}
89
90QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::string& name,
91 const std::vector<u8>& icon, Loader::AppLoader& loader,
92 u64 program_id, const CompatibilityList& compatibility_list,
93 const FileSys::PatchManager& patch) {
94 const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
95
96 // The game list uses this as compatibility number for untested games
97 QString compatibility{"99"};
98 if (it != compatibility_list.end()) {
99 compatibility = it->second.first;
100 }
101
102 QList<QStandardItem*> list{
103 new GameListItemPath(
104 FormatGameName(path), icon, QString::fromStdString(name),
105 QString::fromStdString(Loader::GetFileTypeString(loader.GetFileType())), program_id),
106 new GameListItemCompat(compatibility),
107 new GameListItem(QString::fromStdString(Loader::GetFileTypeString(loader.GetFileType()))),
108 new GameListItemSize(FileUtil::GetSize(path)),
109 };
110
111 if (UISettings::values.show_add_ons) {
112 list.insert(
113 2, new GameListItem(FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable())));
114 }
115
116 return list;
117}
89} // Anonymous namespace 118} // Anonymous namespace
90 119
91GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan, 120GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan,
@@ -116,29 +145,8 @@ void GameListWorker::AddInstalledTitlesToGameList() {
116 if (control != nullptr) 145 if (control != nullptr)
117 GetMetadataFromControlNCA(patch, *control, icon, name); 146 GetMetadataFromControlNCA(patch, *control, icon, name);
118 147
119 auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); 148 emit EntryReady(MakeGameListEntry(file->GetFullPath(), name, icon, *loader, program_id,
120 149 compatibility_list, patch));
121 // The game list uses this as compatibility number for untested games
122 QString compatibility("99");
123 if (it != compatibility_list.end())
124 compatibility = it->second.first;
125
126 QList<QStandardItem*> list{
127 new GameListItemPath(
128 FormatGameName(file->GetFullPath()), icon, QString::fromStdString(name),
129 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())),
130 program_id),
131 new GameListItemCompat(compatibility),
132 new GameListItem(
133 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
134 new GameListItemSize(file->GetSize()),
135 };
136
137 if (UISettings::values.show_add_ons) {
138 list.insert(2, new GameListItem(FormatPatchNameVersions(patch, *loader)));
139 }
140
141 emit EntryReady(list);
142 } 150 }
143 151
144 const auto control_data = cache.ListEntriesFilter(FileSys::TitleType::Application, 152 const auto control_data = cache.ListEntriesFilter(FileSys::TitleType::Application,
@@ -155,14 +163,14 @@ void GameListWorker::AddInstalledTitlesToGameList() {
155void GameListWorker::FillControlMap(const std::string& dir_path) { 163void GameListWorker::FillControlMap(const std::string& dir_path) {
156 const auto nca_control_callback = [this](u64* num_entries_out, const std::string& directory, 164 const auto nca_control_callback = [this](u64* num_entries_out, const std::string& directory,
157 const std::string& virtual_name) -> bool { 165 const std::string& virtual_name) -> bool {
158 std::string physical_name = directory + DIR_SEP + virtual_name; 166 if (stop_processing) {
159 167 // Breaks the callback loop
160 if (stop_processing) 168 return false;
161 return false; // Breaks the callback loop. 169 }
162 170
163 bool is_dir = FileUtil::IsDirectory(physical_name); 171 const std::string physical_name = directory + DIR_SEP + virtual_name;
164 QFileInfo file_info(physical_name.c_str()); 172 const QFileInfo file_info(QString::fromStdString(physical_name));
165 if (!is_dir && file_info.suffix().toStdString() == "nca") { 173 if (!file_info.isDir() && file_info.suffix() == QStringLiteral("nca")) {
166 auto nca = 174 auto nca =
167 std::make_unique<FileSys::NCA>(vfs->OpenFile(physical_name, FileSys::Mode::Read)); 175 std::make_unique<FileSys::NCA>(vfs->OpenFile(physical_name, FileSys::Mode::Read));
168 if (nca->GetType() == FileSys::NCAContentType::Control) { 176 if (nca->GetType() == FileSys::NCAContentType::Control) {
@@ -179,12 +187,13 @@ void GameListWorker::FillControlMap(const std::string& dir_path) {
179void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { 187void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) {
180 const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory, 188 const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory,
181 const std::string& virtual_name) -> bool { 189 const std::string& virtual_name) -> bool {
182 std::string physical_name = directory + DIR_SEP + virtual_name; 190 if (stop_processing) {
183 191 // Breaks the callback loop.
184 if (stop_processing) 192 return false;
185 return false; // Breaks the callback loop. 193 }
186 194
187 bool is_dir = FileUtil::IsDirectory(physical_name); 195 const std::string physical_name = directory + DIR_SEP + virtual_name;
196 const bool is_dir = FileUtil::IsDirectory(physical_name);
188 if (!is_dir && 197 if (!is_dir &&
189 (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { 198 (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {
190 std::unique_ptr<Loader::AppLoader> loader = 199 std::unique_ptr<Loader::AppLoader> loader =
@@ -214,30 +223,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
214 } 223 }
215 } 224 }
216 225
217 auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); 226 emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, program_id,
218 227 compatibility_list, patch));
219 // The game list uses this as compatibility number for untested games
220 QString compatibility("99");
221 if (it != compatibility_list.end())
222 compatibility = it->second.first;
223
224 QList<QStandardItem*> list{
225 new GameListItemPath(
226 FormatGameName(physical_name), icon, QString::fromStdString(name),
227 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())),
228 program_id),
229 new GameListItemCompat(compatibility),
230 new GameListItem(
231 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
232 new GameListItemSize(FileUtil::GetSize(physical_name)),
233 };
234
235 if (UISettings::values.show_add_ons) {
236 list.insert(2, new GameListItem(FormatPatchNameVersions(
237 patch, *loader, loader->IsRomFSUpdatable())));
238 }
239
240 emit EntryReady(std::move(list));
241 } else if (is_dir && recursion > 0) { 228 } else if (is_dir && recursion > 0) {
242 watch_list.append(QString::fromStdString(physical_name)); 229 watch_list.append(QString::fromStdString(physical_name));
243 AddFstEntriesToGameList(physical_name, recursion - 1); 230 AddFstEntriesToGameList(physical_name, recursion - 1);