mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-01 03:15:10 +01:00
Move NVDRV + IHOSBinder Internals to Discrete Components + Fix Lint
This commit is contained in:
parent
5f0073dd87
commit
4cc3a3b2e8
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -1,6 +1,6 @@
|
|||||||
name: CI
|
name: CI
|
||||||
|
|
||||||
on: push
|
on: [push, pull_request]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -113,6 +113,7 @@ add_library(skyline SHARED
|
|||||||
${source_DIR}/skyline/services/fssrv/IFile.cpp
|
${source_DIR}/skyline/services/fssrv/IFile.cpp
|
||||||
${source_DIR}/skyline/services/fssrv/IStorage.cpp
|
${source_DIR}/skyline/services/fssrv/IStorage.cpp
|
||||||
${source_DIR}/skyline/services/nvdrv/INvDrvServices.cpp
|
${source_DIR}/skyline/services/nvdrv/INvDrvServices.cpp
|
||||||
|
${source_DIR}/skyline/services/nvdrv/driver.cpp
|
||||||
${source_DIR}/skyline/services/nvdrv/devices/nvmap.cpp
|
${source_DIR}/skyline/services/nvdrv/devices/nvmap.cpp
|
||||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost_ctrl_gpu.cpp
|
${source_DIR}/skyline/services/nvdrv/devices/nvhost_ctrl_gpu.cpp
|
||||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost_ctrl.cpp
|
${source_DIR}/skyline/services/nvdrv/devices/nvhost_ctrl.cpp
|
||||||
@ -120,6 +121,7 @@ add_library(skyline SHARED
|
|||||||
${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/IHOSBinderDriver.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/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
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace skyline {
|
namespace skyline {
|
||||||
namespace service::hosbinder {
|
namespace service::hosbinder {
|
||||||
class IHOSBinderDriver;
|
class GraphicBufferProducer;
|
||||||
}
|
}
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
namespace texture {
|
namespace texture {
|
||||||
@ -189,7 +189,7 @@ namespace skyline {
|
|||||||
return presentation;
|
return presentation;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend service::hosbinder::IHOSBinderDriver;
|
friend service::hosbinder::GraphicBufferProducer;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
#include <os.h>
|
#include <os.h>
|
||||||
#include <services/hosbinder/IHOSBinderDriver.h>
|
#include <services/hosbinder/GraphicBufferProducer.h>
|
||||||
#include <services/hosbinder/display.h>
|
#include <services/hosbinder/display.h>
|
||||||
#include "ISelfController.h"
|
#include "ISelfController.h"
|
||||||
|
|
||||||
@ -61,10 +61,10 @@ 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");
|
state.logger->Debug("Creating Managed Layer on Default Display");
|
||||||
|
|
||||||
auto hosBinder = state.os->serviceManager.GetService<hosbinder::IHOSBinderDriver>("dispdrv");
|
auto producer = hosbinder::producer.lock();
|
||||||
if (hosBinder->layerStatus != hosbinder::LayerStatus::Uninitialized)
|
if (producer->layerStatus != hosbinder::LayerStatus::Uninitialized)
|
||||||
throw exception("The application is creating more than one layer");
|
throw exception("The application is creating more than one layer");
|
||||||
hosBinder->layerStatus = hosbinder::LayerStatus::Managed;
|
producer->layerStatus = hosbinder::LayerStatus::Managed;
|
||||||
|
|
||||||
response.Push<u64>(0);
|
response.Push<u64>(0);
|
||||||
return {};
|
return {};
|
||||||
|
@ -28,6 +28,7 @@ namespace skyline::service {
|
|||||||
public:
|
public:
|
||||||
std::vector<u8> data; //!< A vector filled with data in the parcel
|
std::vector<u8> data; //!< A vector filled with data in the parcel
|
||||||
std::vector<u8> objects; //!< A vector filled with objects in the parcel
|
std::vector<u8> objects; //!< A vector filled with objects in the parcel
|
||||||
|
size_t dataOffset{}; //!< This is the offset of the data read from the parcel
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This constructor fills in the Parcel object with data from a IPC buffer
|
* @brief This constructor fills in the Parcel object with data from a IPC buffer
|
||||||
@ -52,16 +53,26 @@ namespace skyline::service {
|
|||||||
*/
|
*/
|
||||||
Parcel(const DeviceState &state);
|
Parcel(const DeviceState &state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A reference to an item from the top of data
|
||||||
|
*/
|
||||||
|
template<typename ValueType>
|
||||||
|
inline ValueType &Pop() {
|
||||||
|
ValueType &value = *reinterpret_cast<ValueType *>(data.data() + dataOffset);
|
||||||
|
dataOffset += sizeof(ValueType);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Writes some data to the Parcel
|
* @brief Writes some data to the Parcel
|
||||||
* @tparam ValueType The type of the object to write
|
* @tparam ValueType The type of the object to write
|
||||||
* @param value The object to be written
|
* @param value The object to be written
|
||||||
*/
|
*/
|
||||||
template<typename ValueType>
|
template<typename ValueType>
|
||||||
void WriteData(const ValueType &value) {
|
void Push(const ValueType &value) {
|
||||||
data.reserve(data.size() + sizeof(ValueType));
|
data.reserve(data.size() + sizeof(ValueType));
|
||||||
auto item = reinterpret_cast<const u8 *>(&value);
|
auto item = reinterpret_cast<const u8 *>(&value);
|
||||||
for (uint index = 0; sizeof(ValueType) > index; index++) {
|
for (size_t index{}; sizeof(ValueType) > index; index++) {
|
||||||
data.push_back(*item);
|
data.push_back(*item);
|
||||||
item++;
|
item++;
|
||||||
}
|
}
|
||||||
@ -73,10 +84,10 @@ namespace skyline::service {
|
|||||||
* @param value The object to be written
|
* @param value The object to be written
|
||||||
*/
|
*/
|
||||||
template<typename ValueType>
|
template<typename ValueType>
|
||||||
void WriteObject(const ValueType &value) {
|
void PushObject(const ValueType &value) {
|
||||||
objects.reserve(objects.size() + sizeof(ValueType));
|
objects.reserve(objects.size() + sizeof(ValueType));
|
||||||
auto item = reinterpret_cast<const u8 *>(&value);
|
auto item = reinterpret_cast<const u8 *>(&value);
|
||||||
for (uint index = 0; sizeof(ValueType) > index; index++) {
|
for (size_t index{}; sizeof(ValueType) > index; index++) {
|
||||||
objects.push_back(*item);
|
objects.push_back(*item);
|
||||||
item++;
|
item++;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,212 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#include <gpu.h>
|
||||||
|
#include <os.h>
|
||||||
|
#include <kernel/types/KProcess.h>
|
||||||
|
#include <services/nvdrv/driver.h>
|
||||||
|
#include <services/common/fence.h>
|
||||||
|
#include <gpu/format.h>
|
||||||
|
#include "GraphicBufferProducer.h"
|
||||||
|
#include "display.h"
|
||||||
|
|
||||||
|
namespace skyline::service::hosbinder {
|
||||||
|
Buffer::Buffer(const GbpBuffer &gbpBuffer, const std::shared_ptr<gpu::PresentationTexture> &texture) : gbpBuffer(gbpBuffer), texture(texture) {}
|
||||||
|
|
||||||
|
GraphicBufferProducer::GraphicBufferProducer(const DeviceState &state) : state(state) {}
|
||||||
|
|
||||||
|
void GraphicBufferProducer::RequestBuffer(Parcel &in, Parcel &out) {
|
||||||
|
u32 slot{in.Pop<u32>()};
|
||||||
|
|
||||||
|
out.Push<u32>(1);
|
||||||
|
out.Push<u32>(sizeof(GbpBuffer));
|
||||||
|
out.Push<u32>(0);
|
||||||
|
out.Push(queue.at(slot)->gbpBuffer);
|
||||||
|
|
||||||
|
state.logger->Debug("RequestBuffer: Slot: {}", slot, sizeof(GbpBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphicBufferProducer::DequeueBuffer(Parcel &in, Parcel &out) {
|
||||||
|
u32 format{in.Pop<u32>()};
|
||||||
|
u32 width{in.Pop<u32>()};
|
||||||
|
u32 height{in.Pop<u32>()};
|
||||||
|
u32 timestamp{in.Pop<u32>()};
|
||||||
|
u32 usage{in.Pop<u32>()};
|
||||||
|
|
||||||
|
std::optional<u32> slot{std::nullopt};
|
||||||
|
while (!slot) {
|
||||||
|
for (auto &buffer : queue) {
|
||||||
|
if (buffer.second->status == BufferStatus::Free && buffer.second->gbpBuffer.format == format && buffer.second->gbpBuffer.width == width && buffer.second->gbpBuffer.height == height && (buffer.second->gbpBuffer.usage & usage) == usage) {
|
||||||
|
slot = buffer.first;
|
||||||
|
buffer.second->status = BufferStatus::Dequeued;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.Push(*slot);
|
||||||
|
out.Push(std::array<u32, 13>{1, 0x24}); // Unknown
|
||||||
|
|
||||||
|
state.logger->Debug("DequeueBuffer: Width: {}, Height: {}, Format: {}, Usage: {}, Timestamp: {}, Slot: {}", width, height, format, usage, timestamp, *slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphicBufferProducer::QueueBuffer(Parcel &in, Parcel &out) {
|
||||||
|
struct Data {
|
||||||
|
u32 slot;
|
||||||
|
u64 timestamp;
|
||||||
|
u32 autoTimestamp;
|
||||||
|
ARect crop;
|
||||||
|
u32 scalingMode;
|
||||||
|
u32 transform;
|
||||||
|
u32 stickyTransform;
|
||||||
|
u64 _unk0_;
|
||||||
|
u32 swapInterval;
|
||||||
|
nvdrv::Fence fence[4];
|
||||||
|
} &data = in.Pop<Data>();
|
||||||
|
|
||||||
|
auto buffer = queue.at(data.slot);
|
||||||
|
buffer->status = BufferStatus::Queued;
|
||||||
|
|
||||||
|
auto slot = data.slot;
|
||||||
|
auto bufferEvent = state.gpu->bufferEvent;
|
||||||
|
buffer->texture->releaseCallback = [this, slot, bufferEvent]() {
|
||||||
|
queue.at(slot)->status = BufferStatus::Free;
|
||||||
|
bufferEvent->Signal();
|
||||||
|
};
|
||||||
|
|
||||||
|
buffer->texture->SynchronizeHost();
|
||||||
|
state.gpu->presentationQueue.push(buffer->texture);
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u32 width;
|
||||||
|
u32 height;
|
||||||
|
u32 _pad_[3];
|
||||||
|
} output{
|
||||||
|
.width = buffer->gbpBuffer.width,
|
||||||
|
.height = buffer->gbpBuffer.height,
|
||||||
|
};
|
||||||
|
out.Push(output);
|
||||||
|
|
||||||
|
state.logger->Debug("QueueBuffer: Timestamp: {}, Auto Timestamp: {}, Crop: [T: {}, B: {}, L: {}, R: {}], Scaling Mode: {}, Transform: {}, Sticky Transform: {}, Swap Interval: {}, Slot: {}", data.timestamp, data.autoTimestamp, data.crop.top, data.crop.bottom, data.crop.left, data.crop.right, data.scalingMode, data.transform, data.stickyTransform, data.swapInterval, data.slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphicBufferProducer::CancelBuffer(Parcel &in) {
|
||||||
|
u32 slot{in.Pop<u32>()};
|
||||||
|
//auto fences{in.Pop<std::array<nvdrv::Fence, 4>>()};
|
||||||
|
|
||||||
|
queue.at(slot)->status = BufferStatus::Free;
|
||||||
|
|
||||||
|
state.logger->Debug("CancelBuffer: Slot: {}", slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphicBufferProducer::Connect(Parcel &out) {
|
||||||
|
struct {
|
||||||
|
u32 width{constant::HandheldResolutionW}; //!< The width of the display
|
||||||
|
u32 height{constant::HandheldResolutionH}; //!< The height of the display
|
||||||
|
u32 transformHint{}; //!< A hint of the transformation of the display
|
||||||
|
u32 pendingBuffers{}; //!< The number of pending buffers
|
||||||
|
u32 status{}; //!< The status of the buffer queue
|
||||||
|
} data{};
|
||||||
|
out.Push(data);
|
||||||
|
state.logger->Debug("Connect");
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphicBufferProducer::SetPreallocatedBuffer(Parcel &in) {
|
||||||
|
struct Data {
|
||||||
|
u32 slot;
|
||||||
|
u32 _unk0_;
|
||||||
|
u32 length;
|
||||||
|
u32 _pad0_;
|
||||||
|
} &data = in.Pop<Data>();
|
||||||
|
|
||||||
|
auto& gbpBuffer = in.Pop<GbpBuffer>();
|
||||||
|
|
||||||
|
std::shared_ptr<nvdrv::device::NvMap::NvMapObject> nvBuffer{};
|
||||||
|
|
||||||
|
auto driver = nvdrv::driver.lock();
|
||||||
|
auto nvmap = driver->GetDevice<nvdrv::device::NvMap>(nvdrv::device::NvDeviceType::nvmap);
|
||||||
|
|
||||||
|
if (gbpBuffer.nvmapHandle) {
|
||||||
|
nvBuffer = nvmap->handleTable.at(gbpBuffer.nvmapHandle);
|
||||||
|
} else {
|
||||||
|
for (const auto &object : nvmap->handleTable) {
|
||||||
|
if (object.second->id == gbpBuffer.nvmapId) {
|
||||||
|
nvBuffer = object.second;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!nvBuffer)
|
||||||
|
throw exception("A QueueBuffer request has an invalid NVMap Handle ({}) and ID ({})", gbpBuffer.nvmapHandle, gbpBuffer.nvmapId);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpu::texture::Format format;
|
||||||
|
switch (gbpBuffer.format) {
|
||||||
|
case WINDOW_FORMAT_RGBA_8888:
|
||||||
|
case WINDOW_FORMAT_RGBX_8888:
|
||||||
|
format = gpu::format::RGBA8888Unorm;
|
||||||
|
break;
|
||||||
|
case WINDOW_FORMAT_RGB_565:
|
||||||
|
format = gpu::format::RGB565Unorm;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw exception("Unknown pixel format used for FB");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto texture = std::make_shared<gpu::GuestTexture>(state, nvBuffer->address + gbpBuffer.offset, gpu::texture::Dimensions(gbpBuffer.width, gbpBuffer.height), format, gpu::texture::TileMode::Block, gpu::texture::TileConfig{.surfaceWidth = static_cast<u16>(gbpBuffer.stride), .blockHeight = static_cast<u8>(1U << gbpBuffer.blockHeightLog2), .blockDepth = 1});
|
||||||
|
|
||||||
|
queue[data.slot] = std::make_shared<Buffer>(gbpBuffer, texture->InitializePresentationTexture());
|
||||||
|
state.gpu->bufferEvent->Signal();
|
||||||
|
|
||||||
|
state.logger->Debug("SetPreallocatedBuffer: Slot: {}, Magic: 0x{:X}, Width: {}, Height: {}, Stride: {}, Format: {}, Usage: {}, Index: {}, ID: {}, Handle: {}, Offset: 0x{:X}, Block Height: {}, Size: 0x{:X}", data.slot, gbpBuffer.magic, gbpBuffer.width, gbpBuffer.height, gbpBuffer.stride, gbpBuffer.format, gbpBuffer.usage, gbpBuffer.index, gbpBuffer.nvmapId, gbpBuffer.nvmapHandle, gbpBuffer.offset, (1U << gbpBuffer.blockHeightLog2), gbpBuffer.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphicBufferProducer::OnTransact(TransactionCode code, Parcel &in, Parcel &out) {
|
||||||
|
switch (code) {
|
||||||
|
case TransactionCode::RequestBuffer:
|
||||||
|
RequestBuffer(in, out);
|
||||||
|
break;
|
||||||
|
case TransactionCode::DequeueBuffer:
|
||||||
|
DequeueBuffer(in, out);
|
||||||
|
break;
|
||||||
|
case TransactionCode::QueueBuffer:
|
||||||
|
QueueBuffer(in, out);
|
||||||
|
break;
|
||||||
|
case TransactionCode::CancelBuffer:
|
||||||
|
CancelBuffer(in);
|
||||||
|
break;
|
||||||
|
case TransactionCode::Query:
|
||||||
|
out.Push<u64>(0);
|
||||||
|
break;
|
||||||
|
case TransactionCode::Connect:
|
||||||
|
Connect(out);
|
||||||
|
break;
|
||||||
|
case TransactionCode::Disconnect:
|
||||||
|
break;
|
||||||
|
case TransactionCode::SetPreallocatedBuffer:
|
||||||
|
SetPreallocatedBuffer(in);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw exception("An unimplemented transaction was called: {}", static_cast<u32>(code));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphicBufferProducer::SetDisplay(const std::string &name) {
|
||||||
|
try {
|
||||||
|
const auto type = DisplayTypeMap.at(name);
|
||||||
|
if (displayId == DisplayId::Null)
|
||||||
|
displayId = type;
|
||||||
|
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{};
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gpu.h>
|
||||||
|
#include <services/common/parcel.h>
|
||||||
|
#include "display.h"
|
||||||
|
|
||||||
|
namespace skyline::service::hosbinder {
|
||||||
|
/**
|
||||||
|
* @brief This internal struct contains all data about the graphics buffer (https://github.com/reswitched/libtransistor/blob/0f0c36227842c344d163922fc98ee76229e9f0ee/lib/display/graphic_buffer_queue.c#L66)
|
||||||
|
*/
|
||||||
|
struct GbpBuffer {
|
||||||
|
u32 magic; //!< The magic of the graphics buffer: 0x47424652
|
||||||
|
u32 width; //!< The width of the buffer
|
||||||
|
u32 height; //!< The height of the buffer
|
||||||
|
u32 stride; //!< The stride of the buffer
|
||||||
|
u32 format; //!< The format of the buffer, this corresponds to AHardwareBuffer_Format
|
||||||
|
u32 usage; //!< The usage flags for the buffer
|
||||||
|
u32 _pad0_;
|
||||||
|
u32 index; //!< The index of the buffer
|
||||||
|
u32 _pad1_[3];
|
||||||
|
u32 nvmapId; //!< The ID of the buffer in regards to /dev/nvmap
|
||||||
|
u32 _pad2_[8];
|
||||||
|
u32 size; //!< The size of the buffer
|
||||||
|
u32 _pad3_[8];
|
||||||
|
u32 nvmapHandle; //!< The handle of the buffer in regards to /dev/nvmap
|
||||||
|
u32 offset; //!< This is the offset of the pixel data in the GPU Buffer
|
||||||
|
u32 _pad4_;
|
||||||
|
u32 blockHeightLog2; //!< The log2 of the block height
|
||||||
|
u32 _pad5_[58];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class BufferStatus {
|
||||||
|
Free, //!< The buffer is free
|
||||||
|
Dequeued, //!< The buffer has been dequeued from the display
|
||||||
|
Queued, //!< The buffer is queued to be displayed
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A wrapper over GbpBuffer which contains additional state that we track for a buffer
|
||||||
|
*/
|
||||||
|
class Buffer {
|
||||||
|
public:
|
||||||
|
BufferStatus status{BufferStatus::Free};
|
||||||
|
std::shared_ptr<gpu::PresentationTexture> texture;
|
||||||
|
GbpBuffer gbpBuffer;
|
||||||
|
|
||||||
|
Buffer(const GbpBuffer &gbpBuffer, const std::shared_ptr<gpu::PresentationTexture> &texture);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief nvnflinger:dispdrv or nns::hosbinder::IHOSBinderDriver is responsible for writing buffers to the display
|
||||||
|
*/
|
||||||
|
class GraphicBufferProducer {
|
||||||
|
private:
|
||||||
|
const DeviceState &state;
|
||||||
|
std::unordered_map<u32, std::shared_ptr<Buffer>> queue; //!< A vector of shared pointers to all the queued buffers
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Request for the GbpBuffer of a buffer
|
||||||
|
*/
|
||||||
|
void RequestBuffer(Parcel &in, Parcel &out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Try to dequeue a free graphics buffer that has been consumed
|
||||||
|
*/
|
||||||
|
void DequeueBuffer(Parcel &in, Parcel &out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Queue a buffer to be presented
|
||||||
|
*/
|
||||||
|
void QueueBuffer(Parcel &in, Parcel &out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove a previously queued buffer
|
||||||
|
*/
|
||||||
|
void CancelBuffer(Parcel &in);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Query a few attributes of the graphic buffers
|
||||||
|
*/
|
||||||
|
void Connect(Parcel &out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Attach a GPU buffer to a graphics buffer
|
||||||
|
*/
|
||||||
|
void SetPreallocatedBuffer(Parcel &in);
|
||||||
|
|
||||||
|
public:
|
||||||
|
DisplayId displayId{DisplayId::Null}; //!< The ID of this display
|
||||||
|
LayerStatus layerStatus{LayerStatus::Uninitialized}; //!< This is the status of the single layer the display has
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This enumerates the functions called by TransactParcel for android.gui.IGraphicBufferProducer
|
||||||
|
* @refitem https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#35
|
||||||
|
*/
|
||||||
|
enum class TransactionCode : u32 {
|
||||||
|
RequestBuffer = 1, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#281
|
||||||
|
SetBufferCount = 2, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#293
|
||||||
|
DequeueBuffer = 3, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#300
|
||||||
|
DetachBuffer = 4, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#318
|
||||||
|
DetachNextBuffer = 5, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#325
|
||||||
|
AttachBuffer = 6, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#343
|
||||||
|
QueueBuffer = 7, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#353
|
||||||
|
CancelBuffer = 8, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#364
|
||||||
|
Query = 9, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#372
|
||||||
|
Connect = 10, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#381
|
||||||
|
Disconnect = 11, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#396
|
||||||
|
SetSidebandStream = 12, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#403
|
||||||
|
AllocateBuffers = 13, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#413
|
||||||
|
SetPreallocatedBuffer = 14, //!< No source on this but it's used to set a existing buffer according to libtransistor and libNX
|
||||||
|
};
|
||||||
|
|
||||||
|
GraphicBufferProducer(const DeviceState &state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The handler for Binder IPC transactions with IGraphicBufferProducer (https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#277)
|
||||||
|
*/
|
||||||
|
void OnTransact(TransactionCode code, Parcel &in, Parcel &out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This sets displayId to a specific display type
|
||||||
|
* @param name The name of the display
|
||||||
|
* @note displayId has to be DisplayId::Null or this will throw an exception
|
||||||
|
*/
|
||||||
|
void SetDisplay(const std::string &name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This closes the display by setting displayId to DisplayId::Null
|
||||||
|
*/
|
||||||
|
void CloseDisplay();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern std::weak_ptr<GraphicBufferProducer> producer; //!< A globally shared instance of the GraphicsBufferProducer
|
||||||
|
}
|
@ -1,210 +1,30 @@
|
|||||||
// 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 <gpu.h>
|
|
||||||
#include <os.h>
|
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
#include <services/nvdrv/INvDrvServices.h>
|
|
||||||
#include <services/common/fence.h>
|
|
||||||
#include <gpu/format.h>
|
|
||||||
#include "IHOSBinderDriver.h"
|
#include "IHOSBinderDriver.h"
|
||||||
#include "display.h"
|
#include "GraphicBufferProducer.h"
|
||||||
|
|
||||||
namespace skyline::service::hosbinder {
|
namespace skyline::service::hosbinder {
|
||||||
IHOSBinderDriver::IHOSBinderDriver(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, {
|
IHOSBinderDriver::IHOSBinderDriver(const DeviceState &state, ServiceManager &manager) : producer(hosbinder::producer.expired() ? std::make_shared<GraphicBufferProducer>(state) : hosbinder::producer.lock()), BaseService(state, manager, {
|
||||||
{0x0, SFUNC(IHOSBinderDriver::TransactParcel)},
|
{0x0, SFUNC(IHOSBinderDriver::TransactParcel)},
|
||||||
{0x1, SFUNC(IHOSBinderDriver::AdjustRefcount)},
|
{0x1, SFUNC(IHOSBinderDriver::AdjustRefcount)},
|
||||||
{0x2, SFUNC(IHOSBinderDriver::GetNativeHandle)},
|
{0x2, SFUNC(IHOSBinderDriver::GetNativeHandle)},
|
||||||
{0x3, SFUNC(IHOSBinderDriver::TransactParcel)}
|
{0x3, SFUNC(IHOSBinderDriver::TransactParcel)}
|
||||||
}) {}
|
}) {
|
||||||
|
if (hosbinder::producer.expired())
|
||||||
void IHOSBinderDriver::RequestBuffer(Parcel &in, Parcel &out) {
|
hosbinder::producer = producer;
|
||||||
u32 slot = *reinterpret_cast<u32 *>(in.data.data());
|
|
||||||
out.WriteData<u32>(1);
|
|
||||||
out.WriteData<u32>(sizeof(GbpBuffer));
|
|
||||||
out.WriteData<u32>(0);
|
|
||||||
out.WriteData(queue.at(slot)->gbpBuffer);
|
|
||||||
state.logger->Debug("RequestBuffer: Slot: {}", slot, sizeof(GbpBuffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHOSBinderDriver::DequeueBuffer(Parcel &in, Parcel &out) {
|
|
||||||
struct Data {
|
|
||||||
u32 format;
|
|
||||||
u32 width;
|
|
||||||
u32 height;
|
|
||||||
u32 timestamps;
|
|
||||||
u32 usage;
|
|
||||||
} *data = reinterpret_cast<Data *>(in.data.data());
|
|
||||||
|
|
||||||
i64 slot{-1};
|
|
||||||
while (slot == -1) {
|
|
||||||
for (auto &buffer : queue) {
|
|
||||||
if (buffer.second->status == BufferStatus::Free && buffer.second->gbpBuffer.width == data->width && buffer.second->gbpBuffer.height == data->height && (buffer.second->gbpBuffer.usage & data->usage) == data->usage) {
|
|
||||||
slot = buffer.first;
|
|
||||||
buffer.second->status = BufferStatus::Dequeued;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
asm("yield");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u32 slot;
|
|
||||||
u32 _unk_[13];
|
|
||||||
} output{
|
|
||||||
.slot = static_cast<u32>(slot),
|
|
||||||
._unk_ = {1, 0x24}
|
|
||||||
};
|
|
||||||
out.WriteData(output);
|
|
||||||
|
|
||||||
state.logger->Debug("DequeueBuffer: Width: {}, Height: {}, Format: {}, Usage: {}, Timestamps: {}, Slot: {}", data->width, data->height, data->format, data->usage, data->timestamps, slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHOSBinderDriver::QueueBuffer(Parcel &in, Parcel &out) {
|
|
||||||
struct Data {
|
|
||||||
u32 slot;
|
|
||||||
u64 timestamp;
|
|
||||||
u32 autoTimestamp;
|
|
||||||
ARect crop;
|
|
||||||
u32 scalingMode;
|
|
||||||
u32 transform;
|
|
||||||
u32 stickyTransform;
|
|
||||||
u64 _unk0_;
|
|
||||||
u32 swapInterval;
|
|
||||||
nvdrv::Fence fence[4];
|
|
||||||
} *data = reinterpret_cast<Data *>(in.data.data());
|
|
||||||
|
|
||||||
auto buffer = queue.at(data->slot);
|
|
||||||
buffer->status = BufferStatus::Queued;
|
|
||||||
|
|
||||||
auto slot = data->slot;
|
|
||||||
auto bufferEvent = state.gpu->bufferEvent;
|
|
||||||
buffer->texture->releaseCallback = [this, slot, bufferEvent]() {
|
|
||||||
FreeBuffer(slot);
|
|
||||||
bufferEvent->Signal();
|
|
||||||
};
|
|
||||||
|
|
||||||
buffer->texture->SynchronizeHost();
|
|
||||||
|
|
||||||
state.gpu->presentationQueue.push(buffer->texture);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u32 width;
|
|
||||||
u32 height;
|
|
||||||
u32 _pad0_[3];
|
|
||||||
} output{
|
|
||||||
.width = buffer->gbpBuffer.width,
|
|
||||||
.height = buffer->gbpBuffer.height
|
|
||||||
};
|
|
||||||
|
|
||||||
out.WriteData(output);
|
|
||||||
|
|
||||||
state.logger->Debug("QueueBuffer: Timestamp: {}, Auto Timestamp: {}, Crop: [T: {}, B: {}, L: {}, R: {}], Scaling Mode: {}, Transform: {}, Sticky Transform: {}, Swap Interval: {}, Slot: {}", data->timestamp, data->autoTimestamp, data->crop.top, data->crop.bottom, data->crop.left, data->crop.right, data->scalingMode, data->transform, data->stickyTransform, data->swapInterval, data->slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHOSBinderDriver::CancelBuffer(Parcel &parcel) {
|
|
||||||
struct Data {
|
|
||||||
u32 slot;
|
|
||||||
nvdrv::Fence fence[4];
|
|
||||||
} *data = reinterpret_cast<Data *>(parcel.data.data());
|
|
||||||
FreeBuffer(data->slot);
|
|
||||||
state.logger->Debug("CancelBuffer: Slot: {}", data->slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IHOSBinderDriver::SetPreallocatedBuffer(Parcel &parcel) {
|
|
||||||
auto pointer = parcel.data.data();
|
|
||||||
struct Data {
|
|
||||||
u32 slot;
|
|
||||||
u32 _unk0_;
|
|
||||||
u32 length;
|
|
||||||
u32 _pad0_;
|
|
||||||
} *data = reinterpret_cast<Data *>(pointer);
|
|
||||||
|
|
||||||
pointer += sizeof(Data);
|
|
||||||
auto gbpBuffer = reinterpret_cast<GbpBuffer *>(pointer);
|
|
||||||
|
|
||||||
std::shared_ptr<nvdrv::device::NvMap::NvMapObject> nvBuffer{};
|
|
||||||
auto nvmap = state.os->serviceManager.GetService<nvdrv::INvDrvServices>("nvdrv:a")->GetDevice<nvdrv::device::NvMap>(nvdrv::device::NvDeviceType::nvmap);
|
|
||||||
|
|
||||||
if (gbpBuffer->nvmapHandle) {
|
|
||||||
nvBuffer = nvmap->handleTable.at(gbpBuffer->nvmapHandle);
|
|
||||||
} else {
|
|
||||||
for (const auto &object : nvmap->handleTable) {
|
|
||||||
if (object.second->id == gbpBuffer->nvmapId) {
|
|
||||||
nvBuffer = object.second;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!nvBuffer)
|
|
||||||
throw exception("A QueueBuffer request has an invalid NVMap Handle ({}) and ID ({})", gbpBuffer->nvmapHandle, gbpBuffer->nvmapId);
|
|
||||||
}
|
|
||||||
|
|
||||||
gpu::texture::Format format;
|
|
||||||
switch (gbpBuffer->format) {
|
|
||||||
case WINDOW_FORMAT_RGBA_8888:
|
|
||||||
case WINDOW_FORMAT_RGBX_8888:
|
|
||||||
format = gpu::format::RGBA8888Unorm;
|
|
||||||
break;
|
|
||||||
case WINDOW_FORMAT_RGB_565:
|
|
||||||
format = gpu::format::RGB565Unorm;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw exception("Unknown pixel format used for FB");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto texture = std::make_shared<gpu::GuestTexture>(state, nvBuffer->address + gbpBuffer->offset, gpu::texture::Dimensions(gbpBuffer->width, gbpBuffer->height), format, gpu::texture::TileMode::Block, gpu::texture::TileConfig{.surfaceWidth = static_cast<u16>(gbpBuffer->stride), .blockHeight = static_cast<u8>(1U << gbpBuffer->blockHeightLog2), .blockDepth = 1});
|
|
||||||
|
|
||||||
queue[data->slot] = std::make_shared<Buffer>(data->slot, *gbpBuffer, texture->InitializePresentationTexture());
|
|
||||||
state.gpu->bufferEvent->Signal();
|
|
||||||
|
|
||||||
state.logger->Debug("SetPreallocatedBuffer: Slot: {}, Magic: 0x{:X}, Width: {}, Height: {}, Stride: {}, Format: {}, Usage: {}, Index: {}, ID: {}, Handle: {}, Offset: 0x{:X}, Block Height: {}, Size: 0x{:X}", data->slot, gbpBuffer->magic, gbpBuffer->width, gbpBuffer->height, gbpBuffer->stride, gbpBuffer->format, gbpBuffer->usage, gbpBuffer->index, gbpBuffer->nvmapId,
|
|
||||||
gbpBuffer->nvmapHandle, gbpBuffer->offset, (1U << gbpBuffer->blockHeightLog2), gbpBuffer->size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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>();
|
auto layerId = request.Pop<u32>();
|
||||||
auto code = request.Pop<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);
|
||||||
|
|
||||||
state.logger->Debug("TransactParcel: Layer ID: {}, Code: {}", layerId, code);
|
state.logger->Debug("TransactParcel: Layer ID: {}, Code: {}", layerId, code);
|
||||||
|
producer->OnTransact(code, in, out);
|
||||||
switch (code) {
|
|
||||||
case TransactionCode::RequestBuffer:
|
|
||||||
RequestBuffer(in, out);
|
|
||||||
break;
|
|
||||||
case TransactionCode::DequeueBuffer:
|
|
||||||
DequeueBuffer(in, out);
|
|
||||||
break;
|
|
||||||
case TransactionCode::QueueBuffer:
|
|
||||||
QueueBuffer(in, out);
|
|
||||||
break;
|
|
||||||
case TransactionCode::CancelBuffer:
|
|
||||||
CancelBuffer(in);
|
|
||||||
break;
|
|
||||||
case TransactionCode::Query:
|
|
||||||
out.WriteData<u64>(0);
|
|
||||||
break;
|
|
||||||
case TransactionCode::Connect: {
|
|
||||||
ConnectParcel connect = {
|
|
||||||
.width = constant::HandheldResolutionW,
|
|
||||||
.height = constant::HandheldResolutionH,
|
|
||||||
.transformHint = 0,
|
|
||||||
.pendingBuffers = 0,
|
|
||||||
.status = 0,
|
|
||||||
};
|
|
||||||
out.WriteData(connect);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TransactionCode::Disconnect:
|
|
||||||
break;
|
|
||||||
case TransactionCode::SetPreallocatedBuffer:
|
|
||||||
SetPreallocatedBuffer(in);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw exception("An unimplemented transaction was called: {}", static_cast<u32>(code));
|
|
||||||
}
|
|
||||||
|
|
||||||
out.WriteParcel(request.outputBuf.at(0));
|
out.WriteParcel(request.outputBuf.at(0));
|
||||||
return {};
|
return {};
|
||||||
@ -226,22 +46,4 @@ namespace skyline::service::hosbinder {
|
|||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void IHOSBinderDriver::SetDisplay(const std::string &name) {
|
|
||||||
try {
|
|
||||||
const auto type = DisplayTypeMap.at(name);
|
|
||||||
if (displayId == DisplayId::Null)
|
|
||||||
displayId = type;
|
|
||||||
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 IHOSBinderDriver::CloseDisplay() {
|
|
||||||
if (displayId == DisplayId::Null)
|
|
||||||
state.logger->Warn("Trying to close uninitiated display");
|
|
||||||
displayId = DisplayId::Null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,87 +5,18 @@
|
|||||||
|
|
||||||
#include <services/base_service.h>
|
#include <services/base_service.h>
|
||||||
#include <services/serviceman.h>
|
#include <services/serviceman.h>
|
||||||
#include <services/common/parcel.h>
|
|
||||||
#include "buffer.h"
|
|
||||||
#include "display.h"
|
|
||||||
|
|
||||||
namespace skyline::service::hosbinder {
|
namespace skyline::service::hosbinder {
|
||||||
/**
|
class GraphicBufferProducer;
|
||||||
* @brief This enumerates the functions called by TransactParcel for android.gui.IGraphicBufferProducer
|
|
||||||
* @refitem https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#35
|
|
||||||
*/
|
|
||||||
enum class TransactionCode : u32 {
|
|
||||||
RequestBuffer = 1, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#281
|
|
||||||
SetBufferCount = 2, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#293
|
|
||||||
DequeueBuffer = 3, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#300
|
|
||||||
DetachBuffer = 4, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#318
|
|
||||||
DetachNextBuffer = 5, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#325
|
|
||||||
AttachBuffer = 6, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#343
|
|
||||||
QueueBuffer = 7, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#353
|
|
||||||
CancelBuffer = 8, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#364
|
|
||||||
Query = 9, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#372
|
|
||||||
Connect = 10, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#381
|
|
||||||
Disconnect = 11, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#396
|
|
||||||
SetSidebandStream = 12, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#403
|
|
||||||
AllocateBuffers = 13, //!< https://android.googlesource.com/platform/frameworks/native/+/8dc5539/libs/gui/IGraphicBufferProducer.cpp#413
|
|
||||||
SetPreallocatedBuffer = 14, //!< No source on this but it's used to set a existing buffer according to libtransistor and libNX
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief nvnflinger:dispdrv or nns::hosbinder::IHOSBinderDriver is responsible for writing buffers to the display
|
* @brief nvnflinger:dispdrv or nns::hosbinder::IHOSBinderDriver is responsible for writing buffers to the display
|
||||||
*/
|
*/
|
||||||
class IHOSBinderDriver : public BaseService {
|
class IHOSBinderDriver : public BaseService {
|
||||||
private:
|
private:
|
||||||
/**
|
std::shared_ptr<GraphicBufferProducer> producer;
|
||||||
* @brief This is the structure of the parcel used for TransactionCode::Connect
|
|
||||||
*/
|
|
||||||
struct ConnectParcel {
|
|
||||||
u32 width; //!< The width of the display
|
|
||||||
u32 height; //!< The height of the display
|
|
||||||
u32 transformHint; //!< A hint of the transformation of the display
|
|
||||||
u32 pendingBuffers; //!< The number of pending buffers
|
|
||||||
u32 status; //!< The status of the buffer queue
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unordered_map<u32, std::shared_ptr<Buffer>> queue; //!< A vector of shared pointers to all the queued buffers
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This the GbpBuffer struct of the specified buffer
|
|
||||||
*/
|
|
||||||
void RequestBuffer(Parcel &in, Parcel &out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This returns the slot of a free buffer
|
|
||||||
*/
|
|
||||||
void DequeueBuffer(Parcel &in, Parcel &out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This queues a buffer to be displayed
|
|
||||||
*/
|
|
||||||
void QueueBuffer(Parcel &in, Parcel &out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This removes a previously queued buffer
|
|
||||||
*/
|
|
||||||
void CancelBuffer(Parcel &parcel);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This adds a pre-existing buffer to the queue
|
|
||||||
*/
|
|
||||||
void SetPreallocatedBuffer(Parcel &parcel);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This frees a buffer which is currently queued
|
|
||||||
* @param slotNo The slot of the buffer
|
|
||||||
*/
|
|
||||||
inline void FreeBuffer(u32 slotNo) {
|
|
||||||
queue.at(slotNo)->status = BufferStatus::Free;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DisplayId displayId{DisplayId::Null}; //!< The ID of this display
|
|
||||||
LayerStatus layerStatus{LayerStatus::Uninitialized}; //!< This is the status of the single layer the display has
|
|
||||||
|
|
||||||
IHOSBinderDriver(const DeviceState &state, ServiceManager &manager);
|
IHOSBinderDriver(const DeviceState &state, ServiceManager &manager);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,17 +33,5 @@ namespace skyline::service::hosbinder {
|
|||||||
* @brief This adjusts the reference counts to the underlying binder, it is stubbed as we aren't using the real symbols (https://switchbrew.org/wiki/Nvnflinger_services#GetNativeHandle)
|
* @brief This adjusts the reference counts to the underlying binder, it is stubbed as we aren't using the real symbols (https://switchbrew.org/wiki/Nvnflinger_services#GetNativeHandle)
|
||||||
*/
|
*/
|
||||||
Result GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
Result GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This sets displayId to a specific display type
|
|
||||||
* @param name The name of the display
|
|
||||||
* @note displayId has to be DisplayId::Null or this will throw an exception
|
|
||||||
*/
|
|
||||||
void SetDisplay(const std::string &name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This closes the display by setting displayId to DisplayId::Null
|
|
||||||
*/
|
|
||||||
void CloseDisplay();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -9,49 +9,4 @@
|
|||||||
#include <gpu.h>
|
#include <gpu.h>
|
||||||
|
|
||||||
namespace skyline::service::hosbinder {
|
namespace skyline::service::hosbinder {
|
||||||
/**
|
|
||||||
* @brief This struct holds information about the graphics buffer (https://github.com/reswitched/libtransistor/blob/0f0c36227842c344d163922fc98ee76229e9f0ee/lib/display/graphic_buffer_queue.c#L66)
|
|
||||||
*/
|
|
||||||
struct GbpBuffer {
|
|
||||||
u32 magic; //!< The magic of the graphics buffer: 0x47424652
|
|
||||||
u32 width; //!< The width of the buffer
|
|
||||||
u32 height; //!< The height of the buffer
|
|
||||||
u32 stride; //!< The stride of the buffer
|
|
||||||
u32 format; //!< The format of the buffer, this corresponds to AHardwareBuffer_Format
|
|
||||||
u32 usage; //!< The usage flags for the buffer
|
|
||||||
u32 _pad0_;
|
|
||||||
u32 index; //!< The index of the buffer
|
|
||||||
u32 _pad1_[3];
|
|
||||||
u32 nvmapId; //!< The ID of the buffer in regards to /dev/nvmap
|
|
||||||
u32 _pad2_[8];
|
|
||||||
u32 size; //!< The size of the buffer
|
|
||||||
u32 _pad3_[8];
|
|
||||||
u32 nvmapHandle; //!< The handle of the buffer in regards to /dev/nvmap
|
|
||||||
u32 offset; //!< This is the offset of the pixel data in the GPU Buffer
|
|
||||||
u32 _pad4_;
|
|
||||||
u32 blockHeightLog2; //!< The log2 of the block height
|
|
||||||
u32 _pad5_[58];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The current status of a buffer
|
|
||||||
*/
|
|
||||||
enum class BufferStatus {
|
|
||||||
Free, //!< The buffer is free
|
|
||||||
Dequeued, //!< The buffer has been dequeued from the display
|
|
||||||
Queued, //!< The buffer is queued to be displayed
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This holds all relevant objects for a specific buffer
|
|
||||||
*/
|
|
||||||
class Buffer {
|
|
||||||
public:
|
|
||||||
u32 slot; //!< The slot the buffer is in
|
|
||||||
BufferStatus status{BufferStatus::Free}; //!< The status of this buffer
|
|
||||||
std::shared_ptr<gpu::PresentationTexture> texture{}; //!< The underlying PresentationTexture of this buffer
|
|
||||||
GbpBuffer gbpBuffer; //!< The GbpBuffer object for this buffer
|
|
||||||
|
|
||||||
Buffer(u32 slot, const GbpBuffer &gbpBuffer, const std::shared_ptr<gpu::PresentationTexture> &texture) : slot(slot), gbpBuffer(gbpBuffer), texture(texture) {};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -2,59 +2,12 @@
|
|||||||
// 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 "devices/nvhost_ctrl.h"
|
|
||||||
#include "devices/nvhost_ctrl_gpu.h"
|
|
||||||
#include "devices/nvhost_channel.h"
|
|
||||||
#include "devices/nvhost_as_gpu.h"
|
|
||||||
#include "INvDrvServices.h"
|
#include "INvDrvServices.h"
|
||||||
|
#include "driver.h"
|
||||||
|
#include "devices/nvdevice.h"
|
||||||
|
|
||||||
namespace skyline::service::nvdrv {
|
namespace skyline::service::nvdrv {
|
||||||
u32 INvDrvServices::OpenDevice(const std::string &path) {
|
INvDrvServices::INvDrvServices(const DeviceState &state, ServiceManager &manager) : driver(nvdrv::driver.expired() ? std::make_shared<Driver>(state) : nvdrv::driver.lock()), BaseService(state, manager, {
|
||||||
state.logger->Debug("Opening NVDRV device ({}): {}", fdIndex, path);
|
|
||||||
auto type = device::nvDeviceMap.at(path);
|
|
||||||
for (const auto &device : fdMap) {
|
|
||||||
if (device.second->deviceType == type) {
|
|
||||||
device.second->refCount++;
|
|
||||||
fdMap[fdIndex] = device.second;
|
|
||||||
return fdIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<device::NvDevice> object;
|
|
||||||
switch (type) {
|
|
||||||
case device::NvDeviceType::nvhost_ctrl:
|
|
||||||
object = std::make_shared<device::NvHostCtrl>(state);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case device::NvDeviceType::nvhost_gpu:
|
|
||||||
case device::NvDeviceType::nvhost_vic:
|
|
||||||
case device::NvDeviceType::nvhost_nvdec:
|
|
||||||
object = std::make_shared<device::NvHostChannel>(state, type);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case device::NvDeviceType::nvhost_ctrl_gpu:
|
|
||||||
object = std::make_shared<device::NvHostCtrlGpu>(state);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case device::NvDeviceType::nvmap:
|
|
||||||
object = std::make_shared<device::NvMap>(state);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case device::NvDeviceType::nvhost_as_gpu:
|
|
||||||
object = std::make_shared<device::NvHostAsGpu>(state);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw exception("Cannot find NVDRV device");
|
|
||||||
}
|
|
||||||
|
|
||||||
deviceMap[type] = object;
|
|
||||||
fdMap[fdIndex] = object;
|
|
||||||
|
|
||||||
return fdIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
INvDrvServices::INvDrvServices(const DeviceState &state, ServiceManager &manager) : hostSyncpoint(state), BaseService(state, manager, {
|
|
||||||
{0x0, SFUNC(INvDrvServices::Open)},
|
{0x0, SFUNC(INvDrvServices::Open)},
|
||||||
{0x1, SFUNC(INvDrvServices::Ioctl)},
|
{0x1, SFUNC(INvDrvServices::Ioctl)},
|
||||||
{0x2, SFUNC(INvDrvServices::Close)},
|
{0x2, SFUNC(INvDrvServices::Close)},
|
||||||
@ -62,13 +15,16 @@ namespace skyline::service::nvdrv {
|
|||||||
{0x4, SFUNC(INvDrvServices::QueryEvent)},
|
{0x4, SFUNC(INvDrvServices::QueryEvent)},
|
||||||
{0x8, SFUNC(INvDrvServices::SetAruidByPID)},
|
{0x8, SFUNC(INvDrvServices::SetAruidByPID)},
|
||||||
{0xD, SFUNC(INvDrvServices::SetGraphicsFirmwareMemoryMarginEnabled)}
|
{0xD, SFUNC(INvDrvServices::SetGraphicsFirmwareMemoryMarginEnabled)}
|
||||||
}) {}
|
}) {
|
||||||
|
if (nvdrv::driver.expired())
|
||||||
|
nvdrv::driver = driver;
|
||||||
|
}
|
||||||
|
|
||||||
Result INvDrvServices::Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result INvDrvServices::Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
auto buffer = request.inputBuf.at(0);
|
auto buffer = request.inputBuf.at(0);
|
||||||
auto path = state.process->GetString(buffer.address, buffer.size);
|
auto path = state.process->GetString(buffer.address, buffer.size);
|
||||||
|
|
||||||
response.Push<u32>(OpenDevice(path));
|
response.Push<u32>(driver->OpenDevice(path));
|
||||||
response.Push(device::NvStatus::Success);
|
response.Push(device::NvStatus::Success);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
@ -77,9 +33,10 @@ namespace skyline::service::nvdrv {
|
|||||||
Result INvDrvServices::Ioctl(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result INvDrvServices::Ioctl(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
auto fd = request.Pop<u32>();
|
auto fd = request.Pop<u32>();
|
||||||
auto cmd = request.Pop<u32>();
|
auto cmd = request.Pop<u32>();
|
||||||
|
|
||||||
state.logger->Debug("IOCTL on device: 0x{:X}, cmd: 0x{:X}", fd, cmd);
|
state.logger->Debug("IOCTL on device: 0x{:X}, cmd: 0x{:X}", fd, cmd);
|
||||||
|
|
||||||
|
auto device = driver->GetDevice(fd);
|
||||||
|
|
||||||
// Strip the permissions from the command leaving only the ID
|
// Strip the permissions from the command leaving only the ID
|
||||||
cmd &= 0xFFFF;
|
cmd &= 0xFFFF;
|
||||||
|
|
||||||
@ -88,18 +45,18 @@ namespace skyline::service::nvdrv {
|
|||||||
if (request.inputBuf.empty()) {
|
if (request.inputBuf.empty()) {
|
||||||
device::IoctlData data(request.outputBuf.at(0));
|
device::IoctlData data(request.outputBuf.at(0));
|
||||||
|
|
||||||
fdMap.at(fd)->HandleIoctl(cmd, data);
|
device->HandleIoctl(cmd, data);
|
||||||
response.Push(data.status);
|
response.Push(data.status);
|
||||||
} else {
|
} else {
|
||||||
device::IoctlData data(request.inputBuf.at(0));
|
device::IoctlData data(request.inputBuf.at(0));
|
||||||
|
|
||||||
fdMap.at(fd)->HandleIoctl(cmd, data);
|
device->HandleIoctl(cmd, data);
|
||||||
response.Push(data.status);
|
response.Push(data.status);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
device::IoctlData data(request.inputBuf.at(0), request.outputBuf.at(0));
|
device::IoctlData data(request.inputBuf.at(0), request.outputBuf.at(0));
|
||||||
|
|
||||||
fdMap.at(fd)->HandleIoctl(cmd, data);
|
device->HandleIoctl(cmd, data);
|
||||||
response.Push(data.status);
|
response.Push(data.status);
|
||||||
}
|
}
|
||||||
} catch (const std::out_of_range &) {
|
} catch (const std::out_of_range &) {
|
||||||
@ -113,15 +70,7 @@ namespace skyline::service::nvdrv {
|
|||||||
auto fd = request.Pop<u32>();
|
auto fd = request.Pop<u32>();
|
||||||
state.logger->Debug("Closing NVDRV device ({})", fd);
|
state.logger->Debug("Closing NVDRV device ({})", fd);
|
||||||
|
|
||||||
try {
|
driver->CloseDevice(fd);
|
||||||
auto device = fdMap.at(fd);
|
|
||||||
if (!--device->refCount)
|
|
||||||
deviceMap.erase(device->deviceType);
|
|
||||||
|
|
||||||
fdMap.erase(fd);
|
|
||||||
} catch (const std::out_of_range &) {
|
|
||||||
state.logger->Warn("Trying to close non-existent FD");
|
|
||||||
}
|
|
||||||
|
|
||||||
response.Push(device::NvStatus::Success);
|
response.Push(device::NvStatus::Success);
|
||||||
return {};
|
return {};
|
||||||
@ -135,7 +84,8 @@ namespace skyline::service::nvdrv {
|
|||||||
Result INvDrvServices::QueryEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result INvDrvServices::QueryEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
auto fd = request.Pop<u32>();
|
auto fd = request.Pop<u32>();
|
||||||
auto eventId = request.Pop<u32>();
|
auto eventId = request.Pop<u32>();
|
||||||
auto device = fdMap.at(fd);
|
|
||||||
|
auto device = driver->GetDevice(fd);
|
||||||
auto event = device->QueryEvent(eventId);
|
auto event = device->QueryEvent(eventId);
|
||||||
|
|
||||||
if (event != nullptr) {
|
if (event != nullptr) {
|
||||||
|
@ -5,63 +5,18 @@
|
|||||||
|
|
||||||
#include <services/base_service.h>
|
#include <services/base_service.h>
|
||||||
#include <services/serviceman.h>
|
#include <services/serviceman.h>
|
||||||
#include <kernel/types/KTransferMemory.h>
|
|
||||||
#include <gpu.h>
|
|
||||||
#include "devices/nvdevice.h"
|
|
||||||
#include "devices/nvhost_syncpoint.h"
|
|
||||||
|
|
||||||
namespace skyline::service::nvdrv {
|
namespace skyline::service::nvdrv {
|
||||||
|
class Driver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief nvdrv or INvDrvServices is used to access the Nvidia GPU inside the Switch (https://switchbrew.org/wiki/NV_services#nvdrv.2C_nvdrv:a.2C_nvdrv:s.2C_nvdrv:t)
|
* @brief nvdrv or INvDrvServices is used to access the Nvidia GPU inside the Switch (https://switchbrew.org/wiki/NV_services#nvdrv.2C_nvdrv:a.2C_nvdrv:s.2C_nvdrv:t)
|
||||||
*/
|
*/
|
||||||
class INvDrvServices : public BaseService {
|
class INvDrvServices : public BaseService {
|
||||||
private:
|
private:
|
||||||
std::unordered_map<device::NvDeviceType, std::shared_ptr<device::NvDevice>> deviceMap; //!< A map from a NvDeviceType to the NvDevice object
|
std::shared_ptr<Driver> driver;
|
||||||
std::unordered_map<u32, std::shared_ptr<device::NvDevice>> fdMap; //!< A map from an FD to a shared pointer to it's NvDevice object
|
|
||||||
u32 fdIndex{}; //!< Holds the index of a file descriptor
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Open a specific device and return a FD
|
|
||||||
* @param path The path of the device to open an FD to
|
|
||||||
* @return The file descriptor to the device
|
|
||||||
*/
|
|
||||||
u32 OpenDevice(const std::string &path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns a particular device with a specific FD
|
|
||||||
* @tparam objectClass The class of the device to return
|
|
||||||
* @param fd The file descriptor to retrieve
|
|
||||||
* @return A shared pointer to the device
|
|
||||||
*/
|
|
||||||
template<typename objectClass>
|
|
||||||
std::shared_ptr<objectClass> GetDevice(u32 fd) {
|
|
||||||
try {
|
|
||||||
auto item = fdMap.at(fd);
|
|
||||||
return std::static_pointer_cast<objectClass>(item);
|
|
||||||
} catch (std::out_of_range) {
|
|
||||||
throw exception("GetDevice was called with invalid file descriptor: 0x{:X}", fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NvHostSyncpoint hostSyncpoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns a particular device with a specific type
|
|
||||||
* @tparam objectClass The class of the device to return
|
|
||||||
* @param type The type of the device to return
|
|
||||||
* @return A shared pointer to the device
|
|
||||||
*/
|
|
||||||
template<typename objectClass>
|
|
||||||
std::shared_ptr<objectClass> GetDevice(device::NvDeviceType type) {
|
|
||||||
try {
|
|
||||||
auto item = deviceMap.at(type);
|
|
||||||
return std::static_pointer_cast<objectClass>(item);
|
|
||||||
} catch (std::out_of_range) {
|
|
||||||
throw exception("GetDevice was called with invalid type: 0x{:X}", type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
INvDrvServices(const DeviceState &state, ServiceManager &manager);
|
INvDrvServices(const DeviceState &state, ServiceManager &manager);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#define NFUNC(function) std::bind(&function, this, std::placeholders::_1)
|
#define NFUNC(function) std::bind(&function, this, std::placeholders::_1)
|
||||||
|
|
||||||
namespace skyline::service::nvdrv::device {
|
namespace skyline::service::nvdrv::device {
|
||||||
|
using namespace kernel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief An enumeration of all the devices that can be opened by nvdrv
|
* @brief An enumeration of all the devices that can be opened by nvdrv
|
||||||
*/
|
*/
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <gpu.h>
|
#include <gpu.h>
|
||||||
#include <os.h>
|
#include <os.h>
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
#include <services/nvdrv/INvDrvServices.h>
|
#include <services/nvdrv/driver.h>
|
||||||
#include "nvmap.h"
|
#include "nvmap.h"
|
||||||
#include "nvhost_as_gpu.h"
|
#include "nvhost_as_gpu.h"
|
||||||
|
|
||||||
@ -70,7 +70,8 @@ namespace skyline::service::nvdrv::device {
|
|||||||
if (!region.nvmapHandle)
|
if (!region.nvmapHandle)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto nvmap = state.os->serviceManager.GetService<nvdrv::INvDrvServices>("nvdrv")->GetDevice<nvdrv::device::NvMap>(nvdrv::device::NvDeviceType::nvmap)->handleTable.at(region.nvmapHandle);
|
auto driver = nvdrv::driver.lock();
|
||||||
|
auto nvmap = driver->GetDevice<nvdrv::device::NvMap>(nvdrv::device::NvDeviceType::nvmap)->handleTable.at(region.nvmapHandle);
|
||||||
|
|
||||||
u64 mapPhysicalAddress = region.bufferOffset + nvmap->address;
|
u64 mapPhysicalAddress = region.bufferOffset + nvmap->address;
|
||||||
u64 mapSize = region.mappingSize ? region.mappingSize : nvmap->size;
|
u64 mapSize = region.mappingSize ? region.mappingSize : nvmap->size;
|
||||||
@ -133,7 +134,8 @@ namespace skyline::service::nvdrv::device {
|
|||||||
|
|
||||||
for (auto entry : entries) {
|
for (auto entry : entries) {
|
||||||
try {
|
try {
|
||||||
auto nvmap = state.os->serviceManager.GetService<nvdrv::INvDrvServices>("nvdrv")->GetDevice<nvdrv::device::NvMap>(nvdrv::device::NvDeviceType::nvmap)->handleTable.at(entry.nvmapHandle);
|
auto driver = nvdrv::driver.lock();
|
||||||
|
auto nvmap = driver->GetDevice<nvdrv::device::NvMap>(nvdrv::device::NvDeviceType::nvmap)->handleTable.at(entry.nvmapHandle);
|
||||||
|
|
||||||
u64 mapAddress = static_cast<u64>(entry.gpuOffset) << MinAlignmentShift;
|
u64 mapAddress = static_cast<u64>(entry.gpuOffset) << MinAlignmentShift;
|
||||||
u64 mapPhysicalAddress = nvmap->address + (static_cast<u64>(entry.mapOffset) << MinAlignmentShift);
|
u64 mapPhysicalAddress = nvmap->address + (static_cast<u64>(entry.mapOffset) << MinAlignmentShift);
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <os.h>
|
#include <os.h>
|
||||||
#include <gpu/gpfifo.h>
|
#include <gpu/gpfifo.h>
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
#include <services/nvdrv/INvDrvServices.h>
|
#include <services/nvdrv/driver.h>
|
||||||
#include "nvhost_channel.h"
|
#include "nvhost_channel.h"
|
||||||
|
|
||||||
namespace skyline::service::nvdrv::device {
|
namespace skyline::service::nvdrv::device {
|
||||||
@ -19,7 +19,8 @@ namespace skyline::service::nvdrv::device {
|
|||||||
{0x481A, NFUNC(NvHostChannel::AllocGpfifoEx2)},
|
{0x481A, NFUNC(NvHostChannel::AllocGpfifoEx2)},
|
||||||
{0x4714, NFUNC(NvHostChannel::SetUserData)},
|
{0x4714, NFUNC(NvHostChannel::SetUserData)},
|
||||||
}) {
|
}) {
|
||||||
auto &hostSyncpoint = state.os->serviceManager.GetService<nvdrv::INvDrvServices>("nvdrv")->hostSyncpoint;
|
auto driver = nvdrv::driver.lock();
|
||||||
|
auto &hostSyncpoint = driver->hostSyncpoint;
|
||||||
|
|
||||||
channelFence.id = hostSyncpoint.AllocateSyncpoint(false);
|
channelFence.id = hostSyncpoint.AllocateSyncpoint(false);
|
||||||
channelFence.UpdateValue(hostSyncpoint);
|
channelFence.UpdateValue(hostSyncpoint);
|
||||||
@ -48,7 +49,8 @@ namespace skyline::service::nvdrv::device {
|
|||||||
Fence fence;
|
Fence fence;
|
||||||
} &args = state.process->GetReference<Data>(buffer.output.at(0).address);
|
} &args = state.process->GetReference<Data>(buffer.output.at(0).address);
|
||||||
|
|
||||||
auto &hostSyncpoint = state.os->serviceManager.GetService<nvdrv::INvDrvServices>("nvdrv")->hostSyncpoint;
|
auto driver = nvdrv::driver.lock();
|
||||||
|
auto &hostSyncpoint = driver->hostSyncpoint;
|
||||||
|
|
||||||
if (args.flags.fenceWait) {
|
if (args.flags.fenceWait) {
|
||||||
if (args.flags.incrementWithValue) {
|
if (args.flags.incrementWithValue) {
|
||||||
@ -104,7 +106,8 @@ namespace skyline::service::nvdrv::device {
|
|||||||
u32 reserved[3];
|
u32 reserved[3];
|
||||||
} &args = state.process->GetReference<Data>(buffer.input.at(0).address);
|
} &args = state.process->GetReference<Data>(buffer.input.at(0).address);
|
||||||
|
|
||||||
channelFence.UpdateValue(state.os->serviceManager.GetService<nvdrv::INvDrvServices>("nvdrv")->hostSyncpoint);
|
auto driver = nvdrv::driver.lock();
|
||||||
|
channelFence.UpdateValue(driver->hostSyncpoint);
|
||||||
args.fence = channelFence;
|
args.fence = channelFence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <os.h>
|
#include <os.h>
|
||||||
#include <gpu.h>
|
#include <gpu.h>
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
#include <services/nvdrv/INvDrvServices.h>
|
#include <services/nvdrv/driver.h>
|
||||||
#include "nvhost_ctrl.h"
|
#include "nvhost_ctrl.h"
|
||||||
|
|
||||||
namespace skyline::service::nvdrv::device {
|
namespace skyline::service::nvdrv::device {
|
||||||
@ -95,7 +95,8 @@ namespace skyline::service::nvdrv::device {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &hostSyncpoint = state.os->serviceManager.GetService<nvdrv::INvDrvServices>("nvdrv")->hostSyncpoint;
|
auto driver = nvdrv::driver.lock();
|
||||||
|
auto &hostSyncpoint = driver->hostSyncpoint;
|
||||||
|
|
||||||
// Check if the syncpoint has already expired using the last known values
|
// Check if the syncpoint has already expired using the last known values
|
||||||
if (hostSyncpoint.HasSyncpointExpired(args.fence.id, args.fence.value)) {
|
if (hostSyncpoint.HasSyncpointExpired(args.fence.id, args.fence.value)) {
|
||||||
@ -173,7 +174,8 @@ namespace skyline::service::nvdrv::device {
|
|||||||
|
|
||||||
event.state = NvHostEvent::State::Cancelled;
|
event.state = NvHostEvent::State::Cancelled;
|
||||||
|
|
||||||
auto &hostSyncpoint = state.os->serviceManager.GetService<nvdrv::INvDrvServices>("nvdrv")->hostSyncpoint;
|
auto driver = nvdrv::driver.lock();
|
||||||
|
auto &hostSyncpoint = driver->hostSyncpoint;
|
||||||
hostSyncpoint.UpdateMin(event.fence.id);
|
hostSyncpoint.UpdateMin(event.fence.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ namespace skyline {
|
|||||||
Cancelling = 2,
|
Cancelling = 2,
|
||||||
Signaling = 3,
|
Signaling = 3,
|
||||||
Signaled = 4,
|
Signaled = 4,
|
||||||
Cancelled = 5
|
Cancelled = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
NvHostEvent(const DeviceState &state);
|
NvHostEvent(const DeviceState &state);
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <common.h>
|
|
||||||
#include <gpu/syncpoint.h>
|
#include <gpu/syncpoint.h>
|
||||||
|
|
||||||
namespace skyline::service::nvdrv {
|
namespace skyline::service::nvdrv {
|
||||||
|
72
app/src/main/cpp/skyline/services/nvdrv/driver.cpp
Normal file
72
app/src/main/cpp/skyline/services/nvdrv/driver.cpp
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#include "driver.h"
|
||||||
|
#include "devices/nvhost_ctrl.h"
|
||||||
|
#include "devices/nvhost_ctrl_gpu.h"
|
||||||
|
#include "devices/nvmap.h"
|
||||||
|
#include "devices/nvhost_channel.h"
|
||||||
|
#include "devices/nvhost_as_gpu.h"
|
||||||
|
|
||||||
|
namespace skyline::service::nvdrv {
|
||||||
|
Driver::Driver(const DeviceState &state) : state(state), hostSyncpoint(state) {}
|
||||||
|
|
||||||
|
u32 Driver::OpenDevice(const std::string &path) {
|
||||||
|
state.logger->Debug("Opening NVDRV device ({}): {}", fdIndex, path);
|
||||||
|
auto type = device::nvDeviceMap.at(path);
|
||||||
|
for (const auto &device : fdMap) {
|
||||||
|
if (device.second->deviceType == type) {
|
||||||
|
device.second->refCount++;
|
||||||
|
fdMap[fdIndex] = device.second;
|
||||||
|
return fdIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<device::NvDevice> object;
|
||||||
|
switch (type) {
|
||||||
|
case device::NvDeviceType::nvhost_ctrl:
|
||||||
|
object = std::make_shared<device::NvHostCtrl>(state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case device::NvDeviceType::nvhost_gpu:
|
||||||
|
case device::NvDeviceType::nvhost_vic:
|
||||||
|
case device::NvDeviceType::nvhost_nvdec:
|
||||||
|
object = std::make_shared<device::NvHostChannel>(state, type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case device::NvDeviceType::nvhost_ctrl_gpu:
|
||||||
|
object = std::make_shared<device::NvHostCtrlGpu>(state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case device::NvDeviceType::nvmap:
|
||||||
|
object = std::make_shared<device::NvMap>(state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case device::NvDeviceType::nvhost_as_gpu:
|
||||||
|
object = std::make_shared<device::NvHostAsGpu>(state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw exception("Cannot find NVDRV device");
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceMap[type] = object;
|
||||||
|
fdMap[fdIndex] = object;
|
||||||
|
|
||||||
|
return fdIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Driver::CloseDevice(skyline::u32 fd) {
|
||||||
|
try {
|
||||||
|
auto& device = fdMap.at(fd);
|
||||||
|
if (!--device->refCount)
|
||||||
|
deviceMap.erase(device->deviceType);
|
||||||
|
|
||||||
|
fdMap.erase(fd);
|
||||||
|
} catch (const std::out_of_range &) {
|
||||||
|
state.logger->Warn("Trying to close non-existent FD");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Driver> driver{};
|
||||||
|
}
|
75
app/src/main/cpp/skyline/services/nvdrv/driver.h
Normal file
75
app/src/main/cpp/skyline/services/nvdrv/driver.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "devices/nvhost_syncpoint.h"
|
||||||
|
|
||||||
|
namespace skyline::service::nvdrv {
|
||||||
|
namespace device {
|
||||||
|
class NvDevice;
|
||||||
|
enum class NvDeviceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief nvnflinger:dispdrv or nns::hosbinder::IHOSBinderDriver is responsible for writing buffers to the display
|
||||||
|
*/
|
||||||
|
class Driver {
|
||||||
|
private:
|
||||||
|
const DeviceState &state;
|
||||||
|
std::unordered_map<device::NvDeviceType, std::shared_ptr<device::NvDevice>> deviceMap; //!< A map from a NvDeviceType to the NvDevice object
|
||||||
|
std::unordered_map<u32, std::shared_ptr<device::NvDevice>> fdMap; //!< A map from an FD to a shared pointer to it's NvDevice object
|
||||||
|
u32 fdIndex{}; //!< The index of a file descriptor
|
||||||
|
|
||||||
|
public:
|
||||||
|
NvHostSyncpoint hostSyncpoint;
|
||||||
|
|
||||||
|
Driver(const DeviceState &state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Open a specific device and return a FD
|
||||||
|
* @param path The path of the device to open an FD to
|
||||||
|
* @return The file descriptor to the device
|
||||||
|
*/
|
||||||
|
u32 OpenDevice(const std::string &path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Closes the specified device with it's file descriptor
|
||||||
|
*/
|
||||||
|
void CloseDevice(u32 fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a particular device with a specific FD
|
||||||
|
* @tparam objectClass The class of the device to return
|
||||||
|
* @param fd The file descriptor to retrieve
|
||||||
|
* @return A shared pointer to the device
|
||||||
|
*/
|
||||||
|
template<typename objectClass = device::NvDevice>
|
||||||
|
std::shared_ptr<objectClass> GetDevice(u32 fd) {
|
||||||
|
try {
|
||||||
|
auto item = fdMap.at(fd);
|
||||||
|
return std::static_pointer_cast<objectClass>(item);
|
||||||
|
} catch (std::out_of_range) {
|
||||||
|
throw exception("GetDevice was called with invalid file descriptor: 0x{:X}", fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a particular device with a specific type
|
||||||
|
* @tparam objectClass The class of the device to return
|
||||||
|
* @param type The type of the device to return
|
||||||
|
* @return A shared pointer to the device
|
||||||
|
*/
|
||||||
|
template<typename objectClass = device::NvDevice>
|
||||||
|
std::shared_ptr<objectClass> GetDevice(device::NvDeviceType type) {
|
||||||
|
try {
|
||||||
|
auto item = deviceMap.at(type);
|
||||||
|
return std::static_pointer_cast<objectClass>(item);
|
||||||
|
} catch (std::out_of_range) {
|
||||||
|
throw exception("GetDevice was called with invalid type: 0x{:X}", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern std::weak_ptr<Driver> driver; //!< A globally shared instance of the Driver
|
||||||
|
}
|
@ -100,7 +100,7 @@ namespace skyline::service {
|
|||||||
return serviceObject;
|
return serviceObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceManager::RegisterService(std::shared_ptr<BaseService> serviceObject, type::KSession &session, ipc::IpcResponse &response, bool submodule, ServiceName name) { // NOLINT(performance-unnecessary-value-param)
|
void ServiceManager::RegisterService(std::shared_ptr<BaseService> serviceObject, type::KSession &session, ipc::IpcResponse &response) { // NOLINT(performance-unnecessary-value-param)
|
||||||
std::lock_guard serviceGuard(mutex);
|
std::lock_guard serviceGuard(mutex);
|
||||||
KHandle handle{};
|
KHandle handle{};
|
||||||
|
|
||||||
@ -113,9 +113,6 @@ namespace skyline::service {
|
|||||||
response.moveHandles.push_back(handle);
|
response.moveHandles.push_back(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!submodule)
|
|
||||||
serviceMap[name] = serviceObject;
|
|
||||||
|
|
||||||
state.logger->Debug("Service has been registered: \"{}\" (0x{:X})", serviceObject->GetName(), handle);
|
state.logger->Debug("Service has been registered: \"{}\" (0x{:X})", serviceObject->GetName(), handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ namespace skyline::service {
|
|||||||
* @param submodule If the registered service is a submodule or not
|
* @param submodule If the registered service is a submodule or not
|
||||||
* @param name The name of the service to register if it's not a submodule - it will be added to the service map
|
* @param name The name of the service to register if it's not a submodule - it will be added to the service map
|
||||||
*/
|
*/
|
||||||
void RegisterService(std::shared_ptr<BaseService> serviceObject, type::KSession &session, ipc::IpcResponse &response, bool submodule = true, ServiceName name = {});
|
void RegisterService(std::shared_ptr<BaseService> serviceObject, type::KSession &session, ipc::IpcResponse &response);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param serviceType The type of the service
|
* @param serviceType The type of the service
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <os.h>
|
#include <os.h>
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.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"
|
||||||
@ -25,12 +26,12 @@ namespace skyline::service::visrv {
|
|||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
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, false, util::MakeMagic<ServiceName>("dispdrv"));
|
manager.RegisterService(SRVREG(hosbinder::IHOSBinderDriver), 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, false, util::MakeMagic<ServiceName>("dispdrv"));
|
manager.RegisterService(SRVREG(hosbinder::IHOSBinderDriver), session, response);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +48,9 @@ namespace skyline::service::visrv {
|
|||||||
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());
|
std::string displayName(request.PopString());
|
||||||
state.logger->Debug("Setting display as: {}", displayName);
|
state.logger->Debug("Setting display as: {}", displayName);
|
||||||
state.os->serviceManager.GetService<hosbinder::IHOSBinderDriver>("dispdrv")->SetDisplay(displayName);
|
|
||||||
|
auto producer = hosbinder::producer.lock();
|
||||||
|
producer->SetDisplay(displayName);
|
||||||
|
|
||||||
response.Push<u64>(0); // There's only one display
|
response.Push<u64>(0); // There's only one display
|
||||||
return {};
|
return {};
|
||||||
@ -55,7 +58,8 @@ namespace skyline::service::visrv {
|
|||||||
|
|
||||||
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");
|
state.logger->Debug("Closing the display");
|
||||||
state.os->serviceManager.GetService<hosbinder::IHOSBinderDriver>("dispdrv")->CloseDisplay();
|
auto producer = hosbinder::producer.lock();
|
||||||
|
producer->CloseDisplay();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +80,7 @@ namespace skyline::service::visrv {
|
|||||||
.bufferId = 0, // As we only have one layer and buffer
|
.bufferId = 0, // As we only have one layer and buffer
|
||||||
.string = "dispdrv"
|
.string = "dispdrv"
|
||||||
};
|
};
|
||||||
parcel.WriteData(data);
|
parcel.Push(data);
|
||||||
parcel.objects.resize(4);
|
parcel.objects.resize(4);
|
||||||
|
|
||||||
response.Push<u64>(parcel.WriteParcel(request.outputBuf.at(0)));
|
response.Push<u64>(parcel.WriteParcel(request.outputBuf.at(0)));
|
||||||
@ -87,10 +91,11 @@ namespace skyline::service::visrv {
|
|||||||
u64 layerId = request.Pop<u64>();
|
u64 layerId = request.Pop<u64>();
|
||||||
state.logger->Debug("Closing Layer: {}", layerId);
|
state.logger->Debug("Closing Layer: {}", layerId);
|
||||||
|
|
||||||
auto hosBinder = state.os->serviceManager.GetService<hosbinder::IHOSBinderDriver>("dispdrv");
|
auto producer = hosbinder::producer.lock();
|
||||||
if (hosBinder->layerStatus == hosbinder::LayerStatus::Uninitialized)
|
if (producer->layerStatus == hosbinder::LayerStatus::Uninitialized)
|
||||||
state.logger->Warn("The application is destroying an uninitialized layer");
|
state.logger->Warn("The application is destroying an uninitialized layer");
|
||||||
hosBinder->layerStatus = hosbinder::LayerStatus::Uninitialized;
|
producer->layerStatus = hosbinder::LayerStatus::Uninitialized;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
#include <os.h>
|
#include <os.h>
|
||||||
#include <services/hosbinder/IHOSBinderDriver.h>
|
#include <services/hosbinder/GraphicBufferProducer.h>
|
||||||
#include <services/hosbinder/display.h>
|
#include <services/hosbinder/display.h>
|
||||||
#include "IDisplayService.h"
|
#include "IDisplayService.h"
|
||||||
|
|
||||||
@ -15,10 +15,11 @@ namespace skyline::service::visrv {
|
|||||||
|
|
||||||
state.logger->Debug("Creating Stray Layer on Display: {}", displayId);
|
state.logger->Debug("Creating Stray Layer on Display: {}", displayId);
|
||||||
|
|
||||||
auto hosBinder = state.os->serviceManager.GetService<hosbinder::IHOSBinderDriver>("dispdrv");
|
auto producer = hosbinder::producer.lock();
|
||||||
if (hosBinder->layerStatus == hosbinder::LayerStatus::Stray)
|
if (producer->layerStatus == hosbinder::LayerStatus::Stray)
|
||||||
throw exception("The application is creating more than one stray layer");
|
throw exception("The application is creating more than one stray layer");
|
||||||
hosBinder->layerStatus = hosbinder::LayerStatus::Stray;
|
producer->layerStatus = hosbinder::LayerStatus::Stray;
|
||||||
|
|
||||||
response.Push<u64>(0); // There's only one layer
|
response.Push<u64>(0); // There's only one layer
|
||||||
|
|
||||||
Parcel parcel(state);
|
Parcel parcel(state);
|
||||||
@ -28,7 +29,7 @@ namespace skyline::service::visrv {
|
|||||||
.bufferId = 0, // As we only have one layer and buffer
|
.bufferId = 0, // As we only have one layer and buffer
|
||||||
.string = "dispdrv"
|
.string = "dispdrv"
|
||||||
};
|
};
|
||||||
parcel.WriteData(data);
|
parcel.Push(data);
|
||||||
|
|
||||||
response.Push<u64>(parcel.WriteParcel(request.outputBuf.at(0)));
|
response.Push<u64>(parcel.WriteParcel(request.outputBuf.at(0)));
|
||||||
return {};
|
return {};
|
||||||
@ -38,10 +39,11 @@ namespace skyline::service::visrv {
|
|||||||
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 hosBinder = state.os->serviceManager.GetService<hosbinder::IHOSBinderDriver>("dispdrv");
|
auto producer = hosbinder::producer.lock();
|
||||||
if (hosBinder->layerStatus == hosbinder::LayerStatus::Uninitialized)
|
if (producer->layerStatus == hosbinder::LayerStatus::Uninitialized)
|
||||||
state.logger->Warn("The application is destroying an uninitialized layer");
|
state.logger->Warn("The application is destroying an uninitialized layer");
|
||||||
hosBinder->layerStatus = hosbinder::LayerStatus::Uninitialized;
|
producer->layerStatus = hosbinder::LayerStatus::Uninitialized;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
#include <os.h>
|
#include <os.h>
|
||||||
#include <services/hosbinder/IHOSBinderDriver.h>
|
#include <services/hosbinder/GraphicBufferProducer.h>
|
||||||
#include <services/hosbinder/display.h>
|
#include <services/hosbinder/display.h>
|
||||||
#include "IManagerDisplayService.h"
|
#include "IManagerDisplayService.h"
|
||||||
|
|
||||||
@ -19,10 +19,10 @@ namespace skyline::service::visrv {
|
|||||||
auto displayId = request.Pop<u64>();
|
auto displayId = request.Pop<u64>();
|
||||||
state.logger->Debug("Creating Managed Layer on Display: {}", displayId);
|
state.logger->Debug("Creating Managed Layer on Display: {}", displayId);
|
||||||
|
|
||||||
auto hosBinder = state.os->serviceManager.GetService<hosbinder::IHOSBinderDriver>("dispdrv");
|
auto producer = hosbinder::producer.lock();
|
||||||
if (hosBinder->layerStatus != hosbinder::LayerStatus::Uninitialized)
|
if (producer->layerStatus != hosbinder::LayerStatus::Uninitialized)
|
||||||
throw exception("The application is creating more than one layer");
|
throw exception("The application is creating more than one layer");
|
||||||
hosBinder->layerStatus = hosbinder::LayerStatus::Managed;
|
producer->layerStatus = hosbinder::LayerStatus::Managed;
|
||||||
|
|
||||||
response.Push<u64>(0); // There's only one layer
|
response.Push<u64>(0); // There's only one layer
|
||||||
return {};
|
return {};
|
||||||
@ -32,11 +32,10 @@ namespace skyline::service::visrv {
|
|||||||
auto layerId = request.Pop<u64>();
|
auto layerId = request.Pop<u64>();
|
||||||
state.logger->Debug("Destroying Managed Layer: {}", layerId);
|
state.logger->Debug("Destroying Managed Layer: {}", layerId);
|
||||||
|
|
||||||
auto hosBinder = state.os->serviceManager.GetService<hosbinder::IHOSBinderDriver>("dispdrv");
|
auto producer = hosbinder::producer.lock();
|
||||||
if (hosBinder->layerStatus == hosbinder::LayerStatus::Uninitialized)
|
if (producer->layerStatus == hosbinder::LayerStatus::Uninitialized)
|
||||||
state.logger->Warn("The application is destroying an uninitialized layer");
|
state.logger->Warn("The application is destroying an uninitialized layer");
|
||||||
|
producer->layerStatus = hosbinder::LayerStatus::Uninitialized;
|
||||||
hosBinder->layerStatus = hosbinder::LayerStatus::Uninitialized;
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ class AppDialog : BottomSheetDialogFragment() {
|
|||||||
override fun onCreate(savedInstanceState : Bundle?) {
|
override fun onCreate(savedInstanceState : Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
item = arguments!!.getSerializable("item") as AppItem
|
item = requireArguments().getSerializable("item") as AppItem
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user