diff --git a/src/core/hle/service/gsp/gsp_gpu.cpp b/src/core/hle/service/gsp/gsp_gpu.cpp index 100e03f52..d62f0d294 100644 --- a/src/core/hle/service/gsp/gsp_gpu.cpp +++ b/src/core/hle/service/gsp/gsp_gpu.cpp @@ -4,6 +4,9 @@ #include #include +#include +#include +#include #include "common/archives.h" #include "common/bit_field.h" #include "common/microprofile.h" @@ -478,7 +481,7 @@ void GSP_GPU::SignalInterrupt(InterruptId interrupt_id) { } // For normal interrupts, don't do anything if no process has acquired the GPU right. - if (active_thread_id == UINT32_MAX) { + if (active_thread_id == std::numeric_limits::max()) { return; } @@ -664,7 +667,7 @@ void GSP_GPU::TriggerCmdReqQueue(Kernel::HLERequestContext& ctx) { void GSP_GPU::ImportDisplayCaptureInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); - if (active_thread_id == UINT32_MAX) { + if (active_thread_id == std::numeric_limits::max()) { LOG_WARNING(Service_GSP, "Called without an active thread."); // TODO: Find the right error code. @@ -792,37 +795,57 @@ void GSP_GPU::RestoreVramSysArea(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } -void GSP_GPU::AcquireRight(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx); +ResultCode GSP_GPU::AcquireGpuRight(const Kernel::HLERequestContext& ctx, + const std::shared_ptr& process, u32 flag, + bool blocking) { + const auto session_data = GetSessionData(ctx.Session()); - u32 flag = rp.Pop(); - auto process = rp.PopObject(); - - SessionData* session_data = GetSessionData(ctx.Session()); - - LOG_WARNING(Service_GSP, "called flag={:08X} process={} thread_id={}", flag, - process->process_id, session_data->thread_id); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + LOG_DEBUG(Service_GSP, "called flag={:08X} process={} thread_id={}", flag, process->process_id, + session_data->thread_id); if (active_thread_id == session_data->thread_id) { - rb.Push(ResultCode(ErrorDescription::AlreadyDone, ErrorModule::GX, ErrorSummary::Success, - ErrorLevel::Success)); - return; + return {ErrorDescription::AlreadyDone, ErrorModule::GX, ErrorSummary::Success, + ErrorLevel::Success}; } - // TODO(Subv): This case should put the caller thread to sleep until the right is released. - ASSERT_MSG(active_thread_id == UINT32_MAX, "GPU right has already been acquired"); + if (blocking) { + // TODO: The thread should be put to sleep until acquired. + ASSERT_MSG(active_thread_id == std::numeric_limits::max(), + "Sleeping for GPU right is not yet supported."); + } else if (active_thread_id != std::numeric_limits::max()) { + return {ErrorDescription::Busy, ErrorModule::GX, ErrorSummary::WouldBlock, + ErrorLevel::Status}; + } active_thread_id = session_data->thread_id; + return RESULT_SUCCESS; +} - rb.Push(RESULT_SUCCESS); +void GSP_GPU::TryAcquireRight(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + const auto process = rp.PopObject(); + + const auto result = AcquireGpuRight(ctx, process, 0, false); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(result); +} + +void GSP_GPU::AcquireRight(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + const auto flag = rp.Pop(); + const auto process = rp.PopObject(); + + const auto result = AcquireGpuRight(ctx, process, flag, true); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(result); } void GSP_GPU::ReleaseRight(const SessionData* session_data) { ASSERT_MSG(active_thread_id == session_data->thread_id, "Wrong thread tried to release GPU right"); - active_thread_id = UINT32_MAX; + active_thread_id = std::numeric_limits::max(); } void GSP_GPU::ReleaseRight(Kernel::HLERequestContext& ctx) { @@ -863,6 +886,18 @@ void GSP_GPU::SetLedForceOff(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_GSP, "(STUBBED) called"); } +void GSP_GPU::SetInternalPriorities(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + const auto priority = rp.Pop(); + const auto priority_with_rights = rp.Pop(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_DEBUG(Service_GSP, "(STUBBED) called priority={:#02X}, priority_with_rights={:#02X}", + priority, priority_with_rights); +} + SessionData* GSP_GPU::FindRegisteredThreadData(u32 thread_id) { for (auto& session_info : connected_sessions) { SessionData* data = static_cast(session_info.data.get()); @@ -874,6 +909,17 @@ SessionData* GSP_GPU::FindRegisteredThreadData(u32 thread_id) { return nullptr; } +template +void GSP_GPU::serialize(Archive& ar, const unsigned int) { + ar& boost::serialization::base_object(*this); + ar& shared_memory; + ar& active_thread_id; + ar& first_initialization; + ar& used_thread_ids; + ar& saved_vram; +} +SERIALIZE_IMPL(GSP_GPU) + GSP_GPU::GSP_GPU(Core::System& system) : ServiceFramework("gsp::Gpu", 4), system(system) { static const FunctionInfo functions[] = { // clang-format off @@ -897,7 +943,7 @@ GSP_GPU::GSP_GPU(Core::System& system) : ServiceFramework("gsp::Gpu", 4), system {0x0012, nullptr, "GetPerfLog"}, {0x0013, &GSP_GPU::RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"}, {0x0014, &GSP_GPU::UnregisterInterruptRelayQueue, "UnregisterInterruptRelayQueue"}, - {0x0015, nullptr, "TryAcquireRight"}, + {0x0015, &GSP_GPU::TryAcquireRight, "TryAcquireRight"}, {0x0016, &GSP_GPU::AcquireRight, "AcquireRight"}, {0x0017, &GSP_GPU::ReleaseRight, "ReleaseRight"}, {0x0018, &GSP_GPU::ImportDisplayCaptureInfo, "ImportDisplayCaptureInfo"}, @@ -906,7 +952,7 @@ GSP_GPU::GSP_GPU(Core::System& system) : ServiceFramework("gsp::Gpu", 4), system {0x001B, nullptr, "ResetGpuCore"}, {0x001C, &GSP_GPU::SetLedForceOff, "SetLedForceOff"}, {0x001D, nullptr, "SetTestCommand"}, - {0x001E, nullptr, "SetInternalPriorities"}, + {0x001E, &GSP_GPU::SetInternalPriorities, "SetInternalPriorities"}, {0x001F, &GSP_GPU::StoreDataCache, "StoreDataCache"}, // clang-format on }; @@ -926,6 +972,16 @@ std::unique_ptr GSP_GPU::MakeSes return std::make_unique(this); } +template +void SessionData::serialize(Archive& ar, const unsigned int) { + ar& boost::serialization::base_object(*this); + ar& gsp; + ar& interrupt_event; + ar& thread_id; + ar& registered; +} +SERIALIZE_IMPL(SessionData) + SessionData::SessionData(GSP_GPU* gsp) : gsp(gsp) { // Assign a new thread id to this session when it connects. Note: In the real GSP service this // is done through a real thread (svcCreateThread) but we have to simulate it since our HLE diff --git a/src/core/hle/service/gsp/gsp_gpu.h b/src/core/hle/service/gsp/gsp_gpu.h index 048733898..bc3b5017d 100644 --- a/src/core/hle/service/gsp/gsp_gpu.h +++ b/src/core/hle/service/gsp/gsp_gpu.h @@ -7,9 +7,8 @@ #include #include #include -#include -#include -#include +#include +#include #include "common/bit_field.h" #include "common/common_types.h" #include "core/hle/kernel/event.h" @@ -22,6 +21,8 @@ class System; } namespace Kernel { +class HLERequestContext; +class Process; class SharedMemory; } // namespace Kernel @@ -214,14 +215,7 @@ public: private: template - void serialize(Archive& ar, const unsigned int) { - ar& boost::serialization::base_object( - *this); - ar& gsp; - ar& interrupt_event; - ar& thread_id; - ar& registered; - } + void serialize(Archive& ar, const unsigned int); friend class boost::serialization::access; }; @@ -379,9 +373,25 @@ private: void UnregisterInterruptRelayQueue(Kernel::HLERequestContext& ctx); /** - * GSP_GPU::AcquireRight service function + * GSP_GPU::TryAcquireRight service function + * Inputs: + * 0 : Header code [0x00150002] + * 1 : Handle translate header (0x0) + * 2 : Process handle * Outputs: - * 1: Result code + * 1 : Result of function, 0 on success, otherwise error code + */ + void TryAcquireRight(Kernel::HLERequestContext& ctx); + + /** + * GSP_GPU::AcquireRight service function + * Inputs: + * 0 : Header code [0x00160042] + * 1 : Flags + * 2 : Handle translate header (0x0) + * 3 : Process handle + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code */ void AcquireRight(Kernel::HLERequestContext& ctx); @@ -464,6 +474,17 @@ private: /// Force the 3D LED State (0 = On, Non-Zero = Off) void SetLedForceOff(Kernel::HLERequestContext& ctx); + /** + * GSP_GPU::SetInternalPriorities service function + * Inputs: + * 0 : Header code [0x001E0080] + * 1 : Session thread priority + * 2 : Session thread priority with rights + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void SetInternalPriorities(Kernel::HLERequestContext& ctx); + /// Returns the session data for the specified registered thread id, or nullptr if not found. SessionData* FindRegisteredThreadData(u32 thread_id); @@ -471,13 +492,17 @@ private: std::unique_ptr MakeSessionData() override; + ResultCode AcquireGpuRight(const Kernel::HLERequestContext& ctx, + const std::shared_ptr& process, u32 flag, + bool blocking); + Core::System& system; /// GSP shared memory std::shared_ptr shared_memory; - /// Thread id that currently has GPU rights or UINT32_MAX if none. - u32 active_thread_id = UINT32_MAX; + /// Thread id that currently has GPU rights or std::numeric_limits::max() if none. + u32 active_thread_id = std::numeric_limits::max(); bool first_initialization = true; @@ -493,15 +518,7 @@ private: friend class SessionData; template - void serialize(Archive& ar, const unsigned int) { - ar& boost::serialization::base_object(*this); - ar& shared_memory; - ar& active_thread_id; - ar& first_initialization; - ar& used_thread_ids; - ar& saved_vram; - } - + void serialize(Archive& ar, const unsigned int); friend class boost::serialization::access; };