gsp_gpu: Implement TryAcquireRight and stub SetInternalPriorities. (#7285)

* gsp_gpu: Implement TryAcquireRight.

* gsp_gpu: Stub SetInternalPriorities.

* gsp_gpu: Move serialization logic into implementation.

* gsp_gpu: Replace UINT32_MAX with std::numeric_limits<u32>::max().
This commit is contained in:
Steveice10 2023-12-25 08:29:17 -08:00 committed by GitHub
parent b6b98af105
commit bd4ec251cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 119 additions and 46 deletions

View File

@ -4,6 +4,9 @@
#include <span> #include <span>
#include <vector> #include <vector>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/optional.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include "common/archives.h" #include "common/archives.h"
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/microprofile.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. // 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<u32>::max()) {
return; return;
} }
@ -664,7 +667,7 @@ void GSP_GPU::TriggerCmdReqQueue(Kernel::HLERequestContext& ctx) {
void GSP_GPU::ImportDisplayCaptureInfo(Kernel::HLERequestContext& ctx) { void GSP_GPU::ImportDisplayCaptureInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
if (active_thread_id == UINT32_MAX) { if (active_thread_id == std::numeric_limits<u32>::max()) {
LOG_WARNING(Service_GSP, "Called without an active thread."); LOG_WARNING(Service_GSP, "Called without an active thread.");
// TODO: Find the right error code. // TODO: Find the right error code.
@ -792,37 +795,57 @@ void GSP_GPU::RestoreVramSysArea(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
} }
void GSP_GPU::AcquireRight(Kernel::HLERequestContext& ctx) { ResultCode GSP_GPU::AcquireGpuRight(const Kernel::HLERequestContext& ctx,
IPC::RequestParser rp(ctx); const std::shared_ptr<Kernel::Process>& process, u32 flag,
bool blocking) {
const auto session_data = GetSessionData(ctx.Session());
u32 flag = rp.Pop<u32>(); LOG_DEBUG(Service_GSP, "called flag={:08X} process={} thread_id={}", flag, process->process_id,
auto process = rp.PopObject<Kernel::Process>(); session_data->thread_id);
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);
if (active_thread_id == session_data->thread_id) { if (active_thread_id == session_data->thread_id) {
rb.Push(ResultCode(ErrorDescription::AlreadyDone, ErrorModule::GX, ErrorSummary::Success, return {ErrorDescription::AlreadyDone, ErrorModule::GX, ErrorSummary::Success,
ErrorLevel::Success)); ErrorLevel::Success};
return;
} }
// TODO(Subv): This case should put the caller thread to sleep until the right is released. if (blocking) {
ASSERT_MSG(active_thread_id == UINT32_MAX, "GPU right has already been acquired"); // TODO: The thread should be put to sleep until acquired.
ASSERT_MSG(active_thread_id == std::numeric_limits<u32>::max(),
"Sleeping for GPU right is not yet supported.");
} else if (active_thread_id != std::numeric_limits<u32>::max()) {
return {ErrorDescription::Busy, ErrorModule::GX, ErrorSummary::WouldBlock,
ErrorLevel::Status};
}
active_thread_id = session_data->thread_id; 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<Kernel::Process>();
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<u32>();
const auto process = rp.PopObject<Kernel::Process>();
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) { void GSP_GPU::ReleaseRight(const SessionData* session_data) {
ASSERT_MSG(active_thread_id == session_data->thread_id, ASSERT_MSG(active_thread_id == session_data->thread_id,
"Wrong thread tried to release GPU right"); "Wrong thread tried to release GPU right");
active_thread_id = UINT32_MAX; active_thread_id = std::numeric_limits<u32>::max();
} }
void GSP_GPU::ReleaseRight(Kernel::HLERequestContext& ctx) { void GSP_GPU::ReleaseRight(Kernel::HLERequestContext& ctx) {
@ -863,6 +886,18 @@ void GSP_GPU::SetLedForceOff(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_GSP, "(STUBBED) called"); LOG_DEBUG(Service_GSP, "(STUBBED) called");
} }
void GSP_GPU::SetInternalPriorities(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const auto priority = rp.Pop<u32>();
const auto priority_with_rights = rp.Pop<u32>();
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) { SessionData* GSP_GPU::FindRegisteredThreadData(u32 thread_id) {
for (auto& session_info : connected_sessions) { for (auto& session_info : connected_sessions) {
SessionData* data = static_cast<SessionData*>(session_info.data.get()); SessionData* data = static_cast<SessionData*>(session_info.data.get());
@ -874,6 +909,17 @@ SessionData* GSP_GPU::FindRegisteredThreadData(u32 thread_id) {
return nullptr; return nullptr;
} }
template <class Archive>
void GSP_GPU::serialize(Archive& ar, const unsigned int) {
ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*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) { GSP_GPU::GSP_GPU(Core::System& system) : ServiceFramework("gsp::Gpu", 4), system(system) {
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
// clang-format off // clang-format off
@ -897,7 +943,7 @@ GSP_GPU::GSP_GPU(Core::System& system) : ServiceFramework("gsp::Gpu", 4), system
{0x0012, nullptr, "GetPerfLog"}, {0x0012, nullptr, "GetPerfLog"},
{0x0013, &GSP_GPU::RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"}, {0x0013, &GSP_GPU::RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"},
{0x0014, &GSP_GPU::UnregisterInterruptRelayQueue, "UnregisterInterruptRelayQueue"}, {0x0014, &GSP_GPU::UnregisterInterruptRelayQueue, "UnregisterInterruptRelayQueue"},
{0x0015, nullptr, "TryAcquireRight"}, {0x0015, &GSP_GPU::TryAcquireRight, "TryAcquireRight"},
{0x0016, &GSP_GPU::AcquireRight, "AcquireRight"}, {0x0016, &GSP_GPU::AcquireRight, "AcquireRight"},
{0x0017, &GSP_GPU::ReleaseRight, "ReleaseRight"}, {0x0017, &GSP_GPU::ReleaseRight, "ReleaseRight"},
{0x0018, &GSP_GPU::ImportDisplayCaptureInfo, "ImportDisplayCaptureInfo"}, {0x0018, &GSP_GPU::ImportDisplayCaptureInfo, "ImportDisplayCaptureInfo"},
@ -906,7 +952,7 @@ GSP_GPU::GSP_GPU(Core::System& system) : ServiceFramework("gsp::Gpu", 4), system
{0x001B, nullptr, "ResetGpuCore"}, {0x001B, nullptr, "ResetGpuCore"},
{0x001C, &GSP_GPU::SetLedForceOff, "SetLedForceOff"}, {0x001C, &GSP_GPU::SetLedForceOff, "SetLedForceOff"},
{0x001D, nullptr, "SetTestCommand"}, {0x001D, nullptr, "SetTestCommand"},
{0x001E, nullptr, "SetInternalPriorities"}, {0x001E, &GSP_GPU::SetInternalPriorities, "SetInternalPriorities"},
{0x001F, &GSP_GPU::StoreDataCache, "StoreDataCache"}, {0x001F, &GSP_GPU::StoreDataCache, "StoreDataCache"},
// clang-format on // clang-format on
}; };
@ -926,6 +972,16 @@ std::unique_ptr<Kernel::SessionRequestHandler::SessionDataBase> GSP_GPU::MakeSes
return std::make_unique<SessionData>(this); return std::make_unique<SessionData>(this);
} }
template <class Archive>
void SessionData::serialize(Archive& ar, const unsigned int) {
ar& boost::serialization::base_object<Kernel::SessionRequestHandler::SessionDataBase>(*this);
ar& gsp;
ar& interrupt_event;
ar& thread_id;
ar& registered;
}
SERIALIZE_IMPL(SessionData)
SessionData::SessionData(GSP_GPU* gsp) : gsp(gsp) { 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 // 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 // is done through a real thread (svcCreateThread) but we have to simulate it since our HLE

View File

@ -7,9 +7,8 @@
#include <cstddef> #include <cstddef>
#include <memory> #include <memory>
#include <string> #include <string>
#include <boost/serialization/base_object.hpp> #include <boost/optional/optional.hpp>
#include <boost/serialization/optional.hpp> #include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/kernel/event.h" #include "core/hle/kernel/event.h"
@ -22,6 +21,8 @@ class System;
} }
namespace Kernel { namespace Kernel {
class HLERequestContext;
class Process;
class SharedMemory; class SharedMemory;
} // namespace Kernel } // namespace Kernel
@ -214,14 +215,7 @@ public:
private: private:
template <class Archive> template <class Archive>
void serialize(Archive& ar, const unsigned int) { void serialize(Archive& ar, const unsigned int);
ar& boost::serialization::base_object<Kernel::SessionRequestHandler::SessionDataBase>(
*this);
ar& gsp;
ar& interrupt_event;
ar& thread_id;
ar& registered;
}
friend class boost::serialization::access; friend class boost::serialization::access;
}; };
@ -379,9 +373,25 @@ private:
void UnregisterInterruptRelayQueue(Kernel::HLERequestContext& ctx); 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: * 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); void AcquireRight(Kernel::HLERequestContext& ctx);
@ -464,6 +474,17 @@ private:
/// Force the 3D LED State (0 = On, Non-Zero = Off) /// Force the 3D LED State (0 = On, Non-Zero = Off)
void SetLedForceOff(Kernel::HLERequestContext& ctx); 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. /// Returns the session data for the specified registered thread id, or nullptr if not found.
SessionData* FindRegisteredThreadData(u32 thread_id); SessionData* FindRegisteredThreadData(u32 thread_id);
@ -471,13 +492,17 @@ private:
std::unique_ptr<Kernel::SessionRequestHandler::SessionDataBase> MakeSessionData() override; std::unique_ptr<Kernel::SessionRequestHandler::SessionDataBase> MakeSessionData() override;
ResultCode AcquireGpuRight(const Kernel::HLERequestContext& ctx,
const std::shared_ptr<Kernel::Process>& process, u32 flag,
bool blocking);
Core::System& system; Core::System& system;
/// GSP shared memory /// GSP shared memory
std::shared_ptr<Kernel::SharedMemory> shared_memory; std::shared_ptr<Kernel::SharedMemory> shared_memory;
/// Thread id that currently has GPU rights or UINT32_MAX if none. /// Thread id that currently has GPU rights or std::numeric_limits<u32>::max() if none.
u32 active_thread_id = UINT32_MAX; u32 active_thread_id = std::numeric_limits<u32>::max();
bool first_initialization = true; bool first_initialization = true;
@ -493,15 +518,7 @@ private:
friend class SessionData; friend class SessionData;
template <class Archive> template <class Archive>
void serialize(Archive& ar, const unsigned int) { void serialize(Archive& ar, const unsigned int);
ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
ar& shared_memory;
ar& active_thread_id;
ar& first_initialization;
ar& used_thread_ids;
ar& saved_vram;
}
friend class boost::serialization::access; friend class boost::serialization::access;
}; };