diff options
author | Zephyron <zephyron@citron-emu.org> | 2025-01-25 14:55:50 +1000 |
---|---|---|
committer | Zephyron <zephyron@citron-emu.org> | 2025-01-25 14:55:50 +1000 |
commit | c279df9cfe50ea918abaf10b0f856118a1fcb11f (patch) | |
tree | d3970a267eee5de632df44bf8947960695286bbf /src | |
parent | 0adeac26af77c7fb0605b08ab858a7c8262ffc88 (diff) |
service: mm: Refactor Memory Management service implementation
Refactors the MM (Memory Management) service implementation with improved:
- Session management using a vector of Session objects instead of global vars
- Type safety with proper enums and member encapsulation
- Error handling with consistent patterns
- Modern C++ features (std::erase_if, std::find_if, emplace_back)
- Logging with detailed debug messages
- Code organization and const correctness
Key changes:
- Add Session class with proper encapsulation
- Add EventClearMode enum (Manual = 0, Auto = 1)
- Update Module enum naming for consistency
- Implement proper session tracking and lookup
- Add detailed parameter logging
- Use modern C++ algorithms for session management
The implementation now properly handles multiple sessions and matches
the documented nn::mmnv::IRequest interface more closely.
Refs: switchbrew.org/wiki/Display_services#mm:u
Diffstat (limited to 'src')
-rw-r--r-- | src/core/hle/service/mm/mm_u.cpp | 111 | ||||
-rw-r--r-- | src/core/hle/service/mm/mm_u.h | 44 |
2 files changed, 117 insertions, 38 deletions
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp index 64e3c3eea..a99c01286 100644 --- a/src/core/hle/service/mm/mm_u.cpp +++ b/src/core/hle/service/mm/mm_u.cpp @@ -2,6 +2,7 @@ // SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include <algorithm> #include "common/logging/log.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/mm/mm_u.h" @@ -25,7 +26,6 @@ public: {7, &MM_U::Get, "Get"}, }; // clang-format on - RegisterHandlers(functions); } @@ -33,11 +33,13 @@ private: void InitializeOld(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto module = rp.PopEnum<Module>(); - const auto priority = rp.Pop<Priority>(); - const auto event_clear_mode = rp.PopEnum<EventClearMode>(); + [[maybe_unused]] const auto priority = rp.Pop<u32>(); + const auto clear_mode = static_cast<EventClearMode>(rp.Pop<u32>()); + + LOG_DEBUG(Service_MM, "called. module={:d}, clear_mode={:d}", + static_cast<u32>(module), static_cast<u32>(clear_mode)); - LOG_WARNING(Service_MM, "(STUBBED) called, module={:d}, priority={:d}, event_clear_mode={:d}", - static_cast<u32>(module), priority, static_cast<u32>(event_clear_mode)); + sessions.emplace_back(module, next_request_id++, clear_mode); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -47,7 +49,11 @@ private: IPC::RequestParser rp{ctx}; const auto module = rp.PopEnum<Module>(); - LOG_WARNING(Service_MM, "(STUBBED) called, module={:d}", static_cast<u32>(module)); + LOG_DEBUG(Service_MM, "called. module={:d}", static_cast<u32>(module)); + + std::erase_if(sessions, [&module](const auto& session) { + return session.GetModule() == module; + }); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -56,13 +62,20 @@ private: void SetAndWaitOld(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto module = rp.PopEnum<Module>(); - min = rp.Pop<Setting>(); - max = rp.Pop<Setting>(); + const auto min = rp.Pop<u32>(); + const auto max = rp.Pop<s32>(); - LOG_DEBUG(Service_MM, "(STUBBED) called, module={:d}, min=0x{:X}, max=0x{:X}", + LOG_DEBUG(Service_MM, "called. module={:d}, min=0x{:X}, max=0x{:X}", static_cast<u32>(module), min, max); - current = min; + if (auto it = std::find_if(sessions.begin(), sessions.end(), + [&module](const auto& session) { + return session.GetModule() == module; + }); + it != sessions.end()) { + it->SetAndWait(min, max); + } + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -71,23 +84,48 @@ private: IPC::RequestParser rp{ctx}; const auto module = rp.PopEnum<Module>(); - LOG_DEBUG(Service_MM, "(STUBBED) called, module={:d}", static_cast<u32>(module)); + LOG_DEBUG(Service_MM, "called. module={:d}", static_cast<u32>(module)); + + u32 current_min = 0; + if (auto it = std::find_if(sessions.begin(), sessions.end(), + [&module](const auto& session) { + return session.GetModule() == module; + }); + it != sessions.end()) { + current_min = it->GetMin(); + } IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(current); + rb.Push(current_min); } void Initialize(HLERequestContext& ctx) { - LOG_WARNING(Service_MM, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + const auto module = rp.PopEnum<Module>(); + [[maybe_unused]] const auto priority = rp.Pop<u32>(); + const auto clear_mode = static_cast<EventClearMode>(rp.Pop<u32>()); + + LOG_DEBUG(Service_MM, "called. module={:d}, clear_mode={:d}", + static_cast<u32>(module), static_cast<u32>(clear_mode)); + + const u32 current_id = next_request_id++; + sessions.emplace_back(module, current_id, clear_mode); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push<u32>(id); // Any non zero value + rb.Push(current_id); } void Finalize(HLERequestContext& ctx) { - LOG_WARNING(Service_MM, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + const auto request_id = rp.Pop<u32>(); + + LOG_DEBUG(Service_MM, "called. request_id={:d}", request_id); + + std::erase_if(sessions, [&request_id](const auto& session) { + return session.GetRequestId() == request_id; + }); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -95,34 +133,51 @@ private: void SetAndWait(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u32 input_id = rp.Pop<u32>(); - min = rp.Pop<u32>(); - max = rp.Pop<u32>(); - LOG_DEBUG(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", input_id, - min, max); + const auto request_id = rp.Pop<u32>(); + const auto min = rp.Pop<u32>(); + const auto max = rp.Pop<s32>(); + + LOG_DEBUG(Service_MM, "called. request_id={:d}, min=0x{:X}, max=0x{:X}", + request_id, min, max); + + if (auto it = std::find_if(sessions.begin(), sessions.end(), + [&request_id](const auto& session) { + return session.GetRequestId() == request_id; + }); + it != sessions.end()) { + it->SetAndWait(min, max); + } - current = min; IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void Get(HLERequestContext& ctx) { - LOG_DEBUG(Service_MM, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + const auto request_id = rp.Pop<u32>(); + + LOG_DEBUG(Service_MM, "called. request_id={:d}", request_id); + + u32 current_min = 0; + if (auto it = std::find_if(sessions.begin(), sessions.end(), + [&request_id](const auto& session) { + return session.GetRequestId() == request_id; + }); + it != sessions.end()) { + current_min = it->GetMin(); + } IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(current); + rb.Push(current_min); } - u32 min{0}; - u32 max{0}; - u32 current{0}; - u32 id{1}; + std::vector<Session> sessions; + u32 next_request_id{1}; }; void LoopProcess(Core::System& system) { auto server_manager = std::make_unique<ServerManager>(system); - server_manager->RegisterNamedService("mm:u", std::make_shared<MM_U>(system)); ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/mm/mm_u.h b/src/core/hle/service/mm/mm_u.h index bae9eabf8..dd0a567cf 100644 --- a/src/core/hle/service/mm/mm_u.h +++ b/src/core/hle/service/mm/mm_u.h @@ -4,6 +4,7 @@ #pragma once +#include <vector> #include "common/common_types.h" namespace Core { @@ -13,22 +14,23 @@ class System; namespace Service::MM { enum class Module : u32 { - Cpu = 0, - Gpu = 1, - Emc = 2, - SysBus = 3, - Mselect = 4, - Nvdec = 5, - Nvenc = 6, - Nvjpg = 7, - Test = 8, + CPU = 0, + GPU = 1, + EMC = 2, + SYS_BUS = 3, + M_SELECT = 4, + NVDEC = 5, + NVENC = 6, + NVJPG = 7, + TEST = 8, }; using Priority = u32; using Setting = u32; enum class EventClearMode : u32 { - // TODO: Add specific clear mode values when documented + Manual = 0, + Auto = 1, }; // Consolidate settings into a struct for better organization @@ -39,6 +41,28 @@ struct Settings { u32 id{1}; // Used by newer API versions }; +class Session { +public: + explicit Session(Module module_, u32 request_id_, EventClearMode clear_mode_) + : module{module_}, request_id{request_id_}, clear_mode{clear_mode_} {} + + void SetAndWait(u32 min_, s32 max_) { + min = min_; + max = max_; + } + + [[nodiscard]] u32 GetMin() const { return min; } + [[nodiscard]] Module GetModule() const { return module; } + [[nodiscard]] u32 GetRequestId() const { return request_id; } + +private: + Module module; + u32 request_id{0}; + u32 min{0}; + s32 max{-1}; + EventClearMode clear_mode; +}; + void LoopProcess(Core::System& system); } // namespace Service::MM |