From 3308f3bac87ca499bcd06a493bc71f43b0256738 Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Thu, 8 Feb 2024 19:42:31 +0100 Subject: [PATCH] early-access version 4123 --- README.md | 2 +- src/core/CMakeLists.txt | 13 +- src/core/hle/service/am/applet.h | 2 +- src/core/hle/service/am/applet_data_broker.h | 2 +- src/core/hle/service/glue/time/worker.cpp | 130 ++--- src/core/hle/service/os/event.cpp | 31 ++ src/core/hle/service/os/event.h | 31 ++ src/core/hle/service/os/multi_wait.cpp | 59 +++ src/core/hle/service/os/multi_wait.h | 36 ++ src/core/hle/service/os/multi_wait_holder.cpp | 25 + src/core/hle/service/os/multi_wait_holder.h | 44 ++ src/core/hle/service/os/multi_wait_utils.h | 109 +++++ src/core/hle/service/os/mutex.cpp | 46 ++ src/core/hle/service/os/mutex.h | 31 ++ src/core/hle/service/server_manager.cpp | 460 ++++++++---------- src/core/hle/service/server_manager.h | 59 ++- .../backend/spirv/emit_spirv_image.cpp | 41 +- .../backend/spirv/emit_spirv_instructions.h | 4 +- src/video_core/host1x/codecs/decoder.cpp | 8 +- src/video_core/host1x/codecs/decoder.h | 2 +- src/video_core/host1x/codecs/h264.cpp | 4 +- src/video_core/host1x/codecs/h264.h | 4 +- src/video_core/host1x/host1x.h | 15 +- src/video_core/host1x/nvdec.cpp | 1 - src/video_core/host1x/vic.cpp | 5 +- 25 files changed, 750 insertions(+), 414 deletions(-) create mode 100755 src/core/hle/service/os/event.cpp create mode 100755 src/core/hle/service/os/event.h create mode 100755 src/core/hle/service/os/multi_wait.cpp create mode 100755 src/core/hle/service/os/multi_wait.h create mode 100755 src/core/hle/service/os/multi_wait_holder.cpp create mode 100755 src/core/hle/service/os/multi_wait_holder.h create mode 100755 src/core/hle/service/os/multi_wait_utils.h create mode 100755 src/core/hle/service/os/mutex.cpp create mode 100755 src/core/hle/service/os/mutex.h diff --git a/README.md b/README.md index c62c39d26..0bfd8d3c3 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 4122. +This is the source code for early-access 4123. ## Legal Notice diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 9547462bc..5b2de4ab7 100755 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -548,8 +548,6 @@ add_library(core STATIC hle/service/es/es.h hle/service/eupld/eupld.cpp hle/service/eupld/eupld.h - hle/service/event.cpp - hle/service/event.h hle/service/fatal/fatal.cpp hle/service/fatal/fatal.h hle/service/fatal/fatal_p.cpp @@ -676,8 +674,6 @@ add_library(core STATIC hle/service/mm/mm_u.h hle/service/mnpp/mnpp_app.cpp hle/service/mnpp/mnpp_app.h - hle/service/mutex.cpp - hle/service/mutex.h hle/service/ncm/ncm.cpp hle/service/ncm/ncm.h hle/service/nfc/common/amiibo_crypto.cpp @@ -790,6 +786,15 @@ add_library(core STATIC hle/service/nvnflinger/window.h hle/service/olsc/olsc.cpp hle/service/olsc/olsc.h + hle/service/os/event.cpp + hle/service/os/event.h + hle/service/os/multi_wait_holder.cpp + hle/service/os/multi_wait_holder.h + hle/service/os/multi_wait_utils.h + hle/service/os/multi_wait.cpp + hle/service/os/multi_wait.h + hle/service/os/mutex.cpp + hle/service/os/mutex.h hle/service/pcie/pcie.cpp hle/service/pcie/pcie.h hle/service/pctl/pctl.cpp diff --git a/src/core/hle/service/am/applet.h b/src/core/hle/service/am/applet.h index bce6f9050..b29ecdfed 100755 --- a/src/core/hle/service/am/applet.h +++ b/src/core/hle/service/am/applet.h @@ -9,8 +9,8 @@ #include "common/math_util.h" #include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/caps/caps_types.h" -#include "core/hle/service/event.h" #include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/os/event.h" #include "core/hle/service/service.h" #include "core/hle/service/am/am_types.h" diff --git a/src/core/hle/service/am/applet_data_broker.h b/src/core/hle/service/am/applet_data_broker.h index 12326fd04..5a1d43c11 100755 --- a/src/core/hle/service/am/applet_data_broker.h +++ b/src/core/hle/service/am/applet_data_broker.h @@ -7,8 +7,8 @@ #include #include -#include "core/hle/service/event.h" #include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/os/event.h" union Result; diff --git a/src/core/hle/service/glue/time/worker.cpp b/src/core/hle/service/glue/time/worker.cpp index f44f3077e..8787f2dcd 100755 --- a/src/core/hle/service/glue/time/worker.cpp +++ b/src/core/hle/service/glue/time/worker.cpp @@ -7,6 +7,7 @@ #include "core/hle/service/glue/time/file_timestamp_worker.h" #include "core/hle/service/glue/time/standard_steady_clock_resource.h" #include "core/hle/service/glue/time/worker.h" +#include "core/hle/service/os/multi_wait_utils.h" #include "core/hle/service/psc/time/common.h" #include "core/hle/service/psc/time/service_manager.h" #include "core/hle/service/psc/time/static.h" @@ -143,82 +144,46 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) { Common::SetCurrentThreadName("TimeWorker"); Common::SetCurrentThreadPriority(Common::ThreadPriority::Low); - enum class EventType { - Exit = 0, - IpmModuleService_GetEvent = 1, - PowerStateChange = 2, - SignalAlarms = 3, - UpdateLocalSystemClock = 4, - UpdateNetworkSystemClock = 5, - UpdateEphemeralSystemClock = 6, - UpdateSteadyClock = 7, - UpdateFileTimestamp = 8, - AutoCorrect = 9, - Max = 10, - }; - - s32 num_objs{}; - std::array(EventType::Max)> wait_objs{}; - std::array(EventType::Max)> wait_indices{}; - - const auto AddWaiter{ - [&](Kernel::KSynchronizationObject* synchronization_object, EventType type) { - // Open a new reference to the object. - synchronization_object->Open(); - - // Insert into the list. - wait_indices[num_objs] = type; - wait_objs[num_objs++] = synchronization_object; - }}; - while (!stop_token.stop_requested()) { - SCOPE_EXIT({ - for (s32 i = 0; i < num_objs; i++) { - wait_objs[i]->Close(); - } - }); + enum class EventType : s32 { + Exit = 0, + PowerStateChange = 1, + SignalAlarms = 2, + UpdateLocalSystemClock = 3, + UpdateNetworkSystemClock = 4, + UpdateEphemeralSystemClock = 5, + UpdateSteadyClock = 6, + UpdateFileTimestamp = 7, + AutoCorrect = 8, + }; + + s32 index{}; - num_objs = {}; - wait_objs = {}; if (m_pm_state_change_handler.m_priority != 0) { - AddWaiter(&m_event->GetReadableEvent(), EventType::Exit); - // TODO - // AddWaiter(gIPmModuleService::GetEvent(), 1); - AddWaiter(&m_alarm_worker.GetEvent(), EventType::PowerStateChange); + // TODO: gIPmModuleService::GetEvent() 1 + index = WaitAny(m_system.Kernel(), + &m_event->GetReadableEvent(), // 0 + &m_alarm_worker.GetEvent() // 1 + ); } else { - AddWaiter(&m_event->GetReadableEvent(), EventType::Exit); - // TODO - // AddWaiter(gIPmModuleService::GetEvent(), 1); - AddWaiter(&m_alarm_worker.GetEvent(), EventType::PowerStateChange); - AddWaiter(&m_alarm_worker.GetTimerEvent().GetReadableEvent(), EventType::SignalAlarms); - AddWaiter(m_local_clock_event, EventType::UpdateLocalSystemClock); - AddWaiter(m_network_clock_event, EventType::UpdateNetworkSystemClock); - AddWaiter(m_ephemeral_clock_event, EventType::UpdateEphemeralSystemClock); - AddWaiter(&m_timer_steady_clock->GetReadableEvent(), EventType::UpdateSteadyClock); - AddWaiter(&m_timer_file_system->GetReadableEvent(), EventType::UpdateFileTimestamp); - AddWaiter(m_standard_user_auto_correct_clock_event, EventType::AutoCorrect); + // TODO: gIPmModuleService::GetEvent() 1 + index = WaitAny(m_system.Kernel(), + &m_event->GetReadableEvent(), // 0 + &m_alarm_worker.GetEvent(), // 1 + &m_alarm_worker.GetTimerEvent().GetReadableEvent(), // 2 + m_local_clock_event, // 3 + m_network_clock_event, // 4 + m_ephemeral_clock_event, // 5 + &m_timer_steady_clock->GetReadableEvent(), // 6 + &m_timer_file_system->GetReadableEvent(), // 7 + m_standard_user_auto_correct_clock_event // 8 + ); } - s32 out_index{-1}; - Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(), - num_objs, -1); - ASSERT(out_index >= 0 && out_index < num_objs); - - if (stop_token.stop_requested()) { - return; - } - - switch (wait_indices[out_index]) { + switch (static_cast(index)) { case EventType::Exit: return; - case EventType::IpmModuleService_GetEvent: - // TODO - // IPmModuleService::GetEvent() - // clear the event - // Handle power state change event - break; - case EventType::PowerStateChange: m_alarm_worker.GetEvent().Clear(); if (m_pm_state_change_handler.m_priority <= 1) { @@ -235,19 +200,19 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) { m_local_clock_event->Clear(); Service::PSC::Time::SystemClockContext context{}; - auto res = m_local_clock->GetSystemClockContext(&context); - ASSERT(res == ResultSuccess); + R_ASSERT(m_local_clock->GetSystemClockContext(&context)); m_set_sys->SetUserSystemClockContext(context); - m_file_timestamp_worker.SetFilesystemPosixTime(); - } break; + break; + } case EventType::UpdateNetworkSystemClock: { m_network_clock_event->Clear(); + Service::PSC::Time::SystemClockContext context{}; - auto res = m_network_clock->GetSystemClockContext(&context); - ASSERT(res == ResultSuccess); + R_ASSERT(m_network_clock->GetSystemClockContext(&context)); + m_set_sys->SetNetworkSystemClockContext(context); s64 time{}; @@ -267,7 +232,8 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) { } m_file_timestamp_worker.SetFilesystemPosixTime(); - } break; + break; + } case EventType::UpdateEphemeralSystemClock: { m_ephemeral_clock_event->Clear(); @@ -295,7 +261,8 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) { if (!g_ig_report_ephemeral_clock_context_set) { g_ig_report_ephemeral_clock_context_set = true; } - } break; + break; + } case EventType::UpdateSteadyClock: m_timer_steady_clock->Clear(); @@ -314,21 +281,20 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) { m_standard_user_auto_correct_clock_event->Clear(); bool automatic_correction{}; - auto res = m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled( - &automatic_correction); - ASSERT(res == ResultSuccess); + R_ASSERT(m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled( + &automatic_correction)); Service::PSC::Time::SteadyClockTimePoint time_point{}; - res = m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(&time_point); - ASSERT(res == ResultSuccess); + R_ASSERT( + m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(&time_point)); m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction); m_set_sys->SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); - } break; + break; + } default: UNREACHABLE(); - break; } } } diff --git a/src/core/hle/service/os/event.cpp b/src/core/hle/service/os/event.cpp new file mode 100755 index 000000000..ec52c17fd --- /dev/null +++ b/src/core/hle/service/os/event.cpp @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/os/event.h" + +namespace Service { + +Event::Event(KernelHelpers::ServiceContext& ctx) { + m_event = ctx.CreateEvent("Event"); +} + +Event::~Event() { + m_event->GetReadableEvent().Close(); + m_event->Close(); +} + +void Event::Signal() { + m_event->Signal(); +} + +void Event::Clear() { + m_event->Clear(); +} + +Kernel::KReadableEvent* Event::GetHandle() { + return &m_event->GetReadableEvent(); +} + +} // namespace Service diff --git a/src/core/hle/service/os/event.h b/src/core/hle/service/os/event.h new file mode 100755 index 000000000..cdbc4635a --- /dev/null +++ b/src/core/hle/service/os/event.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace Kernel { +class KEvent; +class KReadableEvent; +} // namespace Kernel + +namespace Service { + +namespace KernelHelpers { +class ServiceContext; +} + +class Event { +public: + explicit Event(KernelHelpers::ServiceContext& ctx); + ~Event(); + + void Signal(); + void Clear(); + + Kernel::KReadableEvent* GetHandle(); + +private: + Kernel::KEvent* m_event; +}; + +} // namespace Service diff --git a/src/core/hle/service/os/multi_wait.cpp b/src/core/hle/service/os/multi_wait.cpp new file mode 100755 index 000000000..7b80d28be --- /dev/null +++ b/src/core/hle/service/os/multi_wait.cpp @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_hardware_timer.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc_common.h" +#include "core/hle/service/os/multi_wait.h" + +namespace Service { + +MultiWait::MultiWait() = default; +MultiWait::~MultiWait() = default; + +MultiWaitHolder* MultiWait::WaitAny(Kernel::KernelCore& kernel) { + return this->TimedWaitImpl(kernel, -1); +} + +MultiWaitHolder* MultiWait::TryWaitAny(Kernel::KernelCore& kernel) { + return this->TimedWaitImpl(kernel, 0); +} + +MultiWaitHolder* MultiWait::TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns) { + return this->TimedWaitImpl(kernel, kernel.HardwareTimer().GetTick() + timeout_ns); +} + +MultiWaitHolder* MultiWait::TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick) { + std::array holders{}; + std::array objects{}; + + s32 out_index = -1; + s32 num_objects = 0; + + for (auto it = m_wait_list.begin(); it != m_wait_list.end(); it++) { + ASSERT(num_objects < Kernel::Svc::ArgumentHandleCountMax); + holders[num_objects] = std::addressof(*it); + objects[num_objects] = it->GetNativeHandle(); + num_objects++; + } + + Kernel::KSynchronizationObject::Wait(kernel, std::addressof(out_index), objects.data(), + num_objects, timeout_tick); + + if (out_index == -1) { + return nullptr; + } else { + return holders[out_index]; + } +} + +void MultiWait::MoveAll(MultiWait* other) { + while (!other->m_wait_list.empty()) { + MultiWaitHolder& holder = other->m_wait_list.front(); + holder.UnlinkFromMultiWait(); + holder.LinkToMultiWait(this); + } +} + +} // namespace Service diff --git a/src/core/hle/service/os/multi_wait.h b/src/core/hle/service/os/multi_wait.h new file mode 100755 index 000000000..340c611b5 --- /dev/null +++ b/src/core/hle/service/os/multi_wait.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/os/multi_wait_holder.h" + +namespace Kernel { +class KernelCore; +} + +namespace Service { + +class MultiWait final { +public: + explicit MultiWait(); + ~MultiWait(); + +public: + MultiWaitHolder* WaitAny(Kernel::KernelCore& kernel); + MultiWaitHolder* TryWaitAny(Kernel::KernelCore& kernel); + MultiWaitHolder* TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns); + // TODO: SdkReplyAndReceive? + + void MoveAll(MultiWait* other); + +private: + MultiWaitHolder* TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick); + +private: + friend class MultiWaitHolder; + using ListType = Common::IntrusiveListMemberTraits<&MultiWaitHolder::m_list_node>::ListType; + ListType m_wait_list{}; +}; + +} // namespace Service diff --git a/src/core/hle/service/os/multi_wait_holder.cpp b/src/core/hle/service/os/multi_wait_holder.cpp new file mode 100755 index 000000000..01efa045b --- /dev/null +++ b/src/core/hle/service/os/multi_wait_holder.cpp @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/os/multi_wait.h" +#include "core/hle/service/os/multi_wait_holder.h" + +namespace Service { + +void MultiWaitHolder::LinkToMultiWait(MultiWait* multi_wait) { + if (m_multi_wait != nullptr) { + UNREACHABLE(); + } + + m_multi_wait = multi_wait; + m_multi_wait->m_wait_list.push_back(*this); +} + +void MultiWaitHolder::UnlinkFromMultiWait() { + if (m_multi_wait) { + m_multi_wait->m_wait_list.erase(m_multi_wait->m_wait_list.iterator_to(*this)); + m_multi_wait = nullptr; + } +} + +} // namespace Service diff --git a/src/core/hle/service/os/multi_wait_holder.h b/src/core/hle/service/os/multi_wait_holder.h new file mode 100755 index 000000000..646395a3f --- /dev/null +++ b/src/core/hle/service/os/multi_wait_holder.h @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/intrusive_list.h" + +namespace Kernel { +class KSynchronizationObject; +} // namespace Kernel + +namespace Service { + +class MultiWait; + +class MultiWaitHolder { +public: + explicit MultiWaitHolder(Kernel::KSynchronizationObject* native_handle) + : m_native_handle(native_handle) {} + + void LinkToMultiWait(MultiWait* multi_wait); + void UnlinkFromMultiWait(); + + void SetUserData(uintptr_t user_data) { + m_user_data = user_data; + } + + uintptr_t GetUserData() const { + return m_user_data; + } + + Kernel::KSynchronizationObject* GetNativeHandle() const { + return m_native_handle; + } + +private: + friend class MultiWait; + Common::IntrusiveListNode m_list_node{}; + MultiWait* m_multi_wait{}; + Kernel::KSynchronizationObject* m_native_handle{}; + uintptr_t m_user_data{}; +}; + +} // namespace Service diff --git a/src/core/hle/service/os/multi_wait_utils.h b/src/core/hle/service/os/multi_wait_utils.h new file mode 100755 index 000000000..96d3a10f3 --- /dev/null +++ b/src/core/hle/service/os/multi_wait_utils.h @@ -0,0 +1,109 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/os/multi_wait.h" + +namespace Service { + +namespace impl { + +class AutoMultiWaitHolder { +private: + MultiWaitHolder m_holder; + +public: + template + explicit AutoMultiWaitHolder(MultiWait* multi_wait, T&& arg) : m_holder(arg) { + m_holder.LinkToMultiWait(multi_wait); + } + + ~AutoMultiWaitHolder() { + m_holder.UnlinkFromMultiWait(); + } + + std::pair ConvertResult(const std::pair result, + int index) { + if (result.first == std::addressof(m_holder)) { + return std::make_pair(static_cast(nullptr), index); + } else { + return result; + } + } +}; + +using WaitAnyFunction = decltype(&MultiWait::WaitAny); + +inline std::pair WaitAnyImpl(Kernel::KernelCore& kernel, + MultiWait* multi_wait, WaitAnyFunction func, + int) { + return std::pair((multi_wait->*func)(kernel), -1); +} + +template +inline std::pair WaitAnyImpl(Kernel::KernelCore& kernel, + MultiWait* multi_wait, WaitAnyFunction func, + int index, T&& x, Args&&... args) { + AutoMultiWaitHolder holder(multi_wait, std::forward(x)); + return holder.ConvertResult( + WaitAnyImpl(kernel, multi_wait, func, index + 1, std::forward(args)...), index); +} + +template +inline std::pair WaitAnyImpl(Kernel::KernelCore& kernel, + MultiWait* multi_wait, WaitAnyFunction func, + Args&&... args) { + return WaitAnyImpl(kernel, multi_wait, func, 0, std::forward(args)...); +} + +template +inline std::pair WaitAnyImpl(Kernel::KernelCore& kernel, + WaitAnyFunction func, Args&&... args) { + MultiWait temp_multi_wait; + return WaitAnyImpl(kernel, std::addressof(temp_multi_wait), func, 0, + std::forward(args)...); +} + +class NotBoolButInt { +public: + constexpr NotBoolButInt(int v) : m_value(v) {} + constexpr operator int() const { + return m_value; + } + explicit operator bool() const = delete; + +private: + int m_value; +}; + +} // namespace impl + +template + requires(sizeof...(Args) > 0) +inline std::pair WaitAny(Kernel::KernelCore& kernel, MultiWait* multi_wait, + Args&&... args) { + return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, multi_wait, std::forward(args)...); +} + +template + requires(sizeof...(Args) > 0) +inline int WaitAny(Kernel::KernelCore& kernel, Args&&... args) { + return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, std::forward(args)...).second; +} + +template + requires(sizeof...(Args) > 0) +inline std::pair TryWaitAny(Kernel::KernelCore& kernel, + MultiWait* multi_wait, Args&&... args) { + return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, multi_wait, + std::forward(args)...); +} + +template + requires(sizeof...(Args) > 0) +inline impl::NotBoolButInt TryWaitAny(Kernel::KernelCore& kernel, Args&&... args) { + return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, std::forward(args)...).second; +} + +} // namespace Service diff --git a/src/core/hle/service/os/mutex.cpp b/src/core/hle/service/os/mutex.cpp new file mode 100755 index 000000000..6009f4866 --- /dev/null +++ b/src/core/hle/service/os/mutex.cpp @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/service/os/mutex.h" + +namespace Service { + +Mutex::Mutex(Core::System& system) : m_system(system) { + m_event = Kernel::KEvent::Create(system.Kernel()); + m_event->Initialize(nullptr); + + // Register the event. + Kernel::KEvent::Register(system.Kernel(), m_event); + + ASSERT(R_SUCCEEDED(m_event->Signal())); +} + +Mutex::~Mutex() { + m_event->GetReadableEvent().Close(); + m_event->Close(); +} + +void Mutex::lock() { + // Infinitely retry until we successfully clear the event. + while (R_FAILED(m_event->GetReadableEvent().Reset())) { + s32 index; + Kernel::KSynchronizationObject* obj = &m_event->GetReadableEvent(); + + // The event was already cleared! + // Wait for it to become signaled again. + ASSERT(R_SUCCEEDED( + Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &index, &obj, 1, -1))); + } + + // We successfully cleared the event, and now have exclusive ownership. +} + +void Mutex::unlock() { + // Unlock. + ASSERT(R_SUCCEEDED(m_event->Signal())); +} + +} // namespace Service diff --git a/src/core/hle/service/os/mutex.h b/src/core/hle/service/os/mutex.h new file mode 100755 index 000000000..95ac9b117 --- /dev/null +++ b/src/core/hle/service/os/mutex.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_types.h" + +namespace Core { +class System; +} + +namespace Kernel { +class KEvent; +} + +namespace Service { + +class Mutex { +public: + explicit Mutex(Core::System& system); + ~Mutex(); + + void lock(); + void unlock(); + +private: + Core::System& m_system; + Kernel::KEvent* m_event{}; +}; + +} // namespace Service diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp index 8ef49387d..8c7f94c8c 100755 --- a/src/core/hle/service/server_manager.cpp +++ b/src/core/hle/service/server_manager.cpp @@ -20,50 +20,91 @@ namespace Service { -constexpr size_t MaximumWaitObjects = 0x40; - -enum HandleType { +enum class UserDataTag { Port, Session, DeferEvent, - Event, }; -ServerManager::ServerManager(Core::System& system) : m_system{system}, m_serve_mutex{system} { +class Port : public MultiWaitHolder, public Common::IntrusiveListBaseNode { +public: + explicit Port(Kernel::KServerPort* server_port, SessionRequestHandlerFactory&& handler_factory) + : MultiWaitHolder(server_port), m_handler_factory(std::move(handler_factory)) { + this->SetUserData(static_cast(UserDataTag::Port)); + } + + ~Port() { + this->GetNativeHandle()->Close(); + } + + SessionRequestHandlerPtr CreateHandler() { + return m_handler_factory(); + } + +private: + const SessionRequestHandlerFactory m_handler_factory; +}; + +class Session : public MultiWaitHolder, public Common::IntrusiveListBaseNode { +public: + explicit Session(Kernel::KServerSession* server_session, + std::shared_ptr&& manager) + : MultiWaitHolder(server_session), m_manager(std::move(manager)) { + this->SetUserData(static_cast(UserDataTag::Session)); + } + + ~Session() { + this->GetNativeHandle()->Close(); + } + + std::shared_ptr& GetManager() { + return m_manager; + } + + std::shared_ptr& GetContext() { + return m_context; + } + +private: + std::shared_ptr m_manager; + std::shared_ptr m_context; +}; + +ServerManager::ServerManager(Core::System& system) : m_system{system}, m_selection_mutex{system} { // Initialize event. - m_event = Kernel::KEvent::Create(system.Kernel()); - m_event->Initialize(nullptr); + m_wakeup_event = Kernel::KEvent::Create(system.Kernel()); + m_wakeup_event->Initialize(nullptr); // Register event. - Kernel::KEvent::Register(system.Kernel(), m_event); + Kernel::KEvent::Register(system.Kernel(), m_wakeup_event); + + // Link to holder. + m_wakeup_holder.emplace(std::addressof(m_wakeup_event->GetReadableEvent())); + m_wakeup_holder->LinkToMultiWait(std::addressof(m_deferred_list)); } ServerManager::~ServerManager() { // Signal stop. m_stop_source.request_stop(); - m_event->Signal(); + m_wakeup_event->Signal(); // Wait for processing to stop. m_stopped.Wait(); m_threads.clear(); - // Clean up server ports. - for (const auto& [port, handler] : m_ports) { - port->Close(); + // Clean up ports. + for (auto it = m_servers.begin(); it != m_servers.end(); it = m_servers.erase(it)) { + delete std::addressof(*it); } // Clean up sessions. - for (const auto& [session, manager] : m_sessions) { - session->Close(); + for (auto it = m_sessions.begin(); it != m_sessions.end(); it = m_sessions.erase(it)) { + delete std::addressof(*it); } - for (const auto& request : m_deferrals) { - request.session->Close(); - } - - // Close event. - m_event->GetReadableEvent().Close(); - m_event->Close(); + // Close wakeup event. + m_wakeup_event->GetReadableEvent().Close(); + m_wakeup_event->Close(); if (m_deferral_event) { m_deferral_event->GetReadableEvent().Close(); @@ -75,19 +116,19 @@ void ServerManager::RunServer(std::unique_ptr&& server_manager) { server_manager->m_system.RunServer(std::move(server_manager)); } -Result ServerManager::RegisterSession(Kernel::KServerSession* session, +Result ServerManager::RegisterSession(Kernel::KServerSession* server_session, std::shared_ptr manager) { - ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects); - // We are taking ownership of the server session, so don't open it. + auto* session = new Session(server_session, std::move(manager)); + // Begin tracking the server session. { - std::scoped_lock ll{m_list_mutex}; - m_sessions.emplace(session, std::move(manager)); + std::scoped_lock ll{m_deferred_list_mutex}; + m_sessions.push_back(*session); } - // Signal the wakeup event. - m_event->Signal(); + // Register to wait on the session. + this->LinkToDeferredList(session); R_SUCCEED(); } @@ -95,21 +136,22 @@ Result ServerManager::RegisterSession(Kernel::KServerSession* session, Result ServerManager::RegisterNamedService(const std::string& service_name, SessionRequestHandlerFactory&& handler_factory, u32 max_sessions) { - ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects); - // Add the new server to sm: and get the moved server port. Kernel::KServerPort* server_port{}; R_ASSERT(m_system.ServiceManager().RegisterService(std::addressof(server_port), service_name, max_sessions, handler_factory)); + // We are taking ownership of the server port, so don't open it. + auto* server = new Port(server_port, std::move(handler_factory)); + // Begin tracking the server port. { - std::scoped_lock ll{m_list_mutex}; - m_ports.emplace(server_port, std::move(handler_factory)); + std::scoped_lock ll{m_deferred_list_mutex}; + m_servers.push_back(*server); } - // Signal the wakeup event. - m_event->Signal(); + // Register to wait on the server port. + this->LinkToDeferredList(server); R_SUCCEED(); } @@ -127,8 +169,6 @@ Result ServerManager::RegisterNamedService(const std::string& service_name, Result ServerManager::ManageNamedPort(const std::string& service_name, SessionRequestHandlerFactory&& handler_factory, u32 max_sessions) { - ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects); - // Create a new port. auto* port = Kernel::KPort::Create(m_system.Kernel()); port->Initialize(max_sessions, false, 0); @@ -149,12 +189,18 @@ Result ServerManager::ManageNamedPort(const std::string& service_name, // Open a new reference to the server port. port->GetServerPort().Open(); - // Begin tracking the server port. + // Transfer ownership into a new port object. + auto* server = new Port(std::addressof(port->GetServerPort()), std::move(handler_factory)); + + // Begin tracking the port. { - std::scoped_lock ll{m_list_mutex}; - m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler_factory)); + std::scoped_lock ll{m_deferred_list_mutex}; + m_servers.push_back(*server); } + // Register to wait on the port. + this->LinkToDeferredList(server); + // We succeeded. R_SUCCEED(); } @@ -173,6 +219,11 @@ Result ServerManager::ManageDeferral(Kernel::KEvent** out_event) { // Set the output. *out_event = m_deferral_event; + // Register to wait on the event. + m_deferral_holder.emplace(std::addressof(m_deferral_event->GetReadableEvent())); + m_deferral_holder->SetUserData(static_cast(UserDataTag::DeferEvent)); + this->LinkToDeferredList(std::addressof(*m_deferral_holder)); + // We succeeded. R_SUCCEED(); } @@ -191,270 +242,185 @@ Result ServerManager::LoopProcess() { R_RETURN(this->LoopProcessImpl()); } +void ServerManager::LinkToDeferredList(MultiWaitHolder* holder) { + // Link. + { + std::scoped_lock lk{m_deferred_list_mutex}; + holder->LinkToMultiWait(std::addressof(m_deferred_list)); + } + + // Signal the wakeup event. + m_wakeup_event->Signal(); +} + +void ServerManager::LinkDeferred() { + std::scoped_lock lk{m_deferred_list_mutex}; + m_multi_wait.MoveAll(std::addressof(m_deferred_list)); +} + +MultiWaitHolder* ServerManager::WaitSignaled() { + // Ensure we are the only thread waiting for this server. + std::scoped_lock lk{m_selection_mutex}; + + while (true) { + this->LinkDeferred(); + + // If we're done, return before we start waiting. + if (m_stop_source.stop_requested()) { + return nullptr; + } + + auto* selected = m_multi_wait.WaitAny(m_system.Kernel()); + if (selected == std::addressof(*m_wakeup_holder)) { + // Clear and restart if we were woken up. + m_wakeup_event->Clear(); + } else { + // Unlink and handle the event. + selected->UnlinkFromMultiWait(); + return selected; + } + } +} + +Result ServerManager::Process(MultiWaitHolder* holder) { + switch (static_cast(holder->GetUserData())) { + case UserDataTag::Session: + R_RETURN(this->OnSessionEvent(static_cast(holder))); + case UserDataTag::Port: + R_RETURN(this->OnPortEvent(static_cast(holder))); + case UserDataTag::DeferEvent: + R_RETURN(this->OnDeferralEvent()); + default: + UNREACHABLE(); + } +} + +bool ServerManager::WaitAndProcessImpl() { + if (auto* signaled_holder = this->WaitSignaled(); signaled_holder != nullptr) { + R_ASSERT(this->Process(signaled_holder)); + return true; + } else { + return false; + } +} + Result ServerManager::LoopProcessImpl() { while (!m_stop_source.stop_requested()) { - R_TRY(this->WaitAndProcessImpl()); + this->WaitAndProcessImpl(); } R_SUCCEED(); } -Result ServerManager::WaitAndProcessImpl() { - Kernel::KScopedAutoObject wait_obj; - HandleType wait_type{}; - - // Ensure we are the only thread waiting for this server. - std::unique_lock sl{m_serve_mutex}; - - // If we're done, return before we start waiting. - R_SUCCEED_IF(m_stop_source.stop_requested()); - - // Wait for a tracked object to become signaled. - { - s32 num_objs{}; - std::array wait_types{}; - std::array wait_objs{}; - - const auto AddWaiter{ - [&](Kernel::KSynchronizationObject* synchronization_object, HandleType type) { - // Open a new reference to the object. - synchronization_object->Open(); - - // Insert into the list. - wait_types[num_objs] = type; - wait_objs[num_objs++] = synchronization_object; - }}; - - { - std::scoped_lock ll{m_list_mutex}; - - // Add all of our ports. - for (const auto& [port, handler] : m_ports) { - AddWaiter(port, HandleType::Port); - } - - // Add all of our sessions. - for (const auto& [session, manager] : m_sessions) { - AddWaiter(session, HandleType::Session); - } - } - - // Add the deferral wakeup event. - if (m_deferral_event != nullptr) { - AddWaiter(std::addressof(m_deferral_event->GetReadableEvent()), HandleType::DeferEvent); - } - - // Add the wakeup event. - AddWaiter(std::addressof(m_event->GetReadableEvent()), HandleType::Event); - - // Clean up extra references on exit. - SCOPE_EXIT({ - for (s32 i = 0; i < num_objs; i++) { - wait_objs[i]->Close(); - } - }); - - // Wait for a signal. - s32 out_index{-1}; - R_TRY_CATCH(Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, - wait_objs.data(), num_objs, -1)) { - R_CATCH(Kernel::ResultSessionClosed) { - // On session closed, index is updated and we don't want to return an error. - } - } - R_END_TRY_CATCH; - ASSERT(out_index >= 0 && out_index < num_objs); - - // Set the output index. - wait_obj = wait_objs[out_index]; - wait_type = wait_types[out_index]; - } - - // Process what we just received, temporarily removing the object so it is - // not processed concurrently by another thread. - { - switch (wait_type) { - case HandleType::Port: { - // Port signaled. - auto* port = wait_obj->DynamicCast(); - SessionRequestHandlerFactory handler_factory; - - // Remove from tracking. - { - std::scoped_lock ll{m_list_mutex}; - ASSERT(m_ports.contains(port)); - m_ports.at(port).swap(handler_factory); - m_ports.erase(port); - } - - // Allow other threads to serve. - sl.unlock(); - - // Finish. - R_RETURN(this->OnPortEvent(port, std::move(handler_factory))); - } - case HandleType::Session: { - // Session signaled. - auto* session = wait_obj->DynamicCast(); - std::shared_ptr manager; - - // Remove from tracking. - { - std::scoped_lock ll{m_list_mutex}; - ASSERT(m_sessions.contains(session)); - m_sessions.at(session).swap(manager); - m_sessions.erase(session); - } - - // Allow other threads to serve. - sl.unlock(); - - // Finish. - R_RETURN(this->OnSessionEvent(session, std::move(manager))); - } - case HandleType::DeferEvent: { - // Clear event. - ASSERT(R_SUCCEEDED(m_deferral_event->Clear())); - - // Drain the list of deferrals while we process. - std::list deferrals; - { - std::scoped_lock ll{m_list_mutex}; - m_deferrals.swap(deferrals); - } - - // Allow other threads to serve. - sl.unlock(); - - // Finish. - R_RETURN(this->OnDeferralEvent(std::move(deferrals))); - } - case HandleType::Event: { - // Clear event and finish. - R_RETURN(m_event->Clear()); - } - default: { - UNREACHABLE(); - } - } - } -} - -Result ServerManager::OnPortEvent(Kernel::KServerPort* port, - SessionRequestHandlerFactory&& handler_factory) { +Result ServerManager::OnPortEvent(Port* server) { // Accept a new server session. - Kernel::KServerSession* session = port->AcceptSession(); - ASSERT(session != nullptr); + auto* server_port = static_cast(server->GetNativeHandle()); + Kernel::KServerSession* server_session = server_port->AcceptSession(); + ASSERT(server_session != nullptr); // Create the session manager and install the handler. auto manager = std::make_shared(m_system.Kernel(), *this); - manager->SetSessionHandler(handler_factory()); + manager->SetSessionHandler(server->CreateHandler()); - // Track the server session. - { - std::scoped_lock ll{m_list_mutex}; - m_ports.emplace(port, std::move(handler_factory)); - m_sessions.emplace(session, std::move(manager)); - } + // Create and register the new session. + this->RegisterSession(server_session, std::move(manager)); - // Signal the wakeup event. - m_event->Signal(); + // Resume tracking the port. + this->LinkToDeferredList(server); // We succeeded. R_SUCCEED(); } -Result ServerManager::OnSessionEvent(Kernel::KServerSession* session, - std::shared_ptr&& manager) { - Result rc{ResultSuccess}; +Result ServerManager::OnSessionEvent(Session* session) { + Result res = ResultSuccess; // Try to receive a message. - std::shared_ptr context; - rc = session->ReceiveRequestHLE(&context, manager); + auto* server_session = static_cast(session->GetNativeHandle()); + res = server_session->ReceiveRequestHLE(&session->GetContext(), session->GetManager()); // If the session has been closed, we're done. - if (rc == Kernel::ResultSessionClosed) { - // Close the session. - session->Close(); - - // Finish. + if (res == Kernel::ResultSessionClosed) { + this->DestroySession(session); R_SUCCEED(); } - ASSERT(R_SUCCEEDED(rc)); - RequestState request{ - .session = session, - .context = std::move(context), - .manager = std::move(manager), - }; + R_ASSERT(res); // Complete the sync request with deferral handling. - R_RETURN(this->CompleteSyncRequest(std::move(request))); + R_RETURN(this->CompleteSyncRequest(session)); } -Result ServerManager::CompleteSyncRequest(RequestState&& request) { - Result rc{ResultSuccess}; - Result service_rc{ResultSuccess}; +Result ServerManager::CompleteSyncRequest(Session* session) { + Result res = ResultSuccess; + Result service_res = ResultSuccess; // Mark the request as not deferred. - request.context->SetIsDeferred(false); + session->GetContext()->SetIsDeferred(false); // Complete the request. We have exclusive access to this session. - service_rc = request.manager->CompleteSyncRequest(request.session, *request.context); + auto* server_session = static_cast(session->GetNativeHandle()); + service_res = + session->GetManager()->CompleteSyncRequest(server_session, *session->GetContext()); // If we've been deferred, we're done. - if (request.context->GetIsDeferred()) { - // Insert into deferral list. - std::scoped_lock ll{m_list_mutex}; - m_deferrals.emplace_back(std::move(request)); + if (session->GetContext()->GetIsDeferred()) { + // Insert into deferred session list. + std::scoped_lock ll{m_deferred_list_mutex}; + m_deferred_sessions.push_back(session); // Finish. R_SUCCEED(); } // Send the reply. - rc = request.session->SendReplyHLE(); + res = server_session->SendReplyHLE(); // If the session has been closed, we're done. - if (rc == Kernel::ResultSessionClosed || service_rc == IPC::ResultSessionClosed) { - // Close the session. - request.session->Close(); - - // Finish. + if (res == Kernel::ResultSessionClosed || service_res == IPC::ResultSessionClosed) { + this->DestroySession(session); R_SUCCEED(); } - ASSERT(R_SUCCEEDED(rc)); - ASSERT(R_SUCCEEDED(service_rc)); + R_ASSERT(res); + R_ASSERT(service_res); - // Reinsert the session. - { - std::scoped_lock ll{m_list_mutex}; - m_sessions.emplace(request.session, std::move(request.manager)); - } + // We succeeded, so we can process future messages on this session. + this->LinkToDeferredList(session); - // Signal the wakeup event. - m_event->Signal(); - - // We succeeded. R_SUCCEED(); } -Result ServerManager::OnDeferralEvent(std::list&& deferrals) { - ON_RESULT_FAILURE { - std::scoped_lock ll{m_list_mutex}; - m_deferrals.splice(m_deferrals.end(), deferrals); - }; +Result ServerManager::OnDeferralEvent() { + // Clear event before grabbing the list. + m_deferral_event->Clear(); - while (!deferrals.empty()) { - RequestState request = deferrals.front(); - deferrals.pop_front(); + // Get and clear list. + const auto deferrals = [&] { + std::scoped_lock lk{m_deferred_list_mutex}; + return std::move(m_deferred_sessions); + }(); - // Try again to complete the request. - R_TRY(this->CompleteSyncRequest(std::move(request))); + // Relink deferral event. + this->LinkToDeferredList(std::addressof(*m_deferral_holder)); + + // For each session, try again to complete the request. + for (auto* session : deferrals) { + R_ASSERT(this->CompleteSyncRequest(session)); } R_SUCCEED(); } +void ServerManager::DestroySession(Session* session) { + // Unlink. + { + std::scoped_lock lk{m_deferred_list_mutex}; + m_sessions.erase(m_sessions.iterator_to(*session)); + } + + // Free the session. + delete session; +} + } // namespace Service diff --git a/src/core/hle/service/server_manager.h b/src/core/hle/service/server_manager.h index c4bc07262..5173ce46e 100755 --- a/src/core/hle/service/server_manager.h +++ b/src/core/hle/service/server_manager.h @@ -3,18 +3,17 @@ #pragma once -#include #include -#include #include -#include +#include #include #include "common/polyfill_thread.h" #include "common/thread.h" #include "core/hle/result.h" #include "core/hle/service/hle_ipc.h" -#include "core/hle/service/mutex.h" +#include "core/hle/service/os/multi_wait.h" +#include "core/hle/service/os/mutex.h" namespace Core { class System; @@ -24,11 +23,13 @@ namespace Kernel { class KEvent; class KServerPort; class KServerSession; -class KSynchronizationObject; } // namespace Kernel namespace Service { +class Port; +class Session; + class ServerManager { public: explicit ServerManager(Core::System& system); @@ -52,34 +53,40 @@ public: static void RunServer(std::unique_ptr&& server); private: - struct RequestState; - + void LinkToDeferredList(MultiWaitHolder* holder); + void LinkDeferred(); + MultiWaitHolder* WaitSignaled(); + Result Process(MultiWaitHolder* holder); + bool WaitAndProcessImpl(); Result LoopProcessImpl(); - Result WaitAndProcessImpl(); - Result OnPortEvent(Kernel::KServerPort* port, SessionRequestHandlerFactory&& handler_factory); - Result OnSessionEvent(Kernel::KServerSession* session, - std::shared_ptr&& manager); - Result OnDeferralEvent(std::list&& deferrals); - Result CompleteSyncRequest(RequestState&& state); + + Result OnPortEvent(Port* port); + Result OnSessionEvent(Session* session); + Result OnDeferralEvent(); + Result CompleteSyncRequest(Session* session); + +private: + void DestroySession(Session* session); private: Core::System& m_system; - Mutex m_serve_mutex; - std::mutex m_list_mutex; + Mutex m_selection_mutex; - // Guest state tracking - std::map m_ports{}; - std::map> m_sessions{}; - Kernel::KEvent* m_event{}; + // Events + Kernel::KEvent* m_wakeup_event{}; Kernel::KEvent* m_deferral_event{}; - // Deferral tracking - struct RequestState { - Kernel::KServerSession* session; - std::shared_ptr context; - std::shared_ptr manager; - }; - std::list m_deferrals{}; + // Deferred wait list + std::mutex m_deferred_list_mutex{}; + MultiWait m_deferred_list{}; + + // Guest state tracking + MultiWait m_multi_wait{}; + Common::IntrusiveListBaseTraits::ListType m_servers{}; + Common::IntrusiveListBaseTraits::ListType m_sessions{}; + std::list m_deferred_sessions{}; + std::optional m_wakeup_holder{}; + std::optional m_deferral_holder{}; // Host state tracking Common::Event m_stopped{}; diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp index 5a559cb35..ad33210f2 100755 --- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp @@ -60,10 +60,11 @@ public: Add(spv::ImageOperandsMask::ConstOffsets, offsets); } - explicit ImageOperands(Id lod, Id ms) { + explicit ImageOperands(EmitContext& ctx, const IR::Value& offset, Id lod, Id ms) { if (Sirit::ValidId(lod)) { Add(spv::ImageOperandsMask::Lod, lod); } + AddOffset(ctx, offset, ImageFetchOffsetAllowed); if (Sirit::ValidId(ms)) { Add(spv::ImageOperandsMask::Sample, ms); } @@ -311,37 +312,6 @@ Id ImageGatherSubpixelOffset(EmitContext& ctx, const IR::TextureInstInfo& info, return coords; } } - -void AddOffsetToCoordinates(EmitContext& ctx, const IR::TextureInstInfo& info, Id& coords, - Id offset) { - if (!Sirit::ValidId(offset)) { - return; - } - - Id result_type{}; - switch (info.type) { - case TextureType::Buffer: - case TextureType::Color1D: - case TextureType::ColorArray1D: { - result_type = ctx.U32[1]; - break; - } - case TextureType::Color2D: - case TextureType::Color2DRect: - case TextureType::ColorArray2D: { - result_type = ctx.U32[2]; - break; - } - case TextureType::Color3D: { - result_type = ctx.U32[3]; - break; - } - case TextureType::ColorCube: - case TextureType::ColorArrayCube: - return; - } - coords = ctx.OpIAdd(result_type, coords, offset); -} } // Anonymous namespace Id EmitBindlessImageSampleImplicitLod(EmitContext&) { @@ -524,10 +494,9 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, operands.Span()); } -Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, - Id lod, Id ms) { +Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, + const IR::Value& offset, Id lod, Id ms) { const auto info{inst->Flags()}; - AddOffsetToCoordinates(ctx, info, coords, offset); if (info.type == TextureType::Buffer) { lod = Id{}; } @@ -535,7 +504,7 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c // This image is multisampled, lod must be implicit lod = Id{}; } - const ImageOperands operands(lod, ms); + const ImageOperands operands(ctx, offset, lod, ms); return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4], TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span()); } diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 7a3300b33..9465b0f32 100755 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -537,8 +537,8 @@ Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id const IR::Value& offset, const IR::Value& offset2); Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, const IR::Value& offset, const IR::Value& offset2, Id dref); -Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, - Id lod, Id ms); +Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, + const IR::Value& offset, Id lod, Id ms); Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod, const IR::Value& skip_mips); Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); diff --git a/src/video_core/host1x/codecs/decoder.cpp b/src/video_core/host1x/codecs/decoder.cpp index 8508cc172..49a601969 100755 --- a/src/video_core/host1x/codecs/decoder.cpp +++ b/src/video_core/host1x/codecs/decoder.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/assert.h" @@ -40,7 +40,8 @@ void Decoder::Decode() { auto frame_copy = frame; if (!frame.get()) { - LOG_ERROR(HW_GPU, "Failed to decode interlaced frame for top 0x{:X} bottom 0x{:X}", + LOG_ERROR(HW_GPU, + "Nvdec {} dailed to decode interlaced frame for top 0x{:X} bottom 0x{:X}", id, luma_top, luma_bottom); } @@ -55,7 +56,8 @@ void Decoder::Decode() { auto [luma_offset, chroma_offset] = GetProgressiveOffsets(); if (!frame.get()) { - LOG_ERROR(HW_GPU, "Failed to decode progressive frame for luma 0x{:X}", luma_offset); + LOG_ERROR(HW_GPU, "Nvdec {} failed to decode progressive frame for luma 0x{:X}", id, + luma_offset); } if (UsingDecodeOrder()) { diff --git a/src/video_core/host1x/codecs/decoder.h b/src/video_core/host1x/codecs/decoder.h index 9b350ee3e..22e6db815 100755 --- a/src/video_core/host1x/codecs/decoder.h +++ b/src/video_core/host1x/codecs/decoder.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/video_core/host1x/codecs/h264.cpp b/src/video_core/host1x/codecs/h264.cpp index d3b66c20c..389f13da0 100755 --- a/src/video_core/host1x/codecs/h264.cpp +++ b/src/video_core/host1x/codecs/h264.cpp @@ -1,5 +1,5 @@ -// SPDX-FileCopyrightText: Ryujinx Team and Contributors -// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include #include diff --git a/src/video_core/host1x/codecs/h264.h b/src/video_core/host1x/codecs/h264.h index 9e95c6c68..85659be33 100755 --- a/src/video_core/host1x/codecs/h264.h +++ b/src/video_core/host1x/codecs/h264.h @@ -1,5 +1,5 @@ -// SPDX-FileCopyrightText: Ryujinx Team and Contributors -// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/video_core/host1x/host1x.h b/src/video_core/host1x/host1x.h index 24a46e26c..7cef351c8 100755 --- a/src/video_core/host1x/host1x.h +++ b/src/video_core/host1x/host1x.h @@ -66,12 +66,18 @@ public: void PushPresentOrder(s32 fd, u64 offset, std::shared_ptr&& frame) { std::scoped_lock l{m_mutex}; auto map = m_presentation_order.find(fd); + if (map == m_presentation_order.end()) { + return; + } map->second.emplace_back(offset, std::move(frame)); } void PushDecodeOrder(s32 fd, u64 offset, std::shared_ptr&& frame) { std::scoped_lock l{m_mutex}; auto map = m_decode_order.find(fd); + if (map == m_decode_order.end()) { + return; + } map->second.insert_or_assign(offset, std::move(frame)); } @@ -82,12 +88,12 @@ public: std::scoped_lock l{m_mutex}; auto present_map = m_presentation_order.find(fd); - if (present_map->second.size() > 0) { + if (present_map != m_presentation_order.end() && present_map->second.size() > 0) { return GetPresentOrderLocked(fd); } auto decode_map = m_decode_order.find(fd); - if (decode_map->second.size() > 0) { + if (decode_map != m_decode_order.end() && decode_map->second.size() > 0) { return GetDecodeOrderLocked(fd, offset); } @@ -97,7 +103,7 @@ public: private: std::shared_ptr GetPresentOrderLocked(s32 fd) { auto map = m_presentation_order.find(fd); - if (map->second.size() == 0) { + if (map == m_presentation_order.end() || map->second.size() == 0) { return {}; } auto frame = std::move(map->second.front().second); @@ -107,6 +113,9 @@ private: std::shared_ptr GetDecodeOrderLocked(s32 fd, u64 offset) { auto map = m_decode_order.find(fd); + if (map == m_decode_order.end() || map->second.size() == 0) { + return {}; + } auto it = map->second.find(offset); if (it == map->second.end()) { return {}; diff --git a/src/video_core/host1x/nvdec.cpp b/src/video_core/host1x/nvdec.cpp index 2972bbf60..a30faf3a6 100755 --- a/src/video_core/host1x/nvdec.cpp +++ b/src/video_core/host1x/nvdec.cpp @@ -24,7 +24,6 @@ Nvdec::Nvdec(Host1x& host1x_, s32 id_, u32 syncpt, FrameQueue& frame_queue_) Nvdec::~Nvdec() { LOG_INFO(HW_GPU, "Destroying nvdec {}", id); - frame_queue.Close(id); } void Nvdec::ProcessMethod(u32 method, u32 argument) { diff --git a/src/video_core/host1x/vic.cpp b/src/video_core/host1x/vic.cpp index 6c0127782..705285fd0 100755 --- a/src/video_core/host1x/vic.cpp +++ b/src/video_core/host1x/vic.cpp @@ -100,10 +100,11 @@ Vic::Vic(Host1x& host1x_, s32 id_, u32 syncpt, FrameQueue& frame_queue_) Vic::~Vic() { LOG_INFO(HW_GPU, "Destroying vic {}", id); + frame_queue.Close(id); } void Vic::ProcessMethod(u32 method, u32 arg) { - LOG_TRACE(HW_GPU, "Vic method 0x{:X}", static_cast(method)); + LOG_TRACE(HW_GPU, "Vic {} method 0x{:X}", id, static_cast(method)); regs.reg_array[method] = arg; switch (static_cast(method * sizeof(u32))) { @@ -140,7 +141,7 @@ void Vic::Execute() { auto frame = frame_queue.GetFrame(nvdec_id, luma_offset); if (!frame.get()) { - LOG_ERROR(HW_GPU, "Vic failed to get frame with offset 0x{:X}", luma_offset); + LOG_ERROR(HW_GPU, "Vic {} failed to get frame with offset 0x{:X}", id, luma_offset); continue; }