mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-26 00:34:18 +01:00
Rework VI + IHOSBinder
VI/IHOSBinder suffered from major inaccuracies in their function due to being quickly thrown together initially with little concern for accuracy, this has now been fixed with them being substantially more accurate now.
This commit is contained in:
parent
ca4744c603
commit
f1433ad0d9
@ -121,7 +121,6 @@ add_library(skyline SHARED
|
|||||||
${source_DIR}/skyline/vfs/ticket.cpp
|
${source_DIR}/skyline/vfs/ticket.cpp
|
||||||
${source_DIR}/skyline/services/serviceman.cpp
|
${source_DIR}/skyline/services/serviceman.cpp
|
||||||
${source_DIR}/skyline/services/base_service.cpp
|
${source_DIR}/skyline/services/base_service.cpp
|
||||||
${source_DIR}/skyline/services/common/parcel.cpp
|
|
||||||
${source_DIR}/skyline/services/sm/IUserInterface.cpp
|
${source_DIR}/skyline/services/sm/IUserInterface.cpp
|
||||||
${source_DIR}/skyline/services/fatalsrv/IService.cpp
|
${source_DIR}/skyline/services/fatalsrv/IService.cpp
|
||||||
${source_DIR}/skyline/services/audio/IAudioOutManager.cpp
|
${source_DIR}/skyline/services/audio/IAudioOutManager.cpp
|
||||||
@ -182,12 +181,13 @@ add_library(skyline SHARED
|
|||||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost_channel.cpp
|
${source_DIR}/skyline/services/nvdrv/devices/nvhost_channel.cpp
|
||||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp
|
${source_DIR}/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp
|
||||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost_syncpoint.cpp
|
${source_DIR}/skyline/services/nvdrv/devices/nvhost_syncpoint.cpp
|
||||||
|
${source_DIR}/skyline/services/hosbinder/parcel.cpp
|
||||||
${source_DIR}/skyline/services/hosbinder/IHOSBinderDriver.cpp
|
${source_DIR}/skyline/services/hosbinder/IHOSBinderDriver.cpp
|
||||||
${source_DIR}/skyline/services/hosbinder/GraphicBufferProducer.cpp
|
${source_DIR}/skyline/services/hosbinder/GraphicBufferProducer.cpp
|
||||||
${source_DIR}/skyline/services/visrv/IDisplayService.cpp
|
${source_DIR}/skyline/services/visrv/IDisplayService.cpp
|
||||||
${source_DIR}/skyline/services/visrv/IApplicationDisplayService.cpp
|
${source_DIR}/skyline/services/visrv/IApplicationDisplayService.cpp
|
||||||
${source_DIR}/skyline/services/visrv/IManagerDisplayService.cpp
|
${source_DIR}/skyline/services/visrv/IManagerDisplayService.cpp
|
||||||
${source_DIR}/skyline/services/visrv/IManagerRootService.cpp
|
${source_DIR}/skyline/services/visrv/IRootService.cpp
|
||||||
${source_DIR}/skyline/services/visrv/ISystemDisplayService.cpp
|
${source_DIR}/skyline/services/visrv/ISystemDisplayService.cpp
|
||||||
${source_DIR}/skyline/services/pl/IPlatformServiceManager.cpp
|
${source_DIR}/skyline/services/pl/IPlatformServiceManager.cpp
|
||||||
${source_DIR}/skyline/services/aocsrv/IAddOnContentManager.cpp
|
${source_DIR}/skyline/services/aocsrv/IAddOnContentManager.cpp
|
||||||
|
@ -218,11 +218,16 @@ namespace skyline {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns a std::string_view from the payload
|
* @brief Returns a std::string_view from the payload
|
||||||
* @param size The length of the string (0 means the string is null terminated)
|
* @param size The length of the string (0 should only be used with nullTerminated and automatically determines size)
|
||||||
|
* @param nullTerminated If the returned view should only encapsulate a null terminated substring
|
||||||
*/
|
*/
|
||||||
std::string_view PopString(size_t size = 0) {
|
std::string_view PopString(size_t size = 0, bool nullTerminated = true) {
|
||||||
auto view{size ? std::string_view(reinterpret_cast<const char *>(payloadOffset), size) : std::string_view(reinterpret_cast<const char *>(payloadOffset))};
|
size = size ? size : cmdArgSz - reinterpret_cast<u64>(payloadOffset);
|
||||||
payloadOffset += view.length();
|
auto view{span(payloadOffset, size).as_string(nullTerminated)};
|
||||||
|
if (nullTerminated)
|
||||||
|
payloadOffset += size;
|
||||||
|
else
|
||||||
|
payloadOffset += view.length();
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
#include <services/hosbinder/GraphicBufferProducer.h>
|
#include <services/hosbinder/IHOSBinderDriver.h>
|
||||||
#include "ISelfController.h"
|
#include "ISelfController.h"
|
||||||
|
|
||||||
namespace skyline::service::am {
|
namespace skyline::service::am {
|
||||||
ISelfController::ISelfController(const DeviceState &state, ServiceManager &manager) : libraryAppletLaunchableEvent(std::make_shared<type::KEvent>(state, false)), accumulatedSuspendedTickChangedEvent(std::make_shared<type::KEvent>(state, false)), BaseService(state, manager) {}
|
ISelfController::ISelfController(const DeviceState &state, ServiceManager &manager) : libraryAppletLaunchableEvent(std::make_shared<type::KEvent>(state, false)), accumulatedSuspendedTickChangedEvent(std::make_shared<type::KEvent>(state, false)), hosbinder(manager.CreateOrGetService<hosbinder::IHOSBinderDriver>("dispdrv")), BaseService(state, manager) {}
|
||||||
|
|
||||||
Result ISelfController::LockExit(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result ISelfController::LockExit(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
return {};
|
return {};
|
||||||
@ -47,18 +47,12 @@ namespace skyline::service::am {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result ISelfController::CreateManagedDisplayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result ISelfController::CreateManagedDisplayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
state.logger->Debug("Creating Managed Layer on Default Display");
|
auto layerId{hosbinder->CreateLayer(hosbinder::DisplayId::Default)};
|
||||||
|
state.logger->Debug("Creating Managed Layer #{} on 'Default' Display", layerId);
|
||||||
auto producer{hosbinder::producer.lock()};
|
response.Push(layerId);
|
||||||
if (producer->layerStatus != hosbinder::LayerStatus::Uninitialized)
|
|
||||||
throw exception("The application is creating more than one layer");
|
|
||||||
producer->layerStatus = hosbinder::LayerStatus::Managed;
|
|
||||||
|
|
||||||
response.Push<u64>(0);
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Result ISelfController::GetAccumulatedSuspendedTickValue(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result ISelfController::GetAccumulatedSuspendedTickValue(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
// TODO: Properly handle this after we implement game suspending
|
// TODO: Properly handle this after we implement game suspending
|
||||||
response.Push<u64>(0);
|
response.Push<u64>(0);
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
|
|
||||||
#include <services/serviceman.h>
|
#include <services/serviceman.h>
|
||||||
|
|
||||||
|
namespace skyline::service::hosbinder {
|
||||||
|
class IHOSBinderDriver;
|
||||||
|
}
|
||||||
|
|
||||||
namespace skyline::service::am {
|
namespace skyline::service::am {
|
||||||
/**
|
/**
|
||||||
* @brief This has functions relating to an application's own current status
|
* @brief This has functions relating to an application's own current status
|
||||||
@ -14,6 +18,7 @@ namespace skyline::service::am {
|
|||||||
private:
|
private:
|
||||||
std::shared_ptr<kernel::type::KEvent> libraryAppletLaunchableEvent; //!< This KEvent is triggered when the library applet is launchable
|
std::shared_ptr<kernel::type::KEvent> libraryAppletLaunchableEvent; //!< This KEvent is triggered when the library applet is launchable
|
||||||
std::shared_ptr<kernel::type::KEvent> accumulatedSuspendedTickChangedEvent; //!< This KEvent is triggered when the time the system has spent in suspend is updated
|
std::shared_ptr<kernel::type::KEvent> accumulatedSuspendedTickChangedEvent; //!< This KEvent is triggered when the time the system has spent in suspend is updated
|
||||||
|
std::shared_ptr<hosbinder::IHOSBinderDriver> hosbinder; //!< IHOSBinder service for managed display layers
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ISelfController(const DeviceState &state, ServiceManager &manager);
|
ISelfController(const DeviceState &state, ServiceManager &manager);
|
||||||
|
@ -70,7 +70,7 @@ namespace skyline::service::hosbinder {
|
|||||||
} else {
|
} else {
|
||||||
size_t index{};
|
size_t index{};
|
||||||
std::string bufferString;
|
std::string bufferString;
|
||||||
for (auto& bufferSlot : queue)
|
for (auto &bufferSlot : queue)
|
||||||
bufferString += util::Format("\n#{} - State: {}, Has Graphic Buffer: {}, Frame Number: {}", ++index, ToString(bufferSlot.state), static_cast<bool>(bufferSlot.graphicBuffer), bufferSlot.frameNumber);
|
bufferString += util::Format("\n#{} - State: {}, Has Graphic Buffer: {}, Frame Number: {}", ++index, ToString(bufferSlot.state), static_cast<bool>(bufferSlot.graphicBuffer), bufferSlot.frameNumber);
|
||||||
state.logger->Warn("Cannot find any free buffers to dequeue:{}", bufferString);
|
state.logger->Warn("Cannot find any free buffers to dequeue:{}", bufferString);
|
||||||
return AndroidStatus::InvalidOperation;
|
return AndroidStatus::InvalidOperation;
|
||||||
@ -489,31 +489,4 @@ namespace skyline::service::hosbinder {
|
|||||||
throw exception("An unimplemented transaction was called: {}", static_cast<u32>(code));
|
throw exception("An unimplemented transaction was called: {}", static_cast<u32>(code));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static frz::unordered_map<frz::string, DisplayId, 5> DisplayTypeMap{
|
|
||||||
{"Default", DisplayId::Default},
|
|
||||||
{"External", DisplayId::External},
|
|
||||||
{"Edid", DisplayId::Edid},
|
|
||||||
{"Internal", DisplayId::Internal},
|
|
||||||
{"Null", DisplayId::Null},
|
|
||||||
};
|
|
||||||
|
|
||||||
void GraphicBufferProducer::SetDisplay(const std::string &name) {
|
|
||||||
try {
|
|
||||||
if (displayId == DisplayId::Null)
|
|
||||||
displayId = DisplayTypeMap.at(frz::string(name.data(), name.size()));
|
|
||||||
else
|
|
||||||
throw exception("Trying to change display type from non-null type");
|
|
||||||
} catch (const std::out_of_range &) {
|
|
||||||
throw exception("The display with name: '{}' doesn't exist", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GraphicBufferProducer::CloseDisplay() {
|
|
||||||
if (displayId == DisplayId::Null)
|
|
||||||
state.logger->Warn("Trying to close uninitiated display");
|
|
||||||
displayId = DisplayId::Null;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::weak_ptr<GraphicBufferProducer> producer{};
|
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <kernel/types/KEvent.h>
|
#include <kernel/types/KEvent.h>
|
||||||
#include <services/common/parcel.h>
|
#include "parcel.h"
|
||||||
#include "android_types.h"
|
#include "android_types.h"
|
||||||
#include "native_window.h"
|
#include "native_window.h"
|
||||||
|
|
||||||
@ -43,24 +43,6 @@ namespace skyline::service::hosbinder {
|
|||||||
std::unique_ptr<GraphicBuffer> graphicBuffer{};
|
std::unique_ptr<GraphicBuffer> graphicBuffer{};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief An enumeration of all the possible display IDs
|
|
||||||
* @url https://switchbrew.org/wiki/Display_services#DisplayName
|
|
||||||
*/
|
|
||||||
enum class DisplayId : u64 {
|
|
||||||
Default, //!< Refers to the default display used by most applications
|
|
||||||
External, //!< Refers to an external display
|
|
||||||
Edid, //!< Refers to an external display with EDID capabilities
|
|
||||||
Internal, //!< Refers to the the internal display
|
|
||||||
Null, //!< Refers to the null display which is used for discarding data
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class LayerStatus {
|
|
||||||
Uninitialized, //!< The layer hasn't been initialized
|
|
||||||
Stray, //!< The layer has been initialized as a stray layer
|
|
||||||
Managed, //!< The layer has been initialized as a managed layer
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief An endpoint for the GraphicBufferProducer interface, it approximately implements BufferQueueProducer but also implements the functionality of interfaces called into by it such as GraphicBufferConsumer, Gralloc and so on
|
* @brief An endpoint for the GraphicBufferProducer interface, it approximately implements BufferQueueProducer but also implements the functionality of interfaces called into by it such as GraphicBufferConsumer, Gralloc and so on
|
||||||
* @url https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IGraphicBufferProducer.h
|
* @url https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IGraphicBufferProducer.h
|
||||||
@ -147,8 +129,6 @@ namespace skyline::service::hosbinder {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<kernel::type::KEvent> bufferEvent; //!< Signalled every time a buffer in the queue is freed
|
std::shared_ptr<kernel::type::KEvent> bufferEvent; //!< Signalled every time a buffer in the queue is freed
|
||||||
DisplayId displayId{DisplayId::Null}; //!< The ID of this display
|
|
||||||
LayerStatus layerStatus{LayerStatus::Uninitialized}; //!< The status of the single layer the display has
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The transactions supported by android.gui.IGraphicBufferProducer
|
* @brief The transactions supported by android.gui.IGraphicBufferProducer
|
||||||
@ -178,18 +158,5 @@ namespace skyline::service::hosbinder {
|
|||||||
* @url https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/IGraphicBufferProducer.cpp;l=277-426
|
* @url https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/IGraphicBufferProducer.cpp;l=277-426
|
||||||
*/
|
*/
|
||||||
void OnTransact(TransactionCode code, Parcel &in, Parcel &out);
|
void OnTransact(TransactionCode code, Parcel &in, Parcel &out);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Sets displayId to a specific display type
|
|
||||||
* @note displayId has to be DisplayId::Null or this will throw an exception
|
|
||||||
*/
|
|
||||||
void SetDisplay(const std::string &name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Closes the display by setting displayId to DisplayId::Null
|
|
||||||
*/
|
|
||||||
void CloseDisplay();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::weak_ptr<GraphicBufferProducer> producer; //!< A globally shared instance of the GraphicsBufferProducer
|
|
||||||
}
|
}
|
||||||
|
@ -7,43 +7,166 @@
|
|||||||
#include "GraphicBufferProducer.h"
|
#include "GraphicBufferProducer.h"
|
||||||
|
|
||||||
namespace skyline::service::hosbinder {
|
namespace skyline::service::hosbinder {
|
||||||
IHOSBinderDriver::IHOSBinderDriver(const DeviceState &state, ServiceManager &manager) : producer(hosbinder::producer.expired() ? std::make_shared<GraphicBufferProducer>(state) : hosbinder::producer.lock()), BaseService(state, manager) {
|
IHOSBinderDriver::IHOSBinderDriver(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {}
|
||||||
if (hosbinder::producer.expired())
|
|
||||||
hosbinder::producer = producer;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result IHOSBinderDriver::TransactParcel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IHOSBinderDriver::TransactParcel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
auto layerId{request.Pop<u32>()};
|
// We opted for just supporting a single layer and display as it's what basically all games use and wasting cycles on it is pointless
|
||||||
|
// If this was not done then we would need to maintain an array of GraphicBufferProducer objects for each layer and send the request for it specifically
|
||||||
|
// There would also need to be an external compositor which composites all the graphics buffers submitted to every GraphicBufferProducer
|
||||||
|
|
||||||
|
auto binderHandle{request.Pop<u32>()};
|
||||||
|
if (binderHandle != DefaultBinderLayerHandle)
|
||||||
|
throw exception("Transaction on unknown binder object: #{}", binderHandle);
|
||||||
|
|
||||||
auto code{request.Pop<GraphicBufferProducer::TransactionCode>()};
|
auto code{request.Pop<GraphicBufferProducer::TransactionCode>()};
|
||||||
|
|
||||||
Parcel in(request.inputBuf.at(0), state, true);
|
Parcel in(request.inputBuf.at(0), state, true);
|
||||||
Parcel out(state);
|
Parcel out(state);
|
||||||
|
|
||||||
// We opted for just supporting a single layer and display as it's what basically all games use and wasting cycles on it is pointless
|
if (!layer)
|
||||||
// If this was not done then we would need to maintain an array of GraphicBufferProducer objects for each layer and send the request for it specifically
|
throw exception("Transacting parcel with non-existant layer");
|
||||||
// There would also need to be an external compositor which composites all the graphics buffers submitted to every GraphicBufferProducer
|
layer->OnTransact(code, in, out);
|
||||||
|
|
||||||
state.logger->Debug("Layer ID: {}, Code: {}", layerId, code);
|
|
||||||
producer->OnTransact(code, in, out);
|
|
||||||
|
|
||||||
out.WriteParcel(request.outputBuf.at(0));
|
out.WriteParcel(request.outputBuf.at(0));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IHOSBinderDriver::AdjustRefcount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IHOSBinderDriver::AdjustRefcount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
request.Skip<u32>();
|
auto binderHandle{request.Pop<u32>()};
|
||||||
auto addVal{request.Pop<i32>()};
|
if (binderHandle != DefaultBinderLayerHandle)
|
||||||
auto type{request.Pop<i32>()};
|
throw exception("Adjusting Binder object reference count for unknown object: #{}", binderHandle);
|
||||||
state.logger->Debug("Reference Change: {} {} reference", addVal, type ? "strong" : "weak");
|
|
||||||
|
auto value{request.Pop<i32>()};
|
||||||
|
bool isStrong{static_cast<bool>(request.Pop<u32>())};
|
||||||
|
if (isStrong) {
|
||||||
|
if (layerStrongReferenceCount != InitialStrongReferenceCount)
|
||||||
|
layerStrongReferenceCount += value;
|
||||||
|
else
|
||||||
|
layerStrongReferenceCount = value;
|
||||||
|
|
||||||
|
if (layerStrongReferenceCount < 0) {
|
||||||
|
state.logger->Warn("Strong reference count is lower than 0: {} + {} = {}", (layerStrongReferenceCount - value), value, layerStrongReferenceCount);
|
||||||
|
layerStrongReferenceCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layerStrongReferenceCount == 0)
|
||||||
|
layer.reset();
|
||||||
|
} else {
|
||||||
|
layerWeakReferenceCount += value;
|
||||||
|
|
||||||
|
if (layerWeakReferenceCount < 0) {
|
||||||
|
state.logger->Warn("Weak reference count is lower than 0: {} + {} = {}", (layerWeakReferenceCount - value), value, layerWeakReferenceCount);
|
||||||
|
layerWeakReferenceCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layerWeakReferenceCount == 0 && layerStrongReferenceCount < 1)
|
||||||
|
layer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
state.logger->Debug("Reference Change: {} {} reference (S{} W{})", value, isStrong ? "strong" : "weak", layerStrongReferenceCount, layerWeakReferenceCount);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IHOSBinderDriver::GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IHOSBinderDriver::GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
KHandle handle{state.process->InsertItem(producer->bufferEvent)};
|
auto binderHandle{request.Pop<u32>()};
|
||||||
|
if (binderHandle != DefaultBinderLayerHandle)
|
||||||
|
throw exception("Getting handle from unknown binder object: #{}", binderHandle);
|
||||||
|
|
||||||
|
constexpr u32 BufferEventHandleId{0xF}; //!< The ID of the buffer event handle in the layer object
|
||||||
|
auto handleId{request.Pop<u32>()};
|
||||||
|
if (handleId != BufferEventHandleId)
|
||||||
|
throw exception("Getting unknown handle from binder object: 0x{:X}", handleId);
|
||||||
|
|
||||||
|
KHandle handle{state.process->InsertItem(layer->bufferEvent)};
|
||||||
state.logger->Debug("Display Buffer Event Handle: 0x{:X}", handle);
|
state.logger->Debug("Display Buffer Event Handle: 0x{:X}", handle);
|
||||||
response.copyHandles.push_back(handle);
|
response.copyHandles.push_back(handle);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DisplayId IHOSBinderDriver::OpenDisplay(std::string_view name) {
|
||||||
|
if (name.length() > sizeof(u64))
|
||||||
|
throw exception("Opening display with name larger than sizeof(u64): '{}' ({})", name, name.length());
|
||||||
|
|
||||||
|
auto newDisplayId{[&]() -> DisplayId {
|
||||||
|
#define DISPLAY_CASE(id) case util::MakeMagic<u64>(#id): { return DisplayId::id; }
|
||||||
|
switch (util::MakeMagic<u64>(name)) {
|
||||||
|
DISPLAY_CASE(Default)
|
||||||
|
DISPLAY_CASE(External)
|
||||||
|
DISPLAY_CASE(Edid)
|
||||||
|
DISPLAY_CASE(Internal)
|
||||||
|
DISPLAY_CASE(Null)
|
||||||
|
default:
|
||||||
|
throw exception("Opening non-existent display: '{}'", name);
|
||||||
|
}
|
||||||
|
#undef DISPLAY_CASE
|
||||||
|
}()};
|
||||||
|
if (displayId != DisplayId::Null && displayId != newDisplayId)
|
||||||
|
throw exception("Opening a new display ({}) prior to closing opened display ({})", name, ToString(displayId));
|
||||||
|
|
||||||
|
return displayId = newDisplayId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHOSBinderDriver::CloseDisplay(DisplayId id) {
|
||||||
|
if (displayId != id)
|
||||||
|
throw exception("Closing an unopened display: {} (Currently open display: {})", ToString(id), ToString(displayId));
|
||||||
|
displayId = DisplayId::Null;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 IHOSBinderDriver::CreateLayer(DisplayId pDisplayId) {
|
||||||
|
if (pDisplayId != displayId)
|
||||||
|
throw exception("Creating layer on unopened display: '{}'", ToString(pDisplayId));
|
||||||
|
else if (layer)
|
||||||
|
throw exception("Creation of multiple layers is not supported");
|
||||||
|
|
||||||
|
layerStrongReferenceCount = InitialStrongReferenceCount;
|
||||||
|
layerWeakReferenceCount = 0;
|
||||||
|
layer.emplace(state);
|
||||||
|
|
||||||
|
return DefaultLayerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parcel IHOSBinderDriver::OpenLayer(DisplayId pDisplayId, u64 layerId) {
|
||||||
|
if (pDisplayId != displayId)
|
||||||
|
throw exception("Opening layer #{} with unopened display: '{}'", layerId, ToString(pDisplayId));
|
||||||
|
else if (layerId != DefaultLayerId)
|
||||||
|
throw exception("Attempting to open unrecognized layer #{}", layerId);
|
||||||
|
else if (!layer)
|
||||||
|
throw exception("Opening layer #{} prior to creation or after destruction", layerId);
|
||||||
|
|
||||||
|
Parcel parcel(state);
|
||||||
|
// Flat Binder with the layer's IGraphicBufferProducer
|
||||||
|
// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:bionic/libc/kernel/uapi/linux/binder.h;l=47-57
|
||||||
|
parcel.Push<u32>(0x2); // Type of the IBinder
|
||||||
|
parcel.Push<u32>(0); // Flags
|
||||||
|
parcel.Push<u64>(DefaultBinderLayerHandle); // Handle
|
||||||
|
parcel.Push<u64>(0); // Cookie
|
||||||
|
// Unknown HOS-specific layer properties
|
||||||
|
parcel.Push(util::MakeMagic<u64>("dispdrv\0"));
|
||||||
|
parcel.Push<u64>({}); // Unknown
|
||||||
|
|
||||||
|
parcel.PushObject(0); // Offset of flattened IBinder relative to Parcel data
|
||||||
|
|
||||||
|
layerWeakReferenceCount++; // IBinder represents a weak reference to the layer
|
||||||
|
|
||||||
|
return parcel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHOSBinderDriver::CloseLayer(u64 layerId) {
|
||||||
|
if (layerId != DefaultLayerId)
|
||||||
|
throw exception("Closing non-existent layer #{}", layerId);
|
||||||
|
else if (layerWeakReferenceCount == 0)
|
||||||
|
throw exception("Closing layer #{} which has no weak references to it", layerId);
|
||||||
|
|
||||||
|
if (--layerWeakReferenceCount == 0 && layerStrongReferenceCount < 1)
|
||||||
|
layer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHOSBinderDriver::DestroyLayer(u64 layerId) {
|
||||||
|
if (layerId != DefaultLayerId)
|
||||||
|
throw exception("Destroying non-existent layer #{}", layerId);
|
||||||
|
else if (layer)
|
||||||
|
throw exception("Destroying layer #{} which hasn't been closed: Weak References: {}, Strong References: {}", layerWeakReferenceCount, layerStrongReferenceCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,46 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <services/serviceman.h>
|
#include <services/base_service.h>
|
||||||
|
#include "GraphicBufferProducer.h"
|
||||||
|
|
||||||
namespace skyline::service::hosbinder {
|
namespace skyline::service::hosbinder {
|
||||||
class GraphicBufferProducer;
|
/**
|
||||||
|
* @brief A display identifier specific to HOS, translated to a corresponding Android display internally
|
||||||
|
* @url https://switchbrew.org/wiki/Display_services#DisplayName
|
||||||
|
*/
|
||||||
|
enum class DisplayId : u64 {
|
||||||
|
Default, //!< Automatically determines the default display
|
||||||
|
External, //!< Refers to an external display, if any
|
||||||
|
Edid, //!< Refers to an external display with EDID capabilities
|
||||||
|
Internal, //!< Refers to the internal display on the Switch
|
||||||
|
Null, //!< A placeholder display which doesn't refer to any display
|
||||||
|
};
|
||||||
|
|
||||||
|
ENUM_STRING(DisplayId, {
|
||||||
|
ENUM_CASE(Default);
|
||||||
|
ENUM_CASE(External);
|
||||||
|
ENUM_CASE(Edid);
|
||||||
|
ENUM_CASE(Internal);
|
||||||
|
ENUM_CASE(Null);
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief nvnflinger:dispdrv or nns::hosbinder::IHOSBinderDriver is a translation layer between Android Binder IPC and HOS IPC to communicate with the Android display stack
|
* @brief nvnflinger:dispdrv or nns::hosbinder::IHOSBinderDriver is a translation layer between Android Binder IPC and HOS IPC to communicate with the Android display stack
|
||||||
*/
|
*/
|
||||||
class IHOSBinderDriver : public BaseService {
|
class IHOSBinderDriver : public BaseService {
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<GraphicBufferProducer> producer;
|
DisplayId displayId{DisplayId::Null}; //!< The ID of the display that the layer is connected to
|
||||||
|
constexpr static u64 DefaultLayerId{1}; //!< The VI ID of the default (and only) layer in our surface stack
|
||||||
|
constexpr static u32 DefaultBinderLayerHandle{1}; //!< The handle as assigned by SurfaceFlinger of the default layer
|
||||||
|
constexpr static i32 InitialStrongReferenceCount{std::numeric_limits<i32>::min()}; //!< Initial value for the strong reference count, weak references will keep the object alive till the strong reference count is first mutated
|
||||||
|
i32 layerStrongReferenceCount; //!< The amount of strong references to the layer object
|
||||||
|
i32 layerWeakReferenceCount; //!< The amount of weak references to the layer object
|
||||||
|
std::optional<GraphicBufferProducer> layer; //!< The IGraphicBufferProducer backing the layer (NativeWindow)
|
||||||
|
|
||||||
|
void AddWeakLayerReference(u32 count = 1) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IHOSBinderDriver(const DeviceState &state, ServiceManager &manager);
|
IHOSBinderDriver(const DeviceState &state, ServiceManager &manager);
|
||||||
@ -25,7 +54,7 @@ namespace skyline::service::hosbinder {
|
|||||||
Result TransactParcel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
Result TransactParcel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adjusts the reference counts to the underlying binder, it's stubbed as we aren't using the real symbols
|
* @brief Adjusts the reference counts to the underlying Android reference counted object
|
||||||
* @url https://switchbrew.org/wiki/Nvnflinger_services#AdjustRefcount
|
* @url https://switchbrew.org/wiki/Nvnflinger_services#AdjustRefcount
|
||||||
*/
|
*/
|
||||||
Result AdjustRefcount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
Result AdjustRefcount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
@ -36,6 +65,38 @@ namespace skyline::service::hosbinder {
|
|||||||
*/
|
*/
|
||||||
Result GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
Result GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @note This will throw an exception if another display was opened and not closed
|
||||||
|
*/
|
||||||
|
DisplayId OpenDisplay(std::string_view name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @note This **must** be called prior to opening a different Display
|
||||||
|
*/
|
||||||
|
void CloseDisplay(DisplayId id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return An ID that can be utilized to refer to the layer
|
||||||
|
* @note This will throw an exception if the specified display has not been opened
|
||||||
|
*/
|
||||||
|
u64 CreateLayer(DisplayId displayId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A parcel with a flattened IBinder to the IGraphicBufferProducer of the layer
|
||||||
|
* @note This will throw an exception if the specified display has not been opened
|
||||||
|
*/
|
||||||
|
Parcel OpenLayer(DisplayId displayId, u64 layerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @note This **must** be called prior to destroying the layer
|
||||||
|
*/
|
||||||
|
void CloseLayer(u64 layerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @note This **must** be called prior to opening a different Display
|
||||||
|
*/
|
||||||
|
void DestroyLayer(u64 layerId);
|
||||||
|
|
||||||
SERVICE_DECL(
|
SERVICE_DECL(
|
||||||
SFUNC(0x0, IHOSBinderDriver, TransactParcel),
|
SFUNC(0x0, IHOSBinderDriver, TransactParcel),
|
||||||
SFUNC(0x1, IHOSBinderDriver, AdjustRefcount),
|
SFUNC(0x1, IHOSBinderDriver, AdjustRefcount),
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "parcel.h"
|
#include "parcel.h"
|
||||||
|
|
||||||
namespace skyline::service {
|
namespace skyline::service::hosbinder {
|
||||||
Parcel::Parcel(span<u8> buffer, const DeviceState &state, bool hasToken) : state(state) {
|
Parcel::Parcel(span<u8> buffer, const DeviceState &state, bool hasToken) : state(state) {
|
||||||
header = buffer.as<ParcelHeader>();
|
header = buffer.as<ParcelHeader>();
|
||||||
|
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include <kernel/ipc.h>
|
#include <kernel/ipc.h>
|
||||||
|
|
||||||
namespace skyline::service {
|
namespace skyline::service::hosbinder {
|
||||||
/**
|
/**
|
||||||
* @brief This allows easy access and efficient serialization of an Android Parcel object
|
* @brief This allows easy access and efficient serialization of an Android Parcel object
|
||||||
* @url https://switchbrew.org/wiki/Display_services#Parcel
|
* @url https://switchbrew.org/wiki/Display_services#Parcel
|
@ -18,6 +18,9 @@
|
|||||||
#include "services/timesrv/core.h"
|
#include "services/timesrv/core.h"
|
||||||
#include "fssrv/IFileSystemProxy.h"
|
#include "fssrv/IFileSystemProxy.h"
|
||||||
#include "services/nvdrv/INvDrvServices.h"
|
#include "services/nvdrv/INvDrvServices.h"
|
||||||
|
#include "hosbinder/IHOSBinderDriver.h"
|
||||||
|
#include "visrv/IApplicationRootService.h"
|
||||||
|
#include "visrv/ISystemRootService.h"
|
||||||
#include "visrv/IManagerRootService.h"
|
#include "visrv/IManagerRootService.h"
|
||||||
#include "pl/IPlatformServiceManager.h"
|
#include "pl/IPlatformServiceManager.h"
|
||||||
#include "aocsrv/IAddOnContentManager.h"
|
#include "aocsrv/IAddOnContentManager.h"
|
||||||
@ -35,7 +38,7 @@
|
|||||||
|
|
||||||
#define SERVICE_CASE(class, name, ...) \
|
#define SERVICE_CASE(class, name, ...) \
|
||||||
case util::MakeMagic<ServiceName>(name): { \
|
case util::MakeMagic<ServiceName>(name): { \
|
||||||
std::shared_ptr<BaseService> serviceObject = std::make_shared<class>(state, *this __VA_OPT__(,) __VA_ARGS__); \
|
std::shared_ptr<BaseService> serviceObject{std::make_shared<class>(state, *this, ##__VA_ARGS__)}; \
|
||||||
serviceMap[util::MakeMagic<ServiceName>(name)] = serviceObject; \
|
serviceMap[util::MakeMagic<ServiceName>(name)] = serviceObject; \
|
||||||
return serviceObject; \
|
return serviceObject; \
|
||||||
}
|
}
|
||||||
@ -49,7 +52,7 @@ namespace skyline::service {
|
|||||||
|
|
||||||
ServiceManager::ServiceManager(const DeviceState &state) : state(state), smUserInterface(std::make_shared<sm::IUserInterface>(state, *this)), globalServiceState(std::make_shared<GlobalServiceState>(state)) {}
|
ServiceManager::ServiceManager(const DeviceState &state) : state(state), smUserInterface(std::make_shared<sm::IUserInterface>(state, *this)), globalServiceState(std::make_shared<GlobalServiceState>(state)) {}
|
||||||
|
|
||||||
std::shared_ptr<BaseService> ServiceManager::CreateService(ServiceName name) {
|
std::shared_ptr<BaseService> ServiceManager::CreateOrGetService(ServiceName name) {
|
||||||
auto serviceIter{serviceMap.find(name)};
|
auto serviceIter{serviceMap.find(name)};
|
||||||
if (serviceIter != serviceMap.end())
|
if (serviceIter != serviceMap.end())
|
||||||
return (*serviceIter).second;
|
return (*serviceIter).second;
|
||||||
@ -74,9 +77,10 @@ namespace skyline::service {
|
|||||||
SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:a")
|
SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:a")
|
||||||
SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:s")
|
SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:s")
|
||||||
SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:t")
|
SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:t")
|
||||||
|
SERVICE_CASE(hosbinder::IHOSBinderDriver, "dispdrv")
|
||||||
|
SERVICE_CASE(visrv::IApplicationRootService, "vi:u")
|
||||||
|
SERVICE_CASE(visrv::ISystemRootService, "vi:s")
|
||||||
SERVICE_CASE(visrv::IManagerRootService, "vi:m")
|
SERVICE_CASE(visrv::IManagerRootService, "vi:m")
|
||||||
SERVICE_CASE(visrv::IManagerRootService, "vi:u")
|
|
||||||
SERVICE_CASE(visrv::IManagerRootService, "vi:s")
|
|
||||||
SERVICE_CASE(pl::IPlatformServiceManager, "pl:u")
|
SERVICE_CASE(pl::IPlatformServiceManager, "pl:u")
|
||||||
SERVICE_CASE(aocsrv::IAddOnContentManager, "aoc:u")
|
SERVICE_CASE(aocsrv::IAddOnContentManager, "aoc:u")
|
||||||
SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl")
|
SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl")
|
||||||
@ -100,7 +104,7 @@ namespace skyline::service {
|
|||||||
|
|
||||||
std::shared_ptr<BaseService> ServiceManager::NewService(ServiceName name, type::KSession &session, ipc::IpcResponse &response) {
|
std::shared_ptr<BaseService> ServiceManager::NewService(ServiceName name, type::KSession &session, ipc::IpcResponse &response) {
|
||||||
std::lock_guard serviceGuard(mutex);
|
std::lock_guard serviceGuard(mutex);
|
||||||
auto serviceObject{CreateService(name)};
|
auto serviceObject{CreateOrGetService(name)};
|
||||||
KHandle handle{};
|
KHandle handle{};
|
||||||
if (session.isDomain) {
|
if (session.isDomain) {
|
||||||
session.domains.push_back(serviceObject);
|
session.domains.push_back(serviceObject);
|
||||||
|
@ -21,13 +21,6 @@ namespace skyline::service {
|
|||||||
std::unordered_map<ServiceName, std::shared_ptr<BaseService>> serviceMap; //!< A mapping from a Service to the underlying object
|
std::unordered_map<ServiceName, std::shared_ptr<BaseService>> serviceMap; //!< A mapping from a Service to the underlying object
|
||||||
std::mutex mutex; //!< Synchronizes concurrent access to services to prevent crashes
|
std::mutex mutex; //!< Synchronizes concurrent access to services to prevent crashes
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Creates an instance of the service if it doesn't already exist, otherwise returns an existing instance
|
|
||||||
* @param name The name of the service to create
|
|
||||||
* @return A shared pointer to an instance of the service
|
|
||||||
*/
|
|
||||||
std::shared_ptr<BaseService> CreateService(ServiceName name);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<BaseService> smUserInterface; //!< Used by applications to open connections to services
|
std::shared_ptr<BaseService> smUserInterface; //!< Used by applications to open connections to services
|
||||||
std::shared_ptr<GlobalServiceState> globalServiceState;
|
std::shared_ptr<GlobalServiceState> globalServiceState;
|
||||||
@ -58,19 +51,13 @@ namespace skyline::service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param serviceType The type of the service
|
* @brief Creates an instance of the service if it doesn't already exist, otherwise returns an existing instance
|
||||||
* @tparam The class of the service
|
|
||||||
* @return A shared pointer to an instance of the service
|
|
||||||
* @note This only works for services created with `NewService` as sub-interfaces used with `RegisterService` can have multiple instances
|
|
||||||
*/
|
*/
|
||||||
template<typename Type>
|
std::shared_ptr<BaseService> CreateOrGetService(ServiceName name);
|
||||||
std::shared_ptr<Type> GetService(ServiceName name) {
|
|
||||||
return std::static_pointer_cast<Type>(serviceMap.at(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
constexpr std::shared_ptr<Type> GetService(std::string_view name) {
|
constexpr std::shared_ptr<Type> CreateOrGetService(std::string_view name) {
|
||||||
return GetService<Type>(util::MakeMagic<ServiceName>(name));
|
return std::static_pointer_cast<Type>(CreateOrGetService(util::MakeMagic<ServiceName>(name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,101 +3,85 @@
|
|||||||
|
|
||||||
#include <gpu.h>
|
#include <gpu.h>
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
|
#include <services/serviceman.h>
|
||||||
#include <services/hosbinder/IHOSBinderDriver.h>
|
#include <services/hosbinder/IHOSBinderDriver.h>
|
||||||
#include <services/hosbinder/GraphicBufferProducer.h>
|
|
||||||
#include "IApplicationDisplayService.h"
|
#include "IApplicationDisplayService.h"
|
||||||
#include "ISystemDisplayService.h"
|
#include "ISystemDisplayService.h"
|
||||||
#include "IManagerDisplayService.h"
|
#include "IManagerDisplayService.h"
|
||||||
|
#include "results.h"
|
||||||
|
|
||||||
namespace skyline::service::visrv {
|
namespace skyline::service::visrv {
|
||||||
IApplicationDisplayService::IApplicationDisplayService(const DeviceState &state, ServiceManager &manager) : IDisplayService(state, manager) {}
|
IApplicationDisplayService::IApplicationDisplayService(const DeviceState &state, ServiceManager &manager, PrivilegeLevel level) : level(level), IDisplayService(state, manager) {}
|
||||||
|
|
||||||
Result IApplicationDisplayService::GetRelayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IApplicationDisplayService::GetRelayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
manager.RegisterService(SRVREG(hosbinder::IHOSBinderDriver), session, response);
|
manager.RegisterService(hosbinder, session, response);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IApplicationDisplayService::GetIndirectDisplayTransactionService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IApplicationDisplayService::GetIndirectDisplayTransactionService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
manager.RegisterService(SRVREG(hosbinder::IHOSBinderDriver), session, response);
|
if (level < PrivilegeLevel::System)
|
||||||
|
return result::IllegalOperation;
|
||||||
|
manager.RegisterService(hosbinder, session, response);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IApplicationDisplayService::GetSystemDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IApplicationDisplayService::GetSystemDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
|
if (level < PrivilegeLevel::System)
|
||||||
|
return result::IllegalOperation;
|
||||||
manager.RegisterService(SRVREG(ISystemDisplayService), session, response);
|
manager.RegisterService(SRVREG(ISystemDisplayService), session, response);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IApplicationDisplayService::GetManagerDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IApplicationDisplayService::GetManagerDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
|
if (level < PrivilegeLevel::Manager)
|
||||||
|
return result::IllegalOperation;
|
||||||
manager.RegisterService(SRVREG(IManagerDisplayService), session, response);
|
manager.RegisterService(SRVREG(IManagerDisplayService), session, response);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IApplicationDisplayService::OpenDisplay(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IApplicationDisplayService::OpenDisplay(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
std::string displayName(request.PopString());
|
auto displayName(request.PopString());
|
||||||
state.logger->Debug("Setting display as: {}", displayName);
|
state.logger->Debug("Opening display: {}", displayName);
|
||||||
|
response.Push(hosbinder->OpenDisplay(displayName));
|
||||||
auto producer{hosbinder::producer.lock()};
|
|
||||||
producer->SetDisplay(displayName);
|
|
||||||
|
|
||||||
response.Push<u64>(0); // There's only one display
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IApplicationDisplayService::CloseDisplay(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IApplicationDisplayService::CloseDisplay(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
state.logger->Debug("Closing the display");
|
auto displayId{request.Pop<hosbinder::DisplayId>()};
|
||||||
auto producer{hosbinder::producer.lock()};
|
state.logger->Debug("Closing display: {}", hosbinder::ToString(displayId));
|
||||||
producer->CloseDisplay();
|
hosbinder->CloseDisplay(displayId);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IApplicationDisplayService::OpenLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IApplicationDisplayService::OpenLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
struct InputStruct {
|
auto displayName{request.PopString(0x40)};
|
||||||
char displayName[0x40];
|
auto layerId{request.Pop<u64>()};
|
||||||
u64 layerId;
|
state.logger->Debug("Opening layer #{} on display: {}", layerId, displayName);
|
||||||
u64 userId;
|
|
||||||
} input = request.Pop<InputStruct>();
|
|
||||||
state.logger->Debug("Opening Layer: Display Name: {}, Layer ID: {}, User ID: {}", input.displayName, input.layerId, input.userId);
|
|
||||||
|
|
||||||
std::string name(input.displayName);
|
|
||||||
|
|
||||||
Parcel parcel(state);
|
|
||||||
LayerParcel data{
|
|
||||||
.type = 0x2,
|
|
||||||
.pid = 0,
|
|
||||||
.bufferId = 0, // As we only have one layer and buffer
|
|
||||||
.string = "dispdrv"
|
|
||||||
};
|
|
||||||
parcel.Push(data);
|
|
||||||
parcel.objects.resize(4);
|
|
||||||
|
|
||||||
|
auto displayId{hosbinder->OpenDisplay(displayName)};
|
||||||
|
auto parcel{hosbinder->OpenLayer(displayId, layerId)};
|
||||||
response.Push<u64>(parcel.WriteParcel(request.outputBuf.at(0)));
|
response.Push<u64>(parcel.WriteParcel(request.outputBuf.at(0)));
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IApplicationDisplayService::CloseLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IApplicationDisplayService::CloseLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
u64 layerId{request.Pop<u64>()};
|
u64 layerId{request.Pop<u64>()};
|
||||||
state.logger->Debug("Closing Layer: {}", layerId);
|
state.logger->Debug("Closing layer #{}", layerId);
|
||||||
|
hosbinder->CloseLayer(layerId);
|
||||||
auto producer{hosbinder::producer.lock()};
|
|
||||||
if (producer->layerStatus == hosbinder::LayerStatus::Uninitialized)
|
|
||||||
state.logger->Warn("The application is destroying an uninitialized layer");
|
|
||||||
producer->layerStatus = hosbinder::LayerStatus::Uninitialized;
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IApplicationDisplayService::SetLayerScalingMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IApplicationDisplayService::SetLayerScalingMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
auto scalingMode{request.Pop<u64>()};
|
auto scalingMode{request.Pop<u64>()};
|
||||||
auto layerId{request.Pop<u64>()};
|
auto layerId{request.Pop<u64>()};
|
||||||
|
|
||||||
state.logger->Debug("Setting Layer Scaling mode to '{}' for layer {}", scalingMode, layerId);
|
state.logger->Debug("Setting Layer Scaling mode to '{}' for layer {}", scalingMode, layerId);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IApplicationDisplayService::GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IApplicationDisplayService::GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
KHandle handle{state.process->InsertItem(state.gpu->presentation.vsyncEvent)};
|
KHandle handle{state.process->InsertItem(state.gpu->presentation.vsyncEvent)};
|
||||||
state.logger->Debug("VSync Event Handle: 0x{:X}", handle);
|
state.logger->Debug("V-Sync Event Handle: 0x{:X}", handle);
|
||||||
|
|
||||||
response.copyHandles.push_back(handle);
|
response.copyHandles.push_back(handle);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "IDisplayService.h"
|
#include "IDisplayService.h"
|
||||||
|
#include "IRootService.h"
|
||||||
|
|
||||||
namespace skyline::service::visrv {
|
namespace skyline::service::visrv {
|
||||||
/**
|
/**
|
||||||
@ -11,8 +12,11 @@ namespace skyline::service::visrv {
|
|||||||
* @url https://switchbrew.org/wiki/Display_services#IApplicationDisplayService
|
* @url https://switchbrew.org/wiki/Display_services#IApplicationDisplayService
|
||||||
*/
|
*/
|
||||||
class IApplicationDisplayService : public IDisplayService {
|
class IApplicationDisplayService : public IDisplayService {
|
||||||
|
private:
|
||||||
|
PrivilegeLevel level;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IApplicationDisplayService(const DeviceState &state, ServiceManager &manager);
|
IApplicationDisplayService(const DeviceState &state, ServiceManager &manager, PrivilegeLevel level);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns an handle to the 'nvnflinger' service
|
* @brief Returns an handle to the 'nvnflinger' service
|
||||||
@ -74,19 +78,19 @@ namespace skyline::service::visrv {
|
|||||||
*/
|
*/
|
||||||
Result GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
Result GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
|
|
||||||
SERVICE_DECL(
|
SERVICE_DECL(
|
||||||
SFUNC(0x64, IApplicationDisplayService, GetRelayService),
|
SFUNC(0x64, IApplicationDisplayService, GetRelayService),
|
||||||
SFUNC(0x65, IApplicationDisplayService, GetSystemDisplayService),
|
SFUNC(0x65, IApplicationDisplayService, GetSystemDisplayService),
|
||||||
SFUNC(0x66, IApplicationDisplayService, GetManagerDisplayService),
|
SFUNC(0x66, IApplicationDisplayService, GetManagerDisplayService),
|
||||||
SFUNC(0x67, IApplicationDisplayService, GetIndirectDisplayTransactionService),
|
SFUNC(0x67, IApplicationDisplayService, GetIndirectDisplayTransactionService),
|
||||||
SFUNC(0x3F2, IApplicationDisplayService, OpenDisplay),
|
SFUNC(0x3F2, IApplicationDisplayService, OpenDisplay),
|
||||||
SFUNC(0x3FC, IApplicationDisplayService, CloseDisplay),
|
SFUNC(0x3FC, IApplicationDisplayService, CloseDisplay),
|
||||||
SFUNC(0x7E4, IApplicationDisplayService, OpenLayer),
|
SFUNC(0x7E4, IApplicationDisplayService, OpenLayer),
|
||||||
SFUNC(0x7E5, IApplicationDisplayService, CloseLayer),
|
SFUNC(0x7E5, IApplicationDisplayService, CloseLayer),
|
||||||
SFUNC_BASE(0x7EE, IApplicationDisplayService, IDisplayService, CreateStrayLayer),
|
SFUNC_BASE(0x7EE, IApplicationDisplayService, IDisplayService, CreateStrayLayer),
|
||||||
SFUNC_BASE(0x7EF, IApplicationDisplayService, IDisplayService, DestroyStrayLayer),
|
SFUNC_BASE(0x7EF, IApplicationDisplayService, IDisplayService, DestroyStrayLayer),
|
||||||
SFUNC(0x835, IApplicationDisplayService, SetLayerScalingMode),
|
SFUNC(0x835, IApplicationDisplayService, SetLayerScalingMode),
|
||||||
SFUNC(0x1452, IApplicationDisplayService, GetDisplayVsyncEvent)
|
SFUNC(0x1452, IApplicationDisplayService, GetDisplayVsyncEvent)
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IRootService.h"
|
||||||
|
|
||||||
|
namespace skyline::service::visrv {
|
||||||
|
/**
|
||||||
|
* @url https://switchbrew.org/wiki/Display_services#vi:u
|
||||||
|
*/
|
||||||
|
class IApplicationRootService : public IRootService {
|
||||||
|
public:
|
||||||
|
IApplicationRootService(const DeviceState &state, ServiceManager &manager) : IRootService(state, manager, PrivilegeLevel::Application) {}
|
||||||
|
|
||||||
|
SERVICE_DECL(
|
||||||
|
SFUNC_BASE(0x0, IApplicationRootService, IRootService, GetDisplayService)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
@ -1,46 +1,33 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
#include <services/hosbinder/GraphicBufferProducer.h>
|
#include <services/serviceman.h>
|
||||||
|
#include <services/hosbinder/IHOSBinderDriver.h>
|
||||||
#include "IDisplayService.h"
|
#include "IDisplayService.h"
|
||||||
|
|
||||||
namespace skyline::service::visrv {
|
namespace skyline::service::visrv {
|
||||||
IDisplayService::IDisplayService(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {}
|
IDisplayService::IDisplayService(const DeviceState &state, ServiceManager &manager) : hosbinder(manager.CreateOrGetService<hosbinder::IHOSBinderDriver>("dispdrv")), BaseService(state, manager) {}
|
||||||
|
|
||||||
Result IDisplayService::CreateStrayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IDisplayService::CreateStrayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
request.Skip<u64>();
|
request.Skip<u64>(); // VI Layer flags
|
||||||
auto displayId{request.Pop<u64>()};
|
auto displayId{request.Pop<hosbinder::DisplayId>()};
|
||||||
|
|
||||||
state.logger->Debug("Creating Stray Layer on Display: {}", displayId);
|
auto layerId{hosbinder->CreateLayer(displayId)};
|
||||||
|
response.Push(layerId);
|
||||||
|
|
||||||
auto producer{hosbinder::producer.lock()};
|
state.logger->Debug("Creating Stray Layer #{} on Display: {}", layerId, hosbinder::ToString(displayId));
|
||||||
if (producer->layerStatus == hosbinder::LayerStatus::Stray)
|
|
||||||
throw exception("The application is creating more than one stray layer");
|
|
||||||
producer->layerStatus = hosbinder::LayerStatus::Stray;
|
|
||||||
|
|
||||||
response.Push<u64>(0); // There's only one layer
|
|
||||||
|
|
||||||
Parcel parcel(state);
|
|
||||||
LayerParcel data{
|
|
||||||
.type = 0x2,
|
|
||||||
.pid = 0,
|
|
||||||
.bufferId = 0, // As we only have one layer and buffer
|
|
||||||
.string = "dispdrv"
|
|
||||||
};
|
|
||||||
parcel.Push(data);
|
|
||||||
|
|
||||||
|
auto parcel{hosbinder->OpenLayer(displayId, layerId)};
|
||||||
response.Push<u64>(parcel.WriteParcel(request.outputBuf.at(0)));
|
response.Push<u64>(parcel.WriteParcel(request.outputBuf.at(0)));
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IDisplayService::DestroyStrayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IDisplayService::DestroyStrayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
auto layerId{request.Pop<u64>()};
|
auto layerId{request.Pop<u64>()};
|
||||||
state.logger->Debug("Destroying Stray Layer: {}", layerId);
|
state.logger->Debug("Destroying Stray Layer #{}", layerId);
|
||||||
|
|
||||||
auto producer{hosbinder::producer.lock()};
|
hosbinder->CloseLayer(layerId);
|
||||||
if (producer->layerStatus == hosbinder::LayerStatus::Uninitialized)
|
|
||||||
state.logger->Warn("The application is destroying an uninitialized layer");
|
|
||||||
producer->layerStatus = hosbinder::LayerStatus::Uninitialized;
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <services/serviceman.h>
|
#include <services/base_service.h>
|
||||||
|
|
||||||
|
namespace skyline::service::hosbinder {
|
||||||
|
class IHOSBinderDriver;
|
||||||
|
}
|
||||||
|
|
||||||
namespace skyline::service::visrv {
|
namespace skyline::service::visrv {
|
||||||
/**
|
/**
|
||||||
@ -11,18 +15,7 @@ namespace skyline::service::visrv {
|
|||||||
*/
|
*/
|
||||||
class IDisplayService : public BaseService {
|
class IDisplayService : public BaseService {
|
||||||
protected:
|
protected:
|
||||||
/**
|
std::shared_ptr<hosbinder::IHOSBinderDriver> hosbinder; //!< The IHOSBinder relayed via this display class
|
||||||
* @brief This is the parcel used in OpenLayer/CreateStrayLayer
|
|
||||||
*/
|
|
||||||
struct LayerParcel {
|
|
||||||
u32 type; //!< The type of the layer
|
|
||||||
u32 pid; //!< The PID that the layer belongs to
|
|
||||||
u32 bufferId; //!< The buffer ID of the layer
|
|
||||||
u32 _pad0_[3];
|
|
||||||
u8 string[0x8]; //!< "dispdrv"
|
|
||||||
u64 _pad1_;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(LayerParcel) == 0x28);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IDisplayService(const DeviceState &state, ServiceManager &manager);
|
IDisplayService(const DeviceState &state, ServiceManager &manager);
|
||||||
|
@ -1,35 +1,27 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
#include <services/hosbinder/GraphicBufferProducer.h>
|
#include <services/hosbinder/IHOSBinderDriver.h>
|
||||||
#include "IManagerDisplayService.h"
|
#include "IManagerDisplayService.h"
|
||||||
|
|
||||||
namespace skyline::service::visrv {
|
namespace skyline::service::visrv {
|
||||||
IManagerDisplayService::IManagerDisplayService(const DeviceState &state, ServiceManager &manager) : IDisplayService(state, manager) {}
|
IManagerDisplayService::IManagerDisplayService(const DeviceState &state, ServiceManager &manager) : IDisplayService(state, manager) {}
|
||||||
|
|
||||||
Result IManagerDisplayService::CreateManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IManagerDisplayService::CreateManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
request.Skip<u32>();
|
request.Skip<u64>(); // VI Layer flags
|
||||||
auto displayId{request.Pop<u64>()};
|
auto displayId{request.Pop<hosbinder::DisplayId>()};
|
||||||
state.logger->Debug("Creating Managed Layer on Display: {}", displayId);
|
|
||||||
|
|
||||||
auto producer{hosbinder::producer.lock()};
|
auto layerId{hosbinder->CreateLayer(displayId)};
|
||||||
if (producer->layerStatus != hosbinder::LayerStatus::Uninitialized)
|
state.logger->Debug("Creating Managed Layer #{} on Display: {}", layerId, hosbinder::ToString(displayId));
|
||||||
throw exception("The application is creating more than one layer");
|
response.Push(layerId);
|
||||||
producer->layerStatus = hosbinder::LayerStatus::Managed;
|
|
||||||
|
|
||||||
response.Push<u64>(0); // There's only one layer
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IManagerDisplayService::DestroyManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IManagerDisplayService::DestroyManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
auto layerId{request.Pop<u64>()};
|
auto layerId{request.Pop<u64>()};
|
||||||
state.logger->Debug("Destroying Managed Layer: {}", layerId);
|
state.logger->Debug("Destroying Managed Layer #{}", layerId);
|
||||||
|
hosbinder->DestroyLayer(layerId);
|
||||||
auto producer{hosbinder::producer.lock()};
|
|
||||||
if (producer->layerStatus == hosbinder::LayerStatus::Uninitialized)
|
|
||||||
state.logger->Warn("The application is destroying an uninitialized layer");
|
|
||||||
producer->layerStatus = hosbinder::LayerStatus::Uninitialized;
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
|
||||||
|
|
||||||
#include "IManagerRootService.h"
|
|
||||||
#include "IApplicationDisplayService.h"
|
|
||||||
|
|
||||||
namespace skyline::service::visrv {
|
|
||||||
IManagerRootService::IManagerRootService(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {}
|
|
||||||
|
|
||||||
Result IManagerRootService::GetDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
|
||||||
manager.RegisterService(SRVREG(IApplicationDisplayService), session, response);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,26 +3,18 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <gpu.h>
|
#include "IRootService.h"
|
||||||
#include <services/serviceman.h>
|
|
||||||
|
|
||||||
namespace skyline::service::visrv {
|
namespace skyline::service::visrv {
|
||||||
/**
|
/**
|
||||||
* @brief This service is used to get an handle to #IApplicationDisplayService
|
|
||||||
* @url https://switchbrew.org/wiki/Display_services#vi:m
|
* @url https://switchbrew.org/wiki/Display_services#vi:m
|
||||||
*/
|
*/
|
||||||
class IManagerRootService : public BaseService {
|
class IManagerRootService : public IRootService {
|
||||||
public:
|
public:
|
||||||
IManagerRootService(const DeviceState &state, ServiceManager &manager);
|
IManagerRootService(const DeviceState &state, ServiceManager &manager) : IRootService(state, manager, PrivilegeLevel::Manager) {}
|
||||||
|
|
||||||
/**
|
SERVICE_DECL(
|
||||||
* @brief Returns an handle to #IApplicationDisplayService
|
SFUNC_BASE(0x2, IManagerRootService, IRootService, GetDisplayService)
|
||||||
* @url https://switchbrew.org/wiki/Display_services#GetDisplayService
|
)
|
||||||
*/
|
|
||||||
Result GetDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
|
||||||
|
|
||||||
SERVICE_DECL(
|
|
||||||
SFUNC(0x2, IManagerRootService, GetDisplayService)
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
19
app/src/main/cpp/skyline/services/visrv/IRootService.cpp
Normal file
19
app/src/main/cpp/skyline/services/visrv/IRootService.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#include <services/serviceman.h>
|
||||||
|
#include "IRootService.h"
|
||||||
|
#include "IApplicationDisplayService.h"
|
||||||
|
#include "results.h"
|
||||||
|
|
||||||
|
namespace skyline::service::visrv {
|
||||||
|
IRootService::IRootService(const DeviceState &state, ServiceManager &manager, PrivilegeLevel level) : level(level), BaseService(state, manager) {}
|
||||||
|
|
||||||
|
Result IRootService::GetDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
|
auto requestedPrivileges{request.Pop<u32>()}; //!< A boolean indicating if the returned service should have higher privileges or not
|
||||||
|
if (requestedPrivileges && level < PrivilegeLevel::System)
|
||||||
|
return result::IllegalOperation;
|
||||||
|
manager.RegisterService(SRVREG(IApplicationDisplayService, level), session, response);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
37
app/src/main/cpp/skyline/services/visrv/IRootService.h
Normal file
37
app/src/main/cpp/skyline/services/visrv/IRootService.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <services/base_service.h>
|
||||||
|
|
||||||
|
namespace skyline::service::visrv {
|
||||||
|
/**
|
||||||
|
* @brief All privilege-based variants that a single service can have
|
||||||
|
*/
|
||||||
|
enum class PrivilegeLevel {
|
||||||
|
Application, //!< The service used by user applications (Lowest)
|
||||||
|
System, //!< The service used by system applications (Higher)
|
||||||
|
Manager, //!< The service used by system services internally (Highest)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Manages allocation of VI to display services
|
||||||
|
* @url https://switchbrew.org/wiki/Display_services#vi:u
|
||||||
|
* @url https://switchbrew.org/wiki/Display_services#vi:s
|
||||||
|
* @url https://switchbrew.org/wiki/Display_services#vi:m
|
||||||
|
*/
|
||||||
|
class IRootService : public BaseService {
|
||||||
|
private:
|
||||||
|
PrivilegeLevel level;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IRootService(const DeviceState &state, ServiceManager &manager, PrivilegeLevel level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns an handle to #IApplicationDisplayService
|
||||||
|
* @url https://switchbrew.org/wiki/Display_services#GetDisplayService
|
||||||
|
*/
|
||||||
|
Result GetDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
|
};
|
||||||
|
}
|
20
app/src/main/cpp/skyline/services/visrv/ISystemRootService.h
Normal file
20
app/src/main/cpp/skyline/services/visrv/ISystemRootService.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IRootService.h"
|
||||||
|
|
||||||
|
namespace skyline::service::visrv {
|
||||||
|
/**
|
||||||
|
* @url https://switchbrew.org/wiki/Display_services#vi:s
|
||||||
|
*/
|
||||||
|
class ISystemRootService : public IRootService {
|
||||||
|
public:
|
||||||
|
ISystemRootService(const DeviceState &state, ServiceManager &manager) : IRootService(state, manager, PrivilegeLevel::System) {}
|
||||||
|
|
||||||
|
SERVICE_DECL(
|
||||||
|
SFUNC_BASE(0x3, ISystemRootService, IRootService, GetDisplayService)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
10
app/src/main/cpp/skyline/services/visrv/results.h
Normal file
10
app/src/main/cpp/skyline/services/visrv/results.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
|
||||||
|
namespace skyline::service::visrv::result {
|
||||||
|
constexpr Result IllegalOperation(114, 6);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user