aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpineappleEA <pineaea@gmail.com>2024-02-12 05:52:53 +0100
committerpineappleEA <pineaea@gmail.com>2024-02-12 05:52:53 +0100
commit765c7bb93a5d63d9ea54d1679f2d1b0c000d26f0 (patch)
treef2b93cfc2e2be9738117584c74ee8632d5d1e08b
parent9d83e9ad1b1431b81fab4b5bc84d3e9c1462d933 (diff)
early-access version 4134EA-4134
-rwxr-xr-xREADME.md2
-rwxr-xr-xsrc/core/hle/service/bcat/news/newly_arrived_event_holder.cpp2
-rwxr-xr-xsrc/core/hle/service/bcat/news/news_database_service.cpp24
-rwxr-xr-xsrc/core/hle/service/bcat/news/news_database_service.h8
-rwxr-xr-xsrc/core/hle/service/bcat/news/news_service.cpp17
-rwxr-xr-xsrc/core/hle/service/bcat/news/news_service.h4
-rwxr-xr-xsrc/core/hle/service/bcat/news/overwrite_event_holder.cpp2
-rwxr-xr-xsrc/core/hle/service/bcat/news/service_creator.cpp10
-rwxr-xr-xsrc/video_core/control/scheduler.cpp149
-rwxr-xr-xsrc/video_core/control/scheduler.h1
-rwxr-xr-xsrc/video_core/texture_cache/image_info.cpp1
-rwxr-xr-xsrc/video_core/texture_cache/image_info.h1
-rwxr-xr-xsrc/video_core/texture_cache/texture_cache.h15
-rwxr-xr-xsrc/yuzu/hotkeys.cpp6
14 files changed, 163 insertions, 79 deletions
diff --git a/README.md b/README.md
index 5bb2c9dd8..10fd85b8d 100755
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
1yuzu emulator early access 1yuzu emulator early access
2============= 2=============
3 3
4This is the source code for early-access 4132. 4This is the source code for early-access 4134.
5 5
6## Legal Notice 6## Legal Notice
7 7
diff --git a/src/core/hle/service/bcat/news/newly_arrived_event_holder.cpp b/src/core/hle/service/bcat/news/newly_arrived_event_holder.cpp
index 5be167fce..ed393f7a2 100755
--- a/src/core/hle/service/bcat/news/newly_arrived_event_holder.cpp
+++ b/src/core/hle/service/bcat/news/newly_arrived_event_holder.cpp
@@ -12,7 +12,7 @@ INewlyArrivedEventHolder::INewlyArrivedEventHolder(Core::System& system_)
12 "INewlyArrivedEventHolder"} { 12 "INewlyArrivedEventHolder"} {
13 // clang-format off 13 // clang-format off
14 static const FunctionInfo functions[] = { 14 static const FunctionInfo functions[] = {
15 {0, C<&INewlyArrivedEventHolder::Get>, "Get"}, 15 {0, D<&INewlyArrivedEventHolder::Get>, "Get"},
16 }; 16 };
17 // clang-format on 17 // clang-format on
18 18
diff --git a/src/core/hle/service/bcat/news/news_database_service.cpp b/src/core/hle/service/bcat/news/news_database_service.cpp
index 18109f9b0..b94ef0636 100755
--- a/src/core/hle/service/bcat/news/news_database_service.cpp
+++ b/src/core/hle/service/bcat/news/news_database_service.cpp
@@ -11,12 +11,12 @@ INewsDatabaseService::INewsDatabaseService(Core::System& system_)
11 // clang-format off 11 // clang-format off
12 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
13 {0, nullptr, "GetListV1"}, 13 {0, nullptr, "GetListV1"},
14 {1, C<&INewsDatabaseService::Count>, "Count"}, 14 {1, D<&INewsDatabaseService::Count>, "Count"},
15 {2, nullptr, "CountWithKey"}, 15 {2, nullptr, "CountWithKey"},
16 {3, nullptr, "UpdateIntegerValue"}, 16 {3, nullptr, "UpdateIntegerValue"},
17 {4, nullptr, "UpdateIntegerValueWithAddition"}, 17 {4, D<&INewsDatabaseService::UpdateIntegerValueWithAddition>, "UpdateIntegerValueWithAddition"},
18 {5, nullptr, "UpdateStringValue"}, 18 {5, nullptr, "UpdateStringValue"},
19 {1000, nullptr, "GetList"}, 19 {1000, D<&INewsDatabaseService::GetList>, "GetList"},
20 }; 20 };
21 // clang-format on 21 // clang-format on
22 22
@@ -32,4 +32,22 @@ Result INewsDatabaseService::Count(Out<s32> out_count,
32 R_SUCCEED(); 32 R_SUCCEED();
33} 33}
34 34
35Result INewsDatabaseService::UpdateIntegerValueWithAddition(
36 u32 value, InBuffer<BufferAttr_HipcPointer> buffer_data_1,
37 InBuffer<BufferAttr_HipcPointer> buffer_data_2) {
38 LOG_WARNING(Service_BCAT, "(STUBBED) called, value={}, buffer_size_1={}, buffer_data_2={}",
39 value, buffer_data_1.size(), buffer_data_2.size());
40 R_SUCCEED();
41}
42
43Result INewsDatabaseService::GetList(Out<s32> out_count, u32 value,
44 OutBuffer<BufferAttr_HipcMapAlias> out_buffer_data,
45 InBuffer<BufferAttr_HipcPointer> buffer_data_1,
46 InBuffer<BufferAttr_HipcPointer> buffer_data_2) {
47 LOG_WARNING(Service_BCAT, "(STUBBED) called, value={}, buffer_size_1={}, buffer_data_2={}",
48 value, buffer_data_1.size(), buffer_data_2.size());
49 *out_count = 0;
50 R_SUCCEED();
51}
52
35} // namespace Service::News 53} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/news_database_service.h b/src/core/hle/service/bcat/news/news_database_service.h
index f5916634b..860b7074c 100755
--- a/src/core/hle/service/bcat/news/news_database_service.h
+++ b/src/core/hle/service/bcat/news/news_database_service.h
@@ -19,6 +19,14 @@ public:
19 19
20private: 20private:
21 Result Count(Out<s32> out_count, InBuffer<BufferAttr_HipcPointer> buffer_data); 21 Result Count(Out<s32> out_count, InBuffer<BufferAttr_HipcPointer> buffer_data);
22
23 Result UpdateIntegerValueWithAddition(u32 value, InBuffer<BufferAttr_HipcPointer> buffer_data_1,
24 InBuffer<BufferAttr_HipcPointer> buffer_data_2);
25
26 Result GetList(Out<s32> out_count, u32 value,
27 OutBuffer<BufferAttr_HipcMapAlias> out_buffer_data,
28 InBuffer<BufferAttr_HipcPointer> buffer_data_1,
29 InBuffer<BufferAttr_HipcPointer> buffer_data_2);
22}; 30};
23 31
24} // namespace Service::News 32} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/news_service.cpp b/src/core/hle/service/bcat/news/news_service.cpp
index e19cea7b5..bc6c2afd2 100755
--- a/src/core/hle/service/bcat/news/news_service.cpp
+++ b/src/core/hle/service/bcat/news/news_service.cpp
@@ -11,10 +11,10 @@ INewsService::INewsService(Core::System& system_) : ServiceFramework{system_, "I
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {10100, nullptr, "PostLocalNews"}, 12 {10100, nullptr, "PostLocalNews"},
13 {20100, nullptr, "SetPassphrase"}, 13 {20100, nullptr, "SetPassphrase"},
14 {30100, C<&INewsService::GetSubscriptionStatus>, "GetSubscriptionStatus"}, 14 {30100, D<&INewsService::GetSubscriptionStatus>, "GetSubscriptionStatus"},
15 {30101, nullptr, "GetTopicList"}, 15 {30101, nullptr, "GetTopicList"},
16 {30110, nullptr, "Unknown30110"}, 16 {30110, nullptr, "Unknown30110"},
17 {30200, nullptr, "IsSystemUpdateRequired"}, 17 {30200, D<&INewsService::IsSystemUpdateRequired>, "IsSystemUpdateRequired"},
18 {30201, nullptr, "Unknown30201"}, 18 {30201, nullptr, "Unknown30201"},
19 {30210, nullptr, "Unknown30210"}, 19 {30210, nullptr, "Unknown30210"},
20 {30300, nullptr, "RequestImmediateReception"}, 20 {30300, nullptr, "RequestImmediateReception"},
@@ -24,7 +24,7 @@ INewsService::INewsService(Core::System& system_) : ServiceFramework{system_, "I
24 {30901, nullptr, "Unknown30901"}, 24 {30901, nullptr, "Unknown30901"},
25 {30902, nullptr, "Unknown30902"}, 25 {30902, nullptr, "Unknown30902"},
26 {40100, nullptr, "SetSubscriptionStatus"}, 26 {40100, nullptr, "SetSubscriptionStatus"},
27 {40101, nullptr, "RequestAutoSubscription"}, 27 {40101, D<&INewsService::RequestAutoSubscription>, "RequestAutoSubscription"},
28 {40200, nullptr, "ClearStorage"}, 28 {40200, nullptr, "ClearStorage"},
29 {40201, nullptr, "ClearSubscriptionStatusAll"}, 29 {40201, nullptr, "ClearSubscriptionStatusAll"},
30 {90100, nullptr, "GetNewsDatabaseDump"}, 30 {90100, nullptr, "GetNewsDatabaseDump"},
@@ -43,4 +43,15 @@ Result INewsService::GetSubscriptionStatus(Out<u32> out_status,
43 R_SUCCEED(); 43 R_SUCCEED();
44} 44}
45 45
46Result INewsService::IsSystemUpdateRequired(Out<bool> out_is_system_update_required) {
47 LOG_WARNING(Service_BCAT, "(STUBBED) called");
48 *out_is_system_update_required = false;
49 R_SUCCEED();
50}
51
52Result INewsService::RequestAutoSubscription(u64 value) {
53 LOG_WARNING(Service_BCAT, "(STUBBED) called");
54 R_SUCCEED();
55}
56
46} // namespace Service::News 57} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/news_service.h b/src/core/hle/service/bcat/news/news_service.h
index 8d06be9d6..f1716a302 100755
--- a/src/core/hle/service/bcat/news/news_service.h
+++ b/src/core/hle/service/bcat/news/news_service.h
@@ -19,6 +19,10 @@ public:
19 19
20private: 20private:
21 Result GetSubscriptionStatus(Out<u32> out_status, InBuffer<BufferAttr_HipcPointer> buffer_data); 21 Result GetSubscriptionStatus(Out<u32> out_status, InBuffer<BufferAttr_HipcPointer> buffer_data);
22
23 Result IsSystemUpdateRequired(Out<bool> out_is_system_update_required);
24
25 Result RequestAutoSubscription(u64 value);
22}; 26};
23 27
24} // namespace Service::News 28} // namespace Service::News
diff --git a/src/core/hle/service/bcat/news/overwrite_event_holder.cpp b/src/core/hle/service/bcat/news/overwrite_event_holder.cpp
index c32a5ca8f..1712971e4 100755
--- a/src/core/hle/service/bcat/news/overwrite_event_holder.cpp
+++ b/src/core/hle/service/bcat/news/overwrite_event_holder.cpp
@@ -11,7 +11,7 @@ IOverwriteEventHolder::IOverwriteEventHolder(Core::System& system_)
11 "IOverwriteEventHolder"} { 11 "IOverwriteEventHolder"} {
12 // clang-format off 12 // clang-format off
13 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
14 {0, C<&IOverwriteEventHolder::Get>, "Get"}, 14 {0, D<&IOverwriteEventHolder::Get>, "Get"},
15 }; 15 };
16 // clang-format on 16 // clang-format on
17 17
diff --git a/src/core/hle/service/bcat/news/service_creator.cpp b/src/core/hle/service/bcat/news/service_creator.cpp
index d5ba5dff7..a1b22c004 100755
--- a/src/core/hle/service/bcat/news/service_creator.cpp
+++ b/src/core/hle/service/bcat/news/service_creator.cpp
@@ -15,11 +15,11 @@ IServiceCreator::IServiceCreator(Core::System& system_, u32 permissions_, const
15 : ServiceFramework{system_, name_}, permissions{permissions_} { 15 : ServiceFramework{system_, name_}, permissions{permissions_} {
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, C<&IServiceCreator::CreateNewsService>, "CreateNewsService"}, 18 {0, D<&IServiceCreator::CreateNewsService>, "CreateNewsService"},
19 {1, C<&IServiceCreator::CreateNewlyArrivedEventHolder>, "CreateNewlyArrivedEventHolder"}, 19 {1, D<&IServiceCreator::CreateNewlyArrivedEventHolder>, "CreateNewlyArrivedEventHolder"},
20 {2, C<&IServiceCreator::CreateNewsDataService>, "CreateNewsDataService"}, 20 {2, D<&IServiceCreator::CreateNewsDataService>, "CreateNewsDataService"},
21 {3, C<&IServiceCreator::CreateNewsDatabaseService>, "CreateNewsDatabaseService"}, 21 {3, D<&IServiceCreator::CreateNewsDatabaseService>, "CreateNewsDatabaseService"},
22 {4, C<&IServiceCreator::CreateOverwriteEventHolder>, "CreateOverwriteEventHolder"}, 22 {4, D<&IServiceCreator::CreateOverwriteEventHolder>, "CreateOverwriteEventHolder"},
23 }; 23 };
24 // clang-format on 24 // clang-format on
25 25
diff --git a/src/video_core/control/scheduler.cpp b/src/video_core/control/scheduler.cpp
index 91d81500a..f57efd189 100755
--- a/src/video_core/control/scheduler.cpp
+++ b/src/video_core/control/scheduler.cpp
@@ -7,6 +7,7 @@
7#include <memory> 7#include <memory>
8#include <mutex> 8#include <mutex>
9#include <unordered_map> 9#include <unordered_map>
10#include <utility>
10 11
11#include "common/assert.h" 12#include "common/assert.h"
12#include "common/fiber.h" 13#include "common/fiber.h"
@@ -53,29 +54,30 @@ void Scheduler::Init() {
53} 54}
54 55
55void Scheduler::Resume() { 56void Scheduler::Resume() {
56 bool pending_work; 57 while (UpdateHighestPriorityChannel()) {
57 do { 58 impl->current_fifo->scheduled_count++;
58 pending_work = false; 59 Common::Fiber::YieldTo(impl->master_control, *impl->current_fifo->context);
59 { 60 }
60 std::unique_lock lk(impl->scheduling_guard); 61}
61 impl->current_fifo = nullptr; 62
62 auto it = impl->schedule_priority_queue.begin(); 63bool Scheduler::UpdateHighestPriorityChannel() {
63 while (it != impl->schedule_priority_queue.end()) { 64 std::scoped_lock lk(impl->scheduling_guard);
64 pending_work = ScheduleLevel(it->second); 65
65 if (pending_work) { 66 // Clear needs to schedule state.
66 break; 67 impl->must_reschedule = false;
67 } 68
68 it = std::next(it); 69 // By default, we don't have a channel to schedule.
69 } 70 impl->current_fifo = nullptr;
70 if (pending_work) { 71
71 impl->must_reschedule = false; 72 // Check each level to see if we can schedule.
72 } 73 for (auto& level : impl->schedule_priority_queue) {
73 } 74 if (ScheduleLevel(level.second)) {
74 if (impl->current_fifo) { 75 return true;
75 impl->current_fifo->scheduled_count++;
76 Common::Fiber::YieldTo(impl->master_control, *impl->current_fifo->context);
77 } 76 }
78 } while (pending_work); 77 }
78
79 // Nothing to schedule.
80 return false;
79} 81}
80 82
81bool Scheduler::ScheduleLevel(std::list<size_t>& queue) { 83bool Scheduler::ScheduleLevel(std::list<size_t>& queue) {
@@ -83,34 +85,48 @@ bool Scheduler::ScheduleLevel(std::list<size_t>& queue) {
83 size_t min_schedule_count = std::numeric_limits<size_t>::max(); 85 size_t min_schedule_count = std::numeric_limits<size_t>::max();
84 for (auto id : queue) { 86 for (auto id : queue) {
85 auto& fifo = impl->gpfifos[id]; 87 auto& fifo = impl->gpfifos[id];
86 std::scoped_lock lk2(fifo.guard); 88 std::scoped_lock lk(fifo.guard);
87 if (!fifo.pending_work.empty() || fifo.is_running) { 89
88 if (fifo.scheduled_count > min_schedule_count) { 90 // With no pending work and nothing running, this channel can't be scheduled.
89 continue; 91 if (fifo.pending_work.empty() && !fifo.is_running) {
90 } 92 continue;
91 if (fifo.scheduled_count < fifo.yield_count) { 93 }
92 fifo.scheduled_count++; 94 // Prioritize channels at current priority which have been run the least.
93 continue; 95 if (fifo.scheduled_count > min_schedule_count) {
94 } 96 continue;
95 min_schedule_count = fifo.scheduled_count;
96 impl->current_fifo = &fifo;
97 found_anything = true;
98 } 97 }
98
99 // Try not to select the same channel we just yielded from.
100 if (fifo.scheduled_count < fifo.yield_count) {
101 fifo.scheduled_count++;
102 continue;
103 }
104
105 // Update best selection.
106 min_schedule_count = fifo.scheduled_count;
107 impl->current_fifo = &fifo;
108 found_anything = true;
99 } 109 }
100 return found_anything; 110 return found_anything;
101} 111}
102 112
103void Scheduler::ChangePriority(s32 channel_id, u32 new_priority) { 113void Scheduler::ChangePriority(s32 channel_id, u32 new_priority) {
104 std::unique_lock lk(impl->scheduling_guard); 114 std::scoped_lock lk(impl->scheduling_guard);
115 // Ensure we are tracking this channel.
105 auto fifo_it = impl->channel_gpfifo_ids.find(channel_id); 116 auto fifo_it = impl->channel_gpfifo_ids.find(channel_id);
106 if (fifo_it == impl->channel_gpfifo_ids.end()) { 117 if (fifo_it == impl->channel_gpfifo_ids.end()) {
107 return; 118 return;
108 } 119 }
120
121 // Get the fifo and update its priority.
109 const size_t fifo_id = fifo_it->second; 122 const size_t fifo_id = fifo_it->second;
110 auto& fifo = impl->gpfifos[fifo_id]; 123 auto& fifo = impl->gpfifos[fifo_id];
111 const auto old_priority = fifo.info->priority; 124 const auto old_priority = std::exchange(fifo.info->priority, new_priority);
112 fifo.info->priority = new_priority; 125
126 // Create the new level if needed.
113 impl->schedule_priority_queue.try_emplace(new_priority); 127 impl->schedule_priority_queue.try_emplace(new_priority);
128
129 // Remove the old level and add to the new level.
114 impl->schedule_priority_queue[new_priority].push_back(fifo_id); 130 impl->schedule_priority_queue[new_priority].push_back(fifo_id);
115 impl->schedule_priority_queue[old_priority].remove_if( 131 impl->schedule_priority_queue[old_priority].remove_if(
116 [fifo_id](size_t id) { return id == fifo_id; }); 132 [fifo_id](size_t id) { return id == fifo_id; });
@@ -118,6 +134,8 @@ void Scheduler::ChangePriority(s32 channel_id, u32 new_priority) {
118 134
119void Scheduler::Yield() { 135void Scheduler::Yield() {
120 ASSERT(impl->current_fifo != nullptr); 136 ASSERT(impl->current_fifo != nullptr);
137
138 // Set yield count higher
121 impl->current_fifo->yield_count = impl->current_fifo->scheduled_count + 1; 139 impl->current_fifo->yield_count = impl->current_fifo->scheduled_count + 1;
122 Common::Fiber::YieldTo(impl->current_fifo->context, *impl->master_control); 140 Common::Fiber::YieldTo(impl->current_fifo->context, *impl->master_control);
123 gpu.BindChannel(impl->current_fifo->bind_id); 141 gpu.BindChannel(impl->current_fifo->bind_id);
@@ -126,50 +144,73 @@ void Scheduler::Yield() {
126void Scheduler::CheckStatus() { 144void Scheduler::CheckStatus() {
127 { 145 {
128 std::unique_lock lk(impl->scheduling_guard); 146 std::unique_lock lk(impl->scheduling_guard);
147 // If no reschedule is needed, don't transfer control
129 if (!impl->must_reschedule) { 148 if (!impl->must_reschedule) {
130 return; 149 return;
131 } 150 }
132 } 151 }
152 // Transfer control to the scheduler
133 Common::Fiber::YieldTo(impl->current_fifo->context, *impl->master_control); 153 Common::Fiber::YieldTo(impl->current_fifo->context, *impl->master_control);
134 gpu.BindChannel(impl->current_fifo->bind_id); 154 gpu.BindChannel(impl->current_fifo->bind_id);
135} 155}
136 156
137void Scheduler::Push(s32 channel, CommandList&& entries) { 157void Scheduler::Push(s32 channel, CommandList&& entries) {
138 std::unique_lock lk(impl->scheduling_guard); 158 std::scoped_lock lk(impl->scheduling_guard);
159 // Get and ensure we have this channel.
139 auto it = impl->channel_gpfifo_ids.find(channel); 160 auto it = impl->channel_gpfifo_ids.find(channel);
140 ASSERT(it != impl->channel_gpfifo_ids.end()); 161 ASSERT(it != impl->channel_gpfifo_ids.end());
141 auto gpfifo_id = it->second; 162 auto gpfifo_id = it->second;
142 auto& fifo = impl->gpfifos[gpfifo_id]; 163 auto& fifo = impl->gpfifos[gpfifo_id];
164 // Add the new new work to the channel.
143 { 165 {
144 std::scoped_lock lk2(fifo.guard); 166 std::scoped_lock lk2(fifo.guard);
145 fifo.pending_work.emplace_back(std::move(entries)); 167 fifo.pending_work.emplace_back(std::move(entries));
146 } 168 }
147 if (impl->current_fifo != nullptr && impl->current_fifo->info->priority < fifo.info->priority) { 169
148 impl->must_reschedule = true; 170 // If the current running FIFO is null or the one being pushed to then
171 // just return
172 if (impl->current_fifo == nullptr || impl->current_fifo == &fifo) {
173 return;
174 }
175
176 // If the current fifo has higher or equal priority to the current fifo then return
177 if (impl->current_fifo->info->priority >= fifo.info->priority) {
178 return;
149 } 179 }
180 // Mark scheduler update as required.
181 impl->must_reschedule = true;
150} 182}
151 183
152void Scheduler::ChannelLoop(size_t gpfifo_id, s32 channel_id) { 184void Scheduler::ChannelLoop(size_t gpfifo_id, s32 channel_id) {
153 gpu.BindChannel(channel_id);
154 auto& fifo = impl->gpfifos[gpfifo_id]; 185 auto& fifo = impl->gpfifos[gpfifo_id];
186 auto* channel_state = fifo.info.get();
187 const auto SendToPuller = [&] {
188 std::scoped_lock lk(fifo.guard);
189 if (fifo.pending_work.empty()) {
190 // Stop if no work available.
191 fifo.is_running = false;
192 return false;
193 }
194 // Otherwise, send work to puller and mark as running.
195 CommandList&& entries = std::move(fifo.pending_work.front());
196 channel_state->dma_pusher->Push(std::move(entries));
197 fifo.pending_work.pop_front();
198 fifo.is_running = true;
199 // Succeed.
200 return true;
201 };
202 // Inform the GPU about the current channel.
203 gpu.BindChannel(channel_id);
155 while (true) { 204 while (true) {
156 auto* channel_state = fifo.info.get(); 205 while (SendToPuller()) {
157 fifo.guard.lock(); 206 // Execute.
158 while (!fifo.pending_work.empty()) {
159 fifo.is_running = true;
160 {
161 CommandList&& entries = std::move(fifo.pending_work.front());
162 channel_state->dma_pusher->Push(std::move(entries));
163 fifo.pending_work.pop_front();
164 }
165 fifo.guard.unlock();
166 channel_state->dma_pusher->DispatchCalls(); 207 channel_state->dma_pusher->DispatchCalls();
208 // Reschedule.
167 CheckStatus(); 209 CheckStatus();
168 fifo.guard.lock();
169 } 210 }
170 fifo.is_running = false; 211 // Return to host execution when all work is completed.
171 fifo.guard.unlock();
172 Common::Fiber::YieldTo(fifo.context, *impl->master_control); 212 Common::Fiber::YieldTo(fifo.context, *impl->master_control);
213 // Inform the GPU about the current channel.
173 gpu.BindChannel(channel_id); 214 gpu.BindChannel(channel_id);
174 } 215 }
175} 216}
diff --git a/src/video_core/control/scheduler.h b/src/video_core/control/scheduler.h
index faa888dde..9b5620499 100755
--- a/src/video_core/control/scheduler.h
+++ b/src/video_core/control/scheduler.h
@@ -39,6 +39,7 @@ private:
39 void ChannelLoop(size_t gpfifo_id, s32 channel_id); 39 void ChannelLoop(size_t gpfifo_id, s32 channel_id);
40 bool ScheduleLevel(std::list<size_t>& queue); 40 bool ScheduleLevel(std::list<size_t>& queue);
41 void CheckStatus(); 41 void CheckStatus();
42 bool UpdateHighestPriorityChannel();
42 43
43 struct SchedulerImpl; 44 struct SchedulerImpl;
44 std::unique_ptr<SchedulerImpl> impl; 45 std::unique_ptr<SchedulerImpl> impl;
diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp
index 22eb7bd00..4cfaf7ce6 100755
--- a/src/video_core/texture_cache/image_info.cpp
+++ b/src/video_core/texture_cache/image_info.cpp
@@ -42,6 +42,7 @@ ImageInfo::ImageInfo(const TICEntry& config) noexcept {
42 }; 42 };
43 } 43 }
44 rescaleable = false; 44 rescaleable = false;
45 is_sparse = config.is_sparse != 0;
45 tile_width_spacing = config.tile_width_spacing; 46 tile_width_spacing = config.tile_width_spacing;
46 if (config.texture_type != TextureType::Texture2D && 47 if (config.texture_type != TextureType::Texture2D &&
47 config.texture_type != TextureType::Texture2DNoMipmap) { 48 config.texture_type != TextureType::Texture2DNoMipmap) {
diff --git a/src/video_core/texture_cache/image_info.h b/src/video_core/texture_cache/image_info.h
index 0a50795b3..286457acc 100755
--- a/src/video_core/texture_cache/image_info.h
+++ b/src/video_core/texture_cache/image_info.h
@@ -41,6 +41,7 @@ struct ImageInfo {
41 bool downscaleable = false; 41 bool downscaleable = false;
42 bool forced_flushed = false; 42 bool forced_flushed = false;
43 bool dma_downloaded = false; 43 bool dma_downloaded = false;
44 bool is_sparse = false;
44}; 45};
45 46
46} // namespace VideoCommon 47} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 85046e708..47ea0bd96 100755
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -600,17 +600,17 @@ void TextureCache<P>::UnmapGPUMemory(size_t as_id, GPUVAddr gpu_addr, size_t siz
600 [&](ImageId id, Image&) { deleted_images.push_back(id); }); 600 [&](ImageId id, Image&) { deleted_images.push_back(id); });
601 for (const ImageId id : deleted_images) { 601 for (const ImageId id : deleted_images) {
602 Image& image = slot_images[id]; 602 Image& image = slot_images[id];
603 if (True(image.flags & ImageFlagBits::CpuModified)) { 603 if (False(image.flags & ImageFlagBits::CpuModified)) {
604 continue; 604 image.flags |= ImageFlagBits::CpuModified;
605 if (True(image.flags & ImageFlagBits::Tracked)) {
606 UntrackImage(image, id);
607 }
605 } 608 }
606 image.flags |= ImageFlagBits::CpuModified; 609
607 if (True(image.flags & ImageFlagBits::Remapped)) { 610 if (True(image.flags & ImageFlagBits::Remapped)) {
608 continue; 611 continue;
609 } 612 }
610 image.flags |= ImageFlagBits::Remapped; 613 image.flags |= ImageFlagBits::Remapped;
611 if (True(image.flags & ImageFlagBits::Tracked)) {
612 UntrackImage(image, id);
613 }
614 } 614 }
615} 615}
616 616
@@ -1469,7 +1469,8 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA
1469 const ImageId new_image_id = slot_images.insert(runtime, new_info, gpu_addr, cpu_addr); 1469 const ImageId new_image_id = slot_images.insert(runtime, new_info, gpu_addr, cpu_addr);
1470 Image& new_image = slot_images[new_image_id]; 1470 Image& new_image = slot_images[new_image_id];
1471 1471
1472 if (!gpu_memory->IsContinuousRange(new_image.gpu_addr, new_image.guest_size_bytes)) { 1472 if (!gpu_memory->IsContinuousRange(new_image.gpu_addr, new_image.guest_size_bytes) &&
1473 new_info.is_sparse) {
1473 new_image.flags |= ImageFlagBits::Sparse; 1474 new_image.flags |= ImageFlagBits::Sparse;
1474 } 1475 }
1475 1476
diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp
index 988bc7409..4bcc6ab04 100755
--- a/src/yuzu/hotkeys.cpp
+++ b/src/yuzu/hotkeys.cpp
@@ -190,10 +190,8 @@ void ControllerShortcut::ControllerUpdateEvent(Core::HID::ControllerTriggerType
190 if (type != Core::HID::ControllerTriggerType::Button) { 190 if (type != Core::HID::ControllerTriggerType::Button) {
191 return; 191 return;
192 } 192 }
193 if (!Settings::values.controller_navigation) { 193 if (button_sequence.npad.raw == Core::HID::NpadButton::None &&
194 return; 194 button_sequence.capture.raw == 0 && button_sequence.home.raw == 0) {
195 }
196 if (button_sequence.npad.raw == Core::HID::NpadButton::None) {
197 return; 195 return;
198 } 196 }
199 197