summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/scratch_buffer.h9
-rw-r--r--src/common/settings.cpp1
-rw-r--r--src/common/settings.h3
-rw-r--r--src/core/file_sys/savedata_factory.cpp4
-rw-r--r--src/core/hle/service/am/am.cpp33
-rw-r--r--src/core/hle/service/am/am.h1
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp17
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h1
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp4
-rw-r--r--src/core/hle/service/hid/controllers/npad.h4
-rw-r--r--src/core/hle/service/hid/hid.cpp20
-rw-r--r--src/core/hle/service/nfc/common/device.cpp35
-rw-r--r--src/core/hle/service/nfc/common/device.h2
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_producer.cpp5
-rw-r--r--src/core/hle/service/nvnflinger/parcel.h72
-rw-r--r--src/core/hle/service/time/clock_types.h12
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp19
-rw-r--r--src/core/hle/service/time/time_sharedmemory.h5
-rw-r--r--src/core/hle/service/vi/vi.cpp12
-rw-r--r--src/input_common/drivers/sdl_driver.cpp35
-rw-r--r--src/input_common/helpers/joycon_protocol/joycon_types.h1
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.cpp10
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.h6
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp8
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp7
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h37
-rw-r--r--src/video_core/buffer_cache/buffer_cache_base.h3
-rw-r--r--src/video_core/engines/sw_blitter/blitter.cpp25
-rw-r--r--src/video_core/host1x/codecs/h264.cpp4
-rw-r--r--src/video_core/renderer_vulkan/pipeline_helper.h6
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp10
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h9
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp39
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.h14
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp12
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp10
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp11
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp18
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h3
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h6
-rw-r--r--src/video_core/renderer_vulkan/vk_update_descriptor.h6
-rw-r--r--src/video_core/texture_cache/texture_cache.h2
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp2
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.cpp2
-rw-r--r--src/yuzu/configuration/config.cpp4
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp3
-rw-r--r--src/yuzu/configuration/configure_dialog.h2
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp23
-rw-r--r--src/yuzu/configuration/configure_graphics.h6
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp17
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.h3
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui11
-rw-r--r--src/yuzu/configuration/configure_hotkeys.cpp65
-rw-r--r--src/yuzu/configuration/configure_hotkeys.h2
-rw-r--r--src/yuzu/configuration/configure_input_advanced.cpp2
-rw-r--r--src/yuzu/configuration/configure_input_advanced.ui22
-rw-r--r--src/yuzu/configuration/configure_per_game.cpp3
-rw-r--r--src/yuzu/configuration/configure_per_game.h2
-rw-r--r--src/yuzu/main.cpp18
-rw-r--r--src/yuzu/main.h3
-rw-r--r--src/yuzu_cmd/config.cpp1
65 files changed, 490 insertions, 261 deletions
diff --git a/src/common/scratch_buffer.h b/src/common/scratch_buffer.h
index 26d4e76dc..a69a5a7af 100644
--- a/src/common/scratch_buffer.h
+++ b/src/common/scratch_buffer.h
@@ -23,7 +23,10 @@ public:
23 buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {} 23 buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {}
24 24
25 ~ScratchBuffer() = default; 25 ~ScratchBuffer() = default;
26 ScratchBuffer(const ScratchBuffer&) = delete;
27 ScratchBuffer& operator=(const ScratchBuffer&) = delete;
26 ScratchBuffer(ScratchBuffer&&) = default; 28 ScratchBuffer(ScratchBuffer&&) = default;
29 ScratchBuffer& operator=(ScratchBuffer&&) = default;
27 30
28 /// This will only grow the buffer's capacity if size is greater than the current capacity. 31 /// This will only grow the buffer's capacity if size is greater than the current capacity.
29 /// The previously held data will remain intact. 32 /// The previously held data will remain intact.
@@ -87,6 +90,12 @@ public:
87 return buffer_capacity; 90 return buffer_capacity;
88 } 91 }
89 92
93 void swap(ScratchBuffer& other) noexcept {
94 std::swap(last_requested_size, other.last_requested_size);
95 std::swap(buffer_capacity, other.buffer_capacity);
96 std::swap(buffer, other.buffer);
97 }
98
90private: 99private:
91 size_t last_requested_size{}; 100 size_t last_requested_size{};
92 size_t buffer_capacity{}; 101 size_t buffer_capacity{};
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index db1774c71..ba617aea1 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -232,6 +232,7 @@ void RestoreGlobalState(bool is_powered_on) {
232 values.bg_red.SetGlobal(true); 232 values.bg_red.SetGlobal(true);
233 values.bg_green.SetGlobal(true); 233 values.bg_green.SetGlobal(true);
234 values.bg_blue.SetGlobal(true); 234 values.bg_blue.SetGlobal(true);
235 values.enable_compute_pipelines.SetGlobal(true);
235 236
236 // System 237 // System
237 values.language_index.SetGlobal(true); 238 values.language_index.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index f4eb4e3cd..36ffcd693 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -472,6 +472,7 @@ struct Values {
472 SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"}; 472 SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
473 SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{true, 473 SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{true,
474 "use_vulkan_driver_pipeline_cache"}; 474 "use_vulkan_driver_pipeline_cache"};
475 SwitchableSetting<bool> enable_compute_pipelines{false, "enable_compute_pipelines"};
475 476
476 SwitchableSetting<u8> bg_red{0, "bg_red"}; 477 SwitchableSetting<u8> bg_red{0, "bg_red"};
477 SwitchableSetting<u8> bg_green{0, "bg_green"}; 478 SwitchableSetting<u8> bg_green{0, "bg_green"};
@@ -535,6 +536,8 @@ struct Values {
535 Setting<bool> enable_ir_sensor{false, "enable_ir_sensor"}; 536 Setting<bool> enable_ir_sensor{false, "enable_ir_sensor"};
536 Setting<std::string> ir_sensor_device{"auto", "ir_sensor_device"}; 537 Setting<std::string> ir_sensor_device{"auto", "ir_sensor_device"};
537 538
539 Setting<bool> random_amiibo_id{false, "random_amiibo_id"};
540
538 // Data Storage 541 // Data Storage
539 Setting<bool> use_virtual_sd{true, "use_virtual_sd"}; 542 Setting<bool> use_virtual_sd{true, "use_virtual_sd"};
540 Setting<bool> gamecard_inserted{false, "gamecard_inserted"}; 543 Setting<bool> gamecard_inserted{false, "gamecard_inserted"};
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index 769065b6f..70b36f170 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -82,9 +82,9 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
82 // Only detect account/device saves from the future location. 82 // Only detect account/device saves from the future location.
83 switch (type) { 83 switch (type) {
84 case SaveDataType::SaveData: 84 case SaveDataType::SaveData:
85 return fmt::format("{}/account/{}/{:016X}/1", space_id_path, uuid.RawString(), title_id); 85 return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id);
86 case SaveDataType::DeviceSaveData: 86 case SaveDataType::DeviceSaveData:
87 return fmt::format("{}/device/{:016X}/1", space_id_path, title_id); 87 return fmt::format("{}/device/{:016X}/0", space_id_path, title_id);
88 default: 88 default:
89 return ""; 89 return "";
90 } 90 }
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index e59de844c..a2375508a 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -13,6 +13,7 @@
13#include "core/file_sys/savedata_factory.h" 13#include "core/file_sys/savedata_factory.h"
14#include "core/hle/kernel/k_event.h" 14#include "core/hle/kernel/k_event.h"
15#include "core/hle/kernel/k_transfer_memory.h" 15#include "core/hle/kernel/k_transfer_memory.h"
16#include "core/hle/result.h"
16#include "core/hle/service/acc/profile_manager.h" 17#include "core/hle/service/acc/profile_manager.h"
17#include "core/hle/service/am/am.h" 18#include "core/hle/service/am/am.h"
18#include "core/hle/service/am/applet_ae.h" 19#include "core/hle/service/am/applet_ae.h"
@@ -1335,7 +1336,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1335 {24, nullptr, "GetLaunchStorageInfoForDebug"}, 1336 {24, nullptr, "GetLaunchStorageInfoForDebug"},
1336 {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"}, 1337 {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
1337 {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"}, 1338 {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
1338 {27, nullptr, "CreateCacheStorage"}, 1339 {27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"},
1339 {28, nullptr, "GetSaveDataSizeMax"}, 1340 {28, nullptr, "GetSaveDataSizeMax"},
1340 {29, nullptr, "GetCacheStorageMax"}, 1341 {29, nullptr, "GetCacheStorageMax"},
1341 {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"}, 1342 {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
@@ -1738,6 +1739,36 @@ void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) {
1738 rb.Push(size.journal); 1739 rb.Push(size.journal);
1739} 1740}
1740 1741
1742void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) {
1743 struct InputParameters {
1744 u16 index;
1745 s64 size;
1746 s64 journal_size;
1747 };
1748 static_assert(sizeof(InputParameters) == 24);
1749
1750 struct OutputParameters {
1751 u32 storage_target;
1752 u64 required_size;
1753 };
1754 static_assert(sizeof(OutputParameters) == 16);
1755
1756 IPC::RequestParser rp{ctx};
1757 const auto params = rp.PopRaw<InputParameters>();
1758
1759 LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}",
1760 params.index, params.size, params.journal_size);
1761
1762 const OutputParameters resp{
1763 .storage_target = 1,
1764 .required_size = 0,
1765 };
1766
1767 IPC::ResponseBuilder rb{ctx, 6};
1768 rb.Push(ResultSuccess);
1769 rb.PushRaw(resp);
1770}
1771
1741void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) { 1772void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) {
1742 LOG_WARNING(Service_AM, "(STUBBED) called"); 1773 LOG_WARNING(Service_AM, "(STUBBED) called");
1743 1774
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 0dbc6485e..d4fd163da 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -333,6 +333,7 @@ private:
333 void GetPseudoDeviceId(HLERequestContext& ctx); 333 void GetPseudoDeviceId(HLERequestContext& ctx);
334 void ExtendSaveData(HLERequestContext& ctx); 334 void ExtendSaveData(HLERequestContext& ctx);
335 void GetSaveDataSize(HLERequestContext& ctx); 335 void GetSaveDataSize(HLERequestContext& ctx);
336 void CreateCacheStorage(HLERequestContext& ctx);
336 void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx); 337 void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
337 void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx); 338 void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
338 void BeginBlockingHomeButton(HLERequestContext& ctx); 339 void BeginBlockingHomeButton(HLERequestContext& ctx);
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 9e559d97e..f73a864c3 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -24,8 +24,10 @@
24#include "core/file_sys/savedata_factory.h" 24#include "core/file_sys/savedata_factory.h"
25#include "core/file_sys/system_archive/system_archive.h" 25#include "core/file_sys/system_archive/system_archive.h"
26#include "core/file_sys/vfs.h" 26#include "core/file_sys/vfs.h"
27#include "core/hle/result.h"
27#include "core/hle/service/filesystem/filesystem.h" 28#include "core/hle/service/filesystem/filesystem.h"
28#include "core/hle/service/filesystem/fsp_srv.h" 29#include "core/hle/service/filesystem/fsp_srv.h"
30#include "core/hle/service/hle_ipc.h"
29#include "core/hle/service/ipc_helpers.h" 31#include "core/hle/service/ipc_helpers.h"
30#include "core/reporter.h" 32#include "core/reporter.h"
31 33
@@ -552,9 +554,9 @@ public:
552 // Write the data to memory 554 // Write the data to memory
553 ctx.WriteBuffer(begin, range_size); 555 ctx.WriteBuffer(begin, range_size);
554 556
555 IPC::ResponseBuilder rb{ctx, 3}; 557 IPC::ResponseBuilder rb{ctx, 4};
556 rb.Push(ResultSuccess); 558 rb.Push(ResultSuccess);
557 rb.Push<u32>(static_cast<u32>(actual_entries)); 559 rb.Push<u64>(actual_entries);
558 } 560 }
559 561
560private: 562private:
@@ -712,7 +714,7 @@ FSP_SRV::FSP_SRV(Core::System& system_)
712 {59, nullptr, "WriteSaveDataFileSystemExtraData"}, 714 {59, nullptr, "WriteSaveDataFileSystemExtraData"},
713 {60, nullptr, "OpenSaveDataInfoReader"}, 715 {60, nullptr, "OpenSaveDataInfoReader"},
714 {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, 716 {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
715 {62, nullptr, "OpenCacheStorageList"}, 717 {62, &FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage, "OpenSaveDataInfoReaderOnlyCacheStorage"},
716 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, 718 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
717 {65, nullptr, "UpdateSaveDataMacForDebug"}, 719 {65, nullptr, "UpdateSaveDataMacForDebug"},
718 {66, nullptr, "WriteSaveDataFileSystemExtraData2"}, 720 {66, nullptr, "WriteSaveDataFileSystemExtraData2"},
@@ -921,6 +923,15 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) {
921 std::make_shared<ISaveDataInfoReader>(system, space, fsc)); 923 std::make_shared<ISaveDataInfoReader>(system, space, fsc));
922} 924}
923 925
926void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) {
927 LOG_WARNING(Service_FS, "(STUBBED) called");
928
929 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
930 rb.Push(ResultSuccess);
931 rb.PushIpcInterface<ISaveDataInfoReader>(system, FileSys::SaveDataSpaceId::TemporaryStorage,
932 fsc);
933}
934
924void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) { 935void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) {
925 LOG_WARNING(Service_FS, "(STUBBED) called."); 936 LOG_WARNING(Service_FS, "(STUBBED) called.");
926 937
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index 49f17c7c3..4f3c2f6de 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -42,6 +42,7 @@ private:
42 void OpenSaveDataFileSystem(HLERequestContext& ctx); 42 void OpenSaveDataFileSystem(HLERequestContext& ctx);
43 void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx); 43 void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx);
44 void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx); 44 void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx);
45 void OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx);
45 void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx); 46 void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx);
46 void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx); 47 void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx);
47 void OpenDataStorageByCurrentProcess(HLERequestContext& ctx); 48 void OpenDataStorageByCurrentProcess(HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index ef4aec4ea..28818c813 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -979,8 +979,8 @@ void Controller_NPad::VibrateController(
979} 979}
980 980
981void Controller_NPad::VibrateControllers( 981void Controller_NPad::VibrateControllers(
982 const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles, 982 std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
983 const std::vector<Core::HID::VibrationValue>& vibration_values) { 983 std::span<const Core::HID::VibrationValue> vibration_values) {
984 if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { 984 if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
985 return; 985 return;
986 } 986 }
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 9cfe298f1..776411261 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -112,8 +112,8 @@ public:
112 const Core::HID::VibrationValue& vibration_value); 112 const Core::HID::VibrationValue& vibration_value);
113 113
114 void VibrateControllers( 114 void VibrateControllers(
115 const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles, 115 std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
116 const std::vector<Core::HID::VibrationValue>& vibration_values); 116 std::span<const Core::HID::VibrationValue> vibration_values);
117 117
118 Core::HID::VibrationValue GetLastVibration( 118 Core::HID::VibrationValue GetLastVibration(
119 const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; 119 const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 87e7b864a..2bf1d8a27 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1601,16 +1601,16 @@ void Hid::SendVibrationValues(HLERequestContext& ctx) {
1601 IPC::RequestParser rp{ctx}; 1601 IPC::RequestParser rp{ctx};
1602 const auto applet_resource_user_id{rp.Pop<u64>()}; 1602 const auto applet_resource_user_id{rp.Pop<u64>()};
1603 1603
1604 const auto handles = ctx.ReadBuffer(0); 1604 const auto handle_data = ctx.ReadBuffer(0);
1605 const auto vibrations = ctx.ReadBuffer(1); 1605 const auto handle_count = ctx.GetReadBufferNumElements<Core::HID::VibrationDeviceHandle>(0);
1606 1606 const auto vibration_data = ctx.ReadBuffer(1);
1607 std::vector<Core::HID::VibrationDeviceHandle> vibration_device_handles( 1607 const auto vibration_count = ctx.GetReadBufferNumElements<Core::HID::VibrationValue>(1);
1608 handles.size() / sizeof(Core::HID::VibrationDeviceHandle)); 1608
1609 std::vector<Core::HID::VibrationValue> vibration_values(vibrations.size() / 1609 auto vibration_device_handles =
1610 sizeof(Core::HID::VibrationValue)); 1610 std::span(reinterpret_cast<const Core::HID::VibrationDeviceHandle*>(handle_data.data()),
1611 1611 handle_count);
1612 std::memcpy(vibration_device_handles.data(), handles.data(), handles.size()); 1612 auto vibration_values = std::span(
1613 std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size()); 1613 reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count);
1614 1614
1615 applet_resource->GetController<Controller_NPad>(HidController::NPad) 1615 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1616 .VibrateControllers(vibration_device_handles, vibration_values); 1616 .VibrateControllers(vibration_device_handles, vibration_values);
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index e5de65ce0..322bde2ed 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -48,9 +48,6 @@ NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
48 }; 48 };
49 is_controller_set = true; 49 is_controller_set = true;
50 callback_key = npad_device->SetCallback(engine_callback); 50 callback_key = npad_device->SetCallback(engine_callback);
51
52 auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
53 current_posix_time = standard_steady_clock.GetCurrentTimePoint(system).time_point;
54} 51}
55 52
56NfcDevice::~NfcDevice() { 53NfcDevice::~NfcDevice() {
@@ -227,11 +224,21 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
227 return ResultWrongDeviceState; 224 return ResultWrongDeviceState;
228 } 225 }
229 226
227 UniqueSerialNumber uuid = encrypted_tag_data.uuid.uid;
228
229 // Generate random UUID to bypass amiibo load limits
230 if (Settings::values.random_amiibo_id) {
231 Common::TinyMT rng{};
232 rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
233 rng.GenerateRandomBytes(uuid.data(), sizeof(UniqueSerialNumber));
234 uuid[3] = 0x88 ^ uuid[0] ^ uuid[1] ^ uuid[2];
235 }
236
230 if (is_mifare) { 237 if (is_mifare) {
231 tag_info = { 238 tag_info = {
232 .uuid = encrypted_tag_data.uuid.uid, 239 .uuid = uuid,
233 .uuid_extension = {}, 240 .uuid_extension = {},
234 .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()), 241 .uuid_length = static_cast<u8>(uuid.size()),
235 .protocol = NfcProtocol::TypeA, 242 .protocol = NfcProtocol::TypeA,
236 .tag_type = TagType::Type4, 243 .tag_type = TagType::Type4,
237 }; 244 };
@@ -240,9 +247,9 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
240 247
241 // Protocol and tag type may change here 248 // Protocol and tag type may change here
242 tag_info = { 249 tag_info = {
243 .uuid = encrypted_tag_data.uuid.uid, 250 .uuid = uuid,
244 .uuid_extension = {}, 251 .uuid_extension = {},
245 .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()), 252 .uuid_length = static_cast<u8>(uuid.size()),
246 .protocol = NfcProtocol::TypeA, 253 .protocol = NfcProtocol::TypeA,
247 .tag_type = TagType::Type2, 254 .tag_type = TagType::Type2,
248 }; 255 };
@@ -406,7 +413,7 @@ Result NfcDevice::Flush() {
406 413
407 auto& settings = tag_data.settings; 414 auto& settings = tag_data.settings;
408 415
409 const auto& current_date = GetAmiiboDate(current_posix_time); 416 const auto& current_date = GetAmiiboDate(GetCurrentPosixTime());
410 if (settings.write_date.raw_date != current_date.raw_date) { 417 if (settings.write_date.raw_date != current_date.raw_date) {
411 settings.write_date = current_date; 418 settings.write_date = current_date;
412 UpdateSettingsCrc(); 419 UpdateSettingsCrc();
@@ -525,6 +532,7 @@ Result NfcDevice::GetModelInfo(NFP::ModelInfo& model_info) const {
525 } 532 }
526 533
527 const auto& model_info_data = encrypted_tag_data.user_memory.model_info; 534 const auto& model_info_data = encrypted_tag_data.user_memory.model_info;
535
528 model_info = { 536 model_info = {
529 .character_id = model_info_data.character_id, 537 .character_id = model_info_data.character_id,
530 .character_variant = model_info_data.character_variant, 538 .character_variant = model_info_data.character_variant,
@@ -669,6 +677,7 @@ Result NfcDevice::DeleteRegisterInfo() {
669 } 677 }
670 678
671 Common::TinyMT rng{}; 679 Common::TinyMT rng{};
680 rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
672 rng.GenerateRandomBytes(&tag_data.owner_mii, sizeof(tag_data.owner_mii)); 681 rng.GenerateRandomBytes(&tag_data.owner_mii, sizeof(tag_data.owner_mii));
673 rng.GenerateRandomBytes(&tag_data.settings.amiibo_name, sizeof(tag_data.settings.amiibo_name)); 682 rng.GenerateRandomBytes(&tag_data.settings.amiibo_name, sizeof(tag_data.settings.amiibo_name));
674 rng.GenerateRandomBytes(&tag_data.unknown, sizeof(u8)); 683 rng.GenerateRandomBytes(&tag_data.unknown, sizeof(u8));
@@ -701,7 +710,7 @@ Result NfcDevice::SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& registe
701 auto& settings = tag_data.settings; 710 auto& settings = tag_data.settings;
702 711
703 if (tag_data.settings.settings.amiibo_initialized == 0) { 712 if (tag_data.settings.settings.amiibo_initialized == 0) {
704 settings.init_date = GetAmiiboDate(current_posix_time); 713 settings.init_date = GetAmiiboDate(GetCurrentPosixTime());
705 settings.write_date.raw_date = 0; 714 settings.write_date.raw_date = 0;
706 } 715 }
707 716
@@ -868,6 +877,7 @@ Result NfcDevice::SetApplicationArea(std::span<const u8> data) {
868 } 877 }
869 878
870 Common::TinyMT rng{}; 879 Common::TinyMT rng{};
880 rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
871 std::memcpy(tag_data.application_area.data(), data.data(), data.size()); 881 std::memcpy(tag_data.application_area.data(), data.data(), data.size());
872 // Fill remaining data with random numbers 882 // Fill remaining data with random numbers
873 rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(), 883 rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
@@ -924,6 +934,7 @@ Result NfcDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> dat
924 } 934 }
925 935
926 Common::TinyMT rng{}; 936 Common::TinyMT rng{};
937 rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
927 std::memcpy(tag_data.application_area.data(), data.data(), data.size()); 938 std::memcpy(tag_data.application_area.data(), data.data(), data.size());
928 // Fill remaining data with random numbers 939 // Fill remaining data with random numbers
929 rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(), 940 rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
@@ -973,6 +984,7 @@ Result NfcDevice::DeleteApplicationArea() {
973 } 984 }
974 985
975 Common::TinyMT rng{}; 986 Common::TinyMT rng{};
987 rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
976 rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(NFP::ApplicationArea)); 988 rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(NFP::ApplicationArea));
977 rng.GenerateRandomBytes(&tag_data.application_id, sizeof(u64)); 989 rng.GenerateRandomBytes(&tag_data.application_id, sizeof(u64));
978 rng.GenerateRandomBytes(&tag_data.application_area_id, sizeof(u32)); 990 rng.GenerateRandomBytes(&tag_data.application_area_id, sizeof(u32));
@@ -1189,6 +1201,11 @@ NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const {
1189 return amiibo_date; 1201 return amiibo_date;
1190} 1202}
1191 1203
1204u64 NfcDevice::GetCurrentPosixTime() const {
1205 auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
1206 return standard_steady_clock.GetCurrentTimePoint(system).time_point;
1207}
1208
1192u64 NfcDevice::RemoveVersionByte(u64 application_id) const { 1209u64 NfcDevice::RemoveVersionByte(u64 application_id) const {
1193 return application_id & ~(0xfULL << NFP::application_id_version_offset); 1210 return application_id & ~(0xfULL << NFP::application_id_version_offset);
1194} 1211}
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h
index 654eda98e..98e1945c1 100644
--- a/src/core/hle/service/nfc/common/device.h
+++ b/src/core/hle/service/nfc/common/device.h
@@ -105,6 +105,7 @@ private:
105 NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const; 105 NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
106 void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name); 106 void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name);
107 NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const; 107 NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const;
108 u64 GetCurrentPosixTime() const;
108 u64 RemoveVersionByte(u64 application_id) const; 109 u64 RemoveVersionByte(u64 application_id) const;
109 void UpdateSettingsCrc(); 110 void UpdateSettingsCrc();
110 void UpdateRegisterInfoCrc(); 111 void UpdateRegisterInfoCrc();
@@ -127,7 +128,6 @@ private:
127 bool is_data_moddified{}; 128 bool is_data_moddified{};
128 bool is_app_area_open{}; 129 bool is_app_area_open{};
129 bool is_plain_amiibo{}; 130 bool is_plain_amiibo{};
130 s64 current_posix_time{};
131 NFP::MountTarget mount_target{NFP::MountTarget::None}; 131 NFP::MountTarget mount_target{NFP::MountTarget::None};
132 132
133 NFP::NTAG215File tag_data{}; 133 NFP::NTAG215File tag_data{};
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
index cd0a13094..b16f9933f 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
@@ -793,6 +793,7 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
793 std::scoped_lock lock{core->mutex}; 793 std::scoped_lock lock{core->mutex};
794 794
795 slots[slot] = {}; 795 slots[slot] = {};
796 slots[slot].fence = Fence::NoFence();
796 slots[slot].graphic_buffer = buffer; 797 slots[slot].graphic_buffer = buffer;
797 slots[slot].frame_number = 0; 798 slots[slot].frame_number = 0;
798 799
@@ -854,7 +855,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u
854 status = DequeueBuffer(&slot, &fence, is_async, width, height, pixel_format, usage); 855 status = DequeueBuffer(&slot, &fence, is_async, width, height, pixel_format, usage);
855 856
856 parcel_out.Write(slot); 857 parcel_out.Write(slot);
857 parcel_out.WriteObject(&fence); 858 parcel_out.WriteFlattenedObject(&fence);
858 break; 859 break;
859 } 860 }
860 case TransactionId::RequestBuffer: { 861 case TransactionId::RequestBuffer: {
@@ -864,7 +865,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u
864 865
865 status = RequestBuffer(slot, &buf); 866 status = RequestBuffer(slot, &buf);
866 867
867 parcel_out.WriteObject(buf); 868 parcel_out.WriteFlattenedObject(buf);
868 break; 869 break;
869 } 870 }
870 case TransactionId::QueueBuffer: { 871 case TransactionId::QueueBuffer: {
diff --git a/src/core/hle/service/nvnflinger/parcel.h b/src/core/hle/service/nvnflinger/parcel.h
index d1b6201e0..fb56d75d7 100644
--- a/src/core/hle/service/nvnflinger/parcel.h
+++ b/src/core/hle/service/nvnflinger/parcel.h
@@ -117,61 +117,67 @@ private:
117 117
118class OutputParcel final { 118class OutputParcel final {
119public: 119public:
120 static constexpr std::size_t DefaultBufferSize = 0x40; 120 OutputParcel() = default;
121
122 OutputParcel() : buffer(DefaultBufferSize) {}
123
124 template <typename T>
125 explicit OutputParcel(const T& out_data) : buffer(DefaultBufferSize) {
126 Write(out_data);
127 }
128 121
129 template <typename T> 122 template <typename T>
130 void Write(const T& val) { 123 void Write(const T& val) {
131 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); 124 this->WriteImpl(val, m_data_buffer);
132
133 if (buffer.size() < write_index + sizeof(T)) {
134 buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize);
135 }
136
137 std::memcpy(buffer.data() + write_index, &val, sizeof(T));
138 write_index += sizeof(T);
139 write_index = Common::AlignUp(write_index, 4);
140 } 125 }
141 126
142 template <typename T> 127 template <typename T>
143 void WriteObject(const T* ptr) { 128 void WriteFlattenedObject(const T* ptr) {
144 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
145
146 if (!ptr) { 129 if (!ptr) {
147 Write<u32>(0); 130 this->Write<u32>(0);
148 return; 131 return;
149 } 132 }
150 133
151 Write<u32>(1); 134 this->Write<u32>(1);
152 Write<s64>(sizeof(T)); 135 this->Write<s64>(sizeof(T));
153 Write(*ptr); 136 this->Write(*ptr);
154 } 137 }
155 138
156 template <typename T> 139 template <typename T>
157 void WriteObject(const std::shared_ptr<T> ptr) { 140 void WriteFlattenedObject(const std::shared_ptr<T> ptr) {
158 WriteObject(ptr.get()); 141 this->WriteFlattenedObject(ptr.get());
142 }
143
144 template <typename T>
145 void WriteInterface(const T& val) {
146 this->WriteImpl(val, m_data_buffer);
147 this->WriteImpl(0U, m_object_buffer);
159 } 148 }
160 149
161 std::vector<u8> Serialize() const { 150 std::vector<u8> Serialize() const {
151 std::vector<u8> output_buffer(sizeof(ParcelHeader) + m_data_buffer.size() +
152 m_object_buffer.size());
153
162 ParcelHeader header{}; 154 ParcelHeader header{};
163 header.data_size = static_cast<u32>(write_index - sizeof(ParcelHeader)); 155 header.data_size = static_cast<u32>(m_data_buffer.size());
164 header.data_offset = sizeof(ParcelHeader); 156 header.data_offset = sizeof(ParcelHeader);
165 header.objects_size = 4; 157 header.objects_size = static_cast<u32>(m_object_buffer.size());
166 header.objects_offset = static_cast<u32>(sizeof(ParcelHeader) + header.data_size); 158 header.objects_offset = header.data_offset + header.data_size;
167 std::memcpy(buffer.data(), &header, sizeof(ParcelHeader)); 159
160 std::memcpy(output_buffer.data(), &header, sizeof(header));
161 std::ranges::copy(m_data_buffer, output_buffer.data() + header.data_offset);
162 std::ranges::copy(m_object_buffer, output_buffer.data() + header.objects_offset);
163
164 return output_buffer;
165 }
166
167private:
168 template <typename T>
169 requires(std::is_trivially_copyable_v<T>)
170 void WriteImpl(const T& val, std::vector<u8>& buffer) {
171 const size_t aligned_size = Common::AlignUp(sizeof(T), 4);
172 const size_t old_size = buffer.size();
173 buffer.resize(old_size + aligned_size);
168 174
169 return buffer; 175 std::memcpy(buffer.data() + old_size, &val, sizeof(T));
170 } 176 }
171 177
172private: 178private:
173 mutable std::vector<u8> buffer; 179 std::vector<u8> m_data_buffer;
174 std::size_t write_index = sizeof(ParcelHeader); 180 std::vector<u8> m_object_buffer;
175}; 181};
176 182
177} // namespace Service::android 183} // namespace Service::android
diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h
index ed1eb5b2d..e6293ffb9 100644
--- a/src/core/hle/service/time/clock_types.h
+++ b/src/core/hle/service/time/clock_types.h
@@ -59,6 +59,18 @@ static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext is incorre
59static_assert(std::is_trivially_copyable_v<SystemClockContext>, 59static_assert(std::is_trivially_copyable_v<SystemClockContext>,
60 "SystemClockContext must be trivially copyable"); 60 "SystemClockContext must be trivially copyable");
61 61
62struct ContinuousAdjustmentTimePoint {
63 s64 measurement_offset;
64 s64 diff_scale;
65 u32 shift_amount;
66 s64 lower;
67 s64 upper;
68 Common::UUID clock_source_id;
69};
70static_assert(sizeof(ContinuousAdjustmentTimePoint) == 0x38);
71static_assert(std::is_trivially_copyable_v<ContinuousAdjustmentTimePoint>,
72 "ContinuousAdjustmentTimePoint must be trivially copyable");
73
62/// https://switchbrew.org/wiki/Glue_services#TimeSpanType 74/// https://switchbrew.org/wiki/Glue_services#TimeSpanType
63struct TimeSpanType { 75struct TimeSpanType {
64 s64 nanoseconds{}; 76 s64 nanoseconds{};
diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp
index ff53a7d6f..ce1c85bcc 100644
--- a/src/core/hle/service/time/time_sharedmemory.cpp
+++ b/src/core/hle/service/time/time_sharedmemory.cpp
@@ -30,6 +30,25 @@ void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id,
30} 30}
31 31
32void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) { 32void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) {
33 // lower and upper are related to the measurement point for the steady time point,
34 // and compare equal on boot
35 const s64 time_point_ns = context.steady_time_point.time_point * 1'000'000'000LL;
36
37 // This adjusts for some sort of time skew
38 // Both 0 on boot
39 const s64 diff_scale = 0;
40 const u32 shift_amount = 0;
41
42 const Clock::ContinuousAdjustmentTimePoint adjustment{
43 .measurement_offset = system.CoreTiming().GetGlobalTimeNs().count(),
44 .diff_scale = diff_scale,
45 .shift_amount = shift_amount,
46 .lower = time_point_ns,
47 .upper = time_point_ns,
48 .clock_source_id = context.steady_time_point.clock_source_id,
49 };
50
51 StoreToLockFreeAtomicType(&GetFormat()->continuous_adjustment_timepoint, adjustment);
33 StoreToLockFreeAtomicType(&GetFormat()->standard_local_system_clock_context, context); 52 StoreToLockFreeAtomicType(&GetFormat()->standard_local_system_clock_context, context);
34} 53}
35 54
diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h
index 044a4d24e..c89be9765 100644
--- a/src/core/hle/service/time/time_sharedmemory.h
+++ b/src/core/hle/service/time/time_sharedmemory.h
@@ -65,14 +65,15 @@ public:
65 LockFreeAtomicType<Clock::SystemClockContext> standard_local_system_clock_context; 65 LockFreeAtomicType<Clock::SystemClockContext> standard_local_system_clock_context;
66 LockFreeAtomicType<Clock::SystemClockContext> standard_network_system_clock_context; 66 LockFreeAtomicType<Clock::SystemClockContext> standard_network_system_clock_context;
67 LockFreeAtomicType<bool> is_standard_user_system_clock_automatic_correction_enabled; 67 LockFreeAtomicType<bool> is_standard_user_system_clock_automatic_correction_enabled;
68 u32 format_version; 68 LockFreeAtomicType<Clock::ContinuousAdjustmentTimePoint> continuous_adjustment_timepoint;
69 }; 69 };
70 static_assert(offsetof(Format, standard_steady_clock_timepoint) == 0x0); 70 static_assert(offsetof(Format, standard_steady_clock_timepoint) == 0x0);
71 static_assert(offsetof(Format, standard_local_system_clock_context) == 0x38); 71 static_assert(offsetof(Format, standard_local_system_clock_context) == 0x38);
72 static_assert(offsetof(Format, standard_network_system_clock_context) == 0x80); 72 static_assert(offsetof(Format, standard_network_system_clock_context) == 0x80);
73 static_assert(offsetof(Format, is_standard_user_system_clock_automatic_correction_enabled) == 73 static_assert(offsetof(Format, is_standard_user_system_clock_automatic_correction_enabled) ==
74 0xc8); 74 0xc8);
75 static_assert(sizeof(Format) == 0xd8, "Format is an invalid size"); 75 static_assert(offsetof(Format, continuous_adjustment_timepoint) == 0xd0);
76 static_assert(sizeof(Format) == 0x148, "Format is an invalid size");
76 77
77 void SetupStandardSteadyClock(const Common::UUID& clock_source_id, 78 void SetupStandardSteadyClock(const Common::UUID& clock_source_id,
78 Clock::TimeSpanType current_time_point); 79 Clock::TimeSpanType current_time_point);
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 68eab5133..1b193f00c 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -64,8 +64,8 @@ public:
64private: 64private:
65 const u32 magic = 2; 65 const u32 magic = 2;
66 const u32 process_id = 1; 66 const u32 process_id = 1;
67 const u32 id; 67 const u64 id;
68 INSERT_PADDING_WORDS(3); 68 INSERT_PADDING_WORDS(2);
69 std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'}; 69 std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
70 INSERT_PADDING_WORDS(2); 70 INSERT_PADDING_WORDS(2);
71}; 71};
@@ -608,7 +608,9 @@ private:
608 return; 608 return;
609 } 609 }
610 610
611 const auto parcel = android::OutputParcel{NativeWindow{*buffer_queue_id}}; 611 android::OutputParcel parcel;
612 parcel.WriteInterface(NativeWindow{*buffer_queue_id});
613
612 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize()); 614 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
613 615
614 IPC::ResponseBuilder rb{ctx, 4}; 616 IPC::ResponseBuilder rb{ctx, 4};
@@ -654,7 +656,9 @@ private:
654 return; 656 return;
655 } 657 }
656 658
657 const auto parcel = android::OutputParcel{NativeWindow{*buffer_queue_id}}; 659 android::OutputParcel parcel;
660 parcel.WriteInterface(NativeWindow{*buffer_queue_id});
661
658 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize()); 662 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
659 663
660 IPC::ResponseBuilder rb{ctx, 6}; 664 IPC::ResponseBuilder rb{ctx, 6};
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index 7f9e8dbb9..9a0439bb5 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -109,14 +109,37 @@ public:
109 } 109 }
110 110
111 bool RumblePlay(const Common::Input::VibrationStatus vibration) { 111 bool RumblePlay(const Common::Input::VibrationStatus vibration) {
112 constexpr u32 rumble_max_duration_ms = 1000; 112 constexpr u32 rumble_max_duration_ms = 2000;
113 constexpr f32 low_start_sensitivity_limit = 140.0;
114 constexpr f32 low_width_sensitivity_limit = 400.0;
115 constexpr f32 high_start_sensitivity_limit = 200.0;
116 constexpr f32 high_width_sensitivity_limit = 700.0;
117 // Try to provide some feeling of the frequency by reducing the amplitude depending on it.
118 f32 low_frequency_scale = 1.0;
119 if (vibration.low_frequency > low_start_sensitivity_limit) {
120 low_frequency_scale =
121 std::max(1.0f - (vibration.low_frequency - low_start_sensitivity_limit) /
122 low_width_sensitivity_limit,
123 0.3f);
124 }
125 f32 low_amplitude = vibration.low_amplitude * low_frequency_scale;
126
127 f32 high_frequency_scale = 1.0;
128 if (vibration.high_frequency > high_start_sensitivity_limit) {
129 high_frequency_scale =
130 std::max(1.0f - (vibration.high_frequency - high_start_sensitivity_limit) /
131 high_width_sensitivity_limit,
132 0.3f);
133 }
134 f32 high_amplitude = vibration.high_amplitude * high_frequency_scale;
135
113 if (sdl_controller) { 136 if (sdl_controller) {
114 return SDL_GameControllerRumble( 137 return SDL_GameControllerRumble(sdl_controller.get(), static_cast<u16>(low_amplitude),
115 sdl_controller.get(), static_cast<u16>(vibration.low_amplitude), 138 static_cast<u16>(high_amplitude),
116 static_cast<u16>(vibration.high_amplitude), rumble_max_duration_ms) != -1; 139 rumble_max_duration_ms) != -1;
117 } else if (sdl_joystick) { 140 } else if (sdl_joystick) {
118 return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(vibration.low_amplitude), 141 return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(low_amplitude),
119 static_cast<u16>(vibration.high_amplitude), 142 static_cast<u16>(high_amplitude),
120 rumble_max_duration_ms) != -1; 143 rumble_max_duration_ms) != -1;
121 } 144 }
122 145
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h
index b03143e04..1c8d294b0 100644
--- a/src/input_common/helpers/joycon_protocol/joycon_types.h
+++ b/src/input_common/helpers/joycon_protocol/joycon_types.h
@@ -394,6 +394,7 @@ enum class DriverResult {
394 InvalidHandle, 394 InvalidHandle,
395 NotSupported, 395 NotSupported,
396 Disabled, 396 Disabled,
397 Delayed,
397 Unknown, 398 Unknown,
398}; 399};
399 400
diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp
index 77ea6d5cf..14818ae33 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.cpp
+++ b/src/input_common/helpers/joycon_protocol/nfc.cpp
@@ -72,6 +72,11 @@ DriverResult NfcProtocol::StartNFCPollingMode() {
72} 72}
73 73
74DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) { 74DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) {
75 if (update_counter++ < AMIIBO_UPDATE_DELAY) {
76 return DriverResult::Delayed;
77 }
78 update_counter = 0;
79
75 LOG_DEBUG(Input, "Start NFC pooling Mode"); 80 LOG_DEBUG(Input, "Start NFC pooling Mode");
76 ScopedSetBlocking sb(this); 81 ScopedSetBlocking sb(this);
77 DriverResult result{DriverResult::Success}; 82 DriverResult result{DriverResult::Success};
@@ -87,7 +92,7 @@ DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) {
87 result = WaitUntilNfcIsReady(); 92 result = WaitUntilNfcIsReady();
88 } 93 }
89 if (result == DriverResult::Success) { 94 if (result == DriverResult::Success) {
90 result = StartPolling(tag_data); 95 result = StartPolling(tag_data, 7);
91 } 96 }
92 if (result == DriverResult::Success) { 97 if (result == DriverResult::Success) {
93 result = GetAmiiboData(data); 98 result = GetAmiiboData(data);
@@ -129,9 +134,8 @@ DriverResult NfcProtocol::WaitUntilNfcIsReady() {
129 return DriverResult::Success; 134 return DriverResult::Success;
130} 135}
131 136
132DriverResult NfcProtocol::StartPolling(TagFoundData& data) { 137DriverResult NfcProtocol::StartPolling(TagFoundData& data, std::size_t timeout_limit) {
133 LOG_DEBUG(Input, "Start Polling for tag"); 138 LOG_DEBUG(Input, "Start Polling for tag");
134 constexpr std::size_t timeout_limit = 7;
135 MCUCommandResponse output{}; 139 MCUCommandResponse output{};
136 std::size_t tries = 0; 140 std::size_t tries = 0;
137 141
diff --git a/src/input_common/helpers/joycon_protocol/nfc.h b/src/input_common/helpers/joycon_protocol/nfc.h
index 11e263e07..4cb992d1d 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.h
+++ b/src/input_common/helpers/joycon_protocol/nfc.h
@@ -32,6 +32,9 @@ public:
32 bool IsEnabled() const; 32 bool IsEnabled() const;
33 33
34private: 34private:
35 // Number of times the function will be delayed until it outputs valid data
36 static constexpr std::size_t AMIIBO_UPDATE_DELAY = 15;
37
35 struct TagFoundData { 38 struct TagFoundData {
36 u8 type; 39 u8 type;
37 std::vector<u8> uuid; 40 std::vector<u8> uuid;
@@ -39,7 +42,7 @@ private:
39 42
40 DriverResult WaitUntilNfcIsReady(); 43 DriverResult WaitUntilNfcIsReady();
41 44
42 DriverResult StartPolling(TagFoundData& data); 45 DriverResult StartPolling(TagFoundData& data, std::size_t timeout_limit = 1);
43 46
44 DriverResult ReadTag(const TagFoundData& data); 47 DriverResult ReadTag(const TagFoundData& data);
45 48
@@ -56,6 +59,7 @@ private:
56 NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; 59 NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const;
57 60
58 bool is_enabled{}; 61 bool is_enabled{};
62 std::size_t update_counter{};
59}; 63};
60 64
61} // namespace InputCommon::Joycon 65} // namespace InputCommon::Joycon
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index fee510f7b..07c2b7b8a 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
@@ -339,9 +339,7 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
339 if (ctx.profile.support_vertex_instance_id) { 339 if (ctx.profile.support_vertex_instance_id) {
340 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_id)); 340 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_id));
341 } else { 341 } else {
342 const Id index{ctx.OpLoad(ctx.U32[1], ctx.vertex_index)}; 342 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_index));
343 const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)};
344 return ctx.OpBitcast(ctx.F32[1], ctx.OpISub(ctx.U32[1], index, base));
345 } 343 }
346 case IR::Attribute::BaseInstance: 344 case IR::Attribute::BaseInstance:
347 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.base_instance)); 345 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.base_instance));
@@ -386,9 +384,7 @@ Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, Id) {
386 if (ctx.profile.support_vertex_instance_id) { 384 if (ctx.profile.support_vertex_instance_id) {
387 return ctx.OpLoad(ctx.U32[1], ctx.vertex_id); 385 return ctx.OpLoad(ctx.U32[1], ctx.vertex_id);
388 } else { 386 } else {
389 const Id index{ctx.OpLoad(ctx.U32[1], ctx.vertex_index)}; 387 return ctx.OpLoad(ctx.U32[1], ctx.vertex_index);
390 const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)};
391 return ctx.OpISub(ctx.U32[1], index, base);
392 } 388 }
393 case IR::Attribute::BaseInstance: 389 case IR::Attribute::BaseInstance:
394 return ctx.OpLoad(ctx.U32[1], ctx.base_instance); 390 return ctx.OpLoad(ctx.U32[1], ctx.base_instance);
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp
index 639da1e9c..eeb49444f 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp
@@ -102,12 +102,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
102 } 102 }
103 IR::F32 value{v.ir.CompositeExtract(sample, element)}; 103 IR::F32 value{v.ir.CompositeExtract(sample, element)};
104 if (element < 2) { 104 if (element < 2) {
105 IR::U32 casted_value; 105 IR::U32 casted_value = v.ir.ConvertFToU(32, value);
106 if (element == 0) {
107 casted_value = v.ir.ConvertFToU(32, value);
108 } else {
109 casted_value = v.ir.ConvertFToS(16, value);
110 }
111 v.X(dest_reg, v.ir.ShiftLeftLogical(casted_value, v.ir.Imm32(8))); 106 v.X(dest_reg, v.ir.ShiftLeftLogical(casted_value, v.ir.Imm32(8)));
112 } else { 107 } else {
113 v.F(dest_reg, value); 108 v.F(dest_reg, value);
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 6624919a4..98756e4da 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -96,12 +96,12 @@ void BufferCache<P>::TickFrame() {
96 96
97template <class P> 97template <class P>
98void BufferCache<P>::WriteMemory(VAddr cpu_addr, u64 size) { 98void BufferCache<P>::WriteMemory(VAddr cpu_addr, u64 size) {
99 memory_tracker.MarkRegionAsCpuModified(cpu_addr, size);
100 if (memory_tracker.IsRegionGpuModified(cpu_addr, size)) { 99 if (memory_tracker.IsRegionGpuModified(cpu_addr, size)) {
101 const IntervalType subtract_interval{cpu_addr, cpu_addr + size}; 100 const IntervalType subtract_interval{cpu_addr, cpu_addr + size};
102 ClearDownload(subtract_interval); 101 ClearDownload(subtract_interval);
103 common_ranges.subtract(subtract_interval); 102 common_ranges.subtract(subtract_interval);
104 } 103 }
104 memory_tracker.MarkRegionAsCpuModified(cpu_addr, size);
105} 105}
106 106
107template <class P> 107template <class P>
@@ -122,41 +122,24 @@ std::optional<VideoCore::RasterizerDownloadArea> BufferCache<P>::GetFlushArea(VA
122 area->preemtive = true; 122 area->preemtive = true;
123 return area; 123 return area;
124 }; 124 };
125 area->preemtive =
126 !IsRegionGpuModified(cpu_addr_start_aligned, cpu_addr_end_aligned - cpu_addr_start_aligned);
125 memory_tracker.MarkRegionAsPreflushable(cpu_addr_start_aligned, 127 memory_tracker.MarkRegionAsPreflushable(cpu_addr_start_aligned,
126 cpu_addr_end_aligned - cpu_addr_start_aligned); 128 cpu_addr_end_aligned - cpu_addr_start_aligned);
127 area->preemtive = !IsRegionGpuModified(cpu_addr, size);
128 return area; 129 return area;
129} 130}
130 131
131template <class P> 132template <class P>
132void BufferCache<P>::DownloadMemory(VAddr cpu_addr, u64 size) { 133void BufferCache<P>::DownloadMemory(VAddr cpu_addr, u64 size) {
133 WaitOnAsyncFlushes(cpu_addr, size);
134 ForEachBufferInRange(cpu_addr, size, [&](BufferId, Buffer& buffer) { 134 ForEachBufferInRange(cpu_addr, size, [&](BufferId, Buffer& buffer) {
135 DownloadBufferMemory(buffer, cpu_addr, size); 135 DownloadBufferMemory(buffer, cpu_addr, size);
136 }); 136 });
137} 137}
138 138
139template <class P> 139template <class P>
140void BufferCache<P>::WaitOnAsyncFlushes(VAddr cpu_addr, u64 size) {
141 bool must_wait = false;
142 ForEachInOverlapCounter(async_downloads, cpu_addr, size,
143 [&](VAddr, VAddr, int) { must_wait = true; });
144 bool must_release = false;
145 ForEachInRangeSet(pending_ranges, cpu_addr, size, [&](VAddr, VAddr) { must_release = true; });
146 if (must_release) {
147 std::function<void()> tmp([]() {});
148 rasterizer.SignalFence(std::move(tmp));
149 }
150 if (must_wait || must_release) {
151 rasterizer.ReleaseFences();
152 }
153}
154
155template <class P>
156void BufferCache<P>::ClearDownload(IntervalType subtract_interval) { 140void BufferCache<P>::ClearDownload(IntervalType subtract_interval) {
157 RemoveEachInOverlapCounter(async_downloads, subtract_interval, -1024); 141 RemoveEachInOverlapCounter(async_downloads, subtract_interval, -1024);
158 uncommitted_ranges.subtract(subtract_interval); 142 uncommitted_ranges.subtract(subtract_interval);
159 pending_ranges.subtract(subtract_interval);
160 for (auto& interval_set : committed_ranges) { 143 for (auto& interval_set : committed_ranges) {
161 interval_set.subtract(subtract_interval); 144 interval_set.subtract(subtract_interval);
162 } 145 }
@@ -176,7 +159,6 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
176 } 159 }
177 160
178 const IntervalType subtract_interval{*cpu_dest_address, *cpu_dest_address + amount}; 161 const IntervalType subtract_interval{*cpu_dest_address, *cpu_dest_address + amount};
179 WaitOnAsyncFlushes(*cpu_src_address, static_cast<u32>(amount));
180 ClearDownload(subtract_interval); 162 ClearDownload(subtract_interval);
181 163
182 BufferId buffer_a; 164 BufferId buffer_a;
@@ -204,7 +186,6 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
204 const IntervalType add_interval{new_base_address, new_base_address + size}; 186 const IntervalType add_interval{new_base_address, new_base_address + size};
205 tmp_intervals.push_back(add_interval); 187 tmp_intervals.push_back(add_interval);
206 uncommitted_ranges.add(add_interval); 188 uncommitted_ranges.add(add_interval);
207 pending_ranges.add(add_interval);
208 }; 189 };
209 ForEachInRangeSet(common_ranges, *cpu_src_address, amount, mirror); 190 ForEachInRangeSet(common_ranges, *cpu_src_address, amount, mirror);
210 // This subtraction in this order is important for overlapping copies. 191 // This subtraction in this order is important for overlapping copies.
@@ -491,7 +472,6 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
491 } 472 }
492 MICROPROFILE_SCOPE(GPU_DownloadMemory); 473 MICROPROFILE_SCOPE(GPU_DownloadMemory);
493 474
494 pending_ranges.clear();
495 auto it = committed_ranges.begin(); 475 auto it = committed_ranges.begin();
496 while (it != committed_ranges.end()) { 476 while (it != committed_ranges.end()) {
497 auto& current_intervals = *it; 477 auto& current_intervals = *it;
@@ -1223,16 +1203,14 @@ void BufferCache<P>::UpdateComputeTextureBuffers() {
1223 1203
1224template <class P> 1204template <class P>
1225void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size) { 1205void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size) {
1226 memory_tracker.MarkRegionAsGpuModified(cpu_addr, size);
1227
1228 if (memory_tracker.IsRegionCpuModified(cpu_addr, size)) { 1206 if (memory_tracker.IsRegionCpuModified(cpu_addr, size)) {
1229 SynchronizeBuffer(slot_buffers[buffer_id], cpu_addr, size); 1207 SynchronizeBuffer(slot_buffers[buffer_id], cpu_addr, size);
1230 } 1208 }
1209 memory_tracker.MarkRegionAsGpuModified(cpu_addr, size);
1231 1210
1232 const IntervalType base_interval{cpu_addr, cpu_addr + size}; 1211 const IntervalType base_interval{cpu_addr, cpu_addr + size};
1233 common_ranges.add(base_interval); 1212 common_ranges.add(base_interval);
1234 uncommitted_ranges.add(base_interval); 1213 uncommitted_ranges.add(base_interval);
1235 pending_ranges.add(base_interval);
1236} 1214}
1237 1215
1238template <class P> 1216template <class P>
@@ -1677,14 +1655,15 @@ typename BufferCache<P>::Binding BufferCache<P>::StorageBufferBinding(GPUVAddr s
1677 const bool is_nvn_cbuf = cbuf_index == 0; 1655 const bool is_nvn_cbuf = cbuf_index == 0;
1678 // The NVN driver buffer (index 0) is known to pack the SSBO address followed by its size. 1656 // The NVN driver buffer (index 0) is known to pack the SSBO address followed by its size.
1679 if (is_nvn_cbuf) { 1657 if (is_nvn_cbuf) {
1680 return gpu_memory->Read<u32>(ssbo_addr + 8); 1658 const u32 ssbo_size = gpu_memory->Read<u32>(ssbo_addr + 8);
1659 if (ssbo_size != 0) {
1660 return ssbo_size;
1661 }
1681 } 1662 }
1682 // Other titles (notably Doom Eternal) may use STG/LDG on buffer addresses in custom defined 1663 // Other titles (notably Doom Eternal) may use STG/LDG on buffer addresses in custom defined
1683 // cbufs, which do not store the sizes adjacent to the addresses, so use the fully 1664 // cbufs, which do not store the sizes adjacent to the addresses, so use the fully
1684 // mapped buffer size for now. 1665 // mapped buffer size for now.
1685 const u32 memory_layout_size = static_cast<u32>(gpu_memory->GetMemoryLayoutSize(gpu_addr)); 1666 const u32 memory_layout_size = static_cast<u32>(gpu_memory->GetMemoryLayoutSize(gpu_addr));
1686 LOG_INFO(HW_GPU, "Binding storage buffer for cbuf index {}, MemoryLayoutSize 0x{:X}",
1687 cbuf_index, memory_layout_size);
1688 return memory_layout_size; 1667 return memory_layout_size;
1689 }(); 1668 }();
1690 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); 1669 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h
index 0445ec47f..ac00d4d9d 100644
--- a/src/video_core/buffer_cache/buffer_cache_base.h
+++ b/src/video_core/buffer_cache/buffer_cache_base.h
@@ -381,8 +381,6 @@ private:
381 381
382 void RunGarbageCollector(); 382 void RunGarbageCollector();
383 383
384 void WaitOnAsyncFlushes(VAddr cpu_addr, u64 size);
385
386 void BindHostIndexBuffer(); 384 void BindHostIndexBuffer();
387 385
388 void BindHostVertexBuffers(); 386 void BindHostVertexBuffers();
@@ -547,7 +545,6 @@ private:
547 IntervalSet uncommitted_ranges; 545 IntervalSet uncommitted_ranges;
548 IntervalSet common_ranges; 546 IntervalSet common_ranges;
549 IntervalSet cached_ranges; 547 IntervalSet cached_ranges;
550 IntervalSet pending_ranges;
551 std::deque<IntervalSet> committed_ranges; 548 std::deque<IntervalSet> committed_ranges;
552 549
553 // Async Buffers 550 // Async Buffers
diff --git a/src/video_core/engines/sw_blitter/blitter.cpp b/src/video_core/engines/sw_blitter/blitter.cpp
index 3c9f38559..ff88cd03d 100644
--- a/src/video_core/engines/sw_blitter/blitter.cpp
+++ b/src/video_core/engines/sw_blitter/blitter.cpp
@@ -5,6 +5,7 @@
5#include <cmath> 5#include <cmath>
6#include <vector> 6#include <vector>
7 7
8#include "common/scratch_buffer.h"
8#include "video_core/engines/sw_blitter/blitter.h" 9#include "video_core/engines/sw_blitter/blitter.h"
9#include "video_core/engines/sw_blitter/converter.h" 10#include "video_core/engines/sw_blitter/converter.h"
10#include "video_core/memory_manager.h" 11#include "video_core/memory_manager.h"
@@ -112,11 +113,11 @@ void Bilinear(std::span<const f32> input, std::span<f32> output, size_t src_widt
112} // namespace 113} // namespace
113 114
114struct SoftwareBlitEngine::BlitEngineImpl { 115struct SoftwareBlitEngine::BlitEngineImpl {
115 std::vector<u8> tmp_buffer; 116 Common::ScratchBuffer<u8> tmp_buffer;
116 std::vector<u8> src_buffer; 117 Common::ScratchBuffer<u8> src_buffer;
117 std::vector<u8> dst_buffer; 118 Common::ScratchBuffer<u8> dst_buffer;
118 std::vector<f32> intermediate_src; 119 Common::ScratchBuffer<f32> intermediate_src;
119 std::vector<f32> intermediate_dst; 120 Common::ScratchBuffer<f32> intermediate_dst;
120 ConverterFactory converter_factory; 121 ConverterFactory converter_factory;
121}; 122};
122 123
@@ -158,14 +159,14 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
158 const auto src_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format)); 159 const auto src_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format));
159 const auto dst_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(dst.format)); 160 const auto dst_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(dst.format));
160 const size_t src_size = get_surface_size(src, src_bytes_per_pixel); 161 const size_t src_size = get_surface_size(src, src_bytes_per_pixel);
161 impl->tmp_buffer.resize(src_size); 162 impl->tmp_buffer.resize_destructive(src_size);
162 memory_manager.ReadBlock(src.Address(), impl->tmp_buffer.data(), src_size); 163 memory_manager.ReadBlock(src.Address(), impl->tmp_buffer.data(), src_size);
163 164
164 const size_t src_copy_size = src_extent_x * src_extent_y * src_bytes_per_pixel; 165 const size_t src_copy_size = src_extent_x * src_extent_y * src_bytes_per_pixel;
165 166
166 const size_t dst_copy_size = dst_extent_x * dst_extent_y * dst_bytes_per_pixel; 167 const size_t dst_copy_size = dst_extent_x * dst_extent_y * dst_bytes_per_pixel;
167 168
168 impl->src_buffer.resize(src_copy_size); 169 impl->src_buffer.resize_destructive(src_copy_size);
169 170
170 const bool no_passthrough = 171 const bool no_passthrough =
171 src.format != dst.format || src_extent_x != dst_extent_x || src_extent_y != dst_extent_y; 172 src.format != dst.format || src_extent_x != dst_extent_x || src_extent_y != dst_extent_y;
@@ -177,8 +178,10 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
177 178
178 const auto convertion_phase_ir = [&]() { 179 const auto convertion_phase_ir = [&]() {
179 auto* input_converter = impl->converter_factory.GetFormatConverter(src.format); 180 auto* input_converter = impl->converter_factory.GetFormatConverter(src.format);
180 impl->intermediate_src.resize((src_copy_size / src_bytes_per_pixel) * ir_components); 181 impl->intermediate_src.resize_destructive((src_copy_size / src_bytes_per_pixel) *
181 impl->intermediate_dst.resize((dst_copy_size / dst_bytes_per_pixel) * ir_components); 182 ir_components);
183 impl->intermediate_dst.resize_destructive((dst_copy_size / dst_bytes_per_pixel) *
184 ir_components);
182 input_converter->ConvertTo(impl->src_buffer, impl->intermediate_src); 185 input_converter->ConvertTo(impl->src_buffer, impl->intermediate_src);
183 186
184 if (config.filter != Fermi2D::Filter::Bilinear) { 187 if (config.filter != Fermi2D::Filter::Bilinear) {
@@ -195,7 +198,7 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
195 198
196 // Do actual Blit 199 // Do actual Blit
197 200
198 impl->dst_buffer.resize(dst_copy_size); 201 impl->dst_buffer.resize_destructive(dst_copy_size);
199 if (src.linear == Fermi2D::MemoryLayout::BlockLinear) { 202 if (src.linear == Fermi2D::MemoryLayout::BlockLinear) {
200 UnswizzleSubrect(impl->src_buffer, impl->tmp_buffer, src_bytes_per_pixel, src.width, 203 UnswizzleSubrect(impl->src_buffer, impl->tmp_buffer, src_bytes_per_pixel, src.width,
201 src.height, src.depth, config.src_x0, config.src_y0, src_extent_x, 204 src.height, src.depth, config.src_x0, config.src_y0, src_extent_x,
@@ -218,7 +221,7 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
218 } 221 }
219 222
220 const size_t dst_size = get_surface_size(dst, dst_bytes_per_pixel); 223 const size_t dst_size = get_surface_size(dst, dst_bytes_per_pixel);
221 impl->tmp_buffer.resize(dst_size); 224 impl->tmp_buffer.resize_destructive(dst_size);
222 memory_manager.ReadBlock(dst.Address(), impl->tmp_buffer.data(), dst_size); 225 memory_manager.ReadBlock(dst.Address(), impl->tmp_buffer.data(), dst_size);
223 226
224 if (dst.linear == Fermi2D::MemoryLayout::BlockLinear) { 227 if (dst.linear == Fermi2D::MemoryLayout::BlockLinear) {
diff --git a/src/video_core/host1x/codecs/h264.cpp b/src/video_core/host1x/codecs/h264.cpp
index e87bd65fa..6ce179167 100644
--- a/src/video_core/host1x/codecs/h264.cpp
+++ b/src/video_core/host1x/codecs/h264.cpp
@@ -111,7 +111,7 @@ const std::vector<u8>& H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegist
111 writer.WriteUe(0); 111 writer.WriteUe(0);
112 112
113 writer.WriteBit(context.h264_parameter_set.entropy_coding_mode_flag != 0); 113 writer.WriteBit(context.h264_parameter_set.entropy_coding_mode_flag != 0);
114 writer.WriteBit(false); 114 writer.WriteBit(context.h264_parameter_set.pic_order_present_flag != 0);
115 writer.WriteUe(0); 115 writer.WriteUe(0);
116 writer.WriteUe(context.h264_parameter_set.num_refidx_l0_default_active); 116 writer.WriteUe(context.h264_parameter_set.num_refidx_l0_default_active);
117 writer.WriteUe(context.h264_parameter_set.num_refidx_l1_default_active); 117 writer.WriteUe(context.h264_parameter_set.num_refidx_l1_default_active);
@@ -129,7 +129,7 @@ const std::vector<u8>& H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegist
129 writer.WriteBit(context.h264_parameter_set.redundant_pic_cnt_present_flag != 0); 129 writer.WriteBit(context.h264_parameter_set.redundant_pic_cnt_present_flag != 0);
130 writer.WriteBit(context.h264_parameter_set.transform_8x8_mode_flag != 0); 130 writer.WriteBit(context.h264_parameter_set.transform_8x8_mode_flag != 0);
131 131
132 writer.WriteBit(true); 132 writer.WriteBit(true); // pic_scaling_matrix_present_flag
133 133
134 for (s32 index = 0; index < 6; index++) { 134 for (s32 index = 0; index < 6; index++) {
135 writer.WriteBit(true); 135 writer.WriteBit(true);
diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h
index 28b893e25..983e1c2e1 100644
--- a/src/video_core/renderer_vulkan/pipeline_helper.h
+++ b/src/video_core/renderer_vulkan/pipeline_helper.h
@@ -176,7 +176,7 @@ public:
176}; 176};
177 177
178inline void PushImageDescriptors(TextureCache& texture_cache, 178inline void PushImageDescriptors(TextureCache& texture_cache,
179 UpdateDescriptorQueue& update_descriptor_queue, 179 GuestDescriptorQueue& guest_descriptor_queue,
180 const Shader::Info& info, RescalingPushConstant& rescaling, 180 const Shader::Info& info, RescalingPushConstant& rescaling,
181 const VkSampler*& samplers, 181 const VkSampler*& samplers,
182 const VideoCommon::ImageViewInOut*& views) { 182 const VideoCommon::ImageViewInOut*& views) {
@@ -190,7 +190,7 @@ inline void PushImageDescriptors(TextureCache& texture_cache,
190 const VkSampler sampler{*(samplers++)}; 190 const VkSampler sampler{*(samplers++)};
191 ImageView& image_view{texture_cache.GetImageView(image_view_id)}; 191 ImageView& image_view{texture_cache.GetImageView(image_view_id)};
192 const VkImageView vk_image_view{image_view.Handle(desc.type)}; 192 const VkImageView vk_image_view{image_view.Handle(desc.type)};
193 update_descriptor_queue.AddSampledImage(vk_image_view, sampler); 193 guest_descriptor_queue.AddSampledImage(vk_image_view, sampler);
194 rescaling.PushTexture(texture_cache.IsRescaling(image_view)); 194 rescaling.PushTexture(texture_cache.IsRescaling(image_view));
195 } 195 }
196 } 196 }
@@ -201,7 +201,7 @@ inline void PushImageDescriptors(TextureCache& texture_cache,
201 texture_cache.MarkModification(image_view.image_id); 201 texture_cache.MarkModification(image_view.image_id);
202 } 202 }
203 const VkImageView vk_image_view{image_view.StorageView(desc.type, desc.format)}; 203 const VkImageView vk_image_view{image_view.StorageView(desc.type, desc.format)};
204 update_descriptor_queue.AddImage(vk_image_view); 204 guest_descriptor_queue.AddImage(vk_image_view);
205 rescaling.PushImage(texture_cache.IsRescaling(image_view)); 205 rescaling.PushImage(texture_cache.IsRescaling(image_view));
206 } 206 }
207 } 207 }
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 510602e8e..9627eb129 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -298,12 +298,14 @@ private:
298 298
299BufferCacheRuntime::BufferCacheRuntime(const Device& device_, MemoryAllocator& memory_allocator_, 299BufferCacheRuntime::BufferCacheRuntime(const Device& device_, MemoryAllocator& memory_allocator_,
300 Scheduler& scheduler_, StagingBufferPool& staging_pool_, 300 Scheduler& scheduler_, StagingBufferPool& staging_pool_,
301 UpdateDescriptorQueue& update_descriptor_queue_, 301 GuestDescriptorQueue& guest_descriptor_queue_,
302 ComputePassDescriptorQueue& compute_pass_descriptor_queue,
302 DescriptorPool& descriptor_pool) 303 DescriptorPool& descriptor_pool)
303 : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_}, 304 : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_},
304 staging_pool{staging_pool_}, update_descriptor_queue{update_descriptor_queue_}, 305 staging_pool{staging_pool_}, guest_descriptor_queue{guest_descriptor_queue_},
305 uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), 306 uint8_pass(device, scheduler, descriptor_pool, staging_pool, compute_pass_descriptor_queue),
306 quad_index_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue) { 307 quad_index_pass(device, scheduler, descriptor_pool, staging_pool,
308 compute_pass_descriptor_queue) {
307 quad_array_index_buffer = std::make_shared<QuadArrayIndexBuffer>(device_, memory_allocator_, 309 quad_array_index_buffer = std::make_shared<QuadArrayIndexBuffer>(device_, memory_allocator_,
308 scheduler_, staging_pool_); 310 scheduler_, staging_pool_);
309 quad_strip_index_buffer = std::make_shared<QuadStripIndexBuffer>(device_, memory_allocator_, 311 quad_strip_index_buffer = std::make_shared<QuadStripIndexBuffer>(device_, memory_allocator_,
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index 879f1ed94..5e9602905 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -63,7 +63,8 @@ class BufferCacheRuntime {
63public: 63public:
64 explicit BufferCacheRuntime(const Device& device_, MemoryAllocator& memory_manager_, 64 explicit BufferCacheRuntime(const Device& device_, MemoryAllocator& memory_manager_,
65 Scheduler& scheduler_, StagingBufferPool& staging_pool_, 65 Scheduler& scheduler_, StagingBufferPool& staging_pool_,
66 UpdateDescriptorQueue& update_descriptor_queue_, 66 GuestDescriptorQueue& guest_descriptor_queue,
67 ComputePassDescriptorQueue& compute_pass_descriptor_queue,
67 DescriptorPool& descriptor_pool); 68 DescriptorPool& descriptor_pool);
68 69
69 void Finish(); 70 void Finish();
@@ -116,12 +117,12 @@ public:
116 117
117 void BindTextureBuffer(Buffer& buffer, u32 offset, u32 size, 118 void BindTextureBuffer(Buffer& buffer, u32 offset, u32 size,
118 VideoCore::Surface::PixelFormat format) { 119 VideoCore::Surface::PixelFormat format) {
119 update_descriptor_queue.AddTexelBuffer(buffer.View(offset, size, format)); 120 guest_descriptor_queue.AddTexelBuffer(buffer.View(offset, size, format));
120 } 121 }
121 122
122private: 123private:
123 void BindBuffer(VkBuffer buffer, u32 offset, u32 size) { 124 void BindBuffer(VkBuffer buffer, u32 offset, u32 size) {
124 update_descriptor_queue.AddBuffer(buffer, offset, size); 125 guest_descriptor_queue.AddBuffer(buffer, offset, size);
125 } 126 }
126 127
127 void ReserveNullBuffer(); 128 void ReserveNullBuffer();
@@ -130,7 +131,7 @@ private:
130 MemoryAllocator& memory_allocator; 131 MemoryAllocator& memory_allocator;
131 Scheduler& scheduler; 132 Scheduler& scheduler;
132 StagingBufferPool& staging_pool; 133 StagingBufferPool& staging_pool;
133 UpdateDescriptorQueue& update_descriptor_queue; 134 GuestDescriptorQueue& guest_descriptor_queue;
134 135
135 std::shared_ptr<QuadArrayIndexBuffer> quad_array_index_buffer; 136 std::shared_ptr<QuadArrayIndexBuffer> quad_array_index_buffer;
136 std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer; 137 std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer;
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index 1a316b6eb..3bc8553e1 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -200,12 +200,12 @@ ComputePass::~ComputePass() = default;
200 200
201Uint8Pass::Uint8Pass(const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool, 201Uint8Pass::Uint8Pass(const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool,
202 StagingBufferPool& staging_buffer_pool_, 202 StagingBufferPool& staging_buffer_pool_,
203 UpdateDescriptorQueue& update_descriptor_queue_) 203 ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
204 : ComputePass(device_, descriptor_pool, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS, 204 : ComputePass(device_, descriptor_pool, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS,
205 INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO, {}, 205 INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO, {},
206 VULKAN_UINT8_COMP_SPV), 206 VULKAN_UINT8_COMP_SPV),
207 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, 207 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
208 update_descriptor_queue{update_descriptor_queue_} {} 208 compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
209 209
210Uint8Pass::~Uint8Pass() = default; 210Uint8Pass::~Uint8Pass() = default;
211 211
@@ -214,10 +214,10 @@ std::pair<VkBuffer, VkDeviceSize> Uint8Pass::Assemble(u32 num_vertices, VkBuffer
214 const u32 staging_size = static_cast<u32>(num_vertices * sizeof(u16)); 214 const u32 staging_size = static_cast<u32>(num_vertices * sizeof(u16));
215 const auto staging = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); 215 const auto staging = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal);
216 216
217 update_descriptor_queue.Acquire(); 217 compute_pass_descriptor_queue.Acquire();
218 update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices); 218 compute_pass_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices);
219 update_descriptor_queue.AddBuffer(staging.buffer, staging.offset, staging_size); 219 compute_pass_descriptor_queue.AddBuffer(staging.buffer, staging.offset, staging_size);
220 const void* const descriptor_data{update_descriptor_queue.UpdateData()}; 220 const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
221 221
222 scheduler.RequestOutsideRenderPassOperationContext(); 222 scheduler.RequestOutsideRenderPassOperationContext();
223 scheduler.Record([this, descriptor_data, num_vertices](vk::CommandBuffer cmdbuf) { 223 scheduler.Record([this, descriptor_data, num_vertices](vk::CommandBuffer cmdbuf) {
@@ -242,12 +242,12 @@ std::pair<VkBuffer, VkDeviceSize> Uint8Pass::Assemble(u32 num_vertices, VkBuffer
242QuadIndexedPass::QuadIndexedPass(const Device& device_, Scheduler& scheduler_, 242QuadIndexedPass::QuadIndexedPass(const Device& device_, Scheduler& scheduler_,
243 DescriptorPool& descriptor_pool_, 243 DescriptorPool& descriptor_pool_,
244 StagingBufferPool& staging_buffer_pool_, 244 StagingBufferPool& staging_buffer_pool_,
245 UpdateDescriptorQueue& update_descriptor_queue_) 245 ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
246 : ComputePass(device_, descriptor_pool_, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS, 246 : ComputePass(device_, descriptor_pool_, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS,
247 INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO, 247 INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO,
248 COMPUTE_PUSH_CONSTANT_RANGE<sizeof(u32) * 3>, VULKAN_QUAD_INDEXED_COMP_SPV), 248 COMPUTE_PUSH_CONSTANT_RANGE<sizeof(u32) * 3>, VULKAN_QUAD_INDEXED_COMP_SPV),
249 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, 249 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
250 update_descriptor_queue{update_descriptor_queue_} {} 250 compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
251 251
252QuadIndexedPass::~QuadIndexedPass() = default; 252QuadIndexedPass::~QuadIndexedPass() = default;
253 253
@@ -272,10 +272,10 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble(
272 const std::size_t staging_size = num_tri_vertices * sizeof(u32); 272 const std::size_t staging_size = num_tri_vertices * sizeof(u32);
273 const auto staging = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); 273 const auto staging = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal);
274 274
275 update_descriptor_queue.Acquire(); 275 compute_pass_descriptor_queue.Acquire();
276 update_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size); 276 compute_pass_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size);
277 update_descriptor_queue.AddBuffer(staging.buffer, staging.offset, staging_size); 277 compute_pass_descriptor_queue.AddBuffer(staging.buffer, staging.offset, staging_size);
278 const void* const descriptor_data{update_descriptor_queue.UpdateData()}; 278 const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
279 279
280 scheduler.RequestOutsideRenderPassOperationContext(); 280 scheduler.RequestOutsideRenderPassOperationContext();
281 scheduler.Record([this, descriptor_data, num_tri_vertices, base_vertex, index_shift, 281 scheduler.Record([this, descriptor_data, num_tri_vertices, base_vertex, index_shift,
@@ -304,13 +304,14 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble(
304ASTCDecoderPass::ASTCDecoderPass(const Device& device_, Scheduler& scheduler_, 304ASTCDecoderPass::ASTCDecoderPass(const Device& device_, Scheduler& scheduler_,
305 DescriptorPool& descriptor_pool_, 305 DescriptorPool& descriptor_pool_,
306 StagingBufferPool& staging_buffer_pool_, 306 StagingBufferPool& staging_buffer_pool_,
307 UpdateDescriptorQueue& update_descriptor_queue_, 307 ComputePassDescriptorQueue& compute_pass_descriptor_queue_,
308 MemoryAllocator& memory_allocator_) 308 MemoryAllocator& memory_allocator_)
309 : ComputePass(device_, descriptor_pool_, ASTC_DESCRIPTOR_SET_BINDINGS, 309 : ComputePass(device_, descriptor_pool_, ASTC_DESCRIPTOR_SET_BINDINGS,
310 ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY, ASTC_BANK_INFO, 310 ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY, ASTC_BANK_INFO,
311 COMPUTE_PUSH_CONSTANT_RANGE<sizeof(AstcPushConstants)>, ASTC_DECODER_COMP_SPV), 311 COMPUTE_PUSH_CONSTANT_RANGE<sizeof(AstcPushConstants)>, ASTC_DECODER_COMP_SPV),
312 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, 312 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
313 update_descriptor_queue{update_descriptor_queue_}, memory_allocator{memory_allocator_} {} 313 compute_pass_descriptor_queue{compute_pass_descriptor_queue_}, memory_allocator{
314 memory_allocator_} {}
314 315
315ASTCDecoderPass::~ASTCDecoderPass() = default; 316ASTCDecoderPass::~ASTCDecoderPass() = default;
316 317
@@ -358,11 +359,11 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
358 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 8U); 359 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 8U);
359 const u32 num_dispatches_z = image.info.resources.layers; 360 const u32 num_dispatches_z = image.info.resources.layers;
360 361
361 update_descriptor_queue.Acquire(); 362 compute_pass_descriptor_queue.Acquire();
362 update_descriptor_queue.AddBuffer(map.buffer, input_offset, 363 compute_pass_descriptor_queue.AddBuffer(map.buffer, input_offset,
363 image.guest_size_bytes - swizzle.buffer_offset); 364 image.guest_size_bytes - swizzle.buffer_offset);
364 update_descriptor_queue.AddImage(image.StorageImageView(swizzle.level)); 365 compute_pass_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
365 const void* const descriptor_data{update_descriptor_queue.UpdateData()}; 366 const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
366 367
367 // To unswizzle the ASTC data 368 // To unswizzle the ASTC data
368 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info); 369 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h
index c4c8fa081..dd3927376 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.h
@@ -9,6 +9,7 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/engines/maxwell_3d.h" 10#include "video_core/engines/maxwell_3d.h"
11#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 11#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
12#include "video_core/renderer_vulkan/vk_update_descriptor.h"
12#include "video_core/vulkan_common/vulkan_memory_allocator.h" 13#include "video_core/vulkan_common/vulkan_memory_allocator.h"
13#include "video_core/vulkan_common/vulkan_wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
14 15
@@ -21,7 +22,6 @@ namespace Vulkan {
21class Device; 22class Device;
22class StagingBufferPool; 23class StagingBufferPool;
23class Scheduler; 24class Scheduler;
24class UpdateDescriptorQueue;
25class Image; 25class Image;
26struct StagingBufferRef; 26struct StagingBufferRef;
27 27
@@ -50,7 +50,7 @@ class Uint8Pass final : public ComputePass {
50public: 50public:
51 explicit Uint8Pass(const Device& device_, Scheduler& scheduler_, 51 explicit Uint8Pass(const Device& device_, Scheduler& scheduler_,
52 DescriptorPool& descriptor_pool_, StagingBufferPool& staging_buffer_pool_, 52 DescriptorPool& descriptor_pool_, StagingBufferPool& staging_buffer_pool_,
53 UpdateDescriptorQueue& update_descriptor_queue_); 53 ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
54 ~Uint8Pass(); 54 ~Uint8Pass();
55 55
56 /// Assemble uint8 indices into an uint16 index buffer 56 /// Assemble uint8 indices into an uint16 index buffer
@@ -61,7 +61,7 @@ public:
61private: 61private:
62 Scheduler& scheduler; 62 Scheduler& scheduler;
63 StagingBufferPool& staging_buffer_pool; 63 StagingBufferPool& staging_buffer_pool;
64 UpdateDescriptorQueue& update_descriptor_queue; 64 ComputePassDescriptorQueue& compute_pass_descriptor_queue;
65}; 65};
66 66
67class QuadIndexedPass final : public ComputePass { 67class QuadIndexedPass final : public ComputePass {
@@ -69,7 +69,7 @@ public:
69 explicit QuadIndexedPass(const Device& device_, Scheduler& scheduler_, 69 explicit QuadIndexedPass(const Device& device_, Scheduler& scheduler_,
70 DescriptorPool& descriptor_pool_, 70 DescriptorPool& descriptor_pool_,
71 StagingBufferPool& staging_buffer_pool_, 71 StagingBufferPool& staging_buffer_pool_,
72 UpdateDescriptorQueue& update_descriptor_queue_); 72 ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
73 ~QuadIndexedPass(); 73 ~QuadIndexedPass();
74 74
75 std::pair<VkBuffer, VkDeviceSize> Assemble( 75 std::pair<VkBuffer, VkDeviceSize> Assemble(
@@ -79,7 +79,7 @@ public:
79private: 79private:
80 Scheduler& scheduler; 80 Scheduler& scheduler;
81 StagingBufferPool& staging_buffer_pool; 81 StagingBufferPool& staging_buffer_pool;
82 UpdateDescriptorQueue& update_descriptor_queue; 82 ComputePassDescriptorQueue& compute_pass_descriptor_queue;
83}; 83};
84 84
85class ASTCDecoderPass final : public ComputePass { 85class ASTCDecoderPass final : public ComputePass {
@@ -87,7 +87,7 @@ public:
87 explicit ASTCDecoderPass(const Device& device_, Scheduler& scheduler_, 87 explicit ASTCDecoderPass(const Device& device_, Scheduler& scheduler_,
88 DescriptorPool& descriptor_pool_, 88 DescriptorPool& descriptor_pool_,
89 StagingBufferPool& staging_buffer_pool_, 89 StagingBufferPool& staging_buffer_pool_,
90 UpdateDescriptorQueue& update_descriptor_queue_, 90 ComputePassDescriptorQueue& compute_pass_descriptor_queue_,
91 MemoryAllocator& memory_allocator_); 91 MemoryAllocator& memory_allocator_);
92 ~ASTCDecoderPass(); 92 ~ASTCDecoderPass();
93 93
@@ -97,7 +97,7 @@ public:
97private: 97private:
98 Scheduler& scheduler; 98 Scheduler& scheduler;
99 StagingBufferPool& staging_buffer_pool; 99 StagingBufferPool& staging_buffer_pool;
100 UpdateDescriptorQueue& update_descriptor_queue; 100 ComputePassDescriptorQueue& compute_pass_descriptor_queue;
101 MemoryAllocator& memory_allocator; 101 MemoryAllocator& memory_allocator;
102}; 102};
103 103
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index 2a0f0dbf0..733e70d9d 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -26,13 +26,13 @@ using Tegra::Texture::TexturePair;
26 26
27ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipeline_cache_, 27ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipeline_cache_,
28 DescriptorPool& descriptor_pool, 28 DescriptorPool& descriptor_pool,
29 UpdateDescriptorQueue& update_descriptor_queue_, 29 GuestDescriptorQueue& guest_descriptor_queue_,
30 Common::ThreadWorker* thread_worker, 30 Common::ThreadWorker* thread_worker,
31 PipelineStatistics* pipeline_statistics, 31 PipelineStatistics* pipeline_statistics,
32 VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_, 32 VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_,
33 vk::ShaderModule spv_module_) 33 vk::ShaderModule spv_module_)
34 : device{device_}, pipeline_cache(pipeline_cache_), 34 : device{device_},
35 update_descriptor_queue{update_descriptor_queue_}, info{info_}, 35 pipeline_cache(pipeline_cache_), guest_descriptor_queue{guest_descriptor_queue_}, info{info_},
36 spv_module(std::move(spv_module_)) { 36 spv_module(std::move(spv_module_)) {
37 if (shader_notify) { 37 if (shader_notify) {
38 shader_notify->MarkShaderBuilding(); 38 shader_notify->MarkShaderBuilding();
@@ -99,7 +99,7 @@ ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipel
99void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, 99void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
100 Tegra::MemoryManager& gpu_memory, Scheduler& scheduler, 100 Tegra::MemoryManager& gpu_memory, Scheduler& scheduler,
101 BufferCache& buffer_cache, TextureCache& texture_cache) { 101 BufferCache& buffer_cache, TextureCache& texture_cache) {
102 update_descriptor_queue.Acquire(); 102 guest_descriptor_queue.Acquire();
103 103
104 buffer_cache.SetComputeUniformBufferState(info.constant_buffer_mask, &uniform_buffer_sizes); 104 buffer_cache.SetComputeUniformBufferState(info.constant_buffer_mask, &uniform_buffer_sizes);
105 buffer_cache.UnbindComputeStorageBuffers(); 105 buffer_cache.UnbindComputeStorageBuffers();
@@ -194,7 +194,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
194 RescalingPushConstant rescaling; 194 RescalingPushConstant rescaling;
195 const VkSampler* samplers_it{samplers.data()}; 195 const VkSampler* samplers_it{samplers.data()};
196 const VideoCommon::ImageViewInOut* views_it{views.data()}; 196 const VideoCommon::ImageViewInOut* views_it{views.data()};
197 PushImageDescriptors(texture_cache, update_descriptor_queue, info, rescaling, samplers_it, 197 PushImageDescriptors(texture_cache, guest_descriptor_queue, info, rescaling, samplers_it,
198 views_it); 198 views_it);
199 199
200 if (!is_built.load(std::memory_order::relaxed)) { 200 if (!is_built.load(std::memory_order::relaxed)) {
@@ -204,7 +204,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
204 build_condvar.wait(lock, [this] { return is_built.load(std::memory_order::relaxed); }); 204 build_condvar.wait(lock, [this] { return is_built.load(std::memory_order::relaxed); });
205 }); 205 });
206 } 206 }
207 const void* const descriptor_data{update_descriptor_queue.UpdateData()}; 207 const void* const descriptor_data{guest_descriptor_queue.UpdateData()};
208 const bool is_rescaling = !info.texture_descriptors.empty() || !info.image_descriptors.empty(); 208 const bool is_rescaling = !info.texture_descriptors.empty() || !info.image_descriptors.empty();
209 scheduler.Record([this, descriptor_data, is_rescaling, 209 scheduler.Record([this, descriptor_data, is_rescaling,
210 rescaling_data = rescaling.Data()](vk::CommandBuffer cmdbuf) { 210 rescaling_data = rescaling.Data()](vk::CommandBuffer cmdbuf) {
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
index 78d77027f..d1a1e2c46 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
@@ -30,7 +30,7 @@ class ComputePipeline {
30public: 30public:
31 explicit ComputePipeline(const Device& device, vk::PipelineCache& pipeline_cache, 31 explicit ComputePipeline(const Device& device, vk::PipelineCache& pipeline_cache,
32 DescriptorPool& descriptor_pool, 32 DescriptorPool& descriptor_pool,
33 UpdateDescriptorQueue& update_descriptor_queue, 33 GuestDescriptorQueue& guest_descriptor_queue,
34 Common::ThreadWorker* thread_worker, 34 Common::ThreadWorker* thread_worker,
35 PipelineStatistics* pipeline_statistics, 35 PipelineStatistics* pipeline_statistics,
36 VideoCore::ShaderNotify* shader_notify, const Shader::Info& info, 36 VideoCore::ShaderNotify* shader_notify, const Shader::Info& info,
@@ -48,7 +48,7 @@ public:
48private: 48private:
49 const Device& device; 49 const Device& device;
50 vk::PipelineCache& pipeline_cache; 50 vk::PipelineCache& pipeline_cache;
51 UpdateDescriptorQueue& update_descriptor_queue; 51 GuestDescriptorQueue& guest_descriptor_queue;
52 Shader::Info info; 52 Shader::Info info;
53 53
54 VideoCommon::ComputeUniformBufferSizes uniform_buffer_sizes{}; 54 VideoCommon::ComputeUniformBufferSizes uniform_buffer_sizes{};
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index baedc4424..f1bcd5cd6 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -236,13 +236,13 @@ GraphicsPipeline::GraphicsPipeline(
236 Scheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_, 236 Scheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_,
237 vk::PipelineCache& pipeline_cache_, VideoCore::ShaderNotify* shader_notify, 237 vk::PipelineCache& pipeline_cache_, VideoCore::ShaderNotify* shader_notify,
238 const Device& device_, DescriptorPool& descriptor_pool, 238 const Device& device_, DescriptorPool& descriptor_pool,
239 UpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread, 239 GuestDescriptorQueue& guest_descriptor_queue_, Common::ThreadWorker* worker_thread,
240 PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache, 240 PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache,
241 const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages, 241 const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages,
242 const std::array<const Shader::Info*, NUM_STAGES>& infos) 242 const std::array<const Shader::Info*, NUM_STAGES>& infos)
243 : key{key_}, device{device_}, texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, 243 : key{key_}, device{device_}, texture_cache{texture_cache_}, buffer_cache{buffer_cache_},
244 pipeline_cache(pipeline_cache_), scheduler{scheduler_}, 244 pipeline_cache(pipeline_cache_), scheduler{scheduler_},
245 update_descriptor_queue{update_descriptor_queue_}, spv_modules{std::move(stages)} { 245 guest_descriptor_queue{guest_descriptor_queue_}, spv_modules{std::move(stages)} {
246 if (shader_notify) { 246 if (shader_notify) {
247 shader_notify->MarkShaderBuilding(); 247 shader_notify->MarkShaderBuilding();
248 } 248 }
@@ -449,7 +449,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
449 buffer_cache.UpdateGraphicsBuffers(is_indexed); 449 buffer_cache.UpdateGraphicsBuffers(is_indexed);
450 buffer_cache.BindHostGeometryBuffers(is_indexed); 450 buffer_cache.BindHostGeometryBuffers(is_indexed);
451 451
452 update_descriptor_queue.Acquire(); 452 guest_descriptor_queue.Acquire();
453 453
454 RescalingPushConstant rescaling; 454 RescalingPushConstant rescaling;
455 RenderAreaPushConstant render_area; 455 RenderAreaPushConstant render_area;
@@ -457,7 +457,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
457 const VideoCommon::ImageViewInOut* views_it{views.data()}; 457 const VideoCommon::ImageViewInOut* views_it{views.data()};
458 const auto prepare_stage{[&](size_t stage) LAMBDA_FORCEINLINE { 458 const auto prepare_stage{[&](size_t stage) LAMBDA_FORCEINLINE {
459 buffer_cache.BindHostStageBuffers(stage); 459 buffer_cache.BindHostStageBuffers(stage);
460 PushImageDescriptors(texture_cache, update_descriptor_queue, stage_infos[stage], rescaling, 460 PushImageDescriptors(texture_cache, guest_descriptor_queue, stage_infos[stage], rescaling,
461 samplers_it, views_it); 461 samplers_it, views_it);
462 const auto& info{stage_infos[0]}; 462 const auto& info{stage_infos[0]};
463 if (info.uses_render_area) { 463 if (info.uses_render_area) {
@@ -499,7 +499,7 @@ void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
499 const bool is_rescaling{texture_cache.IsRescaling()}; 499 const bool is_rescaling{texture_cache.IsRescaling()};
500 const bool update_rescaling{scheduler.UpdateRescaling(is_rescaling)}; 500 const bool update_rescaling{scheduler.UpdateRescaling(is_rescaling)};
501 const bool bind_pipeline{scheduler.UpdateGraphicsPipeline(this)}; 501 const bool bind_pipeline{scheduler.UpdateGraphicsPipeline(this)};
502 const void* const descriptor_data{update_descriptor_queue.UpdateData()}; 502 const void* const descriptor_data{guest_descriptor_queue.UpdateData()};
503 scheduler.Record([this, descriptor_data, bind_pipeline, rescaling_data = rescaling.Data(), 503 scheduler.Record([this, descriptor_data, bind_pipeline, rescaling_data = rescaling.Data(),
504 is_rescaling, update_rescaling, 504 is_rescaling, update_rescaling,
505 uses_render_area = render_area.uses_render_area, 505 uses_render_area = render_area.uses_render_area,
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
index 67c657d0e..99e56e9ad 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
@@ -64,7 +64,6 @@ class RenderPassCache;
64class RescalingPushConstant; 64class RescalingPushConstant;
65class RenderAreaPushConstant; 65class RenderAreaPushConstant;
66class Scheduler; 66class Scheduler;
67class UpdateDescriptorQueue;
68 67
69class GraphicsPipeline { 68class GraphicsPipeline {
70 static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; 69 static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
@@ -74,7 +73,7 @@ public:
74 Scheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache, 73 Scheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache,
75 vk::PipelineCache& pipeline_cache, VideoCore::ShaderNotify* shader_notify, 74 vk::PipelineCache& pipeline_cache, VideoCore::ShaderNotify* shader_notify,
76 const Device& device, DescriptorPool& descriptor_pool, 75 const Device& device, DescriptorPool& descriptor_pool,
77 UpdateDescriptorQueue& update_descriptor_queue, Common::ThreadWorker* worker_thread, 76 GuestDescriptorQueue& guest_descriptor_queue, Common::ThreadWorker* worker_thread,
78 PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache, 77 PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache,
79 const GraphicsPipelineCacheKey& key, std::array<vk::ShaderModule, NUM_STAGES> stages, 78 const GraphicsPipelineCacheKey& key, std::array<vk::ShaderModule, NUM_STAGES> stages,
80 const std::array<const Shader::Info*, NUM_STAGES>& infos); 79 const std::array<const Shader::Info*, NUM_STAGES>& infos);
@@ -133,7 +132,7 @@ private:
133 BufferCache& buffer_cache; 132 BufferCache& buffer_cache;
134 vk::PipelineCache& pipeline_cache; 133 vk::PipelineCache& pipeline_cache;
135 Scheduler& scheduler; 134 Scheduler& scheduler;
136 UpdateDescriptorQueue& update_descriptor_queue; 135 GuestDescriptorQueue& guest_descriptor_queue;
137 136
138 void (*configure_func)(GraphicsPipeline*, bool){}; 137 void (*configure_func)(GraphicsPipeline*, bool){};
139 138
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index a318d643e..66dfe5733 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -277,11 +277,11 @@ bool GraphicsPipelineCacheKey::operator==(const GraphicsPipelineCacheKey& rhs) c
277 277
278PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device_, 278PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device_,
279 Scheduler& scheduler_, DescriptorPool& descriptor_pool_, 279 Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
280 UpdateDescriptorQueue& update_descriptor_queue_, 280 GuestDescriptorQueue& guest_descriptor_queue_,
281 RenderPassCache& render_pass_cache_, BufferCache& buffer_cache_, 281 RenderPassCache& render_pass_cache_, BufferCache& buffer_cache_,
282 TextureCache& texture_cache_, VideoCore::ShaderNotify& shader_notify_) 282 TextureCache& texture_cache_, VideoCore::ShaderNotify& shader_notify_)
283 : VideoCommon::ShaderCache{rasterizer_}, device{device_}, scheduler{scheduler_}, 283 : VideoCommon::ShaderCache{rasterizer_}, device{device_}, scheduler{scheduler_},
284 descriptor_pool{descriptor_pool_}, update_descriptor_queue{update_descriptor_queue_}, 284 descriptor_pool{descriptor_pool_}, guest_descriptor_queue{guest_descriptor_queue_},
285 render_pass_cache{render_pass_cache_}, buffer_cache{buffer_cache_}, 285 render_pass_cache{render_pass_cache_}, buffer_cache{buffer_cache_},
286 texture_cache{texture_cache_}, shader_notify{shader_notify_}, 286 texture_cache{texture_cache_}, shader_notify{shader_notify_},
287 use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()}, 287 use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()},
@@ -643,7 +643,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
643 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; 643 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
644 return std::make_unique<GraphicsPipeline>( 644 return std::make_unique<GraphicsPipeline>(
645 scheduler, buffer_cache, texture_cache, vulkan_pipeline_cache, &shader_notify, device, 645 scheduler, buffer_cache, texture_cache, vulkan_pipeline_cache, &shader_notify, device,
646 descriptor_pool, update_descriptor_queue, thread_worker, statistics, render_pass_cache, key, 646 descriptor_pool, guest_descriptor_queue, thread_worker, statistics, render_pass_cache, key,
647 std::move(modules), infos); 647 std::move(modules), infos);
648 648
649} catch (const Shader::Exception& exception) { 649} catch (const Shader::Exception& exception) {
@@ -698,7 +698,8 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
698 PipelineStatistics* statistics, bool build_in_parallel) try { 698 PipelineStatistics* statistics, bool build_in_parallel) try {
699 // TODO: Remove this when Intel fixes their shader compiler. 699 // TODO: Remove this when Intel fixes their shader compiler.
700 // https://github.com/IGCIT/Intel-GPU-Community-Issue-Tracker-IGCIT/issues/159 700 // https://github.com/IGCIT/Intel-GPU-Community-Issue-Tracker-IGCIT/issues/159
701 if (device.GetDriverID() == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) { 701 if (device.GetDriverID() == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS &&
702 !Settings::values.enable_compute_pipelines.GetValue()) {
702 LOG_ERROR(Render_Vulkan, "Skipping 0x{:016x}", key.Hash()); 703 LOG_ERROR(Render_Vulkan, "Skipping 0x{:016x}", key.Hash());
703 return nullptr; 704 return nullptr;
704 } 705 }
@@ -722,7 +723,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
722 } 723 }
723 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; 724 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
724 return std::make_unique<ComputePipeline>(device, vulkan_pipeline_cache, descriptor_pool, 725 return std::make_unique<ComputePipeline>(device, vulkan_pipeline_cache, descriptor_pool,
725 update_descriptor_queue, thread_worker, statistics, 726 guest_descriptor_queue, thread_worker, statistics,
726 &shader_notify, program.info, std::move(spv_module)); 727 &shader_notify, program.info, std::move(spv_module));
727 728
728} catch (const Shader::Exception& exception) { 729} catch (const Shader::Exception& exception) {
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index 5171912d7..15aa7e224 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -82,7 +82,6 @@ class PipelineStatistics;
82class RasterizerVulkan; 82class RasterizerVulkan;
83class RenderPassCache; 83class RenderPassCache;
84class Scheduler; 84class Scheduler;
85class UpdateDescriptorQueue;
86 85
87using VideoCommon::ShaderInfo; 86using VideoCommon::ShaderInfo;
88 87
@@ -102,7 +101,7 @@ class PipelineCache : public VideoCommon::ShaderCache {
102public: 101public:
103 explicit PipelineCache(RasterizerVulkan& rasterizer, const Device& device, Scheduler& scheduler, 102 explicit PipelineCache(RasterizerVulkan& rasterizer, const Device& device, Scheduler& scheduler,
104 DescriptorPool& descriptor_pool, 103 DescriptorPool& descriptor_pool,
105 UpdateDescriptorQueue& update_descriptor_queue, 104 GuestDescriptorQueue& guest_descriptor_queue,
106 RenderPassCache& render_pass_cache, BufferCache& buffer_cache, 105 RenderPassCache& render_pass_cache, BufferCache& buffer_cache,
107 TextureCache& texture_cache, VideoCore::ShaderNotify& shader_notify_); 106 TextureCache& texture_cache, VideoCore::ShaderNotify& shader_notify_);
108 ~PipelineCache(); 107 ~PipelineCache();
@@ -144,7 +143,7 @@ private:
144 const Device& device; 143 const Device& device;
145 Scheduler& scheduler; 144 Scheduler& scheduler;
146 DescriptorPool& descriptor_pool; 145 DescriptorPool& descriptor_pool;
147 UpdateDescriptorQueue& update_descriptor_queue; 146 GuestDescriptorQueue& guest_descriptor_queue;
148 RenderPassCache& render_pass_cache; 147 RenderPassCache& render_pass_cache;
149 BufferCache& buffer_cache; 148 BufferCache& buffer_cache;
150 TextureCache& texture_cache; 149 TextureCache& texture_cache;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index cbf23552c..8d3a9736b 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -160,17 +160,16 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
160 : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, screen_info{screen_info_}, device{device_}, 160 : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, screen_info{screen_info_}, device{device_},
161 memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_}, 161 memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_},
162 staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), 162 staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler),
163 update_descriptor_queue(device, scheduler), 163 guest_descriptor_queue(device, scheduler), compute_pass_descriptor_queue(device, scheduler),
164 blit_image(device, scheduler, state_tracker, descriptor_pool), 164 blit_image(device, scheduler, state_tracker, descriptor_pool), render_pass_cache(device),
165 render_pass_cache(device), texture_cache_runtime{device, scheduler, 165 texture_cache_runtime{
166 memory_allocator, staging_pool, 166 device, scheduler, memory_allocator, staging_pool,
167 blit_image, render_pass_cache, 167 blit_image, render_pass_cache, descriptor_pool, compute_pass_descriptor_queue},
168 descriptor_pool, update_descriptor_queue},
169 texture_cache(texture_cache_runtime, *this), 168 texture_cache(texture_cache_runtime, *this),
170 buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool, 169 buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool,
171 update_descriptor_queue, descriptor_pool), 170 guest_descriptor_queue, compute_pass_descriptor_queue, descriptor_pool),
172 buffer_cache(*this, cpu_memory_, buffer_cache_runtime), 171 buffer_cache(*this, cpu_memory_, buffer_cache_runtime),
173 pipeline_cache(*this, device, scheduler, descriptor_pool, update_descriptor_queue, 172 pipeline_cache(*this, device, scheduler, descriptor_pool, guest_descriptor_queue,
174 render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()), 173 render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()),
175 query_cache{*this, cpu_memory_, device, scheduler}, 174 query_cache{*this, cpu_memory_, device, scheduler},
176 accelerate_dma(buffer_cache, texture_cache, scheduler), 175 accelerate_dma(buffer_cache, texture_cache, scheduler),
@@ -656,7 +655,8 @@ void RasterizerVulkan::FlushCommands() {
656 655
657void RasterizerVulkan::TickFrame() { 656void RasterizerVulkan::TickFrame() {
658 draw_counter = 0; 657 draw_counter = 0;
659 update_descriptor_queue.TickFrame(); 658 guest_descriptor_queue.TickFrame();
659 compute_pass_descriptor_queue.TickFrame();
660 fence_manager.TickFrame(); 660 fence_manager.TickFrame();
661 staging_pool.TickFrame(); 661 staging_pool.TickFrame();
662 { 662 {
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 9bd422850..b39710b3c 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -184,7 +184,8 @@ private:
184 184
185 StagingBufferPool staging_pool; 185 StagingBufferPool staging_pool;
186 DescriptorPool descriptor_pool; 186 DescriptorPool descriptor_pool;
187 UpdateDescriptorQueue update_descriptor_queue; 187 GuestDescriptorQueue guest_descriptor_queue;
188 ComputePassDescriptorQueue compute_pass_descriptor_queue;
188 BlitImageHelper blit_image; 189 BlitImageHelper blit_image;
189 RenderPassCache render_pass_cache; 190 RenderPassCache render_pass_cache;
190 191
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 9ca7751c5..4d0481f2a 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -798,13 +798,13 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
798 BlitImageHelper& blit_image_helper_, 798 BlitImageHelper& blit_image_helper_,
799 RenderPassCache& render_pass_cache_, 799 RenderPassCache& render_pass_cache_,
800 DescriptorPool& descriptor_pool, 800 DescriptorPool& descriptor_pool,
801 UpdateDescriptorQueue& update_descriptor_queue) 801 ComputePassDescriptorQueue& compute_pass_descriptor_queue)
802 : device{device_}, scheduler{scheduler_}, memory_allocator{memory_allocator_}, 802 : device{device_}, scheduler{scheduler_}, memory_allocator{memory_allocator_},
803 staging_buffer_pool{staging_buffer_pool_}, blit_image_helper{blit_image_helper_}, 803 staging_buffer_pool{staging_buffer_pool_}, blit_image_helper{blit_image_helper_},
804 render_pass_cache{render_pass_cache_}, resolution{Settings::values.resolution_info} { 804 render_pass_cache{render_pass_cache_}, resolution{Settings::values.resolution_info} {
805 if (Settings::values.accelerate_astc) { 805 if (Settings::values.accelerate_astc) {
806 astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool, 806 astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
807 update_descriptor_queue, memory_allocator); 807 compute_pass_descriptor_queue, memory_allocator);
808 } 808 }
809} 809}
810 810
@@ -1864,6 +1864,7 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
1864 num_layers = std::max(num_layers, color_buffer->range.extent.layers); 1864 num_layers = std::max(num_layers, color_buffer->range.extent.layers);
1865 images[num_images] = color_buffer->ImageHandle(); 1865 images[num_images] = color_buffer->ImageHandle();
1866 image_ranges[num_images] = MakeSubresourceRange(color_buffer); 1866 image_ranges[num_images] = MakeSubresourceRange(color_buffer);
1867 rt_map[index] = num_images;
1867 samples = color_buffer->Samples(); 1868 samples = color_buffer->Samples();
1868 ++num_images; 1869 ++num_images;
1869 } 1870 }
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 6f360177a..4166b3d20 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -34,7 +34,6 @@ class ImageView;
34class Framebuffer; 34class Framebuffer;
35class RenderPassCache; 35class RenderPassCache;
36class StagingBufferPool; 36class StagingBufferPool;
37class UpdateDescriptorQueue;
38class Scheduler; 37class Scheduler;
39 38
40class TextureCacheRuntime { 39class TextureCacheRuntime {
@@ -45,7 +44,7 @@ public:
45 BlitImageHelper& blit_image_helper_, 44 BlitImageHelper& blit_image_helper_,
46 RenderPassCache& render_pass_cache_, 45 RenderPassCache& render_pass_cache_,
47 DescriptorPool& descriptor_pool, 46 DescriptorPool& descriptor_pool,
48 UpdateDescriptorQueue& update_descriptor_queue); 47 ComputePassDescriptorQueue& compute_pass_descriptor_queue);
49 48
50 void Finish(); 49 void Finish();
51 50
@@ -335,7 +334,7 @@ public:
335 } 334 }
336 335
337 [[nodiscard]] bool HasAspectColorBit(size_t index) const noexcept { 336 [[nodiscard]] bool HasAspectColorBit(size_t index) const noexcept {
338 return (image_ranges.at(index).aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0; 337 return (image_ranges.at(rt_map[index]).aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0;
339 } 338 }
340 339
341 [[nodiscard]] bool HasAspectDepthBit() const noexcept { 340 [[nodiscard]] bool HasAspectDepthBit() const noexcept {
@@ -355,6 +354,7 @@ private:
355 u32 num_images = 0; 354 u32 num_images = 0;
356 std::array<VkImage, 9> images{}; 355 std::array<VkImage, 9> images{};
357 std::array<VkImageSubresourceRange, 9> image_ranges{}; 356 std::array<VkImageSubresourceRange, 9> image_ranges{};
357 std::array<size_t, NUM_RT> rt_map{};
358 bool has_depth{}; 358 bool has_depth{};
359 bool has_stencil{}; 359 bool has_stencil{};
360}; 360};
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h
index 1c1a7020b..310fb551a 100644
--- a/src/video_core/renderer_vulkan/vk_update_descriptor.h
+++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h
@@ -32,7 +32,7 @@ class UpdateDescriptorQueue final {
32 // This should be plenty for the vast majority of cases. Most desktop platforms only 32 // This should be plenty for the vast majority of cases. Most desktop platforms only
33 // provide up to 3 swapchain images. 33 // provide up to 3 swapchain images.
34 static constexpr size_t FRAMES_IN_FLIGHT = 5; 34 static constexpr size_t FRAMES_IN_FLIGHT = 5;
35 static constexpr size_t FRAME_PAYLOAD_SIZE = 0x10000; 35 static constexpr size_t FRAME_PAYLOAD_SIZE = 0x20000;
36 static constexpr size_t PAYLOAD_SIZE = FRAME_PAYLOAD_SIZE * FRAMES_IN_FLIGHT; 36 static constexpr size_t PAYLOAD_SIZE = FRAME_PAYLOAD_SIZE * FRAMES_IN_FLIGHT;
37 37
38public: 38public:
@@ -86,4 +86,8 @@ private:
86 std::array<DescriptorUpdateEntry, PAYLOAD_SIZE> payload; 86 std::array<DescriptorUpdateEntry, PAYLOAD_SIZE> payload;
87}; 87};
88 88
89// TODO: should these be separate classes instead?
90using GuestDescriptorQueue = UpdateDescriptorQueue;
91using ComputePassDescriptorQueue = UpdateDescriptorQueue;
92
89} // namespace Vulkan 93} // namespace Vulkan
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index e1198dcf8..b24086fce 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -1469,7 +1469,7 @@ std::optional<typename TextureCache<P>::BlitImages> TextureCache<P>::GetBlitImag
1469 if (!copy.must_accelerate) { 1469 if (!copy.must_accelerate) {
1470 do { 1470 do {
1471 if (!src_id && !dst_id) { 1471 if (!src_id && !dst_id) {
1472 return std::nullopt; 1472 break;
1473 } 1473 }
1474 if (src_id && True(slot_images[src_id].flags & ImageFlagBits::GpuModified)) { 1474 if (src_id && True(slot_images[src_id].flags & ImageFlagBits::GpuModified)) {
1475 break; 1475 break;
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 6ffca2af2..161f050b8 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -1009,6 +1009,8 @@ void Device::CollectPhysicalMemoryInfo() {
1009 device_access_memory += mem_properties.memoryHeaps[element].size; 1009 device_access_memory += mem_properties.memoryHeaps[element].size;
1010 } 1010 }
1011 if (!is_integrated) { 1011 if (!is_integrated) {
1012 const u64 reserve_memory = std::min<u64>(device_access_memory / 8, 1_GiB);
1013 device_access_memory -= reserve_memory;
1012 return; 1014 return;
1013 } 1015 }
1014 const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage); 1016 const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage);
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
index 1732866e0..e28a556f8 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
@@ -147,7 +147,7 @@ public:
147 147
148 /// Returns whether this allocation is compatible with the arguments. 148 /// Returns whether this allocation is compatible with the arguments.
149 [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { 149 [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const {
150 return (flags & property_flags) == property_flags && (type_mask & shifted_memory_type) != 0; 150 return (flags & property_flags) == flags && (type_mask & shifted_memory_type) != 0;
151 } 151 }
152 152
153private: 153private:
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index a49d12266..70737c54e 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -443,6 +443,7 @@ void Config::ReadControlValues() {
443 ReadBasicSetting(Settings::values.mouse_panning_sensitivity); 443 ReadBasicSetting(Settings::values.mouse_panning_sensitivity);
444 ReadBasicSetting(Settings::values.enable_joycon_driver); 444 ReadBasicSetting(Settings::values.enable_joycon_driver);
445 ReadBasicSetting(Settings::values.enable_procon_driver); 445 ReadBasicSetting(Settings::values.enable_procon_driver);
446 ReadBasicSetting(Settings::values.random_amiibo_id);
446 447
447 ReadBasicSetting(Settings::values.tas_enable); 448 ReadBasicSetting(Settings::values.tas_enable);
448 ReadBasicSetting(Settings::values.tas_loop); 449 ReadBasicSetting(Settings::values.tas_loop);
@@ -715,6 +716,7 @@ void Config::ReadRendererValues() {
715 ReadGlobalSetting(Settings::values.use_asynchronous_shaders); 716 ReadGlobalSetting(Settings::values.use_asynchronous_shaders);
716 ReadGlobalSetting(Settings::values.use_fast_gpu_time); 717 ReadGlobalSetting(Settings::values.use_fast_gpu_time);
717 ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); 718 ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache);
719 ReadGlobalSetting(Settings::values.enable_compute_pipelines);
718 ReadGlobalSetting(Settings::values.bg_red); 720 ReadGlobalSetting(Settings::values.bg_red);
719 ReadGlobalSetting(Settings::values.bg_green); 721 ReadGlobalSetting(Settings::values.bg_green);
720 ReadGlobalSetting(Settings::values.bg_blue); 722 ReadGlobalSetting(Settings::values.bg_blue);
@@ -1150,6 +1152,7 @@ void Config::SaveControlValues() {
1150 WriteBasicSetting(Settings::values.enable_raw_input); 1152 WriteBasicSetting(Settings::values.enable_raw_input);
1151 WriteBasicSetting(Settings::values.enable_joycon_driver); 1153 WriteBasicSetting(Settings::values.enable_joycon_driver);
1152 WriteBasicSetting(Settings::values.enable_procon_driver); 1154 WriteBasicSetting(Settings::values.enable_procon_driver);
1155 WriteBasicSetting(Settings::values.random_amiibo_id);
1153 WriteBasicSetting(Settings::values.keyboard_enabled); 1156 WriteBasicSetting(Settings::values.keyboard_enabled);
1154 WriteBasicSetting(Settings::values.emulate_analog_keyboard); 1157 WriteBasicSetting(Settings::values.emulate_analog_keyboard);
1155 WriteBasicSetting(Settings::values.mouse_panning_sensitivity); 1158 WriteBasicSetting(Settings::values.mouse_panning_sensitivity);
@@ -1364,6 +1367,7 @@ void Config::SaveRendererValues() {
1364 WriteGlobalSetting(Settings::values.use_asynchronous_shaders); 1367 WriteGlobalSetting(Settings::values.use_asynchronous_shaders);
1365 WriteGlobalSetting(Settings::values.use_fast_gpu_time); 1368 WriteGlobalSetting(Settings::values.use_fast_gpu_time);
1366 WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); 1369 WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache);
1370 WriteGlobalSetting(Settings::values.enable_compute_pipelines);
1367 WriteGlobalSetting(Settings::values.bg_red); 1371 WriteGlobalSetting(Settings::values.bg_red);
1368 WriteGlobalSetting(Settings::values.bg_green); 1372 WriteGlobalSetting(Settings::values.bg_green);
1369 WriteGlobalSetting(Settings::values.bg_blue); 1373 WriteGlobalSetting(Settings::values.bg_blue);
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index 2aaefcc05..8e76a819a 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -36,8 +36,9 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
36 debug_tab_tab{std::make_unique<ConfigureDebugTab>(system_, this)}, 36 debug_tab_tab{std::make_unique<ConfigureDebugTab>(system_, this)},
37 filesystem_tab{std::make_unique<ConfigureFilesystem>(this)}, 37 filesystem_tab{std::make_unique<ConfigureFilesystem>(this)},
38 general_tab{std::make_unique<ConfigureGeneral>(system_, this)}, 38 general_tab{std::make_unique<ConfigureGeneral>(system_, this)},
39 graphics_tab{std::make_unique<ConfigureGraphics>(system_, this)},
40 graphics_advanced_tab{std::make_unique<ConfigureGraphicsAdvanced>(system_, this)}, 39 graphics_advanced_tab{std::make_unique<ConfigureGraphicsAdvanced>(system_, this)},
40 graphics_tab{std::make_unique<ConfigureGraphics>(
41 system_, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, this)},
41 hotkeys_tab{std::make_unique<ConfigureHotkeys>(system_.HIDCore(), this)}, 42 hotkeys_tab{std::make_unique<ConfigureHotkeys>(system_.HIDCore(), this)},
42 input_tab{std::make_unique<ConfigureInput>(system_, this)}, 43 input_tab{std::make_unique<ConfigureInput>(system_, this)},
43 network_tab{std::make_unique<ConfigureNetwork>(system_, this)}, 44 network_tab{std::make_unique<ConfigureNetwork>(system_, this)},
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index 1f724834a..a086a07c4 100644
--- a/src/yuzu/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
@@ -72,8 +72,8 @@ private:
72 std::unique_ptr<ConfigureDebugTab> debug_tab_tab; 72 std::unique_ptr<ConfigureDebugTab> debug_tab_tab;
73 std::unique_ptr<ConfigureFilesystem> filesystem_tab; 73 std::unique_ptr<ConfigureFilesystem> filesystem_tab;
74 std::unique_ptr<ConfigureGeneral> general_tab; 74 std::unique_ptr<ConfigureGeneral> general_tab;
75 std::unique_ptr<ConfigureGraphics> graphics_tab;
76 std::unique_ptr<ConfigureGraphicsAdvanced> graphics_advanced_tab; 75 std::unique_ptr<ConfigureGraphicsAdvanced> graphics_advanced_tab;
76 std::unique_ptr<ConfigureGraphics> graphics_tab;
77 std::unique_ptr<ConfigureHotkeys> hotkeys_tab; 77 std::unique_ptr<ConfigureHotkeys> hotkeys_tab;
78 std::unique_ptr<ConfigureInput> input_tab; 78 std::unique_ptr<ConfigureInput> input_tab;
79 std::unique_ptr<ConfigureNetwork> network_tab; 79 std::unique_ptr<ConfigureNetwork> network_tab;
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index 76e5b7499..f316b598c 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -2,9 +2,11 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4// Include this early to include Vulkan headers how we want to 4// Include this early to include Vulkan headers how we want to
5#include "video_core/vulkan_common/vulkan_device.h"
5#include "video_core/vulkan_common/vulkan_wrapper.h" 6#include "video_core/vulkan_common/vulkan_wrapper.h"
6 7
7#include <algorithm> 8#include <algorithm>
9#include <functional>
8#include <iosfwd> 10#include <iosfwd>
9#include <iterator> 11#include <iterator>
10#include <string> 12#include <string>
@@ -74,8 +76,11 @@ static constexpr Settings::VSyncMode PresentModeToSetting(VkPresentModeKHR mode)
74 } 76 }
75} 77}
76 78
77ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* parent) 79ConfigureGraphics::ConfigureGraphics(const Core::System& system_,
78 : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, system{system_} { 80 const std::function<void()>& expose_compute_option_,
81 QWidget* parent)
82 : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()},
83 expose_compute_option{expose_compute_option_}, system{system_} {
79 vulkan_device = Settings::values.vulkan_device.GetValue(); 84 vulkan_device = Settings::values.vulkan_device.GetValue();
80 RetrieveVulkanDevices(); 85 RetrieveVulkanDevices();
81 86
@@ -513,8 +518,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {
513 const Common::DynamicLibrary library = OpenLibrary(); 518 const Common::DynamicLibrary library = OpenLibrary();
514 const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1, wsi.type); 519 const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1, wsi.type);
515 const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices(); 520 const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
516 vk::SurfaceKHR surface = //< needed to view present modes for a device 521 vk::SurfaceKHR surface = CreateSurface(instance, wsi);
517 CreateSurface(instance, wsi);
518 522
519 vulkan_devices.clear(); 523 vulkan_devices.clear();
520 vulkan_devices.reserve(physical_devices.size()); 524 vulkan_devices.reserve(physical_devices.size());
@@ -527,6 +531,17 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {
527 physical_device.GetSurfacePresentModesKHR(*surface); 531 physical_device.GetSurfacePresentModesKHR(*surface);
528 vulkan_devices.push_back(QString::fromStdString(name)); 532 vulkan_devices.push_back(QString::fromStdString(name));
529 device_present_modes.push_back(present_modes); 533 device_present_modes.push_back(present_modes);
534
535 VkPhysicalDeviceDriverProperties driver_properties{};
536 driver_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
537 driver_properties.pNext = nullptr;
538 VkPhysicalDeviceProperties2 properties{};
539 properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
540 properties.pNext = &driver_properties;
541 dld.vkGetPhysicalDeviceProperties2(physical_device, &properties);
542 if (driver_properties.driverID == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) {
543 expose_compute_option();
544 }
530 } 545 }
531} catch (const Vulkan::vk::Exception& exception) { 546} catch (const Vulkan::vk::Exception& exception) {
532 LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what()); 547 LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what());
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 901f604a5..364b1cac2 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <functional>
6#include <memory> 7#include <memory>
7#include <vector> 8#include <vector>
8#include <QColor> 9#include <QColor>
@@ -37,7 +38,9 @@ class ConfigureGraphics : public QWidget {
37 Q_OBJECT 38 Q_OBJECT
38 39
39public: 40public:
40 explicit ConfigureGraphics(const Core::System& system_, QWidget* parent = nullptr); 41 explicit ConfigureGraphics(const Core::System& system_,
42 const std::function<void()>& expose_compute_option_,
43 QWidget* parent = nullptr);
41 ~ConfigureGraphics() override; 44 ~ConfigureGraphics() override;
42 45
43 void ApplyConfiguration(); 46 void ApplyConfiguration();
@@ -81,6 +84,7 @@ private:
81 // selection in the combobox 84 // selection in the combobox
82 u32 vulkan_device{}; 85 u32 vulkan_device{};
83 Settings::ShaderBackend shader_backend{}; 86 Settings::ShaderBackend shader_backend{};
87 const std::function<void()>& expose_compute_option;
84 88
85 const Core::System& system; 89 const Core::System& system;
86}; 90};
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index 627ed8b17..1f3e489d0 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -15,6 +15,8 @@ ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(const Core::System& system_
15 SetupPerGameUI(); 15 SetupPerGameUI();
16 16
17 SetConfiguration(); 17 SetConfiguration();
18
19 ui->enable_compute_pipelines_checkbox->setVisible(false);
18} 20}
19 21
20ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default; 22ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default;
@@ -27,6 +29,7 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
27 ui->async_astc->setEnabled(runtime_lock); 29 ui->async_astc->setEnabled(runtime_lock);
28 ui->use_asynchronous_shaders->setEnabled(runtime_lock); 30 ui->use_asynchronous_shaders->setEnabled(runtime_lock);
29 ui->anisotropic_filtering_combobox->setEnabled(runtime_lock); 31 ui->anisotropic_filtering_combobox->setEnabled(runtime_lock);
32 ui->enable_compute_pipelines_checkbox->setEnabled(runtime_lock);
30 33
31 ui->async_present->setChecked(Settings::values.async_presentation.GetValue()); 34 ui->async_present->setChecked(Settings::values.async_presentation.GetValue());
32 ui->renderer_force_max_clock->setChecked(Settings::values.renderer_force_max_clock.GetValue()); 35 ui->renderer_force_max_clock->setChecked(Settings::values.renderer_force_max_clock.GetValue());
@@ -36,6 +39,8 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
36 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); 39 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
37 ui->use_vulkan_driver_pipeline_cache->setChecked( 40 ui->use_vulkan_driver_pipeline_cache->setChecked(
38 Settings::values.use_vulkan_driver_pipeline_cache.GetValue()); 41 Settings::values.use_vulkan_driver_pipeline_cache.GetValue());
42 ui->enable_compute_pipelines_checkbox->setChecked(
43 Settings::values.enable_compute_pipelines.GetValue());
39 44
40 if (Settings::IsConfiguringGlobal()) { 45 if (Settings::IsConfiguringGlobal()) {
41 ui->gpu_accuracy->setCurrentIndex( 46 ui->gpu_accuracy->setCurrentIndex(
@@ -74,6 +79,9 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
74 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vulkan_driver_pipeline_cache, 79 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vulkan_driver_pipeline_cache,
75 ui->use_vulkan_driver_pipeline_cache, 80 ui->use_vulkan_driver_pipeline_cache,
76 use_vulkan_driver_pipeline_cache); 81 use_vulkan_driver_pipeline_cache);
82 ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_compute_pipelines,
83 ui->enable_compute_pipelines_checkbox,
84 enable_compute_pipelines);
77} 85}
78 86
79void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { 87void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) {
@@ -104,6 +112,8 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
104 Settings::values.use_vulkan_driver_pipeline_cache.UsingGlobal()); 112 Settings::values.use_vulkan_driver_pipeline_cache.UsingGlobal());
105 ui->anisotropic_filtering_combobox->setEnabled( 113 ui->anisotropic_filtering_combobox->setEnabled(
106 Settings::values.max_anisotropy.UsingGlobal()); 114 Settings::values.max_anisotropy.UsingGlobal());
115 ui->enable_compute_pipelines_checkbox->setEnabled(
116 Settings::values.enable_compute_pipelines.UsingGlobal());
107 117
108 return; 118 return;
109 } 119 }
@@ -125,6 +135,9 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
125 ConfigurationShared::SetColoredTristate(ui->use_vulkan_driver_pipeline_cache, 135 ConfigurationShared::SetColoredTristate(ui->use_vulkan_driver_pipeline_cache,
126 Settings::values.use_vulkan_driver_pipeline_cache, 136 Settings::values.use_vulkan_driver_pipeline_cache,
127 use_vulkan_driver_pipeline_cache); 137 use_vulkan_driver_pipeline_cache);
138 ConfigurationShared::SetColoredTristate(ui->enable_compute_pipelines_checkbox,
139 Settings::values.enable_compute_pipelines,
140 enable_compute_pipelines);
128 ConfigurationShared::SetColoredComboBox( 141 ConfigurationShared::SetColoredComboBox(
129 ui->gpu_accuracy, ui->label_gpu_accuracy, 142 ui->gpu_accuracy, ui->label_gpu_accuracy,
130 static_cast<int>(Settings::values.gpu_accuracy.GetValue(true))); 143 static_cast<int>(Settings::values.gpu_accuracy.GetValue(true)));
@@ -132,3 +145,7 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
132 ui->anisotropic_filtering_combobox, ui->af_label, 145 ui->anisotropic_filtering_combobox, ui->af_label,
133 static_cast<int>(Settings::values.max_anisotropy.GetValue(true))); 146 static_cast<int>(Settings::values.max_anisotropy.GetValue(true)));
134} 147}
148
149void ConfigureGraphicsAdvanced::ExposeComputeOption() {
150 ui->enable_compute_pipelines_checkbox->setVisible(true);
151}
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h
index ae3c10946..1c7b636b9 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.h
+++ b/src/yuzu/configuration/configure_graphics_advanced.h
@@ -28,6 +28,8 @@ public:
28 void ApplyConfiguration(); 28 void ApplyConfiguration();
29 void SetConfiguration(); 29 void SetConfiguration();
30 30
31 void ExposeComputeOption();
32
31private: 33private:
32 void changeEvent(QEvent* event) override; 34 void changeEvent(QEvent* event) override;
33 void RetranslateUI(); 35 void RetranslateUI();
@@ -44,6 +46,7 @@ private:
44 ConfigurationShared::CheckState use_asynchronous_shaders; 46 ConfigurationShared::CheckState use_asynchronous_shaders;
45 ConfigurationShared::CheckState use_fast_gpu_time; 47 ConfigurationShared::CheckState use_fast_gpu_time;
46 ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache; 48 ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache;
49 ConfigurationShared::CheckState enable_compute_pipelines;
47 50
48 const Core::System& system; 51 const Core::System& system;
49}; 52};
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index 9d8cbea09..9ef7c8e8f 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -137,6 +137,17 @@
137 </widget> 137 </widget>
138 </item> 138 </item>
139 <item> 139 <item>
140 <widget class="QCheckBox" name="enable_compute_pipelines_checkbox">
141 <property name="toolTip">
142 <string>Enable compute pipelines, required by some games. This setting only exists for Intel proprietary drivers, and may crash if enabled.
143Compute pipelines are always enabled on all other drivers.</string>
144 </property>
145 <property name="text">
146 <string>Enable Compute Pipelines (Intel Vulkan only)</string>
147 </property>
148 </widget>
149 </item>
150 <item>
140 <widget class="QWidget" name="af_layout" native="true"> 151 <widget class="QWidget" name="af_layout" native="true">
141 <layout class="QHBoxLayout" name="horizontalLayout_1"> 152 <layout class="QHBoxLayout" name="horizontalLayout_1">
142 <property name="leftMargin"> 153 <property name="leftMargin">
diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp
index daa77a8f8..0b2a965f8 100644
--- a/src/yuzu/configuration/configure_hotkeys.cpp
+++ b/src/yuzu/configuration/configure_hotkeys.cpp
@@ -48,7 +48,9 @@ ConfigureHotkeys::ConfigureHotkeys(Core::HID::HIDCore& hid_core, QWidget* parent
48 48
49 connect(poll_timer.get(), &QTimer::timeout, [this] { 49 connect(poll_timer.get(), &QTimer::timeout, [this] {
50 const auto buttons = controller->GetNpadButtons(); 50 const auto buttons = controller->GetNpadButtons();
51 if (buttons.raw != Core::HID::NpadButton::None) { 51 const auto home_pressed = controller->GetHomeButtons().home != 0;
52 const auto capture_pressed = controller->GetCaptureButtons().capture != 0;
53 if (home_pressed || capture_pressed) {
52 SetPollingResult(buttons.raw, false); 54 SetPollingResult(buttons.raw, false);
53 return; 55 return;
54 } 56 }
@@ -154,8 +156,10 @@ void ConfigureHotkeys::ConfigureController(QModelIndex index) {
154 model->setData(index, previous_key); 156 model->setData(index, previous_key);
155 return; 157 return;
156 } 158 }
157 159 const auto home_pressed = this->controller->GetHomeButtons().home != 0;
158 const QString button_string = tr("Home+%1").arg(GetButtonName(button)); 160 const auto capture_pressed = this->controller->GetCaptureButtons().capture != 0;
161 const QString button_string =
162 GetButtonCombinationName(button, home_pressed, capture_pressed);
159 163
160 const auto [key_sequence_used, used_action] = IsUsedControllerKey(button_string); 164 const auto [key_sequence_used, used_action] = IsUsedControllerKey(button_string);
161 165
@@ -174,72 +178,83 @@ void ConfigureHotkeys::ConfigureController(QModelIndex index) {
174 poll_timer->start(200); // Check for new inputs every 200ms 178 poll_timer->start(200); // Check for new inputs every 200ms
175 // We need to disable configuration to be able to read npad buttons 179 // We need to disable configuration to be able to read npad buttons
176 controller->DisableConfiguration(); 180 controller->DisableConfiguration();
177 controller->DisableSystemButtons();
178} 181}
179 182
180void ConfigureHotkeys::SetPollingResult(Core::HID::NpadButton button, const bool cancel) { 183void ConfigureHotkeys::SetPollingResult(Core::HID::NpadButton button, const bool cancel) {
181 timeout_timer->stop(); 184 timeout_timer->stop();
182 poll_timer->stop(); 185 poll_timer->stop();
186 (*input_setter)(button, cancel);
183 // Re-Enable configuration 187 // Re-Enable configuration
184 controller->EnableConfiguration(); 188 controller->EnableConfiguration();
185 controller->EnableSystemButtons();
186
187 (*input_setter)(button, cancel);
188 189
189 input_setter = std::nullopt; 190 input_setter = std::nullopt;
190} 191}
191 192
192QString ConfigureHotkeys::GetButtonName(Core::HID::NpadButton button) const { 193QString ConfigureHotkeys::GetButtonCombinationName(Core::HID::NpadButton button,
194 const bool home = false,
195 const bool capture = false) const {
193 Core::HID::NpadButtonState state{button}; 196 Core::HID::NpadButtonState state{button};
197 QString button_combination;
198 if (home) {
199 button_combination.append(QStringLiteral("Home+"));
200 }
201 if (capture) {
202 button_combination.append(QStringLiteral("Screenshot+"));
203 }
194 if (state.a) { 204 if (state.a) {
195 return QStringLiteral("A"); 205 button_combination.append(QStringLiteral("A+"));
196 } 206 }
197 if (state.b) { 207 if (state.b) {
198 return QStringLiteral("B"); 208 button_combination.append(QStringLiteral("B+"));
199 } 209 }
200 if (state.x) { 210 if (state.x) {
201 return QStringLiteral("X"); 211 button_combination.append(QStringLiteral("X+"));
202 } 212 }
203 if (state.y) { 213 if (state.y) {
204 return QStringLiteral("Y"); 214 button_combination.append(QStringLiteral("Y+"));
205 } 215 }
206 if (state.l || state.right_sl || state.left_sl) { 216 if (state.l || state.right_sl || state.left_sl) {
207 return QStringLiteral("L"); 217 button_combination.append(QStringLiteral("L+"));
208 } 218 }
209 if (state.r || state.right_sr || state.left_sr) { 219 if (state.r || state.right_sr || state.left_sr) {
210 return QStringLiteral("R"); 220 button_combination.append(QStringLiteral("R+"));
211 } 221 }
212 if (state.zl) { 222 if (state.zl) {
213 return QStringLiteral("ZL"); 223 button_combination.append(QStringLiteral("ZL+"));
214 } 224 }
215 if (state.zr) { 225 if (state.zr) {
216 return QStringLiteral("ZR"); 226 button_combination.append(QStringLiteral("ZR+"));
217 } 227 }
218 if (state.left) { 228 if (state.left) {
219 return QStringLiteral("Dpad_Left"); 229 button_combination.append(QStringLiteral("Dpad_Left+"));
220 } 230 }
221 if (state.right) { 231 if (state.right) {
222 return QStringLiteral("Dpad_Right"); 232 button_combination.append(QStringLiteral("Dpad_Right+"));
223 } 233 }
224 if (state.up) { 234 if (state.up) {
225 return QStringLiteral("Dpad_Up"); 235 button_combination.append(QStringLiteral("Dpad_Up+"));
226 } 236 }
227 if (state.down) { 237 if (state.down) {
228 return QStringLiteral("Dpad_Down"); 238 button_combination.append(QStringLiteral("Dpad_Down+"));
229 } 239 }
230 if (state.stick_l) { 240 if (state.stick_l) {
231 return QStringLiteral("Left_Stick"); 241 button_combination.append(QStringLiteral("Left_Stick+"));
232 } 242 }
233 if (state.stick_r) { 243 if (state.stick_r) {
234 return QStringLiteral("Right_Stick"); 244 button_combination.append(QStringLiteral("Right_Stick+"));
235 } 245 }
236 if (state.minus) { 246 if (state.minus) {
237 return QStringLiteral("Minus"); 247 button_combination.append(QStringLiteral("Minus+"));
238 } 248 }
239 if (state.plus) { 249 if (state.plus) {
240 return QStringLiteral("Plus"); 250 button_combination.append(QStringLiteral("Plus+"));
251 }
252 if (button_combination.isEmpty()) {
253 return tr("Invalid");
254 } else {
255 button_combination.chop(1);
256 return button_combination;
241 } 257 }
242 return tr("Invalid");
243} 258}
244 259
245std::pair<bool, QString> ConfigureHotkeys::IsUsedKey(QKeySequence key_sequence) const { 260std::pair<bool, QString> ConfigureHotkeys::IsUsedKey(QKeySequence key_sequence) const {
diff --git a/src/yuzu/configuration/configure_hotkeys.h b/src/yuzu/configuration/configure_hotkeys.h
index e8e414320..5fd1bcbfe 100644
--- a/src/yuzu/configuration/configure_hotkeys.h
+++ b/src/yuzu/configuration/configure_hotkeys.h
@@ -59,7 +59,7 @@ private:
59 QStandardItemModel* model; 59 QStandardItemModel* model;
60 60
61 void SetPollingResult(Core::HID::NpadButton button, bool cancel); 61 void SetPollingResult(Core::HID::NpadButton button, bool cancel);
62 QString GetButtonName(Core::HID::NpadButton button) const; 62 QString GetButtonCombinationName(Core::HID::NpadButton button, bool home, bool capture) const;
63 Core::HID::EmulatedController* controller; 63 Core::HID::EmulatedController* controller;
64 std::unique_ptr<QTimer> timeout_timer; 64 std::unique_ptr<QTimer> timeout_timer;
65 std::unique_ptr<QTimer> poll_timer; 65 std::unique_ptr<QTimer> poll_timer;
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index 8d81322f3..f13156434 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -140,6 +140,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() {
140 Settings::values.enable_ir_sensor = ui->enable_ir_sensor->isChecked(); 140 Settings::values.enable_ir_sensor = ui->enable_ir_sensor->isChecked();
141 Settings::values.enable_joycon_driver = ui->enable_joycon_driver->isChecked(); 141 Settings::values.enable_joycon_driver = ui->enable_joycon_driver->isChecked();
142 Settings::values.enable_procon_driver = ui->enable_procon_driver->isChecked(); 142 Settings::values.enable_procon_driver = ui->enable_procon_driver->isChecked();
143 Settings::values.random_amiibo_id = ui->random_amiibo_id->isChecked();
143} 144}
144 145
145void ConfigureInputAdvanced::LoadConfiguration() { 146void ConfigureInputAdvanced::LoadConfiguration() {
@@ -176,6 +177,7 @@ void ConfigureInputAdvanced::LoadConfiguration() {
176 ui->enable_ir_sensor->setChecked(Settings::values.enable_ir_sensor.GetValue()); 177 ui->enable_ir_sensor->setChecked(Settings::values.enable_ir_sensor.GetValue());
177 ui->enable_joycon_driver->setChecked(Settings::values.enable_joycon_driver.GetValue()); 178 ui->enable_joycon_driver->setChecked(Settings::values.enable_joycon_driver.GetValue());
178 ui->enable_procon_driver->setChecked(Settings::values.enable_procon_driver.GetValue()); 179 ui->enable_procon_driver->setChecked(Settings::values.enable_procon_driver.GetValue());
180 ui->random_amiibo_id->setChecked(Settings::values.random_amiibo_id.GetValue());
179 181
180 UpdateUIEnabled(); 182 UpdateUIEnabled();
181} 183}
diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui
index 0eb2b34bc..2e8b13660 100644
--- a/src/yuzu/configuration/configure_input_advanced.ui
+++ b/src/yuzu/configuration/configure_input_advanced.ui
@@ -2728,6 +2728,22 @@
2728 </widget> 2728 </widget>
2729 </item> 2729 </item>
2730 <item row="7" column="0"> 2730 <item row="7" column="0">
2731 <widget class="QCheckBox" name="random_amiibo_id">
2732 <property name="toolTip">
2733 <string>Allows unlimited uses of the same Amiibo in games that would otherwise limit you to one use.</string>
2734 </property>
2735 <property name="minimumSize">
2736 <size>
2737 <width>0</width>
2738 <height>23</height>
2739 </size>
2740 </property>
2741 <property name="text">
2742 <string>Use random Amiibo ID</string>
2743 </property>
2744 </widget>
2745 </item>
2746 <item row="8" column="0">
2731 <widget class="QCheckBox" name="mouse_panning"> 2747 <widget class="QCheckBox" name="mouse_panning">
2732 <property name="minimumSize"> 2748 <property name="minimumSize">
2733 <size> 2749 <size>
@@ -2740,7 +2756,7 @@
2740 </property> 2756 </property>
2741 </widget> 2757 </widget>
2742 </item> 2758 </item>
2743 <item row="7" column="2"> 2759 <item row="8" column="2">
2744 <widget class="QSpinBox" name="mouse_panning_sensitivity"> 2760 <widget class="QSpinBox" name="mouse_panning_sensitivity">
2745 <property name="toolTip"> 2761 <property name="toolTip">
2746 <string>Mouse sensitivity</string> 2762 <string>Mouse sensitivity</string>
@@ -2762,14 +2778,14 @@
2762 </property> 2778 </property>
2763 </widget> 2779 </widget>
2764 </item> 2780 </item>
2765 <item row="8" column="0"> 2781 <item row="9" column="0">
2766 <widget class="QLabel" name="motion_touch"> 2782 <widget class="QLabel" name="motion_touch">
2767 <property name="text"> 2783 <property name="text">
2768 <string>Motion / Touch</string> 2784 <string>Motion / Touch</string>
2769 </property> 2785 </property>
2770 </widget> 2786 </widget>
2771 </item> 2787 </item>
2772 <item row="8" column="2"> 2788 <item row="9" column="2">
2773 <widget class="QPushButton" name="buttonMotionTouch"> 2789 <widget class="QPushButton" name="buttonMotionTouch">
2774 <property name="text"> 2790 <property name="text">
2775 <string>Configure</string> 2791 <string>Configure</string>
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
index 7e757eafd..7ac162586 100644
--- a/src/yuzu/configuration/configure_per_game.cpp
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -48,8 +48,9 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
48 audio_tab = std::make_unique<ConfigureAudio>(system_, this); 48 audio_tab = std::make_unique<ConfigureAudio>(system_, this);
49 cpu_tab = std::make_unique<ConfigureCpu>(system_, this); 49 cpu_tab = std::make_unique<ConfigureCpu>(system_, this);
50 general_tab = std::make_unique<ConfigureGeneral>(system_, this); 50 general_tab = std::make_unique<ConfigureGeneral>(system_, this);
51 graphics_tab = std::make_unique<ConfigureGraphics>(system_, this);
52 graphics_advanced_tab = std::make_unique<ConfigureGraphicsAdvanced>(system_, this); 51 graphics_advanced_tab = std::make_unique<ConfigureGraphicsAdvanced>(system_, this);
52 graphics_tab = std::make_unique<ConfigureGraphics>(
53 system_, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, this);
53 input_tab = std::make_unique<ConfigureInputPerGame>(system_, game_config.get(), this); 54 input_tab = std::make_unique<ConfigureInputPerGame>(system_, game_config.get(), this);
54 system_tab = std::make_unique<ConfigureSystem>(system_, this); 55 system_tab = std::make_unique<ConfigureSystem>(system_, this);
55 56
diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h
index 4ecc43541..85752f1fa 100644
--- a/src/yuzu/configuration/configure_per_game.h
+++ b/src/yuzu/configuration/configure_per_game.h
@@ -75,8 +75,8 @@ private:
75 std::unique_ptr<ConfigureAudio> audio_tab; 75 std::unique_ptr<ConfigureAudio> audio_tab;
76 std::unique_ptr<ConfigureCpu> cpu_tab; 76 std::unique_ptr<ConfigureCpu> cpu_tab;
77 std::unique_ptr<ConfigureGeneral> general_tab; 77 std::unique_ptr<ConfigureGeneral> general_tab;
78 std::unique_ptr<ConfigureGraphics> graphics_tab;
79 std::unique_ptr<ConfigureGraphicsAdvanced> graphics_advanced_tab; 78 std::unique_ptr<ConfigureGraphicsAdvanced> graphics_advanced_tab;
79 std::unique_ptr<ConfigureGraphics> graphics_tab;
80 std::unique_ptr<ConfigureInputPerGame> input_tab; 80 std::unique_ptr<ConfigureInputPerGame> input_tab;
81 std::unique_ptr<ConfigureSystem> system_tab; 81 std::unique_ptr<ConfigureSystem> system_tab;
82}; 82};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index d932e33a7..4489f43af 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1164,7 +1164,8 @@ void GMainWindow::InitializeRecentFileMenuActions() {
1164 UpdateRecentFiles(); 1164 UpdateRecentFiles();
1165} 1165}
1166 1166
1167void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name) { 1167void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name,
1168 const bool tas_allowed) {
1168 static const QString main_window = QStringLiteral("Main Window"); 1169 static const QString main_window = QStringLiteral("Main Window");
1169 action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name)); 1170 action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name));
1170 action->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, action_name)); 1171 action->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, action_name));
@@ -1176,7 +1177,14 @@ void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name
1176 const auto* controller_hotkey = 1177 const auto* controller_hotkey =
1177 hotkey_registry.GetControllerHotkey(main_window, action_name, controller); 1178 hotkey_registry.GetControllerHotkey(main_window, action_name, controller);
1178 connect( 1179 connect(
1179 controller_hotkey, &ControllerShortcut::Activated, this, [action] { action->trigger(); }, 1180 controller_hotkey, &ControllerShortcut::Activated, this,
1181 [action, tas_allowed, this] {
1182 auto [tas_status, current_tas_frame, total_tas_frames] =
1183 input_subsystem->GetTas()->GetStatus();
1184 if (tas_allowed || tas_status == InputCommon::TasInput::TasState::Stopped) {
1185 action->trigger();
1186 }
1187 },
1180 Qt::QueuedConnection); 1188 Qt::QueuedConnection);
1181} 1189}
1182 1190
@@ -1193,9 +1201,9 @@ void GMainWindow::InitializeHotkeys() {
1193 LinkActionShortcut(ui->action_Show_Status_Bar, QStringLiteral("Toggle Status Bar")); 1201 LinkActionShortcut(ui->action_Show_Status_Bar, QStringLiteral("Toggle Status Bar"));
1194 LinkActionShortcut(ui->action_Fullscreen, QStringLiteral("Fullscreen")); 1202 LinkActionShortcut(ui->action_Fullscreen, QStringLiteral("Fullscreen"));
1195 LinkActionShortcut(ui->action_Capture_Screenshot, QStringLiteral("Capture Screenshot")); 1203 LinkActionShortcut(ui->action_Capture_Screenshot, QStringLiteral("Capture Screenshot"));
1196 LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop")); 1204 LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop"), true);
1197 LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record")); 1205 LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record"), true);
1198 LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset")); 1206 LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset"), true);
1199 1207
1200 static const QString main_window = QStringLiteral("Main Window"); 1208 static const QString main_window = QStringLiteral("Main Window");
1201 const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) { 1209 const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) {
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 7b23f2a59..17631a2d9 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -214,7 +214,8 @@ public slots:
214 214
215private: 215private:
216 /// Updates an action's shortcut and text to reflect an updated hotkey from the hotkey registry. 216 /// Updates an action's shortcut and text to reflect an updated hotkey from the hotkey registry.
217 void LinkActionShortcut(QAction* action, const QString& action_name); 217 void LinkActionShortcut(QAction* action, const QString& action_name,
218 const bool tas_allowed = false);
218 219
219 void RegisterMetaTypes(); 220 void RegisterMetaTypes();
220 221
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index abe7092fc..dc9a3d68f 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -169,6 +169,7 @@ void Config::ReadValues() {
169 ReadSetting("ControlsGeneral", Settings::values.enable_raw_input); 169 ReadSetting("ControlsGeneral", Settings::values.enable_raw_input);
170 ReadSetting("ControlsGeneral", Settings::values.enable_joycon_driver); 170 ReadSetting("ControlsGeneral", Settings::values.enable_joycon_driver);
171 ReadSetting("ControlsGeneral", Settings::values.enable_procon_driver); 171 ReadSetting("ControlsGeneral", Settings::values.enable_procon_driver);
172 ReadSetting("ControlsGeneral", Settings::values.random_amiibo_id);
172 ReadSetting("ControlsGeneral", Settings::values.emulate_analog_keyboard); 173 ReadSetting("ControlsGeneral", Settings::values.emulate_analog_keyboard);
173 ReadSetting("ControlsGeneral", Settings::values.vibration_enabled); 174 ReadSetting("ControlsGeneral", Settings::values.vibration_enabled);
174 ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations); 175 ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations);