summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.ci/scripts/linux/docker.sh2
-rwxr-xr-x.ci/scripts/windows/docker.sh2
-rw-r--r--CMakeLists.txt5
-rw-r--r--README.md2
-rw-r--r--dist/languages/.gitignore2
-rw-r--r--dist/languages/.tx/config8
-rw-r--r--dist/languages/README.md1
-rw-r--r--src/audio_core/stream.cpp23
-rw-r--r--src/audio_core/stream.h10
-rw-r--r--src/common/alignment.h48
-rw-r--r--src/core/core_timing.cpp15
-rw-r--r--src/core/core_timing.h20
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.cpp4
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.h2
-rw-r--r--src/core/file_sys/vfs_concat.cpp8
-rw-r--r--src/core/file_sys/vfs_concat.h6
-rw-r--r--src/core/hardware_interrupt_manager.cpp15
-rw-r--r--src/core/hle/kernel/kernel.cpp8
-rw-r--r--src/core/hle/kernel/server_session.cpp6
-rw-r--r--src/core/hle/kernel/time_manager.cpp5
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp4
-rw-r--r--src/core/hle/service/hid/hid.cpp17
-rw-r--r--src/core/hle/service/hid/hid.h7
-rw-r--r--src/core/hle/service/mii/manager.cpp113
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp19
-rw-r--r--src/core/memory/cheat_engine.cpp16
-rw-r--r--src/core/memory/cheat_engine.h3
-rw-r--r--src/core/memory/dmnt_cheat_vm.cpp29
-rw-r--r--src/core/memory/dmnt_cheat_vm.h14
-rw-r--r--src/core/settings.cpp2
-rw-r--r--src/core/settings.h1
-rw-r--r--src/core/telemetry_session.cpp2
-rw-r--r--src/core/tools/freezer.cpp17
-rw-r--r--src/core/tools/freezer.h3
-rw-r--r--src/tests/core/core_timing.cpp27
-rw-r--r--src/video_core/CMakeLists.txt4
-rw-r--r--src/video_core/compatible_formats.cpp87
-rw-r--r--src/video_core/gpu.cpp2
-rw-r--r--src/video_core/gpu.h93
-rw-r--r--src/video_core/morton.cpp276
-rw-r--r--src/video_core/renderer_opengl/gl_arb_decompiler.cpp84
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_device.h5
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp125
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h14
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h6
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp181
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h36
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.cpp71
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h17
-rw-r--r--src/video_core/renderer_opengl/gl_stream_buffer.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp162
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp4
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp173
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp63
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp194
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp131
-rw-r--r--src/video_core/renderer_vulkan/vk_descriptor_pool.cpp33
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp15
-rw-r--r--src/video_core/renderer_vulkan/vk_image.cpp38
-rw-r--r--src/video_core/renderer_vulkan/vk_memory_manager.cpp13
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp66
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp16
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp88
-rw-r--r--src/video_core/renderer_vulkan/vk_renderpass_cache.cpp129
-rw-r--r--src/video_core/renderer_vulkan/vk_resource_manager.cpp29
-rw-r--r--src/video_core/renderer_vulkan/vk_sampler_cache.cpp51
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp57
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_util.cpp14
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp25
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.cpp35
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp94
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp241
-rw-r--r--src/video_core/renderer_vulkan/wrapper.cpp120
-rw-r--r--src/video_core/shader/async_shaders.cpp181
-rw-r--r--src/video_core/shader/async_shaders.h109
-rw-r--r--src/video_core/shader/decode/image.cpp54
-rw-r--r--src/video_core/shader_notify.cpp42
-rw-r--r--src/video_core/shader_notify.h29
-rw-r--r--src/video_core/surface.cpp257
-rw-r--r--src/video_core/surface.h770
-rw-r--r--src/video_core/texture_cache/format_lookup_table.cpp147
-rw-r--r--src/video_core/texture_cache/surface_base.cpp2
-rw-r--r--src/video_core/texture_cache/surface_params.cpp18
-rw-r--r--src/video_core/texture_cache/texture_cache.h8
-rw-r--r--src/video_core/textures/convert.cpp6
-rw-r--r--src/video_core/textures/decoders.cpp89
-rw-r--r--src/video_core/textures/decoders.h4
-rw-r--r--src/video_core/textures/texture.h49
-rw-r--r--src/yuzu/CMakeLists.txt33
-rw-r--r--src/yuzu/configuration/config.cpp6
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp9
-rw-r--r--src/yuzu/configuration/configure_dialog.h6
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp22
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui10
-rw-r--r--src/yuzu/configuration/configure_ui.cpp31
-rw-r--r--src/yuzu/configuration/configure_ui.h7
-rw-r--r--src/yuzu/configuration/configure_ui.ui188
-rw-r--r--src/yuzu/debugger/wait_tree.cpp52
-rw-r--r--src/yuzu/main.cpp74
-rw-r--r--src/yuzu/main.h6
-rw-r--r--src/yuzu/uisettings.h1
-rw-r--r--src/yuzu_cmd/config.cpp4
-rw-r--r--src/yuzu_cmd/default_ini.h4
106 files changed, 3239 insertions, 2247 deletions
diff --git a/.ci/scripts/linux/docker.sh b/.ci/scripts/linux/docker.sh
index 5559a527c..277775ef6 100755
--- a/.ci/scripts/linux/docker.sh
+++ b/.ci/scripts/linux/docker.sh
@@ -5,7 +5,7 @@ cd /yuzu
5ccache -s 5ccache -s
6 6
7mkdir build || true && cd build 7mkdir build || true && cd build
8cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON 8cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON
9 9
10ninja 10ninja
11 11
diff --git a/.ci/scripts/windows/docker.sh b/.ci/scripts/windows/docker.sh
index d53281741..adfd636fa 100755
--- a/.ci/scripts/windows/docker.sh
+++ b/.ci/scripts/windows/docker.sh
@@ -5,7 +5,7 @@ cd /yuzu
5ccache -s 5ccache -s
6 6
7mkdir build || true && cd build 7mkdir build || true && cd build
8cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release 8cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_QT_TRANSLATION=ON
9ninja 9ninja
10 10
11ccache -s 11ccache -s
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ce46a2c2b..7a49318aa 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,6 +13,7 @@ project(yuzu)
13option(ENABLE_SDL2 "Enable the SDL2 frontend" ON) 13option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
14 14
15option(ENABLE_QT "Enable the Qt frontend" ON) 15option(ENABLE_QT "Enable the Qt frontend" ON)
16option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
16CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "ENABLE_QT;MSVC" OFF) 17CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "ENABLE_QT;MSVC" OFF)
17 18
18option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON) 19option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
@@ -224,6 +225,10 @@ if(ENABLE_QT)
224 if (YUZU_USE_QT_WEB_ENGINE) 225 if (YUZU_USE_QT_WEB_ENGINE)
225 find_package(Qt5 COMPONENTS WebEngineCore WebEngineWidgets) 226 find_package(Qt5 COMPONENTS WebEngineCore WebEngineWidgets)
226 endif() 227 endif()
228
229 if (ENABLE_QT_TRANSLATION)
230 find_package(Qt5 REQUIRED COMPONENTS LinguistTools ${QT_PREFIX_HINT})
231 endif()
227 if (NOT Qt5_FOUND) 232 if (NOT Qt5_FOUND)
228 list(APPEND CONAN_REQUIRED_LIBS "qt/5.14.1@bincrafters/stable") 233 list(APPEND CONAN_REQUIRED_LIBS "qt/5.14.1@bincrafters/stable")
229 endif() 234 endif()
diff --git a/README.md b/README.md
index e4ecb531d..981c8ef24 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,8 @@ Most of the development happens on GitHub. It's also where [our central reposito
24 24
25If you want to contribute please take a look at the [Contributor's Guide](https://github.com/yuzu-emu/yuzu/wiki/Contributing) and [Developer Information](https://github.com/yuzu-emu/yuzu/wiki/Developer-Information). You should also contact any of the developers on Discord in order to know about the current state of the emulator. 25If you want to contribute please take a look at the [Contributor's Guide](https://github.com/yuzu-emu/yuzu/wiki/Contributing) and [Developer Information](https://github.com/yuzu-emu/yuzu/wiki/Developer-Information). You should also contact any of the developers on Discord in order to know about the current state of the emulator.
26 26
27If you want to contribute to the user interface translation, please check out the [yuzu project on transifex](https://www.transifex.com/yuzu-emulator/yuzu). We centralize translation work there, and periodically upstream translations.
28
27### Building 29### Building
28 30
29* __Windows__: [Windows Build](https://github.com/yuzu-emu/yuzu/wiki/Building-For-Windows) 31* __Windows__: [Windows Build](https://github.com/yuzu-emu/yuzu/wiki/Building-For-Windows)
diff --git a/dist/languages/.gitignore b/dist/languages/.gitignore
new file mode 100644
index 000000000..27e5a0158
--- /dev/null
+++ b/dist/languages/.gitignore
@@ -0,0 +1,2 @@
1# Ignore the source language file
2en.ts
diff --git a/dist/languages/.tx/config b/dist/languages/.tx/config
new file mode 100644
index 000000000..0d9b512ea
--- /dev/null
+++ b/dist/languages/.tx/config
@@ -0,0 +1,8 @@
1[main]
2host = https://www.transifex.com
3
4[yuzu.emulator]
5file_filter = <lang>.ts
6source_file = en.ts
7source_lang = en
8type = QT
diff --git a/dist/languages/README.md b/dist/languages/README.md
new file mode 100644
index 000000000..61981ab1d
--- /dev/null
+++ b/dist/languages/README.md
@@ -0,0 +1 @@
This directory stores translation patches (TS files) for yuzu Qt frontend. This directory is linked with [yuzu project on transifex](https://www.transifex.com/yuzu-emulator/yuzu), so you can update the translation by executing `tx pull -a`. If you want to contribute to the translation, please go the transifex link and submit your translation there. This directory on the main repo will be synchronized with transifex periodically. Do not directly open PRs on github to modify the translation.
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index aab3e979a..f80ab92e4 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -38,7 +38,7 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format fo
38 sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} { 38 sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} {
39 39
40 release_event = Core::Timing::CreateEvent( 40 release_event = Core::Timing::CreateEvent(
41 name, [this](u64 userdata, s64 cycles_late) { ReleaseActiveBuffer(cycles_late); }); 41 name, [this](u64, std::chrono::nanoseconds ns_late) { ReleaseActiveBuffer(ns_late); });
42} 42}
43 43
44void Stream::Play() { 44void Stream::Play() {
@@ -59,11 +59,9 @@ Stream::State Stream::GetState() const {
59 return state; 59 return state;
60} 60}
61 61
62s64 Stream::GetBufferReleaseNS(const Buffer& buffer) const { 62std::chrono::nanoseconds Stream::GetBufferReleaseNS(const Buffer& buffer) const {
63 const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()}; 63 const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()};
64 const auto ns = 64 return std::chrono::nanoseconds((static_cast<u64>(num_samples) * 1000000000ULL) / sample_rate);
65 std::chrono::nanoseconds((static_cast<u64>(num_samples) * 1000000000ULL) / sample_rate);
66 return ns.count();
67} 65}
68 66
69static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) { 67static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) {
@@ -80,7 +78,7 @@ static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) {
80 } 78 }
81} 79}
82 80
83void Stream::PlayNextBuffer(s64 cycles_late) { 81void Stream::PlayNextBuffer(std::chrono::nanoseconds ns_late) {
84 if (!IsPlaying()) { 82 if (!IsPlaying()) {
85 // Ensure we are in playing state before playing the next buffer 83 // Ensure we are in playing state before playing the next buffer
86 sink_stream.Flush(); 84 sink_stream.Flush();
@@ -105,17 +103,18 @@ void Stream::PlayNextBuffer(s64 cycles_late) {
105 103
106 sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples()); 104 sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
107 105
108 core_timing.ScheduleEvent( 106 const auto time_stretch_delta = Settings::values.enable_audio_stretching.GetValue()
109 GetBufferReleaseNS(*active_buffer) - 107 ? std::chrono::nanoseconds::zero()
110 (Settings::values.enable_audio_stretching.GetValue() ? 0 : cycles_late), 108 : ns_late;
111 release_event, {}); 109 const auto future_time = GetBufferReleaseNS(*active_buffer) - time_stretch_delta;
110 core_timing.ScheduleEvent(future_time, release_event, {});
112} 111}
113 112
114void Stream::ReleaseActiveBuffer(s64 cycles_late) { 113void Stream::ReleaseActiveBuffer(std::chrono::nanoseconds ns_late) {
115 ASSERT(active_buffer); 114 ASSERT(active_buffer);
116 released_buffers.push(std::move(active_buffer)); 115 released_buffers.push(std::move(active_buffer));
117 release_callback(); 116 release_callback();
118 PlayNextBuffer(cycles_late); 117 PlayNextBuffer(ns_late);
119} 118}
120 119
121bool Stream::QueueBuffer(BufferPtr&& buffer) { 120bool Stream::QueueBuffer(BufferPtr&& buffer) {
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h
index 524376257..6437b8591 100644
--- a/src/audio_core/stream.h
+++ b/src/audio_core/stream.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <chrono>
7#include <functional> 8#include <functional>
8#include <memory> 9#include <memory>
9#include <string> 10#include <string>
@@ -90,16 +91,13 @@ public:
90 91
91private: 92private:
92 /// Plays the next queued buffer in the audio stream, starting playback if necessary 93 /// Plays the next queued buffer in the audio stream, starting playback if necessary
93 void PlayNextBuffer(s64 cycles_late = 0); 94 void PlayNextBuffer(std::chrono::nanoseconds ns_late = {});
94 95
95 /// Releases the actively playing buffer, signalling that it has been completed 96 /// Releases the actively playing buffer, signalling that it has been completed
96 void ReleaseActiveBuffer(s64 cycles_late = 0); 97 void ReleaseActiveBuffer(std::chrono::nanoseconds ns_late = {});
97 98
98 /// Gets the number of core cycles when the specified buffer will be released 99 /// Gets the number of core cycles when the specified buffer will be released
99 s64 GetBufferReleaseNS(const Buffer& buffer) const; 100 std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const;
100
101 /// Gets the number of core cycles when the specified buffer will be released
102 s64 GetBufferReleaseNSHostTiming(const Buffer& buffer) const;
103 101
104 u32 sample_rate; ///< Sample rate of the stream 102 u32 sample_rate; ///< Sample rate of the stream
105 Format format; ///< Format of the stream 103 Format format; ///< Format of the stream
diff --git a/src/common/alignment.h b/src/common/alignment.h
index b37044bb6..ef4d6f896 100644
--- a/src/common/alignment.h
+++ b/src/common/alignment.h
@@ -3,7 +3,7 @@
3#pragma once 3#pragma once
4 4
5#include <cstddef> 5#include <cstddef>
6#include <memory> 6#include <new>
7#include <type_traits> 7#include <type_traits>
8 8
9namespace Common { 9namespace Common {
@@ -54,66 +54,28 @@ public:
54 using size_type = std::size_t; 54 using size_type = std::size_t;
55 using difference_type = std::ptrdiff_t; 55 using difference_type = std::ptrdiff_t;
56 56
57 using pointer = T*;
58 using const_pointer = const T*;
59
60 using reference = T&;
61 using const_reference = const T&;
62
63 using propagate_on_container_copy_assignment = std::true_type; 57 using propagate_on_container_copy_assignment = std::true_type;
64 using propagate_on_container_move_assignment = std::true_type; 58 using propagate_on_container_move_assignment = std::true_type;
65 using propagate_on_container_swap = std::true_type; 59 using propagate_on_container_swap = std::true_type;
66 using is_always_equal = std::true_type; 60 using is_always_equal = std::true_type;
67 61
68public:
69 constexpr AlignmentAllocator() noexcept = default; 62 constexpr AlignmentAllocator() noexcept = default;
70 63
71 template <typename T2> 64 template <typename T2>
72 constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {} 65 constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {}
73 66
74 pointer address(reference r) noexcept { 67 T* allocate(size_type n) {
75 return std::addressof(r); 68 return static_cast<T*>(::operator new (n * sizeof(T), std::align_val_t{Align}));
76 }
77
78 const_pointer address(const_reference r) const noexcept {
79 return std::addressof(r);
80 }
81
82 pointer allocate(size_type n) {
83 return static_cast<pointer>(::operator new (n, std::align_val_t{Align}));
84 }
85
86 void deallocate(pointer p, size_type) {
87 ::operator delete (p, std::align_val_t{Align});
88 } 69 }
89 70
90 void construct(pointer p, const value_type& wert) { 71 void deallocate(T* p, size_type n) {
91 new (p) value_type(wert); 72 ::operator delete (p, n * sizeof(T), std::align_val_t{Align});
92 }
93
94 void destroy(pointer p) {
95 p->~value_type();
96 }
97
98 size_type max_size() const noexcept {
99 return size_type(-1) / sizeof(value_type);
100 } 73 }
101 74
102 template <typename T2> 75 template <typename T2>
103 struct rebind { 76 struct rebind {
104 using other = AlignmentAllocator<T2, Align>; 77 using other = AlignmentAllocator<T2, Align>;
105 }; 78 };
106
107 bool operator!=(const AlignmentAllocator<T, Align>& other) const noexcept {
108 return !(*this == other);
109 }
110
111 // Returns true if and only if storage allocated from *this
112 // can be deallocated from other, and vice versa.
113 // Always returns true for stateless allocators.
114 bool operator==(const AlignmentAllocator<T, Align>& other) const noexcept {
115 return true;
116 }
117}; 79};
118 80
119} // namespace Common 81} // namespace Common
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index a63e60461..b5feb3f24 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -53,12 +53,12 @@ void CoreTiming::ThreadEntry(CoreTiming& instance) {
53 instance.ThreadLoop(); 53 instance.ThreadLoop();
54} 54}
55 55
56void CoreTiming::Initialize(std::function<void(void)>&& on_thread_init_) { 56void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
57 on_thread_init = std::move(on_thread_init_); 57 on_thread_init = std::move(on_thread_init_);
58 event_fifo_id = 0; 58 event_fifo_id = 0;
59 shutting_down = false; 59 shutting_down = false;
60 ticks = 0; 60 ticks = 0;
61 const auto empty_timed_callback = [](u64, s64) {}; 61 const auto empty_timed_callback = [](u64, std::chrono::nanoseconds) {};
62 ev_lost = CreateEvent("_lost_event", empty_timed_callback); 62 ev_lost = CreateEvent("_lost_event", empty_timed_callback);
63 if (is_multicore) { 63 if (is_multicore) {
64 timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this)); 64 timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this));
@@ -106,11 +106,11 @@ bool CoreTiming::HasPendingEvents() const {
106 return !(wait_set && event_queue.empty()); 106 return !(wait_set && event_queue.empty());
107} 107}
108 108
109void CoreTiming::ScheduleEvent(s64 ns_into_future, const std::shared_ptr<EventType>& event_type, 109void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
110 u64 userdata) { 110 const std::shared_ptr<EventType>& event_type, u64 userdata) {
111 { 111 {
112 std::scoped_lock scope{basic_lock}; 112 std::scoped_lock scope{basic_lock};
113 const u64 timeout = static_cast<u64>(GetGlobalTimeNs().count() + ns_into_future); 113 const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count());
114 114
115 event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); 115 event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type});
116 116
@@ -195,8 +195,9 @@ std::optional<s64> CoreTiming::Advance() {
195 event_queue.pop_back(); 195 event_queue.pop_back();
196 basic_lock.unlock(); 196 basic_lock.unlock();
197 197
198 if (auto event_type{evt.type.lock()}) { 198 if (const auto event_type{evt.type.lock()}) {
199 event_type->callback(evt.userdata, global_timer - evt.time); 199 event_type->callback(
200 evt.userdata, std::chrono::nanoseconds{static_cast<s64>(global_timer - evt.time)});
200 } 201 }
201 202
202 basic_lock.lock(); 203 basic_lock.lock();
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 72faaab64..120c74e46 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -17,14 +17,12 @@
17#include "common/common_types.h" 17#include "common/common_types.h"
18#include "common/spin_lock.h" 18#include "common/spin_lock.h"
19#include "common/thread.h" 19#include "common/thread.h"
20#include "common/threadsafe_queue.h"
21#include "common/wall_clock.h" 20#include "common/wall_clock.h"
22#include "core/hardware_properties.h"
23 21
24namespace Core::Timing { 22namespace Core::Timing {
25 23
26/// A callback that may be scheduled for a particular core timing event. 24/// A callback that may be scheduled for a particular core timing event.
27using TimedCallback = std::function<void(u64 userdata, s64 cycles_late)>; 25using TimedCallback = std::function<void(u64 userdata, std::chrono::nanoseconds ns_late)>;
28 26
29/// Contains the characteristics of a particular event. 27/// Contains the characteristics of a particular event.
30struct EventType { 28struct EventType {
@@ -42,12 +40,12 @@ struct EventType {
42 * in main CPU clock cycles. 40 * in main CPU clock cycles.
43 * 41 *
44 * To schedule an event, you first have to register its type. This is where you pass in the 42 * To schedule an event, you first have to register its type. This is where you pass in the
45 * callback. You then schedule events using the type id you get back. 43 * callback. You then schedule events using the type ID you get back.
46 * 44 *
47 * The int cyclesLate that the callbacks get is how many cycles late it was. 45 * The s64 ns_late that the callbacks get is how many ns late it was.
48 * So to schedule a new event on a regular basis: 46 * So to schedule a new event on a regular basis:
49 * inside callback: 47 * inside callback:
50 * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever") 48 * ScheduleEvent(period_in_ns - ns_late, callback, "whatever")
51 */ 49 */
52class CoreTiming { 50class CoreTiming {
53public: 51public:
@@ -62,7 +60,7 @@ public:
62 60
63 /// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is 61 /// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
64 /// required to end slice - 1 and start slice 0 before the first cycle of code is executed. 62 /// required to end slice - 1 and start slice 0 before the first cycle of code is executed.
65 void Initialize(std::function<void(void)>&& on_thread_init_); 63 void Initialize(std::function<void()>&& on_thread_init_);
66 64
67 /// Tears down all timing related functionality. 65 /// Tears down all timing related functionality.
68 void Shutdown(); 66 void Shutdown();
@@ -95,8 +93,8 @@ public:
95 bool HasPendingEvents() const; 93 bool HasPendingEvents() const;
96 94
97 /// Schedules an event in core timing 95 /// Schedules an event in core timing
98 void ScheduleEvent(s64 ns_into_future, const std::shared_ptr<EventType>& event_type, 96 void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
99 u64 userdata = 0); 97 const std::shared_ptr<EventType>& event_type, u64 userdata = 0);
100 98
101 void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata); 99 void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata);
102 100
@@ -141,8 +139,6 @@ private:
141 139
142 u64 global_timer = 0; 140 u64 global_timer = 0;
143 141
144 std::chrono::nanoseconds start_point;
145
146 // The queue is a min-heap using std::make_heap/push_heap/pop_heap. 142 // The queue is a min-heap using std::make_heap/push_heap/pop_heap.
147 // We don't use std::priority_queue because we need to be able to serialize, unserialize and 143 // We don't use std::priority_queue because we need to be able to serialize, unserialize and
148 // erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't 144 // erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't
@@ -161,7 +157,7 @@ private:
161 std::atomic<bool> wait_set{}; 157 std::atomic<bool> wait_set{};
162 std::atomic<bool> shutting_down{}; 158 std::atomic<bool> shutting_down{};
163 std::atomic<bool> has_started{}; 159 std::atomic<bool> has_started{};
164 std::function<void(void)> on_thread_init{}; 160 std::function<void()> on_thread_init{};
165 161
166 bool is_multicore{}; 162 bool is_multicore{};
167 163
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp
index d126ae8dd..2aff2708a 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.cpp
+++ b/src/core/file_sys/fsmitm_romfsbuild.cpp
@@ -240,7 +240,7 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_, VirtualDir ext_)
240 240
241RomFSBuildContext::~RomFSBuildContext() = default; 241RomFSBuildContext::~RomFSBuildContext() = default;
242 242
243std::map<u64, VirtualFile> RomFSBuildContext::Build() { 243std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
244 const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); 244 const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs);
245 const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files); 245 const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files);
246 dir_hash_table_size = 4 * dir_hash_table_entry_count; 246 dir_hash_table_size = 4 * dir_hash_table_entry_count;
@@ -294,7 +294,7 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
294 cur_dir->parent->child = cur_dir; 294 cur_dir->parent->child = cur_dir;
295 } 295 }
296 296
297 std::map<u64, VirtualFile> out; 297 std::multimap<u64, VirtualFile> out;
298 298
299 // Populate file tables. 299 // Populate file tables.
300 for (const auto& it : files) { 300 for (const auto& it : files) {
diff --git a/src/core/file_sys/fsmitm_romfsbuild.h b/src/core/file_sys/fsmitm_romfsbuild.h
index a62502193..049de180b 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.h
+++ b/src/core/file_sys/fsmitm_romfsbuild.h
@@ -43,7 +43,7 @@ public:
43 ~RomFSBuildContext(); 43 ~RomFSBuildContext();
44 44
45 // This finalizes the context. 45 // This finalizes the context.
46 std::map<u64, VirtualFile> Build(); 46 std::multimap<u64, VirtualFile> Build();
47 47
48private: 48private:
49 VirtualDir base; 49 VirtualDir base;
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp
index 16d801c0c..e0ff70174 100644
--- a/src/core/file_sys/vfs_concat.cpp
+++ b/src/core/file_sys/vfs_concat.cpp
@@ -11,7 +11,7 @@
11 11
12namespace FileSys { 12namespace FileSys {
13 13
14static bool VerifyConcatenationMapContinuity(const std::map<u64, VirtualFile>& map) { 14static bool VerifyConcatenationMapContinuity(const std::multimap<u64, VirtualFile>& map) {
15 const auto last_valid = --map.end(); 15 const auto last_valid = --map.end();
16 for (auto iter = map.begin(); iter != last_valid;) { 16 for (auto iter = map.begin(); iter != last_valid;) {
17 const auto old = iter++; 17 const auto old = iter++;
@@ -27,12 +27,12 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::s
27 : name(std::move(name)) { 27 : name(std::move(name)) {
28 std::size_t next_offset = 0; 28 std::size_t next_offset = 0;
29 for (const auto& file : files_) { 29 for (const auto& file : files_) {
30 files[next_offset] = file; 30 files.emplace(next_offset, file);
31 next_offset += file->GetSize(); 31 next_offset += file->GetSize();
32 } 32 }
33} 33}
34 34
35ConcatenatedVfsFile::ConcatenatedVfsFile(std::map<u64, VirtualFile> files_, std::string name) 35ConcatenatedVfsFile::ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files_, std::string name)
36 : files(std::move(files_)), name(std::move(name)) { 36 : files(std::move(files_)), name(std::move(name)) {
37 ASSERT(VerifyConcatenationMapContinuity(files)); 37 ASSERT(VerifyConcatenationMapContinuity(files));
38} 38}
@@ -50,7 +50,7 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::vector<VirtualFile> f
50} 50}
51 51
52VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, 52VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
53 std::map<u64, VirtualFile> files, 53 std::multimap<u64, VirtualFile> files,
54 std::string name) { 54 std::string name) {
55 if (files.empty()) 55 if (files.empty())
56 return nullptr; 56 return nullptr;
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h
index c90f9d5d1..7a26343c0 100644
--- a/src/core/file_sys/vfs_concat.h
+++ b/src/core/file_sys/vfs_concat.h
@@ -15,7 +15,7 @@ namespace FileSys {
15// read-only. 15// read-only.
16class ConcatenatedVfsFile : public VfsFile { 16class ConcatenatedVfsFile : public VfsFile {
17 ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name); 17 ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name);
18 ConcatenatedVfsFile(std::map<u64, VirtualFile> files, std::string name); 18 ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files, std::string name);
19 19
20public: 20public:
21 ~ConcatenatedVfsFile() override; 21 ~ConcatenatedVfsFile() override;
@@ -25,7 +25,7 @@ public:
25 25
26 /// Convenience function that turns a map of offsets to files into a concatenated file, filling 26 /// Convenience function that turns a map of offsets to files into a concatenated file, filling
27 /// gaps with a given filler byte. 27 /// gaps with a given filler byte.
28 static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::map<u64, VirtualFile> files, 28 static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::multimap<u64, VirtualFile> files,
29 std::string name); 29 std::string name);
30 30
31 std::string GetName() const override; 31 std::string GetName() const override;
@@ -40,7 +40,7 @@ public:
40 40
41private: 41private:
42 // Maps starting offset to file -- more efficient. 42 // Maps starting offset to file -- more efficient.
43 std::map<u64, VirtualFile> files; 43 std::multimap<u64, VirtualFile> files;
44 std::string name; 44 std::string name;
45}; 45};
46 46
diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp
index c629d9fa1..efc1030c1 100644
--- a/src/core/hardware_interrupt_manager.cpp
+++ b/src/core/hardware_interrupt_manager.cpp
@@ -11,19 +11,20 @@
11namespace Core::Hardware { 11namespace Core::Hardware {
12 12
13InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { 13InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) {
14 gpu_interrupt_event = Core::Timing::CreateEvent("GPUInterrupt", [this](u64 message, s64) { 14 gpu_interrupt_event =
15 auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv"); 15 Core::Timing::CreateEvent("GPUInterrupt", [this](u64 message, std::chrono::nanoseconds) {
16 const u32 syncpt = static_cast<u32>(message >> 32); 16 auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv");
17 const u32 value = static_cast<u32>(message); 17 const u32 syncpt = static_cast<u32>(message >> 32);
18 nvdrv->SignalGPUInterruptSyncpt(syncpt, value); 18 const u32 value = static_cast<u32>(message);
19 }); 19 nvdrv->SignalGPUInterruptSyncpt(syncpt, value);
20 });
20} 21}
21 22
22InterruptManager::~InterruptManager() = default; 23InterruptManager::~InterruptManager() = default;
23 24
24void InterruptManager::GPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) { 25void InterruptManager::GPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) {
25 const u64 msg = (static_cast<u64>(syncpoint_id) << 32ULL) | value; 26 const u64 msg = (static_cast<u64>(syncpoint_id) << 32ULL) | value;
26 system.CoreTiming().ScheduleEvent(10, gpu_interrupt_event, msg); 27 system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{10}, gpu_interrupt_event, msg);
27} 28}
28 29
29} // namespace Core::Hardware 30} // namespace Core::Hardware
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index e1c7a0f3b..8dd4a2637 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -145,16 +145,18 @@ struct KernelCore::Impl {
145 145
146 void InitializePreemption(KernelCore& kernel) { 146 void InitializePreemption(KernelCore& kernel) {
147 preemption_event = Core::Timing::CreateEvent( 147 preemption_event = Core::Timing::CreateEvent(
148 "PreemptionCallback", [this, &kernel](u64 userdata, s64 cycles_late) { 148 "PreemptionCallback", [this, &kernel](u64, std::chrono::nanoseconds) {
149 { 149 {
150 SchedulerLock lock(kernel); 150 SchedulerLock lock(kernel);
151 global_scheduler.PreemptThreads(); 151 global_scheduler.PreemptThreads();
152 } 152 }
153 s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10)); 153 const auto time_interval = std::chrono::nanoseconds{
154 Core::Timing::msToCycles(std::chrono::milliseconds(10))};
154 system.CoreTiming().ScheduleEvent(time_interval, preemption_event); 155 system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
155 }); 156 });
156 157
157 s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10)); 158 const auto time_interval =
159 std::chrono::nanoseconds{Core::Timing::msToCycles(std::chrono::milliseconds(10))};
158 system.CoreTiming().ScheduleEvent(time_interval, preemption_event); 160 system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
159 } 161 }
160 162
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 7b23a6889..af22f4c33 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -34,7 +34,7 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kern
34 std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; 34 std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)};
35 35
36 session->request_event = Core::Timing::CreateEvent( 36 session->request_event = Core::Timing::CreateEvent(
37 name, [session](u64 userdata, s64 cycles_late) { session->CompleteSyncRequest(); }); 37 name, [session](u64, std::chrono::nanoseconds) { session->CompleteSyncRequest(); });
38 session->name = std::move(name); 38 session->name = std::move(name);
39 session->parent = std::move(parent); 39 session->parent = std::move(parent);
40 40
@@ -184,8 +184,8 @@ ResultCode ServerSession::CompleteSyncRequest() {
184 184
185ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, 185ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
186 Core::Memory::Memory& memory) { 186 Core::Memory::Memory& memory) {
187 ResultCode result = QueueSyncRequest(std::move(thread), memory); 187 const ResultCode result = QueueSyncRequest(std::move(thread), memory);
188 const u64 delay = kernel.IsMulticore() ? 0U : 20000U; 188 const auto delay = std::chrono::nanoseconds{kernel.IsMulticore() ? 0 : 20000};
189 Core::System::GetInstance().CoreTiming().ScheduleEvent(delay, request_event, {}); 189 Core::System::GetInstance().CoreTiming().ScheduleEvent(delay, request_event, {});
190 return result; 190 return result;
191} 191}
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
index 941305e8e..88b01b751 100644
--- a/src/core/hle/kernel/time_manager.cpp
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -16,7 +16,7 @@ namespace Kernel {
16 16
17TimeManager::TimeManager(Core::System& system_) : system{system_} { 17TimeManager::TimeManager(Core::System& system_) : system{system_} {
18 time_manager_event_type = Core::Timing::CreateEvent( 18 time_manager_event_type = Core::Timing::CreateEvent(
19 "Kernel::TimeManagerCallback", [this](u64 thread_handle, [[maybe_unused]] s64 cycles_late) { 19 "Kernel::TimeManagerCallback", [this](u64 thread_handle, std::chrono::nanoseconds) {
20 SchedulerLock lock(system.Kernel()); 20 SchedulerLock lock(system.Kernel());
21 Handle proper_handle = static_cast<Handle>(thread_handle); 21 Handle proper_handle = static_cast<Handle>(thread_handle);
22 if (cancelled_events[proper_handle]) { 22 if (cancelled_events[proper_handle]) {
@@ -34,7 +34,8 @@ void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64
34 ASSERT(timetask); 34 ASSERT(timetask);
35 ASSERT(timetask->GetStatus() != ThreadStatus::Ready); 35 ASSERT(timetask->GetStatus() != ThreadStatus::Ready);
36 ASSERT(timetask->GetStatus() != ThreadStatus::WaitMutex); 36 ASSERT(timetask->GetStatus() != ThreadStatus::WaitMutex);
37 system.CoreTiming().ScheduleEvent(nanoseconds, time_manager_event_type, event_handle); 37 system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{nanoseconds},
38 time_manager_event_type, event_handle);
38 } else { 39 } else {
39 event_handle = InvalidHandle; 40 event_handle = InvalidHandle;
40 } 41 }
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index cadc03805..c66124998 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -55,6 +55,10 @@ std::string VfsDirectoryServiceWrapper::GetName() const {
55ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size) const { 55ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size) const {
56 std::string path(FileUtil::SanitizePath(path_)); 56 std::string path(FileUtil::SanitizePath(path_));
57 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); 57 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
58 // dir can be nullptr if path contains subdirectories, create those prior to creating the file.
59 if (dir == nullptr) {
60 dir = backing->CreateSubdirectory(FileUtil::GetParentPath(path));
61 }
58 auto file = dir->CreateFile(FileUtil::GetFilename(path)); 62 auto file = dir->CreateFile(FileUtil::GetFilename(path));
59 if (file == nullptr) { 63 if (file == nullptr) {
60 // TODO(DarkLordZach): Find a better error code for this 64 // TODO(DarkLordZach): Find a better error code for this
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index e9020e0dc..680290cbd 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -39,9 +39,10 @@ namespace Service::HID {
39 39
40// Updating period for each HID device. 40// Updating period for each HID device.
41// TODO(ogniK): Find actual polling rate of hid 41// TODO(ogniK): Find actual polling rate of hid
42constexpr s64 pad_update_ticks = static_cast<s64>(1000000000 / 66); 42constexpr auto pad_update_ns = std::chrono::nanoseconds{1000000000 / 66};
43[[maybe_unused]] constexpr s64 accelerometer_update_ticks = static_cast<s64>(1000000000 / 100); 43[[maybe_unused]] constexpr auto accelerometer_update_ns =
44[[maybe_unused]] constexpr s64 gyroscope_update_ticks = static_cast<s64>(1000000000 / 100); 44 std::chrono::nanoseconds{1000000000 / 100};
45[[maybe_unused]] constexpr auto gyroscope_update_ticks = std::chrono::nanoseconds{1000000000 / 100};
45constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; 46constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
46 47
47IAppletResource::IAppletResource(Core::System& system) 48IAppletResource::IAppletResource(Core::System& system)
@@ -75,14 +76,14 @@ IAppletResource::IAppletResource(Core::System& system)
75 GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); 76 GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
76 77
77 // Register update callbacks 78 // Register update callbacks
78 pad_update_event = 79 pad_update_event = Core::Timing::CreateEvent(
79 Core::Timing::CreateEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 ns_late) { 80 "HID::UpdatePadCallback", [this](u64 userdata, std::chrono::nanoseconds ns_late) {
80 UpdateControllers(userdata, ns_late); 81 UpdateControllers(userdata, ns_late);
81 }); 82 });
82 83
83 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) 84 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
84 85
85 system.CoreTiming().ScheduleEvent(pad_update_ticks, pad_update_event); 86 system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event);
86 87
87 ReloadInputDevices(); 88 ReloadInputDevices();
88} 89}
@@ -107,7 +108,7 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
107 rb.PushCopyObjects(shared_mem); 108 rb.PushCopyObjects(shared_mem);
108} 109}
109 110
110void IAppletResource::UpdateControllers(u64 userdata, s64 ns_late) { 111void IAppletResource::UpdateControllers(u64 userdata, std::chrono::nanoseconds ns_late) {
111 auto& core_timing = system.CoreTiming(); 112 auto& core_timing = system.CoreTiming();
112 113
113 const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); 114 const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
@@ -118,7 +119,7 @@ void IAppletResource::UpdateControllers(u64 userdata, s64 ns_late) {
118 controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE); 119 controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
119 } 120 }
120 121
121 core_timing.ScheduleEvent(pad_update_ticks - ns_late, pad_update_event); 122 core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
122} 123}
123 124
124class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { 125class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 6fb048360..c6f0a2584 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -4,10 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/service/hid/controllers/controller_base.h" 7#include <chrono>
8#include "core/hle/service/service.h"
9 8
10#include "controllers/controller_base.h" 9#include "core/hle/service/hid/controllers/controller_base.h"
11#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
12 11
13namespace Core::Timing { 12namespace Core::Timing {
@@ -65,7 +64,7 @@ private:
65 } 64 }
66 65
67 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); 66 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
68 void UpdateControllers(u64 userdata, s64 cycles_late); 67 void UpdateControllers(u64 userdata, std::chrono::nanoseconds ns_late);
69 68
70 std::shared_ptr<Kernel::SharedMemory> shared_mem; 69 std::shared_ptr<Kernel::SharedMemory> shared_mem;
71 70
diff --git a/src/core/hle/service/mii/manager.cpp b/src/core/hle/service/mii/manager.cpp
index 4a1d1182e..4730070cb 100644
--- a/src/core/hle/service/mii/manager.cpp
+++ b/src/core/hle/service/mii/manager.cpp
@@ -47,66 +47,67 @@ std::array<T, DestArraySize> ResizeArray(const std::array<T, SourceArraySize>& i
47MiiInfo ConvertStoreDataToInfo(const MiiStoreData& data) { 47MiiInfo ConvertStoreDataToInfo(const MiiStoreData& data) {
48 MiiStoreBitFields bf; 48 MiiStoreBitFields bf;
49 std::memcpy(&bf, data.data.data.data(), sizeof(MiiStoreBitFields)); 49 std::memcpy(&bf, data.data.data.data(), sizeof(MiiStoreBitFields));
50 MiiInfo info{}; 50
51 info.name = ResizeArray<char16_t, 10, 11>(data.data.name); 51 return {
52 info.uuid = data.data.uuid; 52 .uuid = data.data.uuid,
53 info.font_region = static_cast<u8>(bf.font_region.Value()); 53 .name = ResizeArray<char16_t, 10, 11>(data.data.name),
54 info.favorite_color = static_cast<u8>(bf.favorite_color.Value()); 54 .font_region = static_cast<u8>(bf.font_region.Value()),
55 info.gender = static_cast<u8>(bf.gender.Value()); 55 .favorite_color = static_cast<u8>(bf.favorite_color.Value()),
56 info.height = static_cast<u8>(bf.height.Value()); 56 .gender = static_cast<u8>(bf.gender.Value()),
57 info.build = static_cast<u8>(bf.build.Value()); 57 .height = static_cast<u8>(bf.height.Value()),
58 info.type = static_cast<u8>(bf.type.Value()); 58 .build = static_cast<u8>(bf.build.Value()),
59 info.region_move = static_cast<u8>(bf.region_move.Value()); 59 .type = static_cast<u8>(bf.type.Value()),
60 info.faceline_type = static_cast<u8>(bf.faceline_type.Value()); 60 .region_move = static_cast<u8>(bf.region_move.Value()),
61 info.faceline_color = static_cast<u8>(bf.faceline_color.Value()); 61 .faceline_type = static_cast<u8>(bf.faceline_type.Value()),
62 info.faceline_wrinkle = static_cast<u8>(bf.faceline_wrinkle.Value()); 62 .faceline_color = static_cast<u8>(bf.faceline_color.Value()),
63 info.faceline_make = static_cast<u8>(bf.faceline_makeup.Value()); 63 .faceline_wrinkle = static_cast<u8>(bf.faceline_wrinkle.Value()),
64 info.hair_type = static_cast<u8>(bf.hair_type.Value()); 64 .faceline_make = static_cast<u8>(bf.faceline_makeup.Value()),
65 info.hair_color = static_cast<u8>(bf.hair_color.Value()); 65 .hair_type = static_cast<u8>(bf.hair_type.Value()),
66 info.hair_flip = static_cast<u8>(bf.hair_flip.Value()); 66 .hair_color = static_cast<u8>(bf.hair_color.Value()),
67 info.eye_type = static_cast<u8>(bf.eye_type.Value()); 67 .hair_flip = static_cast<u8>(bf.hair_flip.Value()),
68 info.eye_color = static_cast<u8>(bf.eye_color.Value()); 68 .eye_type = static_cast<u8>(bf.eye_type.Value()),
69 info.eye_scale = static_cast<u8>(bf.eye_scale.Value()); 69 .eye_color = static_cast<u8>(bf.eye_color.Value()),
70 info.eye_aspect = static_cast<u8>(bf.eye_aspect.Value()); 70 .eye_scale = static_cast<u8>(bf.eye_scale.Value()),
71 info.eye_rotate = static_cast<u8>(bf.eye_rotate.Value()); 71 .eye_aspect = static_cast<u8>(bf.eye_aspect.Value()),
72 info.eye_x = static_cast<u8>(bf.eye_x.Value()); 72 .eye_rotate = static_cast<u8>(bf.eye_rotate.Value()),
73 info.eye_y = static_cast<u8>(bf.eye_y.Value()); 73 .eye_x = static_cast<u8>(bf.eye_x.Value()),
74 info.eyebrow_type = static_cast<u8>(bf.eyebrow_type.Value()); 74 .eye_y = static_cast<u8>(bf.eye_y.Value()),
75 info.eyebrow_color = static_cast<u8>(bf.eyebrow_color.Value()); 75 .eyebrow_type = static_cast<u8>(bf.eyebrow_type.Value()),
76 info.eyebrow_scale = static_cast<u8>(bf.eyebrow_scale.Value()); 76 .eyebrow_color = static_cast<u8>(bf.eyebrow_color.Value()),
77 info.eyebrow_aspect = static_cast<u8>(bf.eyebrow_aspect.Value()); 77 .eyebrow_scale = static_cast<u8>(bf.eyebrow_scale.Value()),
78 info.eyebrow_rotate = static_cast<u8>(bf.eyebrow_rotate.Value()); 78 .eyebrow_aspect = static_cast<u8>(bf.eyebrow_aspect.Value()),
79 info.eyebrow_x = static_cast<u8>(bf.eyebrow_x.Value()); 79 .eyebrow_rotate = static_cast<u8>(bf.eyebrow_rotate.Value()),
80 info.eyebrow_y = static_cast<u8>(bf.eyebrow_y.Value() + 3); 80 .eyebrow_x = static_cast<u8>(bf.eyebrow_x.Value()),
81 info.nose_type = static_cast<u8>(bf.nose_type.Value()); 81 .eyebrow_y = static_cast<u8>(bf.eyebrow_y.Value() + 3),
82 info.nose_scale = static_cast<u8>(bf.nose_scale.Value()); 82 .nose_type = static_cast<u8>(bf.nose_type.Value()),
83 info.nose_y = static_cast<u8>(bf.nose_y.Value()); 83 .nose_scale = static_cast<u8>(bf.nose_scale.Value()),
84 info.mouth_type = static_cast<u8>(bf.mouth_type.Value()); 84 .nose_y = static_cast<u8>(bf.nose_y.Value()),
85 info.mouth_color = static_cast<u8>(bf.mouth_color.Value()); 85 .mouth_type = static_cast<u8>(bf.mouth_type.Value()),
86 info.mouth_scale = static_cast<u8>(bf.mouth_scale.Value()); 86 .mouth_color = static_cast<u8>(bf.mouth_color.Value()),
87 info.mouth_aspect = static_cast<u8>(bf.mouth_aspect.Value()); 87 .mouth_scale = static_cast<u8>(bf.mouth_scale.Value()),
88 info.mouth_y = static_cast<u8>(bf.mouth_y.Value()); 88 .mouth_aspect = static_cast<u8>(bf.mouth_aspect.Value()),
89 info.beard_color = static_cast<u8>(bf.beard_color.Value()); 89 .mouth_y = static_cast<u8>(bf.mouth_y.Value()),
90 info.beard_type = static_cast<u8>(bf.beard_type.Value()); 90 .beard_color = static_cast<u8>(bf.beard_color.Value()),
91 info.mustache_type = static_cast<u8>(bf.mustache_type.Value()); 91 .beard_type = static_cast<u8>(bf.beard_type.Value()),
92 info.mustache_scale = static_cast<u8>(bf.mustache_scale.Value()); 92 .mustache_type = static_cast<u8>(bf.mustache_type.Value()),
93 info.mustache_y = static_cast<u8>(bf.mustache_y.Value()); 93 .mustache_scale = static_cast<u8>(bf.mustache_scale.Value()),
94 info.glasses_type = static_cast<u8>(bf.glasses_type.Value()); 94 .mustache_y = static_cast<u8>(bf.mustache_y.Value()),
95 info.glasses_color = static_cast<u8>(bf.glasses_color.Value()); 95 .glasses_type = static_cast<u8>(bf.glasses_type.Value()),
96 info.glasses_scale = static_cast<u8>(bf.glasses_scale.Value()); 96 .glasses_color = static_cast<u8>(bf.glasses_color.Value()),
97 info.glasses_y = static_cast<u8>(bf.glasses_y.Value()); 97 .glasses_scale = static_cast<u8>(bf.glasses_scale.Value()),
98 info.mole_type = static_cast<u8>(bf.mole_type.Value()); 98 .glasses_y = static_cast<u8>(bf.glasses_y.Value()),
99 info.mole_scale = static_cast<u8>(bf.mole_scale.Value()); 99 .mole_type = static_cast<u8>(bf.mole_type.Value()),
100 info.mole_x = static_cast<u8>(bf.mole_x.Value()); 100 .mole_scale = static_cast<u8>(bf.mole_scale.Value()),
101 info.mole_y = static_cast<u8>(bf.mole_y.Value()); 101 .mole_x = static_cast<u8>(bf.mole_x.Value()),
102 return info; 102 .mole_y = static_cast<u8>(bf.mole_y.Value()),
103 };
103} 104}
104 105
105u16 GenerateCrc16(const void* data, std::size_t size) { 106u16 GenerateCrc16(const void* data, std::size_t size) {
106 s32 crc{}; 107 s32 crc{};
107 for (int i = 0; i < size; i++) { 108 for (std::size_t i = 0; i < size; i++) {
108 crc ^= reinterpret_cast<const u8*>(data)[i] << 8; 109 crc ^= static_cast<const u8*>(data)[i] << 8;
109 for (int j = 0; j < 8; j++) { 110 for (std::size_t j = 0; j < 8; j++) {
110 crc <<= 1; 111 crc <<= 1;
111 if ((crc & 0x10000) != 0) { 112 if ((crc & 0x10000) != 0) {
112 crc = (crc ^ 0x1021) & 0xFFFF; 113 crc = (crc ^ 0x1021) & 0xFFFF;
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 2f44d3779..789856118 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -28,8 +28,7 @@
28 28
29namespace Service::NVFlinger { 29namespace Service::NVFlinger {
30 30
31constexpr s64 frame_ticks = static_cast<s64>(1000000000 / 60); 31constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60};
32constexpr s64 frame_ticks_30fps = static_cast<s64>(1000000000 / 30);
33 32
34void NVFlinger::VSyncThread(NVFlinger& nv_flinger) { 33void NVFlinger::VSyncThread(NVFlinger& nv_flinger) {
35 nv_flinger.SplitVSync(); 34 nv_flinger.SplitVSync();
@@ -67,20 +66,24 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) {
67 guard = std::make_shared<std::mutex>(); 66 guard = std::make_shared<std::mutex>();
68 67
69 // Schedule the screen composition events 68 // Schedule the screen composition events
70 composition_event = 69 composition_event = Core::Timing::CreateEvent(
71 Core::Timing::CreateEvent("ScreenComposition", [this](u64 userdata, s64 ns_late) { 70 "ScreenComposition", [this](u64, std::chrono::nanoseconds ns_late) {
72 Lock(); 71 Lock();
73 Compose(); 72 Compose();
74 const auto ticks = GetNextTicks(); 73
75 this->system.CoreTiming().ScheduleEvent(std::max<s64>(0LL, ticks - ns_late), 74 const auto ticks = std::chrono::nanoseconds{GetNextTicks()};
76 composition_event); 75 const auto ticks_delta = ticks - ns_late;
76 const auto future_ns = std::max(std::chrono::nanoseconds::zero(), ticks_delta);
77
78 this->system.CoreTiming().ScheduleEvent(future_ns, composition_event);
77 }); 79 });
80
78 if (system.IsMulticore()) { 81 if (system.IsMulticore()) {
79 is_running = true; 82 is_running = true;
80 wait_event = std::make_unique<Common::Event>(); 83 wait_event = std::make_unique<Common::Event>();
81 vsync_thread = std::make_unique<std::thread>(VSyncThread, std::ref(*this)); 84 vsync_thread = std::make_unique<std::thread>(VSyncThread, std::ref(*this));
82 } else { 85 } else {
83 system.CoreTiming().ScheduleEvent(frame_ticks, composition_event); 86 system.CoreTiming().ScheduleEvent(frame_ns, composition_event);
84 } 87 }
85} 88}
86 89
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index 53d27859b..ced41b1fe 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -20,7 +20,7 @@
20 20
21namespace Core::Memory { 21namespace Core::Memory {
22 22
23constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(1000000000 / 12); 23constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12};
24constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF; 24constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF;
25 25
26StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata) 26StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata)
@@ -188,10 +188,12 @@ CheatEngine::~CheatEngine() {
188} 188}
189 189
190void CheatEngine::Initialize() { 190void CheatEngine::Initialize() {
191 event = Core::Timing::CreateEvent( 191 event = Core::Timing::CreateEvent("CheatEngine::FrameCallback::" +
192 "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id), 192 Common::HexToString(metadata.main_nso_build_id),
193 [this](u64 userdata, s64 ns_late) { FrameCallback(userdata, ns_late); }); 193 [this](u64 userdata, std::chrono::nanoseconds ns_late) {
194 core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event); 194 FrameCallback(userdata, ns_late);
195 });
196 core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event);
195 197
196 metadata.process_id = system.CurrentProcess()->GetProcessID(); 198 metadata.process_id = system.CurrentProcess()->GetProcessID();
197 metadata.title_id = system.CurrentProcess()->GetTitleID(); 199 metadata.title_id = system.CurrentProcess()->GetTitleID();
@@ -217,7 +219,7 @@ void CheatEngine::Reload(std::vector<CheatEntry> cheats) {
217 219
218MICROPROFILE_DEFINE(Cheat_Engine, "Add-Ons", "Cheat Engine", MP_RGB(70, 200, 70)); 220MICROPROFILE_DEFINE(Cheat_Engine, "Add-Ons", "Cheat Engine", MP_RGB(70, 200, 70));
219 221
220void CheatEngine::FrameCallback(u64 userdata, s64 ns_late) { 222void CheatEngine::FrameCallback(u64, std::chrono::nanoseconds ns_late) {
221 if (is_pending_reload.exchange(false)) { 223 if (is_pending_reload.exchange(false)) {
222 vm.LoadProgram(cheats); 224 vm.LoadProgram(cheats);
223 } 225 }
@@ -230,7 +232,7 @@ void CheatEngine::FrameCallback(u64 userdata, s64 ns_late) {
230 232
231 vm.Execute(metadata); 233 vm.Execute(metadata);
232 234
233 core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS - ns_late, event); 235 core_timing.ScheduleEvent(CHEAT_ENGINE_NS - ns_late, event);
234} 236}
235 237
236} // namespace Core::Memory 238} // namespace Core::Memory
diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h
index 2649423f8..d4068cf84 100644
--- a/src/core/memory/cheat_engine.h
+++ b/src/core/memory/cheat_engine.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <atomic> 7#include <atomic>
8#include <chrono>
8#include <memory> 9#include <memory>
9#include <vector> 10#include <vector>
10#include "common/common_types.h" 11#include "common/common_types.h"
@@ -71,7 +72,7 @@ public:
71 void Reload(std::vector<CheatEntry> cheats); 72 void Reload(std::vector<CheatEntry> cheats);
72 73
73private: 74private:
74 void FrameCallback(u64 userdata, s64 cycles_late); 75 void FrameCallback(u64 userdata, std::chrono::nanoseconds ns_late);
75 76
76 DmntCheatVm vm; 77 DmntCheatVm vm;
77 CheatProcessMetadata metadata; 78 CheatProcessMetadata metadata;
diff --git a/src/core/memory/dmnt_cheat_vm.cpp b/src/core/memory/dmnt_cheat_vm.cpp
index fb9f36bfd..2e7da23fe 100644
--- a/src/core/memory/dmnt_cheat_vm.cpp
+++ b/src/core/memory/dmnt_cheat_vm.cpp
@@ -190,6 +190,15 @@ void DmntCheatVm::LogOpcode(const CheatVmOpcode& opcode) {
190 callbacks->CommandLog( 190 callbacks->CommandLog(
191 fmt::format("Act[{:02X}]: {:d}", i, save_restore_regmask->should_operate[i])); 191 fmt::format("Act[{:02X}]: {:d}", i, save_restore_regmask->should_operate[i]));
192 } 192 }
193 } else if (auto rw_static_reg = std::get_if<ReadWriteStaticRegisterOpcode>(&opcode.opcode)) {
194 callbacks->CommandLog("Opcode: Read/Write Static Register");
195 if (rw_static_reg->static_idx < NumReadableStaticRegisters) {
196 callbacks->CommandLog("Op Type: ReadStaticRegister");
197 } else {
198 callbacks->CommandLog("Op Type: WriteStaticRegister");
199 }
200 callbacks->CommandLog(fmt::format("Reg Idx {:X}", rw_static_reg->idx));
201 callbacks->CommandLog(fmt::format("Stc Idx {:X}", rw_static_reg->static_idx));
193 } else if (auto debug_log = std::get_if<DebugLogOpcode>(&opcode.opcode)) { 202 } else if (auto debug_log = std::get_if<DebugLogOpcode>(&opcode.opcode)) {
194 callbacks->CommandLog("Opcode: Debug Log"); 203 callbacks->CommandLog("Opcode: Debug Log");
195 callbacks->CommandLog(fmt::format("Bit Width: {:X}", debug_log->bit_width)); 204 callbacks->CommandLog(fmt::format("Bit Width: {:X}", debug_log->bit_width));
@@ -544,6 +553,16 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
544 } 553 }
545 opcode.opcode = save_restore_regmask; 554 opcode.opcode = save_restore_regmask;
546 } break; 555 } break;
556 case CheatVmOpcodeType::ReadWriteStaticRegister: {
557 ReadWriteStaticRegisterOpcode rw_static_reg{};
558 // C3000XXx
559 // C3 = opcode 0xC3.
560 // XX = static register index.
561 // x = register index.
562 rw_static_reg.static_idx = ((first_dword >> 4) & 0xFF);
563 rw_static_reg.idx = (first_dword & 0xF);
564 opcode.opcode = rw_static_reg;
565 } break;
547 case CheatVmOpcodeType::DebugLog: { 566 case CheatVmOpcodeType::DebugLog: {
548 DebugLogOpcode debug_log{}; 567 DebugLogOpcode debug_log{};
549 // FFFTIX## 568 // FFFTIX##
@@ -667,6 +686,7 @@ void DmntCheatVm::ResetState() {
667 registers.fill(0); 686 registers.fill(0);
668 saved_values.fill(0); 687 saved_values.fill(0);
669 loop_tops.fill(0); 688 loop_tops.fill(0);
689 static_registers.fill(0);
670 instruction_ptr = 0; 690 instruction_ptr = 0;
671 condition_depth = 0; 691 condition_depth = 0;
672 decode_success = true; 692 decode_success = true;
@@ -1153,6 +1173,15 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
1153 } 1173 }
1154 } 1174 }
1155 } 1175 }
1176 } else if (auto rw_static_reg =
1177 std::get_if<ReadWriteStaticRegisterOpcode>(&cur_opcode.opcode)) {
1178 if (rw_static_reg->static_idx < NumReadableStaticRegisters) {
1179 // Load a register with a static register.
1180 registers[rw_static_reg->idx] = static_registers[rw_static_reg->static_idx];
1181 } else {
1182 // Store a register to a static register.
1183 static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx];
1184 }
1156 } else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) { 1185 } else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) {
1157 // Read value from memory. 1186 // Read value from memory.
1158 u64 log_value = 0; 1187 u64 log_value = 0;
diff --git a/src/core/memory/dmnt_cheat_vm.h b/src/core/memory/dmnt_cheat_vm.h
index 8351fd798..21b86b72c 100644
--- a/src/core/memory/dmnt_cheat_vm.h
+++ b/src/core/memory/dmnt_cheat_vm.h
@@ -56,6 +56,7 @@ enum class CheatVmOpcodeType : u32 {
56 BeginRegisterConditionalBlock = 0xC0, 56 BeginRegisterConditionalBlock = 0xC0,
57 SaveRestoreRegister = 0xC1, 57 SaveRestoreRegister = 0xC1,
58 SaveRestoreRegisterMask = 0xC2, 58 SaveRestoreRegisterMask = 0xC2,
59 ReadWriteStaticRegister = 0xC3,
59 60
60 // This is a meta entry, and not a real opcode. 61 // This is a meta entry, and not a real opcode.
61 // This is to facilitate multi-nybble instruction decoding. 62 // This is to facilitate multi-nybble instruction decoding.
@@ -237,6 +238,11 @@ struct SaveRestoreRegisterMaskOpcode {
237 std::array<bool, 0x10> should_operate{}; 238 std::array<bool, 0x10> should_operate{};
238}; 239};
239 240
241struct ReadWriteStaticRegisterOpcode {
242 u32 static_idx{};
243 u32 idx{};
244};
245
240struct DebugLogOpcode { 246struct DebugLogOpcode {
241 u32 bit_width{}; 247 u32 bit_width{};
242 u32 log_id{}; 248 u32 log_id{};
@@ -259,7 +265,8 @@ struct CheatVmOpcode {
259 PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode, 265 PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
260 PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode, 266 PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
261 BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode, 267 BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
262 SaveRestoreRegisterMaskOpcode, DebugLogOpcode, UnrecognizedInstruction> 268 SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, DebugLogOpcode,
269 UnrecognizedInstruction>
263 opcode{}; 270 opcode{};
264}; 271};
265 272
@@ -281,6 +288,10 @@ public:
281 288
282 static constexpr std::size_t MaximumProgramOpcodeCount = 0x400; 289 static constexpr std::size_t MaximumProgramOpcodeCount = 0x400;
283 static constexpr std::size_t NumRegisters = 0x10; 290 static constexpr std::size_t NumRegisters = 0x10;
291 static constexpr std::size_t NumReadableStaticRegisters = 0x80;
292 static constexpr std::size_t NumWritableStaticRegisters = 0x80;
293 static constexpr std::size_t NumStaticRegisters =
294 NumReadableStaticRegisters + NumWritableStaticRegisters;
284 295
285 explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks); 296 explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks);
286 ~DmntCheatVm(); 297 ~DmntCheatVm();
@@ -302,6 +313,7 @@ private:
302 std::array<u32, MaximumProgramOpcodeCount> program{}; 313 std::array<u32, MaximumProgramOpcodeCount> program{};
303 std::array<u64, NumRegisters> registers{}; 314 std::array<u64, NumRegisters> registers{};
304 std::array<u64, NumRegisters> saved_values{}; 315 std::array<u64, NumRegisters> saved_values{};
316 std::array<u64, NumStaticRegisters> static_registers{};
305 std::array<std::size_t, NumRegisters> loop_tops{}; 317 std::array<std::size_t, NumRegisters> loop_tops{};
306 318
307 bool DecodeNextOpcode(CheatVmOpcode& out); 319 bool DecodeNextOpcode(CheatVmOpcode& out);
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index e8a6f2a6e..44252dd81 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -115,6 +115,7 @@ void LogSettings() {
115 values.use_asynchronous_gpu_emulation.GetValue()); 115 values.use_asynchronous_gpu_emulation.GetValue());
116 log_setting("Renderer_UseVsync", values.use_vsync.GetValue()); 116 log_setting("Renderer_UseVsync", values.use_vsync.GetValue());
117 log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue()); 117 log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue());
118 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
118 log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue()); 119 log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
119 log_setting("Audio_OutputEngine", values.sink_id); 120 log_setting("Audio_OutputEngine", values.sink_id);
120 log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue()); 121 log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue());
@@ -170,6 +171,7 @@ void RestoreGlobalState() {
170 values.use_asynchronous_gpu_emulation.SetGlobal(true); 171 values.use_asynchronous_gpu_emulation.SetGlobal(true);
171 values.use_vsync.SetGlobal(true); 172 values.use_vsync.SetGlobal(true);
172 values.use_assembly_shaders.SetGlobal(true); 173 values.use_assembly_shaders.SetGlobal(true);
174 values.use_asynchronous_shaders.SetGlobal(true);
173 values.use_fast_gpu_time.SetGlobal(true); 175 values.use_fast_gpu_time.SetGlobal(true);
174 values.force_30fps_mode.SetGlobal(true); 176 values.force_30fps_mode.SetGlobal(true);
175 values.bg_red.SetGlobal(true); 177 values.bg_red.SetGlobal(true);
diff --git a/src/core/settings.h b/src/core/settings.h
index a64debd25..386233fdf 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -434,6 +434,7 @@ struct Values {
434 Setting<bool> use_asynchronous_gpu_emulation; 434 Setting<bool> use_asynchronous_gpu_emulation;
435 Setting<bool> use_vsync; 435 Setting<bool> use_vsync;
436 Setting<bool> use_assembly_shaders; 436 Setting<bool> use_assembly_shaders;
437 Setting<bool> use_asynchronous_shaders;
437 Setting<bool> force_30fps_mode; 438 Setting<bool> force_30fps_mode;
438 Setting<bool> use_fast_gpu_time; 439 Setting<bool> use_fast_gpu_time;
439 440
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 78915e6db..5a30c75da 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -207,6 +207,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
207 AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue()); 207 AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue());
208 AddField(field_type, "Renderer_UseAssemblyShaders", 208 AddField(field_type, "Renderer_UseAssemblyShaders",
209 Settings::values.use_assembly_shaders.GetValue()); 209 Settings::values.use_assembly_shaders.GetValue());
210 AddField(field_type, "Renderer_UseAsynchronousShaders",
211 Settings::values.use_asynchronous_shaders.GetValue());
210 AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode); 212 AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode);
211} 213}
212 214
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 8b0c50d11..27b894b51 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -14,7 +14,7 @@
14namespace Tools { 14namespace Tools {
15namespace { 15namespace {
16 16
17constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(1000000000 / 60); 17constexpr auto memory_freezer_ns = std::chrono::nanoseconds{1000000000 / 60};
18 18
19u64 MemoryReadWidth(Core::Memory::Memory& memory, u32 width, VAddr addr) { 19u64 MemoryReadWidth(Core::Memory::Memory& memory, u32 width, VAddr addr) {
20 switch (width) { 20 switch (width) {
@@ -55,10 +55,11 @@ void MemoryWriteWidth(Core::Memory::Memory& memory, u32 width, VAddr addr, u64 v
55 55
56Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_) 56Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_)
57 : core_timing{core_timing_}, memory{memory_} { 57 : core_timing{core_timing_}, memory{memory_} {
58 event = Core::Timing::CreateEvent( 58 event = Core::Timing::CreateEvent("MemoryFreezer::FrameCallback",
59 "MemoryFreezer::FrameCallback", 59 [this](u64 userdata, std::chrono::nanoseconds ns_late) {
60 [this](u64 userdata, s64 ns_late) { FrameCallback(userdata, ns_late); }); 60 FrameCallback(userdata, ns_late);
61 core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS, event); 61 });
62 core_timing.ScheduleEvent(memory_freezer_ns, event);
62} 63}
63 64
64Freezer::~Freezer() { 65Freezer::~Freezer() {
@@ -68,7 +69,7 @@ Freezer::~Freezer() {
68void Freezer::SetActive(bool active) { 69void Freezer::SetActive(bool active) {
69 if (!this->active.exchange(active)) { 70 if (!this->active.exchange(active)) {
70 FillEntryReads(); 71 FillEntryReads();
71 core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS, event); 72 core_timing.ScheduleEvent(memory_freezer_ns, event);
72 LOG_DEBUG(Common_Memory, "Memory freezer activated!"); 73 LOG_DEBUG(Common_Memory, "Memory freezer activated!");
73 } else { 74 } else {
74 LOG_DEBUG(Common_Memory, "Memory freezer deactivated!"); 75 LOG_DEBUG(Common_Memory, "Memory freezer deactivated!");
@@ -158,7 +159,7 @@ std::vector<Freezer::Entry> Freezer::GetEntries() const {
158 return entries; 159 return entries;
159} 160}
160 161
161void Freezer::FrameCallback(u64 userdata, s64 ns_late) { 162void Freezer::FrameCallback(u64, std::chrono::nanoseconds ns_late) {
162 if (!IsActive()) { 163 if (!IsActive()) {
163 LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events."); 164 LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events.");
164 return; 165 return;
@@ -173,7 +174,7 @@ void Freezer::FrameCallback(u64 userdata, s64 ns_late) {
173 MemoryWriteWidth(memory, entry.width, entry.address, entry.value); 174 MemoryWriteWidth(memory, entry.width, entry.address, entry.value);
174 } 175 }
175 176
176 core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS - ns_late, event); 177 core_timing.ScheduleEvent(memory_freezer_ns - ns_late, event);
177} 178}
178 179
179void Freezer::FillEntryReads() { 180void Freezer::FillEntryReads() {
diff --git a/src/core/tools/freezer.h b/src/core/tools/freezer.h
index 62fc6aa6c..8438783d5 100644
--- a/src/core/tools/freezer.h
+++ b/src/core/tools/freezer.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <atomic> 7#include <atomic>
8#include <chrono>
8#include <memory> 9#include <memory>
9#include <mutex> 10#include <mutex>
10#include <optional> 11#include <optional>
@@ -72,7 +73,7 @@ public:
72 std::vector<Entry> GetEntries() const; 73 std::vector<Entry> GetEntries() const;
73 74
74private: 75private:
75 void FrameCallback(u64 userdata, s64 cycles_late); 76 void FrameCallback(u64 userdata, std::chrono::nanoseconds ns_late);
76 void FillEntryReads(); 77 void FillEntryReads();
77 78
78 std::atomic_bool active{false}; 79 std::atomic_bool active{false};
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp
index e66db1940..244463a47 100644
--- a/src/tests/core/core_timing.cpp
+++ b/src/tests/core/core_timing.cpp
@@ -6,6 +6,7 @@
6 6
7#include <array> 7#include <array>
8#include <bitset> 8#include <bitset>
9#include <chrono>
9#include <cstdlib> 10#include <cstdlib>
10#include <memory> 11#include <memory>
11#include <string> 12#include <string>
@@ -17,7 +18,6 @@
17namespace { 18namespace {
18// Numbers are chosen randomly to make sure the correct one is given. 19// Numbers are chosen randomly to make sure the correct one is given.
19constexpr std::array<u64, 5> CB_IDS{{42, 144, 93, 1026, UINT64_C(0xFFFF7FFFF7FFFF)}}; 20constexpr std::array<u64, 5> CB_IDS{{42, 144, 93, 1026, UINT64_C(0xFFFF7FFFF7FFFF)}};
20constexpr int MAX_SLICE_LENGTH = 10000; // Copied from CoreTiming internals
21constexpr std::array<u64, 5> calls_order{{2, 0, 1, 4, 3}}; 21constexpr std::array<u64, 5> calls_order{{2, 0, 1, 4, 3}};
22std::array<s64, 5> delays{}; 22std::array<s64, 5> delays{};
23 23
@@ -25,12 +25,12 @@ std::bitset<CB_IDS.size()> callbacks_ran_flags;
25u64 expected_callback = 0; 25u64 expected_callback = 0;
26 26
27template <unsigned int IDX> 27template <unsigned int IDX>
28void HostCallbackTemplate(u64 userdata, s64 nanoseconds_late) { 28void HostCallbackTemplate(u64 userdata, std::chrono::nanoseconds ns_late) {
29 static_assert(IDX < CB_IDS.size(), "IDX out of range"); 29 static_assert(IDX < CB_IDS.size(), "IDX out of range");
30 callbacks_ran_flags.set(IDX); 30 callbacks_ran_flags.set(IDX);
31 REQUIRE(CB_IDS[IDX] == userdata); 31 REQUIRE(CB_IDS[IDX] == userdata);
32 REQUIRE(CB_IDS[IDX] == CB_IDS[calls_order[expected_callback]]); 32 REQUIRE(CB_IDS[IDX] == CB_IDS[calls_order[expected_callback]]);
33 delays[IDX] = nanoseconds_late; 33 delays[IDX] = ns_late.count();
34 ++expected_callback; 34 ++expected_callback;
35} 35}
36 36
@@ -77,10 +77,12 @@ TEST_CASE("CoreTiming[BasicOrder]", "[core]") {
77 77
78 core_timing.SyncPause(true); 78 core_timing.SyncPause(true);
79 79
80 u64 one_micro = 1000U; 80 const u64 one_micro = 1000U;
81 for (std::size_t i = 0; i < events.size(); i++) { 81 for (std::size_t i = 0; i < events.size(); i++) {
82 u64 order = calls_order[i]; 82 const u64 order = calls_order[i];
83 core_timing.ScheduleEvent(i * one_micro + 100U, events[order], CB_IDS[order]); 83 const auto future_ns = std::chrono::nanoseconds{static_cast<s64>(i * one_micro + 100)};
84
85 core_timing.ScheduleEvent(future_ns, events[order], CB_IDS[order]);
84 } 86 }
85 /// test pause 87 /// test pause
86 REQUIRE(callbacks_ran_flags.none()); 88 REQUIRE(callbacks_ran_flags.none());
@@ -116,13 +118,16 @@ TEST_CASE("CoreTiming[BasicOrderNoPausing]", "[core]") {
116 118
117 expected_callback = 0; 119 expected_callback = 0;
118 120
119 u64 start = core_timing.GetGlobalTimeNs().count(); 121 const u64 start = core_timing.GetGlobalTimeNs().count();
120 u64 one_micro = 1000U; 122 const u64 one_micro = 1000U;
123
121 for (std::size_t i = 0; i < events.size(); i++) { 124 for (std::size_t i = 0; i < events.size(); i++) {
122 u64 order = calls_order[i]; 125 const u64 order = calls_order[i];
123 core_timing.ScheduleEvent(i * one_micro + 100U, events[order], CB_IDS[order]); 126 const auto future_ns = std::chrono::nanoseconds{static_cast<s64>(i * one_micro + 100)};
127 core_timing.ScheduleEvent(future_ns, events[order], CB_IDS[order]);
124 } 128 }
125 u64 end = core_timing.GetGlobalTimeNs().count(); 129
130 const u64 end = core_timing.GetGlobalTimeNs().count();
126 const double scheduling_time = static_cast<double>(end - start); 131 const double scheduling_time = static_cast<double>(end - start);
127 const double timer_time = static_cast<double>(TestTimerSpeed(core_timing)); 132 const double timer_time = static_cast<double>(TestTimerSpeed(core_timing));
128 133
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 21c46a567..3cd896a0f 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -98,6 +98,8 @@ add_library(video_core STATIC
98 sampler_cache.cpp 98 sampler_cache.cpp
99 sampler_cache.h 99 sampler_cache.h
100 shader_cache.h 100 shader_cache.h
101 shader_notify.cpp
102 shader_notify.h
101 shader/decode/arithmetic.cpp 103 shader/decode/arithmetic.cpp
102 shader/decode/arithmetic_immediate.cpp 104 shader/decode/arithmetic_immediate.cpp
103 shader/decode/bfe.cpp 105 shader/decode/bfe.cpp
@@ -128,6 +130,8 @@ add_library(video_core STATIC
128 shader/decode/other.cpp 130 shader/decode/other.cpp
129 shader/ast.cpp 131 shader/ast.cpp
130 shader/ast.h 132 shader/ast.h
133 shader/async_shaders.cpp
134 shader/async_shaders.h
131 shader/compiler_settings.cpp 135 shader/compiler_settings.cpp
132 shader/compiler_settings.h 136 shader/compiler_settings.h
133 shader/control_flow.cpp 137 shader/control_flow.cpp
diff --git a/src/video_core/compatible_formats.cpp b/src/video_core/compatible_formats.cpp
index 6c426b035..b06c32c84 100644
--- a/src/video_core/compatible_formats.cpp
+++ b/src/video_core/compatible_formats.cpp
@@ -17,101 +17,94 @@ namespace {
17// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_view.txt 17// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_view.txt
18 18
19constexpr std::array VIEW_CLASS_128_BITS = { 19constexpr std::array VIEW_CLASS_128_BITS = {
20 PixelFormat::RGBA32F, 20 PixelFormat::R32G32B32A32_FLOAT,
21 PixelFormat::RGBA32UI, 21 PixelFormat::R32G32B32A32_UINT,
22 PixelFormat::R32G32B32A32_SINT,
22}; 23};
23// Missing formats:
24// PixelFormat::RGBA32I
25 24
26constexpr std::array VIEW_CLASS_96_BITS = { 25constexpr std::array VIEW_CLASS_96_BITS = {
27 PixelFormat::RGB32F, 26 PixelFormat::R32G32B32_FLOAT,
28}; 27};
29// Missing formats: 28// Missing formats:
30// PixelFormat::RGB32UI, 29// PixelFormat::RGB32UI,
31// PixelFormat::RGB32I, 30// PixelFormat::RGB32I,
32 31
33constexpr std::array VIEW_CLASS_64_BITS = { 32constexpr std::array VIEW_CLASS_64_BITS = {
34 PixelFormat::RGBA16F, PixelFormat::RG32F, PixelFormat::RGBA16UI, PixelFormat::RG32UI, 33 PixelFormat::R32G32_FLOAT, PixelFormat::R32G32_UINT,
35 PixelFormat::RGBA16U, PixelFormat::RGBA16F, PixelFormat::RGBA16S, 34 PixelFormat::R32G32_SINT, PixelFormat::R16G16B16A16_FLOAT,
35 PixelFormat::R16G16B16A16_UNORM, PixelFormat::R16G16B16A16_SNORM,
36 PixelFormat::R16G16B16A16_UINT, PixelFormat::R16G16B16A16_SINT,
36}; 37};
37// Missing formats:
38// PixelFormat::RGBA16I
39// PixelFormat::RG32I
40 38
41// TODO: How should we handle 48 bits? 39// TODO: How should we handle 48 bits?
42 40
43constexpr std::array VIEW_CLASS_32_BITS = { 41constexpr std::array VIEW_CLASS_32_BITS = {
44 PixelFormat::RG16F, PixelFormat::R11FG11FB10F, PixelFormat::R32F, 42 PixelFormat::R16G16_FLOAT, PixelFormat::B10G11R11_FLOAT, PixelFormat::R32_FLOAT,
45 PixelFormat::A2B10G10R10U, PixelFormat::RG16UI, PixelFormat::R32UI, 43 PixelFormat::A2B10G10R10_UNORM, PixelFormat::R16G16_UINT, PixelFormat::R32_UINT,
46 PixelFormat::RG16I, PixelFormat::R32I, PixelFormat::ABGR8U, 44 PixelFormat::R16G16_SINT, PixelFormat::R32_SINT, PixelFormat::A8B8G8R8_UNORM,
47 PixelFormat::RG16, PixelFormat::ABGR8S, PixelFormat::RG16S, 45 PixelFormat::R16G16_UNORM, PixelFormat::A8B8G8R8_SNORM, PixelFormat::R16G16_SNORM,
48 PixelFormat::RGBA8_SRGB, PixelFormat::E5B9G9R9F, PixelFormat::BGRA8, 46 PixelFormat::A8B8G8R8_SRGB, PixelFormat::E5B9G9R9_FLOAT, PixelFormat::B8G8R8A8_UNORM,
49 PixelFormat::BGRA8_SRGB, 47 PixelFormat::B8G8R8A8_SRGB, PixelFormat::A8B8G8R8_UINT, PixelFormat::A8B8G8R8_SINT,
48 PixelFormat::A2B10G10R10_UINT,
50}; 49};
51// Missing formats:
52// PixelFormat::RGBA8UI
53// PixelFormat::RGBA8I
54// PixelFormat::RGB10_A2_UI
55 50
56// TODO: How should we handle 24 bits? 51// TODO: How should we handle 24 bits?
57 52
58constexpr std::array VIEW_CLASS_16_BITS = { 53constexpr std::array VIEW_CLASS_16_BITS = {
59 PixelFormat::R16F, PixelFormat::RG8UI, PixelFormat::R16UI, PixelFormat::R16I, 54 PixelFormat::R16_FLOAT, PixelFormat::R8G8_UINT, PixelFormat::R16_UINT,
60 PixelFormat::RG8U, PixelFormat::R16U, PixelFormat::RG8S, PixelFormat::R16S, 55 PixelFormat::R16_SINT, PixelFormat::R8G8_UNORM, PixelFormat::R16_UNORM,
56 PixelFormat::R8G8_SNORM, PixelFormat::R16_SNORM, PixelFormat::R8G8_SINT,
61}; 57};
62// Missing formats:
63// PixelFormat::RG8I
64 58
65constexpr std::array VIEW_CLASS_8_BITS = { 59constexpr std::array VIEW_CLASS_8_BITS = {
66 PixelFormat::R8UI, 60 PixelFormat::R8_UINT,
67 PixelFormat::R8U, 61 PixelFormat::R8_UNORM,
62 PixelFormat::R8_SINT,
63 PixelFormat::R8_SNORM,
68}; 64};
69// Missing formats:
70// PixelFormat::R8I
71// PixelFormat::R8S
72 65
73constexpr std::array VIEW_CLASS_RGTC1_RED = { 66constexpr std::array VIEW_CLASS_RGTC1_RED = {
74 PixelFormat::DXN1, 67 PixelFormat::BC4_UNORM,
68 PixelFormat::BC4_SNORM,
75}; 69};
76// Missing formats:
77// COMPRESSED_SIGNED_RED_RGTC1
78 70
79constexpr std::array VIEW_CLASS_RGTC2_RG = { 71constexpr std::array VIEW_CLASS_RGTC2_RG = {
80 PixelFormat::DXN2UNORM, 72 PixelFormat::BC5_UNORM,
81 PixelFormat::DXN2SNORM, 73 PixelFormat::BC5_SNORM,
82}; 74};
83 75
84constexpr std::array VIEW_CLASS_BPTC_UNORM = { 76constexpr std::array VIEW_CLASS_BPTC_UNORM = {
85 PixelFormat::BC7U, 77 PixelFormat::BC7_UNORM,
86 PixelFormat::BC7U_SRGB, 78 PixelFormat::BC7_SRGB,
87}; 79};
88 80
89constexpr std::array VIEW_CLASS_BPTC_FLOAT = { 81constexpr std::array VIEW_CLASS_BPTC_FLOAT = {
90 PixelFormat::BC6H_SF16, 82 PixelFormat::BC6H_SFLOAT,
91 PixelFormat::BC6H_UF16, 83 PixelFormat::BC6H_UFLOAT,
92}; 84};
93 85
94// Compatibility table taken from Table 4.X.1 in: 86// Compatibility table taken from Table 4.X.1 in:
95// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_copy_image.txt 87// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_copy_image.txt
96 88
97constexpr std::array COPY_CLASS_128_BITS = { 89constexpr std::array COPY_CLASS_128_BITS = {
98 PixelFormat::RGBA32UI, PixelFormat::RGBA32F, PixelFormat::DXT23, 90 PixelFormat::R32G32B32A32_UINT, PixelFormat::R32G32B32A32_FLOAT, PixelFormat::R32G32B32A32_SINT,
99 PixelFormat::DXT23_SRGB, PixelFormat::DXT45, PixelFormat::DXT45_SRGB, 91 PixelFormat::BC2_UNORM, PixelFormat::BC2_SRGB, PixelFormat::BC3_UNORM,
100 PixelFormat::DXN2SNORM, PixelFormat::BC7U, PixelFormat::BC7U_SRGB, 92 PixelFormat::BC3_SRGB, PixelFormat::BC5_UNORM, PixelFormat::BC5_SNORM,
101 PixelFormat::BC6H_SF16, PixelFormat::BC6H_UF16, 93 PixelFormat::BC7_UNORM, PixelFormat::BC7_SRGB, PixelFormat::BC6H_SFLOAT,
94 PixelFormat::BC6H_UFLOAT,
102}; 95};
103// Missing formats: 96// Missing formats:
104// PixelFormat::RGBA32I 97// PixelFormat::RGBA32I
105// COMPRESSED_RG_RGTC2 98// COMPRESSED_RG_RGTC2
106 99
107constexpr std::array COPY_CLASS_64_BITS = { 100constexpr std::array COPY_CLASS_64_BITS = {
108 PixelFormat::RGBA16F, PixelFormat::RG32F, PixelFormat::RGBA16UI, PixelFormat::RG32UI, 101 PixelFormat::R16G16B16A16_FLOAT, PixelFormat::R16G16B16A16_UINT,
109 PixelFormat::RGBA16U, PixelFormat::RGBA16S, PixelFormat::DXT1_SRGB, PixelFormat::DXT1, 102 PixelFormat::R16G16B16A16_UNORM, PixelFormat::R16G16B16A16_SNORM,
110 103 PixelFormat::R16G16B16A16_SINT, PixelFormat::R32G32_UINT,
104 PixelFormat::R32G32_FLOAT, PixelFormat::R32G32_SINT,
105 PixelFormat::BC1_RGBA_UNORM, PixelFormat::BC1_RGBA_SRGB,
111}; 106};
112// Missing formats: 107// Missing formats:
113// PixelFormat::RGBA16I
114// PixelFormat::RG32I,
115// COMPRESSED_RGB_S3TC_DXT1_EXT 108// COMPRESSED_RGB_S3TC_DXT1_EXT
116// COMPRESSED_SRGB_S3TC_DXT1_EXT 109// COMPRESSED_SRGB_S3TC_DXT1_EXT
117// COMPRESSED_RGBA_S3TC_DXT1_EXT 110// COMPRESSED_RGBA_S3TC_DXT1_EXT
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 758bfe148..8e19c3373 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -20,6 +20,7 @@
20#include "video_core/gpu.h" 20#include "video_core/gpu.h"
21#include "video_core/memory_manager.h" 21#include "video_core/memory_manager.h"
22#include "video_core/renderer_base.h" 22#include "video_core/renderer_base.h"
23#include "video_core/shader_notify.h"
23#include "video_core/video_core.h" 24#include "video_core/video_core.h"
24 25
25namespace Tegra { 26namespace Tegra {
@@ -36,6 +37,7 @@ GPU::GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& render
36 kepler_compute = std::make_unique<Engines::KeplerCompute>(system, rasterizer, *memory_manager); 37 kepler_compute = std::make_unique<Engines::KeplerCompute>(system, rasterizer, *memory_manager);
37 maxwell_dma = std::make_unique<Engines::MaxwellDMA>(system, *memory_manager); 38 maxwell_dma = std::make_unique<Engines::MaxwellDMA>(system, *memory_manager);
38 kepler_memory = std::make_unique<Engines::KeplerMemory>(system, *memory_manager); 39 kepler_memory = std::make_unique<Engines::KeplerMemory>(system, *memory_manager);
40 shader_notify = std::make_unique<VideoCore::ShaderNotify>();
39} 41}
40 42
41GPU::~GPU() = default; 43GPU::~GPU() = default;
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 2c42483bd..19a34c402 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -33,59 +33,68 @@ class System;
33 33
34namespace VideoCore { 34namespace VideoCore {
35class RendererBase; 35class RendererBase;
36class ShaderNotify;
36} // namespace VideoCore 37} // namespace VideoCore
37 38
38namespace Tegra { 39namespace Tegra {
39 40
40enum class RenderTargetFormat : u32 { 41enum class RenderTargetFormat : u32 {
41 NONE = 0x0, 42 NONE = 0x0,
42 RGBA32_FLOAT = 0xC0, 43 R32B32G32A32_FLOAT = 0xC0,
43 RGBA32_UINT = 0xC2, 44 R32G32B32A32_SINT = 0xC1,
44 RGBA16_UNORM = 0xC6, 45 R32G32B32A32_UINT = 0xC2,
45 RGBA16_SNORM = 0xC7, 46 R16G16B16A16_UNORM = 0xC6,
46 RGBA16_UINT = 0xC9, 47 R16G16B16A16_SNORM = 0xC7,
47 RGBA16_FLOAT = 0xCA, 48 R16G16B16A16_SINT = 0xC8,
48 RG32_FLOAT = 0xCB, 49 R16G16B16A16_UINT = 0xC9,
49 RG32_UINT = 0xCD, 50 R16G16B16A16_FLOAT = 0xCA,
50 RGBX16_FLOAT = 0xCE, 51 R32G32_FLOAT = 0xCB,
51 BGRA8_UNORM = 0xCF, 52 R32G32_SINT = 0xCC,
52 BGRA8_SRGB = 0xD0, 53 R32G32_UINT = 0xCD,
53 RGB10_A2_UNORM = 0xD1, 54 R16G16B16X16_FLOAT = 0xCE,
54 RGBA8_UNORM = 0xD5, 55 B8G8R8A8_UNORM = 0xCF,
55 RGBA8_SRGB = 0xD6, 56 B8G8R8A8_SRGB = 0xD0,
56 RGBA8_SNORM = 0xD7, 57 A2B10G10R10_UNORM = 0xD1,
57 RGBA8_UINT = 0xD9, 58 A2B10G10R10_UINT = 0xD2,
58 RG16_UNORM = 0xDA, 59 A8B8G8R8_UNORM = 0xD5,
59 RG16_SNORM = 0xDB, 60 A8B8G8R8_SRGB = 0xD6,
60 RG16_SINT = 0xDC, 61 A8B8G8R8_SNORM = 0xD7,
61 RG16_UINT = 0xDD, 62 A8B8G8R8_SINT = 0xD8,
62 RG16_FLOAT = 0xDE, 63 A8B8G8R8_UINT = 0xD9,
63 R11G11B10_FLOAT = 0xE0, 64 R16G16_UNORM = 0xDA,
65 R16G16_SNORM = 0xDB,
66 R16G16_SINT = 0xDC,
67 R16G16_UINT = 0xDD,
68 R16G16_FLOAT = 0xDE,
69 B10G11R11_FLOAT = 0xE0,
64 R32_SINT = 0xE3, 70 R32_SINT = 0xE3,
65 R32_UINT = 0xE4, 71 R32_UINT = 0xE4,
66 R32_FLOAT = 0xE5, 72 R32_FLOAT = 0xE5,
67 B5G6R5_UNORM = 0xE8, 73 R5G6B5_UNORM = 0xE8,
68 BGR5A1_UNORM = 0xE9, 74 A1R5G5B5_UNORM = 0xE9,
69 RG8_UNORM = 0xEA, 75 R8G8_UNORM = 0xEA,
70 RG8_SNORM = 0xEB, 76 R8G8_SNORM = 0xEB,
71 RG8_UINT = 0xED, 77 R8G8_SINT = 0xEC,
78 R8G8_UINT = 0xED,
72 R16_UNORM = 0xEE, 79 R16_UNORM = 0xEE,
73 R16_SNORM = 0xEF, 80 R16_SNORM = 0xEF,
74 R16_SINT = 0xF0, 81 R16_SINT = 0xF0,
75 R16_UINT = 0xF1, 82 R16_UINT = 0xF1,
76 R16_FLOAT = 0xF2, 83 R16_FLOAT = 0xF2,
77 R8_UNORM = 0xF3, 84 R8_UNORM = 0xF3,
85 R8_SNORM = 0xF4,
86 R8_SINT = 0xF5,
78 R8_UINT = 0xF6, 87 R8_UINT = 0xF6,
79}; 88};
80 89
81enum class DepthFormat : u32 { 90enum class DepthFormat : u32 {
82 Z32_FLOAT = 0xA, 91 D32_FLOAT = 0xA,
83 Z16_UNORM = 0x13, 92 D16_UNORM = 0x13,
84 S8_Z24_UNORM = 0x14, 93 S8_UINT_Z24_UNORM = 0x14,
85 Z24_X8_UNORM = 0x15, 94 D24X8_UNORM = 0x15,
86 Z24_S8_UNORM = 0x16, 95 D24S8_UNORM = 0x16,
87 Z24_C8_UNORM = 0x18, 96 D24C8_UNORM = 0x18,
88 Z32_S8_X24_FLOAT = 0x19, 97 D32_FLOAT_S8X24_UINT = 0x19,
89}; 98};
90 99
91struct CommandListHeader; 100struct CommandListHeader;
@@ -96,9 +105,9 @@ class DebugContext;
96 */ 105 */
97struct FramebufferConfig { 106struct FramebufferConfig {
98 enum class PixelFormat : u32 { 107 enum class PixelFormat : u32 {
99 ABGR8 = 1, 108 A8B8G8R8_UNORM = 1,
100 RGB565 = 4, 109 RGB565_UNORM = 4,
101 BGRA8 = 5, 110 B8G8R8A8_UNORM = 5,
102 }; 111 };
103 112
104 VAddr address; 113 VAddr address;
@@ -207,6 +216,14 @@ public:
207 return *renderer; 216 return *renderer;
208 } 217 }
209 218
219 VideoCore::ShaderNotify& ShaderNotify() {
220 return *shader_notify;
221 }
222
223 const VideoCore::ShaderNotify& ShaderNotify() const {
224 return *shader_notify;
225 }
226
210 // Waits for the GPU to finish working 227 // Waits for the GPU to finish working
211 virtual void WaitIdle() const = 0; 228 virtual void WaitIdle() const = 0;
212 229
@@ -347,6 +364,8 @@ private:
347 std::unique_ptr<Engines::MaxwellDMA> maxwell_dma; 364 std::unique_ptr<Engines::MaxwellDMA> maxwell_dma;
348 /// Inline memory engine 365 /// Inline memory engine
349 std::unique_ptr<Engines::KeplerMemory> kepler_memory; 366 std::unique_ptr<Engines::KeplerMemory> kepler_memory;
367 /// Shader build notifier
368 std::unique_ptr<VideoCore::ShaderNotify> shader_notify;
350 369
351 std::array<std::atomic<u32>, Service::Nvidia::MaxSyncPoints> syncpoints{}; 370 std::array<std::atomic<u32>, Service::Nvidia::MaxSyncPoints> syncpoints{};
352 371
diff --git a/src/video_core/morton.cpp b/src/video_core/morton.cpp
index 836b25c1d..9da9fb4ff 100644
--- a/src/video_core/morton.cpp
+++ b/src/video_core/morton.cpp
@@ -41,146 +41,168 @@ static void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth
41} 41}
42 42
43static constexpr ConversionArray morton_to_linear_fns = { 43static constexpr ConversionArray morton_to_linear_fns = {
44 MortonCopy<true, PixelFormat::ABGR8U>, 44 MortonCopy<true, PixelFormat::A8B8G8R8_UNORM>,
45 MortonCopy<true, PixelFormat::ABGR8S>, 45 MortonCopy<true, PixelFormat::A8B8G8R8_SNORM>,
46 MortonCopy<true, PixelFormat::ABGR8UI>, 46 MortonCopy<true, PixelFormat::A8B8G8R8_SINT>,
47 MortonCopy<true, PixelFormat::B5G6R5U>, 47 MortonCopy<true, PixelFormat::A8B8G8R8_UINT>,
48 MortonCopy<true, PixelFormat::A2B10G10R10U>, 48 MortonCopy<true, PixelFormat::R5G6B5_UNORM>,
49 MortonCopy<true, PixelFormat::A1B5G5R5U>, 49 MortonCopy<true, PixelFormat::B5G6R5_UNORM>,
50 MortonCopy<true, PixelFormat::R8U>, 50 MortonCopy<true, PixelFormat::A1R5G5B5_UNORM>,
51 MortonCopy<true, PixelFormat::R8UI>, 51 MortonCopy<true, PixelFormat::A2B10G10R10_UNORM>,
52 MortonCopy<true, PixelFormat::RGBA16F>, 52 MortonCopy<true, PixelFormat::A2B10G10R10_UINT>,
53 MortonCopy<true, PixelFormat::RGBA16U>, 53 MortonCopy<true, PixelFormat::A1B5G5R5_UNORM>,
54 MortonCopy<true, PixelFormat::RGBA16S>, 54 MortonCopy<true, PixelFormat::R8_UNORM>,
55 MortonCopy<true, PixelFormat::RGBA16UI>, 55 MortonCopy<true, PixelFormat::R8_SNORM>,
56 MortonCopy<true, PixelFormat::R11FG11FB10F>, 56 MortonCopy<true, PixelFormat::R8_SINT>,
57 MortonCopy<true, PixelFormat::RGBA32UI>, 57 MortonCopy<true, PixelFormat::R8_UINT>,
58 MortonCopy<true, PixelFormat::DXT1>, 58 MortonCopy<true, PixelFormat::R16G16B16A16_FLOAT>,
59 MortonCopy<true, PixelFormat::DXT23>, 59 MortonCopy<true, PixelFormat::R16G16B16A16_UNORM>,
60 MortonCopy<true, PixelFormat::DXT45>, 60 MortonCopy<true, PixelFormat::R16G16B16A16_SNORM>,
61 MortonCopy<true, PixelFormat::DXN1>, 61 MortonCopy<true, PixelFormat::R16G16B16A16_SINT>,
62 MortonCopy<true, PixelFormat::DXN2UNORM>, 62 MortonCopy<true, PixelFormat::R16G16B16A16_UINT>,
63 MortonCopy<true, PixelFormat::DXN2SNORM>, 63 MortonCopy<true, PixelFormat::B10G11R11_FLOAT>,
64 MortonCopy<true, PixelFormat::BC7U>, 64 MortonCopy<true, PixelFormat::R32G32B32A32_UINT>,
65 MortonCopy<true, PixelFormat::BC6H_UF16>, 65 MortonCopy<true, PixelFormat::BC1_RGBA_UNORM>,
66 MortonCopy<true, PixelFormat::BC6H_SF16>, 66 MortonCopy<true, PixelFormat::BC2_UNORM>,
67 MortonCopy<true, PixelFormat::ASTC_2D_4X4>, 67 MortonCopy<true, PixelFormat::BC3_UNORM>,
68 MortonCopy<true, PixelFormat::BGRA8>, 68 MortonCopy<true, PixelFormat::BC4_UNORM>,
69 MortonCopy<true, PixelFormat::RGBA32F>, 69 MortonCopy<true, PixelFormat::BC4_SNORM>,
70 MortonCopy<true, PixelFormat::RG32F>, 70 MortonCopy<true, PixelFormat::BC5_UNORM>,
71 MortonCopy<true, PixelFormat::R32F>, 71 MortonCopy<true, PixelFormat::BC5_SNORM>,
72 MortonCopy<true, PixelFormat::R16F>, 72 MortonCopy<true, PixelFormat::BC7_UNORM>,
73 MortonCopy<true, PixelFormat::R16U>, 73 MortonCopy<true, PixelFormat::BC6H_UFLOAT>,
74 MortonCopy<true, PixelFormat::R16S>, 74 MortonCopy<true, PixelFormat::BC6H_SFLOAT>,
75 MortonCopy<true, PixelFormat::R16UI>, 75 MortonCopy<true, PixelFormat::ASTC_2D_4X4_UNORM>,
76 MortonCopy<true, PixelFormat::R16I>, 76 MortonCopy<true, PixelFormat::B8G8R8A8_UNORM>,
77 MortonCopy<true, PixelFormat::RG16>, 77 MortonCopy<true, PixelFormat::R32G32B32A32_FLOAT>,
78 MortonCopy<true, PixelFormat::RG16F>, 78 MortonCopy<true, PixelFormat::R32G32B32A32_SINT>,
79 MortonCopy<true, PixelFormat::RG16UI>, 79 MortonCopy<true, PixelFormat::R32G32_FLOAT>,
80 MortonCopy<true, PixelFormat::RG16I>, 80 MortonCopy<true, PixelFormat::R32G32_SINT>,
81 MortonCopy<true, PixelFormat::RG16S>, 81 MortonCopy<true, PixelFormat::R32_FLOAT>,
82 MortonCopy<true, PixelFormat::RGB32F>, 82 MortonCopy<true, PixelFormat::R16_FLOAT>,
83 MortonCopy<true, PixelFormat::RGBA8_SRGB>, 83 MortonCopy<true, PixelFormat::R16_UNORM>,
84 MortonCopy<true, PixelFormat::RG8U>, 84 MortonCopy<true, PixelFormat::R16_SNORM>,
85 MortonCopy<true, PixelFormat::RG8S>, 85 MortonCopy<true, PixelFormat::R16_UINT>,
86 MortonCopy<true, PixelFormat::RG8UI>, 86 MortonCopy<true, PixelFormat::R16_SINT>,
87 MortonCopy<true, PixelFormat::RG32UI>, 87 MortonCopy<true, PixelFormat::R16G16_UNORM>,
88 MortonCopy<true, PixelFormat::RGBX16F>, 88 MortonCopy<true, PixelFormat::R16G16_FLOAT>,
89 MortonCopy<true, PixelFormat::R32UI>, 89 MortonCopy<true, PixelFormat::R16G16_UINT>,
90 MortonCopy<true, PixelFormat::R32I>, 90 MortonCopy<true, PixelFormat::R16G16_SINT>,
91 MortonCopy<true, PixelFormat::ASTC_2D_8X8>, 91 MortonCopy<true, PixelFormat::R16G16_SNORM>,
92 MortonCopy<true, PixelFormat::ASTC_2D_8X5>, 92 MortonCopy<true, PixelFormat::R32G32B32_FLOAT>,
93 MortonCopy<true, PixelFormat::ASTC_2D_5X4>, 93 MortonCopy<true, PixelFormat::A8B8G8R8_SRGB>,
94 MortonCopy<true, PixelFormat::BGRA8_SRGB>, 94 MortonCopy<true, PixelFormat::R8G8_UNORM>,
95 MortonCopy<true, PixelFormat::DXT1_SRGB>, 95 MortonCopy<true, PixelFormat::R8G8_SNORM>,
96 MortonCopy<true, PixelFormat::DXT23_SRGB>, 96 MortonCopy<true, PixelFormat::R8G8_SINT>,
97 MortonCopy<true, PixelFormat::DXT45_SRGB>, 97 MortonCopy<true, PixelFormat::R8G8_UINT>,
98 MortonCopy<true, PixelFormat::BC7U_SRGB>, 98 MortonCopy<true, PixelFormat::R32G32_UINT>,
99 MortonCopy<true, PixelFormat::R4G4B4A4U>, 99 MortonCopy<true, PixelFormat::R16G16B16X16_FLOAT>,
100 MortonCopy<true, PixelFormat::R32_UINT>,
101 MortonCopy<true, PixelFormat::R32_SINT>,
102 MortonCopy<true, PixelFormat::ASTC_2D_8X8_UNORM>,
103 MortonCopy<true, PixelFormat::ASTC_2D_8X5_UNORM>,
104 MortonCopy<true, PixelFormat::ASTC_2D_5X4_UNORM>,
105 MortonCopy<true, PixelFormat::B8G8R8A8_SRGB>,
106 MortonCopy<true, PixelFormat::BC1_RGBA_SRGB>,
107 MortonCopy<true, PixelFormat::BC2_SRGB>,
108 MortonCopy<true, PixelFormat::BC3_SRGB>,
109 MortonCopy<true, PixelFormat::BC7_SRGB>,
110 MortonCopy<true, PixelFormat::A4B4G4R4_UNORM>,
100 MortonCopy<true, PixelFormat::ASTC_2D_4X4_SRGB>, 111 MortonCopy<true, PixelFormat::ASTC_2D_4X4_SRGB>,
101 MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>, 112 MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>,
102 MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>, 113 MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>,
103 MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>, 114 MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>,
104 MortonCopy<true, PixelFormat::ASTC_2D_5X5>, 115 MortonCopy<true, PixelFormat::ASTC_2D_5X5_UNORM>,
105 MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>, 116 MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>,
106 MortonCopy<true, PixelFormat::ASTC_2D_10X8>, 117 MortonCopy<true, PixelFormat::ASTC_2D_10X8_UNORM>,
107 MortonCopy<true, PixelFormat::ASTC_2D_10X8_SRGB>, 118 MortonCopy<true, PixelFormat::ASTC_2D_10X8_SRGB>,
108 MortonCopy<true, PixelFormat::ASTC_2D_6X6>, 119 MortonCopy<true, PixelFormat::ASTC_2D_6X6_UNORM>,
109 MortonCopy<true, PixelFormat::ASTC_2D_6X6_SRGB>, 120 MortonCopy<true, PixelFormat::ASTC_2D_6X6_SRGB>,
110 MortonCopy<true, PixelFormat::ASTC_2D_10X10>, 121 MortonCopy<true, PixelFormat::ASTC_2D_10X10_UNORM>,
111 MortonCopy<true, PixelFormat::ASTC_2D_10X10_SRGB>, 122 MortonCopy<true, PixelFormat::ASTC_2D_10X10_SRGB>,
112 MortonCopy<true, PixelFormat::ASTC_2D_12X12>, 123 MortonCopy<true, PixelFormat::ASTC_2D_12X12_UNORM>,
113 MortonCopy<true, PixelFormat::ASTC_2D_12X12_SRGB>, 124 MortonCopy<true, PixelFormat::ASTC_2D_12X12_SRGB>,
114 MortonCopy<true, PixelFormat::ASTC_2D_8X6>, 125 MortonCopy<true, PixelFormat::ASTC_2D_8X6_UNORM>,
115 MortonCopy<true, PixelFormat::ASTC_2D_8X6_SRGB>, 126 MortonCopy<true, PixelFormat::ASTC_2D_8X6_SRGB>,
116 MortonCopy<true, PixelFormat::ASTC_2D_6X5>, 127 MortonCopy<true, PixelFormat::ASTC_2D_6X5_UNORM>,
117 MortonCopy<true, PixelFormat::ASTC_2D_6X5_SRGB>, 128 MortonCopy<true, PixelFormat::ASTC_2D_6X5_SRGB>,
118 MortonCopy<true, PixelFormat::E5B9G9R9F>, 129 MortonCopy<true, PixelFormat::E5B9G9R9_FLOAT>,
119 MortonCopy<true, PixelFormat::Z32F>, 130 MortonCopy<true, PixelFormat::D32_FLOAT>,
120 MortonCopy<true, PixelFormat::Z16>, 131 MortonCopy<true, PixelFormat::D16_UNORM>,
121 MortonCopy<true, PixelFormat::Z24S8>, 132 MortonCopy<true, PixelFormat::D24_UNORM_S8_UINT>,
122 MortonCopy<true, PixelFormat::S8Z24>, 133 MortonCopy<true, PixelFormat::S8_UINT_D24_UNORM>,
123 MortonCopy<true, PixelFormat::Z32FS8>, 134 MortonCopy<true, PixelFormat::D32_FLOAT_S8_UINT>,
124}; 135};
125 136
126static constexpr ConversionArray linear_to_morton_fns = { 137static constexpr ConversionArray linear_to_morton_fns = {
127 MortonCopy<false, PixelFormat::ABGR8U>, 138 MortonCopy<false, PixelFormat::A8B8G8R8_UNORM>,
128 MortonCopy<false, PixelFormat::ABGR8S>, 139 MortonCopy<false, PixelFormat::A8B8G8R8_SNORM>,
129 MortonCopy<false, PixelFormat::ABGR8UI>, 140 MortonCopy<false, PixelFormat::A8B8G8R8_SINT>,
130 MortonCopy<false, PixelFormat::B5G6R5U>, 141 MortonCopy<false, PixelFormat::A8B8G8R8_UINT>,
131 MortonCopy<false, PixelFormat::A2B10G10R10U>, 142 MortonCopy<false, PixelFormat::R5G6B5_UNORM>,
132 MortonCopy<false, PixelFormat::A1B5G5R5U>, 143 MortonCopy<false, PixelFormat::B5G6R5_UNORM>,
133 MortonCopy<false, PixelFormat::R8U>, 144 MortonCopy<false, PixelFormat::A1R5G5B5_UNORM>,
134 MortonCopy<false, PixelFormat::R8UI>, 145 MortonCopy<false, PixelFormat::A2B10G10R10_UNORM>,
135 MortonCopy<false, PixelFormat::RGBA16F>, 146 MortonCopy<false, PixelFormat::A2B10G10R10_UINT>,
136 MortonCopy<false, PixelFormat::RGBA16S>, 147 MortonCopy<false, PixelFormat::A1B5G5R5_UNORM>,
137 MortonCopy<false, PixelFormat::RGBA16U>, 148 MortonCopy<false, PixelFormat::R8_UNORM>,
138 MortonCopy<false, PixelFormat::RGBA16UI>, 149 MortonCopy<false, PixelFormat::R8_SNORM>,
139 MortonCopy<false, PixelFormat::R11FG11FB10F>, 150 MortonCopy<false, PixelFormat::R8_SINT>,
140 MortonCopy<false, PixelFormat::RGBA32UI>, 151 MortonCopy<false, PixelFormat::R8_UINT>,
141 MortonCopy<false, PixelFormat::DXT1>, 152 MortonCopy<false, PixelFormat::R16G16B16A16_FLOAT>,
142 MortonCopy<false, PixelFormat::DXT23>, 153 MortonCopy<false, PixelFormat::R16G16B16A16_SNORM>,
143 MortonCopy<false, PixelFormat::DXT45>, 154 MortonCopy<false, PixelFormat::R16G16B16A16_SINT>,
144 MortonCopy<false, PixelFormat::DXN1>, 155 MortonCopy<false, PixelFormat::R16G16B16A16_UNORM>,
145 MortonCopy<false, PixelFormat::DXN2UNORM>, 156 MortonCopy<false, PixelFormat::R16G16B16A16_UINT>,
146 MortonCopy<false, PixelFormat::DXN2SNORM>, 157 MortonCopy<false, PixelFormat::B10G11R11_FLOAT>,
147 MortonCopy<false, PixelFormat::BC7U>, 158 MortonCopy<false, PixelFormat::R32G32B32A32_UINT>,
148 MortonCopy<false, PixelFormat::BC6H_UF16>, 159 MortonCopy<false, PixelFormat::BC1_RGBA_UNORM>,
149 MortonCopy<false, PixelFormat::BC6H_SF16>, 160 MortonCopy<false, PixelFormat::BC2_UNORM>,
161 MortonCopy<false, PixelFormat::BC3_UNORM>,
162 MortonCopy<false, PixelFormat::BC4_UNORM>,
163 MortonCopy<false, PixelFormat::BC4_SNORM>,
164 MortonCopy<false, PixelFormat::BC5_UNORM>,
165 MortonCopy<false, PixelFormat::BC5_SNORM>,
166 MortonCopy<false, PixelFormat::BC7_UNORM>,
167 MortonCopy<false, PixelFormat::BC6H_UFLOAT>,
168 MortonCopy<false, PixelFormat::BC6H_SFLOAT>,
150 // TODO(Subv): Swizzling ASTC formats are not supported 169 // TODO(Subv): Swizzling ASTC formats are not supported
151 nullptr, 170 nullptr,
152 MortonCopy<false, PixelFormat::BGRA8>, 171 MortonCopy<false, PixelFormat::B8G8R8A8_UNORM>,
153 MortonCopy<false, PixelFormat::RGBA32F>, 172 MortonCopy<false, PixelFormat::R32G32B32A32_FLOAT>,
154 MortonCopy<false, PixelFormat::RG32F>, 173 MortonCopy<false, PixelFormat::R32G32B32A32_SINT>,
155 MortonCopy<false, PixelFormat::R32F>, 174 MortonCopy<false, PixelFormat::R32G32_FLOAT>,
156 MortonCopy<false, PixelFormat::R16F>, 175 MortonCopy<false, PixelFormat::R32G32_SINT>,
157 MortonCopy<false, PixelFormat::R16U>, 176 MortonCopy<false, PixelFormat::R32_FLOAT>,
158 MortonCopy<false, PixelFormat::R16S>, 177 MortonCopy<false, PixelFormat::R16_FLOAT>,
159 MortonCopy<false, PixelFormat::R16UI>, 178 MortonCopy<false, PixelFormat::R16_UNORM>,
160 MortonCopy<false, PixelFormat::R16I>, 179 MortonCopy<false, PixelFormat::R16_SNORM>,
161 MortonCopy<false, PixelFormat::RG16>, 180 MortonCopy<false, PixelFormat::R16_UINT>,
162 MortonCopy<false, PixelFormat::RG16F>, 181 MortonCopy<false, PixelFormat::R16_SINT>,
163 MortonCopy<false, PixelFormat::RG16UI>, 182 MortonCopy<false, PixelFormat::R16G16_UNORM>,
164 MortonCopy<false, PixelFormat::RG16I>, 183 MortonCopy<false, PixelFormat::R16G16_FLOAT>,
165 MortonCopy<false, PixelFormat::RG16S>, 184 MortonCopy<false, PixelFormat::R16G16_UINT>,
166 MortonCopy<false, PixelFormat::RGB32F>, 185 MortonCopy<false, PixelFormat::R16G16_SINT>,
167 MortonCopy<false, PixelFormat::RGBA8_SRGB>, 186 MortonCopy<false, PixelFormat::R16G16_SNORM>,
168 MortonCopy<false, PixelFormat::RG8U>, 187 MortonCopy<false, PixelFormat::R32G32B32_FLOAT>,
169 MortonCopy<false, PixelFormat::RG8S>, 188 MortonCopy<false, PixelFormat::A8B8G8R8_SRGB>,
170 MortonCopy<false, PixelFormat::RG8UI>, 189 MortonCopy<false, PixelFormat::R8G8_UNORM>,
171 MortonCopy<false, PixelFormat::RG32UI>, 190 MortonCopy<false, PixelFormat::R8G8_SNORM>,
172 MortonCopy<false, PixelFormat::RGBX16F>, 191 MortonCopy<false, PixelFormat::R8G8_SINT>,
173 MortonCopy<false, PixelFormat::R32UI>, 192 MortonCopy<false, PixelFormat::R8G8_UINT>,
174 MortonCopy<false, PixelFormat::R32I>, 193 MortonCopy<false, PixelFormat::R32G32_UINT>,
194 MortonCopy<false, PixelFormat::R16G16B16X16_FLOAT>,
195 MortonCopy<false, PixelFormat::R32_UINT>,
196 MortonCopy<false, PixelFormat::R32_SINT>,
175 nullptr, 197 nullptr,
176 nullptr, 198 nullptr,
177 nullptr, 199 nullptr,
178 MortonCopy<false, PixelFormat::BGRA8_SRGB>, 200 MortonCopy<false, PixelFormat::B8G8R8A8_SRGB>,
179 MortonCopy<false, PixelFormat::DXT1_SRGB>, 201 MortonCopy<false, PixelFormat::BC1_RGBA_SRGB>,
180 MortonCopy<false, PixelFormat::DXT23_SRGB>, 202 MortonCopy<false, PixelFormat::BC2_SRGB>,
181 MortonCopy<false, PixelFormat::DXT45_SRGB>, 203 MortonCopy<false, PixelFormat::BC3_SRGB>,
182 MortonCopy<false, PixelFormat::BC7U_SRGB>, 204 MortonCopy<false, PixelFormat::BC7_SRGB>,
183 MortonCopy<false, PixelFormat::R4G4B4A4U>, 205 MortonCopy<false, PixelFormat::A4B4G4R4_UNORM>,
184 nullptr, 206 nullptr,
185 nullptr, 207 nullptr,
186 nullptr, 208 nullptr,
@@ -199,12 +221,12 @@ static constexpr ConversionArray linear_to_morton_fns = {
199 nullptr, 221 nullptr,
200 nullptr, 222 nullptr,
201 nullptr, 223 nullptr,
202 MortonCopy<false, PixelFormat::E5B9G9R9F>, 224 MortonCopy<false, PixelFormat::E5B9G9R9_FLOAT>,
203 MortonCopy<false, PixelFormat::Z32F>, 225 MortonCopy<false, PixelFormat::D32_FLOAT>,
204 MortonCopy<false, PixelFormat::Z16>, 226 MortonCopy<false, PixelFormat::D16_UNORM>,
205 MortonCopy<false, PixelFormat::Z24S8>, 227 MortonCopy<false, PixelFormat::D24_UNORM_S8_UINT>,
206 MortonCopy<false, PixelFormat::S8Z24>, 228 MortonCopy<false, PixelFormat::S8_UINT_D24_UNORM>,
207 MortonCopy<false, PixelFormat::Z32FS8>, 229 MortonCopy<false, PixelFormat::D32_FLOAT_S8_UINT>,
208}; 230};
209 231
210static MortonCopyFn GetSwizzleFunction(MortonSwizzleMode mode, Surface::PixelFormat format) { 232static MortonCopyFn GetSwizzleFunction(MortonSwizzleMode mode, Surface::PixelFormat format) {
diff --git a/src/video_core/renderer_opengl/gl_arb_decompiler.cpp b/src/video_core/renderer_opengl/gl_arb_decompiler.cpp
index eb5158407..4489abf61 100644
--- a/src/video_core/renderer_opengl/gl_arb_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_arb_decompiler.cpp
@@ -185,10 +185,6 @@ std::string TextureType(const MetaTexture& meta) {
185 return type; 185 return type;
186} 186}
187 187
188std::string GlobalMemoryName(const GlobalMemoryBase& base) {
189 return fmt::format("gmem{}_{}", base.cbuf_index, base.cbuf_offset);
190}
191
192class ARBDecompiler final { 188class ARBDecompiler final {
193public: 189public:
194 explicit ARBDecompiler(const Device& device, const ShaderIR& ir, const Registry& registry, 190 explicit ARBDecompiler(const Device& device, const ShaderIR& ir, const Registry& registry,
@@ -199,6 +195,8 @@ public:
199 } 195 }
200 196
201private: 197private:
198 void DefineGlobalMemory();
199
202 void DeclareHeader(); 200 void DeclareHeader();
203 void DeclareVertex(); 201 void DeclareVertex();
204 void DeclareGeometry(); 202 void DeclareGeometry();
@@ -228,6 +226,7 @@ private:
228 226
229 std::pair<std::string, std::size_t> BuildCoords(Operation); 227 std::pair<std::string, std::size_t> BuildCoords(Operation);
230 std::string BuildAoffi(Operation); 228 std::string BuildAoffi(Operation);
229 std::string GlobalMemoryPointer(const GmemNode& gmem);
231 void Exit(); 230 void Exit();
232 231
233 std::string Assign(Operation); 232 std::string Assign(Operation);
@@ -378,10 +377,8 @@ private:
378 std::string address; 377 std::string address;
379 std::string_view opname; 378 std::string_view opname;
380 if (const auto gmem = std::get_if<GmemNode>(&*operation[0])) { 379 if (const auto gmem = std::get_if<GmemNode>(&*operation[0])) {
381 AddLine("SUB.U {}, {}, {};", temporary, Visit(gmem->GetRealAddress()), 380 address = GlobalMemoryPointer(*gmem);
382 Visit(gmem->GetBaseAddress())); 381 opname = "ATOM";
383 address = fmt::format("{}[{}]", GlobalMemoryName(gmem->GetDescriptor()), temporary);
384 opname = "ATOMB";
385 } else if (const auto smem = std::get_if<SmemNode>(&*operation[0])) { 382 } else if (const auto smem = std::get_if<SmemNode>(&*operation[0])) {
386 address = fmt::format("shared_mem[{}]", Visit(smem->GetAddress())); 383 address = fmt::format("shared_mem[{}]", Visit(smem->GetAddress()));
387 opname = "ATOMS"; 384 opname = "ATOMS";
@@ -456,9 +453,13 @@ private:
456 shader_source += '\n'; 453 shader_source += '\n';
457 } 454 }
458 455
459 std::string AllocTemporary() { 456 std::string AllocLongVectorTemporary() {
460 max_temporaries = std::max(max_temporaries, num_temporaries + 1); 457 max_long_temporaries = std::max(max_long_temporaries, num_long_temporaries + 1);
461 return fmt::format("T{}.x", num_temporaries++); 458 return fmt::format("L{}", num_long_temporaries++);
459 }
460
461 std::string AllocLongTemporary() {
462 return fmt::format("{}.x", AllocLongVectorTemporary());
462 } 463 }
463 464
464 std::string AllocVectorTemporary() { 465 std::string AllocVectorTemporary() {
@@ -466,8 +467,13 @@ private:
466 return fmt::format("T{}", num_temporaries++); 467 return fmt::format("T{}", num_temporaries++);
467 } 468 }
468 469
470 std::string AllocTemporary() {
471 return fmt::format("{}.x", AllocVectorTemporary());
472 }
473
469 void ResetTemporaries() noexcept { 474 void ResetTemporaries() noexcept {
470 num_temporaries = 0; 475 num_temporaries = 0;
476 num_long_temporaries = 0;
471 } 477 }
472 478
473 const Device& device; 479 const Device& device;
@@ -478,6 +484,11 @@ private:
478 std::size_t num_temporaries = 0; 484 std::size_t num_temporaries = 0;
479 std::size_t max_temporaries = 0; 485 std::size_t max_temporaries = 0;
480 486
487 std::size_t num_long_temporaries = 0;
488 std::size_t max_long_temporaries = 0;
489
490 std::map<GlobalMemoryBase, u32> global_memory_names;
491
481 std::string shader_source; 492 std::string shader_source;
482 493
483 static constexpr std::string_view ADD_F32 = "ADD.F32"; 494 static constexpr std::string_view ADD_F32 = "ADD.F32";
@@ -784,6 +795,8 @@ private:
784ARBDecompiler::ARBDecompiler(const Device& device, const ShaderIR& ir, const Registry& registry, 795ARBDecompiler::ARBDecompiler(const Device& device, const ShaderIR& ir, const Registry& registry,
785 ShaderType stage, std::string_view identifier) 796 ShaderType stage, std::string_view identifier)
786 : device{device}, ir{ir}, registry{registry}, stage{stage} { 797 : device{device}, ir{ir}, registry{registry}, stage{stage} {
798 DefineGlobalMemory();
799
787 AddLine("TEMP RC;"); 800 AddLine("TEMP RC;");
788 AddLine("TEMP FSWZA[4];"); 801 AddLine("TEMP FSWZA[4];");
789 AddLine("TEMP FSWZB[4];"); 802 AddLine("TEMP FSWZB[4];");
@@ -829,12 +842,20 @@ std::string_view HeaderStageName(ShaderType stage) {
829 } 842 }
830} 843}
831 844
845void ARBDecompiler::DefineGlobalMemory() {
846 u32 binding = 0;
847 for (const auto& pair : ir.GetGlobalMemory()) {
848 const GlobalMemoryBase base = pair.first;
849 global_memory_names.emplace(base, binding);
850 ++binding;
851 }
852}
853
832void ARBDecompiler::DeclareHeader() { 854void ARBDecompiler::DeclareHeader() {
833 AddLine("!!NV{}5.0", HeaderStageName(stage)); 855 AddLine("!!NV{}5.0", HeaderStageName(stage));
834 // Enabling this allows us to cheat on some instructions like TXL with SHADOWARRAY2D 856 // Enabling this allows us to cheat on some instructions like TXL with SHADOWARRAY2D
835 AddLine("OPTION NV_internal;"); 857 AddLine("OPTION NV_internal;");
836 AddLine("OPTION NV_gpu_program_fp64;"); 858 AddLine("OPTION NV_gpu_program_fp64;");
837 AddLine("OPTION NV_shader_storage_buffer;");
838 AddLine("OPTION NV_shader_thread_group;"); 859 AddLine("OPTION NV_shader_thread_group;");
839 if (ir.UsesWarps() && device.HasWarpIntrinsics()) { 860 if (ir.UsesWarps() && device.HasWarpIntrinsics()) {
840 AddLine("OPTION NV_shader_thread_shuffle;"); 861 AddLine("OPTION NV_shader_thread_shuffle;");
@@ -951,11 +972,10 @@ void ARBDecompiler::DeclareLocalMemory() {
951} 972}
952 973
953void ARBDecompiler::DeclareGlobalMemory() { 974void ARBDecompiler::DeclareGlobalMemory() {
954 u32 binding = 0; // device.GetBaseBindings(stage).shader_storage_buffer; 975 const std::size_t num_entries = ir.GetGlobalMemory().size();
955 for (const auto& pair : ir.GetGlobalMemory()) { 976 if (num_entries > 0) {
956 const auto& base = pair.first; 977 const std::size_t num_vectors = Common::AlignUp(num_entries, 2) / 2;
957 AddLine("STORAGE {}[] = {{ program.storage[{}] }};", GlobalMemoryName(base), binding); 978 AddLine("PARAM c[{}] = {{ program.local[0..{}] }};", num_vectors, num_vectors - 1);
958 ++binding;
959 } 979 }
960} 980}
961 981
@@ -977,6 +997,9 @@ void ARBDecompiler::DeclareTemporaries() {
977 for (std::size_t i = 0; i < max_temporaries; ++i) { 997 for (std::size_t i = 0; i < max_temporaries; ++i) {
978 AddLine("TEMP T{};", i); 998 AddLine("TEMP T{};", i);
979 } 999 }
1000 for (std::size_t i = 0; i < max_long_temporaries; ++i) {
1001 AddLine("LONG TEMP L{};", i);
1002 }
980} 1003}
981 1004
982void ARBDecompiler::DeclarePredicates() { 1005void ARBDecompiler::DeclarePredicates() {
@@ -1339,10 +1362,7 @@ std::string ARBDecompiler::Visit(const Node& node) {
1339 1362
1340 if (const auto gmem = std::get_if<GmemNode>(&*node)) { 1363 if (const auto gmem = std::get_if<GmemNode>(&*node)) {
1341 std::string temporary = AllocTemporary(); 1364 std::string temporary = AllocTemporary();
1342 AddLine("SUB.U {}, {}, {};", temporary, Visit(gmem->GetRealAddress()), 1365 AddLine("LOAD.U32 {}, {};", temporary, GlobalMemoryPointer(*gmem));
1343 Visit(gmem->GetBaseAddress()));
1344 AddLine("LDB.U32 {}, {}[{}];", temporary, GlobalMemoryName(gmem->GetDescriptor()),
1345 temporary);
1346 return temporary; 1366 return temporary;
1347 } 1367 }
1348 1368
@@ -1419,6 +1439,22 @@ std::string ARBDecompiler::BuildAoffi(Operation operation) {
1419 return fmt::format(", offset({})", temporary); 1439 return fmt::format(", offset({})", temporary);
1420} 1440}
1421 1441
1442std::string ARBDecompiler::GlobalMemoryPointer(const GmemNode& gmem) {
1443 const u32 binding = global_memory_names.at(gmem.GetDescriptor());
1444 const char result_swizzle = binding % 2 == 0 ? 'x' : 'y';
1445
1446 const std::string pointer = AllocLongVectorTemporary();
1447 std::string temporary = AllocTemporary();
1448
1449 const u32 local_index = binding / 2;
1450 AddLine("PK64.U {}, c[{}];", pointer, local_index);
1451 AddLine("SUB.U {}, {}, {};", temporary, Visit(gmem.GetRealAddress()),
1452 Visit(gmem.GetBaseAddress()));
1453 AddLine("CVT.U64.U32 {}.z, {};", pointer, temporary);
1454 AddLine("ADD.U64 {}.x, {}.{}, {}.z;", pointer, pointer, result_swizzle, pointer);
1455 return fmt::format("{}.x", pointer);
1456}
1457
1422void ARBDecompiler::Exit() { 1458void ARBDecompiler::Exit() {
1423 if (stage != ShaderType::Fragment) { 1459 if (stage != ShaderType::Fragment) {
1424 AddLine("RET;"); 1460 AddLine("RET;");
@@ -1515,11 +1551,7 @@ std::string ARBDecompiler::Assign(Operation operation) {
1515 ResetTemporaries(); 1551 ResetTemporaries();
1516 return {}; 1552 return {};
1517 } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) { 1553 } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) {
1518 const std::string temporary = AllocTemporary(); 1554 AddLine("STORE.U32 {}, {};", Visit(src), GlobalMemoryPointer(*gmem));
1519 AddLine("SUB.U {}, {}, {};", temporary, Visit(gmem->GetRealAddress()),
1520 Visit(gmem->GetBaseAddress()));
1521 AddLine("STB.U32 {}, {}[{}];", Visit(src), GlobalMemoryName(gmem->GetDescriptor()),
1522 temporary);
1523 ResetTemporaries(); 1555 ResetTemporaries();
1524 return {}; 1556 return {};
1525 } else { 1557 } else {
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index e461e4c70..e866d8f2f 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -26,7 +26,7 @@ Buffer::Buffer(const Device& device, VAddr cpu_addr, std::size_t size)
26 : VideoCommon::BufferBlock{cpu_addr, size} { 26 : VideoCommon::BufferBlock{cpu_addr, size} {
27 gl_buffer.Create(); 27 gl_buffer.Create();
28 glNamedBufferData(gl_buffer.handle, static_cast<GLsizeiptr>(size), nullptr, GL_DYNAMIC_DRAW); 28 glNamedBufferData(gl_buffer.handle, static_cast<GLsizeiptr>(size), nullptr, GL_DYNAMIC_DRAW);
29 if (device.HasVertexBufferUnifiedMemory()) { 29 if (device.UseAssemblyShaders() || device.HasVertexBufferUnifiedMemory()) {
30 glMakeNamedBufferResidentNV(gl_buffer.handle, GL_READ_WRITE); 30 glMakeNamedBufferResidentNV(gl_buffer.handle, GL_READ_WRITE);
31 glGetNamedBufferParameterui64vNV(gl_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, &gpu_address); 31 glGetNamedBufferParameterui64vNV(gl_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, &gpu_address);
32 } 32 }
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index c1f20f0ab..630acb73b 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -233,6 +233,8 @@ Device::Device()
233 GLAD_GL_NV_gpu_program5 && GLAD_GL_NV_compute_program5 && 233 GLAD_GL_NV_gpu_program5 && GLAD_GL_NV_compute_program5 &&
234 GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2; 234 GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2;
235 235
236 use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue();
237
236 LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi); 238 LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
237 LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug); 239 LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug);
238 LOG_INFO(Render_OpenGL, "Renderer_PreciseBug: {}", has_precise_bug); 240 LOG_INFO(Render_OpenGL, "Renderer_PreciseBug: {}", has_precise_bug);
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h
index e1d811966..94d38d7d1 100644
--- a/src/video_core/renderer_opengl/gl_device.h
+++ b/src/video_core/renderer_opengl/gl_device.h
@@ -104,6 +104,10 @@ public:
104 return use_assembly_shaders; 104 return use_assembly_shaders;
105 } 105 }
106 106
107 bool UseAsynchronousShaders() const {
108 return use_asynchronous_shaders;
109 }
110
107private: 111private:
108 static bool TestVariableAoffi(); 112 static bool TestVariableAoffi();
109 static bool TestPreciseBug(); 113 static bool TestPreciseBug();
@@ -127,6 +131,7 @@ private:
127 bool has_fast_buffer_sub_data{}; 131 bool has_fast_buffer_sub_data{};
128 bool has_nv_viewport_array2{}; 132 bool has_nv_viewport_array2{};
129 bool use_assembly_shaders{}; 133 bool use_assembly_shaders{};
134 bool use_asynchronous_shaders{};
130}; 135};
131 136
132} // namespace OpenGL 137} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index e960a0ef1..03e82c599 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -139,6 +139,18 @@ void oglEnable(GLenum cap, bool state) {
139 (state ? glEnable : glDisable)(cap); 139 (state ? glEnable : glDisable)(cap);
140} 140}
141 141
142void UpdateBindlessPointers(GLenum target, GLuint64EXT* pointers, std::size_t num_entries) {
143 if (num_entries == 0) {
144 return;
145 }
146 if (num_entries % 2 == 1) {
147 pointers[num_entries] = 0;
148 }
149 const GLsizei num_vectors = static_cast<GLsizei>((num_entries + 1) / 2);
150 glProgramLocalParametersI4uivNV(target, 0, num_vectors,
151 reinterpret_cast<const GLuint*>(pointers));
152}
153
142} // Anonymous namespace 154} // Anonymous namespace
143 155
144RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, 156RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
@@ -149,7 +161,8 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind
149 shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, 161 shader_cache{*this, system, emu_window, device}, query_cache{system, *this},
150 buffer_cache{*this, system, device, STREAM_BUFFER_SIZE}, 162 buffer_cache{*this, system, device, STREAM_BUFFER_SIZE},
151 fence_manager{system, *this, texture_cache, buffer_cache, query_cache}, system{system}, 163 fence_manager{system, *this, texture_cache, buffer_cache, query_cache}, system{system},
152 screen_info{info}, program_manager{program_manager}, state_tracker{state_tracker} { 164 screen_info{info}, program_manager{program_manager}, state_tracker{state_tracker},
165 async_shaders{emu_window} {
153 CheckExtensions(); 166 CheckExtensions();
154 167
155 unified_uniform_buffer.Create(); 168 unified_uniform_buffer.Create();
@@ -162,6 +175,23 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind
162 nullptr, 0); 175 nullptr, 0);
163 } 176 }
164 } 177 }
178
179 if (device.UseAsynchronousShaders()) {
180 // Max worker threads we should allow
181 constexpr auto MAX_THREADS = 2u;
182 // Amount of threads we should reserve for other parts of yuzu
183 constexpr auto RESERVED_THREADS = 6u;
184 // Get the amount of threads we can use(this can return zero)
185 const auto cpu_thread_count =
186 std::max(RESERVED_THREADS, std::thread::hardware_concurrency());
187 // Deduce how many "extra" threads we have to use.
188 const auto max_threads_unused = cpu_thread_count - RESERVED_THREADS;
189 // Always allow at least 1 thread regardless of our settings
190 const auto max_worker_count = std::max(1u, max_threads_unused);
191 // Don't use more than MAX_THREADS
192 const auto worker_count = std::min(max_worker_count, MAX_THREADS);
193 async_shaders.AllocateWorkers(worker_count);
194 }
165} 195}
166 196
167RasterizerOpenGL::~RasterizerOpenGL() { 197RasterizerOpenGL::~RasterizerOpenGL() {
@@ -306,7 +336,6 @@ GLintptr RasterizerOpenGL::SetupIndexBuffer() {
306void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { 336void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
307 MICROPROFILE_SCOPE(OpenGL_Shader); 337 MICROPROFILE_SCOPE(OpenGL_Shader);
308 auto& gpu = system.GPU().Maxwell3D(); 338 auto& gpu = system.GPU().Maxwell3D();
309 std::size_t num_ssbos = 0;
310 u32 clip_distances = 0; 339 u32 clip_distances = 0;
311 340
312 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { 341 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
@@ -329,31 +358,15 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
329 } 358 }
330 359
331 // Currently this stages are not supported in the OpenGL backend. 360 // Currently this stages are not supported in the OpenGL backend.
332 // Todo(Blinkhawk): Port tesselation shaders from Vulkan to OpenGL 361 // TODO(Blinkhawk): Port tesselation shaders from Vulkan to OpenGL
333 if (program == Maxwell::ShaderProgram::TesselationControl) { 362 if (program == Maxwell::ShaderProgram::TesselationControl ||
334 continue; 363 program == Maxwell::ShaderProgram::TesselationEval) {
335 } else if (program == Maxwell::ShaderProgram::TesselationEval) {
336 continue; 364 continue;
337 } 365 }
338 366
339 Shader* const shader = shader_cache.GetStageProgram(program); 367 Shader* const shader = shader_cache.GetStageProgram(program, async_shaders);
340
341 if (device.UseAssemblyShaders()) {
342 // Check for ARB limitation. We only have 16 SSBOs per context state. To workaround this
343 // all stages share the same bindings.
344 const std::size_t num_stage_ssbos = shader->GetEntries().global_memory_entries.size();
345 ASSERT_MSG(num_stage_ssbos == 0 || num_ssbos == 0, "SSBOs on more than one stage");
346 num_ssbos += num_stage_ssbos;
347 }
348 368
349 // Stage indices are 0 - 5 369 const GLuint program_handle = shader->IsBuilt() ? shader->GetHandle() : 0;
350 const std::size_t stage = index == 0 ? 0 : index - 1;
351 SetupDrawConstBuffers(stage, shader);
352 SetupDrawGlobalMemory(stage, shader);
353 SetupDrawTextures(stage, shader);
354 SetupDrawImages(stage, shader);
355
356 const GLuint program_handle = shader->GetHandle();
357 switch (program) { 370 switch (program) {
358 case Maxwell::ShaderProgram::VertexA: 371 case Maxwell::ShaderProgram::VertexA:
359 case Maxwell::ShaderProgram::VertexB: 372 case Maxwell::ShaderProgram::VertexB:
@@ -370,6 +383,13 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
370 shader_config.enable.Value(), shader_config.offset); 383 shader_config.enable.Value(), shader_config.offset);
371 } 384 }
372 385
386 // Stage indices are 0 - 5
387 const std::size_t stage = index == 0 ? 0 : index - 1;
388 SetupDrawConstBuffers(stage, shader);
389 SetupDrawGlobalMemory(stage, shader);
390 SetupDrawTextures(stage, shader);
391 SetupDrawImages(stage, shader);
392
373 // Workaround for Intel drivers. 393 // Workaround for Intel drivers.
374 // When a clip distance is enabled but not set in the shader it crops parts of the screen 394 // When a clip distance is enabled but not set in the shader it crops parts of the screen
375 // (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the 395 // (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the
@@ -731,6 +751,8 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
731 current_cbuf = 0; 751 current_cbuf = 0;
732 752
733 auto kernel = shader_cache.GetComputeKernel(code_addr); 753 auto kernel = shader_cache.GetComputeKernel(code_addr);
754 program_manager.BindCompute(kernel->GetHandle());
755
734 SetupComputeTextures(kernel); 756 SetupComputeTextures(kernel);
735 SetupComputeImages(kernel); 757 SetupComputeImages(kernel);
736 758
@@ -745,7 +767,6 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
745 buffer_cache.Unmap(); 767 buffer_cache.Unmap();
746 768
747 const auto& launch_desc = system.GPU().KeplerCompute().launch_description; 769 const auto& launch_desc = system.GPU().KeplerCompute().launch_description;
748 program_manager.BindCompute(kernel->GetHandle());
749 glDispatchCompute(launch_desc.grid_dim_x, launch_desc.grid_dim_y, launch_desc.grid_dim_z); 770 glDispatchCompute(launch_desc.grid_dim_x, launch_desc.grid_dim_y, launch_desc.grid_dim_z);
750 ++num_queued_commands; 771 ++num_queued_commands;
751} 772}
@@ -1005,40 +1026,66 @@ void RasterizerOpenGL::SetupConstBuffer(GLenum stage, u32 binding,
1005} 1026}
1006 1027
1007void RasterizerOpenGL::SetupDrawGlobalMemory(std::size_t stage_index, Shader* shader) { 1028void RasterizerOpenGL::SetupDrawGlobalMemory(std::size_t stage_index, Shader* shader) {
1029 static constexpr std::array TARGET_LUT = {
1030 GL_VERTEX_PROGRAM_NV, GL_TESS_CONTROL_PROGRAM_NV, GL_TESS_EVALUATION_PROGRAM_NV,
1031 GL_GEOMETRY_PROGRAM_NV, GL_FRAGMENT_PROGRAM_NV,
1032 };
1033
1008 auto& gpu{system.GPU()}; 1034 auto& gpu{system.GPU()};
1009 auto& memory_manager{gpu.MemoryManager()}; 1035 auto& memory_manager{gpu.MemoryManager()};
1010 const auto cbufs{gpu.Maxwell3D().state.shader_stages[stage_index]}; 1036 const auto& cbufs{gpu.Maxwell3D().state.shader_stages[stage_index]};
1037 const auto& entries{shader->GetEntries().global_memory_entries};
1038
1039 std::array<GLuint64EXT, 32> pointers;
1040 ASSERT(entries.size() < pointers.size());
1011 1041
1012 u32 binding = 1042 const bool assembly_shaders = device.UseAssemblyShaders();
1013 device.UseAssemblyShaders() ? 0 : device.GetBaseBindings(stage_index).shader_storage_buffer; 1043 u32 binding = assembly_shaders ? 0 : device.GetBaseBindings(stage_index).shader_storage_buffer;
1014 for (const auto& entry : shader->GetEntries().global_memory_entries) { 1044 for (const auto& entry : entries) {
1015 const GPUVAddr addr{cbufs.const_buffers[entry.cbuf_index].address + entry.cbuf_offset}; 1045 const GPUVAddr addr{cbufs.const_buffers[entry.cbuf_index].address + entry.cbuf_offset};
1016 const GPUVAddr gpu_addr{memory_manager.Read<u64>(addr)}; 1046 const GPUVAddr gpu_addr{memory_manager.Read<u64>(addr)};
1017 const u32 size{memory_manager.Read<u32>(addr + 8)}; 1047 const u32 size{memory_manager.Read<u32>(addr + 8)};
1018 SetupGlobalMemory(binding++, entry, gpu_addr, size); 1048 SetupGlobalMemory(binding, entry, gpu_addr, size, &pointers[binding]);
1049 ++binding;
1050 }
1051 if (assembly_shaders) {
1052 UpdateBindlessPointers(TARGET_LUT[stage_index], pointers.data(), entries.size());
1019 } 1053 }
1020} 1054}
1021 1055
1022void RasterizerOpenGL::SetupComputeGlobalMemory(Shader* kernel) { 1056void RasterizerOpenGL::SetupComputeGlobalMemory(Shader* kernel) {
1023 auto& gpu{system.GPU()}; 1057 auto& gpu{system.GPU()};
1024 auto& memory_manager{gpu.MemoryManager()}; 1058 auto& memory_manager{gpu.MemoryManager()};
1025 const auto cbufs{gpu.KeplerCompute().launch_description.const_buffer_config}; 1059 const auto& cbufs{gpu.KeplerCompute().launch_description.const_buffer_config};
1060 const auto& entries{kernel->GetEntries().global_memory_entries};
1061
1062 std::array<GLuint64EXT, 32> pointers;
1063 ASSERT(entries.size() < pointers.size());
1026 1064
1027 u32 binding = 0; 1065 u32 binding = 0;
1028 for (const auto& entry : kernel->GetEntries().global_memory_entries) { 1066 for (const auto& entry : entries) {
1029 const auto addr{cbufs[entry.cbuf_index].Address() + entry.cbuf_offset}; 1067 const GPUVAddr addr{cbufs[entry.cbuf_index].Address() + entry.cbuf_offset};
1030 const auto gpu_addr{memory_manager.Read<u64>(addr)}; 1068 const GPUVAddr gpu_addr{memory_manager.Read<u64>(addr)};
1031 const auto size{memory_manager.Read<u32>(addr + 8)}; 1069 const u32 size{memory_manager.Read<u32>(addr + 8)};
1032 SetupGlobalMemory(binding++, entry, gpu_addr, size); 1070 SetupGlobalMemory(binding, entry, gpu_addr, size, &pointers[binding]);
1071 ++binding;
1072 }
1073 if (device.UseAssemblyShaders()) {
1074 UpdateBindlessPointers(GL_COMPUTE_PROGRAM_NV, pointers.data(), entries.size());
1033 } 1075 }
1034} 1076}
1035 1077
1036void RasterizerOpenGL::SetupGlobalMemory(u32 binding, const GlobalMemoryEntry& entry, 1078void RasterizerOpenGL::SetupGlobalMemory(u32 binding, const GlobalMemoryEntry& entry,
1037 GPUVAddr gpu_addr, std::size_t size) { 1079 GPUVAddr gpu_addr, std::size_t size,
1038 const auto alignment{device.GetShaderStorageBufferAlignment()}; 1080 GLuint64EXT* pointer) {
1081 const std::size_t alignment{device.GetShaderStorageBufferAlignment()};
1039 const auto info = buffer_cache.UploadMemory(gpu_addr, size, alignment, entry.is_written); 1082 const auto info = buffer_cache.UploadMemory(gpu_addr, size, alignment, entry.is_written);
1040 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, binding, info.handle, info.offset, 1083 if (device.UseAssemblyShaders()) {
1041 static_cast<GLsizeiptr>(size)); 1084 *pointer = info.address + info.offset;
1085 } else {
1086 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, binding, info.handle, info.offset,
1087 static_cast<GLsizeiptr>(size));
1088 }
1042} 1089}
1043 1090
1044void RasterizerOpenGL::SetupDrawTextures(std::size_t stage_index, Shader* shader) { 1091void RasterizerOpenGL::SetupDrawTextures(std::size_t stage_index, Shader* shader) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 4f082592f..ccc6f50f6 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -33,6 +33,7 @@
33#include "video_core/renderer_opengl/gl_state_tracker.h" 33#include "video_core/renderer_opengl/gl_state_tracker.h"
34#include "video_core/renderer_opengl/gl_texture_cache.h" 34#include "video_core/renderer_opengl/gl_texture_cache.h"
35#include "video_core/renderer_opengl/utils.h" 35#include "video_core/renderer_opengl/utils.h"
36#include "video_core/shader/async_shaders.h"
36#include "video_core/textures/texture.h" 37#include "video_core/textures/texture.h"
37 38
38namespace Core { 39namespace Core {
@@ -91,6 +92,14 @@ public:
91 return num_queued_commands > 0; 92 return num_queued_commands > 0;
92 } 93 }
93 94
95 VideoCommon::Shader::AsyncShaders& GetAsyncShaders() {
96 return async_shaders;
97 }
98
99 const VideoCommon::Shader::AsyncShaders& GetAsyncShaders() const {
100 return async_shaders;
101 }
102
94private: 103private:
95 /// Configures the color and depth framebuffer states. 104 /// Configures the color and depth framebuffer states.
96 void ConfigureFramebuffers(); 105 void ConfigureFramebuffers();
@@ -115,9 +124,9 @@ private:
115 /// Configures the current global memory entries to use for the kernel invocation. 124 /// Configures the current global memory entries to use for the kernel invocation.
116 void SetupComputeGlobalMemory(Shader* kernel); 125 void SetupComputeGlobalMemory(Shader* kernel);
117 126
118 /// Configures a constant buffer. 127 /// Configures a global memory buffer.
119 void SetupGlobalMemory(u32 binding, const GlobalMemoryEntry& entry, GPUVAddr gpu_addr, 128 void SetupGlobalMemory(u32 binding, const GlobalMemoryEntry& entry, GPUVAddr gpu_addr,
120 std::size_t size); 129 std::size_t size, GLuint64EXT* pointer);
121 130
122 /// Configures the current textures to use for the draw command. 131 /// Configures the current textures to use for the draw command.
123 void SetupDrawTextures(std::size_t stage_index, Shader* shader); 132 void SetupDrawTextures(std::size_t stage_index, Shader* shader);
@@ -242,6 +251,7 @@ private:
242 ScreenInfo& screen_info; 251 ScreenInfo& screen_info;
243 ProgramManager& program_manager; 252 ProgramManager& program_manager;
244 StateTracker& state_tracker; 253 StateTracker& state_tracker;
254 VideoCommon::Shader::AsyncShaders async_shaders;
245 255
246 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; 256 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
247 257
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index f8b322227..b05cb641c 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.h
+++ b/src/video_core/renderer_opengl/gl_resource_manager.h
@@ -177,6 +177,12 @@ public:
177 Release(); 177 Release();
178 } 178 }
179 179
180 OGLAssemblyProgram& operator=(OGLAssemblyProgram&& o) noexcept {
181 Release();
182 handle = std::exchange(o.handle, 0);
183 return *this;
184 }
185
180 /// Deletes the internal OpenGL resource 186 /// Deletes the internal OpenGL resource
181 void Release(); 187 void Release();
182 188
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index c6a3bf3a1..f469ed656 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -31,6 +31,7 @@
31#include "video_core/shader/registry.h" 31#include "video_core/shader/registry.h"
32#include "video_core/shader/shader_ir.h" 32#include "video_core/shader/shader_ir.h"
33#include "video_core/shader_cache.h" 33#include "video_core/shader_cache.h"
34#include "video_core/shader_notify.h"
34 35
35namespace OpenGL { 36namespace OpenGL {
36 37
@@ -140,9 +141,24 @@ std::shared_ptr<Registry> MakeRegistry(const ShaderDiskCacheEntry& entry) {
140 return registry; 141 return registry;
141} 142}
142 143
144std::unordered_set<GLenum> GetSupportedFormats() {
145 GLint num_formats;
146 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &num_formats);
147
148 std::vector<GLint> formats(num_formats);
149 glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, formats.data());
150
151 std::unordered_set<GLenum> supported_formats;
152 for (const GLint format : formats) {
153 supported_formats.insert(static_cast<GLenum>(format));
154 }
155 return supported_formats;
156}
157
158} // Anonymous namespace
159
143ProgramSharedPtr BuildShader(const Device& device, ShaderType shader_type, u64 unique_identifier, 160ProgramSharedPtr BuildShader(const Device& device, ShaderType shader_type, u64 unique_identifier,
144 const ShaderIR& ir, const Registry& registry, 161 const ShaderIR& ir, const Registry& registry, bool hint_retrievable) {
145 bool hint_retrievable = false) {
146 const std::string shader_id = MakeShaderID(unique_identifier, shader_type); 162 const std::string shader_id = MakeShaderID(unique_identifier, shader_type);
147 LOG_INFO(Render_OpenGL, "{}", shader_id); 163 LOG_INFO(Render_OpenGL, "{}", shader_id);
148 164
@@ -181,30 +197,17 @@ ProgramSharedPtr BuildShader(const Device& device, ShaderType shader_type, u64 u
181 return program; 197 return program;
182} 198}
183 199
184std::unordered_set<GLenum> GetSupportedFormats() {
185 GLint num_formats;
186 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &num_formats);
187
188 std::vector<GLint> formats(num_formats);
189 glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, formats.data());
190
191 std::unordered_set<GLenum> supported_formats;
192 for (const GLint format : formats) {
193 supported_formats.insert(static_cast<GLenum>(format));
194 }
195 return supported_formats;
196}
197
198} // Anonymous namespace
199
200Shader::Shader(std::shared_ptr<VideoCommon::Shader::Registry> registry_, ShaderEntries entries_, 200Shader::Shader(std::shared_ptr<VideoCommon::Shader::Registry> registry_, ShaderEntries entries_,
201 ProgramSharedPtr program_) 201 ProgramSharedPtr program_, bool is_built)
202 : registry{std::move(registry_)}, entries{std::move(entries_)}, program{std::move(program_)} { 202 : registry{std::move(registry_)}, entries{std::move(entries_)}, program{std::move(program_)},
203 is_built(is_built) {
203 handle = program->assembly_program.handle; 204 handle = program->assembly_program.handle;
204 if (handle == 0) { 205 if (handle == 0) {
205 handle = program->source_program.handle; 206 handle = program->source_program.handle;
206 } 207 }
207 ASSERT(handle != 0); 208 if (is_built) {
209 ASSERT(handle != 0);
210 }
208} 211}
209 212
210Shader::~Shader() = default; 213Shader::~Shader() = default;
@@ -214,42 +217,82 @@ GLuint Shader::GetHandle() const {
214 return handle; 217 return handle;
215} 218}
216 219
217std::unique_ptr<Shader> Shader::CreateStageFromMemory(const ShaderParameters& params, 220bool Shader::IsBuilt() const {
218 Maxwell::ShaderProgram program_type, 221 return is_built;
219 ProgramCode code, ProgramCode code_b) { 222}
223
224void Shader::AsyncOpenGLBuilt(OGLProgram new_program) {
225 program->source_program = std::move(new_program);
226 handle = program->source_program.handle;
227 is_built = true;
228}
229
230void Shader::AsyncGLASMBuilt(OGLAssemblyProgram new_program) {
231 program->assembly_program = std::move(new_program);
232 handle = program->assembly_program.handle;
233 is_built = true;
234}
235
236std::unique_ptr<Shader> Shader::CreateStageFromMemory(
237 const ShaderParameters& params, Maxwell::ShaderProgram program_type, ProgramCode code,
238 ProgramCode code_b, VideoCommon::Shader::AsyncShaders& async_shaders, VAddr cpu_addr) {
220 const auto shader_type = GetShaderType(program_type); 239 const auto shader_type = GetShaderType(program_type);
221 const std::size_t size_in_bytes = code.size() * sizeof(u64); 240 const std::size_t size_in_bytes = code.size() * sizeof(u64);
222 241
223 auto registry = std::make_shared<Registry>(shader_type, params.system.GPU().Maxwell3D()); 242 auto& gpu = params.system.GPU();
224 const ShaderIR ir(code, STAGE_MAIN_OFFSET, COMPILER_SETTINGS, *registry); 243 gpu.ShaderNotify().MarkSharderBuilding();
225 // TODO(Rodrigo): Handle VertexA shaders 244
226 // std::optional<ShaderIR> ir_b; 245 auto registry = std::make_shared<Registry>(shader_type, gpu.Maxwell3D());
227 // if (!code_b.empty()) { 246 if (!async_shaders.IsShaderAsync(params.system.GPU()) ||
228 // ir_b.emplace(code_b, STAGE_MAIN_OFFSET); 247 !params.device.UseAsynchronousShaders()) {
229 // } 248 const ShaderIR ir(code, STAGE_MAIN_OFFSET, COMPILER_SETTINGS, *registry);
230 auto program = BuildShader(params.device, shader_type, params.unique_identifier, ir, *registry); 249 // TODO(Rodrigo): Handle VertexA shaders
250 // std::optional<ShaderIR> ir_b;
251 // if (!code_b.empty()) {
252 // ir_b.emplace(code_b, STAGE_MAIN_OFFSET);
253 // }
254 auto program =
255 BuildShader(params.device, shader_type, params.unique_identifier, ir, *registry);
256 ShaderDiskCacheEntry entry;
257 entry.type = shader_type;
258 entry.code = std::move(code);
259 entry.code_b = std::move(code_b);
260 entry.unique_identifier = params.unique_identifier;
261 entry.bound_buffer = registry->GetBoundBuffer();
262 entry.graphics_info = registry->GetGraphicsInfo();
263 entry.keys = registry->GetKeys();
264 entry.bound_samplers = registry->GetBoundSamplers();
265 entry.bindless_samplers = registry->GetBindlessSamplers();
266 params.disk_cache.SaveEntry(std::move(entry));
267
268 gpu.ShaderNotify().MarkShaderComplete();
269
270 return std::unique_ptr<Shader>(new Shader(std::move(registry),
271 MakeEntries(params.device, ir, shader_type),
272 std::move(program), true));
273 } else {
274 // Required for entries
275 const ShaderIR ir(code, STAGE_MAIN_OFFSET, COMPILER_SETTINGS, *registry);
276 auto entries = MakeEntries(params.device, ir, shader_type);
231 277
232 ShaderDiskCacheEntry entry; 278 async_shaders.QueueOpenGLShader(params.device, shader_type, params.unique_identifier,
233 entry.type = shader_type; 279 std::move(code), std::move(code_b), STAGE_MAIN_OFFSET,
234 entry.code = std::move(code); 280 COMPILER_SETTINGS, *registry, cpu_addr);
235 entry.code_b = std::move(code_b);
236 entry.unique_identifier = params.unique_identifier;
237 entry.bound_buffer = registry->GetBoundBuffer();
238 entry.graphics_info = registry->GetGraphicsInfo();
239 entry.keys = registry->GetKeys();
240 entry.bound_samplers = registry->GetBoundSamplers();
241 entry.bindless_samplers = registry->GetBindlessSamplers();
242 params.disk_cache.SaveEntry(std::move(entry));
243 281
244 return std::unique_ptr<Shader>(new Shader( 282 auto program = std::make_shared<ProgramHandle>();
245 std::move(registry), MakeEntries(params.device, ir, shader_type), std::move(program))); 283 return std::unique_ptr<Shader>(
284 new Shader(std::move(registry), std::move(entries), std::move(program), false));
285 }
246} 286}
247 287
248std::unique_ptr<Shader> Shader::CreateKernelFromMemory(const ShaderParameters& params, 288std::unique_ptr<Shader> Shader::CreateKernelFromMemory(const ShaderParameters& params,
249 ProgramCode code) { 289 ProgramCode code) {
250 const std::size_t size_in_bytes = code.size() * sizeof(u64); 290 const std::size_t size_in_bytes = code.size() * sizeof(u64);
251 291
252 auto& engine = params.system.GPU().KeplerCompute(); 292 auto& gpu = params.system.GPU();
293 gpu.ShaderNotify().MarkSharderBuilding();
294
295 auto& engine = gpu.KeplerCompute();
253 auto registry = std::make_shared<Registry>(ShaderType::Compute, engine); 296 auto registry = std::make_shared<Registry>(ShaderType::Compute, engine);
254 const ShaderIR ir(code, KERNEL_MAIN_OFFSET, COMPILER_SETTINGS, *registry); 297 const ShaderIR ir(code, KERNEL_MAIN_OFFSET, COMPILER_SETTINGS, *registry);
255 const u64 uid = params.unique_identifier; 298 const u64 uid = params.unique_identifier;
@@ -266,6 +309,8 @@ std::unique_ptr<Shader> Shader::CreateKernelFromMemory(const ShaderParameters& p
266 entry.bindless_samplers = registry->GetBindlessSamplers(); 309 entry.bindless_samplers = registry->GetBindlessSamplers();
267 params.disk_cache.SaveEntry(std::move(entry)); 310 params.disk_cache.SaveEntry(std::move(entry));
268 311
312 gpu.ShaderNotify().MarkShaderComplete();
313
269 return std::unique_ptr<Shader>(new Shader(std::move(registry), 314 return std::unique_ptr<Shader>(new Shader(std::move(registry),
270 MakeEntries(params.device, ir, ShaderType::Compute), 315 MakeEntries(params.device, ir, ShaderType::Compute),
271 std::move(program))); 316 std::move(program)));
@@ -436,14 +481,51 @@ ProgramSharedPtr ShaderCacheOpenGL::GeneratePrecompiledProgram(
436 return program; 481 return program;
437} 482}
438 483
439Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { 484Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program,
485 VideoCommon::Shader::AsyncShaders& async_shaders) {
440 if (!system.GPU().Maxwell3D().dirty.flags[Dirty::Shaders]) { 486 if (!system.GPU().Maxwell3D().dirty.flags[Dirty::Shaders]) {
441 return last_shaders[static_cast<std::size_t>(program)]; 487 auto* last_shader = last_shaders[static_cast<std::size_t>(program)];
488 if (last_shader->IsBuilt()) {
489 return last_shader;
490 }
442 } 491 }
443 492
444 auto& memory_manager{system.GPU().MemoryManager()}; 493 auto& memory_manager{system.GPU().MemoryManager()};
445 const GPUVAddr address{GetShaderAddress(system, program)}; 494 const GPUVAddr address{GetShaderAddress(system, program)};
446 495
496 if (device.UseAsynchronousShaders() && async_shaders.HasCompletedWork()) {
497 auto completed_work = async_shaders.GetCompletedWork();
498 for (auto& work : completed_work) {
499 Shader* shader = TryGet(work.cpu_address);
500 auto& gpu = system.GPU();
501 gpu.ShaderNotify().MarkShaderComplete();
502 if (shader == nullptr) {
503 continue;
504 }
505 using namespace VideoCommon::Shader;
506 if (work.backend == AsyncShaders::Backend::OpenGL) {
507 shader->AsyncOpenGLBuilt(std::move(work.program.opengl));
508 } else if (work.backend == AsyncShaders::Backend::GLASM) {
509 shader->AsyncGLASMBuilt(std::move(work.program.glasm));
510 }
511
512 ShaderDiskCacheEntry entry;
513 entry.type = work.shader_type;
514 entry.code = std::move(work.code);
515 entry.code_b = std::move(work.code_b);
516 entry.unique_identifier = work.uid;
517
518 auto& registry = shader->GetRegistry();
519
520 entry.bound_buffer = registry.GetBoundBuffer();
521 entry.graphics_info = registry.GetGraphicsInfo();
522 entry.keys = registry.GetKeys();
523 entry.bound_samplers = registry.GetBoundSamplers();
524 entry.bindless_samplers = registry.GetBindlessSamplers();
525 disk_cache.SaveEntry(std::move(entry));
526 }
527 }
528
447 // Look up shader in the cache based on address 529 // Look up shader in the cache based on address
448 const auto cpu_addr{memory_manager.GpuToCpuAddress(address)}; 530 const auto cpu_addr{memory_manager.GpuToCpuAddress(address)};
449 if (Shader* const shader{cpu_addr ? TryGet(*cpu_addr) : null_shader.get()}) { 531 if (Shader* const shader{cpu_addr ? TryGet(*cpu_addr) : null_shader.get()}) {
@@ -471,7 +553,8 @@ Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
471 std::unique_ptr<Shader> shader; 553 std::unique_ptr<Shader> shader;
472 const auto found = runtime_cache.find(unique_identifier); 554 const auto found = runtime_cache.find(unique_identifier);
473 if (found == runtime_cache.end()) { 555 if (found == runtime_cache.end()) {
474 shader = Shader::CreateStageFromMemory(params, program, std::move(code), std::move(code_b)); 556 shader = Shader::CreateStageFromMemory(params, program, std::move(code), std::move(code_b),
557 async_shaders, cpu_addr.value_or(0));
475 } else { 558 } else {
476 shader = Shader::CreateFromCache(params, found->second); 559 shader = Shader::CreateFromCache(params, found->second);
477 } 560 }
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index 994aaeaf2..7528ac686 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -33,6 +33,10 @@ namespace Core::Frontend {
33class EmuWindow; 33class EmuWindow;
34} 34}
35 35
36namespace VideoCommon::Shader {
37class AsyncShaders;
38}
39
36namespace OpenGL { 40namespace OpenGL {
37 41
38class Device; 42class Device;
@@ -61,6 +65,11 @@ struct ShaderParameters {
61 u64 unique_identifier; 65 u64 unique_identifier;
62}; 66};
63 67
68ProgramSharedPtr BuildShader(const Device& device, Tegra::Engines::ShaderType shader_type,
69 u64 unique_identifier, const VideoCommon::Shader::ShaderIR& ir,
70 const VideoCommon::Shader::Registry& registry,
71 bool hint_retrievable = false);
72
64class Shader final { 73class Shader final {
65public: 74public:
66 ~Shader(); 75 ~Shader();
@@ -68,15 +77,28 @@ public:
68 /// Gets the GL program handle for the shader 77 /// Gets the GL program handle for the shader
69 GLuint GetHandle() const; 78 GLuint GetHandle() const;
70 79
80 bool IsBuilt() const;
81
71 /// Gets the shader entries for the shader 82 /// Gets the shader entries for the shader
72 const ShaderEntries& GetEntries() const { 83 const ShaderEntries& GetEntries() const {
73 return entries; 84 return entries;
74 } 85 }
75 86
76 static std::unique_ptr<Shader> CreateStageFromMemory(const ShaderParameters& params, 87 const VideoCommon::Shader::Registry& GetRegistry() const {
77 Maxwell::ShaderProgram program_type, 88 return *registry;
78 ProgramCode program_code, 89 }
79 ProgramCode program_code_b); 90
91 /// Mark a OpenGL shader as built
92 void AsyncOpenGLBuilt(OGLProgram new_program);
93
94 /// Mark a GLASM shader as built
95 void AsyncGLASMBuilt(OGLAssemblyProgram new_program);
96
97 static std::unique_ptr<Shader> CreateStageFromMemory(
98 const ShaderParameters& params, Maxwell::ShaderProgram program_type,
99 ProgramCode program_code, ProgramCode program_code_b,
100 VideoCommon::Shader::AsyncShaders& async_shaders, VAddr cpu_addr);
101
80 static std::unique_ptr<Shader> CreateKernelFromMemory(const ShaderParameters& params, 102 static std::unique_ptr<Shader> CreateKernelFromMemory(const ShaderParameters& params,
81 ProgramCode code); 103 ProgramCode code);
82 104
@@ -85,12 +107,13 @@ public:
85 107
86private: 108private:
87 explicit Shader(std::shared_ptr<VideoCommon::Shader::Registry> registry, ShaderEntries entries, 109 explicit Shader(std::shared_ptr<VideoCommon::Shader::Registry> registry, ShaderEntries entries,
88 ProgramSharedPtr program); 110 ProgramSharedPtr program, bool is_built = true);
89 111
90 std::shared_ptr<VideoCommon::Shader::Registry> registry; 112 std::shared_ptr<VideoCommon::Shader::Registry> registry;
91 ShaderEntries entries; 113 ShaderEntries entries;
92 ProgramSharedPtr program; 114 ProgramSharedPtr program;
93 GLuint handle = 0; 115 GLuint handle = 0;
116 bool is_built{};
94}; 117};
95 118
96class ShaderCacheOpenGL final : public VideoCommon::ShaderCache<Shader> { 119class ShaderCacheOpenGL final : public VideoCommon::ShaderCache<Shader> {
@@ -104,7 +127,8 @@ public:
104 const VideoCore::DiskResourceLoadCallback& callback); 127 const VideoCore::DiskResourceLoadCallback& callback);
105 128
106 /// Gets the current specified shader stage program 129 /// Gets the current specified shader stage program
107 Shader* GetStageProgram(Maxwell::ShaderProgram program); 130 Shader* GetStageProgram(Maxwell::ShaderProgram program,
131 VideoCommon::Shader::AsyncShaders& async_shaders);
108 132
109 /// Gets a compute kernel in the passed address 133 /// Gets a compute kernel in the passed address
110 Shader* GetComputeKernel(GPUVAddr code_addr); 134 Shader* GetComputeKernel(GPUVAddr code_addr);
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp
index 8e754fa90..691c6c79b 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp
@@ -11,8 +11,30 @@
11 11
12namespace OpenGL { 12namespace OpenGL {
13 13
14ProgramManager::ProgramManager(const Device& device) { 14namespace {
15 use_assembly_programs = device.UseAssemblyShaders(); 15
16void BindProgram(GLenum stage, GLuint current, GLuint old, bool& enabled) {
17 if (current == old) {
18 return;
19 }
20 if (current == 0) {
21 if (enabled) {
22 enabled = false;
23 glDisable(stage);
24 }
25 return;
26 }
27 if (!enabled) {
28 enabled = true;
29 glEnable(stage);
30 }
31 glBindProgramARB(stage, current);
32}
33
34} // Anonymous namespace
35
36ProgramManager::ProgramManager(const Device& device)
37 : use_assembly_programs{device.UseAssemblyShaders()} {
16 if (use_assembly_programs) { 38 if (use_assembly_programs) {
17 glEnable(GL_COMPUTE_PROGRAM_NV); 39 glEnable(GL_COMPUTE_PROGRAM_NV);
18 } else { 40 } else {
@@ -33,9 +55,7 @@ void ProgramManager::BindCompute(GLuint program) {
33} 55}
34 56
35void ProgramManager::BindGraphicsPipeline() { 57void ProgramManager::BindGraphicsPipeline() {
36 if (use_assembly_programs) { 58 if (!use_assembly_programs) {
37 UpdateAssemblyPrograms();
38 } else {
39 UpdateSourcePrograms(); 59 UpdateSourcePrograms();
40 } 60 }
41} 61}
@@ -63,32 +83,25 @@ void ProgramManager::RestoreGuestPipeline() {
63 } 83 }
64} 84}
65 85
66void ProgramManager::UpdateAssemblyPrograms() { 86void ProgramManager::UseVertexShader(GLuint program) {
67 const auto update_state = [](GLenum stage, bool& enabled, GLuint current, GLuint old) { 87 if (use_assembly_programs) {
68 if (current == old) { 88 BindProgram(GL_VERTEX_PROGRAM_NV, program, current_state.vertex, vertex_enabled);
69 return; 89 }
70 } 90 current_state.vertex = program;
71 if (current == 0) { 91}
72 if (enabled) {
73 enabled = false;
74 glDisable(stage);
75 }
76 return;
77 }
78 if (!enabled) {
79 enabled = true;
80 glEnable(stage);
81 }
82 glBindProgramARB(stage, current);
83 };
84 92
85 update_state(GL_VERTEX_PROGRAM_NV, vertex_enabled, current_state.vertex, old_state.vertex); 93void ProgramManager::UseGeometryShader(GLuint program) {
86 update_state(GL_GEOMETRY_PROGRAM_NV, geometry_enabled, current_state.geometry, 94 if (use_assembly_programs) {
87 old_state.geometry); 95 BindProgram(GL_GEOMETRY_PROGRAM_NV, program, current_state.vertex, geometry_enabled);
88 update_state(GL_FRAGMENT_PROGRAM_NV, fragment_enabled, current_state.fragment, 96 }
89 old_state.fragment); 97 current_state.geometry = program;
98}
90 99
91 old_state = current_state; 100void ProgramManager::UseFragmentShader(GLuint program) {
101 if (use_assembly_programs) {
102 BindProgram(GL_FRAGMENT_PROGRAM_NV, program, current_state.vertex, fragment_enabled);
103 }
104 current_state.fragment = program;
92} 105}
93 106
94void ProgramManager::UpdateSourcePrograms() { 107void ProgramManager::UpdateSourcePrograms() {
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index 0f03b4f12..950e0dfcb 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -45,17 +45,9 @@ public:
45 /// Rewinds BindHostPipeline state changes. 45 /// Rewinds BindHostPipeline state changes.
46 void RestoreGuestPipeline(); 46 void RestoreGuestPipeline();
47 47
48 void UseVertexShader(GLuint program) { 48 void UseVertexShader(GLuint program);
49 current_state.vertex = program; 49 void UseGeometryShader(GLuint program);
50 } 50 void UseFragmentShader(GLuint program);
51
52 void UseGeometryShader(GLuint program) {
53 current_state.geometry = program;
54 }
55
56 void UseFragmentShader(GLuint program) {
57 current_state.fragment = program;
58 }
59 51
60private: 52private:
61 struct PipelineState { 53 struct PipelineState {
@@ -64,9 +56,6 @@ private:
64 GLuint fragment = 0; 56 GLuint fragment = 0;
65 }; 57 };
66 58
67 /// Update NV_gpu_program5 programs.
68 void UpdateAssemblyPrograms();
69
70 /// Update GLSL programs. 59 /// Update GLSL programs.
71 void UpdateSourcePrograms(); 60 void UpdateSourcePrograms();
72 61
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
index 3655ff629..887995cf4 100644
--- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp
+++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
@@ -35,7 +35,7 @@ OGLStreamBuffer::OGLStreamBuffer(const Device& device, GLsizeiptr size, bool ver
35 mapped_ptr = static_cast<u8*>( 35 mapped_ptr = static_cast<u8*>(
36 glMapNamedBufferRange(gl_buffer.handle, 0, buffer_size, flags | GL_MAP_FLUSH_EXPLICIT_BIT)); 36 glMapNamedBufferRange(gl_buffer.handle, 0, buffer_size, flags | GL_MAP_FLUSH_EXPLICIT_BIT));
37 37
38 if (device.HasVertexBufferUnifiedMemory()) { 38 if (device.UseAssemblyShaders() || device.HasVertexBufferUnifiedMemory()) {
39 glMakeNamedBufferResidentNV(gl_buffer.handle, GL_READ_ONLY); 39 glMakeNamedBufferResidentNV(gl_buffer.handle, GL_READ_ONLY);
40 glGetNamedBufferParameterui64vNV(gl_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, &gpu_address); 40 glGetNamedBufferParameterui64vNV(gl_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, &gpu_address);
41 } 41 }
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 61505879b..0a7bc9e2b 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -41,91 +41,103 @@ struct FormatTuple {
41}; 41};
42 42
43constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{ 43constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{
44 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV}, // ABGR8U 44 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV}, // A8B8G8R8_UNORM
45 {GL_RGBA8_SNORM, GL_RGBA, GL_BYTE}, // ABGR8S 45 {GL_RGBA8_SNORM, GL_RGBA, GL_BYTE}, // A8B8G8R8_SNORM
46 {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE}, // ABGR8UI 46 {GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE}, // A8B8G8R8_SINT
47 {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV}, // B5G6R5U 47 {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE}, // A8B8G8R8_UINT
48 {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}, // A2B10G10R10U 48 {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // R5G6B5_UNORM
49 {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, // A1B5G5R5U 49 {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV}, // B5G6R5_UNORM
50 {GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // R8U 50 {GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, // A1R5G5B5_UNORM
51 {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE}, // R8UI 51 {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}, // A2B10G10R10_UNORM
52 {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT}, // RGBA16F 52 {GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV}, // A2B10G10R10_UINT
53 {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT}, // RGBA16U 53 {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, // A1B5G5R5_UNORM
54 {GL_RGBA16_SNORM, GL_RGBA, GL_SHORT}, // RGBA16S 54 {GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // R8_UNORM
55 {GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT}, // RGBA16UI 55 {GL_R8_SNORM, GL_RED, GL_BYTE}, // R8_SNORM
56 {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV}, // R11FG11FB10F 56 {GL_R8I, GL_RED_INTEGER, GL_BYTE}, // R8_SINT
57 {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT}, // RGBA32UI 57 {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE}, // R8_UINT
58 {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT}, // DXT1 58 {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT}, // R16G16B16A16_FLOAT
59 {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT}, // DXT23 59 {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT}, // R16G16B16A16_UNORM
60 {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT}, // DXT45 60 {GL_RGBA16_SNORM, GL_RGBA, GL_SHORT}, // R16G16B16A16_SNORM
61 {GL_COMPRESSED_RED_RGTC1}, // DXN1 61 {GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT}, // R16G16B16A16_SINT
62 {GL_COMPRESSED_RG_RGTC2}, // DXN2UNORM 62 {GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT}, // R16G16B16A16_UINT
63 {GL_COMPRESSED_SIGNED_RG_RGTC2}, // DXN2SNORM 63 {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV}, // B10G11R11_FLOAT
64 {GL_COMPRESSED_RGBA_BPTC_UNORM}, // BC7U 64 {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT}, // R32G32B32A32_UINT
65 {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT}, // BC6H_UF16 65 {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT}, // BC1_RGBA_UNORM
66 {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT}, // BC6H_SF16 66 {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT}, // BC2_UNORM
67 {GL_COMPRESSED_RGBA_ASTC_4x4_KHR}, // ASTC_2D_4X4 67 {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT}, // BC3_UNORM
68 {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE}, // BGRA8 68 {GL_COMPRESSED_RED_RGTC1}, // BC4_UNORM
69 {GL_RGBA32F, GL_RGBA, GL_FLOAT}, // RGBA32F 69 {GL_COMPRESSED_SIGNED_RED_RGTC1}, // BC4_SNORM
70 {GL_RG32F, GL_RG, GL_FLOAT}, // RG32F 70 {GL_COMPRESSED_RG_RGTC2}, // BC5_UNORM
71 {GL_R32F, GL_RED, GL_FLOAT}, // R32F 71 {GL_COMPRESSED_SIGNED_RG_RGTC2}, // BC5_SNORM
72 {GL_R16F, GL_RED, GL_HALF_FLOAT}, // R16F 72 {GL_COMPRESSED_RGBA_BPTC_UNORM}, // BC7_UNORM
73 {GL_R16, GL_RED, GL_UNSIGNED_SHORT}, // R16U 73 {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT}, // BC6H_UFLOAT
74 {GL_R16_SNORM, GL_RED, GL_SHORT}, // R16S 74 {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT}, // BC6H_SFLOAT
75 {GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT}, // R16UI 75 {GL_COMPRESSED_RGBA_ASTC_4x4_KHR}, // ASTC_2D_4X4_UNORM
76 {GL_R16I, GL_RED_INTEGER, GL_SHORT}, // R16I 76 {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE}, // B8G8R8A8_UNORM
77 {GL_RG16, GL_RG, GL_UNSIGNED_SHORT}, // RG16 77 {GL_RGBA32F, GL_RGBA, GL_FLOAT}, // R32G32B32A32_FLOAT
78 {GL_RG16F, GL_RG, GL_HALF_FLOAT}, // RG16F 78 {GL_RGBA32I, GL_RGBA_INTEGER, GL_INT}, // R32G32B32A32_SINT
79 {GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT}, // RG16UI 79 {GL_RG32F, GL_RG, GL_FLOAT}, // R32G32_FLOAT
80 {GL_RG16I, GL_RG_INTEGER, GL_SHORT}, // RG16I 80 {GL_RG32I, GL_RG_INTEGER, GL_INT}, // R32G32_SINT
81 {GL_RG16_SNORM, GL_RG, GL_SHORT}, // RG16S 81 {GL_R32F, GL_RED, GL_FLOAT}, // R32_FLOAT
82 {GL_RGB32F, GL_RGB, GL_FLOAT}, // RGB32F 82 {GL_R16F, GL_RED, GL_HALF_FLOAT}, // R16_FLOAT
83 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV}, // RGBA8_SRGB 83 {GL_R16, GL_RED, GL_UNSIGNED_SHORT}, // R16_UNORM
84 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE}, // RG8U 84 {GL_R16_SNORM, GL_RED, GL_SHORT}, // R16_SNORM
85 {GL_RG8_SNORM, GL_RG, GL_BYTE}, // RG8S 85 {GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT}, // R16_UINT
86 {GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_INT}, // RG8UI 86 {GL_R16I, GL_RED_INTEGER, GL_SHORT}, // R16_SINT
87 {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT}, // RG32UI 87 {GL_RG16, GL_RG, GL_UNSIGNED_SHORT}, // R16G16_UNORM
88 {GL_RGB16F, GL_RGBA, GL_HALF_FLOAT}, // RGBX16F 88 {GL_RG16F, GL_RG, GL_HALF_FLOAT}, // R16G16_FLOAT
89 {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT}, // R32UI 89 {GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT}, // R16G16_UINT
90 {GL_R32I, GL_RED_INTEGER, GL_INT}, // R32I 90 {GL_RG16I, GL_RG_INTEGER, GL_SHORT}, // R16G16_SINT
91 {GL_COMPRESSED_RGBA_ASTC_8x8_KHR}, // ASTC_2D_8X8 91 {GL_RG16_SNORM, GL_RG, GL_SHORT}, // R16G16_SNORM
92 {GL_COMPRESSED_RGBA_ASTC_8x5_KHR}, // ASTC_2D_8X5 92 {GL_RGB32F, GL_RGB, GL_FLOAT}, // R32G32B32_FLOAT
93 {GL_COMPRESSED_RGBA_ASTC_5x4_KHR}, // ASTC_2D_5X4 93 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV}, // A8B8G8R8_SRGB
94 {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE}, // BGRA8 94 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE}, // R8G8_UNORM
95 {GL_RG8_SNORM, GL_RG, GL_BYTE}, // R8G8_SNORM
96 {GL_RG8I, GL_RG_INTEGER, GL_BYTE}, // R8G8_SINT
97 {GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE}, // R8G8_UINT
98 {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT}, // R32G32_UINT
99 {GL_RGB16F, GL_RGBA, GL_HALF_FLOAT}, // R16G16B16X16_FLOAT
100 {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT}, // R32_UINT
101 {GL_R32I, GL_RED_INTEGER, GL_INT}, // R32_SINT
102 {GL_COMPRESSED_RGBA_ASTC_8x8_KHR}, // ASTC_2D_8X8_UNORM
103 {GL_COMPRESSED_RGBA_ASTC_8x5_KHR}, // ASTC_2D_8X5_UNORM
104 {GL_COMPRESSED_RGBA_ASTC_5x4_KHR}, // ASTC_2D_5X4_UNORM
105 {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE}, // B8G8R8A8_UNORM
95 // Compressed sRGB formats 106 // Compressed sRGB formats
96 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT}, // DXT1_SRGB 107 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT}, // BC1_RGBA_SRGB
97 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT}, // DXT23_SRGB 108 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT}, // BC2_SRGB
98 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}, // DXT45_SRGB 109 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}, // BC3_SRGB
99 {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM}, // BC7U_SRGB 110 {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM}, // BC7_SRGB
100 {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV}, // R4G4B4A4U 111 {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV}, // A4B4G4R4_UNORM
101 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR}, // ASTC_2D_4X4_SRGB 112 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR}, // ASTC_2D_4X4_SRGB
102 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR}, // ASTC_2D_8X8_SRGB 113 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR}, // ASTC_2D_8X8_SRGB
103 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR}, // ASTC_2D_8X5_SRGB 114 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR}, // ASTC_2D_8X5_SRGB
104 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR}, // ASTC_2D_5X4_SRGB 115 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR}, // ASTC_2D_5X4_SRGB
105 {GL_COMPRESSED_RGBA_ASTC_5x5_KHR}, // ASTC_2D_5X5 116 {GL_COMPRESSED_RGBA_ASTC_5x5_KHR}, // ASTC_2D_5X5_UNORM
106 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR}, // ASTC_2D_5X5_SRGB 117 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR}, // ASTC_2D_5X5_SRGB
107 {GL_COMPRESSED_RGBA_ASTC_10x8_KHR}, // ASTC_2D_10X8 118 {GL_COMPRESSED_RGBA_ASTC_10x8_KHR}, // ASTC_2D_10X8_UNORM
108 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR}, // ASTC_2D_10X8_SRGB 119 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR}, // ASTC_2D_10X8_SRGB
109 {GL_COMPRESSED_RGBA_ASTC_6x6_KHR}, // ASTC_2D_6X6 120 {GL_COMPRESSED_RGBA_ASTC_6x6_KHR}, // ASTC_2D_6X6_UNORM
110 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR}, // ASTC_2D_6X6_SRGB 121 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR}, // ASTC_2D_6X6_SRGB
111 {GL_COMPRESSED_RGBA_ASTC_10x10_KHR}, // ASTC_2D_10X10 122 {GL_COMPRESSED_RGBA_ASTC_10x10_KHR}, // ASTC_2D_10X10_UNORM
112 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR}, // ASTC_2D_10X10_SRGB 123 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR}, // ASTC_2D_10X10_SRGB
113 {GL_COMPRESSED_RGBA_ASTC_12x12_KHR}, // ASTC_2D_12X12 124 {GL_COMPRESSED_RGBA_ASTC_12x12_KHR}, // ASTC_2D_12X12_UNORM
114 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR}, // ASTC_2D_12X12_SRGB 125 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR}, // ASTC_2D_12X12_SRGB
115 {GL_COMPRESSED_RGBA_ASTC_8x6_KHR}, // ASTC_2D_8X6 126 {GL_COMPRESSED_RGBA_ASTC_8x6_KHR}, // ASTC_2D_8X6_UNORM
116 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR}, // ASTC_2D_8X6_SRGB 127 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR}, // ASTC_2D_8X6_SRGB
117 {GL_COMPRESSED_RGBA_ASTC_6x5_KHR}, // ASTC_2D_6X5 128 {GL_COMPRESSED_RGBA_ASTC_6x5_KHR}, // ASTC_2D_6X5_UNORM
118 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR}, // ASTC_2D_6X5_SRGB 129 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR}, // ASTC_2D_6X5_SRGB
119 {GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV}, // E5B9G9R9F 130 {GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV}, // E5B9G9R9_FLOAT
120 131
121 // Depth formats 132 // Depth formats
122 {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}, // Z32F 133 {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}, // D32_FLOAT
123 {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // Z16 134 {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16_UNORM
124 135
125 // DepthStencil formats 136 // DepthStencil formats
126 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // Z24S8 137 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24_UNORM_S8_UINT
127 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // S8Z24 138 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // S8_UINT_D24_UNORM
128 {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV}, // Z32FS8 139 {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL,
140 GL_FLOAT_32_UNSIGNED_INT_24_8_REV}, // D32_FLOAT_S8_UINT
129}}; 141}};
130 142
131const FormatTuple& GetFormatTuple(PixelFormat pixel_format) { 143const FormatTuple& GetFormatTuple(PixelFormat pixel_format) {
@@ -178,10 +190,10 @@ GLint GetSwizzleSource(SwizzleSource source) {
178 190
179GLenum GetComponent(PixelFormat format, bool is_first) { 191GLenum GetComponent(PixelFormat format, bool is_first) {
180 switch (format) { 192 switch (format) {
181 case PixelFormat::Z24S8: 193 case PixelFormat::D24_UNORM_S8_UINT:
182 case PixelFormat::Z32FS8: 194 case PixelFormat::D32_FLOAT_S8_UINT:
183 return is_first ? GL_DEPTH_COMPONENT : GL_STENCIL_INDEX; 195 return is_first ? GL_DEPTH_COMPONENT : GL_STENCIL_INDEX;
184 case PixelFormat::S8Z24: 196 case PixelFormat::S8_UINT_D24_UNORM:
185 return is_first ? GL_STENCIL_INDEX : GL_DEPTH_COMPONENT; 197 return is_first ? GL_STENCIL_INDEX : GL_DEPTH_COMPONENT;
186 default: 198 default:
187 UNREACHABLE(); 199 UNREACHABLE();
@@ -482,9 +494,9 @@ GLuint CachedSurfaceView::GetTexture(SwizzleSource x_source, SwizzleSource y_sou
482 std::array swizzle{x_source, y_source, z_source, w_source}; 494 std::array swizzle{x_source, y_source, z_source, w_source};
483 495
484 switch (const PixelFormat format = GetSurfaceParams().pixel_format) { 496 switch (const PixelFormat format = GetSurfaceParams().pixel_format) {
485 case PixelFormat::Z24S8: 497 case PixelFormat::D24_UNORM_S8_UINT:
486 case PixelFormat::Z32FS8: 498 case PixelFormat::D32_FLOAT_S8_UINT:
487 case PixelFormat::S8Z24: 499 case PixelFormat::S8_UINT_D24_UNORM:
488 UNIMPLEMENTED_IF(x_source != SwizzleSource::R && x_source != SwizzleSource::G); 500 UNIMPLEMENTED_IF(x_source != SwizzleSource::R && x_source != SwizzleSource::G);
489 glTextureParameteri(view.handle, GL_DEPTH_STENCIL_TEXTURE_MODE, 501 glTextureParameteri(view.handle, GL_DEPTH_STENCIL_TEXTURE_MODE,
490 GetComponent(format, x_source == SwizzleSource::R)); 502 GetComponent(format, x_source == SwizzleSource::R));
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index e66cdc083..52e9e8250 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -535,12 +535,12 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
535 535
536 GLint internal_format; 536 GLint internal_format;
537 switch (framebuffer.pixel_format) { 537 switch (framebuffer.pixel_format) {
538 case Tegra::FramebufferConfig::PixelFormat::ABGR8: 538 case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM:
539 internal_format = GL_RGBA8; 539 internal_format = GL_RGBA8;
540 texture.gl_format = GL_RGBA; 540 texture.gl_format = GL_RGBA;
541 texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; 541 texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
542 break; 542 break;
543 case Tegra::FramebufferConfig::PixelFormat::RGB565: 543 case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM:
544 internal_format = GL_RGB565; 544 internal_format = GL_RGB565;
545 texture.gl_format = GL_RGB; 545 texture.gl_format = GL_RGB;
546 texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; 546 texture.gl_type = GL_UNSIGNED_SHORT_5_6_5;
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index d7f1ae89f..f8c77f4fa 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -117,90 +117,101 @@ struct FormatTuple {
117 VkFormat format; ///< Vulkan format 117 VkFormat format; ///< Vulkan format
118 int usage = 0; ///< Describes image format usage 118 int usage = 0; ///< Describes image format usage
119} constexpr tex_format_tuples[] = { 119} constexpr tex_format_tuples[] = {
120 {VK_FORMAT_A8B8G8R8_UNORM_PACK32, Attachable | Storage}, // ABGR8U 120 {VK_FORMAT_A8B8G8R8_UNORM_PACK32, Attachable | Storage}, // A8B8G8R8_UNORM
121 {VK_FORMAT_A8B8G8R8_SNORM_PACK32, Attachable | Storage}, // ABGR8S 121 {VK_FORMAT_A8B8G8R8_SNORM_PACK32, Attachable | Storage}, // A8B8G8R8_SNORM
122 {VK_FORMAT_A8B8G8R8_UINT_PACK32, Attachable | Storage}, // ABGR8UI 122 {VK_FORMAT_A8B8G8R8_SINT_PACK32, Attachable | Storage}, // A8B8G8R8_SINT
123 {VK_FORMAT_B5G6R5_UNORM_PACK16}, // B5G6R5U 123 {VK_FORMAT_A8B8G8R8_UINT_PACK32, Attachable | Storage}, // A8B8G8R8_UINT
124 {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10U 124 {VK_FORMAT_R5G6B5_UNORM_PACK16, Attachable}, // R5G6B5_UNORM
125 {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1B5G5R5U (flipped with swizzle) 125 {VK_FORMAT_B5G6R5_UNORM_PACK16, Attachable}, // B5G6R5_UNORM
126 {VK_FORMAT_R8_UNORM, Attachable | Storage}, // R8U 126 {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1R5G5B5_UNORM
127 {VK_FORMAT_R8_UINT, Attachable | Storage}, // R8UI 127 {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10_UNORM
128 {VK_FORMAT_R16G16B16A16_SFLOAT, Attachable | Storage}, // RGBA16F 128 {VK_FORMAT_A2B10G10R10_UINT_PACK32, Attachable | Storage}, // A2B10G10R10_UINT
129 {VK_FORMAT_R16G16B16A16_UNORM, Attachable | Storage}, // RGBA16U 129 {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1B5G5R5_UNORM (flipped with swizzle)
130 {VK_FORMAT_R16G16B16A16_SNORM, Attachable | Storage}, // RGBA16S 130 {VK_FORMAT_R8_UNORM, Attachable | Storage}, // R8_UNORM
131 {VK_FORMAT_R16G16B16A16_UINT, Attachable | Storage}, // RGBA16UI 131 {VK_FORMAT_R8_SNORM, Attachable | Storage}, // R8_SNORM
132 {VK_FORMAT_B10G11R11_UFLOAT_PACK32, Attachable | Storage}, // R11FG11FB10F 132 {VK_FORMAT_R8_SINT, Attachable | Storage}, // R8_SINT
133 {VK_FORMAT_R32G32B32A32_UINT, Attachable | Storage}, // RGBA32UI 133 {VK_FORMAT_R8_UINT, Attachable | Storage}, // R8_UINT
134 {VK_FORMAT_BC1_RGBA_UNORM_BLOCK}, // DXT1 134 {VK_FORMAT_R16G16B16A16_SFLOAT, Attachable | Storage}, // R16G16B16A16_FLOAT
135 {VK_FORMAT_BC2_UNORM_BLOCK}, // DXT23 135 {VK_FORMAT_R16G16B16A16_UNORM, Attachable | Storage}, // R16G16B16A16_UNORM
136 {VK_FORMAT_BC3_UNORM_BLOCK}, // DXT45 136 {VK_FORMAT_R16G16B16A16_SNORM, Attachable | Storage}, // R16G16B16A16_SNORM
137 {VK_FORMAT_BC4_UNORM_BLOCK}, // DXN1 137 {VK_FORMAT_R16G16B16A16_SINT, Attachable | Storage}, // R16G16B16A16_SINT
138 {VK_FORMAT_BC5_UNORM_BLOCK}, // DXN2UNORM 138 {VK_FORMAT_R16G16B16A16_UINT, Attachable | Storage}, // R16G16B16A16_UINT
139 {VK_FORMAT_BC5_SNORM_BLOCK}, // DXN2SNORM 139 {VK_FORMAT_B10G11R11_UFLOAT_PACK32, Attachable | Storage}, // B10G11R11_FLOAT
140 {VK_FORMAT_BC7_UNORM_BLOCK}, // BC7U 140 {VK_FORMAT_R32G32B32A32_UINT, Attachable | Storage}, // R32G32B32A32_UINT
141 {VK_FORMAT_BC6H_UFLOAT_BLOCK}, // BC6H_UF16 141 {VK_FORMAT_BC1_RGBA_UNORM_BLOCK}, // BC1_RGBA_UNORM
142 {VK_FORMAT_BC6H_SFLOAT_BLOCK}, // BC6H_SF16 142 {VK_FORMAT_BC2_UNORM_BLOCK}, // BC2_UNORM
143 {VK_FORMAT_ASTC_4x4_UNORM_BLOCK}, // ASTC_2D_4X4 143 {VK_FORMAT_BC3_UNORM_BLOCK}, // BC3_UNORM
144 {VK_FORMAT_B8G8R8A8_UNORM, Attachable}, // BGRA8 144 {VK_FORMAT_BC4_UNORM_BLOCK}, // BC4_UNORM
145 {VK_FORMAT_R32G32B32A32_SFLOAT, Attachable | Storage}, // RGBA32F 145 {VK_FORMAT_BC4_SNORM_BLOCK}, // BC4_SNORM
146 {VK_FORMAT_R32G32_SFLOAT, Attachable | Storage}, // RG32F 146 {VK_FORMAT_BC5_UNORM_BLOCK}, // BC5_UNORM
147 {VK_FORMAT_R32_SFLOAT, Attachable | Storage}, // R32F 147 {VK_FORMAT_BC5_SNORM_BLOCK}, // BC5_SNORM
148 {VK_FORMAT_R16_SFLOAT, Attachable | Storage}, // R16F 148 {VK_FORMAT_BC7_UNORM_BLOCK}, // BC7_UNORM
149 {VK_FORMAT_R16_UNORM, Attachable | Storage}, // R16U 149 {VK_FORMAT_BC6H_UFLOAT_BLOCK}, // BC6H_UFLOAT
150 {VK_FORMAT_UNDEFINED}, // R16S 150 {VK_FORMAT_BC6H_SFLOAT_BLOCK}, // BC6H_SFLOAT
151 {VK_FORMAT_R16_UINT, Attachable | Storage}, // R16UI 151 {VK_FORMAT_ASTC_4x4_UNORM_BLOCK}, // ASTC_2D_4X4_UNORM
152 {VK_FORMAT_UNDEFINED}, // R16I 152 {VK_FORMAT_B8G8R8A8_UNORM, Attachable}, // B8G8R8A8_UNORM
153 {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // RG16 153 {VK_FORMAT_R32G32B32A32_SFLOAT, Attachable | Storage}, // R32G32B32A32_FLOAT
154 {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // RG16F 154 {VK_FORMAT_R32G32B32A32_SINT, Attachable | Storage}, // R32G32B32A32_SINT
155 {VK_FORMAT_UNDEFINED}, // RG16UI 155 {VK_FORMAT_R32G32_SFLOAT, Attachable | Storage}, // R32G32_FLOAT
156 {VK_FORMAT_UNDEFINED}, // RG16I 156 {VK_FORMAT_R32G32_SINT, Attachable | Storage}, // R32G32_SINT
157 {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // RG16S 157 {VK_FORMAT_R32_SFLOAT, Attachable | Storage}, // R32_FLOAT
158 {VK_FORMAT_UNDEFINED}, // RGB32F 158 {VK_FORMAT_R16_SFLOAT, Attachable | Storage}, // R16_FLOAT
159 {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // RGBA8_SRGB 159 {VK_FORMAT_R16_UNORM, Attachable | Storage}, // R16_UNORM
160 {VK_FORMAT_R8G8_UNORM, Attachable | Storage}, // RG8U 160 {VK_FORMAT_UNDEFINED}, // R16_SNORM
161 {VK_FORMAT_R8G8_SNORM, Attachable | Storage}, // RG8S 161 {VK_FORMAT_R16_UINT, Attachable | Storage}, // R16_UINT
162 {VK_FORMAT_R8G8_UINT, Attachable | Storage}, // RG8UI 162 {VK_FORMAT_UNDEFINED}, // R16_SINT
163 {VK_FORMAT_R32G32_UINT, Attachable | Storage}, // RG32UI 163 {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // R16G16_UNORM
164 {VK_FORMAT_UNDEFINED}, // RGBX16F 164 {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // R16G16_FLOAT
165 {VK_FORMAT_R32_UINT, Attachable | Storage}, // R32UI 165 {VK_FORMAT_UNDEFINED}, // R16G16_UINT
166 {VK_FORMAT_R32_SINT, Attachable | Storage}, // R32I 166 {VK_FORMAT_UNDEFINED}, // R16G16_SINT
167 {VK_FORMAT_ASTC_8x8_UNORM_BLOCK}, // ASTC_2D_8X8 167 {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM
168 {VK_FORMAT_UNDEFINED}, // ASTC_2D_8X5 168 {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT
169 {VK_FORMAT_UNDEFINED}, // ASTC_2D_5X4 169 {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // A8B8G8R8_SRGB
170 {VK_FORMAT_B8G8R8A8_SRGB, Attachable}, // BGRA8_SRGB 170 {VK_FORMAT_R8G8_UNORM, Attachable | Storage}, // R8G8_UNORM
171 {VK_FORMAT_BC1_RGBA_SRGB_BLOCK}, // DXT1_SRGB 171 {VK_FORMAT_R8G8_SNORM, Attachable | Storage}, // R8G8_SNORM
172 {VK_FORMAT_BC2_SRGB_BLOCK}, // DXT23_SRGB 172 {VK_FORMAT_R8G8_SINT, Attachable | Storage}, // R8G8_SINT
173 {VK_FORMAT_BC3_SRGB_BLOCK}, // DXT45_SRGB 173 {VK_FORMAT_R8G8_UINT, Attachable | Storage}, // R8G8_UINT
174 {VK_FORMAT_BC7_SRGB_BLOCK}, // BC7U_SRGB 174 {VK_FORMAT_R32G32_UINT, Attachable | Storage}, // R32G32_UINT
175 {VK_FORMAT_R4G4B4A4_UNORM_PACK16, Attachable}, // R4G4B4A4U 175 {VK_FORMAT_UNDEFINED}, // R16G16B16X16_FLOAT
176 {VK_FORMAT_ASTC_4x4_SRGB_BLOCK}, // ASTC_2D_4X4_SRGB 176 {VK_FORMAT_R32_UINT, Attachable | Storage}, // R32_UINT
177 {VK_FORMAT_ASTC_8x8_SRGB_BLOCK}, // ASTC_2D_8X8_SRGB 177 {VK_FORMAT_R32_SINT, Attachable | Storage}, // R32_SINT
178 {VK_FORMAT_ASTC_8x5_SRGB_BLOCK}, // ASTC_2D_8X5_SRGB 178 {VK_FORMAT_ASTC_8x8_UNORM_BLOCK}, // ASTC_2D_8X8_UNORM
179 {VK_FORMAT_ASTC_5x4_SRGB_BLOCK}, // ASTC_2D_5X4_SRGB 179 {VK_FORMAT_UNDEFINED}, // ASTC_2D_8X5_UNORM
180 {VK_FORMAT_ASTC_5x5_UNORM_BLOCK}, // ASTC_2D_5X5 180 {VK_FORMAT_UNDEFINED}, // ASTC_2D_5X4_UNORM
181 {VK_FORMAT_ASTC_5x5_SRGB_BLOCK}, // ASTC_2D_5X5_SRGB 181 {VK_FORMAT_B8G8R8A8_SRGB, Attachable}, // B8G8R8A8_SRGB
182 {VK_FORMAT_ASTC_10x8_UNORM_BLOCK}, // ASTC_2D_10X8 182 {VK_FORMAT_BC1_RGBA_SRGB_BLOCK}, // BC1_RGBA_SRGB
183 {VK_FORMAT_ASTC_10x8_SRGB_BLOCK}, // ASTC_2D_10X8_SRGB 183 {VK_FORMAT_BC2_SRGB_BLOCK}, // BC2_SRGB
184 {VK_FORMAT_ASTC_6x6_UNORM_BLOCK}, // ASTC_2D_6X6 184 {VK_FORMAT_BC3_SRGB_BLOCK}, // BC3_SRGB
185 {VK_FORMAT_ASTC_6x6_SRGB_BLOCK}, // ASTC_2D_6X6_SRGB 185 {VK_FORMAT_BC7_SRGB_BLOCK}, // BC7_SRGB
186 {VK_FORMAT_ASTC_10x10_UNORM_BLOCK}, // ASTC_2D_10X10 186 {VK_FORMAT_R4G4B4A4_UNORM_PACK16, Attachable}, // A4B4G4R4_UNORM
187 {VK_FORMAT_ASTC_10x10_SRGB_BLOCK}, // ASTC_2D_10X10_SRGB 187 {VK_FORMAT_ASTC_4x4_SRGB_BLOCK}, // ASTC_2D_4X4_SRGB
188 {VK_FORMAT_ASTC_12x12_UNORM_BLOCK}, // ASTC_2D_12X12 188 {VK_FORMAT_ASTC_8x8_SRGB_BLOCK}, // ASTC_2D_8X8_SRGB
189 {VK_FORMAT_ASTC_12x12_SRGB_BLOCK}, // ASTC_2D_12X12_SRGB 189 {VK_FORMAT_ASTC_8x5_SRGB_BLOCK}, // ASTC_2D_8X5_SRGB
190 {VK_FORMAT_ASTC_8x6_UNORM_BLOCK}, // ASTC_2D_8X6 190 {VK_FORMAT_ASTC_5x4_SRGB_BLOCK}, // ASTC_2D_5X4_SRGB
191 {VK_FORMAT_ASTC_8x6_SRGB_BLOCK}, // ASTC_2D_8X6_SRGB 191 {VK_FORMAT_ASTC_5x5_UNORM_BLOCK}, // ASTC_2D_5X5_UNORM
192 {VK_FORMAT_ASTC_6x5_UNORM_BLOCK}, // ASTC_2D_6X5 192 {VK_FORMAT_ASTC_5x5_SRGB_BLOCK}, // ASTC_2D_5X5_SRGB
193 {VK_FORMAT_ASTC_6x5_SRGB_BLOCK}, // ASTC_2D_6X5_SRGB 193 {VK_FORMAT_ASTC_10x8_UNORM_BLOCK}, // ASTC_2D_10X8_UNORM
194 {VK_FORMAT_E5B9G9R9_UFLOAT_PACK32}, // E5B9G9R9F 194 {VK_FORMAT_ASTC_10x8_SRGB_BLOCK}, // ASTC_2D_10X8_SRGB
195 {VK_FORMAT_ASTC_6x6_UNORM_BLOCK}, // ASTC_2D_6X6_UNORM
196 {VK_FORMAT_ASTC_6x6_SRGB_BLOCK}, // ASTC_2D_6X6_SRGB
197 {VK_FORMAT_ASTC_10x10_UNORM_BLOCK}, // ASTC_2D_10X10_UNORM
198 {VK_FORMAT_ASTC_10x10_SRGB_BLOCK}, // ASTC_2D_10X10_SRGB
199 {VK_FORMAT_ASTC_12x12_UNORM_BLOCK}, // ASTC_2D_12X12_UNORM
200 {VK_FORMAT_ASTC_12x12_SRGB_BLOCK}, // ASTC_2D_12X12_SRGB
201 {VK_FORMAT_ASTC_8x6_UNORM_BLOCK}, // ASTC_2D_8X6_UNORM
202 {VK_FORMAT_ASTC_8x6_SRGB_BLOCK}, // ASTC_2D_8X6_SRGB
203 {VK_FORMAT_ASTC_6x5_UNORM_BLOCK}, // ASTC_2D_6X5_UNORM
204 {VK_FORMAT_ASTC_6x5_SRGB_BLOCK}, // ASTC_2D_6X5_SRGB
205 {VK_FORMAT_E5B9G9R9_UFLOAT_PACK32}, // E5B9G9R9_FLOAT
195 206
196 // Depth formats 207 // Depth formats
197 {VK_FORMAT_D32_SFLOAT, Attachable}, // Z32F 208 {VK_FORMAT_D32_SFLOAT, Attachable}, // D32_FLOAT
198 {VK_FORMAT_D16_UNORM, Attachable}, // Z16 209 {VK_FORMAT_D16_UNORM, Attachable}, // D16_UNORM
199 210
200 // DepthStencil formats 211 // DepthStencil formats
201 {VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // Z24S8 212 {VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // D24_UNORM_S8_UINT
202 {VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // S8Z24 (emulated) 213 {VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // S8_UINT_D24_UNORM (emulated)
203 {VK_FORMAT_D32_SFLOAT_S8_UINT, Attachable}, // Z32FS8 214 {VK_FORMAT_D32_SFLOAT_S8_UINT, Attachable}, // D32_FLOAT_S8_UINT
204}; 215};
205static_assert(std::size(tex_format_tuples) == VideoCore::Surface::MaxPixelFormat); 216static_assert(std::size(tex_format_tuples) == VideoCore::Surface::MaxPixelFormat);
206 217
@@ -221,7 +232,7 @@ FormatInfo SurfaceFormat(const VKDevice& device, FormatType format_type, PixelFo
221 return {VK_FORMAT_A8B8G8R8_UNORM_PACK32, true, true}; 232 return {VK_FORMAT_A8B8G8R8_UNORM_PACK32, true, true};
222 } 233 }
223 234
224 // Use ABGR8 on hardware that doesn't support ASTC natively 235 // Use A8B8G8R8_UNORM on hardware that doesn't support ASTC natively
225 if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) { 236 if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) {
226 tuple.format = VideoCore::Surface::IsPixelFormatSRGB(pixel_format) 237 tuple.format = VideoCore::Surface::IsPixelFormatSRGB(pixel_format)
227 ? VK_FORMAT_A8B8G8R8_SRGB_PACK32 238 ? VK_FORMAT_A8B8G8R8_SRGB_PACK32
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 866813465..ce53e5a6b 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -187,9 +187,9 @@ std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) {
187 187
188VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) { 188VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) {
189 switch (framebuffer.pixel_format) { 189 switch (framebuffer.pixel_format) {
190 case Tegra::FramebufferConfig::PixelFormat::ABGR8: 190 case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM:
191 return VK_FORMAT_A8B8G8R8_UNORM_PACK32; 191 return VK_FORMAT_A8B8G8R8_UNORM_PACK32;
192 case Tegra::FramebufferConfig::PixelFormat::RGB565: 192 case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM:
193 return VK_FORMAT_R5G6B5_UNORM_PACK16; 193 return VK_FORMAT_R5G6B5_UNORM_PACK16;
194 default: 194 default:
195 UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", 195 UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}",
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 2be38d419..1d2f8b557 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -39,16 +39,17 @@ std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const VKDevice& device, VKSch
39 39
40Buffer::Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKScheduler& scheduler_, 40Buffer::Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKScheduler& scheduler_,
41 VKStagingBufferPool& staging_pool_, VAddr cpu_addr, std::size_t size) 41 VKStagingBufferPool& staging_pool_, VAddr cpu_addr, std::size_t size)
42 : VideoCommon::BufferBlock{cpu_addr, size}, scheduler{scheduler_}, staging_pool{staging_pool_} { 42 : BufferBlock{cpu_addr, size}, scheduler{scheduler_}, staging_pool{staging_pool_} {
43 VkBufferCreateInfo ci; 43 const VkBufferCreateInfo ci{
44 ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 44 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
45 ci.pNext = nullptr; 45 .pNext = nullptr,
46 ci.flags = 0; 46 .flags = 0,
47 ci.size = static_cast<VkDeviceSize>(size); 47 .size = static_cast<VkDeviceSize>(size),
48 ci.usage = BUFFER_USAGE | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; 48 .usage = BUFFER_USAGE | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
49 ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 49 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
50 ci.queueFamilyIndexCount = 0; 50 .queueFamilyIndexCount = 0,
51 ci.pQueueFamilyIndices = nullptr; 51 .pQueueFamilyIndices = nullptr,
52 };
52 53
53 buffer.handle = device.GetLogical().CreateBuffer(ci); 54 buffer.handle = device.GetLogical().CreateBuffer(ci);
54 buffer.commit = memory_manager.Commit(buffer.handle, false); 55 buffer.commit = memory_manager.Commit(buffer.handle, false);
@@ -66,16 +67,17 @@ void Buffer::Upload(std::size_t offset, std::size_t size, const u8* data) {
66 scheduler.Record([staging = *staging.handle, handle, offset, size](vk::CommandBuffer cmdbuf) { 67 scheduler.Record([staging = *staging.handle, handle, offset, size](vk::CommandBuffer cmdbuf) {
67 cmdbuf.CopyBuffer(staging, handle, VkBufferCopy{0, offset, size}); 68 cmdbuf.CopyBuffer(staging, handle, VkBufferCopy{0, offset, size});
68 69
69 VkBufferMemoryBarrier barrier; 70 const VkBufferMemoryBarrier barrier{
70 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; 71 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
71 barrier.pNext = nullptr; 72 .pNext = nullptr,
72 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; 73 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
73 barrier.dstAccessMask = UPLOAD_ACCESS_BARRIERS; 74 .dstAccessMask = UPLOAD_ACCESS_BARRIERS,
74 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 75 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
75 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 76 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
76 barrier.buffer = handle; 77 .buffer = handle,
77 barrier.offset = offset; 78 .offset = offset,
78 barrier.size = size; 79 .size = size,
80 };
79 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, {}, 81 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, {},
80 barrier, {}); 82 barrier, {});
81 }); 83 });
@@ -87,16 +89,17 @@ void Buffer::Download(std::size_t offset, std::size_t size, u8* data) {
87 89
88 const VkBuffer handle = Handle(); 90 const VkBuffer handle = Handle();
89 scheduler.Record([staging = *staging.handle, handle, offset, size](vk::CommandBuffer cmdbuf) { 91 scheduler.Record([staging = *staging.handle, handle, offset, size](vk::CommandBuffer cmdbuf) {
90 VkBufferMemoryBarrier barrier; 92 const VkBufferMemoryBarrier barrier{
91 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; 93 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
92 barrier.pNext = nullptr; 94 .pNext = nullptr,
93 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; 95 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
94 barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; 96 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
95 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 97 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
96 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 98 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
97 barrier.buffer = handle; 99 .buffer = handle,
98 barrier.offset = offset; 100 .offset = offset,
99 barrier.size = size; 101 .size = size,
102 };
100 103
101 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | 104 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
102 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | 105 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index da71e710c..182461ed9 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -115,32 +115,32 @@ constexpr u8 quad_array[] = {
115 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; 115 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00};
116 116
117VkDescriptorSetLayoutBinding BuildQuadArrayPassDescriptorSetLayoutBinding() { 117VkDescriptorSetLayoutBinding BuildQuadArrayPassDescriptorSetLayoutBinding() {
118 VkDescriptorSetLayoutBinding binding; 118 return {
119 binding.binding = 0; 119 .binding = 0,
120 binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 120 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
121 binding.descriptorCount = 1; 121 .descriptorCount = 1,
122 binding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; 122 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
123 binding.pImmutableSamplers = nullptr; 123 .pImmutableSamplers = nullptr,
124 return binding; 124 };
125} 125}
126 126
127VkDescriptorUpdateTemplateEntryKHR BuildQuadArrayPassDescriptorUpdateTemplateEntry() { 127VkDescriptorUpdateTemplateEntryKHR BuildQuadArrayPassDescriptorUpdateTemplateEntry() {
128 VkDescriptorUpdateTemplateEntryKHR entry; 128 return {
129 entry.dstBinding = 0; 129 .dstBinding = 0,
130 entry.dstArrayElement = 0; 130 .dstArrayElement = 0,
131 entry.descriptorCount = 1; 131 .descriptorCount = 1,
132 entry.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 132 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
133 entry.offset = 0; 133 .offset = 0,
134 entry.stride = sizeof(DescriptorUpdateEntry); 134 .stride = sizeof(DescriptorUpdateEntry),
135 return entry; 135 };
136} 136}
137 137
138VkPushConstantRange BuildComputePushConstantRange(std::size_t size) { 138VkPushConstantRange BuildComputePushConstantRange(std::size_t size) {
139 VkPushConstantRange range; 139 return {
140 range.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; 140 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
141 range.offset = 0; 141 .offset = 0,
142 range.size = static_cast<u32>(size); 142 .size = static_cast<u32>(size),
143 return range; 143 };
144} 144}
145 145
146// Uint8 SPIR-V module. Generated from the "shaders/" directory. 146// Uint8 SPIR-V module. Generated from the "shaders/" directory.
@@ -344,29 +344,33 @@ constexpr u8 QUAD_INDEXED_SPV[] = {
344 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; 344 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00};
345 345
346std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBindings() { 346std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBindings() {
347 std::array<VkDescriptorSetLayoutBinding, 2> bindings; 347 return {{
348 bindings[0].binding = 0; 348 {
349 bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 349 .binding = 0,
350 bindings[0].descriptorCount = 1; 350 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
351 bindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; 351 .descriptorCount = 1,
352 bindings[0].pImmutableSamplers = nullptr; 352 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
353 bindings[1].binding = 1; 353 .pImmutableSamplers = nullptr,
354 bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 354 },
355 bindings[1].descriptorCount = 1; 355 {
356 bindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; 356 .binding = 1,
357 bindings[1].pImmutableSamplers = nullptr; 357 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
358 return bindings; 358 .descriptorCount = 1,
359 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
360 .pImmutableSamplers = nullptr,
361 },
362 }};
359} 363}
360 364
361VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() { 365VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() {
362 VkDescriptorUpdateTemplateEntryKHR entry; 366 return {
363 entry.dstBinding = 0; 367 .dstBinding = 0,
364 entry.dstArrayElement = 0; 368 .dstArrayElement = 0,
365 entry.descriptorCount = 2; 369 .descriptorCount = 2,
366 entry.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 370 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
367 entry.offset = 0; 371 .offset = 0,
368 entry.stride = sizeof(DescriptorUpdateEntry); 372 .stride = sizeof(DescriptorUpdateEntry),
369 return entry; 373 };
370} 374}
371 375
372} // Anonymous namespace 376} // Anonymous namespace
@@ -376,37 +380,37 @@ VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descripto
376 vk::Span<VkDescriptorUpdateTemplateEntryKHR> templates, 380 vk::Span<VkDescriptorUpdateTemplateEntryKHR> templates,
377 vk::Span<VkPushConstantRange> push_constants, std::size_t code_size, 381 vk::Span<VkPushConstantRange> push_constants, std::size_t code_size,
378 const u8* code) { 382 const u8* code) {
379 VkDescriptorSetLayoutCreateInfo descriptor_layout_ci; 383 descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout({
380 descriptor_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; 384 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
381 descriptor_layout_ci.pNext = nullptr; 385 .pNext = nullptr,
382 descriptor_layout_ci.flags = 0; 386 .flags = 0,
383 descriptor_layout_ci.bindingCount = bindings.size(); 387 .bindingCount = bindings.size(),
384 descriptor_layout_ci.pBindings = bindings.data(); 388 .pBindings = bindings.data(),
385 descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(descriptor_layout_ci); 389 });
386 390
387 VkPipelineLayoutCreateInfo pipeline_layout_ci; 391 layout = device.GetLogical().CreatePipelineLayout({
388 pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 392 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
389 pipeline_layout_ci.pNext = nullptr; 393 .pNext = nullptr,
390 pipeline_layout_ci.flags = 0; 394 .flags = 0,
391 pipeline_layout_ci.setLayoutCount = 1; 395 .setLayoutCount = 1,
392 pipeline_layout_ci.pSetLayouts = descriptor_set_layout.address(); 396 .pSetLayouts = descriptor_set_layout.address(),
393 pipeline_layout_ci.pushConstantRangeCount = push_constants.size(); 397 .pushConstantRangeCount = push_constants.size(),
394 pipeline_layout_ci.pPushConstantRanges = push_constants.data(); 398 .pPushConstantRanges = push_constants.data(),
395 layout = device.GetLogical().CreatePipelineLayout(pipeline_layout_ci); 399 });
396 400
397 if (!templates.empty()) { 401 if (!templates.empty()) {
398 VkDescriptorUpdateTemplateCreateInfoKHR template_ci; 402 descriptor_template = device.GetLogical().CreateDescriptorUpdateTemplateKHR({
399 template_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR; 403 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
400 template_ci.pNext = nullptr; 404 .pNext = nullptr,
401 template_ci.flags = 0; 405 .flags = 0,
402 template_ci.descriptorUpdateEntryCount = templates.size(); 406 .descriptorUpdateEntryCount = templates.size(),
403 template_ci.pDescriptorUpdateEntries = templates.data(); 407 .pDescriptorUpdateEntries = templates.data(),
404 template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR; 408 .templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR,
405 template_ci.descriptorSetLayout = *descriptor_set_layout; 409 .descriptorSetLayout = *descriptor_set_layout,
406 template_ci.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; 410 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
407 template_ci.pipelineLayout = *layout; 411 .pipelineLayout = *layout,
408 template_ci.set = 0; 412 .set = 0,
409 descriptor_template = device.GetLogical().CreateDescriptorUpdateTemplateKHR(template_ci); 413 });
410 414
411 descriptor_allocator.emplace(descriptor_pool, *descriptor_set_layout); 415 descriptor_allocator.emplace(descriptor_pool, *descriptor_set_layout);
412 } 416 }
@@ -414,32 +418,32 @@ VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descripto
414 auto code_copy = std::make_unique<u32[]>(code_size / sizeof(u32) + 1); 418 auto code_copy = std::make_unique<u32[]>(code_size / sizeof(u32) + 1);
415 std::memcpy(code_copy.get(), code, code_size); 419 std::memcpy(code_copy.get(), code, code_size);
416 420
417 VkShaderModuleCreateInfo module_ci; 421 module = device.GetLogical().CreateShaderModule({
418 module_ci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 422 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
419 module_ci.pNext = nullptr; 423 .pNext = nullptr,
420 module_ci.flags = 0; 424 .flags = 0,
421 module_ci.codeSize = code_size; 425 .codeSize = code_size,
422 module_ci.pCode = code_copy.get(); 426 .pCode = code_copy.get(),
423 module = device.GetLogical().CreateShaderModule(module_ci); 427 });
424 428
425 VkComputePipelineCreateInfo pipeline_ci; 429 pipeline = device.GetLogical().CreateComputePipeline({
426 pipeline_ci.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; 430 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
427 pipeline_ci.pNext = nullptr; 431 .pNext = nullptr,
428 pipeline_ci.flags = 0; 432 .flags = 0,
429 pipeline_ci.layout = *layout; 433 .stage =
430 pipeline_ci.basePipelineHandle = nullptr; 434 {
431 pipeline_ci.basePipelineIndex = 0; 435 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
432 436 .pNext = nullptr,
433 VkPipelineShaderStageCreateInfo& stage_ci = pipeline_ci.stage; 437 .flags = 0,
434 stage_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 438 .stage = VK_SHADER_STAGE_COMPUTE_BIT,
435 stage_ci.pNext = nullptr; 439 .module = *module,
436 stage_ci.flags = 0; 440 .pName = "main",
437 stage_ci.stage = VK_SHADER_STAGE_COMPUTE_BIT; 441 .pSpecializationInfo = nullptr,
438 stage_ci.module = *module; 442 },
439 stage_ci.pName = "main"; 443 .layout = *layout,
440 stage_ci.pSpecializationInfo = nullptr; 444 .basePipelineHandle = nullptr,
441 445 .basePipelineIndex = 0,
442 pipeline = device.GetLogical().CreateComputePipeline(pipeline_ci); 446 });
443} 447}
444 448
445VKComputePass::~VKComputePass() = default; 449VKComputePass::~VKComputePass() = default;
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index 281bf9ac3..ed9d2991c 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -43,12 +43,13 @@ vk::DescriptorSetLayout VKComputePipeline::CreateDescriptorSetLayout() const {
43 const auto add_bindings = [&](VkDescriptorType descriptor_type, std::size_t num_entries) { 43 const auto add_bindings = [&](VkDescriptorType descriptor_type, std::size_t num_entries) {
44 // TODO(Rodrigo): Maybe make individual bindings here? 44 // TODO(Rodrigo): Maybe make individual bindings here?
45 for (u32 bindpoint = 0; bindpoint < static_cast<u32>(num_entries); ++bindpoint) { 45 for (u32 bindpoint = 0; bindpoint < static_cast<u32>(num_entries); ++bindpoint) {
46 VkDescriptorSetLayoutBinding& entry = bindings.emplace_back(); 46 bindings.push_back({
47 entry.binding = binding++; 47 .binding = binding++,
48 entry.descriptorType = descriptor_type; 48 .descriptorType = descriptor_type,
49 entry.descriptorCount = 1; 49 .descriptorCount = 1,
50 entry.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; 50 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
51 entry.pImmutableSamplers = nullptr; 51 .pImmutableSamplers = nullptr,
52 });
52 } 53 }
53 }; 54 };
54 add_bindings(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, entries.const_buffers.size()); 55 add_bindings(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, entries.const_buffers.size());
@@ -58,25 +59,25 @@ vk::DescriptorSetLayout VKComputePipeline::CreateDescriptorSetLayout() const {
58 add_bindings(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, entries.storage_texels.size()); 59 add_bindings(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, entries.storage_texels.size());
59 add_bindings(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, entries.images.size()); 60 add_bindings(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, entries.images.size());
60 61
61 VkDescriptorSetLayoutCreateInfo ci; 62 return device.GetLogical().CreateDescriptorSetLayout({
62 ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; 63 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
63 ci.pNext = nullptr; 64 .pNext = nullptr,
64 ci.flags = 0; 65 .flags = 0,
65 ci.bindingCount = static_cast<u32>(bindings.size()); 66 .bindingCount = static_cast<u32>(bindings.size()),
66 ci.pBindings = bindings.data(); 67 .pBindings = bindings.data(),
67 return device.GetLogical().CreateDescriptorSetLayout(ci); 68 });
68} 69}
69 70
70vk::PipelineLayout VKComputePipeline::CreatePipelineLayout() const { 71vk::PipelineLayout VKComputePipeline::CreatePipelineLayout() const {
71 VkPipelineLayoutCreateInfo ci; 72 return device.GetLogical().CreatePipelineLayout({
72 ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 73 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
73 ci.pNext = nullptr; 74 .pNext = nullptr,
74 ci.flags = 0; 75 .flags = 0,
75 ci.setLayoutCount = 1; 76 .setLayoutCount = 1,
76 ci.pSetLayouts = descriptor_set_layout.address(); 77 .pSetLayouts = descriptor_set_layout.address(),
77 ci.pushConstantRangeCount = 0; 78 .pushConstantRangeCount = 0,
78 ci.pPushConstantRanges = nullptr; 79 .pPushConstantRanges = nullptr,
79 return device.GetLogical().CreatePipelineLayout(ci); 80 });
80} 81}
81 82
82vk::DescriptorUpdateTemplateKHR VKComputePipeline::CreateDescriptorUpdateTemplate() const { 83vk::DescriptorUpdateTemplateKHR VKComputePipeline::CreateDescriptorUpdateTemplate() const {
@@ -89,59 +90,63 @@ vk::DescriptorUpdateTemplateKHR VKComputePipeline::CreateDescriptorUpdateTemplat
89 return {}; 90 return {};
90 } 91 }
91 92
92 VkDescriptorUpdateTemplateCreateInfoKHR ci; 93 return device.GetLogical().CreateDescriptorUpdateTemplateKHR({
93 ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR; 94 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
94 ci.pNext = nullptr; 95 .pNext = nullptr,
95 ci.flags = 0; 96 .flags = 0,
96 ci.descriptorUpdateEntryCount = static_cast<u32>(template_entries.size()); 97 .descriptorUpdateEntryCount = static_cast<u32>(template_entries.size()),
97 ci.pDescriptorUpdateEntries = template_entries.data(); 98 .pDescriptorUpdateEntries = template_entries.data(),
98 ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR; 99 .templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR,
99 ci.descriptorSetLayout = *descriptor_set_layout; 100 .descriptorSetLayout = *descriptor_set_layout,
100 ci.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; 101 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
101 ci.pipelineLayout = *layout; 102 .pipelineLayout = *layout,
102 ci.set = DESCRIPTOR_SET; 103 .set = DESCRIPTOR_SET,
103 return device.GetLogical().CreateDescriptorUpdateTemplateKHR(ci); 104 });
104} 105}
105 106
106vk::ShaderModule VKComputePipeline::CreateShaderModule(const std::vector<u32>& code) const { 107vk::ShaderModule VKComputePipeline::CreateShaderModule(const std::vector<u32>& code) const {
107 device.SaveShader(code); 108 device.SaveShader(code);
108 109
109 VkShaderModuleCreateInfo ci; 110 return device.GetLogical().CreateShaderModule({
110 ci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 111 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
111 ci.pNext = nullptr; 112 .pNext = nullptr,
112 ci.flags = 0; 113 .flags = 0,
113 ci.codeSize = code.size() * sizeof(u32); 114 .codeSize = code.size() * sizeof(u32),
114 ci.pCode = code.data(); 115 .pCode = code.data(),
115 return device.GetLogical().CreateShaderModule(ci); 116 });
116} 117}
117 118
118vk::Pipeline VKComputePipeline::CreatePipeline() const { 119vk::Pipeline VKComputePipeline::CreatePipeline() const {
119 VkComputePipelineCreateInfo ci; 120
120 VkPipelineShaderStageCreateInfo& stage_ci = ci.stage; 121 VkComputePipelineCreateInfo ci{
121 stage_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 122 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
122 stage_ci.pNext = nullptr; 123 .pNext = nullptr,
123 stage_ci.flags = 0; 124 .flags = 0,
124 stage_ci.stage = VK_SHADER_STAGE_COMPUTE_BIT; 125 .stage =
125 stage_ci.module = *shader_module; 126 {
126 stage_ci.pName = "main"; 127 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
127 stage_ci.pSpecializationInfo = nullptr; 128 .pNext = nullptr,
128 129 .flags = 0,
129 VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_ci; 130 .stage = VK_SHADER_STAGE_COMPUTE_BIT,
130 subgroup_size_ci.sType = 131 .module = *shader_module,
131 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT; 132 .pName = "main",
132 subgroup_size_ci.pNext = nullptr; 133 .pSpecializationInfo = nullptr,
133 subgroup_size_ci.requiredSubgroupSize = GuestWarpSize; 134 },
135 .layout = *layout,
136 .basePipelineHandle = nullptr,
137 .basePipelineIndex = 0,
138 };
139
140 const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_ci{
141 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT,
142 .pNext = nullptr,
143 .requiredSubgroupSize = GuestWarpSize,
144 };
134 145
135 if (entries.uses_warps && device.IsGuestWarpSizeSupported(VK_SHADER_STAGE_COMPUTE_BIT)) { 146 if (entries.uses_warps && device.IsGuestWarpSizeSupported(VK_SHADER_STAGE_COMPUTE_BIT)) {
136 stage_ci.pNext = &subgroup_size_ci; 147 ci.stage.pNext = &subgroup_size_ci;
137 } 148 }
138 149
139 ci.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
140 ci.pNext = nullptr;
141 ci.flags = 0;
142 ci.layout = *layout;
143 ci.basePipelineHandle = nullptr;
144 ci.basePipelineIndex = 0;
145 return device.GetLogical().CreateComputePipeline(ci); 150 return device.GetLogical().CreateComputePipeline(ci);
146} 151}
147 152
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
index 9259b618d..ac4a0884e 100644
--- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
@@ -43,27 +43,30 @@ vk::DescriptorPool* VKDescriptorPool::AllocateNewPool() {
43 {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, num_sets * 64}, 43 {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, num_sets * 64},
44 {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, num_sets * 64}, 44 {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, num_sets * 64},
45 {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, num_sets * 64}, 45 {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, num_sets * 64},
46 {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, num_sets * 40}}; 46 {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, num_sets * 40},
47 47 };
48 VkDescriptorPoolCreateInfo ci; 48
49 ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; 49 const VkDescriptorPoolCreateInfo ci{
50 ci.pNext = nullptr; 50 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
51 ci.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; 51 .pNext = nullptr,
52 ci.maxSets = num_sets; 52 .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
53 ci.poolSizeCount = static_cast<u32>(std::size(pool_sizes)); 53 .maxSets = num_sets,
54 ci.pPoolSizes = std::data(pool_sizes); 54 .poolSizeCount = static_cast<u32>(std::size(pool_sizes)),
55 .pPoolSizes = std::data(pool_sizes),
56 };
55 return &pools.emplace_back(device.GetLogical().CreateDescriptorPool(ci)); 57 return &pools.emplace_back(device.GetLogical().CreateDescriptorPool(ci));
56} 58}
57 59
58vk::DescriptorSets VKDescriptorPool::AllocateDescriptors(VkDescriptorSetLayout layout, 60vk::DescriptorSets VKDescriptorPool::AllocateDescriptors(VkDescriptorSetLayout layout,
59 std::size_t count) { 61 std::size_t count) {
60 const std::vector layout_copies(count, layout); 62 const std::vector layout_copies(count, layout);
61 VkDescriptorSetAllocateInfo ai; 63 VkDescriptorSetAllocateInfo ai{
62 ai.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; 64 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
63 ai.pNext = nullptr; 65 .pNext = nullptr,
64 ai.descriptorPool = **active_pool; 66 .descriptorPool = **active_pool,
65 ai.descriptorSetCount = static_cast<u32>(count); 67 .descriptorSetCount = static_cast<u32>(count),
66 ai.pSetLayouts = layout_copies.data(); 68 .pSetLayouts = layout_copies.data(),
69 };
67 70
68 vk::DescriptorSets sets = active_pool->Allocate(ai); 71 vk::DescriptorSets sets = active_pool->Allocate(ai);
69 if (!sets.IsOutOfPoolMemory()) { 72 if (!sets.IsOutOfPoolMemory()) {
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp
index 9226e591c..6245e0d78 100644
--- a/src/video_core/renderer_vulkan/vk_device.cpp
+++ b/src/video_core/renderer_vulkan/vk_device.cpp
@@ -84,14 +84,19 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
84 VK_FORMAT_A8B8G8R8_UNORM_PACK32, 84 VK_FORMAT_A8B8G8R8_UNORM_PACK32,
85 VK_FORMAT_A8B8G8R8_UINT_PACK32, 85 VK_FORMAT_A8B8G8R8_UINT_PACK32,
86 VK_FORMAT_A8B8G8R8_SNORM_PACK32, 86 VK_FORMAT_A8B8G8R8_SNORM_PACK32,
87 VK_FORMAT_A8B8G8R8_SINT_PACK32,
87 VK_FORMAT_A8B8G8R8_SRGB_PACK32, 88 VK_FORMAT_A8B8G8R8_SRGB_PACK32,
88 VK_FORMAT_B5G6R5_UNORM_PACK16, 89 VK_FORMAT_B5G6R5_UNORM_PACK16,
89 VK_FORMAT_A2B10G10R10_UNORM_PACK32, 90 VK_FORMAT_A2B10G10R10_UNORM_PACK32,
91 VK_FORMAT_A2B10G10R10_UINT_PACK32,
90 VK_FORMAT_A1R5G5B5_UNORM_PACK16, 92 VK_FORMAT_A1R5G5B5_UNORM_PACK16,
91 VK_FORMAT_R32G32B32A32_SFLOAT, 93 VK_FORMAT_R32G32B32A32_SFLOAT,
94 VK_FORMAT_R32G32B32A32_SINT,
92 VK_FORMAT_R32G32B32A32_UINT, 95 VK_FORMAT_R32G32B32A32_UINT,
93 VK_FORMAT_R32G32_SFLOAT, 96 VK_FORMAT_R32G32_SFLOAT,
97 VK_FORMAT_R32G32_SINT,
94 VK_FORMAT_R32G32_UINT, 98 VK_FORMAT_R32G32_UINT,
99 VK_FORMAT_R16G16B16A16_SINT,
95 VK_FORMAT_R16G16B16A16_UINT, 100 VK_FORMAT_R16G16B16A16_UINT,
96 VK_FORMAT_R16G16B16A16_SNORM, 101 VK_FORMAT_R16G16B16A16_SNORM,
97 VK_FORMAT_R16G16B16A16_UNORM, 102 VK_FORMAT_R16G16B16A16_UNORM,
@@ -103,8 +108,11 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
103 VK_FORMAT_R8G8B8A8_SRGB, 108 VK_FORMAT_R8G8B8A8_SRGB,
104 VK_FORMAT_R8G8_UNORM, 109 VK_FORMAT_R8G8_UNORM,
105 VK_FORMAT_R8G8_SNORM, 110 VK_FORMAT_R8G8_SNORM,
111 VK_FORMAT_R8G8_SINT,
106 VK_FORMAT_R8G8_UINT, 112 VK_FORMAT_R8G8_UINT,
107 VK_FORMAT_R8_UNORM, 113 VK_FORMAT_R8_UNORM,
114 VK_FORMAT_R8_SNORM,
115 VK_FORMAT_R8_SINT,
108 VK_FORMAT_R8_UINT, 116 VK_FORMAT_R8_UINT,
109 VK_FORMAT_B10G11R11_UFLOAT_PACK32, 117 VK_FORMAT_B10G11R11_UFLOAT_PACK32,
110 VK_FORMAT_R32_SFLOAT, 118 VK_FORMAT_R32_SFLOAT,
@@ -124,6 +132,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
124 VK_FORMAT_BC2_UNORM_BLOCK, 132 VK_FORMAT_BC2_UNORM_BLOCK,
125 VK_FORMAT_BC3_UNORM_BLOCK, 133 VK_FORMAT_BC3_UNORM_BLOCK,
126 VK_FORMAT_BC4_UNORM_BLOCK, 134 VK_FORMAT_BC4_UNORM_BLOCK,
135 VK_FORMAT_BC4_SNORM_BLOCK,
127 VK_FORMAT_BC5_UNORM_BLOCK, 136 VK_FORMAT_BC5_UNORM_BLOCK,
128 VK_FORMAT_BC5_SNORM_BLOCK, 137 VK_FORMAT_BC5_SNORM_BLOCK,
129 VK_FORMAT_BC7_UNORM_BLOCK, 138 VK_FORMAT_BC7_UNORM_BLOCK,
@@ -757,14 +766,14 @@ std::vector<VkDeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const
757 queue_cis.reserve(unique_queue_families.size()); 766 queue_cis.reserve(unique_queue_families.size());
758 767
759 for (const u32 queue_family : unique_queue_families) { 768 for (const u32 queue_family : unique_queue_families) {
760 queue_cis.push_back({ 769 auto& ci = queue_cis.emplace_back(VkDeviceQueueCreateInfo{
761 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 770 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
762 .pNext = nullptr, 771 .pNext = nullptr,
763 .flags = 0, 772 .flags = 0,
764 .queueFamilyIndex = queue_family, 773 .queueFamilyIndex = queue_family,
765 .queueCount = 1,
766 .pQueuePriorities = &QUEUE_PRIORITY,
767 }); 774 });
775 ci.queueCount = 1;
776 ci.pQueuePriorities = &QUEUE_PRIORITY;
768 } 777 }
769 778
770 return queue_cis; 779 return queue_cis;
diff --git a/src/video_core/renderer_vulkan/vk_image.cpp b/src/video_core/renderer_vulkan/vk_image.cpp
index 9bceb3861..1c418ea17 100644
--- a/src/video_core/renderer_vulkan/vk_image.cpp
+++ b/src/video_core/renderer_vulkan/vk_image.cpp
@@ -102,21 +102,29 @@ bool VKImage::HasChanged(u32 base_layer, u32 num_layers, u32 base_level, u32 num
102 102
103void VKImage::CreatePresentView() { 103void VKImage::CreatePresentView() {
104 // Image type has to be 2D to be presented. 104 // Image type has to be 2D to be presented.
105 VkImageViewCreateInfo image_view_ci; 105 present_view = device.GetLogical().CreateImageView({
106 image_view_ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 106 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
107 image_view_ci.pNext = nullptr; 107 .pNext = nullptr,
108 image_view_ci.flags = 0; 108 .flags = 0,
109 image_view_ci.image = *image; 109 .image = *image,
110 image_view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D; 110 .viewType = VK_IMAGE_VIEW_TYPE_2D,
111 image_view_ci.format = format; 111 .format = format,
112 image_view_ci.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, 112 .components =
113 VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; 113 {
114 image_view_ci.subresourceRange.aspectMask = aspect_mask; 114 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
115 image_view_ci.subresourceRange.baseMipLevel = 0; 115 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
116 image_view_ci.subresourceRange.levelCount = 1; 116 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
117 image_view_ci.subresourceRange.baseArrayLayer = 0; 117 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
118 image_view_ci.subresourceRange.layerCount = 1; 118 },
119 present_view = device.GetLogical().CreateImageView(image_view_ci); 119 .subresourceRange =
120 {
121 .aspectMask = aspect_mask,
122 .baseMipLevel = 0,
123 .levelCount = 1,
124 .baseArrayLayer = 0,
125 .layerCount = 1,
126 },
127 });
120} 128}
121 129
122VKImage::SubrangeState& VKImage::GetSubrangeState(u32 layer, u32 level) noexcept { 130VKImage::SubrangeState& VKImage::GetSubrangeState(u32 layer, u32 level) noexcept {
diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.cpp b/src/video_core/renderer_vulkan/vk_memory_manager.cpp
index b4c650a63..24c8960ac 100644
--- a/src/video_core/renderer_vulkan/vk_memory_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_memory_manager.cpp
@@ -178,13 +178,12 @@ bool VKMemoryManager::AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 t
178 }(); 178 }();
179 179
180 // Try to allocate found type. 180 // Try to allocate found type.
181 VkMemoryAllocateInfo memory_ai; 181 vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({
182 memory_ai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 182 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
183 memory_ai.pNext = nullptr; 183 .pNext = nullptr,
184 memory_ai.allocationSize = size; 184 .allocationSize = size,
185 memory_ai.memoryTypeIndex = type; 185 .memoryTypeIndex = type,
186 186 });
187 vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory(memory_ai);
188 if (!memory) { 187 if (!memory) {
189 LOG_CRITICAL(Render_Vulkan, "Device allocation failed!"); 188 LOG_CRITICAL(Render_Vulkan, "Device allocation failed!");
190 return false; 189 return false;
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 3da835324..42b3a744c 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -88,12 +88,13 @@ void AddBindings(std::vector<VkDescriptorSetLayoutBinding>& bindings, u32& bindi
88 // Combined image samplers can be arrayed. 88 // Combined image samplers can be arrayed.
89 count = container[i].size; 89 count = container[i].size;
90 } 90 }
91 VkDescriptorSetLayoutBinding& entry = bindings.emplace_back(); 91 bindings.push_back({
92 entry.binding = binding++; 92 .binding = binding++,
93 entry.descriptorType = descriptor_type; 93 .descriptorType = descriptor_type,
94 entry.descriptorCount = count; 94 .descriptorCount = count,
95 entry.stageFlags = stage_flags; 95 .stageFlags = stage_flags,
96 entry.pImmutableSamplers = nullptr; 96 .pImmutableSamplers = nullptr,
97 });
97 } 98 }
98} 99}
99 100
@@ -259,10 +260,10 @@ VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCach
259 } 260 }
260 } 261 }
261 262
262 Specialization specialization; 263 const Specialization specialization{
263 specialization.workgroup_size = key.workgroup_size; 264 .workgroup_size = key.workgroup_size,
264 specialization.shared_memory_size = key.shared_memory_size; 265 .shared_memory_size = key.shared_memory_size,
265 266 };
266 const SPIRVShader spirv_shader{Decompile(device, shader->GetIR(), ShaderType::Compute, 267 const SPIRVShader spirv_shader{Decompile(device, shader->GetIR(), ShaderType::Compute,
267 shader->GetRegistry(), specialization), 268 shader->GetRegistry(), specialization),
268 shader->GetEntries()}; 269 shader->GetEntries()};
@@ -370,13 +371,14 @@ void AddEntry(std::vector<VkDescriptorUpdateTemplateEntry>& template_entries, u3
370 if constexpr (descriptor_type == COMBINED_IMAGE_SAMPLER) { 371 if constexpr (descriptor_type == COMBINED_IMAGE_SAMPLER) {
371 for (u32 i = 0; i < count; ++i) { 372 for (u32 i = 0; i < count; ++i) {
372 const u32 num_samplers = container[i].size; 373 const u32 num_samplers = container[i].size;
373 VkDescriptorUpdateTemplateEntry& entry = template_entries.emplace_back(); 374 template_entries.push_back({
374 entry.dstBinding = binding; 375 .dstBinding = binding,
375 entry.dstArrayElement = 0; 376 .dstArrayElement = 0,
376 entry.descriptorCount = num_samplers; 377 .descriptorCount = num_samplers,
377 entry.descriptorType = descriptor_type; 378 .descriptorType = descriptor_type,
378 entry.offset = offset; 379 .offset = offset,
379 entry.stride = entry_size; 380 .stride = entry_size,
381 });
380 382
381 ++binding; 383 ++binding;
382 offset += num_samplers * entry_size; 384 offset += num_samplers * entry_size;
@@ -389,22 +391,24 @@ void AddEntry(std::vector<VkDescriptorUpdateTemplateEntry>& template_entries, u3
389 // Nvidia has a bug where updating multiple texels at once causes the driver to crash. 391 // Nvidia has a bug where updating multiple texels at once causes the driver to crash.
390 // Note: Fixed in driver Windows 443.24, Linux 440.66.15 392 // Note: Fixed in driver Windows 443.24, Linux 440.66.15
391 for (u32 i = 0; i < count; ++i) { 393 for (u32 i = 0; i < count; ++i) {
392 VkDescriptorUpdateTemplateEntry& entry = template_entries.emplace_back(); 394 template_entries.push_back({
393 entry.dstBinding = binding + i; 395 .dstBinding = binding + i,
394 entry.dstArrayElement = 0; 396 .dstArrayElement = 0,
395 entry.descriptorCount = 1; 397 .descriptorCount = 1,
396 entry.descriptorType = descriptor_type; 398 .descriptorType = descriptor_type,
397 entry.offset = static_cast<std::size_t>(offset + i * entry_size); 399 .offset = static_cast<std::size_t>(offset + i * entry_size),
398 entry.stride = entry_size; 400 .stride = entry_size,
401 });
399 } 402 }
400 } else if (count > 0) { 403 } else if (count > 0) {
401 VkDescriptorUpdateTemplateEntry& entry = template_entries.emplace_back(); 404 template_entries.push_back({
402 entry.dstBinding = binding; 405 .dstBinding = binding,
403 entry.dstArrayElement = 0; 406 .dstArrayElement = 0,
404 entry.descriptorCount = count; 407 .descriptorCount = count,
405 entry.descriptorType = descriptor_type; 408 .descriptorType = descriptor_type,
406 entry.offset = offset; 409 .offset = offset,
407 entry.stride = entry_size; 410 .stride = entry_size,
411 });
408 } 412 }
409 offset += count * entry_size; 413 offset += count * entry_size;
410 binding += count; 414 binding += count;
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index bc91c48cc..6cd63d090 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -47,14 +47,14 @@ std::pair<VkQueryPool, u32> QueryPool::Commit(VKFence& fence) {
47void QueryPool::Allocate(std::size_t begin, std::size_t end) { 47void QueryPool::Allocate(std::size_t begin, std::size_t end) {
48 usage.resize(end); 48 usage.resize(end);
49 49
50 VkQueryPoolCreateInfo query_pool_ci; 50 pools.push_back(device->GetLogical().CreateQueryPool({
51 query_pool_ci.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; 51 .sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
52 query_pool_ci.pNext = nullptr; 52 .pNext = nullptr,
53 query_pool_ci.flags = 0; 53 .flags = 0,
54 query_pool_ci.queryType = GetTarget(type); 54 .queryType = GetTarget(type),
55 query_pool_ci.queryCount = static_cast<u32>(end - begin); 55 .queryCount = static_cast<u32>(end - begin),
56 query_pool_ci.pipelineStatistics = 0; 56 .pipelineStatistics = 0,
57 pools.push_back(device->GetLogical().CreateQueryPool(query_pool_ci)); 57 }));
58} 58}
59 59
60void QueryPool::Reserve(std::pair<VkQueryPool, u32> query) { 60void QueryPool::Reserve(std::pair<VkQueryPool, u32> query) {
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 7625871c2..31e44aa2b 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -64,20 +64,22 @@ VkViewport GetViewportState(const VKDevice& device, const Maxwell& regs, std::si
64 const auto& src = regs.viewport_transform[index]; 64 const auto& src = regs.viewport_transform[index];
65 const float width = src.scale_x * 2.0f; 65 const float width = src.scale_x * 2.0f;
66 const float height = src.scale_y * 2.0f; 66 const float height = src.scale_y * 2.0f;
67 const float reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1.0f : 0.0f;
67 68
68 VkViewport viewport; 69 VkViewport viewport{
69 viewport.x = src.translate_x - src.scale_x; 70 .x = src.translate_x - src.scale_x,
70 viewport.y = src.translate_y - src.scale_y; 71 .y = src.translate_y - src.scale_y,
71 viewport.width = width != 0.0f ? width : 1.0f; 72 .width = width != 0.0f ? width : 1.0f,
72 viewport.height = height != 0.0f ? height : 1.0f; 73 .height = height != 0.0f ? height : 1.0f,
74 .minDepth = src.translate_z - src.scale_z * reduce_z,
75 .maxDepth = src.translate_z + src.scale_z,
76 };
73 77
74 const float reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1.0f : 0.0f;
75 viewport.minDepth = src.translate_z - src.scale_z * reduce_z;
76 viewport.maxDepth = src.translate_z + src.scale_z;
77 if (!device.IsExtDepthRangeUnrestrictedSupported()) { 78 if (!device.IsExtDepthRangeUnrestrictedSupported()) {
78 viewport.minDepth = std::clamp(viewport.minDepth, 0.0f, 1.0f); 79 viewport.minDepth = std::clamp(viewport.minDepth, 0.0f, 1.0f);
79 viewport.maxDepth = std::clamp(viewport.maxDepth, 0.0f, 1.0f); 80 viewport.maxDepth = std::clamp(viewport.maxDepth, 0.0f, 1.0f);
80 } 81 }
82
81 return viewport; 83 return viewport;
82} 84}
83 85
@@ -508,10 +510,11 @@ void RasterizerVulkan::Clear() {
508 510
509 const u32 color_attachment = regs.clear_buffers.RT; 511 const u32 color_attachment = regs.clear_buffers.RT;
510 scheduler.Record([color_attachment, clear_value, clear_rect](vk::CommandBuffer cmdbuf) { 512 scheduler.Record([color_attachment, clear_value, clear_rect](vk::CommandBuffer cmdbuf) {
511 VkClearAttachment attachment; 513 const VkClearAttachment attachment{
512 attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 514 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
513 attachment.colorAttachment = color_attachment; 515 .colorAttachment = color_attachment,
514 attachment.clearValue = clear_value; 516 .clearValue = clear_value,
517 };
515 cmdbuf.ClearAttachments(attachment, clear_rect); 518 cmdbuf.ClearAttachments(attachment, clear_rect);
516 }); 519 });
517 } 520 }
@@ -551,13 +554,16 @@ void RasterizerVulkan::DispatchCompute(GPUVAddr code_addr) {
551 query_cache.UpdateCounters(); 554 query_cache.UpdateCounters();
552 555
553 const auto& launch_desc = system.GPU().KeplerCompute().launch_description; 556 const auto& launch_desc = system.GPU().KeplerCompute().launch_description;
554 ComputePipelineCacheKey key; 557 auto& pipeline = pipeline_cache.GetComputePipeline({
555 key.shader = code_addr; 558 .shader = code_addr,
556 key.shared_memory_size = launch_desc.shared_alloc; 559 .shared_memory_size = launch_desc.shared_alloc,
557 key.workgroup_size = {launch_desc.block_dim_x, launch_desc.block_dim_y, 560 .workgroup_size =
558 launch_desc.block_dim_z}; 561 {
559 562 launch_desc.block_dim_x,
560 auto& pipeline = pipeline_cache.GetComputePipeline(key); 563 launch_desc.block_dim_y,
564 launch_desc.block_dim_z,
565 },
566 });
561 567
562 // Compute dispatches can't be executed inside a renderpass 568 // Compute dispatches can't be executed inside a renderpass
563 scheduler.RequestOutsideRenderPassOperationContext(); 569 scheduler.RequestOutsideRenderPassOperationContext();
@@ -841,17 +847,17 @@ std::tuple<VkFramebuffer, VkExtent2D> RasterizerVulkan::ConfigureFramebuffers(
841 const auto [fbentry, is_cache_miss] = framebuffer_cache.try_emplace(key); 847 const auto [fbentry, is_cache_miss] = framebuffer_cache.try_emplace(key);
842 auto& framebuffer = fbentry->second; 848 auto& framebuffer = fbentry->second;
843 if (is_cache_miss) { 849 if (is_cache_miss) {
844 VkFramebufferCreateInfo framebuffer_ci; 850 framebuffer = device.GetLogical().CreateFramebuffer({
845 framebuffer_ci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; 851 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
846 framebuffer_ci.pNext = nullptr; 852 .pNext = nullptr,
847 framebuffer_ci.flags = 0; 853 .flags = 0,
848 framebuffer_ci.renderPass = key.renderpass; 854 .renderPass = key.renderpass,
849 framebuffer_ci.attachmentCount = static_cast<u32>(key.views.size()); 855 .attachmentCount = static_cast<u32>(key.views.size()),
850 framebuffer_ci.pAttachments = key.views.data(); 856 .pAttachments = key.views.data(),
851 framebuffer_ci.width = key.width; 857 .width = key.width,
852 framebuffer_ci.height = key.height; 858 .height = key.height,
853 framebuffer_ci.layers = key.layers; 859 .layers = key.layers,
854 framebuffer = device.GetLogical().CreateFramebuffer(framebuffer_ci); 860 });
855 } 861 }
856 862
857 return {*framebuffer, VkExtent2D{key.width, key.height}}; 863 return {*framebuffer, VkExtent2D{key.width, key.height}};
@@ -1553,17 +1559,17 @@ VkBuffer RasterizerVulkan::DefaultBuffer() {
1553 return *default_buffer; 1559 return *default_buffer;
1554 } 1560 }
1555 1561
1556 VkBufferCreateInfo ci; 1562 default_buffer = device.GetLogical().CreateBuffer({
1557 ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 1563 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1558 ci.pNext = nullptr; 1564 .pNext = nullptr,
1559 ci.flags = 0; 1565 .flags = 0,
1560 ci.size = DEFAULT_BUFFER_SIZE; 1566 .size = DEFAULT_BUFFER_SIZE,
1561 ci.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | 1567 .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
1562 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; 1568 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
1563 ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 1569 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
1564 ci.queueFamilyIndexCount = 0; 1570 .queueFamilyIndexCount = 0,
1565 ci.pQueueFamilyIndices = nullptr; 1571 .pQueueFamilyIndices = nullptr,
1566 default_buffer = device.GetLogical().CreateBuffer(ci); 1572 });
1567 default_buffer_commit = memory_manager.Commit(default_buffer, false); 1573 default_buffer_commit = memory_manager.Commit(default_buffer, false);
1568 1574
1569 scheduler.RequestOutsideRenderPassOperationContext(); 1575 scheduler.RequestOutsideRenderPassOperationContext();
diff --git a/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp b/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp
index 3f71d005e..80284cf92 100644
--- a/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp
@@ -39,10 +39,14 @@ VkRenderPass VKRenderPassCache::GetRenderPass(const RenderPassParams& params) {
39 39
40vk::RenderPass VKRenderPassCache::CreateRenderPass(const RenderPassParams& params) const { 40vk::RenderPass VKRenderPassCache::CreateRenderPass(const RenderPassParams& params) const {
41 using namespace VideoCore::Surface; 41 using namespace VideoCore::Surface;
42 const std::size_t num_attachments = static_cast<std::size_t>(params.num_color_attachments);
43
42 std::vector<VkAttachmentDescription> descriptors; 44 std::vector<VkAttachmentDescription> descriptors;
45 descriptors.reserve(num_attachments);
46
43 std::vector<VkAttachmentReference> color_references; 47 std::vector<VkAttachmentReference> color_references;
48 color_references.reserve(num_attachments);
44 49
45 const std::size_t num_attachments = static_cast<std::size_t>(params.num_color_attachments);
46 for (std::size_t rt = 0; rt < num_attachments; ++rt) { 50 for (std::size_t rt = 0; rt < num_attachments; ++rt) {
47 const auto guest_format = static_cast<Tegra::RenderTargetFormat>(params.color_formats[rt]); 51 const auto guest_format = static_cast<Tegra::RenderTargetFormat>(params.color_formats[rt]);
48 const PixelFormat pixel_format = PixelFormatFromRenderTargetFormat(guest_format); 52 const PixelFormat pixel_format = PixelFormatFromRenderTargetFormat(guest_format);
@@ -54,20 +58,22 @@ vk::RenderPass VKRenderPassCache::CreateRenderPass(const RenderPassParams& param
54 const VkImageLayout color_layout = ((params.texceptions >> rt) & 1) != 0 58 const VkImageLayout color_layout = ((params.texceptions >> rt) & 1) != 0
55 ? VK_IMAGE_LAYOUT_GENERAL 59 ? VK_IMAGE_LAYOUT_GENERAL
56 : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 60 : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
57 VkAttachmentDescription& descriptor = descriptors.emplace_back(); 61 descriptors.push_back({
58 descriptor.flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT; 62 .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT,
59 descriptor.format = format.format; 63 .format = format.format,
60 descriptor.samples = VK_SAMPLE_COUNT_1_BIT; 64 .samples = VK_SAMPLE_COUNT_1_BIT,
61 descriptor.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; 65 .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
62 descriptor.storeOp = VK_ATTACHMENT_STORE_OP_STORE; 66 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
63 descriptor.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 67 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
64 descriptor.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 68 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
65 descriptor.initialLayout = color_layout; 69 .initialLayout = color_layout,
66 descriptor.finalLayout = color_layout; 70 .finalLayout = color_layout,
67 71 });
68 VkAttachmentReference& reference = color_references.emplace_back(); 72
69 reference.attachment = static_cast<u32>(rt); 73 color_references.push_back({
70 reference.layout = color_layout; 74 .attachment = static_cast<u32>(rt),
75 .layout = color_layout,
76 });
71 } 77 }
72 78
73 VkAttachmentReference zeta_attachment_ref; 79 VkAttachmentReference zeta_attachment_ref;
@@ -82,32 +88,36 @@ vk::RenderPass VKRenderPassCache::CreateRenderPass(const RenderPassParams& param
82 const VkImageLayout zeta_layout = params.zeta_texception != 0 88 const VkImageLayout zeta_layout = params.zeta_texception != 0
83 ? VK_IMAGE_LAYOUT_GENERAL 89 ? VK_IMAGE_LAYOUT_GENERAL
84 : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 90 : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
85 VkAttachmentDescription& descriptor = descriptors.emplace_back(); 91 descriptors.push_back({
86 descriptor.flags = 0; 92 .flags = 0,
87 descriptor.format = format.format; 93 .format = format.format,
88 descriptor.samples = VK_SAMPLE_COUNT_1_BIT; 94 .samples = VK_SAMPLE_COUNT_1_BIT,
89 descriptor.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; 95 .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
90 descriptor.storeOp = VK_ATTACHMENT_STORE_OP_STORE; 96 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
91 descriptor.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; 97 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
92 descriptor.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; 98 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
93 descriptor.initialLayout = zeta_layout; 99 .initialLayout = zeta_layout,
94 descriptor.finalLayout = zeta_layout; 100 .finalLayout = zeta_layout,
95 101 });
96 zeta_attachment_ref.attachment = static_cast<u32>(num_attachments); 102
97 zeta_attachment_ref.layout = zeta_layout; 103 zeta_attachment_ref = {
104 .attachment = static_cast<u32>(num_attachments),
105 .layout = zeta_layout,
106 };
98 } 107 }
99 108
100 VkSubpassDescription subpass_description; 109 const VkSubpassDescription subpass_description{
101 subpass_description.flags = 0; 110 .flags = 0,
102 subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; 111 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
103 subpass_description.inputAttachmentCount = 0; 112 .inputAttachmentCount = 0,
104 subpass_description.pInputAttachments = nullptr; 113 .pInputAttachments = nullptr,
105 subpass_description.colorAttachmentCount = static_cast<u32>(color_references.size()); 114 .colorAttachmentCount = static_cast<u32>(color_references.size()),
106 subpass_description.pColorAttachments = color_references.data(); 115 .pColorAttachments = color_references.data(),
107 subpass_description.pResolveAttachments = nullptr; 116 .pResolveAttachments = nullptr,
108 subpass_description.pDepthStencilAttachment = has_zeta ? &zeta_attachment_ref : nullptr; 117 .pDepthStencilAttachment = has_zeta ? &zeta_attachment_ref : nullptr,
109 subpass_description.preserveAttachmentCount = 0; 118 .preserveAttachmentCount = 0,
110 subpass_description.pPreserveAttachments = nullptr; 119 .pPreserveAttachments = nullptr,
120 };
111 121
112 VkAccessFlags access = 0; 122 VkAccessFlags access = 0;
113 VkPipelineStageFlags stage = 0; 123 VkPipelineStageFlags stage = 0;
@@ -122,26 +132,27 @@ vk::RenderPass VKRenderPassCache::CreateRenderPass(const RenderPassParams& param
122 stage |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; 132 stage |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
123 } 133 }
124 134
125 VkSubpassDependency subpass_dependency; 135 const VkSubpassDependency subpass_dependency{
126 subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL; 136 .srcSubpass = VK_SUBPASS_EXTERNAL,
127 subpass_dependency.dstSubpass = 0; 137 .dstSubpass = 0,
128 subpass_dependency.srcStageMask = stage; 138 .srcStageMask = stage,
129 subpass_dependency.dstStageMask = stage; 139 .dstStageMask = stage,
130 subpass_dependency.srcAccessMask = 0; 140 .srcAccessMask = 0,
131 subpass_dependency.dstAccessMask = access; 141 .dstAccessMask = access,
132 subpass_dependency.dependencyFlags = 0; 142 .dependencyFlags = 0,
133 143 };
134 VkRenderPassCreateInfo ci; 144
135 ci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; 145 return device.GetLogical().CreateRenderPass({
136 ci.pNext = nullptr; 146 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
137 ci.flags = 0; 147 .pNext = nullptr,
138 ci.attachmentCount = static_cast<u32>(descriptors.size()); 148 .flags = 0,
139 ci.pAttachments = descriptors.data(); 149 .attachmentCount = static_cast<u32>(descriptors.size()),
140 ci.subpassCount = 1; 150 .pAttachments = descriptors.data(),
141 ci.pSubpasses = &subpass_description; 151 .subpassCount = 1,
142 ci.dependencyCount = 1; 152 .pSubpasses = &subpass_description,
143 ci.pDependencies = &subpass_dependency; 153 .dependencyCount = 1,
144 return device.GetLogical().CreateRenderPass(ci); 154 .pDependencies = &subpass_dependency,
155 });
145} 156}
146 157
147} // namespace Vulkan 158} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp
index dc06f545a..f19330a36 100644
--- a/src/video_core/renderer_vulkan/vk_resource_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_resource_manager.cpp
@@ -18,33 +18,32 @@ namespace {
18constexpr std::size_t COMMAND_BUFFER_POOL_SIZE = 0x1000; 18constexpr std::size_t COMMAND_BUFFER_POOL_SIZE = 0x1000;
19constexpr std::size_t FENCES_GROW_STEP = 0x40; 19constexpr std::size_t FENCES_GROW_STEP = 0x40;
20 20
21VkFenceCreateInfo BuildFenceCreateInfo() { 21constexpr VkFenceCreateInfo BuildFenceCreateInfo() {
22 VkFenceCreateInfo fence_ci; 22 return {
23 fence_ci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; 23 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
24 fence_ci.pNext = nullptr; 24 .pNext = nullptr,
25 fence_ci.flags = 0; 25 .flags = 0,
26 return fence_ci; 26 };
27} 27}
28 28
29} // Anonymous namespace 29} // Anonymous namespace
30 30
31class CommandBufferPool final : public VKFencedPool { 31class CommandBufferPool final : public VKFencedPool {
32public: 32public:
33 CommandBufferPool(const VKDevice& device) 33 explicit CommandBufferPool(const VKDevice& device)
34 : VKFencedPool(COMMAND_BUFFER_POOL_SIZE), device{device} {} 34 : VKFencedPool(COMMAND_BUFFER_POOL_SIZE), device{device} {}
35 35
36 void Allocate(std::size_t begin, std::size_t end) override { 36 void Allocate(std::size_t begin, std::size_t end) override {
37 // Command buffers are going to be commited, recorded, executed every single usage cycle. 37 // Command buffers are going to be commited, recorded, executed every single usage cycle.
38 // They are also going to be reseted when commited. 38 // They are also going to be reseted when commited.
39 VkCommandPoolCreateInfo command_pool_ci;
40 command_pool_ci.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
41 command_pool_ci.pNext = nullptr;
42 command_pool_ci.flags =
43 VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
44 command_pool_ci.queueFamilyIndex = device.GetGraphicsFamily();
45
46 Pool& pool = pools.emplace_back(); 39 Pool& pool = pools.emplace_back();
47 pool.handle = device.GetLogical().CreateCommandPool(command_pool_ci); 40 pool.handle = device.GetLogical().CreateCommandPool({
41 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
42 .pNext = nullptr,
43 .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT |
44 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
45 .queueFamilyIndex = device.GetGraphicsFamily(),
46 });
48 pool.cmdbufs = pool.handle.Allocate(COMMAND_BUFFER_POOL_SIZE); 47 pool.cmdbufs = pool.handle.Allocate(COMMAND_BUFFER_POOL_SIZE);
49 } 48 }
50 49
diff --git a/src/video_core/renderer_vulkan/vk_sampler_cache.cpp b/src/video_core/renderer_vulkan/vk_sampler_cache.cpp
index 616eacc36..2d5460776 100644
--- a/src/video_core/renderer_vulkan/vk_sampler_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_sampler_cache.cpp
@@ -44,32 +44,35 @@ vk::Sampler VKSamplerCache::CreateSampler(const Tegra::Texture::TSCEntry& tsc) c
44 const bool arbitrary_borders = device.IsExtCustomBorderColorSupported(); 44 const bool arbitrary_borders = device.IsExtCustomBorderColorSupported();
45 const std::array color = tsc.GetBorderColor(); 45 const std::array color = tsc.GetBorderColor();
46 46
47 VkSamplerCustomBorderColorCreateInfoEXT border; 47 VkSamplerCustomBorderColorCreateInfoEXT border{
48 border.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT; 48 .sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
49 border.pNext = nullptr; 49 .pNext = nullptr,
50 border.format = VK_FORMAT_UNDEFINED; 50 .format = VK_FORMAT_UNDEFINED,
51 };
51 std::memcpy(&border.customBorderColor, color.data(), sizeof(color)); 52 std::memcpy(&border.customBorderColor, color.data(), sizeof(color));
52 53
53 VkSamplerCreateInfo ci; 54 return device.GetLogical().CreateSampler({
54 ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; 55 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
55 ci.pNext = arbitrary_borders ? &border : nullptr; 56 .pNext = arbitrary_borders ? &border : nullptr,
56 ci.flags = 0; 57 .flags = 0,
57 ci.magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter); 58 .magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter),
58 ci.minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter); 59 .minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter),
59 ci.mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter); 60 .mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter),
60 ci.addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter); 61 .addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter),
61 ci.addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter); 62 .addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter),
62 ci.addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter); 63 .addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter),
63 ci.mipLodBias = tsc.GetLodBias(); 64 .mipLodBias = tsc.GetLodBias(),
64 ci.anisotropyEnable = tsc.GetMaxAnisotropy() > 1.0f ? VK_TRUE : VK_FALSE; 65 .anisotropyEnable =
65 ci.maxAnisotropy = tsc.GetMaxAnisotropy(); 66 static_cast<VkBool32>(tsc.GetMaxAnisotropy() > 1.0f ? VK_TRUE : VK_FALSE),
66 ci.compareEnable = tsc.depth_compare_enabled; 67 .maxAnisotropy = tsc.GetMaxAnisotropy(),
67 ci.compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func); 68 .compareEnable = tsc.depth_compare_enabled,
68 ci.minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.GetMinLod(); 69 .compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func),
69 ci.maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.GetMaxLod(); 70 .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.GetMinLod(),
70 ci.borderColor = arbitrary_borders ? VK_BORDER_COLOR_INT_CUSTOM_EXT : ConvertBorderColor(color); 71 .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.GetMaxLod(),
71 ci.unnormalizedCoordinates = VK_FALSE; 72 .borderColor =
72 return device.GetLogical().CreateSampler(ci); 73 arbitrary_borders ? VK_BORDER_COLOR_INT_CUSTOM_EXT : ConvertBorderColor(color),
74 .unnormalizedCoordinates = VK_FALSE,
75 });
73} 76}
74 77
75VkSampler VKSamplerCache::ToSamplerType(const vk::Sampler& sampler) const { 78VkSampler VKSamplerCache::ToSamplerType(const vk::Sampler& sampler) const {
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index 56524e6f3..dbbd0961a 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -100,16 +100,19 @@ void VKScheduler::RequestRenderpass(VkRenderPass renderpass, VkFramebuffer frame
100 state.framebuffer = framebuffer; 100 state.framebuffer = framebuffer;
101 state.render_area = render_area; 101 state.render_area = render_area;
102 102
103 VkRenderPassBeginInfo renderpass_bi; 103 const VkRenderPassBeginInfo renderpass_bi{
104 renderpass_bi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; 104 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
105 renderpass_bi.pNext = nullptr; 105 .pNext = nullptr,
106 renderpass_bi.renderPass = renderpass; 106 .renderPass = renderpass,
107 renderpass_bi.framebuffer = framebuffer; 107 .framebuffer = framebuffer,
108 renderpass_bi.renderArea.offset.x = 0; 108 .renderArea =
109 renderpass_bi.renderArea.offset.y = 0; 109 {
110 renderpass_bi.renderArea.extent = render_area; 110 .offset = {.x = 0, .y = 0},
111 renderpass_bi.clearValueCount = 0; 111 .extent = render_area,
112 renderpass_bi.pClearValues = nullptr; 112 },
113 .clearValueCount = 0,
114 .pClearValues = nullptr,
115 };
113 116
114 Record([renderpass_bi, end_renderpass](vk::CommandBuffer cmdbuf) { 117 Record([renderpass_bi, end_renderpass](vk::CommandBuffer cmdbuf) {
115 if (end_renderpass) { 118 if (end_renderpass) {
@@ -157,16 +160,17 @@ void VKScheduler::SubmitExecution(VkSemaphore semaphore) {
157 160
158 current_cmdbuf.End(); 161 current_cmdbuf.End();
159 162
160 VkSubmitInfo submit_info; 163 const VkSubmitInfo submit_info{
161 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 164 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
162 submit_info.pNext = nullptr; 165 .pNext = nullptr,
163 submit_info.waitSemaphoreCount = 0; 166 .waitSemaphoreCount = 0,
164 submit_info.pWaitSemaphores = nullptr; 167 .pWaitSemaphores = nullptr,
165 submit_info.pWaitDstStageMask = nullptr; 168 .pWaitDstStageMask = nullptr,
166 submit_info.commandBufferCount = 1; 169 .commandBufferCount = 1,
167 submit_info.pCommandBuffers = current_cmdbuf.address(); 170 .pCommandBuffers = current_cmdbuf.address(),
168 submit_info.signalSemaphoreCount = semaphore ? 1 : 0; 171 .signalSemaphoreCount = semaphore ? 1U : 0U,
169 submit_info.pSignalSemaphores = &semaphore; 172 .pSignalSemaphores = &semaphore,
173 };
170 switch (const VkResult result = device.GetGraphicsQueue().Submit(submit_info, *current_fence)) { 174 switch (const VkResult result = device.GetGraphicsQueue().Submit(submit_info, *current_fence)) {
171 case VK_SUCCESS: 175 case VK_SUCCESS:
172 break; 176 break;
@@ -181,19 +185,18 @@ void VKScheduler::SubmitExecution(VkSemaphore semaphore) {
181void VKScheduler::AllocateNewContext() { 185void VKScheduler::AllocateNewContext() {
182 ++ticks; 186 ++ticks;
183 187
184 VkCommandBufferBeginInfo cmdbuf_bi;
185 cmdbuf_bi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
186 cmdbuf_bi.pNext = nullptr;
187 cmdbuf_bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
188 cmdbuf_bi.pInheritanceInfo = nullptr;
189
190 std::unique_lock lock{mutex}; 188 std::unique_lock lock{mutex};
191 current_fence = next_fence; 189 current_fence = next_fence;
192 next_fence = &resource_manager.CommitFence(); 190 next_fence = &resource_manager.CommitFence();
193 191
194 current_cmdbuf = vk::CommandBuffer(resource_manager.CommitCommandBuffer(*current_fence), 192 current_cmdbuf = vk::CommandBuffer(resource_manager.CommitCommandBuffer(*current_fence),
195 device.GetDispatchLoader()); 193 device.GetDispatchLoader());
196 current_cmdbuf.Begin(cmdbuf_bi); 194 current_cmdbuf.Begin({
195 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
196 .pNext = nullptr,
197 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
198 .pInheritanceInfo = nullptr,
199 });
197 200
198 // Enable counters once again. These are disabled when a command buffer is finished. 201 // Enable counters once again. These are disabled when a command buffer is finished.
199 if (query_cache) { 202 if (query_cache) {
diff --git a/src/video_core/renderer_vulkan/vk_shader_util.cpp b/src/video_core/renderer_vulkan/vk_shader_util.cpp
index 112df9c71..c1a218d76 100644
--- a/src/video_core/renderer_vulkan/vk_shader_util.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_util.cpp
@@ -19,13 +19,13 @@ vk::ShaderModule BuildShader(const VKDevice& device, std::size_t code_size, cons
19 const auto data = std::make_unique<u32[]>(code_size / sizeof(u32)); 19 const auto data = std::make_unique<u32[]>(code_size / sizeof(u32));
20 std::memcpy(data.get(), code_data, code_size); 20 std::memcpy(data.get(), code_data, code_size);
21 21
22 VkShaderModuleCreateInfo ci; 22 return device.GetLogical().CreateShaderModule({
23 ci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 23 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
24 ci.pNext = nullptr; 24 .pNext = nullptr,
25 ci.flags = 0; 25 .flags = 0,
26 ci.codeSize = code_size; 26 .codeSize = code_size,
27 ci.pCode = data.get(); 27 .pCode = data.get(),
28 return device.GetLogical().CreateShaderModule(ci); 28 });
29} 29}
30 30
31} // namespace Vulkan 31} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
index 45c180221..5eca0ab91 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
@@ -71,20 +71,19 @@ VKBuffer* VKStagingBufferPool::TryGetReservedBuffer(std::size_t size, bool host_
71VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_visible) { 71VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_visible) {
72 const u32 log2 = Common::Log2Ceil64(size); 72 const u32 log2 = Common::Log2Ceil64(size);
73 73
74 VkBufferCreateInfo ci;
75 ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
76 ci.pNext = nullptr;
77 ci.flags = 0;
78 ci.size = 1ULL << log2;
79 ci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
80 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
81 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
82 ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
83 ci.queueFamilyIndexCount = 0;
84 ci.pQueueFamilyIndices = nullptr;
85
86 auto buffer = std::make_unique<VKBuffer>(); 74 auto buffer = std::make_unique<VKBuffer>();
87 buffer->handle = device.GetLogical().CreateBuffer(ci); 75 buffer->handle = device.GetLogical().CreateBuffer({
76 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
77 .pNext = nullptr,
78 .flags = 0,
79 .size = 1ULL << log2,
80 .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
81 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
82 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
83 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
84 .queueFamilyIndexCount = 0,
85 .pQueueFamilyIndices = nullptr,
86 });
88 buffer->commit = memory_manager.Commit(buffer->handle, host_visible); 87 buffer->commit = memory_manager.Commit(buffer->handle, host_visible);
89 88
90 auto& entries = GetCache(host_visible)[log2].entries; 89 auto& entries = GetCache(host_visible)[log2].entries;
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
index 2d28a6c47..a5526a3f5 100644
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
+++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
@@ -122,30 +122,27 @@ void VKStreamBuffer::CreateBuffers(VkBufferUsageFlags usage) {
122 // Substract from the preferred heap size some bytes to avoid getting out of memory. 122 // Substract from the preferred heap size some bytes to avoid getting out of memory.
123 const VkDeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size; 123 const VkDeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size;
124 const VkDeviceSize allocable_size = heap_size - 9 * 1024 * 1024; 124 const VkDeviceSize allocable_size = heap_size - 9 * 1024 * 1024;
125 125 buffer = device.GetLogical().CreateBuffer({
126 VkBufferCreateInfo buffer_ci; 126 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
127 buffer_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 127 .pNext = nullptr,
128 buffer_ci.pNext = nullptr; 128 .flags = 0,
129 buffer_ci.flags = 0; 129 .size = std::min(PREFERRED_STREAM_BUFFER_SIZE, allocable_size),
130 buffer_ci.size = std::min(PREFERRED_STREAM_BUFFER_SIZE, allocable_size); 130 .usage = usage,
131 buffer_ci.usage = usage; 131 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
132 buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 132 .queueFamilyIndexCount = 0,
133 buffer_ci.queueFamilyIndexCount = 0; 133 .pQueueFamilyIndices = nullptr,
134 buffer_ci.pQueueFamilyIndices = nullptr; 134 });
135
136 buffer = device.GetLogical().CreateBuffer(buffer_ci);
137 135
138 const auto requirements = device.GetLogical().GetBufferMemoryRequirements(*buffer); 136 const auto requirements = device.GetLogical().GetBufferMemoryRequirements(*buffer);
139 const u32 required_flags = requirements.memoryTypeBits; 137 const u32 required_flags = requirements.memoryTypeBits;
140 stream_buffer_size = static_cast<u64>(requirements.size); 138 stream_buffer_size = static_cast<u64>(requirements.size);
141 139
142 VkMemoryAllocateInfo memory_ai; 140 memory = device.GetLogical().AllocateMemory({
143 memory_ai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 141 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
144 memory_ai.pNext = nullptr; 142 .pNext = nullptr,
145 memory_ai.allocationSize = requirements.size; 143 .allocationSize = requirements.size,
146 memory_ai.memoryTypeIndex = GetMemoryType(memory_properties, required_flags); 144 .memoryTypeIndex = GetMemoryType(memory_properties, required_flags),
147 145 });
148 memory = device.GetLogical().AllocateMemory(memory_ai);
149 buffer.BindMemory(*memory, 0); 146 buffer.BindMemory(*memory, 0);
150} 147}
151 148
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index bffd8f32a..c25e312b6 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -95,15 +95,16 @@ bool VKSwapchain::Present(VkSemaphore render_semaphore, VKFence& fence) {
95 const auto present_queue{device.GetPresentQueue()}; 95 const auto present_queue{device.GetPresentQueue()};
96 bool recreated = false; 96 bool recreated = false;
97 97
98 VkPresentInfoKHR present_info; 98 const VkPresentInfoKHR present_info{
99 present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; 99 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
100 present_info.pNext = nullptr; 100 .pNext = nullptr,
101 present_info.waitSemaphoreCount = render_semaphore ? 2U : 1U; 101 .waitSemaphoreCount = render_semaphore ? 2U : 1U,
102 present_info.pWaitSemaphores = semaphores.data(); 102 .pWaitSemaphores = semaphores.data(),
103 present_info.swapchainCount = 1; 103 .swapchainCount = 1,
104 present_info.pSwapchains = swapchain.address(); 104 .pSwapchains = swapchain.address(),
105 present_info.pImageIndices = &image_index; 105 .pImageIndices = &image_index,
106 present_info.pResults = nullptr; 106 .pResults = nullptr,
107 };
107 108
108 switch (const VkResult result = present_queue.Present(present_info)) { 109 switch (const VkResult result = present_queue.Present(present_info)) {
109 case VK_SUCCESS: 110 case VK_SUCCESS:
@@ -147,24 +148,25 @@ void VKSwapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities,
147 requested_image_count = capabilities.maxImageCount; 148 requested_image_count = capabilities.maxImageCount;
148 } 149 }
149 150
150 VkSwapchainCreateInfoKHR swapchain_ci; 151 VkSwapchainCreateInfoKHR swapchain_ci{
151 swapchain_ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; 152 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
152 swapchain_ci.pNext = nullptr; 153 .pNext = nullptr,
153 swapchain_ci.flags = 0; 154 .flags = 0,
154 swapchain_ci.surface = surface; 155 .surface = surface,
155 swapchain_ci.minImageCount = requested_image_count; 156 .minImageCount = requested_image_count,
156 swapchain_ci.imageFormat = surface_format.format; 157 .imageFormat = surface_format.format,
157 swapchain_ci.imageColorSpace = surface_format.colorSpace; 158 .imageColorSpace = surface_format.colorSpace,
158 swapchain_ci.imageArrayLayers = 1; 159 .imageArrayLayers = 1,
159 swapchain_ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 160 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
160 swapchain_ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; 161 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
161 swapchain_ci.queueFamilyIndexCount = 0; 162 .queueFamilyIndexCount = 0,
162 swapchain_ci.pQueueFamilyIndices = nullptr; 163 .pQueueFamilyIndices = nullptr,
163 swapchain_ci.preTransform = capabilities.currentTransform; 164 .preTransform = capabilities.currentTransform,
164 swapchain_ci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 165 .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
165 swapchain_ci.presentMode = present_mode; 166 .presentMode = present_mode,
166 swapchain_ci.clipped = VK_FALSE; 167 .clipped = VK_FALSE,
167 swapchain_ci.oldSwapchain = nullptr; 168 .oldSwapchain = nullptr,
169 };
168 170
169 const u32 graphics_family{device.GetGraphicsFamily()}; 171 const u32 graphics_family{device.GetGraphicsFamily()};
170 const u32 present_family{device.GetPresentFamily()}; 172 const u32 present_family{device.GetPresentFamily()};
@@ -173,8 +175,6 @@ void VKSwapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities,
173 swapchain_ci.imageSharingMode = VK_SHARING_MODE_CONCURRENT; 175 swapchain_ci.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
174 swapchain_ci.queueFamilyIndexCount = static_cast<u32>(queue_indices.size()); 176 swapchain_ci.queueFamilyIndexCount = static_cast<u32>(queue_indices.size());
175 swapchain_ci.pQueueFamilyIndices = queue_indices.data(); 177 swapchain_ci.pQueueFamilyIndices = queue_indices.data();
176 } else {
177 swapchain_ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
178 } 178 }
179 179
180 // Request the size again to reduce the possibility of a TOCTOU race condition. 180 // Request the size again to reduce the possibility of a TOCTOU race condition.
@@ -200,20 +200,28 @@ void VKSwapchain::CreateSemaphores() {
200} 200}
201 201
202void VKSwapchain::CreateImageViews() { 202void VKSwapchain::CreateImageViews() {
203 VkImageViewCreateInfo ci; 203 VkImageViewCreateInfo ci{
204 ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 204 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
205 ci.pNext = nullptr; 205 .pNext = nullptr,
206 ci.flags = 0; 206 .flags = 0,
207 // ci.image 207 .viewType = VK_IMAGE_VIEW_TYPE_2D,
208 ci.viewType = VK_IMAGE_VIEW_TYPE_2D; 208 .format = image_format,
209 ci.format = image_format; 209 .components =
210 ci.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, 210 {
211 VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; 211 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
212 ci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 212 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
213 ci.subresourceRange.baseMipLevel = 0; 213 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
214 ci.subresourceRange.levelCount = 1; 214 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
215 ci.subresourceRange.baseArrayLayer = 0; 215 },
216 ci.subresourceRange.layerCount = 1; 216 .subresourceRange =
217 {
218 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
219 .baseMipLevel = 0,
220 .levelCount = 1,
221 .baseArrayLayer = 0,
222 .layerCount = 1,
223 },
224 };
217 225
218 image_views.resize(image_count); 226 image_views.resize(image_count);
219 for (std::size_t i = 0; i < image_count; i++) { 227 for (std::size_t i = 0; i < image_count; i++) {
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index bd93dcf20..d102e6d27 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -95,17 +95,18 @@ VkImageViewType GetImageViewType(SurfaceTarget target) {
95vk::Buffer CreateBuffer(const VKDevice& device, const SurfaceParams& params, 95vk::Buffer CreateBuffer(const VKDevice& device, const SurfaceParams& params,
96 std::size_t host_memory_size) { 96 std::size_t host_memory_size) {
97 // TODO(Rodrigo): Move texture buffer creation to the buffer cache 97 // TODO(Rodrigo): Move texture buffer creation to the buffer cache
98 VkBufferCreateInfo ci; 98 return device.GetLogical().CreateBuffer({
99 ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 99 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
100 ci.pNext = nullptr; 100 .pNext = nullptr,
101 ci.flags = 0; 101 .flags = 0,
102 ci.size = static_cast<VkDeviceSize>(host_memory_size); 102 .size = static_cast<VkDeviceSize>(host_memory_size),
103 ci.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | 103 .usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT |
104 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; 104 VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
105 ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 105 VK_BUFFER_USAGE_TRANSFER_DST_BIT,
106 ci.queueFamilyIndexCount = 0; 106 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
107 ci.pQueueFamilyIndices = nullptr; 107 .queueFamilyIndexCount = 0,
108 return device.GetLogical().CreateBuffer(ci); 108 .pQueueFamilyIndices = nullptr,
109 });
109} 110}
110 111
111VkBufferViewCreateInfo GenerateBufferViewCreateInfo(const VKDevice& device, 112VkBufferViewCreateInfo GenerateBufferViewCreateInfo(const VKDevice& device,
@@ -113,15 +114,16 @@ VkBufferViewCreateInfo GenerateBufferViewCreateInfo(const VKDevice& device,
113 std::size_t host_memory_size) { 114 std::size_t host_memory_size) {
114 ASSERT(params.IsBuffer()); 115 ASSERT(params.IsBuffer());
115 116
116 VkBufferViewCreateInfo ci; 117 return {
117 ci.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; 118 .sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
118 ci.pNext = nullptr; 119 .pNext = nullptr,
119 ci.flags = 0; 120 .flags = 0,
120 ci.buffer = buffer; 121 .buffer = buffer,
121 ci.format = MaxwellToVK::SurfaceFormat(device, FormatType::Buffer, params.pixel_format).format; 122 .format =
122 ci.offset = 0; 123 MaxwellToVK::SurfaceFormat(device, FormatType::Buffer, params.pixel_format).format,
123 ci.range = static_cast<VkDeviceSize>(host_memory_size); 124 .offset = 0,
124 return ci; 125 .range = static_cast<VkDeviceSize>(host_memory_size),
126 };
125} 127}
126 128
127VkImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceParams& params) { 129VkImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceParams& params) {
@@ -130,23 +132,23 @@ VkImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceP
130 const auto [format, attachable, storage] = 132 const auto [format, attachable, storage] =
131 MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, params.pixel_format); 133 MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, params.pixel_format);
132 134
133 VkImageCreateInfo ci; 135 VkImageCreateInfo ci{
134 ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; 136 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
135 ci.pNext = nullptr; 137 .pNext = nullptr,
136 ci.flags = 0; 138 .flags = 0,
137 ci.imageType = SurfaceTargetToImage(params.target); 139 .imageType = SurfaceTargetToImage(params.target),
138 ci.format = format; 140 .format = format,
139 ci.mipLevels = params.num_levels; 141 .mipLevels = params.num_levels,
140 ci.arrayLayers = static_cast<u32>(params.GetNumLayers()); 142 .arrayLayers = static_cast<u32>(params.GetNumLayers()),
141 ci.samples = VK_SAMPLE_COUNT_1_BIT; 143 .samples = VK_SAMPLE_COUNT_1_BIT,
142 ci.tiling = VK_IMAGE_TILING_OPTIMAL; 144 .tiling = VK_IMAGE_TILING_OPTIMAL,
143 ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 145 .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
144 ci.queueFamilyIndexCount = 0; 146 VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
145 ci.pQueueFamilyIndices = nullptr; 147 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
146 ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 148 .queueFamilyIndexCount = 0,
147 149 .pQueueFamilyIndices = nullptr,
148 ci.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | 150 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
149 VK_IMAGE_USAGE_TRANSFER_SRC_BIT; 151 };
150 if (attachable) { 152 if (attachable) {
151 ci.usage |= params.IsPixelFormatZeta() ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT 153 ci.usage |= params.IsPixelFormatZeta() ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
152 : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 154 : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
@@ -233,7 +235,7 @@ void CachedSurface::UploadTexture(const std::vector<u8>& staging_buffer) {
233void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) { 235void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) {
234 UNIMPLEMENTED_IF(params.IsBuffer()); 236 UNIMPLEMENTED_IF(params.IsBuffer());
235 237
236 if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5U) { 238 if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5_UNORM) {
237 LOG_WARNING(Render_Vulkan, "A1B5G5R5 flushing is stubbed"); 239 LOG_WARNING(Render_Vulkan, "A1B5G5R5 flushing is stubbed");
238 } 240 }
239 241
@@ -321,22 +323,25 @@ void CachedSurface::UploadImage(const std::vector<u8>& staging_buffer) {
321} 323}
322 324
323VkBufferImageCopy CachedSurface::GetBufferImageCopy(u32 level) const { 325VkBufferImageCopy CachedSurface::GetBufferImageCopy(u32 level) const {
324 VkBufferImageCopy copy; 326 return {
325 copy.bufferOffset = params.GetHostMipmapLevelOffset(level, is_converted); 327 .bufferOffset = params.GetHostMipmapLevelOffset(level, is_converted),
326 copy.bufferRowLength = 0; 328 .bufferRowLength = 0,
327 copy.bufferImageHeight = 0; 329 .bufferImageHeight = 0,
328 copy.imageSubresource.aspectMask = image->GetAspectMask(); 330 .imageSubresource =
329 copy.imageSubresource.mipLevel = level; 331 {
330 copy.imageSubresource.baseArrayLayer = 0; 332 .aspectMask = image->GetAspectMask(),
331 copy.imageSubresource.layerCount = static_cast<u32>(params.GetNumLayers()); 333 .mipLevel = level,
332 copy.imageOffset.x = 0; 334 .baseArrayLayer = 0,
333 copy.imageOffset.y = 0; 335 .layerCount = static_cast<u32>(params.GetNumLayers()),
334 copy.imageOffset.z = 0; 336 },
335 copy.imageExtent.width = params.GetMipWidth(level); 337 .imageOffset = {.x = 0, .y = 0, .z = 0},
336 copy.imageExtent.height = params.GetMipHeight(level); 338 .imageExtent =
337 copy.imageExtent.depth = 339 {
338 params.target == SurfaceTarget::Texture3D ? params.GetMipDepth(level) : 1; 340 .width = params.GetMipWidth(level),
339 return copy; 341 .height = params.GetMipHeight(level),
342 .depth = params.target == SurfaceTarget::Texture3D ? params.GetMipDepth(level) : 1U,
343 },
344 };
340} 345}
341 346
342VkImageSubresourceRange CachedSurface::GetImageSubresourceRange() const { 347VkImageSubresourceRange CachedSurface::GetImageSubresourceRange() const {
@@ -380,7 +385,7 @@ VkImageView CachedSurfaceView::GetImageView(SwizzleSource x_source, SwizzleSourc
380 385
381 std::array swizzle{MaxwellToVK::SwizzleSource(x_source), MaxwellToVK::SwizzleSource(y_source), 386 std::array swizzle{MaxwellToVK::SwizzleSource(x_source), MaxwellToVK::SwizzleSource(y_source),
382 MaxwellToVK::SwizzleSource(z_source), MaxwellToVK::SwizzleSource(w_source)}; 387 MaxwellToVK::SwizzleSource(z_source), MaxwellToVK::SwizzleSource(w_source)};
383 if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5U) { 388 if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5_UNORM) {
384 // A1B5G5R5 is implemented as A1R5G5B5, we have to change the swizzle here. 389 // A1B5G5R5 is implemented as A1R5G5B5, we have to change the swizzle here.
385 std::swap(swizzle[0], swizzle[2]); 390 std::swap(swizzle[0], swizzle[2]);
386 } 391 }
@@ -392,11 +397,11 @@ VkImageView CachedSurfaceView::GetImageView(SwizzleSource x_source, SwizzleSourc
392 UNIMPLEMENTED_IF(x_source != SwizzleSource::R && x_source != SwizzleSource::G); 397 UNIMPLEMENTED_IF(x_source != SwizzleSource::R && x_source != SwizzleSource::G);
393 const bool is_first = x_source == SwizzleSource::R; 398 const bool is_first = x_source == SwizzleSource::R;
394 switch (params.pixel_format) { 399 switch (params.pixel_format) {
395 case VideoCore::Surface::PixelFormat::Z24S8: 400 case VideoCore::Surface::PixelFormat::D24_UNORM_S8_UINT:
396 case VideoCore::Surface::PixelFormat::Z32FS8: 401 case VideoCore::Surface::PixelFormat::D32_FLOAT_S8_UINT:
397 aspect = is_first ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT; 402 aspect = is_first ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT;
398 break; 403 break;
399 case VideoCore::Surface::PixelFormat::S8Z24: 404 case VideoCore::Surface::PixelFormat::S8_UINT_D24_UNORM:
400 aspect = is_first ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; 405 aspect = is_first ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT;
401 break; 406 break;
402 default: 407 default:
@@ -416,20 +421,29 @@ VkImageView CachedSurfaceView::GetImageView(SwizzleSource x_source, SwizzleSourc
416 ASSERT(num_slices == params.depth); 421 ASSERT(num_slices == params.depth);
417 } 422 }
418 423
419 VkImageViewCreateInfo ci; 424 image_view = device.GetLogical().CreateImageView({
420 ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 425 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
421 ci.pNext = nullptr; 426 .pNext = nullptr,
422 ci.flags = 0; 427 .flags = 0,
423 ci.image = surface.GetImageHandle(); 428 .image = surface.GetImageHandle(),
424 ci.viewType = image_view_type; 429 .viewType = image_view_type,
425 ci.format = surface.GetImage().GetFormat(); 430 .format = surface.GetImage().GetFormat(),
426 ci.components = {swizzle[0], swizzle[1], swizzle[2], swizzle[3]}; 431 .components =
427 ci.subresourceRange.aspectMask = aspect; 432 {
428 ci.subresourceRange.baseMipLevel = base_level; 433 .r = swizzle[0],
429 ci.subresourceRange.levelCount = num_levels; 434 .g = swizzle[1],
430 ci.subresourceRange.baseArrayLayer = base_layer; 435 .b = swizzle[2],
431 ci.subresourceRange.layerCount = num_layers; 436 .a = swizzle[3],
432 image_view = device.GetLogical().CreateImageView(ci); 437 },
438 .subresourceRange =
439 {
440 .aspectMask = aspect,
441 .baseMipLevel = base_level,
442 .levelCount = num_levels,
443 .baseArrayLayer = base_layer,
444 .layerCount = num_layers,
445 },
446 });
433 447
434 return last_image_view = *image_view; 448 return last_image_view = *image_view;
435} 449}
@@ -439,17 +453,26 @@ VkImageView CachedSurfaceView::GetAttachment() {
439 return *render_target; 453 return *render_target;
440 } 454 }
441 455
442 VkImageViewCreateInfo ci; 456 VkImageViewCreateInfo ci{
443 ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 457 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
444 ci.pNext = nullptr; 458 .pNext = nullptr,
445 ci.flags = 0; 459 .flags = 0,
446 ci.image = surface.GetImageHandle(); 460 .image = surface.GetImageHandle(),
447 ci.format = surface.GetImage().GetFormat(); 461 .format = surface.GetImage().GetFormat(),
448 ci.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, 462 .components =
449 VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; 463 {
450 ci.subresourceRange.aspectMask = aspect_mask; 464 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
451 ci.subresourceRange.baseMipLevel = base_level; 465 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
452 ci.subresourceRange.levelCount = num_levels; 466 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
467 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
468 },
469 .subresourceRange =
470 {
471 .aspectMask = aspect_mask,
472 .baseMipLevel = base_level,
473 .levelCount = num_levels,
474 },
475 };
453 if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { 476 if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) {
454 ci.viewType = num_slices > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D; 477 ci.viewType = num_slices > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
455 ci.subresourceRange.baseArrayLayer = base_slice; 478 ci.subresourceRange.baseArrayLayer = base_slice;
@@ -502,24 +525,40 @@ void VKTextureCache::ImageCopy(Surface& src_surface, Surface& dst_surface,
502 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, 525 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
503 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 526 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
504 527
505 VkImageCopy copy; 528 const VkImageCopy copy{
506 copy.srcSubresource.aspectMask = src_surface->GetAspectMask(); 529 .srcSubresource =
507 copy.srcSubresource.mipLevel = copy_params.source_level; 530 {
508 copy.srcSubresource.baseArrayLayer = copy_params.source_z; 531 .aspectMask = src_surface->GetAspectMask(),
509 copy.srcSubresource.layerCount = num_layers; 532 .mipLevel = copy_params.source_level,
510 copy.srcOffset.x = copy_params.source_x; 533 .baseArrayLayer = copy_params.source_z,
511 copy.srcOffset.y = copy_params.source_y; 534 .layerCount = num_layers,
512 copy.srcOffset.z = 0; 535 },
513 copy.dstSubresource.aspectMask = dst_surface->GetAspectMask(); 536 .srcOffset =
514 copy.dstSubresource.mipLevel = copy_params.dest_level; 537 {
515 copy.dstSubresource.baseArrayLayer = dst_base_layer; 538 .x = static_cast<s32>(copy_params.source_x),
516 copy.dstSubresource.layerCount = num_layers; 539 .y = static_cast<s32>(copy_params.source_y),
517 copy.dstOffset.x = copy_params.dest_x; 540 .z = 0,
518 copy.dstOffset.y = copy_params.dest_y; 541 },
519 copy.dstOffset.z = dst_offset_z; 542 .dstSubresource =
520 copy.extent.width = copy_params.width; 543 {
521 copy.extent.height = copy_params.height; 544 .aspectMask = dst_surface->GetAspectMask(),
522 copy.extent.depth = extent_z; 545 .mipLevel = copy_params.dest_level,
546 .baseArrayLayer = dst_base_layer,
547 .layerCount = num_layers,
548 },
549 .dstOffset =
550 {
551 .x = static_cast<s32>(copy_params.dest_x),
552 .y = static_cast<s32>(copy_params.dest_y),
553 .z = static_cast<s32>(dst_offset_z),
554 },
555 .extent =
556 {
557 .width = copy_params.width,
558 .height = copy_params.height,
559 .depth = extent_z,
560 },
561 };
523 562
524 const VkImage src_image = src_surface->GetImageHandle(); 563 const VkImage src_image = src_surface->GetImageHandle();
525 const VkImage dst_image = dst_surface->GetImageHandle(); 564 const VkImage dst_image = dst_surface->GetImageHandle();
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp
index 051298cc8..14cac38ea 100644
--- a/src/video_core/renderer_vulkan/wrapper.cpp
+++ b/src/video_core/renderer_vulkan/wrapper.cpp
@@ -377,24 +377,26 @@ VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffe
377 377
378Instance Instance::Create(Span<const char*> layers, Span<const char*> extensions, 378Instance Instance::Create(Span<const char*> layers, Span<const char*> extensions,
379 InstanceDispatch& dld) noexcept { 379 InstanceDispatch& dld) noexcept {
380 VkApplicationInfo application_info; 380 static constexpr VkApplicationInfo application_info{
381 application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; 381 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
382 application_info.pNext = nullptr; 382 .pNext = nullptr,
383 application_info.pApplicationName = "yuzu Emulator"; 383 .pApplicationName = "yuzu Emulator",
384 application_info.applicationVersion = VK_MAKE_VERSION(0, 1, 0); 384 .applicationVersion = VK_MAKE_VERSION(0, 1, 0),
385 application_info.pEngineName = "yuzu Emulator"; 385 .pEngineName = "yuzu Emulator",
386 application_info.engineVersion = VK_MAKE_VERSION(0, 1, 0); 386 .engineVersion = VK_MAKE_VERSION(0, 1, 0),
387 application_info.apiVersion = VK_API_VERSION_1_1; 387 .apiVersion = VK_API_VERSION_1_1,
388 388 };
389 VkInstanceCreateInfo ci; 389
390 ci.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 390 const VkInstanceCreateInfo ci{
391 ci.pNext = nullptr; 391 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
392 ci.flags = 0; 392 .pNext = nullptr,
393 ci.pApplicationInfo = &application_info; 393 .flags = 0,
394 ci.enabledLayerCount = layers.size(); 394 .pApplicationInfo = &application_info,
395 ci.ppEnabledLayerNames = layers.data(); 395 .enabledLayerCount = layers.size(),
396 ci.enabledExtensionCount = extensions.size(); 396 .ppEnabledLayerNames = layers.data(),
397 ci.ppEnabledExtensionNames = extensions.data(); 397 .enabledExtensionCount = extensions.size(),
398 .ppEnabledExtensionNames = extensions.data(),
399 };
398 400
399 VkInstance instance; 401 VkInstance instance;
400 if (dld.vkCreateInstance(&ci, nullptr, &instance) != VK_SUCCESS) { 402 if (dld.vkCreateInstance(&ci, nullptr, &instance) != VK_SUCCESS) {
@@ -425,19 +427,20 @@ std::optional<std::vector<VkPhysicalDevice>> Instance::EnumeratePhysicalDevices(
425 427
426DebugCallback Instance::TryCreateDebugCallback( 428DebugCallback Instance::TryCreateDebugCallback(
427 PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept { 429 PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept {
428 VkDebugUtilsMessengerCreateInfoEXT ci; 430 const VkDebugUtilsMessengerCreateInfoEXT ci{
429 ci.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; 431 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
430 ci.pNext = nullptr; 432 .pNext = nullptr,
431 ci.flags = 0; 433 .flags = 0,
432 ci.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | 434 .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
433 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | 435 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
434 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | 436 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
435 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; 437 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
436 ci.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | 438 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
437 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | 439 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
438 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; 440 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
439 ci.pfnUserCallback = callback; 441 .pfnUserCallback = callback,
440 ci.pUserData = nullptr; 442 .pUserData = nullptr,
443 };
441 444
442 VkDebugUtilsMessengerEXT messenger; 445 VkDebugUtilsMessengerEXT messenger;
443 if (dld->vkCreateDebugUtilsMessengerEXT(handle, &ci, nullptr, &messenger) != VK_SUCCESS) { 446 if (dld->vkCreateDebugUtilsMessengerEXT(handle, &ci, nullptr, &messenger) != VK_SUCCESS) {
@@ -468,12 +471,13 @@ DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) c
468} 471}
469 472
470CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLevel level) const { 473CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLevel level) const {
471 VkCommandBufferAllocateInfo ai; 474 const VkCommandBufferAllocateInfo ai{
472 ai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 475 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
473 ai.pNext = nullptr; 476 .pNext = nullptr,
474 ai.commandPool = handle; 477 .commandPool = handle,
475 ai.level = level; 478 .level = level,
476 ai.commandBufferCount = static_cast<u32>(num_buffers); 479 .commandBufferCount = static_cast<u32>(num_buffers),
480 };
477 481
478 std::unique_ptr buffers = std::make_unique<VkCommandBuffer[]>(num_buffers); 482 std::unique_ptr buffers = std::make_unique<VkCommandBuffer[]>(num_buffers);
479 switch (const VkResult result = dld->vkAllocateCommandBuffers(owner, &ai, buffers.get())) { 483 switch (const VkResult result = dld->vkAllocateCommandBuffers(owner, &ai, buffers.get())) {
@@ -497,17 +501,18 @@ std::vector<VkImage> SwapchainKHR::GetImages() const {
497Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, 501Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
498 Span<const char*> enabled_extensions, const void* next, 502 Span<const char*> enabled_extensions, const void* next,
499 DeviceDispatch& dld) noexcept { 503 DeviceDispatch& dld) noexcept {
500 VkDeviceCreateInfo ci; 504 const VkDeviceCreateInfo ci{
501 ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 505 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
502 ci.pNext = next; 506 .pNext = next,
503 ci.flags = 0; 507 .flags = 0,
504 ci.queueCreateInfoCount = queues_ci.size(); 508 .queueCreateInfoCount = queues_ci.size(),
505 ci.pQueueCreateInfos = queues_ci.data(); 509 .pQueueCreateInfos = queues_ci.data(),
506 ci.enabledLayerCount = 0; 510 .enabledLayerCount = 0,
507 ci.ppEnabledLayerNames = nullptr; 511 .ppEnabledLayerNames = nullptr,
508 ci.enabledExtensionCount = enabled_extensions.size(); 512 .enabledExtensionCount = enabled_extensions.size(),
509 ci.ppEnabledExtensionNames = enabled_extensions.data(); 513 .ppEnabledExtensionNames = enabled_extensions.data(),
510 ci.pEnabledFeatures = nullptr; 514 .pEnabledFeatures = nullptr,
515 };
511 516
512 VkDevice device; 517 VkDevice device;
513 if (dld.vkCreateDevice(physical_device, &ci, nullptr, &device) != VK_SUCCESS) { 518 if (dld.vkCreateDevice(physical_device, &ci, nullptr, &device) != VK_SUCCESS) {
@@ -548,10 +553,11 @@ ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const {
548} 553}
549 554
550Semaphore Device::CreateSemaphore() const { 555Semaphore Device::CreateSemaphore() const {
551 VkSemaphoreCreateInfo ci; 556 static constexpr VkSemaphoreCreateInfo ci{
552 ci.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; 557 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
553 ci.pNext = nullptr; 558 .pNext = nullptr,
554 ci.flags = 0; 559 .flags = 0,
560 };
555 561
556 VkSemaphore object; 562 VkSemaphore object;
557 Check(dld->vkCreateSemaphore(handle, &ci, nullptr, &object)); 563 Check(dld->vkCreateSemaphore(handle, &ci, nullptr, &object));
@@ -639,10 +645,12 @@ ShaderModule Device::CreateShaderModule(const VkShaderModuleCreateInfo& ci) cons
639} 645}
640 646
641Event Device::CreateEvent() const { 647Event Device::CreateEvent() const {
642 VkEventCreateInfo ci; 648 static constexpr VkEventCreateInfo ci{
643 ci.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; 649 .sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO,
644 ci.pNext = nullptr; 650 .pNext = nullptr,
645 ci.flags = 0; 651 .flags = 0,
652 };
653
646 VkEvent object; 654 VkEvent object;
647 Check(dld->vkCreateEvent(handle, &ci, nullptr, &object)); 655 Check(dld->vkCreateEvent(handle, &ci, nullptr, &object));
648 return Event(object, handle, *dld); 656 return Event(object, handle, *dld);
diff --git a/src/video_core/shader/async_shaders.cpp b/src/video_core/shader/async_shaders.cpp
new file mode 100644
index 000000000..b7f66d7ee
--- /dev/null
+++ b/src/video_core/shader/async_shaders.cpp
@@ -0,0 +1,181 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <chrono>
6#include <condition_variable>
7#include <mutex>
8#include <thread>
9#include <vector>
10#include "video_core/engines/maxwell_3d.h"
11#include "video_core/renderer_base.h"
12#include "video_core/renderer_opengl/gl_shader_cache.h"
13#include "video_core/shader/async_shaders.h"
14
15namespace VideoCommon::Shader {
16
17AsyncShaders::AsyncShaders(Core::Frontend::EmuWindow& emu_window) : emu_window(emu_window) {}
18
19AsyncShaders::~AsyncShaders() {
20 KillWorkers();
21}
22
23void AsyncShaders::AllocateWorkers(std::size_t num_workers) {
24 // If we're already have workers queued or don't want to queue workers, ignore
25 if (num_workers == worker_threads.size() || num_workers == 0) {
26 return;
27 }
28
29 // If workers already exist, clear them
30 if (!worker_threads.empty()) {
31 FreeWorkers();
32 }
33
34 // Create workers
35 for (std::size_t i = 0; i < num_workers; i++) {
36 context_list.push_back(emu_window.CreateSharedContext());
37 worker_threads.push_back(std::move(
38 std::thread(&AsyncShaders::ShaderCompilerThread, this, context_list[i].get())));
39 }
40}
41
42void AsyncShaders::FreeWorkers() {
43 // Mark all threads to quit
44 is_thread_exiting.store(true);
45 cv.notify_all();
46 for (auto& thread : worker_threads) {
47 thread.join();
48 }
49 // Clear our shared contexts
50 context_list.clear();
51
52 // Clear our worker threads
53 worker_threads.clear();
54}
55
56void AsyncShaders::KillWorkers() {
57 is_thread_exiting.store(true);
58 for (auto& thread : worker_threads) {
59 thread.detach();
60 }
61 // Clear our shared contexts
62 context_list.clear();
63
64 // Clear our worker threads
65 worker_threads.clear();
66}
67
68bool AsyncShaders::HasWorkQueued() {
69 return !pending_queue.empty();
70}
71
72bool AsyncShaders::HasCompletedWork() {
73 std::shared_lock lock{completed_mutex};
74 return !finished_work.empty();
75}
76
77bool AsyncShaders::IsShaderAsync(const Tegra::GPU& gpu) const {
78 const auto& regs = gpu.Maxwell3D().regs;
79
80 // If something is using depth, we can assume that games are not rendering anything which will
81 // be used one time.
82 if (regs.zeta_enable) {
83 return true;
84 }
85
86 // If games are using a small index count, we can assume these are full screen quads. Usually
87 // these shaders are only used once for building textures so we can assume they can't be built
88 // async
89 if (regs.index_array.count <= 6 || regs.vertex_buffer.count <= 6) {
90 return false;
91 }
92
93 return true;
94}
95
96std::vector<AsyncShaders::Result> AsyncShaders::GetCompletedWork() {
97 std::vector<AsyncShaders::Result> results;
98 {
99 std::unique_lock lock{completed_mutex};
100 results.assign(std::make_move_iterator(finished_work.begin()),
101 std::make_move_iterator(finished_work.end()));
102 finished_work.clear();
103 }
104 return results;
105}
106
107void AsyncShaders::QueueOpenGLShader(const OpenGL::Device& device,
108 Tegra::Engines::ShaderType shader_type, u64 uid,
109 std::vector<u64> code, std::vector<u64> code_b,
110 u32 main_offset,
111 VideoCommon::Shader::CompilerSettings compiler_settings,
112 const VideoCommon::Shader::Registry& registry,
113 VAddr cpu_addr) {
114 WorkerParams params{device.UseAssemblyShaders() ? AsyncShaders::Backend::GLASM
115 : AsyncShaders::Backend::OpenGL,
116 device,
117 shader_type,
118 uid,
119 std::move(code),
120 std::move(code_b),
121 main_offset,
122 compiler_settings,
123 registry,
124 cpu_addr};
125 std::unique_lock lock(queue_mutex);
126 pending_queue.push_back(std::move(params));
127 cv.notify_one();
128}
129
130void AsyncShaders::ShaderCompilerThread(Core::Frontend::GraphicsContext* context) {
131 using namespace std::chrono_literals;
132 while (!is_thread_exiting.load(std::memory_order_relaxed)) {
133 std::unique_lock lock{queue_mutex};
134 cv.wait(lock, [this] { return HasWorkQueued() || is_thread_exiting; });
135 if (is_thread_exiting) {
136 return;
137 }
138
139 // Partial lock to allow all threads to read at the same time
140 if (!HasWorkQueued()) {
141 continue;
142 }
143 // Another thread beat us, just unlock and wait for the next load
144 if (pending_queue.empty()) {
145 continue;
146 }
147 // Pull work from queue
148 WorkerParams work = std::move(pending_queue.front());
149 pending_queue.pop_front();
150
151 lock.unlock();
152
153 if (work.backend == AsyncShaders::Backend::OpenGL ||
154 work.backend == AsyncShaders::Backend::GLASM) {
155 const ShaderIR ir(work.code, work.main_offset, work.compiler_settings, work.registry);
156 const auto scope = context->Acquire();
157 auto program =
158 OpenGL::BuildShader(work.device, work.shader_type, work.uid, ir, work.registry);
159 Result result{};
160 result.backend = work.backend;
161 result.cpu_address = work.cpu_address;
162 result.uid = work.uid;
163 result.code = std::move(work.code);
164 result.code_b = std::move(work.code_b);
165 result.shader_type = work.shader_type;
166
167 if (work.backend == AsyncShaders::Backend::OpenGL) {
168 result.program.opengl = std::move(program->source_program);
169 } else if (work.backend == AsyncShaders::Backend::GLASM) {
170 result.program.glasm = std::move(program->assembly_program);
171 }
172
173 {
174 std::unique_lock complete_lock(completed_mutex);
175 finished_work.push_back(std::move(result));
176 }
177 }
178 }
179}
180
181} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/async_shaders.h b/src/video_core/shader/async_shaders.h
new file mode 100644
index 000000000..2f5ee94ad
--- /dev/null
+++ b/src/video_core/shader/async_shaders.h
@@ -0,0 +1,109 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <condition_variable>
8#include <deque>
9#include <memory>
10#include <shared_mutex>
11#include <thread>
12#include "common/bit_field.h"
13#include "common/common_types.h"
14#include "video_core/renderer_opengl/gl_device.h"
15#include "video_core/renderer_opengl/gl_resource_manager.h"
16#include "video_core/renderer_opengl/gl_shader_decompiler.h"
17
18namespace Core::Frontend {
19class EmuWindow;
20class GraphicsContext;
21} // namespace Core::Frontend
22
23namespace Tegra {
24class GPU;
25}
26
27namespace VideoCommon::Shader {
28
29class AsyncShaders {
30public:
31 enum class Backend {
32 OpenGL,
33 GLASM,
34 };
35
36 struct ResultPrograms {
37 OpenGL::OGLProgram opengl;
38 OpenGL::OGLAssemblyProgram glasm;
39 };
40
41 struct Result {
42 u64 uid;
43 VAddr cpu_address;
44 Backend backend;
45 ResultPrograms program;
46 std::vector<u64> code;
47 std::vector<u64> code_b;
48 Tegra::Engines::ShaderType shader_type;
49 };
50
51 explicit AsyncShaders(Core::Frontend::EmuWindow& emu_window);
52 ~AsyncShaders();
53
54 /// Start up shader worker threads
55 void AllocateWorkers(std::size_t num_workers);
56
57 /// Clear the shader queue and kill all worker threads
58 void FreeWorkers();
59
60 // Force end all threads
61 void KillWorkers();
62
63 /// Check to see if any shaders have actually been compiled
64 bool HasCompletedWork();
65
66 /// Deduce if a shader can be build on another thread of MUST be built in sync. We cannot build
67 /// every shader async as some shaders are only built and executed once. We try to "guess" which
68 /// shader would be used only once
69 bool IsShaderAsync(const Tegra::GPU& gpu) const;
70
71 /// Pulls completed compiled shaders
72 std::vector<Result> GetCompletedWork();
73
74 void QueueOpenGLShader(const OpenGL::Device& device, Tegra::Engines::ShaderType shader_type,
75 u64 uid, std::vector<u64> code, std::vector<u64> code_b, u32 main_offset,
76 VideoCommon::Shader::CompilerSettings compiler_settings,
77 const VideoCommon::Shader::Registry& registry, VAddr cpu_addr);
78
79private:
80 void ShaderCompilerThread(Core::Frontend::GraphicsContext* context);
81
82 /// Check our worker queue to see if we have any work queued already
83 bool HasWorkQueued();
84
85 struct WorkerParams {
86 AsyncShaders::Backend backend;
87 OpenGL::Device device;
88 Tegra::Engines::ShaderType shader_type;
89 u64 uid;
90 std::vector<u64> code;
91 std::vector<u64> code_b;
92 u32 main_offset;
93 VideoCommon::Shader::CompilerSettings compiler_settings;
94 VideoCommon::Shader::Registry registry;
95 VAddr cpu_address;
96 };
97
98 std::condition_variable cv;
99 std::mutex queue_mutex;
100 std::shared_mutex completed_mutex;
101 std::atomic<bool> is_thread_exiting{};
102 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> context_list;
103 std::vector<std::thread> worker_threads;
104 std::deque<WorkerParams> pending_queue;
105 std::vector<AsyncShaders::Result> finished_work;
106 Core::Frontend::EmuWindow& emu_window;
107};
108
109} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp
index 07778dc3e..e75ca4fdb 100644
--- a/src/video_core/shader/decode/image.cpp
+++ b/src/video_core/shader/decode/image.cpp
@@ -31,11 +31,11 @@ ComponentType GetComponentType(Tegra::Engines::SamplerDescriptor descriptor,
31 std::size_t component) { 31 std::size_t component) {
32 const TextureFormat format{descriptor.format}; 32 const TextureFormat format{descriptor.format};
33 switch (format) { 33 switch (format) {
34 case TextureFormat::R16_G16_B16_A16: 34 case TextureFormat::R16G16B16A16:
35 case TextureFormat::R32_G32_B32_A32: 35 case TextureFormat::R32G32B32A32:
36 case TextureFormat::R32_G32_B32: 36 case TextureFormat::R32G32B32:
37 case TextureFormat::R32_G32: 37 case TextureFormat::R32G32:
38 case TextureFormat::R16_G16: 38 case TextureFormat::R16G16:
39 case TextureFormat::R32: 39 case TextureFormat::R32:
40 case TextureFormat::R16: 40 case TextureFormat::R16:
41 case TextureFormat::R8: 41 case TextureFormat::R8:
@@ -97,7 +97,7 @@ ComponentType GetComponentType(Tegra::Engines::SamplerDescriptor descriptor,
97 break; 97 break;
98 case TextureFormat::B5G6R5: 98 case TextureFormat::B5G6R5:
99 case TextureFormat::B6G5R5: 99 case TextureFormat::B6G5R5:
100 case TextureFormat::BF10GF11RF11: 100 case TextureFormat::B10G11R11:
101 if (component == 0) { 101 if (component == 0) {
102 return descriptor.b_type; 102 return descriptor.b_type;
103 } 103 }
@@ -108,9 +108,9 @@ ComponentType GetComponentType(Tegra::Engines::SamplerDescriptor descriptor,
108 return descriptor.r_type; 108 return descriptor.r_type;
109 } 109 }
110 break; 110 break;
111 case TextureFormat::G8R24: 111 case TextureFormat::R24G8:
112 case TextureFormat::G24R8: 112 case TextureFormat::R8G24:
113 case TextureFormat::G8R8: 113 case TextureFormat::R8G8:
114 case TextureFormat::G4R4: 114 case TextureFormat::G4R4:
115 if (component == 0) { 115 if (component == 0) {
116 return descriptor.g_type; 116 return descriptor.g_type;
@@ -137,15 +137,15 @@ bool IsComponentEnabled(std::size_t component_mask, std::size_t component) {
137 137
138u32 GetComponentSize(TextureFormat format, std::size_t component) { 138u32 GetComponentSize(TextureFormat format, std::size_t component) {
139 switch (format) { 139 switch (format) {
140 case TextureFormat::R32_G32_B32_A32: 140 case TextureFormat::R32G32B32A32:
141 return 32; 141 return 32;
142 case TextureFormat::R16_G16_B16_A16: 142 case TextureFormat::R16G16B16A16:
143 return 16; 143 return 16;
144 case TextureFormat::R32_G32_B32: 144 case TextureFormat::R32G32B32:
145 return component <= 2 ? 32 : 0; 145 return component <= 2 ? 32 : 0;
146 case TextureFormat::R32_G32: 146 case TextureFormat::R32G32:
147 return component <= 1 ? 32 : 0; 147 return component <= 1 ? 32 : 0;
148 case TextureFormat::R16_G16: 148 case TextureFormat::R16G16:
149 return component <= 1 ? 16 : 0; 149 return component <= 1 ? 16 : 0;
150 case TextureFormat::R32: 150 case TextureFormat::R32:
151 return component == 0 ? 32 : 0; 151 return component == 0 ? 32 : 0;
@@ -192,7 +192,7 @@ u32 GetComponentSize(TextureFormat format, std::size_t component) {
192 return 6; 192 return 6;
193 } 193 }
194 return 0; 194 return 0;
195 case TextureFormat::BF10GF11RF11: 195 case TextureFormat::B10G11R11:
196 if (component == 1 || component == 2) { 196 if (component == 1 || component == 2) {
197 return 11; 197 return 11;
198 } 198 }
@@ -200,7 +200,7 @@ u32 GetComponentSize(TextureFormat format, std::size_t component) {
200 return 10; 200 return 10;
201 } 201 }
202 return 0; 202 return 0;
203 case TextureFormat::G8R24: 203 case TextureFormat::R24G8:
204 if (component == 0) { 204 if (component == 0) {
205 return 8; 205 return 8;
206 } 206 }
@@ -208,7 +208,7 @@ u32 GetComponentSize(TextureFormat format, std::size_t component) {
208 return 24; 208 return 24;
209 } 209 }
210 return 0; 210 return 0;
211 case TextureFormat::G24R8: 211 case TextureFormat::R8G24:
212 if (component == 0) { 212 if (component == 0) {
213 return 8; 213 return 8;
214 } 214 }
@@ -216,7 +216,7 @@ u32 GetComponentSize(TextureFormat format, std::size_t component) {
216 return 24; 216 return 24;
217 } 217 }
218 return 0; 218 return 0;
219 case TextureFormat::G8R8: 219 case TextureFormat::R8G8:
220 return (component == 0 || component == 1) ? 8 : 0; 220 return (component == 0 || component == 1) ? 8 : 0;
221 case TextureFormat::G4R4: 221 case TextureFormat::G4R4:
222 return (component == 0 || component == 1) ? 4 : 0; 222 return (component == 0 || component == 1) ? 4 : 0;
@@ -231,25 +231,25 @@ std::size_t GetImageComponentMask(TextureFormat format) {
231 constexpr u8 B = 0b0100; 231 constexpr u8 B = 0b0100;
232 constexpr u8 A = 0b1000; 232 constexpr u8 A = 0b1000;
233 switch (format) { 233 switch (format) {
234 case TextureFormat::R32_G32_B32_A32: 234 case TextureFormat::R32G32B32A32:
235 case TextureFormat::R16_G16_B16_A16: 235 case TextureFormat::R16G16B16A16:
236 case TextureFormat::A8R8G8B8: 236 case TextureFormat::A8R8G8B8:
237 case TextureFormat::A2B10G10R10: 237 case TextureFormat::A2B10G10R10:
238 case TextureFormat::A4B4G4R4: 238 case TextureFormat::A4B4G4R4:
239 case TextureFormat::A5B5G5R1: 239 case TextureFormat::A5B5G5R1:
240 case TextureFormat::A1B5G5R5: 240 case TextureFormat::A1B5G5R5:
241 return std::size_t{R | G | B | A}; 241 return std::size_t{R | G | B | A};
242 case TextureFormat::R32_G32_B32: 242 case TextureFormat::R32G32B32:
243 case TextureFormat::R32_B24G8: 243 case TextureFormat::R32_B24G8:
244 case TextureFormat::B5G6R5: 244 case TextureFormat::B5G6R5:
245 case TextureFormat::B6G5R5: 245 case TextureFormat::B6G5R5:
246 case TextureFormat::BF10GF11RF11: 246 case TextureFormat::B10G11R11:
247 return std::size_t{R | G | B}; 247 return std::size_t{R | G | B};
248 case TextureFormat::R32_G32: 248 case TextureFormat::R32G32:
249 case TextureFormat::R16_G16: 249 case TextureFormat::R16G16:
250 case TextureFormat::G8R24: 250 case TextureFormat::R24G8:
251 case TextureFormat::G24R8: 251 case TextureFormat::R8G24:
252 case TextureFormat::G8R8: 252 case TextureFormat::R8G8:
253 case TextureFormat::G4R4: 253 case TextureFormat::G4R4:
254 return std::size_t{R | G}; 254 return std::size_t{R | G};
255 case TextureFormat::R32: 255 case TextureFormat::R32:
diff --git a/src/video_core/shader_notify.cpp b/src/video_core/shader_notify.cpp
new file mode 100644
index 000000000..c3c71657d
--- /dev/null
+++ b/src/video_core/shader_notify.cpp
@@ -0,0 +1,42 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "video_core/shader_notify.h"
6
7using namespace std::chrono_literals;
8
9namespace VideoCore {
10namespace {
11constexpr auto UPDATE_TICK = 32ms;
12}
13
14ShaderNotify::ShaderNotify() = default;
15ShaderNotify::~ShaderNotify() = default;
16
17std::size_t ShaderNotify::GetShadersBuilding() {
18 const auto now = std::chrono::high_resolution_clock::now();
19 const auto diff = now - last_update;
20 if (diff > UPDATE_TICK) {
21 std::shared_lock lock(mutex);
22 last_updated_count = accurate_count;
23 }
24 return last_updated_count;
25}
26
27std::size_t ShaderNotify::GetShadersBuildingAccurate() {
28 std::shared_lock lock{mutex};
29 return accurate_count;
30}
31
32void ShaderNotify::MarkShaderComplete() {
33 std::unique_lock lock{mutex};
34 accurate_count--;
35}
36
37void ShaderNotify::MarkSharderBuilding() {
38 std::unique_lock lock{mutex};
39 accurate_count++;
40}
41
42} // namespace VideoCore
diff --git a/src/video_core/shader_notify.h b/src/video_core/shader_notify.h
new file mode 100644
index 000000000..a9c92d179
--- /dev/null
+++ b/src/video_core/shader_notify.h
@@ -0,0 +1,29 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <chrono>
8#include <shared_mutex>
9#include "common/common_types.h"
10
11namespace VideoCore {
12class ShaderNotify {
13public:
14 ShaderNotify();
15 ~ShaderNotify();
16
17 std::size_t GetShadersBuilding();
18 std::size_t GetShadersBuildingAccurate();
19
20 void MarkShaderComplete();
21 void MarkSharderBuilding();
22
23private:
24 std::size_t last_updated_count{};
25 std::size_t accurate_count{};
26 std::shared_mutex mutex;
27 std::chrono::high_resolution_clock::time_point last_update{};
28};
29} // namespace VideoCore
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index bbe93903c..1688267bb 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -74,117 +74,131 @@ bool SurfaceTargetIsArray(SurfaceTarget target) {
74 74
75PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) { 75PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
76 switch (format) { 76 switch (format) {
77 case Tegra::DepthFormat::S8_Z24_UNORM: 77 case Tegra::DepthFormat::S8_UINT_Z24_UNORM:
78 return PixelFormat::S8Z24; 78 return PixelFormat::S8_UINT_D24_UNORM;
79 case Tegra::DepthFormat::Z24_S8_UNORM: 79 case Tegra::DepthFormat::D24S8_UNORM:
80 return PixelFormat::Z24S8; 80 return PixelFormat::D24_UNORM_S8_UINT;
81 case Tegra::DepthFormat::Z32_FLOAT: 81 case Tegra::DepthFormat::D32_FLOAT:
82 return PixelFormat::Z32F; 82 return PixelFormat::D32_FLOAT;
83 case Tegra::DepthFormat::Z16_UNORM: 83 case Tegra::DepthFormat::D16_UNORM:
84 return PixelFormat::Z16; 84 return PixelFormat::D16_UNORM;
85 case Tegra::DepthFormat::Z32_S8_X24_FLOAT: 85 case Tegra::DepthFormat::D32_FLOAT_S8X24_UINT:
86 return PixelFormat::Z32FS8; 86 return PixelFormat::D32_FLOAT_S8_UINT;
87 default: 87 default:
88 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); 88 UNIMPLEMENTED_MSG("Unimplemented format={}", static_cast<u32>(format));
89 UNREACHABLE(); 89 return PixelFormat::S8_UINT_D24_UNORM;
90 return PixelFormat::S8Z24;
91 } 90 }
92} 91}
93 92
94PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) { 93PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
95 switch (format) { 94 switch (format) {
96 case Tegra::RenderTargetFormat::RGBA8_SRGB: 95 case Tegra::RenderTargetFormat::R32B32G32A32_FLOAT:
97 return PixelFormat::RGBA8_SRGB; 96 return PixelFormat::R32G32B32A32_FLOAT;
98 case Tegra::RenderTargetFormat::RGBA8_UNORM: 97 case Tegra::RenderTargetFormat::R32G32B32A32_SINT:
99 return PixelFormat::ABGR8U; 98 return PixelFormat::R32G32B32A32_SINT;
100 case Tegra::RenderTargetFormat::RGBA8_SNORM: 99 case Tegra::RenderTargetFormat::R32G32B32A32_UINT:
101 return PixelFormat::ABGR8S; 100 return PixelFormat::R32G32B32A32_UINT;
102 case Tegra::RenderTargetFormat::RGBA8_UINT: 101 case Tegra::RenderTargetFormat::R16G16B16A16_UNORM:
103 return PixelFormat::ABGR8UI; 102 return PixelFormat::R16G16B16A16_UNORM;
104 case Tegra::RenderTargetFormat::BGRA8_SRGB: 103 case Tegra::RenderTargetFormat::R16G16B16A16_SNORM:
105 return PixelFormat::BGRA8_SRGB; 104 return PixelFormat::R16G16B16A16_SNORM;
106 case Tegra::RenderTargetFormat::BGRA8_UNORM: 105 case Tegra::RenderTargetFormat::R16G16B16A16_SINT:
107 return PixelFormat::BGRA8; 106 return PixelFormat::R16G16B16A16_SINT;
108 case Tegra::RenderTargetFormat::RGB10_A2_UNORM: 107 case Tegra::RenderTargetFormat::R16G16B16A16_UINT:
109 return PixelFormat::A2B10G10R10U; 108 return PixelFormat::R16G16B16A16_UINT;
110 case Tegra::RenderTargetFormat::RGBA16_FLOAT: 109 case Tegra::RenderTargetFormat::R16G16B16A16_FLOAT:
111 return PixelFormat::RGBA16F; 110 return PixelFormat::R16G16B16A16_FLOAT;
112 case Tegra::RenderTargetFormat::RGBA16_UNORM: 111 case Tegra::RenderTargetFormat::R32G32_FLOAT:
113 return PixelFormat::RGBA16U; 112 return PixelFormat::R32G32_FLOAT;
114 case Tegra::RenderTargetFormat::RGBA16_SNORM: 113 case Tegra::RenderTargetFormat::R32G32_SINT:
115 return PixelFormat::RGBA16S; 114 return PixelFormat::R32G32_SINT;
116 case Tegra::RenderTargetFormat::RGBA16_UINT: 115 case Tegra::RenderTargetFormat::R32G32_UINT:
117 return PixelFormat::RGBA16UI; 116 return PixelFormat::R32G32_UINT;
118 case Tegra::RenderTargetFormat::RGBA32_FLOAT: 117 case Tegra::RenderTargetFormat::R16G16B16X16_FLOAT:
119 return PixelFormat::RGBA32F; 118 return PixelFormat::R16G16B16X16_FLOAT;
120 case Tegra::RenderTargetFormat::RG32_FLOAT: 119 case Tegra::RenderTargetFormat::B8G8R8A8_UNORM:
121 return PixelFormat::RG32F; 120 return PixelFormat::B8G8R8A8_UNORM;
122 case Tegra::RenderTargetFormat::R11G11B10_FLOAT: 121 case Tegra::RenderTargetFormat::B8G8R8A8_SRGB:
123 return PixelFormat::R11FG11FB10F; 122 return PixelFormat::B8G8R8A8_SRGB;
124 case Tegra::RenderTargetFormat::B5G6R5_UNORM: 123 case Tegra::RenderTargetFormat::A2B10G10R10_UNORM:
125 return PixelFormat::B5G6R5U; 124 return PixelFormat::A2B10G10R10_UNORM;
126 case Tegra::RenderTargetFormat::BGR5A1_UNORM: 125 case Tegra::RenderTargetFormat::A2B10G10R10_UINT:
127 return PixelFormat::A1B5G5R5U; 126 return PixelFormat::A2B10G10R10_UINT;
128 case Tegra::RenderTargetFormat::RGBA32_UINT: 127 case Tegra::RenderTargetFormat::A8B8G8R8_UNORM:
129 return PixelFormat::RGBA32UI; 128 return PixelFormat::A8B8G8R8_UNORM;
130 case Tegra::RenderTargetFormat::R8_UNORM: 129 case Tegra::RenderTargetFormat::A8B8G8R8_SRGB:
131 return PixelFormat::R8U; 130 return PixelFormat::A8B8G8R8_SRGB;
132 case Tegra::RenderTargetFormat::R8_UINT: 131 case Tegra::RenderTargetFormat::A8B8G8R8_SNORM:
133 return PixelFormat::R8UI; 132 return PixelFormat::A8B8G8R8_SNORM;
134 case Tegra::RenderTargetFormat::RG16_FLOAT: 133 case Tegra::RenderTargetFormat::A8B8G8R8_SINT:
135 return PixelFormat::RG16F; 134 return PixelFormat::A8B8G8R8_SINT;
136 case Tegra::RenderTargetFormat::RG16_UINT: 135 case Tegra::RenderTargetFormat::A8B8G8R8_UINT:
137 return PixelFormat::RG16UI; 136 return PixelFormat::A8B8G8R8_UINT;
138 case Tegra::RenderTargetFormat::RG16_SINT: 137 case Tegra::RenderTargetFormat::R16G16_UNORM:
139 return PixelFormat::RG16I; 138 return PixelFormat::R16G16_UNORM;
140 case Tegra::RenderTargetFormat::RG16_UNORM: 139 case Tegra::RenderTargetFormat::R16G16_SNORM:
141 return PixelFormat::RG16; 140 return PixelFormat::R16G16_SNORM;
142 case Tegra::RenderTargetFormat::RG16_SNORM: 141 case Tegra::RenderTargetFormat::R16G16_SINT:
143 return PixelFormat::RG16S; 142 return PixelFormat::R16G16_SINT;
144 case Tegra::RenderTargetFormat::RG8_UNORM: 143 case Tegra::RenderTargetFormat::R16G16_UINT:
145 return PixelFormat::RG8U; 144 return PixelFormat::R16G16_UINT;
146 case Tegra::RenderTargetFormat::RG8_SNORM: 145 case Tegra::RenderTargetFormat::R16G16_FLOAT:
147 return PixelFormat::RG8S; 146 return PixelFormat::R16G16_FLOAT;
148 case Tegra::RenderTargetFormat::RG8_UINT: 147 case Tegra::RenderTargetFormat::B10G11R11_FLOAT:
149 return PixelFormat::RG8UI; 148 return PixelFormat::B10G11R11_FLOAT;
150 case Tegra::RenderTargetFormat::R16_FLOAT: 149 case Tegra::RenderTargetFormat::R32_SINT:
151 return PixelFormat::R16F; 150 return PixelFormat::R32_SINT;
151 case Tegra::RenderTargetFormat::R32_UINT:
152 return PixelFormat::R32_UINT;
153 case Tegra::RenderTargetFormat::R32_FLOAT:
154 return PixelFormat::R32_FLOAT;
155 case Tegra::RenderTargetFormat::R5G6B5_UNORM:
156 return PixelFormat::R5G6B5_UNORM;
157 case Tegra::RenderTargetFormat::A1R5G5B5_UNORM:
158 return PixelFormat::A1R5G5B5_UNORM;
159 case Tegra::RenderTargetFormat::R8G8_UNORM:
160 return PixelFormat::R8G8_UNORM;
161 case Tegra::RenderTargetFormat::R8G8_SNORM:
162 return PixelFormat::R8G8_SNORM;
163 case Tegra::RenderTargetFormat::R8G8_SINT:
164 return PixelFormat::R8G8_SINT;
165 case Tegra::RenderTargetFormat::R8G8_UINT:
166 return PixelFormat::R8G8_UINT;
152 case Tegra::RenderTargetFormat::R16_UNORM: 167 case Tegra::RenderTargetFormat::R16_UNORM:
153 return PixelFormat::R16U; 168 return PixelFormat::R16_UNORM;
154 case Tegra::RenderTargetFormat::R16_SNORM: 169 case Tegra::RenderTargetFormat::R16_SNORM:
155 return PixelFormat::R16S; 170 return PixelFormat::R16_SNORM;
156 case Tegra::RenderTargetFormat::R16_UINT:
157 return PixelFormat::R16UI;
158 case Tegra::RenderTargetFormat::R16_SINT: 171 case Tegra::RenderTargetFormat::R16_SINT:
159 return PixelFormat::R16I; 172 return PixelFormat::R16_SINT;
160 case Tegra::RenderTargetFormat::R32_FLOAT: 173 case Tegra::RenderTargetFormat::R16_UINT:
161 return PixelFormat::R32F; 174 return PixelFormat::R16_UINT;
162 case Tegra::RenderTargetFormat::R32_SINT: 175 case Tegra::RenderTargetFormat::R16_FLOAT:
163 return PixelFormat::R32I; 176 return PixelFormat::R16_FLOAT;
164 case Tegra::RenderTargetFormat::R32_UINT: 177 case Tegra::RenderTargetFormat::R8_UNORM:
165 return PixelFormat::R32UI; 178 return PixelFormat::R8_UNORM;
166 case Tegra::RenderTargetFormat::RG32_UINT: 179 case Tegra::RenderTargetFormat::R8_SNORM:
167 return PixelFormat::RG32UI; 180 return PixelFormat::R8_SNORM;
168 case Tegra::RenderTargetFormat::RGBX16_FLOAT: 181 case Tegra::RenderTargetFormat::R8_SINT:
169 return PixelFormat::RGBX16F; 182 return PixelFormat::R8_SINT;
183 case Tegra::RenderTargetFormat::R8_UINT:
184 return PixelFormat::R8_UINT;
170 default: 185 default:
171 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); 186 UNIMPLEMENTED_MSG("Unimplemented format={}", static_cast<int>(format));
172 UNREACHABLE(); 187 return PixelFormat::A8B8G8R8_UNORM;
173 return PixelFormat::RGBA8_SRGB;
174 } 188 }
175} 189}
176 190
177PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) { 191PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
178 switch (format) { 192 switch (format) {
179 case Tegra::FramebufferConfig::PixelFormat::ABGR8: 193 case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM:
180 return PixelFormat::ABGR8U; 194 return PixelFormat::A8B8G8R8_UNORM;
181 case Tegra::FramebufferConfig::PixelFormat::RGB565: 195 case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM:
182 return PixelFormat::B5G6R5U; 196 return PixelFormat::R5G6B5_UNORM;
183 case Tegra::FramebufferConfig::PixelFormat::BGRA8: 197 case Tegra::FramebufferConfig::PixelFormat::B8G8R8A8_UNORM:
184 return PixelFormat::BGRA8; 198 return PixelFormat::B8G8R8A8_UNORM;
185 default: 199 default:
186 UNIMPLEMENTED_MSG("Unimplemented format={}", static_cast<u32>(format)); 200 UNIMPLEMENTED_MSG("Unimplemented format={}", static_cast<u32>(format));
187 return PixelFormat::ABGR8U; 201 return PixelFormat::A8B8G8R8_UNORM;
188 } 202 }
189} 203}
190 204
@@ -212,27 +226,27 @@ SurfaceType GetFormatType(PixelFormat pixel_format) {
212 226
213bool IsPixelFormatASTC(PixelFormat format) { 227bool IsPixelFormatASTC(PixelFormat format) {
214 switch (format) { 228 switch (format) {
215 case PixelFormat::ASTC_2D_4X4: 229 case PixelFormat::ASTC_2D_4X4_UNORM:
216 case PixelFormat::ASTC_2D_5X4: 230 case PixelFormat::ASTC_2D_5X4_UNORM:
217 case PixelFormat::ASTC_2D_5X5: 231 case PixelFormat::ASTC_2D_5X5_UNORM:
218 case PixelFormat::ASTC_2D_8X8: 232 case PixelFormat::ASTC_2D_8X8_UNORM:
219 case PixelFormat::ASTC_2D_8X5: 233 case PixelFormat::ASTC_2D_8X5_UNORM:
220 case PixelFormat::ASTC_2D_4X4_SRGB: 234 case PixelFormat::ASTC_2D_4X4_SRGB:
221 case PixelFormat::ASTC_2D_5X4_SRGB: 235 case PixelFormat::ASTC_2D_5X4_SRGB:
222 case PixelFormat::ASTC_2D_5X5_SRGB: 236 case PixelFormat::ASTC_2D_5X5_SRGB:
223 case PixelFormat::ASTC_2D_8X8_SRGB: 237 case PixelFormat::ASTC_2D_8X8_SRGB:
224 case PixelFormat::ASTC_2D_8X5_SRGB: 238 case PixelFormat::ASTC_2D_8X5_SRGB:
225 case PixelFormat::ASTC_2D_10X8: 239 case PixelFormat::ASTC_2D_10X8_UNORM:
226 case PixelFormat::ASTC_2D_10X8_SRGB: 240 case PixelFormat::ASTC_2D_10X8_SRGB:
227 case PixelFormat::ASTC_2D_6X6: 241 case PixelFormat::ASTC_2D_6X6_UNORM:
228 case PixelFormat::ASTC_2D_6X6_SRGB: 242 case PixelFormat::ASTC_2D_6X6_SRGB:
229 case PixelFormat::ASTC_2D_10X10: 243 case PixelFormat::ASTC_2D_10X10_UNORM:
230 case PixelFormat::ASTC_2D_10X10_SRGB: 244 case PixelFormat::ASTC_2D_10X10_SRGB:
231 case PixelFormat::ASTC_2D_12X12: 245 case PixelFormat::ASTC_2D_12X12_UNORM:
232 case PixelFormat::ASTC_2D_12X12_SRGB: 246 case PixelFormat::ASTC_2D_12X12_SRGB:
233 case PixelFormat::ASTC_2D_8X6: 247 case PixelFormat::ASTC_2D_8X6_UNORM:
234 case PixelFormat::ASTC_2D_8X6_SRGB: 248 case PixelFormat::ASTC_2D_8X6_SRGB:
235 case PixelFormat::ASTC_2D_6X5: 249 case PixelFormat::ASTC_2D_6X5_UNORM:
236 case PixelFormat::ASTC_2D_6X5_SRGB: 250 case PixelFormat::ASTC_2D_6X5_SRGB:
237 return true; 251 return true;
238 default: 252 default:
@@ -242,12 +256,12 @@ bool IsPixelFormatASTC(PixelFormat format) {
242 256
243bool IsPixelFormatSRGB(PixelFormat format) { 257bool IsPixelFormatSRGB(PixelFormat format) {
244 switch (format) { 258 switch (format) {
245 case PixelFormat::RGBA8_SRGB: 259 case PixelFormat::A8B8G8R8_SRGB:
246 case PixelFormat::BGRA8_SRGB: 260 case PixelFormat::B8G8R8A8_SRGB:
247 case PixelFormat::DXT1_SRGB: 261 case PixelFormat::BC1_RGBA_SRGB:
248 case PixelFormat::DXT23_SRGB: 262 case PixelFormat::BC2_SRGB:
249 case PixelFormat::DXT45_SRGB: 263 case PixelFormat::BC3_SRGB:
250 case PixelFormat::BC7U_SRGB: 264 case PixelFormat::BC7_SRGB:
251 case PixelFormat::ASTC_2D_4X4_SRGB: 265 case PixelFormat::ASTC_2D_4X4_SRGB:
252 case PixelFormat::ASTC_2D_8X8_SRGB: 266 case PixelFormat::ASTC_2D_8X8_SRGB:
253 case PixelFormat::ASTC_2D_8X5_SRGB: 267 case PixelFormat::ASTC_2D_8X5_SRGB:
@@ -269,25 +283,4 @@ std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
269 return {GetDefaultBlockWidth(format), GetDefaultBlockHeight(format)}; 283 return {GetDefaultBlockWidth(format), GetDefaultBlockHeight(format)};
270} 284}
271 285
272bool IsFormatBCn(PixelFormat format) {
273 switch (format) {
274 case PixelFormat::DXT1:
275 case PixelFormat::DXT23:
276 case PixelFormat::DXT45:
277 case PixelFormat::DXN1:
278 case PixelFormat::DXN2SNORM:
279 case PixelFormat::DXN2UNORM:
280 case PixelFormat::BC7U:
281 case PixelFormat::BC6H_UF16:
282 case PixelFormat::BC6H_SF16:
283 case PixelFormat::DXT1_SRGB:
284 case PixelFormat::DXT23_SRGB:
285 case PixelFormat::DXT45_SRGB:
286 case PixelFormat::BC7U_SRGB:
287 return true;
288 default:
289 return false;
290 }
291}
292
293} // namespace VideoCore::Surface 286} // namespace VideoCore::Surface
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 6da6a1b97..cfd12fa61 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -15,94 +15,105 @@
15namespace VideoCore::Surface { 15namespace VideoCore::Surface {
16 16
17enum class PixelFormat { 17enum class PixelFormat {
18 ABGR8U = 0, 18 A8B8G8R8_UNORM,
19 ABGR8S = 1, 19 A8B8G8R8_SNORM,
20 ABGR8UI = 2, 20 A8B8G8R8_SINT,
21 B5G6R5U = 3, 21 A8B8G8R8_UINT,
22 A2B10G10R10U = 4, 22 R5G6B5_UNORM,
23 A1B5G5R5U = 5, 23 B5G6R5_UNORM,
24 R8U = 6, 24 A1R5G5B5_UNORM,
25 R8UI = 7, 25 A2B10G10R10_UNORM,
26 RGBA16F = 8, 26 A2B10G10R10_UINT,
27 RGBA16U = 9, 27 A1B5G5R5_UNORM,
28 RGBA16S = 10, 28 R8_UNORM,
29 RGBA16UI = 11, 29 R8_SNORM,
30 R11FG11FB10F = 12, 30 R8_SINT,
31 RGBA32UI = 13, 31 R8_UINT,
32 DXT1 = 14, 32 R16G16B16A16_FLOAT,
33 DXT23 = 15, 33 R16G16B16A16_UNORM,
34 DXT45 = 16, 34 R16G16B16A16_SNORM,
35 DXN1 = 17, // This is also known as BC4 35 R16G16B16A16_SINT,
36 DXN2UNORM = 18, 36 R16G16B16A16_UINT,
37 DXN2SNORM = 19, 37 B10G11R11_FLOAT,
38 BC7U = 20, 38 R32G32B32A32_UINT,
39 BC6H_UF16 = 21, 39 BC1_RGBA_UNORM,
40 BC6H_SF16 = 22, 40 BC2_UNORM,
41 ASTC_2D_4X4 = 23, 41 BC3_UNORM,
42 BGRA8 = 24, 42 BC4_UNORM,
43 RGBA32F = 25, 43 BC4_SNORM,
44 RG32F = 26, 44 BC5_UNORM,
45 R32F = 27, 45 BC5_SNORM,
46 R16F = 28, 46 BC7_UNORM,
47 R16U = 29, 47 BC6H_UFLOAT,
48 R16S = 30, 48 BC6H_SFLOAT,
49 R16UI = 31, 49 ASTC_2D_4X4_UNORM,
50 R16I = 32, 50 B8G8R8A8_UNORM,
51 RG16 = 33, 51 R32G32B32A32_FLOAT,
52 RG16F = 34, 52 R32G32B32A32_SINT,
53 RG16UI = 35, 53 R32G32_FLOAT,
54 RG16I = 36, 54 R32G32_SINT,
55 RG16S = 37, 55 R32_FLOAT,
56 RGB32F = 38, 56 R16_FLOAT,
57 RGBA8_SRGB = 39, 57 R16_UNORM,
58 RG8U = 40, 58 R16_SNORM,
59 RG8S = 41, 59 R16_UINT,
60 RG8UI = 42, 60 R16_SINT,
61 RG32UI = 43, 61 R16G16_UNORM,
62 RGBX16F = 44, 62 R16G16_FLOAT,
63 R32UI = 45, 63 R16G16_UINT,
64 R32I = 46, 64 R16G16_SINT,
65 ASTC_2D_8X8 = 47, 65 R16G16_SNORM,
66 ASTC_2D_8X5 = 48, 66 R32G32B32_FLOAT,
67 ASTC_2D_5X4 = 49, 67 A8B8G8R8_SRGB,
68 BGRA8_SRGB = 50, 68 R8G8_UNORM,
69 DXT1_SRGB = 51, 69 R8G8_SNORM,
70 DXT23_SRGB = 52, 70 R8G8_SINT,
71 DXT45_SRGB = 53, 71 R8G8_UINT,
72 BC7U_SRGB = 54, 72 R32G32_UINT,
73 R4G4B4A4U = 55, 73 R16G16B16X16_FLOAT,
74 ASTC_2D_4X4_SRGB = 56, 74 R32_UINT,
75 ASTC_2D_8X8_SRGB = 57, 75 R32_SINT,
76 ASTC_2D_8X5_SRGB = 58, 76 ASTC_2D_8X8_UNORM,
77 ASTC_2D_5X4_SRGB = 59, 77 ASTC_2D_8X5_UNORM,
78 ASTC_2D_5X5 = 60, 78 ASTC_2D_5X4_UNORM,
79 ASTC_2D_5X5_SRGB = 61, 79 B8G8R8A8_SRGB,
80 ASTC_2D_10X8 = 62, 80 BC1_RGBA_SRGB,
81 ASTC_2D_10X8_SRGB = 63, 81 BC2_SRGB,
82 ASTC_2D_6X6 = 64, 82 BC3_SRGB,
83 ASTC_2D_6X6_SRGB = 65, 83 BC7_SRGB,
84 ASTC_2D_10X10 = 66, 84 A4B4G4R4_UNORM,
85 ASTC_2D_10X10_SRGB = 67, 85 ASTC_2D_4X4_SRGB,
86 ASTC_2D_12X12 = 68, 86 ASTC_2D_8X8_SRGB,
87 ASTC_2D_12X12_SRGB = 69, 87 ASTC_2D_8X5_SRGB,
88 ASTC_2D_8X6 = 70, 88 ASTC_2D_5X4_SRGB,
89 ASTC_2D_8X6_SRGB = 71, 89 ASTC_2D_5X5_UNORM,
90 ASTC_2D_6X5 = 72, 90 ASTC_2D_5X5_SRGB,
91 ASTC_2D_6X5_SRGB = 73, 91 ASTC_2D_10X8_UNORM,
92 E5B9G9R9F = 74, 92 ASTC_2D_10X8_SRGB,
93 ASTC_2D_6X6_UNORM,
94 ASTC_2D_6X6_SRGB,
95 ASTC_2D_10X10_UNORM,
96 ASTC_2D_10X10_SRGB,
97 ASTC_2D_12X12_UNORM,
98 ASTC_2D_12X12_SRGB,
99 ASTC_2D_8X6_UNORM,
100 ASTC_2D_8X6_SRGB,
101 ASTC_2D_6X5_UNORM,
102 ASTC_2D_6X5_SRGB,
103 E5B9G9R9_FLOAT,
93 104
94 MaxColorFormat, 105 MaxColorFormat,
95 106
96 // Depth formats 107 // Depth formats
97 Z32F = 75, 108 D32_FLOAT = MaxColorFormat,
98 Z16 = 76, 109 D16_UNORM,
99 110
100 MaxDepthFormat, 111 MaxDepthFormat,
101 112
102 // DepthStencil formats 113 // DepthStencil formats
103 Z24S8 = 77, 114 D24_UNORM_S8_UINT = MaxDepthFormat,
104 S8Z24 = 78, 115 S8_UINT_D24_UNORM,
105 Z32FS8 = 79, 116 D32_FLOAT_S8_UINT,
106 117
107 MaxDepthStencilFormat, 118 MaxDepthStencilFormat,
108 119
@@ -130,86 +141,97 @@ enum class SurfaceTarget {
130}; 141};
131 142
132constexpr std::array<u32, MaxPixelFormat> compression_factor_shift_table = {{ 143constexpr std::array<u32, MaxPixelFormat> compression_factor_shift_table = {{
133 0, // ABGR8U 144 0, // A8B8G8R8_UNORM
134 0, // ABGR8S 145 0, // A8B8G8R8_SNORM
135 0, // ABGR8UI 146 0, // A8B8G8R8_SINT
136 0, // B5G6R5U 147 0, // A8B8G8R8_UINT
137 0, // A2B10G10R10U 148 0, // R5G6B5_UNORM
138 0, // A1B5G5R5U 149 0, // B5G6R5_UNORM
139 0, // R8U 150 0, // A1R5G5B5_UNORM
140 0, // R8UI 151 0, // A2B10G10R10_UNORM
141 0, // RGBA16F 152 0, // A2B10G10R10_UINT
142 0, // RGBA16U 153 0, // A1B5G5R5_UNORM
143 0, // RGBA16S 154 0, // R8_UNORM
144 0, // RGBA16UI 155 0, // R8_SNORM
145 0, // R11FG11FB10F 156 0, // R8_SINT
146 0, // RGBA32UI 157 0, // R8_UINT
147 2, // DXT1 158 0, // R16G16B16A16_FLOAT
148 2, // DXT23 159 0, // R16G16B16A16_UNORM
149 2, // DXT45 160 0, // R16G16B16A16_SNORM
150 2, // DXN1 161 0, // R16G16B16A16_SINT
151 2, // DXN2UNORM 162 0, // R16G16B16A16_UINT
152 2, // DXN2SNORM 163 0, // B10G11R11_FLOAT
153 2, // BC7U 164 0, // R32G32B32A32_UINT
154 2, // BC6H_UF16 165 2, // BC1_RGBA_UNORM
155 2, // BC6H_SF16 166 2, // BC2_UNORM
156 2, // ASTC_2D_4X4 167 2, // BC3_UNORM
157 0, // BGRA8 168 2, // BC4_UNORM
158 0, // RGBA32F 169 2, // BC4_SNORM
159 0, // RG32F 170 2, // BC5_UNORM
160 0, // R32F 171 2, // BC5_SNORM
161 0, // R16F 172 2, // BC7_UNORM
162 0, // R16U 173 2, // BC6H_UFLOAT
163 0, // R16S 174 2, // BC6H_SFLOAT
164 0, // R16UI 175 2, // ASTC_2D_4X4_UNORM
165 0, // R16I 176 0, // B8G8R8A8_UNORM
166 0, // RG16 177 0, // R32G32B32A32_FLOAT
167 0, // RG16F 178 0, // R32G32B32A32_SINT
168 0, // RG16UI 179 0, // R32G32_FLOAT
169 0, // RG16I 180 0, // R32G32_SINT
170 0, // RG16S 181 0, // R32_FLOAT
171 0, // RGB32F 182 0, // R16_FLOAT
172 0, // RGBA8_SRGB 183 0, // R16_UNORM
173 0, // RG8U 184 0, // R16_SNORM
174 0, // RG8S 185 0, // R16_UINT
175 0, // RG8UI 186 0, // R16_SINT
176 0, // RG32UI 187 0, // R16G16_UNORM
177 0, // RGBX16F 188 0, // R16G16_FLOAT
178 0, // R32UI 189 0, // R16G16_UINT
179 0, // R32I 190 0, // R16G16_SINT
180 2, // ASTC_2D_8X8 191 0, // R16G16_SNORM
181 2, // ASTC_2D_8X5 192 0, // R32G32B32_FLOAT
182 2, // ASTC_2D_5X4 193 0, // A8B8G8R8_SRGB
183 0, // BGRA8_SRGB 194 0, // R8G8_UNORM
184 2, // DXT1_SRGB 195 0, // R8G8_SNORM
185 2, // DXT23_SRGB 196 0, // R8G8_SINT
186 2, // DXT45_SRGB 197 0, // R8G8_UINT
187 2, // BC7U_SRGB 198 0, // R32G32_UINT
188 0, // R4G4B4A4U 199 0, // R16G16B16X16_FLOAT
200 0, // R32_UINT
201 0, // R32_SINT
202 2, // ASTC_2D_8X8_UNORM
203 2, // ASTC_2D_8X5_UNORM
204 2, // ASTC_2D_5X4_UNORM
205 0, // B8G8R8A8_SRGB
206 2, // BC1_RGBA_SRGB
207 2, // BC2_SRGB
208 2, // BC3_SRGB
209 2, // BC7_SRGB
210 0, // A4B4G4R4_UNORM
189 2, // ASTC_2D_4X4_SRGB 211 2, // ASTC_2D_4X4_SRGB
190 2, // ASTC_2D_8X8_SRGB 212 2, // ASTC_2D_8X8_SRGB
191 2, // ASTC_2D_8X5_SRGB 213 2, // ASTC_2D_8X5_SRGB
192 2, // ASTC_2D_5X4_SRGB 214 2, // ASTC_2D_5X4_SRGB
193 2, // ASTC_2D_5X5 215 2, // ASTC_2D_5X5_UNORM
194 2, // ASTC_2D_5X5_SRGB 216 2, // ASTC_2D_5X5_SRGB
195 2, // ASTC_2D_10X8 217 2, // ASTC_2D_10X8_UNORM
196 2, // ASTC_2D_10X8_SRGB 218 2, // ASTC_2D_10X8_SRGB
197 2, // ASTC_2D_6X6 219 2, // ASTC_2D_6X6_UNORM
198 2, // ASTC_2D_6X6_SRGB 220 2, // ASTC_2D_6X6_SRGB
199 2, // ASTC_2D_10X10 221 2, // ASTC_2D_10X10_UNORM
200 2, // ASTC_2D_10X10_SRGB 222 2, // ASTC_2D_10X10_SRGB
201 2, // ASTC_2D_12X12 223 2, // ASTC_2D_12X12_UNORM
202 2, // ASTC_2D_12X12_SRGB 224 2, // ASTC_2D_12X12_SRGB
203 2, // ASTC_2D_8X6 225 2, // ASTC_2D_8X6_UNORM
204 2, // ASTC_2D_8X6_SRGB 226 2, // ASTC_2D_8X6_SRGB
205 2, // ASTC_2D_6X5 227 2, // ASTC_2D_6X5_UNORM
206 2, // ASTC_2D_6X5_SRGB 228 2, // ASTC_2D_6X5_SRGB
207 0, // E5B9G9R9F 229 0, // E5B9G9R9_FLOAT
208 0, // Z32F 230 0, // D32_FLOAT
209 0, // Z16 231 0, // D16_UNORM
210 0, // Z24S8 232 0, // D24_UNORM_S8_UINT
211 0, // S8Z24 233 0, // S8_UINT_D24_UNORM
212 0, // Z32FS8 234 0, // D32_FLOAT_S8_UINT
213}}; 235}};
214 236
215/** 237/**
@@ -229,86 +251,97 @@ inline constexpr u32 GetCompressionFactor(PixelFormat format) {
229} 251}
230 252
231constexpr std::array<u32, MaxPixelFormat> block_width_table = {{ 253constexpr std::array<u32, MaxPixelFormat> block_width_table = {{
232 1, // ABGR8U 254 1, // A8B8G8R8_UNORM
233 1, // ABGR8S 255 1, // A8B8G8R8_SNORM
234 1, // ABGR8UI 256 1, // A8B8G8R8_SINT
235 1, // B5G6R5U 257 1, // A8B8G8R8_UINT
236 1, // A2B10G10R10U 258 1, // R5G6B5_UNORM
237 1, // A1B5G5R5U 259 1, // B5G6R5_UNORM
238 1, // R8U 260 1, // A1R5G5B5_UNORM
239 1, // R8UI 261 1, // A2B10G10R10_UNORM
240 1, // RGBA16F 262 1, // A2B10G10R10_UINT
241 1, // RGBA16U 263 1, // A1B5G5R5_UNORM
242 1, // RGBA16S 264 1, // R8_UNORM
243 1, // RGBA16UI 265 1, // R8_SNORM
244 1, // R11FG11FB10F 266 1, // R8_SINT
245 1, // RGBA32UI 267 1, // R8_UINT
246 4, // DXT1 268 1, // R16G16B16A16_FLOAT
247 4, // DXT23 269 1, // R16G16B16A16_UNORM
248 4, // DXT45 270 1, // R16G16B16A16_SNORM
249 4, // DXN1 271 1, // R16G16B16A16_SINT
250 4, // DXN2UNORM 272 1, // R16G16B16A16_UINT
251 4, // DXN2SNORM 273 1, // B10G11R11_FLOAT
252 4, // BC7U 274 1, // R32G32B32A32_UINT
253 4, // BC6H_UF16 275 4, // BC1_RGBA_UNORM
254 4, // BC6H_SF16 276 4, // BC2_UNORM
255 4, // ASTC_2D_4X4 277 4, // BC3_UNORM
256 1, // BGRA8 278 4, // BC4_UNORM
257 1, // RGBA32F 279 4, // BC4_SNORM
258 1, // RG32F 280 4, // BC5_UNORM
259 1, // R32F 281 4, // BC5_SNORM
260 1, // R16F 282 4, // BC7_UNORM
261 1, // R16U 283 4, // BC6H_UFLOAT
262 1, // R16S 284 4, // BC6H_SFLOAT
263 1, // R16UI 285 4, // ASTC_2D_4X4_UNORM
264 1, // R16I 286 1, // B8G8R8A8_UNORM
265 1, // RG16 287 1, // R32G32B32A32_FLOAT
266 1, // RG16F 288 1, // R32G32B32A32_SINT
267 1, // RG16UI 289 1, // R32G32_FLOAT
268 1, // RG16I 290 1, // R32G32_SINT
269 1, // RG16S 291 1, // R32_FLOAT
270 1, // RGB32F 292 1, // R16_FLOAT
271 1, // RGBA8_SRGB 293 1, // R16_UNORM
272 1, // RG8U 294 1, // R16_SNORM
273 1, // RG8S 295 1, // R16_UINT
274 1, // RG8UI 296 1, // R16_SINT
275 1, // RG32UI 297 1, // R16G16_UNORM
276 1, // RGBX16F 298 1, // R16G16_FLOAT
277 1, // R32UI 299 1, // R16G16_UINT
278 1, // R32I 300 1, // R16G16_SINT
279 8, // ASTC_2D_8X8 301 1, // R16G16_SNORM
280 8, // ASTC_2D_8X5 302 1, // R32G32B32_FLOAT
281 5, // ASTC_2D_5X4 303 1, // A8B8G8R8_SRGB
282 1, // BGRA8_SRGB 304 1, // R8G8_UNORM
283 4, // DXT1_SRGB 305 1, // R8G8_SNORM
284 4, // DXT23_SRGB 306 1, // R8G8_SINT
285 4, // DXT45_SRGB 307 1, // R8G8_UINT
286 4, // BC7U_SRGB 308 1, // R32G32_UINT
287 1, // R4G4B4A4U 309 1, // R16G16B16X16_FLOAT
310 1, // R32_UINT
311 1, // R32_SINT
312 8, // ASTC_2D_8X8_UNORM
313 8, // ASTC_2D_8X5_UNORM
314 5, // ASTC_2D_5X4_UNORM
315 1, // B8G8R8A8_SRGB
316 4, // BC1_RGBA_SRGB
317 4, // BC2_SRGB
318 4, // BC3_SRGB
319 4, // BC7_SRGB
320 1, // A4B4G4R4_UNORM
288 4, // ASTC_2D_4X4_SRGB 321 4, // ASTC_2D_4X4_SRGB
289 8, // ASTC_2D_8X8_SRGB 322 8, // ASTC_2D_8X8_SRGB
290 8, // ASTC_2D_8X5_SRGB 323 8, // ASTC_2D_8X5_SRGB
291 5, // ASTC_2D_5X4_SRGB 324 5, // ASTC_2D_5X4_SRGB
292 5, // ASTC_2D_5X5 325 5, // ASTC_2D_5X5_UNORM
293 5, // ASTC_2D_5X5_SRGB 326 5, // ASTC_2D_5X5_SRGB
294 10, // ASTC_2D_10X8 327 10, // ASTC_2D_10X8_UNORM
295 10, // ASTC_2D_10X8_SRGB 328 10, // ASTC_2D_10X8_SRGB
296 6, // ASTC_2D_6X6 329 6, // ASTC_2D_6X6_UNORM
297 6, // ASTC_2D_6X6_SRGB 330 6, // ASTC_2D_6X6_SRGB
298 10, // ASTC_2D_10X10 331 10, // ASTC_2D_10X10_UNORM
299 10, // ASTC_2D_10X10_SRGB 332 10, // ASTC_2D_10X10_SRGB
300 12, // ASTC_2D_12X12 333 12, // ASTC_2D_12X12_UNORM
301 12, // ASTC_2D_12X12_SRGB 334 12, // ASTC_2D_12X12_SRGB
302 8, // ASTC_2D_8X6 335 8, // ASTC_2D_8X6_UNORM
303 8, // ASTC_2D_8X6_SRGB 336 8, // ASTC_2D_8X6_SRGB
304 6, // ASTC_2D_6X5 337 6, // ASTC_2D_6X5_UNORM
305 6, // ASTC_2D_6X5_SRGB 338 6, // ASTC_2D_6X5_SRGB
306 1, // E5B9G9R9F 339 1, // E5B9G9R9_FLOAT
307 1, // Z32F 340 1, // D32_FLOAT
308 1, // Z16 341 1, // D16_UNORM
309 1, // Z24S8 342 1, // D24_UNORM_S8_UINT
310 1, // S8Z24 343 1, // S8_UINT_D24_UNORM
311 1, // Z32FS8 344 1, // D32_FLOAT_S8_UINT
312}}; 345}};
313 346
314static constexpr u32 GetDefaultBlockWidth(PixelFormat format) { 347static constexpr u32 GetDefaultBlockWidth(PixelFormat format) {
@@ -320,86 +353,97 @@ static constexpr u32 GetDefaultBlockWidth(PixelFormat format) {
320} 353}
321 354
322constexpr std::array<u32, MaxPixelFormat> block_height_table = {{ 355constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
323 1, // ABGR8U 356 1, // A8B8G8R8_UNORM
324 1, // ABGR8S 357 1, // A8B8G8R8_SNORM
325 1, // ABGR8UI 358 1, // A8B8G8R8_SINT
326 1, // B5G6R5U 359 1, // A8B8G8R8_UINT
327 1, // A2B10G10R10U 360 1, // R5G6B5_UNORM
328 1, // A1B5G5R5U 361 1, // B5G6R5_UNORM
329 1, // R8U 362 1, // A1R5G5B5_UNORM
330 1, // R8UI 363 1, // A2B10G10R10_UNORM
331 1, // RGBA16F 364 1, // A2B10G10R10_UINT
332 1, // RGBA16U 365 1, // A1B5G5R5_UNORM
333 1, // RGBA16S 366 1, // R8_UNORM
334 1, // RGBA16UI 367 1, // R8_SNORM
335 1, // R11FG11FB10F 368 1, // R8_SINT
336 1, // RGBA32UI 369 1, // R8_UINT
337 4, // DXT1 370 1, // R16G16B16A16_FLOAT
338 4, // DXT23 371 1, // R16G16B16A16_UNORM
339 4, // DXT45 372 1, // R16G16B16A16_SNORM
340 4, // DXN1 373 1, // R16G16B16A16_SINT
341 4, // DXN2UNORM 374 1, // R16G16B16A16_UINT
342 4, // DXN2SNORM 375 1, // B10G11R11_FLOAT
343 4, // BC7U 376 1, // R32G32B32A32_UINT
344 4, // BC6H_UF16 377 4, // BC1_RGBA_UNORM
345 4, // BC6H_SF16 378 4, // BC2_UNORM
346 4, // ASTC_2D_4X4 379 4, // BC3_UNORM
347 1, // BGRA8 380 4, // BC4_UNORM
348 1, // RGBA32F 381 4, // BC4_SNORM
349 1, // RG32F 382 4, // BC5_UNORM
350 1, // R32F 383 4, // BC5_SNORM
351 1, // R16F 384 4, // BC7_UNORM
352 1, // R16U 385 4, // BC6H_UFLOAT
353 1, // R16S 386 4, // BC6H_SFLOAT
354 1, // R16UI 387 4, // ASTC_2D_4X4_UNORM
355 1, // R16I 388 1, // B8G8R8A8_UNORM
356 1, // RG16 389 1, // R32G32B32A32_FLOAT
357 1, // RG16F 390 1, // R32G32B32A32_SINT
358 1, // RG16UI 391 1, // R32G32_FLOAT
359 1, // RG16I 392 1, // R32G32_SINT
360 1, // RG16S 393 1, // R32_FLOAT
361 1, // RGB32F 394 1, // R16_FLOAT
362 1, // RGBA8_SRGB 395 1, // R16_UNORM
363 1, // RG8U 396 1, // R16_SNORM
364 1, // RG8S 397 1, // R16_UINT
365 1, // RG8UI 398 1, // R16_SINT
366 1, // RG32UI 399 1, // R16G16_UNORM
367 1, // RGBX16F 400 1, // R16G16_FLOAT
368 1, // R32UI 401 1, // R16G16_UINT
369 1, // R32I 402 1, // R16G16_SINT
370 8, // ASTC_2D_8X8 403 1, // R16G16_SNORM
371 5, // ASTC_2D_8X5 404 1, // R32G32B32_FLOAT
372 4, // ASTC_2D_5X4 405 1, // A8B8G8R8_SRGB
373 1, // BGRA8_SRGB 406 1, // R8G8_UNORM
374 4, // DXT1_SRGB 407 1, // R8G8_SNORM
375 4, // DXT23_SRGB 408 1, // R8G8_SINT
376 4, // DXT45_SRGB 409 1, // R8G8_UINT
377 4, // BC7U_SRGB 410 1, // R32G32_UINT
378 1, // R4G4B4A4U 411 1, // R16G16B16X16_FLOAT
412 1, // R32_UINT
413 1, // R32_SINT
414 8, // ASTC_2D_8X8_UNORM
415 5, // ASTC_2D_8X5_UNORM
416 4, // ASTC_2D_5X4_UNORM
417 1, // B8G8R8A8_SRGB
418 4, // BC1_RGBA_SRGB
419 4, // BC2_SRGB
420 4, // BC3_SRGB
421 4, // BC7_SRGB
422 1, // A4B4G4R4_UNORM
379 4, // ASTC_2D_4X4_SRGB 423 4, // ASTC_2D_4X4_SRGB
380 8, // ASTC_2D_8X8_SRGB 424 8, // ASTC_2D_8X8_SRGB
381 5, // ASTC_2D_8X5_SRGB 425 5, // ASTC_2D_8X5_SRGB
382 4, // ASTC_2D_5X4_SRGB 426 4, // ASTC_2D_5X4_SRGB
383 5, // ASTC_2D_5X5 427 5, // ASTC_2D_5X5_UNORM
384 5, // ASTC_2D_5X5_SRGB 428 5, // ASTC_2D_5X5_SRGB
385 8, // ASTC_2D_10X8 429 8, // ASTC_2D_10X8_UNORM
386 8, // ASTC_2D_10X8_SRGB 430 8, // ASTC_2D_10X8_SRGB
387 6, // ASTC_2D_6X6 431 6, // ASTC_2D_6X6_UNORM
388 6, // ASTC_2D_6X6_SRGB 432 6, // ASTC_2D_6X6_SRGB
389 10, // ASTC_2D_10X10 433 10, // ASTC_2D_10X10_UNORM
390 10, // ASTC_2D_10X10_SRGB 434 10, // ASTC_2D_10X10_SRGB
391 12, // ASTC_2D_12X12 435 12, // ASTC_2D_12X12_UNORM
392 12, // ASTC_2D_12X12_SRGB 436 12, // ASTC_2D_12X12_SRGB
393 6, // ASTC_2D_8X6 437 6, // ASTC_2D_8X6_UNORM
394 6, // ASTC_2D_8X6_SRGB 438 6, // ASTC_2D_8X6_SRGB
395 5, // ASTC_2D_6X5 439 5, // ASTC_2D_6X5_UNORM
396 5, // ASTC_2D_6X5_SRGB 440 5, // ASTC_2D_6X5_SRGB
397 1, // E5B9G9R9F 441 1, // E5B9G9R9_FLOAT
398 1, // Z32F 442 1, // D32_FLOAT
399 1, // Z16 443 1, // D16_UNORM
400 1, // Z24S8 444 1, // D24_UNORM_S8_UINT
401 1, // S8Z24 445 1, // S8_UINT_D24_UNORM
402 1, // Z32FS8 446 1, // D32_FLOAT_S8_UINT
403}}; 447}};
404 448
405static constexpr u32 GetDefaultBlockHeight(PixelFormat format) { 449static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
@@ -411,86 +455,97 @@ static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
411} 455}
412 456
413constexpr std::array<u32, MaxPixelFormat> bpp_table = {{ 457constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
414 32, // ABGR8U 458 32, // A8B8G8R8_UNORM
415 32, // ABGR8S 459 32, // A8B8G8R8_SNORM
416 32, // ABGR8UI 460 32, // A8B8G8R8_SINT
417 16, // B5G6R5U 461 32, // A8B8G8R8_UINT
418 32, // A2B10G10R10U 462 16, // R5G6B5_UNORM
419 16, // A1B5G5R5U 463 16, // B5G6R5_UNORM
420 8, // R8U 464 16, // A1R5G5B5_UNORM
421 8, // R8UI 465 32, // A2B10G10R10_UNORM
422 64, // RGBA16F 466 32, // A2B10G10R10_UINT
423 64, // RGBA16U 467 16, // A1B5G5R5_UNORM
424 64, // RGBA16S 468 8, // R8_UNORM
425 64, // RGBA16UI 469 8, // R8_SNORM
426 32, // R11FG11FB10F 470 8, // R8_SINT
427 128, // RGBA32UI 471 8, // R8_UINT
428 64, // DXT1 472 64, // R16G16B16A16_FLOAT
429 128, // DXT23 473 64, // R16G16B16A16_UNORM
430 128, // DXT45 474 64, // R16G16B16A16_SNORM
431 64, // DXN1 475 64, // R16G16B16A16_SINT
432 128, // DXN2UNORM 476 64, // R16G16B16A16_UINT
433 128, // DXN2SNORM 477 32, // B10G11R11_FLOAT
434 128, // BC7U 478 128, // R32G32B32A32_UINT
435 128, // BC6H_UF16 479 64, // BC1_RGBA_UNORM
436 128, // BC6H_SF16 480 128, // BC2_UNORM
437 128, // ASTC_2D_4X4 481 128, // BC3_UNORM
438 32, // BGRA8 482 64, // BC4_UNORM
439 128, // RGBA32F 483 64, // BC4_SNORM
440 64, // RG32F 484 128, // BC5_UNORM
441 32, // R32F 485 128, // BC5_SNORM
442 16, // R16F 486 128, // BC7_UNORM
443 16, // R16U 487 128, // BC6H_UFLOAT
444 16, // R16S 488 128, // BC6H_SFLOAT
445 16, // R16UI 489 128, // ASTC_2D_4X4_UNORM
446 16, // R16I 490 32, // B8G8R8A8_UNORM
447 32, // RG16 491 128, // R32G32B32A32_FLOAT
448 32, // RG16F 492 128, // R32G32B32A32_SINT
449 32, // RG16UI 493 64, // R32G32_FLOAT
450 32, // RG16I 494 64, // R32G32_SINT
451 32, // RG16S 495 32, // R32_FLOAT
452 96, // RGB32F 496 16, // R16_FLOAT
453 32, // RGBA8_SRGB 497 16, // R16_UNORM
454 16, // RG8U 498 16, // R16_SNORM
455 16, // RG8S 499 16, // R16_UINT
456 16, // RG8UI 500 16, // R16_SINT
457 64, // RG32UI 501 32, // R16G16_UNORM
458 64, // RGBX16F 502 32, // R16G16_FLOAT
459 32, // R32UI 503 32, // R16G16_UINT
460 32, // R32I 504 32, // R16G16_SINT
461 128, // ASTC_2D_8X8 505 32, // R16G16_SNORM
462 128, // ASTC_2D_8X5 506 96, // R32G32B32_FLOAT
463 128, // ASTC_2D_5X4 507 32, // A8B8G8R8_SRGB
464 32, // BGRA8_SRGB 508 16, // R8G8_UNORM
465 64, // DXT1_SRGB 509 16, // R8G8_SNORM
466 128, // DXT23_SRGB 510 16, // R8G8_SINT
467 128, // DXT45_SRGB 511 16, // R8G8_UINT
468 128, // BC7U 512 64, // R32G32_UINT
469 16, // R4G4B4A4U 513 64, // R16G16B16X16_FLOAT
514 32, // R32_UINT
515 32, // R32_SINT
516 128, // ASTC_2D_8X8_UNORM
517 128, // ASTC_2D_8X5_UNORM
518 128, // ASTC_2D_5X4_UNORM
519 32, // B8G8R8A8_SRGB
520 64, // BC1_RGBA_SRGB
521 128, // BC2_SRGB
522 128, // BC3_SRGB
523 128, // BC7_UNORM
524 16, // A4B4G4R4_UNORM
470 128, // ASTC_2D_4X4_SRGB 525 128, // ASTC_2D_4X4_SRGB
471 128, // ASTC_2D_8X8_SRGB 526 128, // ASTC_2D_8X8_SRGB
472 128, // ASTC_2D_8X5_SRGB 527 128, // ASTC_2D_8X5_SRGB
473 128, // ASTC_2D_5X4_SRGB 528 128, // ASTC_2D_5X4_SRGB
474 128, // ASTC_2D_5X5 529 128, // ASTC_2D_5X5_UNORM
475 128, // ASTC_2D_5X5_SRGB 530 128, // ASTC_2D_5X5_SRGB
476 128, // ASTC_2D_10X8 531 128, // ASTC_2D_10X8_UNORM
477 128, // ASTC_2D_10X8_SRGB 532 128, // ASTC_2D_10X8_SRGB
478 128, // ASTC_2D_6X6 533 128, // ASTC_2D_6X6_UNORM
479 128, // ASTC_2D_6X6_SRGB 534 128, // ASTC_2D_6X6_SRGB
480 128, // ASTC_2D_10X10 535 128, // ASTC_2D_10X10_UNORM
481 128, // ASTC_2D_10X10_SRGB 536 128, // ASTC_2D_10X10_SRGB
482 128, // ASTC_2D_12X12 537 128, // ASTC_2D_12X12_UNORM
483 128, // ASTC_2D_12X12_SRGB 538 128, // ASTC_2D_12X12_SRGB
484 128, // ASTC_2D_8X6 539 128, // ASTC_2D_8X6_UNORM
485 128, // ASTC_2D_8X6_SRGB 540 128, // ASTC_2D_8X6_SRGB
486 128, // ASTC_2D_6X5 541 128, // ASTC_2D_6X5_UNORM
487 128, // ASTC_2D_6X5_SRGB 542 128, // ASTC_2D_6X5_SRGB
488 32, // E5B9G9R9F 543 32, // E5B9G9R9_FLOAT
489 32, // Z32F 544 32, // D32_FLOAT
490 16, // Z16 545 16, // D16_UNORM
491 32, // Z24S8 546 32, // D24_UNORM_S8_UINT
492 32, // S8Z24 547 32, // S8_UINT_D24_UNORM
493 64, // Z32FS8 548 64, // D32_FLOAT_S8_UINT
494}}; 549}};
495 550
496static constexpr u32 GetFormatBpp(PixelFormat format) { 551static constexpr u32 GetFormatBpp(PixelFormat format) {
@@ -529,7 +584,4 @@ bool IsPixelFormatSRGB(PixelFormat format);
529 584
530std::pair<u32, u32> GetASTCBlockSize(PixelFormat format); 585std::pair<u32, u32> GetASTCBlockSize(PixelFormat format);
531 586
532/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
533bool IsFormatBCn(PixelFormat format);
534
535} // namespace VideoCore::Surface 587} // namespace VideoCore::Surface
diff --git a/src/video_core/texture_cache/format_lookup_table.cpp b/src/video_core/texture_cache/format_lookup_table.cpp
index f476f03b0..a1cc4756d 100644
--- a/src/video_core/texture_cache/format_lookup_table.cpp
+++ b/src/video_core/texture_cache/format_lookup_table.cpp
@@ -41,119 +41,126 @@ struct Table {
41 ComponentType alpha_component; 41 ComponentType alpha_component;
42 bool is_srgb; 42 bool is_srgb;
43}; 43};
44constexpr std::array<Table, 78> DefinitionTable = {{ 44constexpr std::array<Table, 86> DefinitionTable = {{
45 {TextureFormat::A8R8G8B8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ABGR8U}, 45 {TextureFormat::A8R8G8B8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::A8B8G8R8_UNORM},
46 {TextureFormat::A8R8G8B8, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::ABGR8S}, 46 {TextureFormat::A8R8G8B8, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::A8B8G8R8_SNORM},
47 {TextureFormat::A8R8G8B8, C, UINT, UINT, UINT, UINT, PixelFormat::ABGR8UI}, 47 {TextureFormat::A8R8G8B8, C, UINT, UINT, UINT, UINT, PixelFormat::A8B8G8R8_UINT},
48 {TextureFormat::A8R8G8B8, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::RGBA8_SRGB}, 48 {TextureFormat::A8R8G8B8, C, SINT, SINT, SINT, SINT, PixelFormat::A8B8G8R8_SINT},
49 {TextureFormat::A8R8G8B8, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::A8B8G8R8_SRGB},
49 50
50 {TextureFormat::B5G6R5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::B5G6R5U}, 51 {TextureFormat::B5G6R5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::B5G6R5_UNORM},
51 52
52 {TextureFormat::A2B10G10R10, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::A2B10G10R10U}, 53 {TextureFormat::A2B10G10R10, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::A2B10G10R10_UNORM},
54 {TextureFormat::A2B10G10R10, C, UINT, UINT, UINT, UINT, PixelFormat::A2B10G10R10_UINT},
53 55
54 {TextureFormat::A1B5G5R5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::A1B5G5R5U}, 56 {TextureFormat::A1B5G5R5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::A1B5G5R5_UNORM},
55 57
56 {TextureFormat::A4B4G4R4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R4G4B4A4U}, 58 {TextureFormat::A4B4G4R4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::A4B4G4R4_UNORM},
57 59
58 {TextureFormat::R8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R8U}, 60 {TextureFormat::R8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R8_UNORM},
59 {TextureFormat::R8, C, UINT, UINT, UINT, UINT, PixelFormat::R8UI}, 61 {TextureFormat::R8, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::R8_SNORM},
62 {TextureFormat::R8, C, UINT, UINT, UINT, UINT, PixelFormat::R8_UINT},
63 {TextureFormat::R8, C, SINT, SINT, SINT, SINT, PixelFormat::R8_SINT},
60 64
61 {TextureFormat::G8R8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::RG8U}, 65 {TextureFormat::R8G8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R8G8_UNORM},
62 {TextureFormat::G8R8, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::RG8S}, 66 {TextureFormat::R8G8, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::R8G8_SNORM},
63 {TextureFormat::G8R8, C, UINT, UINT, UINT, UINT, PixelFormat::RG8UI}, 67 {TextureFormat::R8G8, C, UINT, UINT, UINT, UINT, PixelFormat::R8G8_UINT},
68 {TextureFormat::R8G8, C, SINT, SINT, SINT, SINT, PixelFormat::R8G8_SINT},
64 69
65 {TextureFormat::R16_G16_B16_A16, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::RGBA16S}, 70 {TextureFormat::R16G16B16A16, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::R16G16B16A16_SNORM},
66 {TextureFormat::R16_G16_B16_A16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::RGBA16U}, 71 {TextureFormat::R16G16B16A16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R16G16B16A16_UNORM},
67 {TextureFormat::R16_G16_B16_A16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RGBA16F}, 72 {TextureFormat::R16G16B16A16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R16G16B16A16_FLOAT},
68 {TextureFormat::R16_G16_B16_A16, C, UINT, UINT, UINT, UINT, PixelFormat::RGBA16UI}, 73 {TextureFormat::R16G16B16A16, C, UINT, UINT, UINT, UINT, PixelFormat::R16G16B16A16_UINT},
74 {TextureFormat::R16G16B16A16, C, SINT, SINT, SINT, SINT, PixelFormat::R16G16B16A16_SINT},
69 75
70 {TextureFormat::R16_G16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RG16F}, 76 {TextureFormat::R16G16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R16G16_FLOAT},
71 {TextureFormat::R16_G16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::RG16}, 77 {TextureFormat::R16G16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R16G16_UNORM},
72 {TextureFormat::R16_G16, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::RG16S}, 78 {TextureFormat::R16G16, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::R16G16_SNORM},
73 {TextureFormat::R16_G16, C, UINT, UINT, UINT, UINT, PixelFormat::RG16UI}, 79 {TextureFormat::R16G16, C, UINT, UINT, UINT, UINT, PixelFormat::R16G16_UINT},
74 {TextureFormat::R16_G16, C, SINT, SINT, SINT, SINT, PixelFormat::RG16I}, 80 {TextureFormat::R16G16, C, SINT, SINT, SINT, SINT, PixelFormat::R16G16_SINT},
75 81
76 {TextureFormat::R16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R16F}, 82 {TextureFormat::R16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R16_FLOAT},
77 {TextureFormat::R16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R16U}, 83 {TextureFormat::R16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R16_UNORM},
78 {TextureFormat::R16, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::R16S}, 84 {TextureFormat::R16, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::R16_SNORM},
79 {TextureFormat::R16, C, UINT, UINT, UINT, UINT, PixelFormat::R16UI}, 85 {TextureFormat::R16, C, UINT, UINT, UINT, UINT, PixelFormat::R16_UINT},
80 {TextureFormat::R16, C, SINT, SINT, SINT, SINT, PixelFormat::R16I}, 86 {TextureFormat::R16, C, SINT, SINT, SINT, SINT, PixelFormat::R16_SINT},
81 87
82 {TextureFormat::BF10GF11RF11, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R11FG11FB10F}, 88 {TextureFormat::B10G11R11, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::B10G11R11_FLOAT},
83 89
84 {TextureFormat::R32_G32_B32_A32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RGBA32F}, 90 {TextureFormat::R32G32B32A32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R32G32B32A32_FLOAT},
85 {TextureFormat::R32_G32_B32_A32, C, UINT, UINT, UINT, UINT, PixelFormat::RGBA32UI}, 91 {TextureFormat::R32G32B32A32, C, UINT, UINT, UINT, UINT, PixelFormat::R32G32B32A32_UINT},
92 {TextureFormat::R32G32B32A32, C, SINT, SINT, SINT, SINT, PixelFormat::R32G32B32A32_SINT},
86 93
87 {TextureFormat::R32_G32_B32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RGB32F}, 94 {TextureFormat::R32G32B32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R32G32B32_FLOAT},
88 95
89 {TextureFormat::R32_G32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RG32F}, 96 {TextureFormat::R32G32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R32G32_FLOAT},
90 {TextureFormat::R32_G32, C, UINT, UINT, UINT, UINT, PixelFormat::RG32UI}, 97 {TextureFormat::R32G32, C, UINT, UINT, UINT, UINT, PixelFormat::R32G32_UINT},
98 {TextureFormat::R32G32, C, SINT, SINT, SINT, SINT, PixelFormat::R32G32_SINT},
91 99
92 {TextureFormat::R32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R32F}, 100 {TextureFormat::R32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R32_FLOAT},
93 {TextureFormat::R32, C, UINT, UINT, UINT, UINT, PixelFormat::R32UI}, 101 {TextureFormat::R32, C, UINT, UINT, UINT, UINT, PixelFormat::R32_UINT},
94 {TextureFormat::R32, C, SINT, SINT, SINT, SINT, PixelFormat::R32I}, 102 {TextureFormat::R32, C, SINT, SINT, SINT, SINT, PixelFormat::R32_SINT},
95 103
96 {TextureFormat::E5B9G9R9_SHAREDEXP, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::E5B9G9R9F}, 104 {TextureFormat::E5B9G9R9, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::E5B9G9R9_FLOAT},
97 105
98 {TextureFormat::ZF32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::Z32F}, 106 {TextureFormat::D32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::D32_FLOAT},
99 {TextureFormat::Z16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::Z16}, 107 {TextureFormat::D16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::D16_UNORM},
100 {TextureFormat::S8Z24, C, UINT, UNORM, UNORM, UNORM, PixelFormat::S8Z24}, 108 {TextureFormat::S8D24, C, UINT, UNORM, UNORM, UNORM, PixelFormat::S8_UINT_D24_UNORM},
101 {TextureFormat::G24R8, C, UINT, UNORM, UNORM, UNORM, PixelFormat::S8Z24}, 109 {TextureFormat::R8G24, C, UINT, UNORM, UNORM, UNORM, PixelFormat::S8_UINT_D24_UNORM},
102 {TextureFormat::ZF32_X24S8, C, FLOAT, UINT, UNORM, UNORM, PixelFormat::Z32FS8}, 110 {TextureFormat::D32S8, C, FLOAT, UINT, UNORM, UNORM, PixelFormat::D32_FLOAT_S8_UINT},
103 111
104 {TextureFormat::DXT1, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT1}, 112 {TextureFormat::BC1_RGBA, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC1_RGBA_UNORM},
105 {TextureFormat::DXT1, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT1_SRGB}, 113 {TextureFormat::BC1_RGBA, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC1_RGBA_SRGB},
106 114
107 {TextureFormat::DXT23, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT23}, 115 {TextureFormat::BC2, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC2_UNORM},
108 {TextureFormat::DXT23, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT23_SRGB}, 116 {TextureFormat::BC2, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC2_SRGB},
109 117
110 {TextureFormat::DXT45, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT45}, 118 {TextureFormat::BC3, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC3_UNORM},
111 {TextureFormat::DXT45, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT45_SRGB}, 119 {TextureFormat::BC3, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC3_SRGB},
112 120
113 // TODO: Use a different pixel format for SNORM 121 {TextureFormat::BC4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC4_UNORM},
114 {TextureFormat::DXN1, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXN1}, 122 {TextureFormat::BC4, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::BC4_SNORM},
115 {TextureFormat::DXN1, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::DXN1},
116 123
117 {TextureFormat::DXN2, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXN2UNORM}, 124 {TextureFormat::BC5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC5_UNORM},
118 {TextureFormat::DXN2, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::DXN2SNORM}, 125 {TextureFormat::BC5, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::BC5_SNORM},
119 126
120 {TextureFormat::BC7U, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC7U}, 127 {TextureFormat::BC7, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC7_UNORM},
121 {TextureFormat::BC7U, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC7U_SRGB}, 128 {TextureFormat::BC7, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC7_SRGB},
122 129
123 {TextureFormat::BC6H_SF16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::BC6H_SF16}, 130 {TextureFormat::BC6H_SFLOAT, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::BC6H_SFLOAT},
124 {TextureFormat::BC6H_UF16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::BC6H_UF16}, 131 {TextureFormat::BC6H_UFLOAT, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::BC6H_UFLOAT},
125 132
126 {TextureFormat::ASTC_2D_4X4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_4X4}, 133 {TextureFormat::ASTC_2D_4X4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_4X4_UNORM},
127 {TextureFormat::ASTC_2D_4X4, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_4X4_SRGB}, 134 {TextureFormat::ASTC_2D_4X4, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_4X4_SRGB},
128 135
129 {TextureFormat::ASTC_2D_5X4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X4}, 136 {TextureFormat::ASTC_2D_5X4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X4_UNORM},
130 {TextureFormat::ASTC_2D_5X4, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X4_SRGB}, 137 {TextureFormat::ASTC_2D_5X4, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X4_SRGB},
131 138
132 {TextureFormat::ASTC_2D_5X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X5}, 139 {TextureFormat::ASTC_2D_5X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X5_UNORM},
133 {TextureFormat::ASTC_2D_5X5, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X5_SRGB}, 140 {TextureFormat::ASTC_2D_5X5, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X5_SRGB},
134 141
135 {TextureFormat::ASTC_2D_8X8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X8}, 142 {TextureFormat::ASTC_2D_8X8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X8_UNORM},
136 {TextureFormat::ASTC_2D_8X8, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X8_SRGB}, 143 {TextureFormat::ASTC_2D_8X8, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X8_SRGB},
137 144
138 {TextureFormat::ASTC_2D_8X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X5}, 145 {TextureFormat::ASTC_2D_8X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X5_UNORM},
139 {TextureFormat::ASTC_2D_8X5, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X5_SRGB}, 146 {TextureFormat::ASTC_2D_8X5, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X5_SRGB},
140 147
141 {TextureFormat::ASTC_2D_10X8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X8}, 148 {TextureFormat::ASTC_2D_10X8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X8_UNORM},
142 {TextureFormat::ASTC_2D_10X8, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X8_SRGB}, 149 {TextureFormat::ASTC_2D_10X8, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X8_SRGB},
143 150
144 {TextureFormat::ASTC_2D_6X6, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X6}, 151 {TextureFormat::ASTC_2D_6X6, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X6_UNORM},
145 {TextureFormat::ASTC_2D_6X6, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X6_SRGB}, 152 {TextureFormat::ASTC_2D_6X6, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X6_SRGB},
146 153
147 {TextureFormat::ASTC_2D_10X10, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X10}, 154 {TextureFormat::ASTC_2D_10X10, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X10_UNORM},
148 {TextureFormat::ASTC_2D_10X10, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X10_SRGB}, 155 {TextureFormat::ASTC_2D_10X10, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X10_SRGB},
149 156
150 {TextureFormat::ASTC_2D_12X12, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_12X12}, 157 {TextureFormat::ASTC_2D_12X12, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_12X12_UNORM},
151 {TextureFormat::ASTC_2D_12X12, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_12X12_SRGB}, 158 {TextureFormat::ASTC_2D_12X12, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_12X12_SRGB},
152 159
153 {TextureFormat::ASTC_2D_8X6, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X6}, 160 {TextureFormat::ASTC_2D_8X6, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X6_UNORM},
154 {TextureFormat::ASTC_2D_8X6, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X6_SRGB}, 161 {TextureFormat::ASTC_2D_8X6, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X6_SRGB},
155 162
156 {TextureFormat::ASTC_2D_6X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X5}, 163 {TextureFormat::ASTC_2D_6X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X5_UNORM},
157 {TextureFormat::ASTC_2D_6X5, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X5_SRGB}, 164 {TextureFormat::ASTC_2D_6X5, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X5_SRGB},
158}}; 165}};
159 166
@@ -184,7 +191,7 @@ PixelFormat FormatLookupTable::GetPixelFormat(TextureFormat format, bool is_srgb
184 static_cast<int>(format), is_srgb, static_cast<int>(red_component), 191 static_cast<int>(format), is_srgb, static_cast<int>(red_component),
185 static_cast<int>(green_component), static_cast<int>(blue_component), 192 static_cast<int>(green_component), static_cast<int>(blue_component),
186 static_cast<int>(alpha_component)); 193 static_cast<int>(alpha_component));
187 return PixelFormat::ABGR8U; 194 return PixelFormat::A8B8G8R8_UNORM;
188} 195}
189 196
190void FormatLookupTable::Set(TextureFormat format, bool is_srgb, ComponentType red_component, 197void FormatLookupTable::Set(TextureFormat format, bool is_srgb, ComponentType red_component,
diff --git a/src/video_core/texture_cache/surface_base.cpp b/src/video_core/texture_cache/surface_base.cpp
index 0caf3b4f0..dfcf36e0b 100644
--- a/src/video_core/texture_cache/surface_base.cpp
+++ b/src/video_core/texture_cache/surface_base.cpp
@@ -228,7 +228,7 @@ void SurfaceBaseImpl::LoadBuffer(Tegra::MemoryManager& memory_manager,
228 } 228 }
229 } 229 }
230 230
231 if (!is_converted && params.pixel_format != PixelFormat::S8Z24) { 231 if (!is_converted && params.pixel_format != PixelFormat::S8_UINT_D24_UNORM) {
232 return; 232 return;
233 } 233 }
234 234
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp
index 921562c1f..9e5fe2374 100644
--- a/src/video_core/texture_cache/surface_params.cpp
+++ b/src/video_core/texture_cache/surface_params.cpp
@@ -83,12 +83,12 @@ SurfaceParams SurfaceParams::CreateForTexture(const FormatLookupTable& lookup_ta
83 params.type = GetFormatType(params.pixel_format); 83 params.type = GetFormatType(params.pixel_format);
84 if (entry.is_shadow && params.type == SurfaceType::ColorTexture) { 84 if (entry.is_shadow && params.type == SurfaceType::ColorTexture) {
85 switch (params.pixel_format) { 85 switch (params.pixel_format) {
86 case PixelFormat::R16U: 86 case PixelFormat::R16_UNORM:
87 case PixelFormat::R16F: 87 case PixelFormat::R16_FLOAT:
88 params.pixel_format = PixelFormat::Z16; 88 params.pixel_format = PixelFormat::D16_UNORM;
89 break; 89 break;
90 case PixelFormat::R32F: 90 case PixelFormat::R32_FLOAT:
91 params.pixel_format = PixelFormat::Z32F; 91 params.pixel_format = PixelFormat::D32_FLOAT;
92 break; 92 break;
93 default: 93 default:
94 UNIMPLEMENTED_MSG("Unimplemented shadow convert format: {}", 94 UNIMPLEMENTED_MSG("Unimplemented shadow convert format: {}",
@@ -195,8 +195,8 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz
195 SurfaceParams params; 195 SurfaceParams params;
196 params.is_tiled = 196 params.is_tiled =
197 config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear; 197 config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear;
198 params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || 198 params.srgb_conversion = config.format == Tegra::RenderTargetFormat::B8G8R8A8_SRGB ||
199 config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; 199 config.format == Tegra::RenderTargetFormat::A8B8G8R8_SRGB;
200 params.block_width = config.memory_layout.block_width; 200 params.block_width = config.memory_layout.block_width;
201 params.block_height = config.memory_layout.block_height; 201 params.block_height = config.memory_layout.block_height;
202 params.block_depth = config.memory_layout.block_depth; 202 params.block_depth = config.memory_layout.block_depth;
@@ -235,8 +235,8 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface(
235 const Tegra::Engines::Fermi2D::Regs::Surface& config) { 235 const Tegra::Engines::Fermi2D::Regs::Surface& config) {
236 SurfaceParams params{}; 236 SurfaceParams params{};
237 params.is_tiled = !config.linear; 237 params.is_tiled = !config.linear;
238 params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || 238 params.srgb_conversion = config.format == Tegra::RenderTargetFormat::B8G8R8A8_SRGB ||
239 config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; 239 config.format == Tegra::RenderTargetFormat::A8B8G8R8_SRGB;
240 params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 5U) : 0, 240 params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 5U) : 0,
241 params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 5U) : 0, 241 params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 5U) : 0,
242 params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 5U) : 0, 242 params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 5U) : 0,
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index cdcddb225..96c4e4cc2 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -373,9 +373,9 @@ protected:
373 siblings_table[static_cast<std::size_t>(b)] = a; 373 siblings_table[static_cast<std::size_t>(b)] = a;
374 }; 374 };
375 std::fill(siblings_table.begin(), siblings_table.end(), PixelFormat::Invalid); 375 std::fill(siblings_table.begin(), siblings_table.end(), PixelFormat::Invalid);
376 make_siblings(PixelFormat::Z16, PixelFormat::R16U); 376 make_siblings(PixelFormat::D16_UNORM, PixelFormat::R16_UNORM);
377 make_siblings(PixelFormat::Z32F, PixelFormat::R32F); 377 make_siblings(PixelFormat::D32_FLOAT, PixelFormat::R32_FLOAT);
378 make_siblings(PixelFormat::Z32FS8, PixelFormat::RG32F); 378 make_siblings(PixelFormat::D32_FLOAT_S8_UINT, PixelFormat::R32G32_FLOAT);
379 379
380 sampled_textures.reserve(64); 380 sampled_textures.reserve(64);
381 } 381 }
@@ -1031,7 +1031,7 @@ private:
1031 params.pitch = 4; 1031 params.pitch = 4;
1032 params.num_levels = 1; 1032 params.num_levels = 1;
1033 params.emulated_levels = 1; 1033 params.emulated_levels = 1;
1034 params.pixel_format = VideoCore::Surface::PixelFormat::R8U; 1034 params.pixel_format = VideoCore::Surface::PixelFormat::R8_UNORM;
1035 params.type = VideoCore::Surface::SurfaceType::ColorTexture; 1035 params.type = VideoCore::Surface::SurfaceType::ColorTexture;
1036 auto surface = CreateSurface(0ULL, params); 1036 auto surface = CreateSurface(0ULL, params);
1037 invalid_memory.resize(surface->GetHostSizeInBytes(), 0U); 1037 invalid_memory.resize(surface->GetHostSizeInBytes(), 0U);
diff --git a/src/video_core/textures/convert.cpp b/src/video_core/textures/convert.cpp
index f3efa7eb0..962921483 100644
--- a/src/video_core/textures/convert.cpp
+++ b/src/video_core/textures/convert.cpp
@@ -35,7 +35,7 @@ void SwapS8Z24ToZ24S8(u8* data, u32 width, u32 height) {
35 S8Z24 s8z24_pixel{}; 35 S8Z24 s8z24_pixel{};
36 Z24S8 z24s8_pixel{}; 36 Z24S8 z24s8_pixel{};
37 constexpr auto bpp{ 37 constexpr auto bpp{
38 VideoCore::Surface::GetBytesPerPixel(VideoCore::Surface::PixelFormat::S8Z24)}; 38 VideoCore::Surface::GetBytesPerPixel(VideoCore::Surface::PixelFormat::S8_UINT_D24_UNORM)};
39 for (std::size_t y = 0; y < height; ++y) { 39 for (std::size_t y = 0; y < height; ++y) {
40 for (std::size_t x = 0; x < width; ++x) { 40 for (std::size_t x = 0; x < width; ++x) {
41 const std::size_t offset{bpp * (y * width + x)}; 41 const std::size_t offset{bpp * (y * width + x)};
@@ -73,7 +73,7 @@ void ConvertFromGuestToHost(u8* in_data, u8* out_data, PixelFormat pixel_format,
73 in_data, width, height, depth, block_width, block_height); 73 in_data, width, height, depth, block_width, block_height);
74 std::copy(rgba8_data.begin(), rgba8_data.end(), out_data); 74 std::copy(rgba8_data.begin(), rgba8_data.end(), out_data);
75 75
76 } else if (convert_s8z24 && pixel_format == PixelFormat::S8Z24) { 76 } else if (convert_s8z24 && pixel_format == PixelFormat::S8_UINT_D24_UNORM) {
77 Tegra::Texture::ConvertS8Z24ToZ24S8(in_data, width, height); 77 Tegra::Texture::ConvertS8Z24ToZ24S8(in_data, width, height);
78 } 78 }
79} 79}
@@ -85,7 +85,7 @@ void ConvertFromHostToGuest(u8* data, PixelFormat pixel_format, u32 width, u32 h
85 static_cast<u32>(pixel_format)); 85 static_cast<u32>(pixel_format));
86 UNREACHABLE(); 86 UNREACHABLE();
87 87
88 } else if (convert_s8z24 && pixel_format == PixelFormat::S8Z24) { 88 } else if (convert_s8z24 && pixel_format == PixelFormat::S8_UINT_D24_UNORM) {
89 Tegra::Texture::ConvertZ24S8ToS8Z24(data, width, height); 89 Tegra::Texture::ConvertZ24S8ToS8Z24(data, width, height);
90 } 90 }
91} 91}
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 98beabef1..474ae620a 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -184,53 +184,6 @@ void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel,
184 } 184 }
185} 185}
186 186
187u32 BytesPerPixel(TextureFormat format) {
188 switch (format) {
189 case TextureFormat::DXT1:
190 case TextureFormat::DXN1:
191 // In this case a 'pixel' actually refers to a 4x4 tile.
192 return 8;
193 case TextureFormat::DXT23:
194 case TextureFormat::DXT45:
195 case TextureFormat::DXN2:
196 case TextureFormat::BC7U:
197 case TextureFormat::BC6H_UF16:
198 case TextureFormat::BC6H_SF16:
199 // In this case a 'pixel' actually refers to a 4x4 tile.
200 return 16;
201 case TextureFormat::R32_G32_B32:
202 return 12;
203 case TextureFormat::ASTC_2D_4X4:
204 case TextureFormat::ASTC_2D_5X4:
205 case TextureFormat::ASTC_2D_8X8:
206 case TextureFormat::ASTC_2D_8X5:
207 case TextureFormat::ASTC_2D_10X8:
208 case TextureFormat::ASTC_2D_5X5:
209 case TextureFormat::A8R8G8B8:
210 case TextureFormat::A2B10G10R10:
211 case TextureFormat::BF10GF11RF11:
212 case TextureFormat::R32:
213 case TextureFormat::R16_G16:
214 return 4;
215 case TextureFormat::A1B5G5R5:
216 case TextureFormat::B5G6R5:
217 case TextureFormat::G8R8:
218 case TextureFormat::R16:
219 return 2;
220 case TextureFormat::R8:
221 return 1;
222 case TextureFormat::R16_G16_B16_A16:
223 return 8;
224 case TextureFormat::R32_G32_B32_A32:
225 return 16;
226 case TextureFormat::R32_G32:
227 return 8;
228 default:
229 UNIMPLEMENTED_MSG("Format not implemented");
230 return 1;
231 }
232}
233
234void UnswizzleTexture(u8* const unswizzled_data, u8* address, u32 tile_size_x, u32 tile_size_y, 187void UnswizzleTexture(u8* const unswizzled_data, u8* address, u32 tile_size_x, u32 tile_size_y,
235 u32 bytes_per_pixel, u32 width, u32 height, u32 depth, u32 block_height, 188 u32 bytes_per_pixel, u32 width, u32 height, u32 depth, u32 block_height,
236 u32 block_depth, u32 width_spacing) { 189 u32 block_depth, u32 width_spacing) {
@@ -348,48 +301,6 @@ void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32
348 } 301 }
349} 302}
350 303
351std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat format, u32 width,
352 u32 height) {
353 std::vector<u8> rgba_data;
354
355 // TODO(Subv): Implement.
356 switch (format) {
357 case TextureFormat::DXT1:
358 case TextureFormat::DXT23:
359 case TextureFormat::DXT45:
360 case TextureFormat::DXN1:
361 case TextureFormat::DXN2:
362 case TextureFormat::BC7U:
363 case TextureFormat::BC6H_UF16:
364 case TextureFormat::BC6H_SF16:
365 case TextureFormat::ASTC_2D_4X4:
366 case TextureFormat::ASTC_2D_8X8:
367 case TextureFormat::ASTC_2D_5X5:
368 case TextureFormat::ASTC_2D_10X8:
369 case TextureFormat::A8R8G8B8:
370 case TextureFormat::A2B10G10R10:
371 case TextureFormat::A1B5G5R5:
372 case TextureFormat::B5G6R5:
373 case TextureFormat::R8:
374 case TextureFormat::G8R8:
375 case TextureFormat::BF10GF11RF11:
376 case TextureFormat::R32_G32_B32_A32:
377 case TextureFormat::R32_G32:
378 case TextureFormat::R32:
379 case TextureFormat::R16:
380 case TextureFormat::R16_G16:
381 case TextureFormat::R32_G32_B32:
382 // TODO(Subv): For the time being just forward the same data without any decoding.
383 rgba_data = texture_data;
384 break;
385 default:
386 UNIMPLEMENTED_MSG("Format not implemented");
387 break;
388 }
389
390 return rgba_data;
391}
392
393std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, 304std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
394 u32 block_height, u32 block_depth) { 305 u32 block_height, u32 block_depth) {
395 if (tiled) { 306 if (tiled) {
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index 232b696b3..d6fe35d37 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -38,10 +38,6 @@ void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel,
38 u32 out_bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, 38 u32 out_bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data,
39 bool unswizzle, u32 block_height, u32 block_depth, u32 width_spacing); 39 bool unswizzle, u32 block_height, u32 block_depth, u32 width_spacing);
40 40
41/// Decodes an unswizzled texture into a A8R8G8B8 texture.
42std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat format, u32 width,
43 u32 height);
44
45/// This function calculates the correct size of a texture depending if it's tiled or not. 41/// This function calculates the correct size of a texture depending if it's tiled or not.
46std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, 42std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
47 u32 block_height, u32 block_depth); 43 u32 block_height, u32 block_depth);
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h
index eba05aced..0574fef12 100644
--- a/src/video_core/textures/texture.h
+++ b/src/video_core/textures/texture.h
@@ -12,10 +12,10 @@
12namespace Tegra::Texture { 12namespace Tegra::Texture {
13 13
14enum class TextureFormat : u32 { 14enum class TextureFormat : u32 {
15 R32_G32_B32_A32 = 0x01, 15 R32G32B32A32 = 0x01,
16 R32_G32_B32 = 0x02, 16 R32G32B32 = 0x02,
17 R16_G16_B16_A16 = 0x03, 17 R16G16B16A16 = 0x03,
18 R32_G32 = 0x04, 18 R32G32 = 0x04,
19 R32_B24G8 = 0x05, 19 R32_B24G8 = 0x05,
20 ETC2_RGB = 0x06, 20 ETC2_RGB = 0x06,
21 X8B8G8R8 = 0x07, 21 X8B8G8R8 = 0x07,
@@ -23,19 +23,19 @@ enum class TextureFormat : u32 {
23 A2B10G10R10 = 0x09, 23 A2B10G10R10 = 0x09,
24 ETC2_RGB_PTA = 0x0a, 24 ETC2_RGB_PTA = 0x0a,
25 ETC2_RGBA = 0x0b, 25 ETC2_RGBA = 0x0b,
26 R16_G16 = 0x0c, 26 R16G16 = 0x0c,
27 G8R24 = 0x0d, 27 R24G8 = 0x0d,
28 G24R8 = 0x0e, 28 R8G24 = 0x0e,
29 R32 = 0x0f, 29 R32 = 0x0f,
30 BC6H_SF16 = 0x10, 30 BC6H_SFLOAT = 0x10,
31 BC6H_UF16 = 0x11, 31 BC6H_UFLOAT = 0x11,
32 A4B4G4R4 = 0x12, 32 A4B4G4R4 = 0x12,
33 A5B5G5R1 = 0x13, 33 A5B5G5R1 = 0x13,
34 A1B5G5R5 = 0x14, 34 A1B5G5R5 = 0x14,
35 B5G6R5 = 0x15, 35 B5G6R5 = 0x15,
36 B6G5R5 = 0x16, 36 B6G5R5 = 0x16,
37 BC7U = 0x17, 37 BC7 = 0x17,
38 G8R8 = 0x18, 38 R8G8 = 0x18,
39 EAC = 0x19, 39 EAC = 0x19,
40 EACX2 = 0x1a, 40 EACX2 = 0x1a,
41 R16 = 0x1b, 41 R16 = 0x1b,
@@ -43,23 +43,23 @@ enum class TextureFormat : u32 {
43 R8 = 0x1d, 43 R8 = 0x1d,
44 G4R4 = 0x1e, 44 G4R4 = 0x1e,
45 R1 = 0x1f, 45 R1 = 0x1f,
46 E5B9G9R9_SHAREDEXP = 0x20, 46 E5B9G9R9 = 0x20,
47 BF10GF11RF11 = 0x21, 47 B10G11R11 = 0x21,
48 G8B8G8R8 = 0x22, 48 G8B8G8R8 = 0x22,
49 B8G8R8G8 = 0x23, 49 B8G8R8G8 = 0x23,
50 DXT1 = 0x24, 50 BC1_RGBA = 0x24,
51 DXT23 = 0x25, 51 BC2 = 0x25,
52 DXT45 = 0x26, 52 BC3 = 0x26,
53 DXN1 = 0x27, 53 BC4 = 0x27,
54 DXN2 = 0x28, 54 BC5 = 0x28,
55 S8Z24 = 0x29, 55 S8D24 = 0x29,
56 X8Z24 = 0x2a, 56 X8Z24 = 0x2a,
57 Z24S8 = 0x2b, 57 D24S8 = 0x2b,
58 X4V4Z24__COV4R4V = 0x2c, 58 X4V4Z24__COV4R4V = 0x2c,
59 X4V4Z24__COV8R8V = 0x2d, 59 X4V4Z24__COV8R8V = 0x2d,
60 V8Z24__COV4R12V = 0x2e, 60 V8Z24__COV4R12V = 0x2e,
61 ZF32 = 0x2f, 61 D32 = 0x2f,
62 ZF32_X24S8 = 0x30, 62 D32S8 = 0x30,
63 X8Z24_X20V4S8__COV4R4V = 0x31, 63 X8Z24_X20V4S8__COV4R4V = 0x31,
64 X8Z24_X20V4S8__COV8R8V = 0x32, 64 X8Z24_X20V4S8__COV8R8V = 0x32,
65 ZF32_X20V4X8__COV4R4V = 0x33, 65 ZF32_X20V4X8__COV4R4V = 0x33,
@@ -69,7 +69,7 @@ enum class TextureFormat : u32 {
69 X8Z24_X16V8S8__COV4R12V = 0x37, 69 X8Z24_X16V8S8__COV4R12V = 0x37,
70 ZF32_X16V8X8__COV4R12V = 0x38, 70 ZF32_X16V8X8__COV4R12V = 0x38,
71 ZF32_X16V8S8__COV4R12V = 0x39, 71 ZF32_X16V8S8__COV4R12V = 0x39,
72 Z16 = 0x3a, 72 D16 = 0x3a,
73 V8Z24__COV8R24V = 0x3b, 73 V8Z24__COV8R24V = 0x3b,
74 X8Z24_X16V8S8__COV8R24V = 0x3c, 74 X8Z24_X16V8S8__COV8R24V = 0x3c,
75 ZF32_X16V8X8__COV8R24V = 0x3d, 75 ZF32_X16V8X8__COV8R24V = 0x3d,
@@ -375,7 +375,4 @@ struct FullTextureInfo {
375 TSCEntry tsc; 375 TSCEntry tsc;
376}; 376};
377 377
378/// Returns the number of bytes per pixel of the input texture format.
379u32 BytesPerPixel(TextureFormat format);
380
381} // namespace Tegra::Texture 378} // namespace Tegra::Texture
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index a862b2610..656096c9f 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -133,11 +133,44 @@ file(GLOB COMPAT_LIST
133file(GLOB_RECURSE ICONS ${PROJECT_SOURCE_DIR}/dist/icons/*) 133file(GLOB_RECURSE ICONS ${PROJECT_SOURCE_DIR}/dist/icons/*)
134file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*) 134file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*)
135 135
136if (ENABLE_QT_TRANSLATION)
137 set(YUZU_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend")
138 option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF)
139
140 # Update source TS file if enabled
141 if (GENERATE_QT_TRANSLATION)
142 get_target_property(SRCS yuzu SOURCES)
143 qt5_create_translation(QM_FILES ${SRCS} ${UIS} ${YUZU_QT_LANGUAGES}/en.ts)
144 add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts)
145 endif()
146
147 # Find all TS files except en.ts
148 file(GLOB_RECURSE LANGUAGES_TS ${YUZU_QT_LANGUAGES}/*.ts)
149 list(REMOVE_ITEM LANGUAGES_TS ${YUZU_QT_LANGUAGES}/en.ts)
150
151 # Compile TS files to QM files
152 qt5_add_translation(LANGUAGES_QM ${LANGUAGES_TS})
153
154 # Build a QRC file from the QM file list
155 set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc)
156 file(WRITE ${LANGUAGES_QRC} "<RCC><qresource prefix=\"languages\">\n")
157 foreach (QM ${LANGUAGES_QM})
158 get_filename_component(QM_FILE ${QM} NAME)
159 file(APPEND ${LANGUAGES_QRC} "<file>${QM_FILE}</file>\n")
160 endforeach (QM)
161 file(APPEND ${LANGUAGES_QRC} "</qresource></RCC>")
162
163 # Add the QRC file to package in all QM files
164 qt5_add_resources(LANGUAGES ${LANGUAGES_QRC})
165else()
166 set(LANGUAGES)
167endif()
136 168
137target_sources(yuzu 169target_sources(yuzu
138 PRIVATE 170 PRIVATE
139 ${COMPAT_LIST} 171 ${COMPAT_LIST}
140 ${ICONS} 172 ${ICONS}
173 ${LANGUAGES}
141 ${THEMES} 174 ${THEMES}
142) 175)
143 176
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index d25b99a32..59a193edd 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -611,6 +611,7 @@ void Config::ReadPathValues() {
611 } 611 }
612 } 612 }
613 UISettings::values.recent_files = ReadSetting(QStringLiteral("recentFiles")).toStringList(); 613 UISettings::values.recent_files = ReadSetting(QStringLiteral("recentFiles")).toStringList();
614 UISettings::values.language = ReadSetting(QStringLiteral("language"), QString{}).toString();
614 615
615 qt_config->endGroup(); 616 qt_config->endGroup();
616} 617}
@@ -661,6 +662,8 @@ void Config::ReadRendererValues() {
661 ReadSettingGlobal(Settings::values.use_vsync, QStringLiteral("use_vsync"), true); 662 ReadSettingGlobal(Settings::values.use_vsync, QStringLiteral("use_vsync"), true);
662 ReadSettingGlobal(Settings::values.use_assembly_shaders, QStringLiteral("use_assembly_shaders"), 663 ReadSettingGlobal(Settings::values.use_assembly_shaders, QStringLiteral("use_assembly_shaders"),
663 false); 664 false);
665 ReadSettingGlobal(Settings::values.use_asynchronous_shaders,
666 QStringLiteral("use_asynchronous_shaders"), false);
664 ReadSettingGlobal(Settings::values.use_fast_gpu_time, QStringLiteral("use_fast_gpu_time"), 667 ReadSettingGlobal(Settings::values.use_fast_gpu_time, QStringLiteral("use_fast_gpu_time"),
665 true); 668 true);
666 ReadSettingGlobal(Settings::values.force_30fps_mode, QStringLiteral("force_30fps_mode"), false); 669 ReadSettingGlobal(Settings::values.force_30fps_mode, QStringLiteral("force_30fps_mode"), false);
@@ -1093,6 +1096,7 @@ void Config::SavePathValues() {
1093 } 1096 }
1094 qt_config->endArray(); 1097 qt_config->endArray();
1095 WriteSetting(QStringLiteral("recentFiles"), UISettings::values.recent_files); 1098 WriteSetting(QStringLiteral("recentFiles"), UISettings::values.recent_files);
1099 WriteSetting(QStringLiteral("language"), UISettings::values.language, QString{});
1096 1100
1097 qt_config->endGroup(); 1101 qt_config->endGroup();
1098} 1102}
@@ -1145,6 +1149,8 @@ void Config::SaveRendererValues() {
1145 WriteSettingGlobal(QStringLiteral("use_vsync"), Settings::values.use_vsync, true); 1149 WriteSettingGlobal(QStringLiteral("use_vsync"), Settings::values.use_vsync, true);
1146 WriteSettingGlobal(QStringLiteral("use_assembly_shaders"), 1150 WriteSettingGlobal(QStringLiteral("use_assembly_shaders"),
1147 Settings::values.use_assembly_shaders, false); 1151 Settings::values.use_assembly_shaders, false);
1152 WriteSettingGlobal(QStringLiteral("use_asynchronous_shaders"),
1153 Settings::values.use_asynchronous_shaders, false);
1148 WriteSettingGlobal(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time, 1154 WriteSettingGlobal(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time,
1149 true); 1155 true);
1150 WriteSettingGlobal(QStringLiteral("force_30fps_mode"), Settings::values.force_30fps_mode, 1156 WriteSettingGlobal(QStringLiteral("force_30fps_mode"), Settings::values.force_30fps_mode,
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index a5afb354f..4e30dc51e 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -23,6 +23,7 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
23 SetConfiguration(); 23 SetConfiguration();
24 PopulateSelectionList(); 24 PopulateSelectionList();
25 25
26 connect(ui->uiTab, &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged);
26 connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, 27 connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
27 &ConfigureDialog::UpdateVisibleTabs); 28 &ConfigureDialog::UpdateVisibleTabs);
28 29
@@ -98,6 +99,14 @@ void ConfigureDialog::PopulateSelectionList() {
98 } 99 }
99} 100}
100 101
102void ConfigureDialog::OnLanguageChanged(const QString& locale) {
103 emit LanguageChanged(locale);
104 // first apply the configuration, and then restore the display
105 ApplyConfiguration();
106 RetranslateUI();
107 SetConfiguration();
108}
109
101void ConfigureDialog::UpdateVisibleTabs() { 110void ConfigureDialog::UpdateVisibleTabs() {
102 const auto items = ui->selectorList->selectedItems(); 111 const auto items = ui->selectorList->selectedItems();
103 if (items.isEmpty()) { 112 if (items.isEmpty()) {
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index 2d3bfc2da..4289bc225 100644
--- a/src/yuzu/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
@@ -22,6 +22,12 @@ public:
22 22
23 void ApplyConfiguration(); 23 void ApplyConfiguration();
24 24
25private slots:
26 void OnLanguageChanged(const QString& locale);
27
28signals:
29 void LanguageChanged(const QString& locale);
30
25private: 31private:
26 void changeEvent(QEvent* event) override; 32 void changeEvent(QEvent* event) override;
27 33
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index 7c0fa7ec5..ce30188cd 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -24,6 +24,7 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
24 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 24 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
25 ui->use_vsync->setEnabled(runtime_lock); 25 ui->use_vsync->setEnabled(runtime_lock);
26 ui->use_assembly_shaders->setEnabled(runtime_lock); 26 ui->use_assembly_shaders->setEnabled(runtime_lock);
27 ui->use_asynchronous_shaders->setEnabled(runtime_lock);
27 ui->force_30fps_mode->setEnabled(runtime_lock); 28 ui->force_30fps_mode->setEnabled(runtime_lock);
28 ui->anisotropic_filtering_combobox->setEnabled(runtime_lock); 29 ui->anisotropic_filtering_combobox->setEnabled(runtime_lock);
29 30
@@ -32,6 +33,8 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
32 static_cast<int>(Settings::values.gpu_accuracy.GetValue())); 33 static_cast<int>(Settings::values.gpu_accuracy.GetValue()));
33 ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue()); 34 ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue());
34 ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders.GetValue()); 35 ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders.GetValue());
36 ui->use_asynchronous_shaders->setChecked(
37 Settings::values.use_asynchronous_shaders.GetValue());
35 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); 38 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
36 ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode.GetValue()); 39 ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode.GetValue());
37 ui->anisotropic_filtering_combobox->setCurrentIndex( 40 ui->anisotropic_filtering_combobox->setCurrentIndex(
@@ -41,6 +44,10 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
41 ConfigurationShared::SetPerGameSetting(ui->use_vsync, &Settings::values.use_vsync); 44 ConfigurationShared::SetPerGameSetting(ui->use_vsync, &Settings::values.use_vsync);
42 ConfigurationShared::SetPerGameSetting(ui->use_assembly_shaders, 45 ConfigurationShared::SetPerGameSetting(ui->use_assembly_shaders,
43 &Settings::values.use_assembly_shaders); 46 &Settings::values.use_assembly_shaders);
47 ConfigurationShared::SetPerGameSetting(ui->use_asynchronous_shaders,
48 &Settings::values.use_asynchronous_shaders);
49 ConfigurationShared::SetPerGameSetting(ui->use_asynchronous_shaders,
50 &Settings::values.use_asynchronous_shaders);
44 ConfigurationShared::SetPerGameSetting(ui->use_fast_gpu_time, 51 ConfigurationShared::SetPerGameSetting(ui->use_fast_gpu_time,
45 &Settings::values.use_fast_gpu_time); 52 &Settings::values.use_fast_gpu_time);
46 ConfigurationShared::SetPerGameSetting(ui->force_30fps_mode, 53 ConfigurationShared::SetPerGameSetting(ui->force_30fps_mode,
@@ -67,6 +74,14 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
67 if (Settings::values.use_assembly_shaders.UsingGlobal()) { 74 if (Settings::values.use_assembly_shaders.UsingGlobal()) {
68 Settings::values.use_assembly_shaders.SetValue(ui->use_assembly_shaders->isChecked()); 75 Settings::values.use_assembly_shaders.SetValue(ui->use_assembly_shaders->isChecked());
69 } 76 }
77 if (Settings::values.use_asynchronous_shaders.UsingGlobal()) {
78 Settings::values.use_asynchronous_shaders.SetValue(
79 ui->use_asynchronous_shaders->isChecked());
80 }
81 if (Settings::values.use_asynchronous_shaders.UsingGlobal()) {
82 Settings::values.use_asynchronous_shaders.SetValue(
83 ui->use_asynchronous_shaders->isChecked());
84 }
70 if (Settings::values.use_fast_gpu_time.UsingGlobal()) { 85 if (Settings::values.use_fast_gpu_time.UsingGlobal()) {
71 Settings::values.use_fast_gpu_time.SetValue(ui->use_fast_gpu_time->isChecked()); 86 Settings::values.use_fast_gpu_time.SetValue(ui->use_fast_gpu_time->isChecked());
72 } 87 }
@@ -83,6 +98,10 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
83 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync); 98 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync);
84 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders, 99 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders,
85 ui->use_assembly_shaders); 100 ui->use_assembly_shaders);
101 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
102 ui->use_asynchronous_shaders);
103 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
104 ui->use_asynchronous_shaders);
86 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time, 105 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
87 ui->use_fast_gpu_time); 106 ui->use_fast_gpu_time);
88 ConfigurationShared::ApplyPerGameSetting(&Settings::values.force_30fps_mode, 107 ConfigurationShared::ApplyPerGameSetting(&Settings::values.force_30fps_mode,
@@ -117,6 +136,8 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
117 ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal()); 136 ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal());
118 ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal()); 137 ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal());
119 ui->use_assembly_shaders->setEnabled(Settings::values.use_assembly_shaders.UsingGlobal()); 138 ui->use_assembly_shaders->setEnabled(Settings::values.use_assembly_shaders.UsingGlobal());
139 ui->use_asynchronous_shaders->setEnabled(
140 Settings::values.use_asynchronous_shaders.UsingGlobal());
120 ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal()); 141 ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal());
121 ui->force_30fps_mode->setEnabled(Settings::values.force_30fps_mode.UsingGlobal()); 142 ui->force_30fps_mode->setEnabled(Settings::values.force_30fps_mode.UsingGlobal());
122 ui->anisotropic_filtering_combobox->setEnabled( 143 ui->anisotropic_filtering_combobox->setEnabled(
@@ -128,6 +149,7 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
128 ConfigurationShared::InsertGlobalItem(ui->gpu_accuracy); 149 ConfigurationShared::InsertGlobalItem(ui->gpu_accuracy);
129 ui->use_vsync->setTristate(true); 150 ui->use_vsync->setTristate(true);
130 ui->use_assembly_shaders->setTristate(true); 151 ui->use_assembly_shaders->setTristate(true);
152 ui->use_asynchronous_shaders->setTristate(true);
131 ui->use_fast_gpu_time->setTristate(true); 153 ui->use_fast_gpu_time->setTristate(true);
132 ui->force_30fps_mode->setTristate(true); 154 ui->force_30fps_mode->setTristate(true);
133 ConfigurationShared::InsertGlobalItem(ui->anisotropic_filtering_combobox); 155 ConfigurationShared::InsertGlobalItem(ui->anisotropic_filtering_combobox);
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index 0021607ac..71e7dfe5e 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -73,6 +73,16 @@
73 </widget> 73 </widget>
74 </item> 74 </item>
75 <item> 75 <item>
76 <widget class="QCheckBox" name="use_asynchronous_shaders">
77 <property name="toolTip">
78 <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string>
79 </property>
80 <property name="text">
81 <string>Use asynchronous shader building (experimental, OpenGL or Assembly shaders only)</string>
82 </property>
83 </widget>
84 </item>
85 <item>
76 <widget class="QCheckBox" name="force_30fps_mode"> 86 <widget class="QCheckBox" name="force_30fps_mode">
77 <property name="text"> 87 <property name="text">
78 <string>Force 30 FPS mode</string> 88 <string>Force 30 FPS mode</string>
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index 94424ee44..24b6c5b72 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -5,6 +5,7 @@
5#include <array> 5#include <array>
6#include <utility> 6#include <utility>
7 7
8#include <QDirIterator>
8#include "common/common_types.h" 9#include "common/common_types.h"
9#include "core/settings.h" 10#include "core/settings.h"
10#include "ui_configure_ui.h" 11#include "ui_configure_ui.h"
@@ -29,6 +30,8 @@ constexpr std::array row_text_names{
29ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureUi) { 30ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureUi) {
30 ui->setupUi(this); 31 ui->setupUi(this);
31 32
33 InitializeLanguageComboBox();
34
32 for (const auto& theme : UISettings::themes) { 35 for (const auto& theme : UISettings::themes) {
33 ui->theme_combobox->addItem(QString::fromUtf8(theme.first), 36 ui->theme_combobox->addItem(QString::fromUtf8(theme.first),
34 QString::fromUtf8(theme.second)); 37 QString::fromUtf8(theme.second));
@@ -72,6 +75,8 @@ void ConfigureUi::RequestGameListUpdate() {
72 75
73void ConfigureUi::SetConfiguration() { 76void ConfigureUi::SetConfiguration() {
74 ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); 77 ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
78 ui->language_combobox->setCurrentIndex(
79 ui->language_combobox->findData(UISettings::values.language));
75 ui->show_add_ons->setChecked(UISettings::values.show_add_ons); 80 ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
76 ui->icon_size_combobox->setCurrentIndex( 81 ui->icon_size_combobox->setCurrentIndex(
77 ui->icon_size_combobox->findData(UISettings::values.icon_size)); 82 ui->icon_size_combobox->findData(UISettings::values.icon_size));
@@ -100,6 +105,25 @@ void ConfigureUi::RetranslateUI() {
100 } 105 }
101} 106}
102 107
108void ConfigureUi::InitializeLanguageComboBox() {
109 ui->language_combobox->addItem(tr("<System>"), QString{});
110 ui->language_combobox->addItem(tr("English"), QStringLiteral("en"));
111 QDirIterator it(QStringLiteral(":/languages"), QDirIterator::NoIteratorFlags);
112 while (it.hasNext()) {
113 QString locale = it.next();
114 locale.truncate(locale.lastIndexOf(QLatin1Char{'.'}));
115 locale.remove(0, locale.lastIndexOf(QLatin1Char{'/'}) + 1);
116 const QString lang = QLocale::languageToString(QLocale(locale).language());
117 ui->language_combobox->addItem(lang, locale);
118 }
119
120 // Unlike other configuration changes, interface language changes need to be reflected on the
121 // interface immediately. This is done by passing a signal to the main window, and then
122 // retranslating when passing back.
123 connect(ui->language_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
124 &ConfigureUi::OnLanguageChanged);
125}
126
103void ConfigureUi::InitializeIconSizeComboBox() { 127void ConfigureUi::InitializeIconSizeComboBox() {
104 for (const auto& size : default_icon_sizes) { 128 for (const auto& size : default_icon_sizes) {
105 ui->icon_size_combobox->addItem(QString::fromUtf8(size.second), size.first); 129 ui->icon_size_combobox->addItem(QString::fromUtf8(size.second), size.first);
@@ -147,3 +171,10 @@ void ConfigureUi::UpdateSecondRowComboBox(bool init) {
147 ui->row_2_text_combobox->removeItem( 171 ui->row_2_text_combobox->removeItem(
148 ui->row_2_text_combobox->findData(ui->row_1_text_combobox->currentData())); 172 ui->row_2_text_combobox->findData(ui->row_1_text_combobox->currentData()));
149} 173}
174
175void ConfigureUi::OnLanguageChanged(int index) {
176 if (index == -1)
177 return;
178
179 emit LanguageChanged(ui->language_combobox->itemData(index).toString());
180}
diff --git a/src/yuzu/configuration/configure_ui.h b/src/yuzu/configuration/configure_ui.h
index d471afe99..c30bcf6ff 100644
--- a/src/yuzu/configuration/configure_ui.h
+++ b/src/yuzu/configuration/configure_ui.h
@@ -20,6 +20,12 @@ public:
20 20
21 void ApplyConfiguration(); 21 void ApplyConfiguration();
22 22
23private slots:
24 void OnLanguageChanged(int index);
25
26signals:
27 void LanguageChanged(const QString& locale);
28
23private: 29private:
24 void RequestGameListUpdate(); 30 void RequestGameListUpdate();
25 31
@@ -28,6 +34,7 @@ private:
28 void changeEvent(QEvent*) override; 34 void changeEvent(QEvent*) override;
29 void RetranslateUI(); 35 void RetranslateUI();
30 36
37 void InitializeLanguageComboBox();
31 void InitializeIconSizeComboBox(); 38 void InitializeIconSizeComboBox();
32 void InitializeRowComboBoxes(); 39 void InitializeRowComboBoxes();
33 40
diff --git a/src/yuzu/configuration/configure_ui.ui b/src/yuzu/configuration/configure_ui.ui
index bd5c5d3c2..0b81747d7 100644
--- a/src/yuzu/configuration/configure_ui.ui
+++ b/src/yuzu/configuration/configure_ui.ui
@@ -13,112 +13,132 @@
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <layout class="QHBoxLayout" name="HorizontalLayout"> 16 <layout class="QVBoxLayout" name="verticalLayout">
17 <item> 17 <item>
18 <layout class="QVBoxLayout" name="VerticalLayout"> 18 <widget class="QGroupBox" name="general_groupBox">
19 <item> 19 <property name="title">
20 <widget class="QGroupBox" name="GeneralGroupBox"> 20 <string>General</string>
21 <property name="title"> 21 </property>
22 <string>General</string> 22 <layout class="QHBoxLayout" name="horizontalLayout">
23 </property> 23 <item>
24 <layout class="QHBoxLayout" name="horizontalLayout"> 24 <layout class="QVBoxLayout" name="verticalLayout_2">
25 <item> 25 <item>
26 <layout class="QVBoxLayout" name="verticalLayout"> 26 <widget class="QLabel" name="label_change_language_info">
27 <property name="text">
28 <string>Note: Changing language will apply your configuration.</string>
29 </property>
30 <property name="wordWrap">
31 <bool>true</bool>
32 </property>
33 </widget>
34 </item>
35 <item>
36 <layout class="QHBoxLayout" name="horizontalLayout_2">
37 <item>
38 <widget class="QLabel" name="language_label">
39 <property name="text">
40 <string>Interface language:</string>
41 </property>
42 </widget>
43 </item>
44 <item>
45 <widget class="QComboBox" name="language_combobox"/>
46 </item>
47 </layout>
48 </item>
49 <item>
50 <layout class="QHBoxLayout" name="horizontalLayout_3">
51 <item>
52 <widget class="QLabel" name="theme_label">
53 <property name="text">
54 <string>Theme:</string>
55 </property>
56 </widget>
57 </item>
27 <item> 58 <item>
28 <layout class="QHBoxLayout" name="horizontalLayout_3"> 59 <widget class="QComboBox" name="theme_combobox"/>
29 <item>
30 <widget class="QLabel" name="theme_label">
31 <property name="text">
32 <string>Theme:</string>
33 </property>
34 </widget>
35 </item>
36 <item>
37 <widget class="QComboBox" name="theme_combobox"/>
38 </item>
39 </layout>
40 </item> 60 </item>
41 </layout> 61 </layout>
42 </item> 62 </item>
43 </layout> 63 </layout>
44 </widget> 64 </item>
45 </item> 65 </layout>
46 <item> 66 </widget>
47 <widget class="QGroupBox" name="GameListGroupBox"> 67 </item>
48 <property name="title"> 68 <item>
49 <string>Game List</string> 69 <widget class="QGroupBox" name="GameListGroupBox">
50 </property> 70 <property name="title">
51 <layout class="QHBoxLayout" name="GameListHorizontalLayout"> 71 <string>Game List</string>
72 </property>
73 <layout class="QHBoxLayout" name="GameListHorizontalLayout">
74 <item>
75 <layout class="QVBoxLayout" name="GeneralVerticalLayout">
52 <item> 76 <item>
53 <layout class="QVBoxLayout" name="GeneralVerticalLayout"> 77 <widget class="QCheckBox" name="show_add_ons">
78 <property name="text">
79 <string>Show Add-Ons Column</string>
80 </property>
81 </widget>
82 </item>
83 <item>
84 <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2">
54 <item> 85 <item>
55 <widget class="QCheckBox" name="show_add_ons"> 86 <widget class="QLabel" name="icon_size_label">
56 <property name="text"> 87 <property name="text">
57 <string>Show Add-Ons Column</string> 88 <string>Icon Size:</string>
58 </property> 89 </property>
59 </widget> 90 </widget>
60 </item> 91 </item>
61 <item> 92 <item>
62 <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2"> 93 <widget class="QComboBox" name="icon_size_combobox"/>
63 <item>
64 <widget class="QLabel" name="icon_size_label">
65 <property name="text">
66 <string>Icon Size:</string>
67 </property>
68 </widget>
69 </item>
70 <item>
71 <widget class="QComboBox" name="icon_size_combobox"/>
72 </item>
73 </layout>
74 </item> 94 </item>
95 </layout>
96 </item>
97 <item>
98 <layout class="QHBoxLayout" name="row_1_qhbox_layout">
75 <item> 99 <item>
76 <layout class="QHBoxLayout" name="row_1_qhbox_layout"> 100 <widget class="QLabel" name="row_1_label">
77 <item> 101 <property name="text">
78 <widget class="QLabel" name="row_1_label"> 102 <string>Row 1 Text:</string>
79 <property name="text"> 103 </property>
80 <string>Row 1 Text:</string> 104 </widget>
81 </property>
82 </widget>
83 </item>
84 <item>
85 <widget class="QComboBox" name="row_1_text_combobox"/>
86 </item>
87 </layout>
88 </item> 105 </item>
89 <item> 106 <item>
90 <layout class="QHBoxLayout" name="row_2_qhbox_layout"> 107 <widget class="QComboBox" name="row_1_text_combobox"/>
91 <item> 108 </item>
92 <widget class="QLabel" name="row_2_label"> 109 </layout>
93 <property name="text"> 110 </item>
94 <string>Row 2 Text:</string> 111 <item>
95 </property> 112 <layout class="QHBoxLayout" name="row_2_qhbox_layout">
96 </widget> 113 <item>
97 </item> 114 <widget class="QLabel" name="row_2_label">
98 <item> 115 <property name="text">
99 <widget class="QComboBox" name="row_2_text_combobox"/> 116 <string>Row 2 Text:</string>
100 </item> 117 </property>
101 </layout> 118 </widget>
119 </item>
120 <item>
121 <widget class="QComboBox" name="row_2_text_combobox"/>
102 </item> 122 </item>
103 </layout> 123 </layout>
104 </item> 124 </item>
105 </layout> 125 </layout>
106 </widget> 126 </item>
107 </item> 127 </layout>
108 <item> 128 </widget>
109 <spacer name="verticalSpacer"> 129 </item>
110 <property name="orientation"> 130 <item>
111 <enum>Qt::Vertical</enum> 131 <spacer name="verticalSpacer">
112 </property> 132 <property name="orientation">
113 <property name="sizeHint" stdset="0"> 133 <enum>Qt::Vertical</enum>
114 <size> 134 </property>
115 <width>20</width> 135 <property name="sizeHint" stdset="0">
116 <height>40</height> 136 <size>
117 </size> 137 <width>20</width>
118 </property> 138 <height>40</height>
119 </spacer> 139 </size>
120 </item> 140 </property>
121 </layout> 141 </spacer>
122 </item> 142 </item>
123 </layout> 143 </layout>
124 </widget> 144 </widget>
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 9bb0a0109..f391a41a9 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -2,9 +2,11 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array>
5#include <fmt/format.h> 6#include <fmt/format.h>
6 7
7#include "yuzu/debugger/wait_tree.h" 8#include "yuzu/debugger/wait_tree.h"
9#include "yuzu/uisettings.h"
8#include "yuzu/util/util.h" 10#include "yuzu/util/util.h"
9 11
10#include "common/assert.h" 12#include "common/assert.h"
@@ -19,11 +21,37 @@
19#include "core/hle/kernel/thread.h" 21#include "core/hle/kernel/thread.h"
20#include "core/memory.h" 22#include "core/memory.h"
21 23
24namespace {
25
26constexpr std::array<std::array<Qt::GlobalColor, 2>, 10> WaitTreeColors{{
27 {Qt::GlobalColor::darkGreen, Qt::GlobalColor::green},
28 {Qt::GlobalColor::darkGreen, Qt::GlobalColor::green},
29 {Qt::GlobalColor::darkBlue, Qt::GlobalColor::cyan},
30 {Qt::GlobalColor::lightGray, Qt::GlobalColor::lightGray},
31 {Qt::GlobalColor::lightGray, Qt::GlobalColor::lightGray},
32 {Qt::GlobalColor::darkRed, Qt::GlobalColor::red},
33 {Qt::GlobalColor::darkYellow, Qt::GlobalColor::yellow},
34 {Qt::GlobalColor::red, Qt::GlobalColor::red},
35 {Qt::GlobalColor::darkCyan, Qt::GlobalColor::cyan},
36 {Qt::GlobalColor::gray, Qt::GlobalColor::gray},
37}};
38
39bool IsDarkTheme() {
40 const auto& theme = UISettings::values.theme;
41 return theme == QStringLiteral("qdarkstyle") || theme == QStringLiteral("colorful_dark");
42}
43
44} // namespace
45
22WaitTreeItem::WaitTreeItem() = default; 46WaitTreeItem::WaitTreeItem() = default;
23WaitTreeItem::~WaitTreeItem() = default; 47WaitTreeItem::~WaitTreeItem() = default;
24 48
25QColor WaitTreeItem::GetColor() const { 49QColor WaitTreeItem::GetColor() const {
26 return QColor(Qt::GlobalColor::black); 50 if (IsDarkTheme()) {
51 return QColor(Qt::GlobalColor::white);
52 } else {
53 return QColor(Qt::GlobalColor::black);
54 }
27} 55}
28 56
29std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeItem::GetChildren() const { 57std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeItem::GetChildren() const {
@@ -263,36 +291,38 @@ QString WaitTreeThread::GetText() const {
263} 291}
264 292
265QColor WaitTreeThread::GetColor() const { 293QColor WaitTreeThread::GetColor() const {
294 const std::size_t color_index = IsDarkTheme() ? 1 : 0;
295
266 const auto& thread = static_cast<const Kernel::Thread&>(object); 296 const auto& thread = static_cast<const Kernel::Thread&>(object);
267 switch (thread.GetStatus()) { 297 switch (thread.GetStatus()) {
268 case Kernel::ThreadStatus::Running: 298 case Kernel::ThreadStatus::Running:
269 return QColor(Qt::GlobalColor::darkGreen); 299 return QColor(WaitTreeColors[0][color_index]);
270 case Kernel::ThreadStatus::Ready: 300 case Kernel::ThreadStatus::Ready:
271 if (!thread.IsPaused()) { 301 if (!thread.IsPaused()) {
272 if (thread.WasRunning()) { 302 if (thread.WasRunning()) {
273 return QColor(Qt::GlobalColor::darkGreen); 303 return QColor(WaitTreeColors[1][color_index]);
274 } else { 304 } else {
275 return QColor(Qt::GlobalColor::darkBlue); 305 return QColor(WaitTreeColors[2][color_index]);
276 } 306 }
277 } else { 307 } else {
278 return QColor(Qt::GlobalColor::lightGray); 308 return QColor(WaitTreeColors[3][color_index]);
279 } 309 }
280 case Kernel::ThreadStatus::Paused: 310 case Kernel::ThreadStatus::Paused:
281 return QColor(Qt::GlobalColor::lightGray); 311 return QColor(WaitTreeColors[4][color_index]);
282 case Kernel::ThreadStatus::WaitHLEEvent: 312 case Kernel::ThreadStatus::WaitHLEEvent:
283 case Kernel::ThreadStatus::WaitIPC: 313 case Kernel::ThreadStatus::WaitIPC:
284 return QColor(Qt::GlobalColor::darkRed); 314 return QColor(WaitTreeColors[5][color_index]);
285 case Kernel::ThreadStatus::WaitSleep: 315 case Kernel::ThreadStatus::WaitSleep:
286 return QColor(Qt::GlobalColor::darkYellow); 316 return QColor(WaitTreeColors[6][color_index]);
287 case Kernel::ThreadStatus::WaitSynch: 317 case Kernel::ThreadStatus::WaitSynch:
288 case Kernel::ThreadStatus::WaitMutex: 318 case Kernel::ThreadStatus::WaitMutex:
289 case Kernel::ThreadStatus::WaitCondVar: 319 case Kernel::ThreadStatus::WaitCondVar:
290 case Kernel::ThreadStatus::WaitArb: 320 case Kernel::ThreadStatus::WaitArb:
291 return QColor(Qt::GlobalColor::red); 321 return QColor(WaitTreeColors[7][color_index]);
292 case Kernel::ThreadStatus::Dormant: 322 case Kernel::ThreadStatus::Dormant:
293 return QColor(Qt::GlobalColor::darkCyan); 323 return QColor(WaitTreeColors[8][color_index]);
294 case Kernel::ThreadStatus::Dead: 324 case Kernel::ThreadStatus::Dead:
295 return QColor(Qt::GlobalColor::gray); 325 return QColor(WaitTreeColors[9][color_index]);
296 default: 326 default:
297 return WaitTreeItem::GetColor(); 327 return WaitTreeItem::GetColor();
298 } 328 }
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 9f758605a..31a635176 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -94,6 +94,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
94#include "core/perf_stats.h" 94#include "core/perf_stats.h"
95#include "core/settings.h" 95#include "core/settings.h"
96#include "core/telemetry_session.h" 96#include "core/telemetry_session.h"
97#include "video_core/gpu.h"
98#include "video_core/shader_notify.h"
97#include "yuzu/about_dialog.h" 99#include "yuzu/about_dialog.h"
98#include "yuzu/bootmanager.h" 100#include "yuzu/bootmanager.h"
99#include "yuzu/compatdb.h" 101#include "yuzu/compatdb.h"
@@ -189,6 +191,8 @@ GMainWindow::GMainWindow()
189 provider(std::make_unique<FileSys::ManualContentProvider>()) { 191 provider(std::make_unique<FileSys::ManualContentProvider>()) {
190 InitializeLogging(); 192 InitializeLogging();
191 193
194 LoadTranslation();
195
192 setAcceptDrops(true); 196 setAcceptDrops(true);
193 ui.setupUi(this); 197 ui.setupUi(this);
194 statusBar()->hide(); 198 statusBar()->hide();
@@ -498,6 +502,8 @@ void GMainWindow::InitializeWidgets() {
498 message_label->setAlignment(Qt::AlignLeft); 502 message_label->setAlignment(Qt::AlignLeft);
499 statusBar()->addPermanentWidget(message_label, 1); 503 statusBar()->addPermanentWidget(message_label, 1);
500 504
505 shader_building_label = new QLabel();
506 shader_building_label->setToolTip(tr("The amount of shaders currently being built"));
501 emu_speed_label = new QLabel(); 507 emu_speed_label = new QLabel();
502 emu_speed_label->setToolTip( 508 emu_speed_label->setToolTip(
503 tr("Current emulation speed. Values higher or lower than 100% " 509 tr("Current emulation speed. Values higher or lower than 100% "
@@ -510,7 +516,8 @@ void GMainWindow::InitializeWidgets() {
510 tr("Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For " 516 tr("Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For "
511 "full-speed emulation this should be at most 16.67 ms.")); 517 "full-speed emulation this should be at most 16.67 ms."));
512 518
513 for (auto& label : {emu_speed_label, game_fps_label, emu_frametime_label}) { 519 for (auto& label :
520 {shader_building_label, emu_speed_label, game_fps_label, emu_frametime_label}) {
514 label->setVisible(false); 521 label->setVisible(false);
515 label->setFrameStyle(QFrame::NoFrame); 522 label->setFrameStyle(QFrame::NoFrame);
516 label->setContentsMargins(4, 0, 4, 0); 523 label->setContentsMargins(4, 0, 4, 0);
@@ -1176,6 +1183,7 @@ void GMainWindow::ShutdownGame() {
1176 1183
1177 // Disable status bar updates 1184 // Disable status bar updates
1178 status_bar_update_timer.stop(); 1185 status_bar_update_timer.stop();
1186 shader_building_label->setVisible(false);
1179 emu_speed_label->setVisible(false); 1187 emu_speed_label->setVisible(false);
1180 game_fps_label->setVisible(false); 1188 game_fps_label->setVisible(false);
1181 emu_frametime_label->setVisible(false); 1189 emu_frametime_label->setVisible(false);
@@ -2042,6 +2050,9 @@ void GMainWindow::OnConfigure() {
2042 const bool old_discord_presence = UISettings::values.enable_discord_presence; 2050 const bool old_discord_presence = UISettings::values.enable_discord_presence;
2043 2051
2044 ConfigureDialog configure_dialog(this, hotkey_registry); 2052 ConfigureDialog configure_dialog(this, hotkey_registry);
2053 connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this,
2054 &GMainWindow::OnLanguageChanged);
2055
2045 const auto result = configure_dialog.exec(); 2056 const auto result = configure_dialog.exec();
2046 if (result != QDialog::Accepted) { 2057 if (result != QDialog::Accepted) {
2047 return; 2058 return;
@@ -2186,6 +2197,17 @@ void GMainWindow::UpdateStatusBar() {
2186 } 2197 }
2187 2198
2188 auto results = Core::System::GetInstance().GetAndResetPerfStats(); 2199 auto results = Core::System::GetInstance().GetAndResetPerfStats();
2200 auto& shader_notify = Core::System::GetInstance().GPU().ShaderNotify();
2201 const auto shaders_building = shader_notify.GetShadersBuilding();
2202
2203 if (shaders_building != 0) {
2204 shader_building_label->setText(
2205 tr("Building: %1 shader").arg(shaders_building) +
2206 (shaders_building != 1 ? QString::fromStdString("s") : QString::fromStdString("")));
2207 shader_building_label->setVisible(true);
2208 } else {
2209 shader_building_label->setVisible(false);
2210 }
2189 2211
2190 if (Settings::values.use_frame_limit.GetValue()) { 2212 if (Settings::values.use_frame_limit.GetValue()) {
2191 emu_speed_label->setText(tr("Speed: %1% / %2%") 2213 emu_speed_label->setText(tr("Speed: %1% / %2%")
@@ -2315,9 +2337,12 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
2315 if (behavior == ReinitializeKeyBehavior::Warning) { 2337 if (behavior == ReinitializeKeyBehavior::Warning) {
2316 const auto res = QMessageBox::information( 2338 const auto res = QMessageBox::information(
2317 this, tr("Confirm Key Rederivation"), 2339 this, tr("Confirm Key Rederivation"),
2318 tr("You are about to force rederive all of your keys. \nIf you do not know what this " 2340 tr("You are about to force rederive all of your keys. \nIf you do not know what "
2319 "means or what you are doing, \nthis is a potentially destructive action. \nPlease " 2341 "this "
2320 "make sure this is what you want \nand optionally make backups.\n\nThis will delete " 2342 "means or what you are doing, \nthis is a potentially destructive action. "
2343 "\nPlease "
2344 "make sure this is what you want \nand optionally make backups.\n\nThis will "
2345 "delete "
2321 "your autogenerated key files and re-run the key derivation module."), 2346 "your autogenerated key files and re-run the key derivation module."),
2322 QMessageBox::StandardButtons{QMessageBox::Ok, QMessageBox::Cancel}); 2347 QMessageBox::StandardButtons{QMessageBox::Ok, QMessageBox::Cancel});
2323 2348
@@ -2600,6 +2625,43 @@ void GMainWindow::UpdateUITheme() {
2600 QIcon::setThemeSearchPaths(theme_paths); 2625 QIcon::setThemeSearchPaths(theme_paths);
2601} 2626}
2602 2627
2628void GMainWindow::LoadTranslation() {
2629 // If the selected language is English, no need to install any translation
2630 if (UISettings::values.language == QStringLiteral("en")) {
2631 return;
2632 }
2633
2634 bool loaded;
2635
2636 if (UISettings::values.language.isEmpty()) {
2637 // If the selected language is empty, use system locale
2638 loaded = translator.load(QLocale(), {}, {}, QStringLiteral(":/languages/"));
2639 } else {
2640 // Otherwise load from the specified file
2641 loaded = translator.load(UISettings::values.language, QStringLiteral(":/languages/"));
2642 }
2643
2644 if (loaded) {
2645 qApp->installTranslator(&translator);
2646 } else {
2647 UISettings::values.language = QStringLiteral("en");
2648 }
2649}
2650
2651void GMainWindow::OnLanguageChanged(const QString& locale) {
2652 if (UISettings::values.language != QStringLiteral("en")) {
2653 qApp->removeTranslator(&translator);
2654 }
2655
2656 UISettings::values.language = locale;
2657 LoadTranslation();
2658 ui.retranslateUi(this);
2659 UpdateWindowTitle();
2660
2661 if (emulation_running)
2662 ui.action_Start->setText(tr("Continue"));
2663}
2664
2603void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { 2665void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) {
2604#ifdef USE_DISCORD_PRESENCE 2666#ifdef USE_DISCORD_PRESENCE
2605 if (state) { 2667 if (state) {
@@ -2628,8 +2690,8 @@ int main(int argc, char* argv[]) {
2628 2690
2629#ifdef __APPLE__ 2691#ifdef __APPLE__
2630 // If you start a bundle (binary) on OSX without the Terminal, the working directory is "/". 2692 // If you start a bundle (binary) on OSX without the Terminal, the working directory is "/".
2631 // But since we require the working directory to be the executable path for the location of the 2693 // But since we require the working directory to be the executable path for the location of
2632 // user folder in the Qt Frontend, we need to cd into that working directory 2694 // the user folder in the Qt Frontend, we need to cd into that working directory
2633 const std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + ".."; 2695 const std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + "..";
2634 chdir(bin_path.c_str()); 2696 chdir(bin_path.c_str());
2635#endif 2697#endif
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index adff65fb5..db573d606 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -10,6 +10,7 @@
10 10
11#include <QMainWindow> 11#include <QMainWindow>
12#include <QTimer> 12#include <QTimer>
13#include <QTranslator>
13 14
14#include "common/common_types.h" 15#include "common/common_types.h"
15#include "core/core.h" 16#include "core/core.h"
@@ -225,6 +226,7 @@ private slots:
225 void OnCaptureScreenshot(); 226 void OnCaptureScreenshot();
226 void OnCoreError(Core::System::ResultStatus, std::string); 227 void OnCoreError(Core::System::ResultStatus, std::string);
227 void OnReinitializeKeys(ReinitializeKeyBehavior behavior); 228 void OnReinitializeKeys(ReinitializeKeyBehavior behavior);
229 void OnLanguageChanged(const QString& locale);
228 230
229private: 231private:
230 std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); 232 std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
@@ -237,6 +239,7 @@ private:
237 void HideMouseCursor(); 239 void HideMouseCursor();
238 void ShowMouseCursor(); 240 void ShowMouseCursor();
239 void OpenURL(const QUrl& url); 241 void OpenURL(const QUrl& url);
242 void LoadTranslation();
240 243
241 Ui::MainWindow ui; 244 Ui::MainWindow ui;
242 245
@@ -248,6 +251,7 @@ private:
248 251
249 // Status bar elements 252 // Status bar elements
250 QLabel* message_label = nullptr; 253 QLabel* message_label = nullptr;
254 QLabel* shader_building_label = nullptr;
251 QLabel* emu_speed_label = nullptr; 255 QLabel* emu_speed_label = nullptr;
252 QLabel* game_fps_label = nullptr; 256 QLabel* game_fps_label = nullptr;
253 QLabel* emu_frametime_label = nullptr; 257 QLabel* emu_frametime_label = nullptr;
@@ -284,6 +288,8 @@ private:
284 288
285 HotkeyRegistry hotkey_registry; 289 HotkeyRegistry hotkey_registry;
286 290
291 QTranslator translator;
292
287 // Install progress dialog 293 // Install progress dialog
288 QProgressDialog* install_progress; 294 QProgressDialog* install_progress;
289 295
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index 830932d45..6cc65736d 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -75,6 +75,7 @@ struct Values {
75 bool game_dir_deprecated_deepscan; 75 bool game_dir_deprecated_deepscan;
76 QVector<UISettings::GameDir> game_dirs; 76 QVector<UISettings::GameDir> game_dirs;
77 QStringList recent_files; 77 QStringList recent_files;
78 QString language;
78 79
79 QString theme; 80 QString theme;
80 81
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 7773228c8..c2a2982fb 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -394,6 +394,10 @@ void Config::ReadValues() {
394 static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync", 1))); 394 static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync", 1)));
395 Settings::values.use_assembly_shaders.SetValue( 395 Settings::values.use_assembly_shaders.SetValue(
396 sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", false)); 396 sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", false));
397 Settings::values.use_asynchronous_shaders.SetValue(
398 sdl2_config->GetBoolean("Renderer", "use_asynchronous_shaders", false));
399 Settings::values.use_asynchronous_shaders.SetValue(
400 sdl2_config->GetBoolean("Renderer", "use_asynchronous_shaders", false));
397 Settings::values.use_fast_gpu_time.SetValue( 401 Settings::values.use_fast_gpu_time.SetValue(
398 sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true)); 402 sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true));
399 403
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 5bed47fd7..aa9e40380 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -166,6 +166,10 @@ use_vsync =
166# 0 (default): Off, 1: On 166# 0 (default): Off, 1: On
167use_assembly_shaders = 167use_assembly_shaders =
168 168
169# Whether to allow asynchronous shader building.
170# 0 (default): Off, 1: On
171use_asynchronous_shaders =
172
169# Turns on the frame limiter, which will limit frames output to the target game speed 173# Turns on the frame limiter, which will limit frames output to the target game speed
170# 0: Off, 1: On (default) 174# 0: Off, 1: On (default)
171use_frame_limit = 175use_frame_limit =