mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-29 16:35:29 +03: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
879d01f78d
commit
a9de99357b
@ -121,7 +121,6 @@ add_library(skyline SHARED
|
||||
${source_DIR}/skyline/vfs/ticket.cpp
|
||||
${source_DIR}/skyline/services/serviceman.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/fatalsrv/IService.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_as_gpu.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/GraphicBufferProducer.cpp
|
||||
${source_DIR}/skyline/services/visrv/IDisplayService.cpp
|
||||
${source_DIR}/skyline/services/visrv/IApplicationDisplayService.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/pl/IPlatformServiceManager.cpp
|
||||
${source_DIR}/skyline/services/aocsrv/IAddOnContentManager.cpp
|
||||
|
@ -218,11 +218,16 @@ namespace skyline {
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
auto view{size ? std::string_view(reinterpret_cast<const char *>(payloadOffset), size) : std::string_view(reinterpret_cast<const char *>(payloadOffset))};
|
||||
payloadOffset += view.length();
|
||||
std::string_view PopString(size_t size = 0, bool nullTerminated = true) {
|
||||
size = size ? size : cmdArgSz - reinterpret_cast<u64>(payloadOffset);
|
||||
auto view{span(payloadOffset, size).as_string(nullTerminated)};
|
||||
if (nullTerminated)
|
||||
payloadOffset += size;
|
||||
else
|
||||
payloadOffset += view.length();
|
||||
return view;
|
||||
}
|
||||
|
||||
|
@ -2,11 +2,11 @@
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <kernel/types/KProcess.h>
|
||||
#include <services/hosbinder/GraphicBufferProducer.h>
|
||||
#include <services/hosbinder/IHOSBinderDriver.h>
|
||||
#include "ISelfController.h"
|
||||
|
||||
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) {
|
||||
return {};
|
||||
@ -47,18 +47,12 @@ namespace skyline::service::am {
|
||||
}
|
||||
|
||||
Result ISelfController::CreateManagedDisplayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
state.logger->Debug("Creating Managed Layer on Default Display");
|
||||
|
||||
auto producer{hosbinder::producer.lock()};
|
||||
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);
|
||||
auto layerId{hosbinder->CreateLayer(hosbinder::DisplayId::Default)};
|
||||
state.logger->Debug("Creating Managed Layer #{} on 'Default' Display", layerId);
|
||||
response.Push(layerId);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
Result ISelfController::GetAccumulatedSuspendedTickValue(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
// TODO: Properly handle this after we implement game suspending
|
||||
response.Push<u64>(0);
|
||||
|
@ -5,6 +5,10 @@
|
||||
|
||||
#include <services/serviceman.h>
|
||||
|
||||
namespace skyline::service::hosbinder {
|
||||
class IHOSBinderDriver;
|
||||
}
|
||||
|
||||
namespace skyline::service::am {
|
||||
/**
|
||||
* @brief This has functions relating to an application's own current status
|
||||
@ -14,6 +18,7 @@ namespace skyline::service::am {
|
||||
private:
|
||||
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<hosbinder::IHOSBinderDriver> hosbinder; //!< IHOSBinder service for managed display layers
|
||||
|
||||
public:
|
||||
ISelfController(const DeviceState &state, ServiceManager &manager);
|
||||
|
@ -70,7 +70,7 @@ namespace skyline::service::hosbinder {
|
||||
} else {
|
||||
size_t index{};
|
||||
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);
|
||||
state.logger->Warn("Cannot find any free buffers to dequeue:{}", bufferString);
|
||||
return AndroidStatus::InvalidOperation;
|
||||
@ -489,31 +489,4 @@ namespace skyline::service::hosbinder {
|
||||
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
|
||||
|
||||
#include <kernel/types/KEvent.h>
|
||||
#include <services/common/parcel.h>
|
||||
#include "parcel.h"
|
||||
#include "android_types.h"
|
||||
#include "native_window.h"
|
||||
|
||||
@ -43,24 +43,6 @@ namespace skyline::service::hosbinder {
|
||||
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
|
||||
* @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:
|
||||
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
|
||||
@ -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
|
||||
*/
|
||||
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"
|
||||
|
||||
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) {
|
||||
if (hosbinder::producer.expired())
|
||||
hosbinder::producer = producer;
|
||||
}
|
||||
IHOSBinderDriver::IHOSBinderDriver(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {}
|
||||
|
||||
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>()};
|
||||
|
||||
Parcel in(request.inputBuf.at(0), state, true);
|
||||
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 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
|
||||
|
||||
state.logger->Debug("Layer ID: {}, Code: {}", layerId, code);
|
||||
producer->OnTransact(code, in, out);
|
||||
if (!layer)
|
||||
throw exception("Transacting parcel with non-existant layer");
|
||||
layer->OnTransact(code, in, out);
|
||||
|
||||
out.WriteParcel(request.outputBuf.at(0));
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IHOSBinderDriver::AdjustRefcount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
request.Skip<u32>();
|
||||
auto addVal{request.Pop<i32>()};
|
||||
auto type{request.Pop<i32>()};
|
||||
state.logger->Debug("Reference Change: {} {} reference", addVal, type ? "strong" : "weak");
|
||||
auto binderHandle{request.Pop<u32>()};
|
||||
if (binderHandle != DefaultBinderLayerHandle)
|
||||
throw exception("Adjusting Binder object reference count for unknown object: #{}", binderHandle);
|
||||
|
||||
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 {};
|
||||
}
|
||||
|
||||
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);
|
||||
response.copyHandles.push_back(handle);
|
||||
|
||||
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
|
||||
|
||||
#include <services/serviceman.h>
|
||||
#include <services/base_service.h>
|
||||
#include "GraphicBufferProducer.h"
|
||||
|
||||
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
|
||||
*/
|
||||
class IHOSBinderDriver : public BaseService {
|
||||
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:
|
||||
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);
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @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(
|
||||
SFUNC(0x0, IHOSBinderDriver, TransactParcel),
|
||||
SFUNC(0x1, IHOSBinderDriver, AdjustRefcount),
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "parcel.h"
|
||||
|
||||
namespace skyline::service {
|
||||
namespace skyline::service::hosbinder {
|
||||
Parcel::Parcel(span<u8> buffer, const DeviceState &state, bool hasToken) : state(state) {
|
||||
header = buffer.as<ParcelHeader>();
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <kernel/ipc.h>
|
||||
|
||||
namespace skyline::service {
|
||||
namespace skyline::service::hosbinder {
|
||||
/**
|
||||
* @brief This allows easy access and efficient serialization of an Android Parcel object
|
||||
* @url https://switchbrew.org/wiki/Display_services#Parcel
|
@ -18,6 +18,9 @@
|
||||
#include "services/timesrv/core.h"
|
||||
#include "fssrv/IFileSystemProxy.h"
|
||||
#include "services/nvdrv/INvDrvServices.h"
|
||||
#include "hosbinder/IHOSBinderDriver.h"
|
||||
#include "visrv/IApplicationRootService.h"
|
||||
#include "visrv/ISystemRootService.h"
|
||||
#include "visrv/IManagerRootService.h"
|
||||
#include "pl/IPlatformServiceManager.h"
|
||||
#include "aocsrv/IAddOnContentManager.h"
|
||||
@ -35,7 +38,7 @@
|
||||
|
||||
#define SERVICE_CASE(class, 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; \
|
||||
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)) {}
|
||||
|
||||
std::shared_ptr<BaseService> ServiceManager::CreateService(ServiceName name) {
|
||||
std::shared_ptr<BaseService> ServiceManager::CreateOrGetService(ServiceName name) {
|
||||
auto serviceIter{serviceMap.find(name)};
|
||||
if (serviceIter != serviceMap.end())
|
||||
return (*serviceIter).second;
|
||||
@ -74,9 +77,10 @@ namespace skyline::service {
|
||||
SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:a")
|
||||
SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:s")
|
||||
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:u")
|
||||
SERVICE_CASE(visrv::IManagerRootService, "vi:s")
|
||||
SERVICE_CASE(pl::IPlatformServiceManager, "pl:u")
|
||||
SERVICE_CASE(aocsrv::IAddOnContentManager, "aoc:u")
|
||||
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::lock_guard serviceGuard(mutex);
|
||||
auto serviceObject{CreateService(name)};
|
||||
auto serviceObject{CreateOrGetService(name)};
|
||||
KHandle handle{};
|
||||
if (session.isDomain) {
|
||||
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::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:
|
||||
std::shared_ptr<BaseService> smUserInterface; //!< Used by applications to open connections to services
|
||||
std::shared_ptr<GlobalServiceState> globalServiceState;
|
||||
@ -58,19 +51,13 @@ namespace skyline::service {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param serviceType The type of the service
|
||||
* @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
|
||||
* @brief Creates an instance of the service if it doesn't already exist, otherwise returns an existing instance
|
||||
*/
|
||||
template<typename Type>
|
||||
std::shared_ptr<Type> GetService(ServiceName name) {
|
||||
return std::static_pointer_cast<Type>(serviceMap.at(name));
|
||||
}
|
||||
std::shared_ptr<BaseService> CreateOrGetService(ServiceName name);
|
||||
|
||||
template<typename Type>
|
||||
constexpr std::shared_ptr<Type> GetService(std::string_view name) {
|
||||
return GetService<Type>(util::MakeMagic<ServiceName>(name));
|
||||
constexpr std::shared_ptr<Type> CreateOrGetService(std::string_view name) {
|
||||
return std::static_pointer_cast<Type>(CreateOrGetService(util::MakeMagic<ServiceName>(name)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,101 +3,85 @@
|
||||
|
||||
#include <gpu.h>
|
||||
#include <kernel/types/KProcess.h>
|
||||
#include <services/serviceman.h>
|
||||
#include <services/hosbinder/IHOSBinderDriver.h>
|
||||
#include <services/hosbinder/GraphicBufferProducer.h>
|
||||
#include "IApplicationDisplayService.h"
|
||||
#include "ISystemDisplayService.h"
|
||||
#include "IManagerDisplayService.h"
|
||||
#include "results.h"
|
||||
|
||||
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) {
|
||||
manager.RegisterService(SRVREG(hosbinder::IHOSBinderDriver), session, response);
|
||||
manager.RegisterService(hosbinder, session, response);
|
||||
return {};
|
||||
}
|
||||
|
||||
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 {};
|
||||
}
|
||||
|
||||
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);
|
||||
return {};
|
||||
}
|
||||
|
||||
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);
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IApplicationDisplayService::OpenDisplay(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
std::string displayName(request.PopString());
|
||||
state.logger->Debug("Setting display as: {}", displayName);
|
||||
|
||||
auto producer{hosbinder::producer.lock()};
|
||||
producer->SetDisplay(displayName);
|
||||
|
||||
response.Push<u64>(0); // There's only one display
|
||||
auto displayName(request.PopString());
|
||||
state.logger->Debug("Opening display: {}", displayName);
|
||||
response.Push(hosbinder->OpenDisplay(displayName));
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IApplicationDisplayService::CloseDisplay(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
state.logger->Debug("Closing the display");
|
||||
auto producer{hosbinder::producer.lock()};
|
||||
producer->CloseDisplay();
|
||||
auto displayId{request.Pop<hosbinder::DisplayId>()};
|
||||
state.logger->Debug("Closing display: {}", hosbinder::ToString(displayId));
|
||||
hosbinder->CloseDisplay(displayId);
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IApplicationDisplayService::OpenLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
struct InputStruct {
|
||||
char displayName[0x40];
|
||||
u64 layerId;
|
||||
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 displayName{request.PopString(0x40)};
|
||||
auto layerId{request.Pop<u64>()};
|
||||
state.logger->Debug("Opening layer #{} on display: {}", layerId, displayName);
|
||||
|
||||
auto displayId{hosbinder->OpenDisplay(displayName)};
|
||||
auto parcel{hosbinder->OpenLayer(displayId, layerId)};
|
||||
response.Push<u64>(parcel.WriteParcel(request.outputBuf.at(0)));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IApplicationDisplayService::CloseLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
u64 layerId{request.Pop<u64>()};
|
||||
state.logger->Debug("Closing Layer: {}", 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;
|
||||
|
||||
state.logger->Debug("Closing layer #{}", layerId);
|
||||
hosbinder->CloseLayer(layerId);
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IApplicationDisplayService::SetLayerScalingMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto scalingMode{request.Pop<u64>()};
|
||||
auto layerId{request.Pop<u64>()};
|
||||
|
||||
state.logger->Debug("Setting Layer Scaling mode to '{}' for layer {}", scalingMode, layerId);
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IApplicationDisplayService::GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
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);
|
||||
return {};
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "IDisplayService.h"
|
||||
#include "IRootService.h"
|
||||
|
||||
namespace skyline::service::visrv {
|
||||
/**
|
||||
@ -11,8 +12,11 @@ namespace skyline::service::visrv {
|
||||
* @url https://switchbrew.org/wiki/Display_services#IApplicationDisplayService
|
||||
*/
|
||||
class IApplicationDisplayService : public IDisplayService {
|
||||
private:
|
||||
PrivilegeLevel level;
|
||||
|
||||
public:
|
||||
IApplicationDisplayService(const DeviceState &state, ServiceManager &manager);
|
||||
IApplicationDisplayService(const DeviceState &state, ServiceManager &manager, PrivilegeLevel level);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
SERVICE_DECL(
|
||||
SFUNC(0x64, IApplicationDisplayService, GetRelayService),
|
||||
SFUNC(0x65, IApplicationDisplayService, GetSystemDisplayService),
|
||||
SFUNC(0x66, IApplicationDisplayService, GetManagerDisplayService),
|
||||
SFUNC(0x67, IApplicationDisplayService, GetIndirectDisplayTransactionService),
|
||||
SFUNC(0x3F2, IApplicationDisplayService, OpenDisplay),
|
||||
SFUNC(0x3FC, IApplicationDisplayService, CloseDisplay),
|
||||
SFUNC(0x7E4, IApplicationDisplayService, OpenLayer),
|
||||
SFUNC(0x7E5, IApplicationDisplayService, CloseLayer),
|
||||
SFUNC_BASE(0x7EE, IApplicationDisplayService, IDisplayService, CreateStrayLayer),
|
||||
SFUNC_BASE(0x7EF, IApplicationDisplayService, IDisplayService, DestroyStrayLayer),
|
||||
SFUNC(0x835, IApplicationDisplayService, SetLayerScalingMode),
|
||||
SFUNC(0x1452, IApplicationDisplayService, GetDisplayVsyncEvent)
|
||||
)
|
||||
SERVICE_DECL(
|
||||
SFUNC(0x64, IApplicationDisplayService, GetRelayService),
|
||||
SFUNC(0x65, IApplicationDisplayService, GetSystemDisplayService),
|
||||
SFUNC(0x66, IApplicationDisplayService, GetManagerDisplayService),
|
||||
SFUNC(0x67, IApplicationDisplayService, GetIndirectDisplayTransactionService),
|
||||
SFUNC(0x3F2, IApplicationDisplayService, OpenDisplay),
|
||||
SFUNC(0x3FC, IApplicationDisplayService, CloseDisplay),
|
||||
SFUNC(0x7E4, IApplicationDisplayService, OpenLayer),
|
||||
SFUNC(0x7E5, IApplicationDisplayService, CloseLayer),
|
||||
SFUNC_BASE(0x7EE, IApplicationDisplayService, IDisplayService, CreateStrayLayer),
|
||||
SFUNC_BASE(0x7EF, IApplicationDisplayService, IDisplayService, DestroyStrayLayer),
|
||||
SFUNC(0x835, IApplicationDisplayService, SetLayerScalingMode),
|
||||
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
|
||||
// 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"
|
||||
|
||||
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) {
|
||||
request.Skip<u64>();
|
||||
auto displayId{request.Pop<u64>()};
|
||||
request.Skip<u64>(); // VI Layer flags
|
||||
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()};
|
||||
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);
|
||||
state.logger->Debug("Creating Stray Layer #{} on Display: {}", layerId, hosbinder::ToString(displayId));
|
||||
|
||||
auto parcel{hosbinder->OpenLayer(displayId, layerId)};
|
||||
response.Push<u64>(parcel.WriteParcel(request.outputBuf.at(0)));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IDisplayService::DestroyStrayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto layerId{request.Pop<u64>()};
|
||||
state.logger->Debug("Destroying Stray Layer: {}", layerId);
|
||||
state.logger->Debug("Destroying Stray Layer #{}", 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;
|
||||
hosbinder->CloseLayer(layerId);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -3,7 +3,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <services/serviceman.h>
|
||||
#include <services/base_service.h>
|
||||
|
||||
namespace skyline::service::hosbinder {
|
||||
class IHOSBinderDriver;
|
||||
}
|
||||
|
||||
namespace skyline::service::visrv {
|
||||
/**
|
||||
@ -11,18 +15,7 @@ namespace skyline::service::visrv {
|
||||
*/
|
||||
class IDisplayService : public BaseService {
|
||||
protected:
|
||||
/**
|
||||
* @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);
|
||||
std::shared_ptr<hosbinder::IHOSBinderDriver> hosbinder; //!< The IHOSBinder relayed via this display class
|
||||
|
||||
public:
|
||||
IDisplayService(const DeviceState &state, ServiceManager &manager);
|
||||
|
@ -1,35 +1,27 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <services/hosbinder/GraphicBufferProducer.h>
|
||||
#include <services/hosbinder/IHOSBinderDriver.h>
|
||||
#include "IManagerDisplayService.h"
|
||||
|
||||
namespace skyline::service::visrv {
|
||||
IManagerDisplayService::IManagerDisplayService(const DeviceState &state, ServiceManager &manager) : IDisplayService(state, manager) {}
|
||||
|
||||
Result IManagerDisplayService::CreateManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
request.Skip<u32>();
|
||||
auto displayId{request.Pop<u64>()};
|
||||
state.logger->Debug("Creating Managed Layer on Display: {}", displayId);
|
||||
request.Skip<u64>(); // VI Layer flags
|
||||
auto displayId{request.Pop<hosbinder::DisplayId>()};
|
||||
|
||||
auto producer{hosbinder::producer.lock()};
|
||||
if (producer->layerStatus != hosbinder::LayerStatus::Uninitialized)
|
||||
throw exception("The application is creating more than one layer");
|
||||
producer->layerStatus = hosbinder::LayerStatus::Managed;
|
||||
auto layerId{hosbinder->CreateLayer(displayId)};
|
||||
state.logger->Debug("Creating Managed Layer #{} on Display: {}", layerId, hosbinder::ToString(displayId));
|
||||
response.Push(layerId);
|
||||
|
||||
response.Push<u64>(0); // There's only one layer
|
||||
return {};
|
||||
}
|
||||
|
||||
Result IManagerDisplayService::DestroyManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto layerId{request.Pop<u64>()};
|
||||
state.logger->Debug("Destroying Managed Layer: {}", 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;
|
||||
|
||||
state.logger->Debug("Destroying Managed Layer #{}", layerId);
|
||||
hosbinder->DestroyLayer(layerId);
|
||||
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
|
||||
|
||||
#include <gpu.h>
|
||||
#include <services/serviceman.h>
|
||||
#include "IRootService.h"
|
||||
|
||||
namespace skyline::service::visrv {
|
||||
/**
|
||||
* @brief This service is used to get an handle to #IApplicationDisplayService
|
||||
* @url https://switchbrew.org/wiki/Display_services#vi:m
|
||||
*/
|
||||
class IManagerRootService : public BaseService {
|
||||
class IManagerRootService : public IRootService {
|
||||
public:
|
||||
IManagerRootService(const DeviceState &state, ServiceManager &manager);
|
||||
IManagerRootService(const DeviceState &state, ServiceManager &manager) : IRootService(state, manager, PrivilegeLevel::Manager) {}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
SERVICE_DECL(
|
||||
SFUNC(0x2, IManagerRootService, GetDisplayService)
|
||||
)
|
||||
SERVICE_DECL(
|
||||
SFUNC_BASE(0x2, IManagerRootService, IRootService, 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