summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_renderer.cpp10
-rw-r--r--src/audio_core/stream.cpp5
-rw-r--r--src/common/common_funcs.h10
-rw-r--r--src/core/core_timing.cpp85
-rw-r--r--src/core/core_timing.h25
-rw-r--r--src/core/hardware_interrupt_manager.cpp5
-rw-r--r--src/core/hle/kernel/k_code_memory.h6
-rw-r--r--src/core/hle/kernel/k_thread.cpp12
-rw-r--r--src/core/hle/kernel/kernel.cpp9
-rw-r--r--src/core/hle/kernel/time_manager.cpp20
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp4
-rw-r--r--src/core/hle/service/hid/hid.cpp41
-rw-r--r--src/core/hle/service/hid/hidbus.cpp16
-rw-r--r--src/core/hle/service/nvflinger/binder.h1
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp13
-rw-r--r--src/core/memory/cheat_engine.cpp8
-rw-r--r--src/core/tools/freezer.cpp4
-rw-r--r--src/input_common/drivers/sdl_driver.cpp10
-rw-r--r--src/input_common/drivers/sdl_driver.h1
-rw-r--r--src/tests/core/core_timing.cpp5
-rw-r--r--src/video_core/compatible_formats.cpp6
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h1
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp1
-rw-r--r--src/video_core/surface.cpp1
-rw-r--r--src/video_core/surface.h4
-rw-r--r--src/video_core/texture_cache/format_lookup_table.cpp2
-rw-r--r--src/video_core/texture_cache/formatter.h2
-rw-r--r--src/yuzu/applets/qt_web_browser.cpp8
28 files changed, 206 insertions, 109 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 2ee0a96ed..9191ca093 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -2,6 +2,7 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <limits> 4#include <limits>
5#include <optional>
5#include <vector> 6#include <vector>
6 7
7#include "audio_core/audio_out.h" 8#include "audio_core/audio_out.h"
@@ -88,9 +89,12 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing_, Core::Memor
88 stream = audio_out->OpenStream( 89 stream = audio_out->OpenStream(
89 core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, 90 core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
90 fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback)); 91 fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback));
91 process_event = Core::Timing::CreateEvent( 92 process_event =
92 fmt::format("AudioRenderer-Instance{}-Process", instance_number), 93 Core::Timing::CreateEvent(fmt::format("AudioRenderer-Instance{}-Process", instance_number),
93 [this](std::uintptr_t, std::chrono::nanoseconds) { ReleaseAndQueueBuffers(); }); 94 [this](std::uintptr_t, s64, std::chrono::nanoseconds) {
95 ReleaseAndQueueBuffers();
96 return std::nullopt;
97 });
94 for (s32 i = 0; i < NUM_BUFFERS; ++i) { 98 for (s32 i = 0; i < NUM_BUFFERS; ++i) {
95 QueueMixedBuffer(i); 99 QueueMixedBuffer(i);
96 } 100 }
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index f8034b04b..cf3d94c53 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -34,9 +34,10 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing_, u32 sample_rate_, Format
34 ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_) 34 ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_)
35 : sample_rate{sample_rate_}, format{format_}, release_callback{std::move(release_callback_)}, 35 : sample_rate{sample_rate_}, format{format_}, release_callback{std::move(release_callback_)},
36 sink_stream{sink_stream_}, core_timing{core_timing_}, name{std::move(name_)} { 36 sink_stream{sink_stream_}, core_timing{core_timing_}, name{std::move(name_)} {
37 release_event = 37 release_event = Core::Timing::CreateEvent(
38 Core::Timing::CreateEvent(name, [this](std::uintptr_t, std::chrono::nanoseconds ns_late) { 38 name, [this](std::uintptr_t, s64 time, std::chrono::nanoseconds ns_late) {
39 ReleaseActiveBuffer(ns_late); 39 ReleaseActiveBuffer(ns_late);
40 return std::nullopt;
40 }); 41 });
41} 42}
42 43
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index adc31c758..e1e2a90fc 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -18,14 +18,16 @@
18/// Helper macros to insert unused bytes or words to properly align structs. These values will be 18/// Helper macros to insert unused bytes or words to properly align structs. These values will be
19/// zero-initialized. 19/// zero-initialized.
20#define INSERT_PADDING_BYTES(num_bytes) \ 20#define INSERT_PADDING_BYTES(num_bytes) \
21 std::array<u8, num_bytes> CONCAT2(pad, __LINE__) {} 21 [[maybe_unused]] std::array<u8, num_bytes> CONCAT2(pad, __LINE__) {}
22#define INSERT_PADDING_WORDS(num_words) \ 22#define INSERT_PADDING_WORDS(num_words) \
23 std::array<u32, num_words> CONCAT2(pad, __LINE__) {} 23 [[maybe_unused]] std::array<u32, num_words> CONCAT2(pad, __LINE__) {}
24 24
25/// These are similar to the INSERT_PADDING_* macros but do not zero-initialize the contents. 25/// These are similar to the INSERT_PADDING_* macros but do not zero-initialize the contents.
26/// This keeps the structure trivial to construct. 26/// This keeps the structure trivial to construct.
27#define INSERT_PADDING_BYTES_NOINIT(num_bytes) std::array<u8, num_bytes> CONCAT2(pad, __LINE__) 27#define INSERT_PADDING_BYTES_NOINIT(num_bytes) \
28#define INSERT_PADDING_WORDS_NOINIT(num_words) std::array<u32, num_words> CONCAT2(pad, __LINE__) 28 [[maybe_unused]] std::array<u8, num_bytes> CONCAT2(pad, __LINE__)
29#define INSERT_PADDING_WORDS_NOINIT(num_words) \
30 [[maybe_unused]] std::array<u32, num_words> CONCAT2(pad, __LINE__)
29 31
30#ifndef _MSC_VER 32#ifndef _MSC_VER
31 33
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 140578069..5425637f5 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -22,10 +22,11 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac
22} 22}
23 23
24struct CoreTiming::Event { 24struct CoreTiming::Event {
25 u64 time; 25 s64 time;
26 u64 fifo_order; 26 u64 fifo_order;
27 std::uintptr_t user_data; 27 std::uintptr_t user_data;
28 std::weak_ptr<EventType> type; 28 std::weak_ptr<EventType> type;
29 s64 reschedule_time;
29 30
30 // Sort by time, unless the times are the same, in which case sort by 31 // Sort by time, unless the times are the same, in which case sort by
31 // the order added to the queue 32 // the order added to the queue
@@ -58,15 +59,11 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
58 event_fifo_id = 0; 59 event_fifo_id = 0;
59 shutting_down = false; 60 shutting_down = false;
60 ticks = 0; 61 ticks = 0;
61 const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {}; 62 const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds)
63 -> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
62 ev_lost = CreateEvent("_lost_event", empty_timed_callback); 64 ev_lost = CreateEvent("_lost_event", empty_timed_callback);
63 if (is_multicore) { 65 if (is_multicore) {
64 const auto hardware_concurrency = std::thread::hardware_concurrency(); 66 worker_threads.emplace_back(ThreadEntry, std::ref(*this), 0);
65 size_t id = 0;
66 worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++);
67 if (hardware_concurrency > 8) {
68 worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++);
69 }
70 } 67 }
71} 68}
72 69
@@ -81,6 +78,7 @@ void CoreTiming::Shutdown() {
81 thread.join(); 78 thread.join();
82 } 79 }
83 worker_threads.clear(); 80 worker_threads.clear();
81 pause_callbacks.clear();
84 ClearPendingEvents(); 82 ClearPendingEvents();
85 has_started = false; 83 has_started = false;
86} 84}
@@ -98,6 +96,14 @@ void CoreTiming::Pause(bool is_paused_) {
98 } 96 }
99 } 97 }
100 paused_state.store(is_paused_, std::memory_order_relaxed); 98 paused_state.store(is_paused_, std::memory_order_relaxed);
99
100 if (!is_paused_) {
101 pause_end_time = GetGlobalTimeNs().count();
102 }
103
104 for (auto& cb : pause_callbacks) {
105 cb(is_paused_);
106 }
101} 107}
102 108
103void CoreTiming::SyncPause(bool is_paused_) { 109void CoreTiming::SyncPause(bool is_paused_) {
@@ -121,6 +127,14 @@ void CoreTiming::SyncPause(bool is_paused_) {
121 wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; }); 127 wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; });
122 } 128 }
123 } 129 }
130
131 if (!is_paused_) {
132 pause_end_time = GetGlobalTimeNs().count();
133 }
134
135 for (auto& cb : pause_callbacks) {
136 cb(is_paused_);
137 }
124} 138}
125 139
126bool CoreTiming::IsRunning() const { 140bool CoreTiming::IsRunning() const {
@@ -134,12 +148,30 @@ bool CoreTiming::HasPendingEvents() const {
134 148
135void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future, 149void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
136 const std::shared_ptr<EventType>& event_type, 150 const std::shared_ptr<EventType>& event_type,
137 std::uintptr_t user_data) { 151 std::uintptr_t user_data, bool absolute_time) {
138 152
139 std::unique_lock main_lock(event_mutex); 153 std::unique_lock main_lock(event_mutex);
140 const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count()); 154 const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future};
141 155
142 event_queue.emplace_back(Event{timeout, event_fifo_id++, user_data, event_type}); 156 event_queue.emplace_back(Event{next_time.count(), event_fifo_id++, user_data, event_type, 0});
157 pending_events.fetch_add(1, std::memory_order_relaxed);
158
159 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
160
161 if (is_multicore) {
162 event_cv.notify_one();
163 }
164}
165
166void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
167 std::chrono::nanoseconds resched_time,
168 const std::shared_ptr<EventType>& event_type,
169 std::uintptr_t user_data, bool absolute_time) {
170 std::unique_lock main_lock(event_mutex);
171 const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time};
172
173 event_queue.emplace_back(
174 Event{next_time.count(), event_fifo_id++, user_data, event_type, resched_time.count()});
143 pending_events.fetch_add(1, std::memory_order_relaxed); 175 pending_events.fetch_add(1, std::memory_order_relaxed);
144 176
145 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); 177 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
@@ -218,6 +250,11 @@ void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
218 } 250 }
219} 251}
220 252
253void CoreTiming::RegisterPauseCallback(PauseCallback&& callback) {
254 std::unique_lock main_lock(event_mutex);
255 pause_callbacks.emplace_back(std::move(callback));
256}
257
221std::optional<s64> CoreTiming::Advance() { 258std::optional<s64> CoreTiming::Advance() {
222 global_timer = GetGlobalTimeNs().count(); 259 global_timer = GetGlobalTimeNs().count();
223 260
@@ -228,17 +265,31 @@ std::optional<s64> CoreTiming::Advance() {
228 event_queue.pop_back(); 265 event_queue.pop_back();
229 266
230 if (const auto event_type{evt.type.lock()}) { 267 if (const auto event_type{evt.type.lock()}) {
231 sequence_mutex.lock();
232 event_mutex.unlock(); 268 event_mutex.unlock();
233 269
234 event_type->guard.lock(); 270 const auto new_schedule_time{event_type->callback(
235 sequence_mutex.unlock(); 271 evt.user_data, evt.time,
236 const s64 delay = static_cast<s64>(GetGlobalTimeNs().count() - evt.time); 272 std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})};
237 event_type->callback(evt.user_data, std::chrono::nanoseconds{delay});
238 event_type->guard.unlock();
239 273
240 event_mutex.lock(); 274 event_mutex.lock();
241 pending_events.fetch_sub(1, std::memory_order_relaxed); 275 pending_events.fetch_sub(1, std::memory_order_relaxed);
276
277 if (evt.reschedule_time != 0) {
278 // If this event was scheduled into a pause, its time now is going to be way behind.
279 // Re-set this event to continue from the end of the pause.
280 auto next_time{evt.time + evt.reschedule_time};
281 if (evt.time < pause_end_time) {
282 next_time = pause_end_time + evt.reschedule_time;
283 }
284
285 const auto next_schedule_time{new_schedule_time.has_value()
286 ? new_schedule_time.value().count()
287 : evt.reschedule_time};
288 event_queue.emplace_back(
289 Event{next_time, event_fifo_id++, evt.user_data, evt.type, next_schedule_time});
290 pending_events.fetch_add(1, std::memory_order_relaxed);
291 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
292 }
242 } 293 }
243 294
244 global_timer = GetGlobalTimeNs().count(); 295 global_timer = GetGlobalTimeNs().count();
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index a86553e08..09b6ed81a 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -20,8 +20,9 @@
20namespace Core::Timing { 20namespace Core::Timing {
21 21
22/// A callback that may be scheduled for a particular core timing event. 22/// A callback that may be scheduled for a particular core timing event.
23using TimedCallback = 23using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
24 std::function<void(std::uintptr_t user_data, std::chrono::nanoseconds ns_late)>; 24 std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>;
25using PauseCallback = std::function<void(bool paused)>;
25 26
26/// Contains the characteristics of a particular event. 27/// Contains the characteristics of a particular event.
27struct EventType { 28struct EventType {
@@ -32,7 +33,6 @@ struct EventType {
32 TimedCallback callback; 33 TimedCallback callback;
33 /// A pointer to the name of the event. 34 /// A pointer to the name of the event.
34 const std::string name; 35 const std::string name;
35 mutable std::mutex guard;
36}; 36};
37 37
38/** 38/**
@@ -94,7 +94,15 @@ public:
94 94
95 /// Schedules an event in core timing 95 /// Schedules an event in core timing
96 void ScheduleEvent(std::chrono::nanoseconds ns_into_future, 96 void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
97 const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0); 97 const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0,
98 bool absolute_time = false);
99
100 /// Schedules an event which will automatically re-schedule itself with the given time, until
101 /// unscheduled
102 void ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
103 std::chrono::nanoseconds resched_time,
104 const std::shared_ptr<EventType>& event_type,
105 std::uintptr_t user_data = 0, bool absolute_time = false);
98 106
99 void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data); 107 void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data);
100 108
@@ -126,6 +134,9 @@ public:
126 /// Checks for events manually and returns time in nanoseconds for next event, threadsafe. 134 /// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
127 std::optional<s64> Advance(); 135 std::optional<s64> Advance();
128 136
137 /// Register a callback function to be called when coretiming pauses.
138 void RegisterPauseCallback(PauseCallback&& callback);
139
129private: 140private:
130 struct Event; 141 struct Event;
131 142
@@ -137,7 +148,7 @@ private:
137 148
138 std::unique_ptr<Common::WallClock> clock; 149 std::unique_ptr<Common::WallClock> clock;
139 150
140 u64 global_timer = 0; 151 s64 global_timer = 0;
141 152
142 // The queue is a min-heap using std::make_heap/push_heap/pop_heap. 153 // The queue is a min-heap using std::make_heap/push_heap/pop_heap.
143 // We don't use std::priority_queue because we need to be able to serialize, unserialize and 154 // We don't use std::priority_queue because we need to be able to serialize, unserialize and
@@ -157,17 +168,19 @@ private:
157 std::condition_variable wait_pause_cv; 168 std::condition_variable wait_pause_cv;
158 std::condition_variable wait_signal_cv; 169 std::condition_variable wait_signal_cv;
159 mutable std::mutex event_mutex; 170 mutable std::mutex event_mutex;
160 mutable std::mutex sequence_mutex;
161 171
162 std::atomic<bool> paused_state{}; 172 std::atomic<bool> paused_state{};
163 bool is_paused{}; 173 bool is_paused{};
164 bool shutting_down{}; 174 bool shutting_down{};
165 bool is_multicore{}; 175 bool is_multicore{};
166 size_t pause_count{}; 176 size_t pause_count{};
177 s64 pause_end_time{};
167 178
168 /// Cycle timing 179 /// Cycle timing
169 u64 ticks{}; 180 u64 ticks{};
170 s64 downcount{}; 181 s64 downcount{};
182
183 std::vector<PauseCallback> pause_callbacks{};
171}; 184};
172 185
173/// Creates a core timing event with the given name and callback. 186/// Creates a core timing event with the given name and callback.
diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp
index d2d968a76..d08cc3315 100644
--- a/src/core/hardware_interrupt_manager.cpp
+++ b/src/core/hardware_interrupt_manager.cpp
@@ -11,11 +11,14 @@ namespace Core::Hardware {
11 11
12InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { 12InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) {
13 gpu_interrupt_event = Core::Timing::CreateEvent( 13 gpu_interrupt_event = Core::Timing::CreateEvent(
14 "GPUInterrupt", [this](std::uintptr_t message, std::chrono::nanoseconds) { 14 "GPUInterrupt",
15 [this](std::uintptr_t message, u64 time,
16 std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
15 auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv"); 17 auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv");
16 const u32 syncpt = static_cast<u32>(message >> 32); 18 const u32 syncpt = static_cast<u32>(message >> 32);
17 const u32 value = static_cast<u32>(message); 19 const u32 value = static_cast<u32>(message);
18 nvdrv->SignalGPUInterruptSyncpt(syncpt, value); 20 nvdrv->SignalGPUInterruptSyncpt(syncpt, value);
21 return std::nullopt;
19 }); 22 });
20} 23}
21 24
diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h
index 2410f74a3..2e7e1436a 100644
--- a/src/core/hle/kernel/k_code_memory.h
+++ b/src/core/hle/kernel/k_code_memory.h
@@ -30,19 +30,19 @@ public:
30 explicit KCodeMemory(KernelCore& kernel_); 30 explicit KCodeMemory(KernelCore& kernel_);
31 31
32 Result Initialize(Core::DeviceMemory& device_memory, VAddr address, size_t size); 32 Result Initialize(Core::DeviceMemory& device_memory, VAddr address, size_t size);
33 void Finalize(); 33 void Finalize() override;
34 34
35 Result Map(VAddr address, size_t size); 35 Result Map(VAddr address, size_t size);
36 Result Unmap(VAddr address, size_t size); 36 Result Unmap(VAddr address, size_t size);
37 Result MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm); 37 Result MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm);
38 Result UnmapFromOwner(VAddr address, size_t size); 38 Result UnmapFromOwner(VAddr address, size_t size);
39 39
40 bool IsInitialized() const { 40 bool IsInitialized() const override {
41 return m_is_initialized; 41 return m_is_initialized;
42 } 42 }
43 static void PostDestroy([[maybe_unused]] uintptr_t arg) {} 43 static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
44 44
45 KProcess* GetOwner() const { 45 KProcess* GetOwner() const override {
46 return m_owner; 46 return m_owner;
47 } 47 }
48 VAddr GetSourceAddress() const { 48 VAddr GetSourceAddress() const {
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 50cb5fc90..90de86770 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -308,14 +308,20 @@ void KThread::Finalize() {
308 308
309 auto it = waiter_list.begin(); 309 auto it = waiter_list.begin();
310 while (it != waiter_list.end()) { 310 while (it != waiter_list.end()) {
311 // Clear the lock owner 311 // Get the thread.
312 it->SetLockOwner(nullptr); 312 KThread* const waiter = std::addressof(*it);
313
314 // The thread shouldn't be a kernel waiter.
315 ASSERT(!IsKernelAddressKey(waiter->GetAddressKey()));
316
317 // Clear the lock owner.
318 waiter->SetLockOwner(nullptr);
313 319
314 // Erase the waiter from our list. 320 // Erase the waiter from our list.
315 it = waiter_list.erase(it); 321 it = waiter_list.erase(it);
316 322
317 // Cancel the thread's wait. 323 // Cancel the thread's wait.
318 it->CancelWait(ResultInvalidState, true); 324 waiter->CancelWait(ResultInvalidState, true);
319 } 325 }
320 } 326 }
321 327
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 0009193be..7307cf262 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -234,17 +234,18 @@ struct KernelCore::Impl {
234 234
235 void InitializePreemption(KernelCore& kernel) { 235 void InitializePreemption(KernelCore& kernel) {
236 preemption_event = Core::Timing::CreateEvent( 236 preemption_event = Core::Timing::CreateEvent(
237 "PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) { 237 "PreemptionCallback",
238 [this, &kernel](std::uintptr_t, s64 time,
239 std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
238 { 240 {
239 KScopedSchedulerLock lock(kernel); 241 KScopedSchedulerLock lock(kernel);
240 global_scheduler_context->PreemptThreads(); 242 global_scheduler_context->PreemptThreads();
241 } 243 }
242 const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; 244 return std::nullopt;
243 system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
244 }); 245 });
245 246
246 const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; 247 const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)};
247 system.CoreTiming().ScheduleEvent(time_interval, preemption_event); 248 system.CoreTiming().ScheduleLoopingEvent(time_interval, time_interval, preemption_event);
248 } 249 }
249 250
250 void InitializeShutdownThreads() { 251 void InitializeShutdownThreads() {
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
index 2724c3782..5ee72c432 100644
--- a/src/core/hle/kernel/time_manager.cpp
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -11,15 +11,17 @@
11namespace Kernel { 11namespace Kernel {
12 12
13TimeManager::TimeManager(Core::System& system_) : system{system_} { 13TimeManager::TimeManager(Core::System& system_) : system{system_} {
14 time_manager_event_type = 14 time_manager_event_type = Core::Timing::CreateEvent(
15 Core::Timing::CreateEvent("Kernel::TimeManagerCallback", 15 "Kernel::TimeManagerCallback",
16 [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { 16 [this](std::uintptr_t thread_handle, s64 time,
17 KThread* thread = reinterpret_cast<KThread*>(thread_handle); 17 std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
18 { 18 KThread* thread = reinterpret_cast<KThread*>(thread_handle);
19 KScopedSchedulerLock sl(system.Kernel()); 19 {
20 thread->OnTimer(); 20 KScopedSchedulerLock sl(system.Kernel());
21 } 21 thread->OnTimer();
22 }); 22 }
23 return std::nullopt;
24 });
23} 25}
24 26
25void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { 27void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index aa7189bda..3c28dee76 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -838,11 +838,11 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id,
838 838
839 const auto now = steady_clock::now(); 839 const auto now = steady_clock::now();
840 840
841 // Filter out non-zero vibrations that are within 10ms of each other. 841 // Filter out non-zero vibrations that are within 15ms of each other.
842 if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) && 842 if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) &&
843 duration_cast<milliseconds>( 843 duration_cast<milliseconds>(
844 now - controller.vibration[device_index].last_vibration_timepoint) < 844 now - controller.vibration[device_index].last_vibration_timepoint) <
845 milliseconds(10)) { 845 milliseconds(15)) {
846 return false; 846 return false;
847 } 847 }
848 848
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 78efffc50..89bb12442 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -74,26 +74,34 @@ IAppletResource::IAppletResource(Core::System& system_,
74 // Register update callbacks 74 // Register update callbacks
75 pad_update_event = Core::Timing::CreateEvent( 75 pad_update_event = Core::Timing::CreateEvent(
76 "HID::UpdatePadCallback", 76 "HID::UpdatePadCallback",
77 [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 77 [this](std::uintptr_t user_data, s64 time,
78 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
78 const auto guard = LockService(); 79 const auto guard = LockService();
79 UpdateControllers(user_data, ns_late); 80 UpdateControllers(user_data, ns_late);
81 return std::nullopt;
80 }); 82 });
81 mouse_keyboard_update_event = Core::Timing::CreateEvent( 83 mouse_keyboard_update_event = Core::Timing::CreateEvent(
82 "HID::UpdateMouseKeyboardCallback", 84 "HID::UpdateMouseKeyboardCallback",
83 [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 85 [this](std::uintptr_t user_data, s64 time,
86 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
84 const auto guard = LockService(); 87 const auto guard = LockService();
85 UpdateMouseKeyboard(user_data, ns_late); 88 UpdateMouseKeyboard(user_data, ns_late);
89 return std::nullopt;
86 }); 90 });
87 motion_update_event = Core::Timing::CreateEvent( 91 motion_update_event = Core::Timing::CreateEvent(
88 "HID::UpdateMotionCallback", 92 "HID::UpdateMotionCallback",
89 [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 93 [this](std::uintptr_t user_data, s64 time,
94 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
90 const auto guard = LockService(); 95 const auto guard = LockService();
91 UpdateMotion(user_data, ns_late); 96 UpdateMotion(user_data, ns_late);
97 return std::nullopt;
92 }); 98 });
93 99
94 system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); 100 system.CoreTiming().ScheduleLoopingEvent(pad_update_ns, pad_update_ns, pad_update_event);
95 system.CoreTiming().ScheduleEvent(mouse_keyboard_update_ns, mouse_keyboard_update_event); 101 system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
96 system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); 102 mouse_keyboard_update_event);
103 system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
104 motion_update_event);
97 105
98 system.HIDCore().ReloadInputDevices(); 106 system.HIDCore().ReloadInputDevices();
99} 107}
@@ -135,13 +143,6 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
135 } 143 }
136 controller->OnUpdate(core_timing); 144 controller->OnUpdate(core_timing);
137 } 145 }
138
139 // If ns_late is higher than the update rate ignore the delay
140 if (ns_late > pad_update_ns) {
141 ns_late = {};
142 }
143
144 core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
145} 146}
146 147
147void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, 148void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
@@ -150,26 +151,12 @@ void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
150 151
151 controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing); 152 controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing);
152 controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing); 153 controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing);
153
154 // If ns_late is higher than the update rate ignore the delay
155 if (ns_late > mouse_keyboard_update_ns) {
156 ns_late = {};
157 }
158
159 core_timing.ScheduleEvent(mouse_keyboard_update_ns - ns_late, mouse_keyboard_update_event);
160} 154}
161 155
162void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 156void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
163 auto& core_timing = system.CoreTiming(); 157 auto& core_timing = system.CoreTiming();
164 158
165 controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing); 159 controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing);
166
167 // If ns_late is higher than the update rate ignore the delay
168 if (ns_late > motion_update_ns) {
169 ns_late = {};
170 }
171
172 core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event);
173} 160}
174 161
175class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { 162class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp
index fa6153b4c..e5e50845f 100644
--- a/src/core/hle/service/hid/hidbus.cpp
+++ b/src/core/hle/service/hid/hidbus.cpp
@@ -50,12 +50,15 @@ HidBus::HidBus(Core::System& system_)
50 // Register update callbacks 50 // Register update callbacks
51 hidbus_update_event = Core::Timing::CreateEvent( 51 hidbus_update_event = Core::Timing::CreateEvent(
52 "Hidbus::UpdateCallback", 52 "Hidbus::UpdateCallback",
53 [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 53 [this](std::uintptr_t user_data, s64 time,
54 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
54 const auto guard = LockService(); 55 const auto guard = LockService();
55 UpdateHidbus(user_data, ns_late); 56 UpdateHidbus(user_data, ns_late);
57 return std::nullopt;
56 }); 58 });
57 59
58 system_.CoreTiming().ScheduleEvent(hidbus_update_ns, hidbus_update_event); 60 system_.CoreTiming().ScheduleLoopingEvent(hidbus_update_ns, hidbus_update_ns,
61 hidbus_update_event);
59} 62}
60 63
61HidBus::~HidBus() { 64HidBus::~HidBus() {
@@ -63,8 +66,6 @@ HidBus::~HidBus() {
63} 66}
64 67
65void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 68void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
66 auto& core_timing = system.CoreTiming();
67
68 if (is_hidbus_enabled) { 69 if (is_hidbus_enabled) {
69 for (std::size_t i = 0; i < devices.size(); ++i) { 70 for (std::size_t i = 0; i < devices.size(); ++i) {
70 if (!devices[i].is_device_initializated) { 71 if (!devices[i].is_device_initializated) {
@@ -82,13 +83,6 @@ void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_
82 sizeof(HidbusStatusManagerEntry)); 83 sizeof(HidbusStatusManagerEntry));
83 } 84 }
84 } 85 }
85
86 // If ns_late is higher than the update rate ignore the delay
87 if (ns_late > hidbus_update_ns) {
88 ns_late = {};
89 }
90
91 core_timing.ScheduleEvent(hidbus_update_ns - ns_late, hidbus_update_event);
92} 86}
93 87
94std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) const { 88std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) const {
diff --git a/src/core/hle/service/nvflinger/binder.h b/src/core/hle/service/nvflinger/binder.h
index 21aaa40cd..157333ff8 100644
--- a/src/core/hle/service/nvflinger/binder.h
+++ b/src/core/hle/service/nvflinger/binder.h
@@ -34,6 +34,7 @@ enum class TransactionId {
34 34
35class IBinder { 35class IBinder {
36public: 36public:
37 virtual ~IBinder() = default;
37 virtual void Transact(Kernel::HLERequestContext& ctx, android::TransactionId code, 38 virtual void Transact(Kernel::HLERequestContext& ctx, android::TransactionId code,
38 u32 flags) = 0; 39 u32 flags) = 0;
39 virtual Kernel::KReadableEvent& GetNativeHandle() = 0; 40 virtual Kernel::KReadableEvent& GetNativeHandle() = 0;
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 2b2985a2d..5f69c8c2c 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -67,21 +67,20 @@ NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_dr
67 67
68 // Schedule the screen composition events 68 // Schedule the screen composition events
69 composition_event = Core::Timing::CreateEvent( 69 composition_event = Core::Timing::CreateEvent(
70 "ScreenComposition", [this](std::uintptr_t, std::chrono::nanoseconds ns_late) { 70 "ScreenComposition",
71 [this](std::uintptr_t, s64 time,
72 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
71 const auto lock_guard = Lock(); 73 const auto lock_guard = Lock();
72 Compose(); 74 Compose();
73 75
74 const auto ticks = std::chrono::nanoseconds{GetNextTicks()}; 76 return std::max(std::chrono::nanoseconds::zero(),
75 const auto ticks_delta = ticks - ns_late; 77 std::chrono::nanoseconds(GetNextTicks()) - ns_late);
76 const auto future_ns = std::max(std::chrono::nanoseconds::zero(), ticks_delta);
77
78 this->system.CoreTiming().ScheduleEvent(future_ns, composition_event);
79 }); 78 });
80 79
81 if (system.IsMulticore()) { 80 if (system.IsMulticore()) {
82 vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); }); 81 vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); });
83 } else { 82 } else {
84 system.CoreTiming().ScheduleEvent(frame_ns, composition_event); 83 system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, composition_event);
85 } 84 }
86} 85}
87 86
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index 5f71f0ff5..ffdbacc18 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -184,10 +184,12 @@ CheatEngine::~CheatEngine() {
184void CheatEngine::Initialize() { 184void CheatEngine::Initialize() {
185 event = Core::Timing::CreateEvent( 185 event = Core::Timing::CreateEvent(
186 "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id), 186 "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
187 [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 187 [this](std::uintptr_t user_data, s64 time,
188 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
188 FrameCallback(user_data, ns_late); 189 FrameCallback(user_data, ns_late);
190 return std::nullopt;
189 }); 191 });
190 core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event); 192 core_timing.ScheduleLoopingEvent(CHEAT_ENGINE_NS, CHEAT_ENGINE_NS, event);
191 193
192 metadata.process_id = system.CurrentProcess()->GetProcessID(); 194 metadata.process_id = system.CurrentProcess()->GetProcessID();
193 metadata.title_id = system.GetCurrentProcessProgramID(); 195 metadata.title_id = system.GetCurrentProcessProgramID();
@@ -237,8 +239,6 @@ void CheatEngine::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late
237 MICROPROFILE_SCOPE(Cheat_Engine); 239 MICROPROFILE_SCOPE(Cheat_Engine);
238 240
239 vm.Execute(metadata); 241 vm.Execute(metadata);
240
241 core_timing.ScheduleEvent(CHEAT_ENGINE_NS - ns_late, event);
242} 242}
243 243
244} // namespace Core::Memory 244} // namespace Core::Memory
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 5cc99fbe4..98ebbbf32 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -53,8 +53,10 @@ Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& m
53 : core_timing{core_timing_}, memory{memory_} { 53 : core_timing{core_timing_}, memory{memory_} {
54 event = Core::Timing::CreateEvent( 54 event = Core::Timing::CreateEvent(
55 "MemoryFreezer::FrameCallback", 55 "MemoryFreezer::FrameCallback",
56 [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 56 [this](std::uintptr_t user_data, s64 time,
57 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
57 FrameCallback(user_data, ns_late); 58 FrameCallback(user_data, ns_late);
59 return std::nullopt;
58 }); 60 });
59 core_timing.ScheduleEvent(memory_freezer_ns, event); 61 core_timing.ScheduleEvent(memory_freezer_ns, event);
60} 62}
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index 446c027d3..00474ac77 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -438,10 +438,17 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
438 using namespace std::chrono_literals; 438 using namespace std::chrono_literals;
439 while (initialized) { 439 while (initialized) {
440 SDL_PumpEvents(); 440 SDL_PumpEvents();
441 SendVibrations();
442 std::this_thread::sleep_for(1ms); 441 std::this_thread::sleep_for(1ms);
443 } 442 }
444 }); 443 });
444 vibration_thread = std::thread([this] {
445 Common::SetCurrentThreadName("yuzu:input:SDL_Vibration");
446 using namespace std::chrono_literals;
447 while (initialized) {
448 SendVibrations();
449 std::this_thread::sleep_for(10ms);
450 }
451 });
445 } 452 }
446 // Because the events for joystick connection happens before we have our event watcher added, we 453 // Because the events for joystick connection happens before we have our event watcher added, we
447 // can just open all the joysticks right here 454 // can just open all the joysticks right here
@@ -457,6 +464,7 @@ SDLDriver::~SDLDriver() {
457 initialized = false; 464 initialized = false;
458 if (start_thread) { 465 if (start_thread) {
459 poll_thread.join(); 466 poll_thread.join();
467 vibration_thread.join();
460 SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); 468 SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
461 } 469 }
462} 470}
diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h
index 0846fbb50..7dc7a93c7 100644
--- a/src/input_common/drivers/sdl_driver.h
+++ b/src/input_common/drivers/sdl_driver.h
@@ -128,5 +128,6 @@ private:
128 std::atomic<bool> initialized = false; 128 std::atomic<bool> initialized = false;
129 129
130 std::thread poll_thread; 130 std::thread poll_thread;
131 std::thread vibration_thread;
131}; 132};
132} // namespace InputCommon 133} // namespace InputCommon
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp
index e687416a8..894975e6f 100644
--- a/src/tests/core/core_timing.cpp
+++ b/src/tests/core/core_timing.cpp
@@ -9,6 +9,7 @@
9#include <cstdlib> 9#include <cstdlib>
10#include <memory> 10#include <memory>
11#include <mutex> 11#include <mutex>
12#include <optional>
12#include <string> 13#include <string>
13 14
14#include "core/core.h" 15#include "core/core.h"
@@ -25,13 +26,15 @@ u64 expected_callback = 0;
25std::mutex control_mutex; 26std::mutex control_mutex;
26 27
27template <unsigned int IDX> 28template <unsigned int IDX>
28void HostCallbackTemplate(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 29std::optional<std::chrono::nanoseconds> HostCallbackTemplate(std::uintptr_t user_data, s64 time,
30 std::chrono::nanoseconds ns_late) {
29 std::unique_lock<std::mutex> lk(control_mutex); 31 std::unique_lock<std::mutex> lk(control_mutex);
30 static_assert(IDX < CB_IDS.size(), "IDX out of range"); 32 static_assert(IDX < CB_IDS.size(), "IDX out of range");
31 callbacks_ran_flags.set(IDX); 33 callbacks_ran_flags.set(IDX);
32 REQUIRE(CB_IDS[IDX] == user_data); 34 REQUIRE(CB_IDS[IDX] == user_data);
33 delays[IDX] = ns_late.count(); 35 delays[IDX] = ns_late.count();
34 ++expected_callback; 36 ++expected_callback;
37 return std::nullopt;
35} 38}
36 39
37struct ScopeInit final { 40struct ScopeInit final {
diff --git a/src/video_core/compatible_formats.cpp b/src/video_core/compatible_formats.cpp
index 014d880e2..4e75f33ca 100644
--- a/src/video_core/compatible_formats.cpp
+++ b/src/video_core/compatible_formats.cpp
@@ -131,9 +131,12 @@ constexpr std::array VIEW_CLASS_ASTC_8x8_RGBA{
131// PixelFormat::ASTC_2D_10X5_SRGB 131// PixelFormat::ASTC_2D_10X5_SRGB
132 132
133// Missing formats: 133// Missing formats:
134// PixelFormat::ASTC_2D_10X6_UNORM
135// PixelFormat::ASTC_2D_10X6_SRGB 134// PixelFormat::ASTC_2D_10X6_SRGB
136 135
136constexpr std::array VIEW_CLASS_ASTC_10x6_RGBA{
137 PixelFormat::ASTC_2D_10X6_UNORM,
138};
139
137constexpr std::array VIEW_CLASS_ASTC_10x8_RGBA{ 140constexpr std::array VIEW_CLASS_ASTC_10x8_RGBA{
138 PixelFormat::ASTC_2D_10X8_UNORM, 141 PixelFormat::ASTC_2D_10X8_UNORM,
139 PixelFormat::ASTC_2D_10X8_SRGB, 142 PixelFormat::ASTC_2D_10X8_SRGB,
@@ -226,6 +229,7 @@ constexpr Table MakeViewTable() {
226 EnableRange(view, VIEW_CLASS_ASTC_6x6_RGBA); 229 EnableRange(view, VIEW_CLASS_ASTC_6x6_RGBA);
227 EnableRange(view, VIEW_CLASS_ASTC_8x5_RGBA); 230 EnableRange(view, VIEW_CLASS_ASTC_8x5_RGBA);
228 EnableRange(view, VIEW_CLASS_ASTC_8x8_RGBA); 231 EnableRange(view, VIEW_CLASS_ASTC_8x8_RGBA);
232 EnableRange(view, VIEW_CLASS_ASTC_10x6_RGBA);
229 EnableRange(view, VIEW_CLASS_ASTC_10x8_RGBA); 233 EnableRange(view, VIEW_CLASS_ASTC_10x8_RGBA);
230 EnableRange(view, VIEW_CLASS_ASTC_10x10_RGBA); 234 EnableRange(view, VIEW_CLASS_ASTC_10x10_RGBA);
231 EnableRange(view, VIEW_CLASS_ASTC_12x12_RGBA); 235 EnableRange(view, VIEW_CLASS_ASTC_12x12_RGBA);
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index 644b60d73..9a72d0d6d 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -98,6 +98,7 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> FORMAT_TAB
98 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR}, // ASTC_2D_10X8_SRGB 98 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR}, // ASTC_2D_10X8_SRGB
99 {GL_COMPRESSED_RGBA_ASTC_6x6_KHR}, // ASTC_2D_6X6_UNORM 99 {GL_COMPRESSED_RGBA_ASTC_6x6_KHR}, // ASTC_2D_6X6_UNORM
100 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR}, // ASTC_2D_6X6_SRGB 100 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR}, // ASTC_2D_6X6_SRGB
101 {GL_COMPRESSED_RGBA_ASTC_10x6_KHR}, // ASTC_2D_10X6_UNORM
101 {GL_COMPRESSED_RGBA_ASTC_10x10_KHR}, // ASTC_2D_10X10_UNORM 102 {GL_COMPRESSED_RGBA_ASTC_10x10_KHR}, // ASTC_2D_10X10_UNORM
102 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR}, // ASTC_2D_10X10_SRGB 103 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR}, // ASTC_2D_10X10_SRGB
103 {GL_COMPRESSED_RGBA_ASTC_12x12_KHR}, // ASTC_2D_12X12_UNORM 104 {GL_COMPRESSED_RGBA_ASTC_12x12_KHR}, // ASTC_2D_12X12_UNORM
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 193cbe15e..689164a6a 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -195,6 +195,7 @@ struct FormatTuple {
195 {VK_FORMAT_ASTC_10x8_SRGB_BLOCK}, // ASTC_2D_10X8_SRGB 195 {VK_FORMAT_ASTC_10x8_SRGB_BLOCK}, // ASTC_2D_10X8_SRGB
196 {VK_FORMAT_ASTC_6x6_UNORM_BLOCK}, // ASTC_2D_6X6_UNORM 196 {VK_FORMAT_ASTC_6x6_UNORM_BLOCK}, // ASTC_2D_6X6_UNORM
197 {VK_FORMAT_ASTC_6x6_SRGB_BLOCK}, // ASTC_2D_6X6_SRGB 197 {VK_FORMAT_ASTC_6x6_SRGB_BLOCK}, // ASTC_2D_6X6_SRGB
198 {VK_FORMAT_ASTC_10x6_UNORM_BLOCK}, // ASTC_2D_10X6_UNORM
198 {VK_FORMAT_ASTC_10x10_UNORM_BLOCK}, // ASTC_2D_10X10_UNORM 199 {VK_FORMAT_ASTC_10x10_UNORM_BLOCK}, // ASTC_2D_10X10_UNORM
199 {VK_FORMAT_ASTC_10x10_SRGB_BLOCK}, // ASTC_2D_10X10_SRGB 200 {VK_FORMAT_ASTC_10x10_SRGB_BLOCK}, // ASTC_2D_10X10_SRGB
200 {VK_FORMAT_ASTC_12x12_UNORM_BLOCK}, // ASTC_2D_12X12_UNORM 201 {VK_FORMAT_ASTC_12x12_UNORM_BLOCK}, // ASTC_2D_12X12_UNORM
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index 69c1b1e6d..eecd0deff 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -247,6 +247,7 @@ bool IsPixelFormatASTC(PixelFormat format) {
247 case PixelFormat::ASTC_2D_10X8_SRGB: 247 case PixelFormat::ASTC_2D_10X8_SRGB:
248 case PixelFormat::ASTC_2D_6X6_UNORM: 248 case PixelFormat::ASTC_2D_6X6_UNORM:
249 case PixelFormat::ASTC_2D_6X6_SRGB: 249 case PixelFormat::ASTC_2D_6X6_SRGB:
250 case PixelFormat::ASTC_2D_10X6_UNORM:
250 case PixelFormat::ASTC_2D_10X10_UNORM: 251 case PixelFormat::ASTC_2D_10X10_UNORM:
251 case PixelFormat::ASTC_2D_10X10_SRGB: 252 case PixelFormat::ASTC_2D_10X10_SRGB:
252 case PixelFormat::ASTC_2D_12X12_UNORM: 253 case PixelFormat::ASTC_2D_12X12_UNORM:
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 75e055592..0175432ff 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -94,6 +94,7 @@ enum class PixelFormat {
94 ASTC_2D_10X8_SRGB, 94 ASTC_2D_10X8_SRGB,
95 ASTC_2D_6X6_UNORM, 95 ASTC_2D_6X6_UNORM,
96 ASTC_2D_6X6_SRGB, 96 ASTC_2D_6X6_SRGB,
97 ASTC_2D_10X6_UNORM,
97 ASTC_2D_10X10_UNORM, 98 ASTC_2D_10X10_UNORM,
98 ASTC_2D_10X10_SRGB, 99 ASTC_2D_10X10_SRGB,
99 ASTC_2D_12X12_UNORM, 100 ASTC_2D_12X12_UNORM,
@@ -227,6 +228,7 @@ constexpr std::array<u8, MaxPixelFormat> BLOCK_WIDTH_TABLE = {{
227 10, // ASTC_2D_10X8_SRGB 228 10, // ASTC_2D_10X8_SRGB
228 6, // ASTC_2D_6X6_UNORM 229 6, // ASTC_2D_6X6_UNORM
229 6, // ASTC_2D_6X6_SRGB 230 6, // ASTC_2D_6X6_SRGB
231 10, // ASTC_2D_10X6_UNORM
230 10, // ASTC_2D_10X10_UNORM 232 10, // ASTC_2D_10X10_UNORM
231 10, // ASTC_2D_10X10_SRGB 233 10, // ASTC_2D_10X10_SRGB
232 12, // ASTC_2D_12X12_UNORM 234 12, // ASTC_2D_12X12_UNORM
@@ -329,6 +331,7 @@ constexpr std::array<u8, MaxPixelFormat> BLOCK_HEIGHT_TABLE = {{
329 8, // ASTC_2D_10X8_SRGB 331 8, // ASTC_2D_10X8_SRGB
330 6, // ASTC_2D_6X6_UNORM 332 6, // ASTC_2D_6X6_UNORM
331 6, // ASTC_2D_6X6_SRGB 333 6, // ASTC_2D_6X6_SRGB
334 6, // ASTC_2D_10X6_UNORM
332 10, // ASTC_2D_10X10_UNORM 335 10, // ASTC_2D_10X10_UNORM
333 10, // ASTC_2D_10X10_SRGB 336 10, // ASTC_2D_10X10_SRGB
334 12, // ASTC_2D_12X12_UNORM 337 12, // ASTC_2D_12X12_UNORM
@@ -431,6 +434,7 @@ constexpr std::array<u8, MaxPixelFormat> BITS_PER_BLOCK_TABLE = {{
431 128, // ASTC_2D_10X8_SRGB 434 128, // ASTC_2D_10X8_SRGB
432 128, // ASTC_2D_6X6_UNORM 435 128, // ASTC_2D_6X6_UNORM
433 128, // ASTC_2D_6X6_SRGB 436 128, // ASTC_2D_6X6_SRGB
437 128, // ASTC_2D_10X6_UNORM
434 128, // ASTC_2D_10X10_UNORM 438 128, // ASTC_2D_10X10_UNORM
435 128, // ASTC_2D_10X10_SRGB 439 128, // ASTC_2D_10X10_SRGB
436 128, // ASTC_2D_12X12_UNORM 440 128, // ASTC_2D_12X12_UNORM
diff --git a/src/video_core/texture_cache/format_lookup_table.cpp b/src/video_core/texture_cache/format_lookup_table.cpp
index 0937768d6..1412aa076 100644
--- a/src/video_core/texture_cache/format_lookup_table.cpp
+++ b/src/video_core/texture_cache/format_lookup_table.cpp
@@ -206,6 +206,8 @@ PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red,
206 return PixelFormat::ASTC_2D_6X6_UNORM; 206 return PixelFormat::ASTC_2D_6X6_UNORM;
207 case Hash(TextureFormat::ASTC_2D_6X6, UNORM, SRGB): 207 case Hash(TextureFormat::ASTC_2D_6X6, UNORM, SRGB):
208 return PixelFormat::ASTC_2D_6X6_SRGB; 208 return PixelFormat::ASTC_2D_6X6_SRGB;
209 case Hash(TextureFormat::ASTC_2D_10X6, UNORM, LINEAR):
210 return PixelFormat::ASTC_2D_10X6_UNORM;
209 case Hash(TextureFormat::ASTC_2D_10X10, UNORM, LINEAR): 211 case Hash(TextureFormat::ASTC_2D_10X10, UNORM, LINEAR):
210 return PixelFormat::ASTC_2D_10X10_UNORM; 212 return PixelFormat::ASTC_2D_10X10_UNORM;
211 case Hash(TextureFormat::ASTC_2D_10X10, UNORM, SRGB): 213 case Hash(TextureFormat::ASTC_2D_10X10, UNORM, SRGB):
diff --git a/src/video_core/texture_cache/formatter.h b/src/video_core/texture_cache/formatter.h
index 1b78ed445..95a572604 100644
--- a/src/video_core/texture_cache/formatter.h
+++ b/src/video_core/texture_cache/formatter.h
@@ -175,6 +175,8 @@ struct fmt::formatter<VideoCore::Surface::PixelFormat> : fmt::formatter<fmt::str
175 return "ASTC_2D_6X6_UNORM"; 175 return "ASTC_2D_6X6_UNORM";
176 case PixelFormat::ASTC_2D_6X6_SRGB: 176 case PixelFormat::ASTC_2D_6X6_SRGB:
177 return "ASTC_2D_6X6_SRGB"; 177 return "ASTC_2D_6X6_SRGB";
178 case PixelFormat::ASTC_2D_10X6_UNORM:
179 return "ASTC_2D_10X6_UNORM";
178 case PixelFormat::ASTC_2D_10X10_UNORM: 180 case PixelFormat::ASTC_2D_10X10_UNORM:
179 return "ASTC_2D_10X10_UNORM"; 181 return "ASTC_2D_10X10_UNORM";
180 case PixelFormat::ASTC_2D_10X10_SRGB: 182 case PixelFormat::ASTC_2D_10X10_SRGB:
diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp
index 790edbb2a..89bd482e0 100644
--- a/src/yuzu/applets/qt_web_browser.cpp
+++ b/src/yuzu/applets/qt_web_browser.cpp
@@ -2,6 +2,8 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#ifdef YUZU_USE_QT_WEB_ENGINE 4#ifdef YUZU_USE_QT_WEB_ENGINE
5#include <bit>
6
5#include <QApplication> 7#include <QApplication>
6#include <QKeyEvent> 8#include <QKeyEvent>
7 9
@@ -211,8 +213,10 @@ template <Core::HID::NpadButton... T>
211void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() { 213void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() {
212 const auto f = [this](Core::HID::NpadButton button) { 214 const auto f = [this](Core::HID::NpadButton button) {
213 if (input_interpreter->IsButtonPressedOnce(button)) { 215 if (input_interpreter->IsButtonPressedOnce(button)) {
216 const auto button_index = std::countr_zero(static_cast<u64>(button));
217
214 page()->runJavaScript( 218 page()->runJavaScript(
215 QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(static_cast<u8>(button)), 219 QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(button_index),
216 [this, button](const QVariant& variant) { 220 [this, button](const QVariant& variant) {
217 if (variant.toBool()) { 221 if (variant.toBool()) {
218 switch (button) { 222 switch (button) {
@@ -236,7 +240,7 @@ void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() {
236 240
237 page()->runJavaScript( 241 page()->runJavaScript(
238 QStringLiteral("if (yuzu_key_callbacks[%1] != null) { yuzu_key_callbacks[%1](); }") 242 QStringLiteral("if (yuzu_key_callbacks[%1] != null) { yuzu_key_callbacks[%1](); }")
239 .arg(static_cast<u8>(button))); 243 .arg(button_index));
240 } 244 }
241 }; 245 };
242 246