summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/CMakeLists.txt3
-rw-r--r--src/common/common_funcs.h13
-rw-r--r--src/common/error.cpp (renamed from src/common/misc.cpp)6
-rw-r--r--src/common/error.h21
-rw-r--r--src/common/settings.cpp4
-rw-r--r--src/common/settings.h8
-rw-r--r--src/common/thread.cpp6
-rw-r--r--src/core/file_sys/kernel_executable.h1
-rw-r--r--src/core/hle/api_version.h17
-rw-r--r--src/core/hle/kernel/kernel.h1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp9
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h4
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp2
-rw-r--r--src/core/network/network.cpp5
-rw-r--r--src/core/telemetry_session.cpp16
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/command_classes/codecs/codec.cpp224
-rw-r--r--src/video_core/command_classes/codecs/codec.h10
-rw-r--r--src/video_core/command_classes/codecs/h264.cpp3
-rw-r--r--src/video_core/memory_manager.cpp2
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_descriptor_pool.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp11
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp40
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.h6
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp30
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.h10
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h14
-rw-r--r--src/video_core/shader_environment.cpp1
-rw-r--r--src/video_core/texture_cache/slot_vector.h1
-rw-r--r--src/video_core/video_core.cpp3
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp10
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h6
-rw-r--r--src/yuzu/configuration/config.cpp7
-rw-r--r--src/yuzu/configuration/config.h1
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp42
-rw-r--r--src/yuzu/configuration/configure_graphics.h1
-rw-r--r--src/yuzu/configuration/configure_graphics.ui51
-rw-r--r--src/yuzu_cmd/config.cpp2
-rw-r--r--src/yuzu_cmd/default_ini.h6
42 files changed, 414 insertions, 195 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 57922b51c..b18a2a2f5 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -53,6 +53,8 @@ add_library(common STATIC
53 div_ceil.h 53 div_ceil.h
54 dynamic_library.cpp 54 dynamic_library.cpp
55 dynamic_library.h 55 dynamic_library.h
56 error.cpp
57 error.h
56 fiber.cpp 58 fiber.cpp
57 fiber.h 59 fiber.h
58 fs/file.cpp 60 fs/file.cpp
@@ -88,7 +90,6 @@ add_library(common STATIC
88 microprofile.cpp 90 microprofile.cpp
89 microprofile.h 91 microprofile.h
90 microprofileui.h 92 microprofileui.h
91 misc.cpp
92 nvidia_flags.cpp 93 nvidia_flags.cpp
93 nvidia_flags.h 94 nvidia_flags.h
94 page_table.cpp 95 page_table.cpp
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 53bd7da60..1e74d6930 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -4,9 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
8#include <array> 7#include <array>
9#include <string> 8#include <iterator>
10 9
11#if !defined(ARCHITECTURE_x86_64) 10#if !defined(ARCHITECTURE_x86_64)
12#include <cstdlib> // for exit 11#include <cstdlib> // for exit
@@ -49,16 +48,6 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
49 48
50#endif // _MSC_VER ndef 49#endif // _MSC_VER ndef
51 50
52// Generic function to get last error message.
53// Call directly after the command or use the error num.
54// This function might change the error code.
55// Defined in misc.cpp.
56[[nodiscard]] std::string GetLastErrorMsg();
57
58// Like GetLastErrorMsg(), but passing an explicit error code.
59// Defined in misc.cpp.
60[[nodiscard]] std::string NativeErrorToString(int e);
61
62#define DECLARE_ENUM_FLAG_OPERATORS(type) \ 51#define DECLARE_ENUM_FLAG_OPERATORS(type) \
63 [[nodiscard]] constexpr type operator|(type a, type b) noexcept { \ 52 [[nodiscard]] constexpr type operator|(type a, type b) noexcept { \
64 using T = std::underlying_type_t<type>; \ 53 using T = std::underlying_type_t<type>; \
diff --git a/src/common/misc.cpp b/src/common/error.cpp
index 495385b9e..d4455e310 100644
--- a/src/common/misc.cpp
+++ b/src/common/error.cpp
@@ -10,7 +10,9 @@
10#include <cstring> 10#include <cstring>
11#endif 11#endif
12 12
13#include "common/common_funcs.h" 13#include "common/error.h"
14
15namespace Common {
14 16
15std::string NativeErrorToString(int e) { 17std::string NativeErrorToString(int e) {
16#ifdef _WIN32 18#ifdef _WIN32
@@ -50,3 +52,5 @@ std::string GetLastErrorMsg() {
50 return NativeErrorToString(errno); 52 return NativeErrorToString(errno);
51#endif 53#endif
52} 54}
55
56} // namespace Common
diff --git a/src/common/error.h b/src/common/error.h
new file mode 100644
index 000000000..e084d4b0f
--- /dev/null
+++ b/src/common/error.h
@@ -0,0 +1,21 @@
1// Copyright 2013 Dolphin Emulator Project / 2014 Citra 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 <string>
8
9namespace Common {
10
11// Generic function to get last error message.
12// Call directly after the command or use the error num.
13// This function might change the error code.
14// Defined in error.cpp.
15[[nodiscard]] std::string GetLastErrorMsg();
16
17// Like GetLastErrorMsg(), but passing an explicit error code.
18// Defined in error.cpp.
19[[nodiscard]] std::string NativeErrorToString(int e);
20
21} // namespace Common
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index fd3b639cd..0d2df80a8 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -54,7 +54,7 @@ void LogSettings() {
54 log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue()); 54 log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue());
55 log_setting("Renderer_UseAsynchronousGpuEmulation", 55 log_setting("Renderer_UseAsynchronousGpuEmulation",
56 values.use_asynchronous_gpu_emulation.GetValue()); 56 values.use_asynchronous_gpu_emulation.GetValue());
57 log_setting("Renderer_UseNvdecEmulation", values.use_nvdec_emulation.GetValue()); 57 log_setting("Renderer_NvdecEmulation", values.nvdec_emulation.GetValue());
58 log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue()); 58 log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue());
59 log_setting("Renderer_UseVsync", values.use_vsync.GetValue()); 59 log_setting("Renderer_UseVsync", values.use_vsync.GetValue());
60 log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue()); 60 log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue());
@@ -136,7 +136,7 @@ void RestoreGlobalState(bool is_powered_on) {
136 values.use_disk_shader_cache.SetGlobal(true); 136 values.use_disk_shader_cache.SetGlobal(true);
137 values.gpu_accuracy.SetGlobal(true); 137 values.gpu_accuracy.SetGlobal(true);
138 values.use_asynchronous_gpu_emulation.SetGlobal(true); 138 values.use_asynchronous_gpu_emulation.SetGlobal(true);
139 values.use_nvdec_emulation.SetGlobal(true); 139 values.nvdec_emulation.SetGlobal(true);
140 values.accelerate_astc.SetGlobal(true); 140 values.accelerate_astc.SetGlobal(true);
141 values.use_vsync.SetGlobal(true); 141 values.use_vsync.SetGlobal(true);
142 values.shader_backend.SetGlobal(true); 142 values.shader_backend.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index ec4d381e8..b7195670b 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -48,6 +48,12 @@ enum class FullscreenMode : u32 {
48 Exclusive = 1, 48 Exclusive = 1,
49}; 49};
50 50
51enum class NvdecEmulation : u32 {
52 Off = 0,
53 CPU = 1,
54 GPU = 2,
55};
56
51/** The BasicSetting class is a simple resource manager. It defines a label and default value 57/** The BasicSetting class is a simple resource manager. It defines a label and default value
52 * alongside the actual value of the setting for simpler and less-error prone use with frontend 58 * alongside the actual value of the setting for simpler and less-error prone use with frontend
53 * configurations. Setting a default value and label is required, though subclasses may deviate from 59 * configurations. Setting a default value and label is required, though subclasses may deviate from
@@ -466,7 +472,7 @@ struct Values {
466 RangedSetting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal, 472 RangedSetting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal,
467 GPUAccuracy::Extreme, "gpu_accuracy"}; 473 GPUAccuracy::Extreme, "gpu_accuracy"};
468 Setting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"}; 474 Setting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
469 Setting<bool> use_nvdec_emulation{true, "use_nvdec_emulation"}; 475 Setting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
470 Setting<bool> accelerate_astc{true, "accelerate_astc"}; 476 Setting<bool> accelerate_astc{true, "accelerate_astc"};
471 Setting<bool> use_vsync{true, "use_vsync"}; 477 Setting<bool> use_vsync{true, "use_vsync"};
472 BasicRangedSetting<u16> fps_cap{1000, 1, 1000, "fps_cap"}; 478 BasicRangedSetting<u16> fps_cap{1000, 1, 1000, "fps_cap"};
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index d2c1ac60d..946a1114d 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -2,7 +2,9 @@
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 "common/common_funcs.h" 5#include <string>
6
7#include "common/error.h"
6#include "common/logging/log.h" 8#include "common/logging/log.h"
7#include "common/thread.h" 9#include "common/thread.h"
8#ifdef __APPLE__ 10#ifdef __APPLE__
@@ -21,8 +23,6 @@
21#include <unistd.h> 23#include <unistd.h>
22#endif 24#endif
23 25
24#include <string>
25
26#ifdef __FreeBSD__ 26#ifdef __FreeBSD__
27#define cpu_set_t cpuset_t 27#define cpu_set_t cpuset_t
28#endif 28#endif
diff --git a/src/core/file_sys/kernel_executable.h b/src/core/file_sys/kernel_executable.h
index 044c554d3..79ca82f8b 100644
--- a/src/core/file_sys/kernel_executable.h
+++ b/src/core/file_sys/kernel_executable.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <string>
8#include <vector> 9#include <vector>
9 10
10#include "common/common_funcs.h" 11#include "common/common_funcs.h"
diff --git a/src/core/hle/api_version.h b/src/core/hle/api_version.h
index 43d5670a9..626e30753 100644
--- a/src/core/hle/api_version.h
+++ b/src/core/hle/api_version.h
@@ -28,13 +28,20 @@ constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 12.1.0-1.0";
28 28
29// Atmosphere version constants. 29// Atmosphere version constants.
30 30
31constexpr u8 ATMOSPHERE_RELEASE_VERSION_MAJOR = 0; 31constexpr u8 ATMOSPHERE_RELEASE_VERSION_MAJOR = 1;
32constexpr u8 ATMOSPHERE_RELEASE_VERSION_MINOR = 19; 32constexpr u8 ATMOSPHERE_RELEASE_VERSION_MINOR = 0;
33constexpr u8 ATMOSPHERE_RELEASE_VERSION_MICRO = 5; 33constexpr u8 ATMOSPHERE_RELEASE_VERSION_MICRO = 0;
34
35constexpr u32 AtmosphereTargetFirmwareWithRevision(u8 major, u8 minor, u8 micro, u8 rev) {
36 return u32{major} << 24 | u32{minor} << 16 | u32{micro} << 8 | u32{rev};
37}
38
39constexpr u32 AtmosphereTargetFirmware(u8 major, u8 minor, u8 micro) {
40 return AtmosphereTargetFirmwareWithRevision(major, minor, micro, 0);
41}
34 42
35constexpr u32 GetTargetFirmware() { 43constexpr u32 GetTargetFirmware() {
36 return u32{HOS_VERSION_MAJOR} << 24 | u32{HOS_VERSION_MINOR} << 16 | 44 return AtmosphereTargetFirmware(HOS_VERSION_MAJOR, HOS_VERSION_MINOR, HOS_VERSION_MICRO);
37 u32{HOS_VERSION_MICRO} << 8 | 0U;
38} 45}
39 46
40} // namespace HLE::ApiVersion 47} // namespace HLE::ApiVersion
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 3a6db0b1c..901d43da9 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <functional>
8#include <memory> 9#include <memory>
9#include <string> 10#include <string>
10#include <unordered_map> 11#include <unordered_map>
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index ce6065db2..a33e47d0b 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -42,15 +42,14 @@ void nvdisp_disp0::OnClose(DeviceFD fd) {}
42void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, 42void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
43 u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform, 43 u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform,
44 const Common::Rectangle<int>& crop_rect) { 44 const Common::Rectangle<int>& crop_rect) {
45 VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle); 45 const VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle);
46 LOG_TRACE(Service, 46 LOG_TRACE(Service,
47 "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", 47 "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}",
48 addr, offset, width, height, stride, format); 48 addr, offset, width, height, stride, format);
49 49
50 using PixelFormat = Tegra::FramebufferConfig::PixelFormat; 50 const auto pixel_format = static_cast<Tegra::FramebufferConfig::PixelFormat>(format);
51 const Tegra::FramebufferConfig framebuffer{ 51 const Tegra::FramebufferConfig framebuffer{addr, offset, width, height,
52 addr, offset, width, height, stride, static_cast<PixelFormat>(format), 52 stride, pixel_format, transform, crop_rect};
53 transform, crop_rect};
54 53
55 system.GetPerfStats().EndSystemFrame(); 54 system.GetPerfStats().EndSystemFrame();
56 system.GPU().SwapBuffers(&framebuffer); 55 system.GPU().SwapBuffers(&framebuffer);
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 759247eb0..78de3f354 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -42,7 +42,9 @@ struct IGBPBuffer {
42 u32_le index; 42 u32_le index;
43 INSERT_PADDING_WORDS(3); 43 INSERT_PADDING_WORDS(3);
44 u32_le gpu_buffer_id; 44 u32_le gpu_buffer_id;
45 INSERT_PADDING_WORDS(17); 45 INSERT_PADDING_WORDS(6);
46 u32_le external_format;
47 INSERT_PADDING_WORDS(10);
46 u32_le nvmap_handle; 48 u32_le nvmap_handle;
47 u32_le offset; 49 u32_le offset;
48 INSERT_PADDING_WORDS(60); 50 INSERT_PADDING_WORDS(60);
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 00bff8caf..3ead813b0 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -298,7 +298,7 @@ void NVFlinger::Compose() {
298 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); 298 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0");
299 ASSERT(nvdisp); 299 ASSERT(nvdisp);
300 300
301 nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format, 301 nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.external_format,
302 igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, 302 igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride,
303 buffer->get().transform, buffer->get().crop_rect); 303 buffer->get().transform, buffer->get().crop_rect);
304 304
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp
index 4732d4485..72eea52f0 100644
--- a/src/core/network/network.cpp
+++ b/src/core/network/network.cpp
@@ -7,7 +7,8 @@
7#include <limits> 7#include <limits>
8#include <utility> 8#include <utility>
9#include <vector> 9#include <vector>
10#include "common/common_funcs.h" 10
11#include "common/error.h"
11 12
12#ifdef _WIN32 13#ifdef _WIN32
13#include <winsock2.h> 14#include <winsock2.h>
@@ -223,7 +224,7 @@ Errno GetAndLogLastError() {
223 if (err == Errno::AGAIN) { 224 if (err == Errno::AGAIN) {
224 return err; 225 return err;
225 } 226 }
226 LOG_ERROR(Network, "Socket operation error: {}", NativeErrorToString(e)); 227 LOG_ERROR(Network, "Socket operation error: {}", Common::NativeErrorToString(e));
227 return err; 228 return err;
228} 229}
229 230
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 5a8cfd301..1f1607998 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -72,6 +72,18 @@ static const char* TranslateGPUAccuracyLevel(Settings::GPUAccuracy backend) {
72 return "Unknown"; 72 return "Unknown";
73} 73}
74 74
75static const char* TranslateNvdecEmulation(Settings::NvdecEmulation backend) {
76 switch (backend) {
77 case Settings::NvdecEmulation::Off:
78 return "Off";
79 case Settings::NvdecEmulation::CPU:
80 return "CPU";
81 case Settings::NvdecEmulation::GPU:
82 return "GPU";
83 }
84 return "Unknown";
85}
86
75u64 GetTelemetryId() { 87u64 GetTelemetryId() {
76 u64 telemetry_id{}; 88 u64 telemetry_id{};
77 const auto filename = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "telemetry_id"; 89 const auto filename = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "telemetry_id";
@@ -229,8 +241,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
229 TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy.GetValue())); 241 TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy.GetValue()));
230 AddField(field_type, "Renderer_UseAsynchronousGpuEmulation", 242 AddField(field_type, "Renderer_UseAsynchronousGpuEmulation",
231 Settings::values.use_asynchronous_gpu_emulation.GetValue()); 243 Settings::values.use_asynchronous_gpu_emulation.GetValue());
232 AddField(field_type, "Renderer_UseNvdecEmulation", 244 AddField(field_type, "Renderer_NvdecEmulation",
233 Settings::values.use_nvdec_emulation.GetValue()); 245 TranslateNvdecEmulation(Settings::values.nvdec_emulation.GetValue()));
234 AddField(field_type, "Renderer_AccelerateASTC", Settings::values.accelerate_astc.GetValue()); 246 AddField(field_type, "Renderer_AccelerateASTC", Settings::values.accelerate_astc.GetValue());
235 AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue()); 247 AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue());
236 AddField(field_type, "Renderer_ShaderBackend", 248 AddField(field_type, "Renderer_ShaderBackend",
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 2f6cdd216..269db21a5 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -231,6 +231,7 @@ endif()
231 231
232target_include_directories(video_core PRIVATE ${FFmpeg_INCLUDE_DIR}) 232target_include_directories(video_core PRIVATE ${FFmpeg_INCLUDE_DIR})
233target_link_libraries(video_core PRIVATE ${FFmpeg_LIBRARIES}) 233target_link_libraries(video_core PRIVATE ${FFmpeg_LIBRARIES})
234target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS})
234 235
235add_dependencies(video_core host_shaders) 236add_dependencies(video_core host_shaders)
236target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) 237target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp
index f798a0053..61966cbfe 100644
--- a/src/video_core/command_classes/codecs/codec.cpp
+++ b/src/video_core/command_classes/codecs/codec.cpp
@@ -5,6 +5,7 @@
5#include <fstream> 5#include <fstream>
6#include <vector> 6#include <vector>
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/settings.h"
8#include "video_core/command_classes/codecs/codec.h" 9#include "video_core/command_classes/codecs/codec.h"
9#include "video_core/command_classes/codecs/h264.h" 10#include "video_core/command_classes/codecs/h264.h"
10#include "video_core/command_classes/codecs/vp9.h" 11#include "video_core/command_classes/codecs/vp9.h"
@@ -16,108 +17,146 @@ extern "C" {
16} 17}
17 18
18namespace Tegra { 19namespace Tegra {
19#if defined(LIBVA_FOUND)
20// Hardware acceleration code from FFmpeg/doc/examples/hw_decode.c originally under MIT license
21namespace { 20namespace {
22constexpr std::array<const char*, 2> VAAPI_DRIVERS = { 21constexpr AVPixelFormat PREFERRED_GPU_FMT = AV_PIX_FMT_NV12;
23 "i915", 22constexpr AVPixelFormat PREFERRED_CPU_FMT = AV_PIX_FMT_YUV420P;
24 "amdgpu", 23
25}; 24void AVPacketDeleter(AVPacket* ptr) {
25 av_packet_free(&ptr);
26}
26 27
27AVPixelFormat GetHwFormat(AVCodecContext*, const AVPixelFormat* pix_fmts) { 28using AVPacketPtr = std::unique_ptr<AVPacket, decltype(&AVPacketDeleter)>;
29
30AVPixelFormat GetGpuFormat(AVCodecContext* av_codec_ctx, const AVPixelFormat* pix_fmts) {
28 for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) { 31 for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) {
29 if (*p == AV_PIX_FMT_VAAPI) { 32 if (*p == av_codec_ctx->pix_fmt) {
30 return AV_PIX_FMT_VAAPI; 33 return av_codec_ctx->pix_fmt;
31 } 34 }
32 } 35 }
33 LOG_INFO(Service_NVDRV, "Could not find compatible GPU AV format, falling back to CPU"); 36 LOG_INFO(Service_NVDRV, "Could not find compatible GPU AV format, falling back to CPU");
34 return *pix_fmts; 37 av_buffer_unref(&av_codec_ctx->hw_device_ctx);
38 av_codec_ctx->pix_fmt = PREFERRED_CPU_FMT;
39 return PREFERRED_CPU_FMT;
40}
41} // namespace
42
43void AVFrameDeleter(AVFrame* ptr) {
44 av_frame_free(&ptr);
35} 45}
36 46
37bool CreateVaapiHwdevice(AVBufferRef** av_hw_device) { 47Codec::Codec(GPU& gpu_, const NvdecCommon::NvdecRegisters& regs)
48 : gpu(gpu_), state{regs}, h264_decoder(std::make_unique<Decoder::H264>(gpu)),
49 vp9_decoder(std::make_unique<Decoder::VP9>(gpu)) {}
50
51Codec::~Codec() {
52 if (!initialized) {
53 return;
54 }
55 // Free libav memory
56 avcodec_free_context(&av_codec_ctx);
57 av_buffer_unref(&av_gpu_decoder);
58}
59
60bool Codec::CreateGpuAvDevice() {
61#if defined(LIBVA_FOUND)
62 static constexpr std::array<const char*, 3> VAAPI_DRIVERS = {
63 "i915",
64 "iHD",
65 "amdgpu",
66 };
38 AVDictionary* hwdevice_options = nullptr; 67 AVDictionary* hwdevice_options = nullptr;
39 av_dict_set(&hwdevice_options, "connection_type", "drm", 0); 68 av_dict_set(&hwdevice_options, "connection_type", "drm", 0);
40 for (const auto& driver : VAAPI_DRIVERS) { 69 for (const auto& driver : VAAPI_DRIVERS) {
41 av_dict_set(&hwdevice_options, "kernel_driver", driver, 0); 70 av_dict_set(&hwdevice_options, "kernel_driver", driver, 0);
42 const int hwdevice_error = av_hwdevice_ctx_create(av_hw_device, AV_HWDEVICE_TYPE_VAAPI, 71 const int hwdevice_error = av_hwdevice_ctx_create(&av_gpu_decoder, AV_HWDEVICE_TYPE_VAAPI,
43 nullptr, hwdevice_options, 0); 72 nullptr, hwdevice_options, 0);
44 if (hwdevice_error >= 0) { 73 if (hwdevice_error >= 0) {
45 LOG_INFO(Service_NVDRV, "Using VA-API with {}", driver); 74 LOG_INFO(Service_NVDRV, "Using VA-API with {}", driver);
46 av_dict_free(&hwdevice_options); 75 av_dict_free(&hwdevice_options);
76 av_codec_ctx->pix_fmt = AV_PIX_FMT_VAAPI;
47 return true; 77 return true;
48 } 78 }
49 LOG_DEBUG(Service_NVDRV, "VA-API av_hwdevice_ctx_create failed {}", hwdevice_error); 79 LOG_DEBUG(Service_NVDRV, "VA-API av_hwdevice_ctx_create failed {}", hwdevice_error);
50 } 80 }
51 LOG_DEBUG(Service_NVDRV, "VA-API av_hwdevice_ctx_create failed for all drivers"); 81 LOG_DEBUG(Service_NVDRV, "VA-API av_hwdevice_ctx_create failed for all drivers");
52 av_dict_free(&hwdevice_options); 82 av_dict_free(&hwdevice_options);
53 return false;
54}
55} // namespace
56#endif 83#endif
57 84 static constexpr auto HW_CONFIG_METHOD = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX;
58void AVFrameDeleter(AVFrame* ptr) { 85 static constexpr std::array GPU_DECODER_TYPES{
59 av_frame_free(&ptr); 86 AV_HWDEVICE_TYPE_CUDA,
87#ifdef _WIN32
88 AV_HWDEVICE_TYPE_D3D11VA,
89#else
90 AV_HWDEVICE_TYPE_VDPAU,
91#endif
92 };
93 for (const auto& type : GPU_DECODER_TYPES) {
94 const int hwdevice_res = av_hwdevice_ctx_create(&av_gpu_decoder, type, nullptr, nullptr, 0);
95 if (hwdevice_res < 0) {
96 LOG_DEBUG(Service_NVDRV, "{} av_hwdevice_ctx_create failed {}",
97 av_hwdevice_get_type_name(type), hwdevice_res);
98 continue;
99 }
100 for (int i = 0;; i++) {
101 const AVCodecHWConfig* config = avcodec_get_hw_config(av_codec, i);
102 if (!config) {
103 LOG_DEBUG(Service_NVDRV, "{} decoder does not support device type {}.",
104 av_codec->name, av_hwdevice_get_type_name(type));
105 break;
106 }
107 if (config->methods & HW_CONFIG_METHOD && config->device_type == type) {
108 av_codec_ctx->pix_fmt = config->pix_fmt;
109 LOG_INFO(Service_NVDRV, "Using {} GPU decoder", av_hwdevice_get_type_name(type));
110 return true;
111 }
112 }
113 }
114 return false;
60} 115}
61 116
62Codec::Codec(GPU& gpu_, const NvdecCommon::NvdecRegisters& regs) 117void Codec::InitializeAvCodecContext() {
63 : gpu(gpu_), state{regs}, h264_decoder(std::make_unique<Decoder::H264>(gpu)), 118 av_codec_ctx = avcodec_alloc_context3(av_codec);
64 vp9_decoder(std::make_unique<Decoder::VP9>(gpu)) {} 119 av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0);
65
66Codec::~Codec() {
67 if (!initialized) {
68 return;
69 }
70 // Free libav memory
71 avcodec_send_packet(av_codec_ctx, nullptr);
72 AVFrame* av_frame = av_frame_alloc();
73 avcodec_receive_frame(av_codec_ctx, av_frame);
74 avcodec_flush_buffers(av_codec_ctx);
75 av_frame_free(&av_frame);
76 avcodec_close(av_codec_ctx);
77 av_buffer_unref(&av_hw_device);
78} 120}
79 121
80void Codec::InitializeHwdec() { 122void Codec::InitializeGpuDecoder() {
81 // Prioritize integrated GPU to mitigate bandwidth bottlenecks 123 if (!CreateGpuAvDevice()) {
82#if defined(LIBVA_FOUND) 124 av_buffer_unref(&av_gpu_decoder);
83 if (CreateVaapiHwdevice(&av_hw_device)) {
84 const auto hw_device_ctx = av_buffer_ref(av_hw_device);
85 ASSERT_MSG(hw_device_ctx, "av_buffer_ref failed");
86 av_codec_ctx->hw_device_ctx = hw_device_ctx;
87 av_codec_ctx->get_format = GetHwFormat;
88 return; 125 return;
89 } 126 }
90#endif 127 auto* hw_device_ctx = av_buffer_ref(av_gpu_decoder);
91 // TODO more GPU accelerated decoders 128 ASSERT_MSG(hw_device_ctx, "av_buffer_ref failed");
129 av_codec_ctx->hw_device_ctx = hw_device_ctx;
130 av_codec_ctx->get_format = GetGpuFormat;
92} 131}
93 132
94void Codec::Initialize() { 133void Codec::Initialize() {
95 AVCodecID codec; 134 const AVCodecID codec = [&] {
96 switch (current_codec) { 135 switch (current_codec) {
97 case NvdecCommon::VideoCodec::H264: 136 case NvdecCommon::VideoCodec::H264:
98 codec = AV_CODEC_ID_H264; 137 return AV_CODEC_ID_H264;
99 break; 138 case NvdecCommon::VideoCodec::Vp9:
100 case NvdecCommon::VideoCodec::Vp9: 139 return AV_CODEC_ID_VP9;
101 codec = AV_CODEC_ID_VP9; 140 default:
102 break; 141 UNIMPLEMENTED_MSG("Unknown codec {}", current_codec);
103 default: 142 return AV_CODEC_ID_NONE;
104 UNIMPLEMENTED_MSG("Unknown codec {}", current_codec); 143 }
144 }();
145 av_codec = avcodec_find_decoder(codec);
146
147 InitializeAvCodecContext();
148 if (Settings::values.nvdec_emulation.GetValue() == Settings::NvdecEmulation::GPU) {
149 InitializeGpuDecoder();
150 }
151 if (const int res = avcodec_open2(av_codec_ctx, av_codec, nullptr); res < 0) {
152 LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed with result {}", res);
153 avcodec_free_context(&av_codec_ctx);
154 av_buffer_unref(&av_gpu_decoder);
105 return; 155 return;
106 } 156 }
107 av_codec = avcodec_find_decoder(codec);
108 av_codec_ctx = avcodec_alloc_context3(av_codec);
109 av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0);
110 InitializeHwdec();
111 if (!av_codec_ctx->hw_device_ctx) { 157 if (!av_codec_ctx->hw_device_ctx) {
112 LOG_INFO(Service_NVDRV, "Using FFmpeg software decoding"); 158 LOG_INFO(Service_NVDRV, "Using FFmpeg software decoding");
113 } 159 }
114 const auto av_error = avcodec_open2(av_codec_ctx, av_codec, nullptr);
115 if (av_error < 0) {
116 LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed.");
117 avcodec_close(av_codec_ctx);
118 av_buffer_unref(&av_hw_device);
119 return;
120 }
121 initialized = true; 160 initialized = true;
122} 161}
123 162
@@ -133,6 +172,9 @@ void Codec::Decode() {
133 if (is_first_frame) { 172 if (is_first_frame) {
134 Initialize(); 173 Initialize();
135 } 174 }
175 if (!initialized) {
176 return;
177 }
136 bool vp9_hidden_frame = false; 178 bool vp9_hidden_frame = false;
137 std::vector<u8> frame_data; 179 std::vector<u8> frame_data;
138 if (current_codec == NvdecCommon::VideoCodec::H264) { 180 if (current_codec == NvdecCommon::VideoCodec::H264) {
@@ -141,50 +183,48 @@ void Codec::Decode() {
141 frame_data = vp9_decoder->ComposeFrameHeader(state); 183 frame_data = vp9_decoder->ComposeFrameHeader(state);
142 vp9_hidden_frame = vp9_decoder->WasFrameHidden(); 184 vp9_hidden_frame = vp9_decoder->WasFrameHidden();
143 } 185 }
144 AVPacket packet{}; 186 AVPacketPtr packet{av_packet_alloc(), AVPacketDeleter};
145 av_init_packet(&packet); 187 if (!packet) {
146 packet.data = frame_data.data(); 188 LOG_ERROR(Service_NVDRV, "av_packet_alloc failed");
147 packet.size = static_cast<s32>(frame_data.size()); 189 return;
148 if (const int ret = avcodec_send_packet(av_codec_ctx, &packet); ret) { 190 }
149 LOG_DEBUG(Service_NVDRV, "avcodec_send_packet error {}", ret); 191 packet->data = frame_data.data();
192 packet->size = static_cast<s32>(frame_data.size());
193 if (const int res = avcodec_send_packet(av_codec_ctx, packet.get()); res != 0) {
194 LOG_DEBUG(Service_NVDRV, "avcodec_send_packet error {}", res);
150 return; 195 return;
151 } 196 }
152 // Only receive/store visible frames 197 // Only receive/store visible frames
153 if (vp9_hidden_frame) { 198 if (vp9_hidden_frame) {
154 return; 199 return;
155 } 200 }
156 AVFrame* hw_frame = av_frame_alloc(); 201 AVFramePtr initial_frame{av_frame_alloc(), AVFrameDeleter};
157 AVFrame* sw_frame = hw_frame; 202 AVFramePtr final_frame{nullptr, AVFrameDeleter};
158 ASSERT_MSG(hw_frame, "av_frame_alloc hw_frame failed"); 203 ASSERT_MSG(initial_frame, "av_frame_alloc initial_frame failed");
159 if (const int ret = avcodec_receive_frame(av_codec_ctx, hw_frame); ret) { 204 if (const int ret = avcodec_receive_frame(av_codec_ctx, initial_frame.get()); ret) {
160 LOG_DEBUG(Service_NVDRV, "avcodec_receive_frame error {}", ret); 205 LOG_DEBUG(Service_NVDRV, "avcodec_receive_frame error {}", ret);
161 av_frame_free(&hw_frame);
162 return; 206 return;
163 } 207 }
164 if (!hw_frame->width || !hw_frame->height) { 208 if (initial_frame->width == 0 || initial_frame->height == 0) {
165 LOG_WARNING(Service_NVDRV, "Zero width or height in frame"); 209 LOG_WARNING(Service_NVDRV, "Zero width or height in frame");
166 av_frame_free(&hw_frame);
167 return; 210 return;
168 } 211 }
169#if defined(LIBVA_FOUND) 212 if (av_codec_ctx->hw_device_ctx) {
170 // Hardware acceleration code from FFmpeg/doc/examples/hw_decode.c under MIT license 213 final_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter};
171 if (hw_frame->format == AV_PIX_FMT_VAAPI) { 214 ASSERT_MSG(final_frame, "av_frame_alloc final_frame failed");
172 sw_frame = av_frame_alloc();
173 ASSERT_MSG(sw_frame, "av_frame_alloc sw_frame failed");
174 // Can't use AV_PIX_FMT_YUV420P and share code with software decoding in vic.cpp 215 // Can't use AV_PIX_FMT_YUV420P and share code with software decoding in vic.cpp
175 // because Intel drivers crash unless using AV_PIX_FMT_NV12 216 // because Intel drivers crash unless using AV_PIX_FMT_NV12
176 sw_frame->format = AV_PIX_FMT_NV12; 217 final_frame->format = PREFERRED_GPU_FMT;
177 const int transfer_data_ret = av_hwframe_transfer_data(sw_frame, hw_frame, 0); 218 const int ret = av_hwframe_transfer_data(final_frame.get(), initial_frame.get(), 0);
178 ASSERT_MSG(!transfer_data_ret, "av_hwframe_transfer_data error {}", transfer_data_ret); 219 ASSERT_MSG(!ret, "av_hwframe_transfer_data error {}", ret);
179 av_frame_free(&hw_frame); 220 } else {
221 final_frame = std::move(initial_frame);
180 } 222 }
181#endif 223 if (final_frame->format != PREFERRED_CPU_FMT && final_frame->format != PREFERRED_GPU_FMT) {
182 if (sw_frame->format != AV_PIX_FMT_YUV420P && sw_frame->format != AV_PIX_FMT_NV12) { 224 UNIMPLEMENTED_MSG("Unexpected video format: {}", final_frame->format);
183 UNIMPLEMENTED_MSG("Unexpected video format from host graphics: {}", sw_frame->format);
184 av_frame_free(&sw_frame);
185 return; 225 return;
186 } 226 }
187 av_frames.push(AVFramePtr{sw_frame, AVFrameDeleter}); 227 av_frames.push(std::move(final_frame));
188 if (av_frames.size() > 10) { 228 if (av_frames.size() > 10) {
189 LOG_TRACE(Service_NVDRV, "av_frames.push overflow dropped frame"); 229 LOG_TRACE(Service_NVDRV, "av_frames.push overflow dropped frame");
190 av_frames.pop(); 230 av_frames.pop();
diff --git a/src/video_core/command_classes/codecs/codec.h b/src/video_core/command_classes/codecs/codec.h
index 71936203f..f9a80886f 100644
--- a/src/video_core/command_classes/codecs/codec.h
+++ b/src/video_core/command_classes/codecs/codec.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <string_view>
8#include <queue> 9#include <queue>
9#include "common/common_types.h" 10#include "common/common_types.h"
10#include "video_core/command_classes/nvdec_common.h" 11#include "video_core/command_classes/nvdec_common.h"
@@ -50,18 +51,23 @@ public:
50 51
51 /// Returns the value of current_codec 52 /// Returns the value of current_codec
52 [[nodiscard]] NvdecCommon::VideoCodec GetCurrentCodec() const; 53 [[nodiscard]] NvdecCommon::VideoCodec GetCurrentCodec() const;
54
53 /// Return name of the current codec 55 /// Return name of the current codec
54 [[nodiscard]] std::string_view GetCurrentCodecName() const; 56 [[nodiscard]] std::string_view GetCurrentCodecName() const;
55 57
56private: 58private:
57 void InitializeHwdec(); 59 void InitializeAvCodecContext();
60
61 void InitializeGpuDecoder();
62
63 bool CreateGpuAvDevice();
58 64
59 bool initialized{}; 65 bool initialized{};
60 NvdecCommon::VideoCodec current_codec{NvdecCommon::VideoCodec::None}; 66 NvdecCommon::VideoCodec current_codec{NvdecCommon::VideoCodec::None};
61 67
62 AVCodec* av_codec{nullptr}; 68 AVCodec* av_codec{nullptr};
63 AVBufferRef* av_hw_device{nullptr};
64 AVCodecContext* av_codec_ctx{nullptr}; 69 AVCodecContext* av_codec_ctx{nullptr};
70 AVBufferRef* av_gpu_decoder{nullptr};
65 71
66 GPU& gpu; 72 GPU& gpu;
67 const NvdecCommon::NvdecRegisters& state; 73 const NvdecCommon::NvdecRegisters& state;
diff --git a/src/video_core/command_classes/codecs/h264.cpp b/src/video_core/command_classes/codecs/h264.cpp
index 5fb6d45ee..51ee14c13 100644
--- a/src/video_core/command_classes/codecs/h264.cpp
+++ b/src/video_core/command_classes/codecs/h264.cpp
@@ -95,7 +95,8 @@ const std::vector<u8>& H264::ComposeFrameHeader(const NvdecCommon::NvdecRegister
95 const s32 pic_height = context.h264_parameter_set.frame_height_in_map_units / 95 const s32 pic_height = context.h264_parameter_set.frame_height_in_map_units /
96 (context.h264_parameter_set.frame_mbs_only_flag ? 1 : 2); 96 (context.h264_parameter_set.frame_mbs_only_flag ? 1 : 2);
97 97
98 writer.WriteUe(16); 98 // TODO (ameerj): Where do we get this number, it seems to be particular for each stream
99 writer.WriteUe(6); // Max number of reference frames
99 writer.WriteBit(false); 100 writer.WriteBit(false);
100 writer.WriteUe(context.h264_parameter_set.pic_width_in_mbs - 1); 101 writer.WriteUe(context.h264_parameter_set.pic_width_in_mbs - 1);
101 writer.WriteUe(pic_height - 1); 102 writer.WriteUe(pic_height - 1);
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index c60ed6453..dce00e829 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -2,6 +2,8 @@
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 <algorithm>
6
5#include "common/alignment.h" 7#include "common/alignment.h"
6#include "common/assert.h" 8#include "common/assert.h"
7#include "common/logging/log.h" 9#include "common/logging/log.h"
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 7c9b0d6db..9ff0a28cd 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -164,7 +164,8 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
164 blit_screen.Recreate(); 164 blit_screen.Recreate();
165 } 165 }
166 const VkSemaphore render_semaphore = blit_screen.DrawToSwapchain(*framebuffer, use_accelerated); 166 const VkSemaphore render_semaphore = blit_screen.DrawToSwapchain(*framebuffer, use_accelerated);
167 scheduler.Flush(render_semaphore); 167 const VkSemaphore present_semaphore = swapchain.CurrentPresentSemaphore();
168 scheduler.Flush(render_semaphore, present_semaphore);
168 scheduler.WaitWorker(); 169 scheduler.WaitWorker();
169 swapchain.Present(render_semaphore); 170 swapchain.Present(render_semaphore);
170 171
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index cb0580182..888bc7392 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -358,7 +358,7 @@ void VKBlitScreen::CreateDescriptorPool() {
358void VKBlitScreen::CreateRenderPass() { 358void VKBlitScreen::CreateRenderPass() {
359 const VkAttachmentDescription color_attachment{ 359 const VkAttachmentDescription color_attachment{
360 .flags = 0, 360 .flags = 0,
361 .format = swapchain.GetImageFormat(), 361 .format = swapchain.GetImageViewFormat(),
362 .samples = VK_SAMPLE_COUNT_1_BIT, 362 .samples = VK_SAMPLE_COUNT_1_BIT,
363 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 363 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
364 .storeOp = VK_ATTACHMENT_STORE_OP_STORE, 364 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
index 8e77e4796..adb557f60 100644
--- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
@@ -2,6 +2,7 @@
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 <algorithm>
5#include <mutex> 6#include <mutex>
6#include <span> 7#include <span>
7#include <vector> 8#include <vector>
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 3ac18ea54..841a6b846 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -228,9 +228,7 @@ void RasterizerVulkan::Clear() {
228 }; 228 };
229 229
230 const u32 color_attachment = regs.clear_buffers.RT; 230 const u32 color_attachment = regs.clear_buffers.RT;
231 const auto attachment_aspect_mask = framebuffer->ImageRanges()[color_attachment].aspectMask; 231 if (use_color && framebuffer->HasAspectColorBit(color_attachment)) {
232 const bool is_color_rt = (attachment_aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0;
233 if (use_color && is_color_rt) {
234 VkClearValue clear_value; 232 VkClearValue clear_value;
235 std::memcpy(clear_value.color.float32, regs.clear_color, sizeof(regs.clear_color)); 233 std::memcpy(clear_value.color.float32, regs.clear_color, sizeof(regs.clear_color));
236 234
@@ -248,12 +246,15 @@ void RasterizerVulkan::Clear() {
248 return; 246 return;
249 } 247 }
250 VkImageAspectFlags aspect_flags = 0; 248 VkImageAspectFlags aspect_flags = 0;
251 if (use_depth) { 249 if (use_depth && framebuffer->HasAspectDepthBit()) {
252 aspect_flags |= VK_IMAGE_ASPECT_DEPTH_BIT; 250 aspect_flags |= VK_IMAGE_ASPECT_DEPTH_BIT;
253 } 251 }
254 if (use_stencil) { 252 if (use_stencil && framebuffer->HasAspectStencilBit()) {
255 aspect_flags |= VK_IMAGE_ASPECT_STENCIL_BIT; 253 aspect_flags |= VK_IMAGE_ASPECT_STENCIL_BIT;
256 } 254 }
255 if (aspect_flags == 0) {
256 return;
257 }
257 scheduler.Record([clear_depth = regs.clear_depth, clear_stencil = regs.clear_stencil, 258 scheduler.Record([clear_depth = regs.clear_depth, clear_stencil = regs.clear_stencil,
258 clear_rect, aspect_flags](vk::CommandBuffer cmdbuf) { 259 clear_rect, aspect_flags](vk::CommandBuffer cmdbuf) {
259 VkClearAttachment attachment; 260 VkClearAttachment attachment;
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index 4840962de..1d438787a 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -55,14 +55,14 @@ VKScheduler::~VKScheduler() {
55 worker_thread.join(); 55 worker_thread.join();
56} 56}
57 57
58void VKScheduler::Flush(VkSemaphore semaphore) { 58void VKScheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
59 SubmitExecution(semaphore); 59 SubmitExecution(signal_semaphore, wait_semaphore);
60 AllocateNewContext(); 60 AllocateNewContext();
61} 61}
62 62
63void VKScheduler::Finish(VkSemaphore semaphore) { 63void VKScheduler::Finish(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
64 const u64 presubmit_tick = CurrentTick(); 64 const u64 presubmit_tick = CurrentTick();
65 SubmitExecution(semaphore); 65 SubmitExecution(signal_semaphore, wait_semaphore);
66 WaitWorker(); 66 WaitWorker();
67 Wait(presubmit_tick); 67 Wait(presubmit_tick);
68 AllocateNewContext(); 68 AllocateNewContext();
@@ -171,37 +171,41 @@ void VKScheduler::AllocateWorkerCommandBuffer() {
171 }); 171 });
172} 172}
173 173
174void VKScheduler::SubmitExecution(VkSemaphore semaphore) { 174void VKScheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
175 EndPendingOperations(); 175 EndPendingOperations();
176 InvalidateState(); 176 InvalidateState();
177 177
178 const u64 signal_value = master_semaphore->NextTick(); 178 const u64 signal_value = master_semaphore->NextTick();
179 Record([semaphore, signal_value, this](vk::CommandBuffer cmdbuf) { 179 Record([signal_semaphore, wait_semaphore, signal_value, this](vk::CommandBuffer cmdbuf) {
180 cmdbuf.End(); 180 cmdbuf.End();
181
182 const u32 num_signal_semaphores = semaphore ? 2U : 1U;
183
184 const u64 wait_value = signal_value - 1;
185 const VkPipelineStageFlags wait_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
186
187 const VkSemaphore timeline_semaphore = master_semaphore->Handle(); 181 const VkSemaphore timeline_semaphore = master_semaphore->Handle();
182
183 const u32 num_signal_semaphores = signal_semaphore ? 2U : 1U;
188 const std::array signal_values{signal_value, u64(0)}; 184 const std::array signal_values{signal_value, u64(0)};
189 const std::array signal_semaphores{timeline_semaphore, semaphore}; 185 const std::array signal_semaphores{timeline_semaphore, signal_semaphore};
186
187 const u32 num_wait_semaphores = wait_semaphore ? 2U : 1U;
188 const std::array wait_values{signal_value - 1, u64(1)};
189 const std::array wait_semaphores{timeline_semaphore, wait_semaphore};
190 static constexpr std::array<VkPipelineStageFlags, 2> wait_stage_masks{
191 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
192 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
193 };
190 194
191 const VkTimelineSemaphoreSubmitInfoKHR timeline_si{ 195 const VkTimelineSemaphoreSubmitInfoKHR timeline_si{
192 .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR, 196 .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR,
193 .pNext = nullptr, 197 .pNext = nullptr,
194 .waitSemaphoreValueCount = 1, 198 .waitSemaphoreValueCount = num_wait_semaphores,
195 .pWaitSemaphoreValues = &wait_value, 199 .pWaitSemaphoreValues = wait_values.data(),
196 .signalSemaphoreValueCount = num_signal_semaphores, 200 .signalSemaphoreValueCount = num_signal_semaphores,
197 .pSignalSemaphoreValues = signal_values.data(), 201 .pSignalSemaphoreValues = signal_values.data(),
198 }; 202 };
199 const VkSubmitInfo submit_info{ 203 const VkSubmitInfo submit_info{
200 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, 204 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
201 .pNext = &timeline_si, 205 .pNext = &timeline_si,
202 .waitSemaphoreCount = 1, 206 .waitSemaphoreCount = num_wait_semaphores,
203 .pWaitSemaphores = &timeline_semaphore, 207 .pWaitSemaphores = wait_semaphores.data(),
204 .pWaitDstStageMask = &wait_stage_mask, 208 .pWaitDstStageMask = wait_stage_masks.data(),
205 .commandBufferCount = 1, 209 .commandBufferCount = 1,
206 .pCommandBuffers = cmdbuf.address(), 210 .pCommandBuffers = cmdbuf.address(),
207 .signalSemaphoreCount = num_signal_semaphores, 211 .signalSemaphoreCount = num_signal_semaphores,
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h
index cf39a2363..759ed5a48 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.h
+++ b/src/video_core/renderer_vulkan/vk_scheduler.h
@@ -34,10 +34,10 @@ public:
34 ~VKScheduler(); 34 ~VKScheduler();
35 35
36 /// Sends the current execution context to the GPU. 36 /// Sends the current execution context to the GPU.
37 void Flush(VkSemaphore semaphore = nullptr); 37 void Flush(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr);
38 38
39 /// Sends the current execution context to the GPU and waits for it to complete. 39 /// Sends the current execution context to the GPU and waits for it to complete.
40 void Finish(VkSemaphore semaphore = nullptr); 40 void Finish(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr);
41 41
42 /// Waits for the worker thread to finish executing everything. After this function returns it's 42 /// Waits for the worker thread to finish executing everything. After this function returns it's
43 /// safe to touch worker resources. 43 /// safe to touch worker resources.
@@ -191,7 +191,7 @@ private:
191 191
192 void AllocateWorkerCommandBuffer(); 192 void AllocateWorkerCommandBuffer();
193 193
194 void SubmitExecution(VkSemaphore semaphore); 194 void SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore);
195 195
196 void AllocateNewContext(); 196 void AllocateNewContext();
197 197
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index d990eefba..aadf03cb0 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -20,16 +20,15 @@ namespace Vulkan {
20 20
21namespace { 21namespace {
22 22
23VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span<VkSurfaceFormatKHR> formats, bool srgb) { 23VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span<VkSurfaceFormatKHR> formats) {
24 if (formats.size() == 1 && formats[0].format == VK_FORMAT_UNDEFINED) { 24 if (formats.size() == 1 && formats[0].format == VK_FORMAT_UNDEFINED) {
25 VkSurfaceFormatKHR format; 25 VkSurfaceFormatKHR format;
26 format.format = VK_FORMAT_B8G8R8A8_UNORM; 26 format.format = VK_FORMAT_B8G8R8A8_UNORM;
27 format.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; 27 format.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
28 return format; 28 return format;
29 } 29 }
30 const auto& found = std::find_if(formats.begin(), formats.end(), [srgb](const auto& format) { 30 const auto& found = std::find_if(formats.begin(), formats.end(), [](const auto& format) {
31 const auto request_format = srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM; 31 return format.format == VK_FORMAT_B8G8R8A8_UNORM &&
32 return format.format == request_format &&
33 format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; 32 format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
34 }); 33 });
35 return found != formats.end() ? *found : formats[0]; 34 return found != formats.end() ? *found : formats[0];
@@ -107,14 +106,12 @@ void VKSwapchain::AcquireNextImage() {
107} 106}
108 107
109void VKSwapchain::Present(VkSemaphore render_semaphore) { 108void VKSwapchain::Present(VkSemaphore render_semaphore) {
110 const VkSemaphore present_semaphore{*present_semaphores[frame_index]};
111 const std::array<VkSemaphore, 2> semaphores{present_semaphore, render_semaphore};
112 const auto present_queue{device.GetPresentQueue()}; 109 const auto present_queue{device.GetPresentQueue()};
113 const VkPresentInfoKHR present_info{ 110 const VkPresentInfoKHR present_info{
114 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 111 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
115 .pNext = nullptr, 112 .pNext = nullptr,
116 .waitSemaphoreCount = render_semaphore ? 2U : 1U, 113 .waitSemaphoreCount = render_semaphore ? 1U : 0U,
117 .pWaitSemaphores = semaphores.data(), 114 .pWaitSemaphores = &render_semaphore,
118 .swapchainCount = 1, 115 .swapchainCount = 1,
119 .pSwapchains = swapchain.address(), 116 .pSwapchains = swapchain.address(),
120 .pImageIndices = &image_index, 117 .pImageIndices = &image_index,
@@ -145,7 +142,7 @@ void VKSwapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities,
145 const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; 142 const auto formats{physical_device.GetSurfaceFormatsKHR(surface)};
146 const auto present_modes{physical_device.GetSurfacePresentModesKHR(surface)}; 143 const auto present_modes{physical_device.GetSurfacePresentModesKHR(surface)};
147 144
148 const VkSurfaceFormatKHR surface_format{ChooseSwapSurfaceFormat(formats, srgb)}; 145 const VkSurfaceFormatKHR surface_format{ChooseSwapSurfaceFormat(formats)};
149 const VkPresentModeKHR present_mode{ChooseSwapPresentMode(present_modes)}; 146 const VkPresentModeKHR present_mode{ChooseSwapPresentMode(present_modes)};
150 147
151 u32 requested_image_count{capabilities.minImageCount + 1}; 148 u32 requested_image_count{capabilities.minImageCount + 1};
@@ -180,6 +177,17 @@ void VKSwapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities,
180 swapchain_ci.queueFamilyIndexCount = static_cast<u32>(queue_indices.size()); 177 swapchain_ci.queueFamilyIndexCount = static_cast<u32>(queue_indices.size());
181 swapchain_ci.pQueueFamilyIndices = queue_indices.data(); 178 swapchain_ci.pQueueFamilyIndices = queue_indices.data();
182 } 179 }
180 static constexpr std::array view_formats{VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SRGB};
181 VkImageFormatListCreateInfo format_list{
182 .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
183 .pNext = nullptr,
184 .viewFormatCount = static_cast<u32>(view_formats.size()),
185 .pViewFormats = view_formats.data(),
186 };
187 if (device.IsKhrSwapchainMutableFormatEnabled()) {
188 format_list.pNext = std::exchange(swapchain_ci.pNext, &format_list);
189 swapchain_ci.flags |= VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR;
190 }
183 // Request the size again to reduce the possibility of a TOCTOU race condition. 191 // Request the size again to reduce the possibility of a TOCTOU race condition.
184 const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(surface); 192 const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(surface);
185 swapchain_ci.imageExtent = ChooseSwapExtent(updated_capabilities, width, height); 193 swapchain_ci.imageExtent = ChooseSwapExtent(updated_capabilities, width, height);
@@ -191,7 +199,7 @@ void VKSwapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities,
191 199
192 images = swapchain.GetImages(); 200 images = swapchain.GetImages();
193 image_count = static_cast<u32>(images.size()); 201 image_count = static_cast<u32>(images.size());
194 image_format = surface_format.format; 202 image_view_format = srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
195} 203}
196 204
197void VKSwapchain::CreateSemaphores() { 205void VKSwapchain::CreateSemaphores() {
@@ -207,7 +215,7 @@ void VKSwapchain::CreateImageViews() {
207 .flags = 0, 215 .flags = 0,
208 .image = {}, 216 .image = {},
209 .viewType = VK_IMAGE_VIEW_TYPE_2D, 217 .viewType = VK_IMAGE_VIEW_TYPE_2D,
210 .format = image_format, 218 .format = image_view_format,
211 .components = 219 .components =
212 { 220 {
213 .r = VK_COMPONENT_SWIZZLE_IDENTITY, 221 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h
index 35c2cdc14..5bce41e21 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.h
+++ b/src/video_core/renderer_vulkan/vk_swapchain.h
@@ -68,8 +68,12 @@ public:
68 return *image_views[index]; 68 return *image_views[index];
69 } 69 }
70 70
71 VkFormat GetImageFormat() const { 71 VkFormat GetImageViewFormat() const {
72 return image_format; 72 return image_view_format;
73 }
74
75 VkSemaphore CurrentPresentSemaphore() const {
76 return *present_semaphores[frame_index];
73 } 77 }
74 78
75private: 79private:
@@ -96,7 +100,7 @@ private:
96 u32 image_index{}; 100 u32 image_index{};
97 u32 frame_index{}; 101 u32 frame_index{};
98 102
99 VkFormat image_format{}; 103 VkFormat image_view_format{};
100 VkExtent2D extent{}; 104 VkExtent2D extent{};
101 105
102 bool current_srgb{}; 106 bool current_srgb{};
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 8f4df7122..ff979a7ac 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -1186,9 +1186,12 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
1186 renderpass_key.depth_format = depth_buffer->format; 1186 renderpass_key.depth_format = depth_buffer->format;
1187 num_layers = std::max(num_layers, depth_buffer->range.extent.layers); 1187 num_layers = std::max(num_layers, depth_buffer->range.extent.layers);
1188 images[num_images] = depth_buffer->ImageHandle(); 1188 images[num_images] = depth_buffer->ImageHandle();
1189 image_ranges[num_images] = MakeSubresourceRange(depth_buffer); 1189 const VkImageSubresourceRange subresource_range = MakeSubresourceRange(depth_buffer);
1190 image_ranges[num_images] = subresource_range;
1190 samples = depth_buffer->Samples(); 1191 samples = depth_buffer->Samples();
1191 ++num_images; 1192 ++num_images;
1193 has_depth = (subresource_range.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
1194 has_stencil = (subresource_range.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
1192 } else { 1195 } else {
1193 renderpass_key.depth_format = PixelFormat::Invalid; 1196 renderpass_key.depth_format = PixelFormat::Invalid;
1194 } 1197 }
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 5fe6b7ba3..6d5a68bfe 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -232,6 +232,18 @@ public:
232 return image_ranges; 232 return image_ranges;
233 } 233 }
234 234
235 [[nodiscard]] bool HasAspectColorBit(size_t index) const noexcept {
236 return (image_ranges.at(index).aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0;
237 }
238
239 [[nodiscard]] bool HasAspectDepthBit() const noexcept {
240 return has_depth;
241 }
242
243 [[nodiscard]] bool HasAspectStencilBit() const noexcept {
244 return has_stencil;
245 }
246
235private: 247private:
236 vk::Framebuffer framebuffer; 248 vk::Framebuffer framebuffer;
237 VkRenderPass renderpass{}; 249 VkRenderPass renderpass{};
@@ -241,6 +253,8 @@ private:
241 u32 num_images = 0; 253 u32 num_images = 0;
242 std::array<VkImage, 9> images{}; 254 std::array<VkImage, 9> images{};
243 std::array<VkImageSubresourceRange, 9> image_ranges{}; 255 std::array<VkImageSubresourceRange, 9> image_ranges{};
256 bool has_depth{};
257 bool has_stencil{};
244}; 258};
245 259
246struct TextureCacheParams { 260struct TextureCacheParams {
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp
index 8a4581c19..81a878bb2 100644
--- a/src/video_core/shader_environment.cpp
+++ b/src/video_core/shader_environment.cpp
@@ -2,6 +2,7 @@
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 <algorithm>
5#include <filesystem> 6#include <filesystem>
6#include <fstream> 7#include <fstream>
7#include <memory> 8#include <memory>
diff --git a/src/video_core/texture_cache/slot_vector.h b/src/video_core/texture_cache/slot_vector.h
index 6180b8c0e..74cd3c9d8 100644
--- a/src/video_core/texture_cache/slot_vector.h
+++ b/src/video_core/texture_cache/slot_vector.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
7#include <array> 8#include <array>
8#include <bit> 9#include <bit>
9#include <concepts> 10#include <concepts>
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index 3b575db4d..cae543a51 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -37,7 +37,8 @@ std::unique_ptr<VideoCore::RendererBase> CreateRenderer(
37namespace VideoCore { 37namespace VideoCore {
38 38
39std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system) { 39std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system) {
40 const bool use_nvdec = Settings::values.use_nvdec_emulation.GetValue(); 40 const auto nvdec_value = Settings::values.nvdec_emulation.GetValue();
41 const bool use_nvdec = nvdec_value != Settings::NvdecEmulation::Off;
41 const bool use_async = Settings::values.use_asynchronous_gpu_emulation.GetValue(); 42 const bool use_async = Settings::values.use_asynchronous_gpu_emulation.GetValue();
42 auto gpu = std::make_unique<Tegra::GPU>(system, use_async, use_nvdec); 43 auto gpu = std::make_unique<Tegra::GPU>(system, use_async, use_nvdec);
43 auto context = emu_window.CreateSharedContext(); 44 auto context = emu_window.CreateSharedContext();
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 86ca4be54..24821c1a3 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -839,6 +839,8 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
839 bool has_khr_shader_float16_int8{}; 839 bool has_khr_shader_float16_int8{};
840 bool has_khr_workgroup_memory_explicit_layout{}; 840 bool has_khr_workgroup_memory_explicit_layout{};
841 bool has_khr_pipeline_executable_properties{}; 841 bool has_khr_pipeline_executable_properties{};
842 bool has_khr_image_format_list{};
843 bool has_khr_swapchain_mutable_format{};
842 bool has_ext_subgroup_size_control{}; 844 bool has_ext_subgroup_size_control{};
843 bool has_ext_transform_feedback{}; 845 bool has_ext_transform_feedback{};
844 bool has_ext_custom_border_color{}; 846 bool has_ext_custom_border_color{};
@@ -888,6 +890,9 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
888 test(has_ext_shader_atomic_int64, VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME, false); 890 test(has_ext_shader_atomic_int64, VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME, false);
889 test(has_khr_workgroup_memory_explicit_layout, 891 test(has_khr_workgroup_memory_explicit_layout,
890 VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME, false); 892 VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME, false);
893 test(has_khr_image_format_list, VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, false);
894 test(has_khr_swapchain_mutable_format, VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME,
895 false);
891 test(has_ext_line_rasterization, VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, false); 896 test(has_ext_line_rasterization, VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, false);
892 if (Settings::values.enable_nsight_aftermath) { 897 if (Settings::values.enable_nsight_aftermath) {
893 test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, 898 test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,
@@ -1066,6 +1071,11 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
1066 khr_pipeline_executable_properties = true; 1071 khr_pipeline_executable_properties = true;
1067 } 1072 }
1068 } 1073 }
1074 if (has_khr_image_format_list && has_khr_swapchain_mutable_format) {
1075 extensions.push_back(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
1076 extensions.push_back(VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME);
1077 khr_swapchain_mutable_format = true;
1078 }
1069 if (khr_push_descriptor) { 1079 if (khr_push_descriptor) {
1070 VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor; 1080 VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor;
1071 push_descriptor.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR; 1081 push_descriptor.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR;
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index 234d74129..5599c38c5 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -224,6 +224,11 @@ public:
224 return khr_pipeline_executable_properties; 224 return khr_pipeline_executable_properties;
225 } 225 }
226 226
227 /// Returns true if VK_KHR_swapchain_mutable_format is enabled.
228 bool IsKhrSwapchainMutableFormatEnabled() const {
229 return khr_swapchain_mutable_format;
230 }
231
227 /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout. 232 /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout.
228 bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const { 233 bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const {
229 return khr_workgroup_memory_explicit_layout; 234 return khr_workgroup_memory_explicit_layout;
@@ -390,6 +395,7 @@ private:
390 bool khr_workgroup_memory_explicit_layout{}; ///< Support for explicit workgroup layouts. 395 bool khr_workgroup_memory_explicit_layout{}; ///< Support for explicit workgroup layouts.
391 bool khr_push_descriptor{}; ///< Support for VK_KHR_push_descritor. 396 bool khr_push_descriptor{}; ///< Support for VK_KHR_push_descritor.
392 bool khr_pipeline_executable_properties{}; ///< Support for executable properties. 397 bool khr_pipeline_executable_properties{}; ///< Support for executable properties.
398 bool khr_swapchain_mutable_format{}; ///< Support for VK_KHR_swapchain_mutable_format.
393 bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8. 399 bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8.
394 bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax. 400 bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax.
395 bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. 401 bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted.
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 85d292bcc..8744d8e5d 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -812,7 +812,7 @@ void Config::ReadRendererValues() {
812 ReadGlobalSetting(Settings::values.use_disk_shader_cache); 812 ReadGlobalSetting(Settings::values.use_disk_shader_cache);
813 ReadGlobalSetting(Settings::values.gpu_accuracy); 813 ReadGlobalSetting(Settings::values.gpu_accuracy);
814 ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation); 814 ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation);
815 ReadGlobalSetting(Settings::values.use_nvdec_emulation); 815 ReadGlobalSetting(Settings::values.nvdec_emulation);
816 ReadGlobalSetting(Settings::values.accelerate_astc); 816 ReadGlobalSetting(Settings::values.accelerate_astc);
817 ReadGlobalSetting(Settings::values.use_vsync); 817 ReadGlobalSetting(Settings::values.use_vsync);
818 ReadGlobalSetting(Settings::values.shader_backend); 818 ReadGlobalSetting(Settings::values.shader_backend);
@@ -1349,7 +1349,10 @@ void Config::SaveRendererValues() {
1349 static_cast<u32>(Settings::values.gpu_accuracy.GetDefault()), 1349 static_cast<u32>(Settings::values.gpu_accuracy.GetDefault()),
1350 Settings::values.gpu_accuracy.UsingGlobal()); 1350 Settings::values.gpu_accuracy.UsingGlobal());
1351 WriteGlobalSetting(Settings::values.use_asynchronous_gpu_emulation); 1351 WriteGlobalSetting(Settings::values.use_asynchronous_gpu_emulation);
1352 WriteGlobalSetting(Settings::values.use_nvdec_emulation); 1352 WriteSetting(QString::fromStdString(Settings::values.nvdec_emulation.GetLabel()),
1353 static_cast<u32>(Settings::values.nvdec_emulation.GetValue(global)),
1354 static_cast<u32>(Settings::values.nvdec_emulation.GetDefault()),
1355 Settings::values.nvdec_emulation.UsingGlobal());
1353 WriteGlobalSetting(Settings::values.accelerate_astc); 1356 WriteGlobalSetting(Settings::values.accelerate_astc);
1354 WriteGlobalSetting(Settings::values.use_vsync); 1357 WriteGlobalSetting(Settings::values.use_vsync);
1355 WriteSetting(QString::fromStdString(Settings::values.shader_backend.GetLabel()), 1358 WriteSetting(QString::fromStdString(Settings::values.shader_backend.GetLabel()),
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 9555f4498..4733227b6 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -182,5 +182,6 @@ private:
182Q_DECLARE_METATYPE(Settings::CPUAccuracy); 182Q_DECLARE_METATYPE(Settings::CPUAccuracy);
183Q_DECLARE_METATYPE(Settings::GPUAccuracy); 183Q_DECLARE_METATYPE(Settings::GPUAccuracy);
184Q_DECLARE_METATYPE(Settings::FullscreenMode); 184Q_DECLARE_METATYPE(Settings::FullscreenMode);
185Q_DECLARE_METATYPE(Settings::NvdecEmulation);
185Q_DECLARE_METATYPE(Settings::RendererBackend); 186Q_DECLARE_METATYPE(Settings::RendererBackend);
186Q_DECLARE_METATYPE(Settings::ShaderBackend); 187Q_DECLARE_METATYPE(Settings::ShaderBackend);
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index 37e896258..c594164be 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -88,24 +88,30 @@ void ConfigureGraphics::SetConfiguration() {
88 ui->api_widget->setEnabled(runtime_lock); 88 ui->api_widget->setEnabled(runtime_lock);
89 ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock); 89 ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock);
90 ui->use_disk_shader_cache->setEnabled(runtime_lock); 90 ui->use_disk_shader_cache->setEnabled(runtime_lock);
91 ui->use_nvdec_emulation->setEnabled(runtime_lock); 91 ui->nvdec_emulation_widget->setEnabled(runtime_lock);
92 ui->accelerate_astc->setEnabled(runtime_lock); 92 ui->accelerate_astc->setEnabled(runtime_lock);
93 ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue()); 93 ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
94 ui->use_asynchronous_gpu_emulation->setChecked( 94 ui->use_asynchronous_gpu_emulation->setChecked(
95 Settings::values.use_asynchronous_gpu_emulation.GetValue()); 95 Settings::values.use_asynchronous_gpu_emulation.GetValue());
96 ui->use_nvdec_emulation->setChecked(Settings::values.use_nvdec_emulation.GetValue());
97 ui->accelerate_astc->setChecked(Settings::values.accelerate_astc.GetValue()); 96 ui->accelerate_astc->setChecked(Settings::values.accelerate_astc.GetValue());
98 97
99 if (Settings::IsConfiguringGlobal()) { 98 if (Settings::IsConfiguringGlobal()) {
100 ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue())); 99 ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue()));
101 ui->fullscreen_mode_combobox->setCurrentIndex( 100 ui->fullscreen_mode_combobox->setCurrentIndex(
102 static_cast<int>(Settings::values.fullscreen_mode.GetValue())); 101 static_cast<int>(Settings::values.fullscreen_mode.GetValue()));
102 ui->nvdec_emulation->setCurrentIndex(
103 static_cast<int>(Settings::values.nvdec_emulation.GetValue()));
103 ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue()); 104 ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue());
104 } else { 105 } else {
105 ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend); 106 ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
106 ConfigurationShared::SetHighlight(ui->api_widget, 107 ConfigurationShared::SetHighlight(ui->api_widget,
107 !Settings::values.renderer_backend.UsingGlobal()); 108 !Settings::values.renderer_backend.UsingGlobal());
108 109
110 ConfigurationShared::SetPerGameSetting(ui->nvdec_emulation,
111 &Settings::values.nvdec_emulation);
112 ConfigurationShared::SetHighlight(ui->nvdec_emulation_widget,
113 !Settings::values.nvdec_emulation.UsingGlobal());
114
109 ConfigurationShared::SetPerGameSetting(ui->fullscreen_mode_combobox, 115 ConfigurationShared::SetPerGameSetting(ui->fullscreen_mode_combobox,
110 &Settings::values.fullscreen_mode); 116 &Settings::values.fullscreen_mode);
111 ConfigurationShared::SetHighlight(ui->fullscreen_mode_label, 117 ConfigurationShared::SetHighlight(ui->fullscreen_mode_label,
@@ -137,8 +143,6 @@ void ConfigureGraphics::ApplyConfiguration() {
137 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation, 143 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation,
138 ui->use_asynchronous_gpu_emulation, 144 ui->use_asynchronous_gpu_emulation,
139 use_asynchronous_gpu_emulation); 145 use_asynchronous_gpu_emulation);
140 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_nvdec_emulation,
141 ui->use_nvdec_emulation, use_nvdec_emulation);
142 ConfigurationShared::ApplyPerGameSetting(&Settings::values.accelerate_astc, ui->accelerate_astc, 146 ConfigurationShared::ApplyPerGameSetting(&Settings::values.accelerate_astc, ui->accelerate_astc,
143 accelerate_astc); 147 accelerate_astc);
144 148
@@ -147,6 +151,9 @@ void ConfigureGraphics::ApplyConfiguration() {
147 if (Settings::values.renderer_backend.UsingGlobal()) { 151 if (Settings::values.renderer_backend.UsingGlobal()) {
148 Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend()); 152 Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());
149 } 153 }
154 if (Settings::values.nvdec_emulation.UsingGlobal()) {
155 Settings::values.nvdec_emulation.SetValue(GetCurrentNvdecEmulation());
156 }
150 if (Settings::values.shader_backend.UsingGlobal()) { 157 if (Settings::values.shader_backend.UsingGlobal()) {
151 Settings::values.shader_backend.SetValue(shader_backend); 158 Settings::values.shader_backend.SetValue(shader_backend);
152 } 159 }
@@ -180,6 +187,13 @@ void ConfigureGraphics::ApplyConfiguration() {
180 } 187 }
181 } 188 }
182 189
190 if (ui->nvdec_emulation->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
191 Settings::values.nvdec_emulation.SetGlobal(true);
192 } else {
193 Settings::values.nvdec_emulation.SetGlobal(false);
194 Settings::values.nvdec_emulation.SetValue(GetCurrentNvdecEmulation());
195 }
196
183 if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { 197 if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
184 Settings::values.bg_red.SetGlobal(true); 198 Settings::values.bg_red.SetGlobal(true);
185 Settings::values.bg_green.SetGlobal(true); 199 Settings::values.bg_green.SetGlobal(true);
@@ -278,6 +292,20 @@ Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const {
278 ConfigurationShared::USE_GLOBAL_OFFSET); 292 ConfigurationShared::USE_GLOBAL_OFFSET);
279} 293}
280 294
295Settings::NvdecEmulation ConfigureGraphics::GetCurrentNvdecEmulation() const {
296 if (Settings::IsConfiguringGlobal()) {
297 return static_cast<Settings::NvdecEmulation>(ui->nvdec_emulation->currentIndex());
298 }
299
300 if (ui->nvdec_emulation->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
301 Settings::values.nvdec_emulation.SetGlobal(true);
302 return Settings::values.nvdec_emulation.GetValue();
303 }
304 Settings::values.nvdec_emulation.SetGlobal(false);
305 return static_cast<Settings::NvdecEmulation>(ui->nvdec_emulation->currentIndex() -
306 ConfigurationShared::USE_GLOBAL_OFFSET);
307}
308
281void ConfigureGraphics::SetupPerGameUI() { 309void ConfigureGraphics::SetupPerGameUI() {
282 if (Settings::IsConfiguringGlobal()) { 310 if (Settings::IsConfiguringGlobal()) {
283 ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal()); 311 ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal());
@@ -286,7 +314,7 @@ void ConfigureGraphics::SetupPerGameUI() {
286 ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal()); 314 ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal());
287 ui->use_asynchronous_gpu_emulation->setEnabled( 315 ui->use_asynchronous_gpu_emulation->setEnabled(
288 Settings::values.use_asynchronous_gpu_emulation.UsingGlobal()); 316 Settings::values.use_asynchronous_gpu_emulation.UsingGlobal());
289 ui->use_nvdec_emulation->setEnabled(Settings::values.use_nvdec_emulation.UsingGlobal()); 317 ui->nvdec_emulation->setEnabled(Settings::values.nvdec_emulation.UsingGlobal());
290 ui->accelerate_astc->setEnabled(Settings::values.accelerate_astc.UsingGlobal()); 318 ui->accelerate_astc->setEnabled(Settings::values.accelerate_astc.UsingGlobal());
291 ui->use_disk_shader_cache->setEnabled(Settings::values.use_disk_shader_cache.UsingGlobal()); 319 ui->use_disk_shader_cache->setEnabled(Settings::values.use_disk_shader_cache.UsingGlobal());
292 ui->bg_button->setEnabled(Settings::values.bg_red.UsingGlobal()); 320 ui->bg_button->setEnabled(Settings::values.bg_red.UsingGlobal());
@@ -301,8 +329,6 @@ void ConfigureGraphics::SetupPerGameUI() {
301 329
302 ConfigurationShared::SetColoredTristate( 330 ConfigurationShared::SetColoredTristate(
303 ui->use_disk_shader_cache, Settings::values.use_disk_shader_cache, use_disk_shader_cache); 331 ui->use_disk_shader_cache, Settings::values.use_disk_shader_cache, use_disk_shader_cache);
304 ConfigurationShared::SetColoredTristate(
305 ui->use_nvdec_emulation, Settings::values.use_nvdec_emulation, use_nvdec_emulation);
306 ConfigurationShared::SetColoredTristate(ui->accelerate_astc, Settings::values.accelerate_astc, 332 ConfigurationShared::SetColoredTristate(ui->accelerate_astc, Settings::values.accelerate_astc,
307 accelerate_astc); 333 accelerate_astc);
308 ConfigurationShared::SetColoredTristate(ui->use_asynchronous_gpu_emulation, 334 ConfigurationShared::SetColoredTristate(ui->use_asynchronous_gpu_emulation,
@@ -316,4 +342,6 @@ void ConfigureGraphics::SetupPerGameUI() {
316 static_cast<int>(Settings::values.fullscreen_mode.GetValue(true))); 342 static_cast<int>(Settings::values.fullscreen_mode.GetValue(true)));
317 ConfigurationShared::InsertGlobalItem( 343 ConfigurationShared::InsertGlobalItem(
318 ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); 344 ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
345 ConfigurationShared::InsertGlobalItem(
346 ui->nvdec_emulation, static_cast<int>(Settings::values.nvdec_emulation.GetValue(true)));
319} 347}
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index c866b911b..7d7ac329d 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -43,6 +43,7 @@ private:
43 void SetupPerGameUI(); 43 void SetupPerGameUI();
44 44
45 Settings::RendererBackend GetCurrentGraphicsBackend() const; 45 Settings::RendererBackend GetCurrentGraphicsBackend() const;
46 Settings::NvdecEmulation GetCurrentNvdecEmulation() const;
46 47
47 std::unique_ptr<Ui::ConfigureGraphics> ui; 48 std::unique_ptr<Ui::ConfigureGraphics> ui;
48 QColor bg_color; 49 QColor bg_color;
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 43f1887d1..1a12cfa4d 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -168,13 +168,6 @@
168 </widget> 168 </widget>
169 </item> 169 </item>
170 <item> 170 <item>
171 <widget class="QCheckBox" name="use_nvdec_emulation">
172 <property name="text">
173 <string>Use NVDEC emulation</string>
174 </property>
175 </widget>
176 </item>
177 <item>
178 <widget class="QCheckBox" name="accelerate_astc"> 171 <widget class="QCheckBox" name="accelerate_astc">
179 <property name="text"> 172 <property name="text">
180 <string>Accelerate ASTC texture decoding</string> 173 <string>Accelerate ASTC texture decoding</string>
@@ -182,6 +175,50 @@
182 </widget> 175 </widget>
183 </item> 176 </item>
184 <item> 177 <item>
178 <widget class="QWidget" name="nvdec_emulation_widget" native="true">
179 <layout class="QHBoxLayout" name="nvdec_emulation_layout">
180 <property name="leftMargin">
181 <number>0</number>
182 </property>
183 <property name="topMargin">
184 <number>0</number>
185 </property>
186 <property name="rightMargin">
187 <number>0</number>
188 </property>
189 <property name="bottomMargin">
190 <number>0</number>
191 </property>
192 <item>
193 <widget class="QLabel" name="nvdec_emulation_label">
194 <property name="text">
195 <string>NVDEC emulation:</string>
196 </property>
197 </widget>
198 </item>
199 <item>
200 <widget class="QComboBox" name="nvdec_emulation">
201 <item>
202 <property name="text">
203 <string>Disabled</string>
204 </property>
205 </item>
206 <item>
207 <property name="text">
208 <string>CPU Decoding</string>
209 </property>
210 </item>
211 <item>
212 <property name="text">
213 <string>GPU Decoding</string>
214 </property>
215 </item>
216 </widget>
217 </item>
218 </layout>
219 </widget>
220 </item>
221 <item>
185 <widget class="QWidget" name="fullscreen_mode_layout" native="true"> 222 <widget class="QWidget" name="fullscreen_mode_layout" native="true">
186 <layout class="QHBoxLayout" name="horizontalLayout_1"> 223 <layout class="QHBoxLayout" name="horizontalLayout_1">
187 <property name="leftMargin"> 224 <property name="leftMargin">
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 757dd1ea0..891f7be6f 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -465,7 +465,7 @@ void Config::ReadValues() {
465 ReadSetting("Renderer", Settings::values.disable_fps_limit); 465 ReadSetting("Renderer", Settings::values.disable_fps_limit);
466 ReadSetting("Renderer", Settings::values.shader_backend); 466 ReadSetting("Renderer", Settings::values.shader_backend);
467 ReadSetting("Renderer", Settings::values.use_asynchronous_shaders); 467 ReadSetting("Renderer", Settings::values.use_asynchronous_shaders);
468 ReadSetting("Renderer", Settings::values.use_nvdec_emulation); 468 ReadSetting("Renderer", Settings::values.nvdec_emulation);
469 ReadSetting("Renderer", Settings::values.accelerate_astc); 469 ReadSetting("Renderer", Settings::values.accelerate_astc);
470 ReadSetting("Renderer", Settings::values.use_fast_gpu_time); 470 ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
471 471
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index e02eceb99..72f3213fb 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -261,9 +261,9 @@ shader_backend =
261# 0 (default): Off, 1: On 261# 0 (default): Off, 1: On
262use_asynchronous_shaders = 262use_asynchronous_shaders =
263 263
264# Enable NVDEC emulation. 264# NVDEC emulation.
265# 0: Off, 1 (default): On 265# 0: Disabled, 1: CPU Decoding, 2 (default): GPU Decoding
266use_nvdec_emulation = 266nvdec_emulation =
267 267
268# Accelerate ASTC texture decoding. 268# Accelerate ASTC texture decoding.
269# 0: Off, 1 (default): On 269# 0: Off, 1 (default): On