early-access version 2426

This commit is contained in:
pineappleEA 2022-01-22 03:12:16 +01:00
parent e69d3cd638
commit a4455c2612
6 changed files with 103 additions and 2 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 2425. This is the source code for early-access 2426.
## Legal Notice ## Legal Notice

View file

@ -45,6 +45,7 @@ concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) {
{ t.GetActiveCore() } -> Common::ConvertibleTo<s32>; { t.GetActiveCore() } -> Common::ConvertibleTo<s32>;
{ t.GetPriority() } -> Common::ConvertibleTo<s32>; { t.GetPriority() } -> Common::ConvertibleTo<s32>;
{ t.IsDummyThread() } -> Common::ConvertibleTo<bool>;
}; };
template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority> template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority>
@ -349,24 +350,49 @@ public:
// Mutators. // Mutators.
constexpr void PushBack(Member* member) { constexpr void PushBack(Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
this->PushBack(member->GetPriority(), member); this->PushBack(member->GetPriority(), member);
} }
constexpr void Remove(Member* member) { constexpr void Remove(Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
this->Remove(member->GetPriority(), member); this->Remove(member->GetPriority(), member);
} }
constexpr void MoveToScheduledFront(Member* member) { constexpr void MoveToScheduledFront(Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member); this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member);
} }
constexpr KThread* MoveToScheduledBack(Member* member) { constexpr KThread* MoveToScheduledBack(Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return {};
}
return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(), return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(),
member); member);
} }
// First class fancy operations. // First class fancy operations.
constexpr void ChangePriority(s32 prev_priority, bool is_running, Member* member) { constexpr void ChangePriority(s32 prev_priority, bool is_running, Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
ASSERT(IsValidPriority(prev_priority)); ASSERT(IsValidPriority(prev_priority));
// Remove the member from the queues. // Remove the member from the queues.
@ -383,6 +409,11 @@ public:
constexpr void ChangeAffinityMask(s32 prev_core, const AffinityMaskType& prev_affinity, constexpr void ChangeAffinityMask(s32 prev_core, const AffinityMaskType& prev_affinity,
Member* member) { Member* member) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
// Get the new information. // Get the new information.
const s32 priority = member->GetPriority(); const s32 priority = member->GetPriority();
const AffinityMaskType& new_affinity = member->GetAffinityMask(); const AffinityMaskType& new_affinity = member->GetAffinityMask();
@ -412,6 +443,11 @@ public:
} }
constexpr void ChangeCore(s32 prev_core, Member* member, bool to_front = false) { constexpr void ChangeCore(s32 prev_core, Member* member, bool to_front = false) {
// This is for host (dummy) threads that we do not want to enter the priority queue.
if (member->IsDummyThread()) {
return;
}
// Get the new information. // Get the new information.
const s32 new_core = member->GetActiveCore(); const s32 new_core = member->GetActiveCore();
const s32 priority = member->GetPriority(); const s32 priority = member->GetPriority();

View file

@ -406,6 +406,9 @@ void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduli
} else { } else {
RescheduleCores(kernel, cores_needing_scheduling); RescheduleCores(kernel, cores_needing_scheduling);
} }
// Special case to ensure dummy threads that are waiting block.
current_thread->IfDummyThreadTryWait();
} }
u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) {

View file

@ -1075,12 +1075,46 @@ ResultCode KThread::Sleep(s64 timeout) {
return ResultSuccess; return ResultSuccess;
} }
void KThread::IfDummyThreadTryWait() {
if (!IsDummyThread()) {
return;
}
if (GetState() != ThreadState::Waiting) {
return;
}
// Block until we can grab the lock.
KScopedSpinLock lk{dummy_wait_lock};
}
void KThread::IfDummyThreadBeginWait() {
if (!IsDummyThread()) {
return;
}
// Ensure the thread will block when IfDummyThreadTryWait is called.
dummy_wait_lock.Lock();
}
void KThread::IfDummyThreadEndWait() {
if (!IsDummyThread()) {
return;
}
// Ensure the thread will no longer block.
dummy_wait_lock.Unlock();
}
void KThread::BeginWait(KThreadQueue* queue) { void KThread::BeginWait(KThreadQueue* queue) {
// Set our state as waiting. // Set our state as waiting.
SetState(ThreadState::Waiting); SetState(ThreadState::Waiting);
// Set our wait queue. // Set our wait queue.
wait_queue = queue; wait_queue = queue;
// Special case for dummy threads to ensure they block.
IfDummyThreadBeginWait();
} }
void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) {
@ -1106,6 +1140,9 @@ void KThread::EndWait(ResultCode wait_result_) {
} }
wait_queue->EndWait(this, wait_result_); wait_queue->EndWait(this, wait_result_);
// Special case for dummy threads to wakeup if necessary.
IfDummyThreadEndWait();
} }
} }

View file

@ -558,6 +558,10 @@ public:
return thread_type; return thread_type;
} }
[[nodiscard]] bool IsDummyThread() const {
return GetThreadType() == ThreadType::Dummy;
}
void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) {
wait_objects_for_debugging.clear(); wait_objects_for_debugging.clear();
wait_objects_for_debugging.reserve(objects.size()); wait_objects_for_debugging.reserve(objects.size());
@ -632,6 +636,14 @@ public:
return condvar_key; return condvar_key;
} }
// Dummy threads (used for HLE host threads) cannot wait based on the guest scheduler, and
// therefore will not block on guest kernel synchronization primitives. These methods handle
// blocking as needed.
void IfDummyThreadTryWait();
void IfDummyThreadBeginWait();
void IfDummyThreadEndWait();
private: private:
static constexpr size_t PriorityInheritanceCountMax = 10; static constexpr size_t PriorityInheritanceCountMax = 10;
union SyncObjectBuffer { union SyncObjectBuffer {
@ -750,6 +762,7 @@ private:
bool resource_limit_release_hint{}; bool resource_limit_release_hint{};
StackParameters stack_parameters{}; StackParameters stack_parameters{};
KSpinLock context_guard{}; KSpinLock context_guard{};
KSpinLock dummy_wait_lock{};
// For emulation // For emulation
std::shared_ptr<Common::Fiber> host_context{}; std::shared_ptr<Common::Fiber> host_context{};

View file

@ -17,7 +17,7 @@ public:
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"}, {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"},
{1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"}, {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"},
{2, nullptr, "SetCpuOverclockEnabled"}, {2, &ISession::SetCpuOverclockEnabled, "SetCpuOverclockEnabled"},
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
} }
@ -47,6 +47,18 @@ private:
rb.PushEnum(controller.GetCurrentPerformanceConfiguration(mode)); rb.PushEnum(controller.GetCurrentPerformanceConfiguration(mode));
} }
void SetCpuOverclockEnabled(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto cpu_overclock_enabled = rp.Pop<bool>();
LOG_WARNING(Service_APM, "(STUBBED) called, cpu_overclock_enabled={}",
cpu_overclock_enabled);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
Controller& controller; Controller& controller;
}; };