diff options
32 files changed, 213 insertions, 116 deletions
diff --git a/.ci/scripts/windows/docker.sh b/.ci/scripts/windows/docker.sh index d670fe47d..5bd5f0b6b 100755 --- a/.ci/scripts/windows/docker.sh +++ b/.ci/scripts/windows/docker.sh | |||
| @@ -65,7 +65,7 @@ python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll | |||
| 65 | # copy FFmpeg libraries | 65 | # copy FFmpeg libraries |
| 66 | EXTERNALS_PATH="$(pwd)/build/externals" | 66 | EXTERNALS_PATH="$(pwd)/build/externals" |
| 67 | FFMPEG_DLL_PATH="$(find "${EXTERNALS_PATH}" -maxdepth 1 -type d | grep 'ffmpeg-')/bin" | 67 | FFMPEG_DLL_PATH="$(find "${EXTERNALS_PATH}" -maxdepth 1 -type d | grep 'ffmpeg-')/bin" |
| 68 | find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';' | 68 | find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -nv {} package/ ';' |
| 69 | 69 | ||
| 70 | # copy libraries from yuzu.exe path | 70 | # copy libraries from yuzu.exe path |
| 71 | find "$(pwd)/build/bin/" -type f -regex ".*\.dll" -exec cp -v {} package/ ';' | 71 | find "$(pwd)/build/bin/" -type f -regex ".*\.dll" -exec cp -v {} package/ ';' |
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3400670a..8ec7e3c69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml | |||
| @@ -13,7 +13,7 @@ jobs: | |||
| 13 | container: yuzuemu/build-environments:linux-transifex | 13 | container: yuzuemu/build-environments:linux-transifex |
| 14 | if: ${{ github.repository == 'yuzu-emu/yuzu' && !github.head_ref }} | 14 | if: ${{ github.repository == 'yuzu-emu/yuzu' && !github.head_ref }} |
| 15 | steps: | 15 | steps: |
| 16 | - uses: actions/checkout@v2 | 16 | - uses: actions/checkout@v3 |
| 17 | with: | 17 | with: |
| 18 | submodules: recursive | 18 | submodules: recursive |
| 19 | fetch-depth: 0 | 19 | fetch-depth: 0 |
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 7e39ef847..c1886b9f3 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml | |||
| @@ -12,7 +12,7 @@ jobs: | |||
| 12 | image: yuzuemu/build-environments:linux-clang-format | 12 | image: yuzuemu/build-environments:linux-clang-format |
| 13 | options: -u 1001 | 13 | options: -u 1001 |
| 14 | steps: | 14 | steps: |
| 15 | - uses: actions/checkout@v2 | 15 | - uses: actions/checkout@v3 |
| 16 | with: | 16 | with: |
| 17 | submodules: false | 17 | submodules: false |
| 18 | - name: 'Verify Formatting' | 18 | - name: 'Verify Formatting' |
| @@ -35,12 +35,12 @@ jobs: | |||
| 35 | image: yuzuemu/build-environments:${{ matrix.image }} | 35 | image: yuzuemu/build-environments:${{ matrix.image }} |
| 36 | options: -u 1001 | 36 | options: -u 1001 |
| 37 | steps: | 37 | steps: |
| 38 | - uses: actions/checkout@v2 | 38 | - uses: actions/checkout@v3 |
| 39 | with: | 39 | with: |
| 40 | submodules: recursive | 40 | submodules: recursive |
| 41 | fetch-depth: 0 | 41 | fetch-depth: 0 |
| 42 | - name: Set up cache | 42 | - name: Set up cache |
| 43 | uses: actions/cache@v2 | 43 | uses: actions/cache@v3 |
| 44 | id: ccache-restore | 44 | id: ccache-restore |
| 45 | with: | 45 | with: |
| 46 | path: ~/.ccache | 46 | path: ~/.ccache |
| @@ -69,7 +69,7 @@ jobs: | |||
| 69 | runs-on: windows-2019 | 69 | runs-on: windows-2019 |
| 70 | steps: | 70 | steps: |
| 71 | - name: Set up cache | 71 | - name: Set up cache |
| 72 | uses: actions/cache@v2 | 72 | uses: actions/cache@v3 |
| 73 | with: | 73 | with: |
| 74 | path: ~/.buildcache | 74 | path: ~/.buildcache |
| 75 | key: ${{ runner.os }}-msvc-${{ github.sha }} | 75 | key: ${{ runner.os }}-msvc-${{ github.sha }} |
| @@ -89,7 +89,7 @@ jobs: | |||
| 89 | echo %PATH% >> %GITHUB_PATH% | 89 | echo %PATH% >> %GITHUB_PATH% |
| 90 | - name: Set up MSVC | 90 | - name: Set up MSVC |
| 91 | uses: ilammy/msvc-dev-cmd@v1 | 91 | uses: ilammy/msvc-dev-cmd@v1 |
| 92 | - uses: actions/checkout@v2 | 92 | - uses: actions/checkout@v3 |
| 93 | with: | 93 | with: |
| 94 | submodules: recursive | 94 | submodules: recursive |
| 95 | fetch-depth: 0 | 95 | fetch-depth: 0 |
diff --git a/externals/dynarmic b/externals/dynarmic | |||
| Subproject 7f84870712ac2fe06aa62dc2bebbe46b51a2cc2 | Subproject 9ebf6a8384836322ce58beb7ca10f5d4c66e921 | ||
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 | ||
| 24 | struct CoreTiming::Event { | 24 | struct 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 | ||
| 103 | void CoreTiming::SyncPause(bool is_paused_) { | 109 | void 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 | ||
| 126 | bool CoreTiming::IsRunning() const { | 140 | bool CoreTiming::IsRunning() const { |
| @@ -134,12 +148,30 @@ bool CoreTiming::HasPendingEvents() const { | |||
| 134 | 148 | ||
| 135 | void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future, | 149 | void 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 | |||
| 166 | void 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 | ||
| 253 | void CoreTiming::RegisterPauseCallback(PauseCallback&& callback) { | ||
| 254 | std::unique_lock main_lock(event_mutex); | ||
| 255 | pause_callbacks.emplace_back(std::move(callback)); | ||
| 256 | } | ||
| 257 | |||
| 221 | std::optional<s64> CoreTiming::Advance() { | 258 | std::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 @@ | |||
| 20 | namespace Core::Timing { | 20 | namespace 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. |
| 23 | using TimedCallback = | 23 | using 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)>; |
| 25 | using PauseCallback = std::function<void(bool paused)>; | ||
| 25 | 26 | ||
| 26 | /// Contains the characteristics of a particular event. | 27 | /// Contains the characteristics of a particular event. |
| 27 | struct EventType { | 28 | struct 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 | |||
| 129 | private: | 140 | private: |
| 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 | ||
| 12 | InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { | 12 | InterruptManager::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 @@ | |||
| 11 | namespace Kernel { | 11 | namespace Kernel { |
| 12 | 12 | ||
| 13 | TimeManager::TimeManager(Core::System& system_) : system{system_} { | 13 | TimeManager::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 | ||
| 25 | void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { | 27 | void 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 | ||
| 147 | void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, | 148 | void 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 | ||
| 162 | void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 156 | void 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 | ||
| 175 | class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { | 162 | class 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 | ||
| 61 | HidBus::~HidBus() { | 64 | HidBus::~HidBus() { |
| @@ -63,8 +66,6 @@ HidBus::~HidBus() { | |||
| 63 | } | 66 | } |
| 64 | 67 | ||
| 65 | void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 68 | void 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 | ||
| 94 | std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) const { | 88 | std::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 | ||
| 35 | class IBinder { | 35 | class IBinder { |
| 36 | public: | 36 | public: |
| 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() { | |||
| 184 | void CheatEngine::Initialize() { | 184 | void 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; | |||
| 25 | std::mutex control_mutex; | 26 | std::mutex control_mutex; |
| 26 | 27 | ||
| 27 | template <unsigned int IDX> | 28 | template <unsigned int IDX> |
| 28 | void HostCallbackTemplate(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 29 | std::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 | ||
| 37 | struct ScopeInit final { | 40 | struct 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 | ||
| 136 | constexpr std::array VIEW_CLASS_ASTC_10x6_RGBA{ | ||
| 137 | PixelFormat::ASTC_2D_10X6_UNORM, | ||
| 138 | }; | ||
| 139 | |||
| 137 | constexpr std::array VIEW_CLASS_ASTC_10x8_RGBA{ | 140 | constexpr 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> | |||
| 211 | void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() { | 213 | void 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 | ||