mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-27 13:55:29 +03:00
Implement mmnv::IRequest for media module clock control
This is used by games before calling into nvdec in order to clock up the HW module, it can also be used to request a RAM frequency. Since we obviously don't emulate the hardware down to this level a basic stub that provides the correct reponses is enough. Fixes a crash on first level of Super Mario Odyssey.
This commit is contained in:
parent
54d39fbaa7
commit
a7dc69223b
@ -192,6 +192,7 @@ add_library(skyline SHARED
|
||||
${source_DIR}/skyline/services/ssl/ISslService.cpp
|
||||
${source_DIR}/skyline/services/ssl/ISslContext.cpp
|
||||
${source_DIR}/skyline/services/prepo/IPrepoService.cpp
|
||||
${source_DIR}/skyline/services/mmnv/IRequest.cpp
|
||||
)
|
||||
# target_precompile_headers(skyline PRIVATE ${source_DIR}/skyline/common.h) # PCH will currently break Intellisense
|
||||
target_link_libraries(skyline android perfetto fmt lz4_static tzcode oboe mbedtls::mbedcrypto)
|
||||
|
146
app/src/main/cpp/skyline/services/mmnv/IRequest.cpp
Normal file
146
app/src/main/cpp/skyline/services/mmnv/IRequest.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <kernel/types/KProcess.h>
|
||||
#include "IRequest.h"
|
||||
|
||||
namespace skyline::service::mmnv {
|
||||
IRequest::IRequest(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {}
|
||||
|
||||
IRequest::Allocation IRequest::AllocateRequest() {
|
||||
// Search existing requests first
|
||||
for (u32 i{}; i < requests.size(); i++) {
|
||||
auto &req = requests[i];
|
||||
if (!req) {
|
||||
return {req.emplace(), i};
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate a new request otherwise
|
||||
return {requests.emplace_back().emplace(), static_cast<u32>(requests.size() - 1)};
|
||||
}
|
||||
|
||||
Result IRequest::InitializeOld(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto module{request.Pop<ModuleType>()};
|
||||
request.Skip<u32>(); // Unknown unused param in HOS
|
||||
//u32 autoClear{request.Pop<u32>()};
|
||||
|
||||
std::lock_guard lock(requestsMutex);
|
||||
AllocateRequest().request.module = module;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IRequest::FinalizeOld(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto module{request.Pop<ModuleType>()};
|
||||
|
||||
std::lock_guard lock(requestsMutex);
|
||||
for (auto &req : requests) {
|
||||
if (req && req->module == module) {
|
||||
req.reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IRequest::SetAndWaitOld(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto module{request.Pop<ModuleType>()};
|
||||
u32 freqHz{request.Pop<u32>()};
|
||||
|
||||
std::lock_guard lock(requestsMutex);
|
||||
for (auto &req : requests) {
|
||||
if (req && req->module == module) {
|
||||
req->freqHz = freqHz;
|
||||
state.logger->Debug("Set frequency for module {}: {} Hz", static_cast<u32>(module), freqHz);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// This doesn't return any errors in HOS
|
||||
state.logger->Warn("Tried to set frequency to {} Hz for unregistered module {}", freqHz, static_cast<u32>(module));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IRequest::GetOld(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto module{request.Pop<ModuleType>()};
|
||||
|
||||
std::lock_guard lock(requestsMutex);
|
||||
for (auto &req : requests) {
|
||||
if (req && req->module == module) {
|
||||
state.logger->Debug("Get frequency for module {}: {} Hz", static_cast<u32>(module), req->freqHz);
|
||||
response.Push<u32>(req->freqHz);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// This doesn't return any errors in HOS
|
||||
state.logger->Warn("Tried to get frequency of unregistered module {}", static_cast<u32>(module));
|
||||
response.Push<u32>(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IRequest::Initialize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto module{request.Pop<ModuleType>()};
|
||||
request.Skip<u32>(); // Unknown unused param in HOS
|
||||
//u32 autoClear{request.Pop<u32>()};
|
||||
|
||||
std::lock_guard lock(requestsMutex);
|
||||
auto req{AllocateRequest()};
|
||||
req.request.module = module;
|
||||
response.Push<u32>(req.id);
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IRequest::Finalize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
u32 id{request.Pop<u32>()};
|
||||
|
||||
std::lock_guard lock(requestsMutex);
|
||||
if (id >= requests.size())
|
||||
return {};
|
||||
|
||||
requests[id].reset();
|
||||
return {};
|
||||
};
|
||||
|
||||
Result IRequest::SetAndWait(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
u32 id{request.Pop<u32>()};
|
||||
u32 freqHz{request.Pop<u32>()};
|
||||
|
||||
std::lock_guard lock(requestsMutex);
|
||||
if (id < requests.size()) {
|
||||
auto &req{requests[id]};
|
||||
if (req) {
|
||||
req->freqHz = freqHz;
|
||||
state.logger->Debug("Set frequency for request {}: {} Hz", id, freqHz);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// This doesn't return any errors in HOS
|
||||
state.logger->Warn("Tried to set frequency for unregistered request {}", id);
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IRequest::Get(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
u32 id{request.Pop<u32>()};
|
||||
u32 freqHz{request.Pop<u32>()};
|
||||
|
||||
std::lock_guard lock(requestsMutex);
|
||||
if (id >= requests.size()) {
|
||||
auto &req{requests[id]};
|
||||
if (req) {
|
||||
state.logger->Debug("Get frequency for request {}: {} Hz", id, req->freqHz);
|
||||
response.Push<u32>(req->freqHz);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// This doesn't return any errors in HOS
|
||||
state.logger->Warn("Tried to get frequency of unregistered request {}", id);
|
||||
response.Push<u32>(0);
|
||||
return {};
|
||||
}
|
||||
}
|
105
app/src/main/cpp/skyline/services/mmnv/IRequest.h
Normal file
105
app/src/main/cpp/skyline/services/mmnv/IRequest.h
Normal file
@ -0,0 +1,105 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <kernel/types/KEvent.h>
|
||||
#include <services/serviceman.h>
|
||||
|
||||
namespace skyline::service::mmnv {
|
||||
/**
|
||||
* @brief IRequest or mm:u is used to control clocks and powergating of various hardware modules
|
||||
* @url https://switchbrew.org/wiki/Display_services#mm:u
|
||||
*/
|
||||
class IRequest : public BaseService {
|
||||
private:
|
||||
/**
|
||||
* @brief Enumerates the modules that can be controlled by mmnv, these are passed directly to FGM services
|
||||
*/
|
||||
enum class ModuleType : u32 {
|
||||
Ram = 2,
|
||||
NvEnc = 5,
|
||||
NvDec = 6,
|
||||
NvJpg = 7
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Holds a single mmnv request, detailing its target module and current frequency
|
||||
*/
|
||||
struct Request {
|
||||
ModuleType module;
|
||||
u32 freqHz;
|
||||
};
|
||||
|
||||
std::mutex requestsMutex; // Protects accesses to requests
|
||||
std::vector<std::optional<Request>> requests; //!< Holds allocated requests with the index corresponding to the request ID
|
||||
|
||||
/**
|
||||
* @brief Holds the result of a request allocation
|
||||
*/
|
||||
struct Allocation {
|
||||
Request &request;
|
||||
u32 id;
|
||||
};
|
||||
|
||||
/*
|
||||
* @note requestsMutex should be locked when calling this
|
||||
* @return A reference to an empty request
|
||||
*/
|
||||
Allocation AllocateRequest();
|
||||
|
||||
public:
|
||||
IRequest(const DeviceState &state, ServiceManager &manager);
|
||||
|
||||
/**
|
||||
* @brief Initialises the request for the given module ID
|
||||
*/
|
||||
Result InitializeOld(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Finalises the request for the given module ID
|
||||
*/
|
||||
Result FinalizeOld(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Sets the target frequency in HZ for the given module and waits for it to be applied
|
||||
*/
|
||||
Result SetAndWaitOld(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Gets the frequency in HZ for the given module
|
||||
*/
|
||||
Result GetOld(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Initialises a new request for the given module ID and returns a new request ID
|
||||
*/
|
||||
Result Initialize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Finalises the request with the given ID
|
||||
*/
|
||||
Result Finalize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Sets the target frequency in HZ for the request with the given ID and waits for it to be applied
|
||||
*/
|
||||
Result SetAndWait(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
/**
|
||||
* @brief Gets the frequency in HZ for the request with the given ID
|
||||
*/
|
||||
Result Get(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||
|
||||
SERVICE_DECL(
|
||||
SFUNC(0x0, IRequest, InitializeOld),
|
||||
SFUNC(0x1, IRequest, FinalizeOld),
|
||||
SFUNC(0x2, IRequest, SetAndWaitOld),
|
||||
SFUNC(0x3, IRequest, GetOld),
|
||||
SFUNC(0x4, IRequest, Initialize),
|
||||
SFUNC(0x5, IRequest, Finalize),
|
||||
SFUNC(0x6, IRequest, SetAndWait),
|
||||
SFUNC(0x7, IRequest, Get)
|
||||
)
|
||||
};
|
||||
}
|
@ -30,6 +30,7 @@
|
||||
#include "socket/bsd/IClient.h"
|
||||
#include "ssl/ISslService.h"
|
||||
#include "prepo/IPrepoService.h"
|
||||
#include "mmnv/IRequest.h"
|
||||
#include "serviceman.h"
|
||||
|
||||
#define SERVICE_CASE(class, name, ...) \
|
||||
@ -90,6 +91,7 @@ namespace skyline::service {
|
||||
SERVICE_CASE(socket::IClient, "bsd:u")
|
||||
SERVICE_CASE(ssl::ISslService, "ssl")
|
||||
SERVICE_CASE(prepo::IPrepoService, "prepo:u")
|
||||
SERVICE_CASE(mmnv::IRequest, "mm:u")
|
||||
default:
|
||||
std::string_view nameString(span(reinterpret_cast<char *>(&name), sizeof(name)).as_string(true));
|
||||
throw std::out_of_range(fmt::format("CreateService called with an unknown service name: {}", nameString));
|
||||
|
Loading…
Reference in New Issue
Block a user