mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-04 23:35:12 +01:00
Make GraphicBufferProducer use the new nvmap API
This commit is contained in:
parent
c97f5a9315
commit
1149158198
@ -6,13 +6,18 @@
|
||||
#include <gpu.h>
|
||||
#include <gpu/texture/format.h>
|
||||
#include <soc.h>
|
||||
#include <services/nvdrv/driver.h>
|
||||
#include <services/nvdrv/devices/nvmap.h>
|
||||
#include <services/common/fence.h>
|
||||
#include "GraphicBufferProducer.h"
|
||||
|
||||
namespace skyline::service::hosbinder {
|
||||
GraphicBufferProducer::GraphicBufferProducer(const DeviceState &state) : state(state), bufferEvent(std::make_shared<kernel::type::KEvent>(state, true)) {}
|
||||
GraphicBufferProducer::GraphicBufferProducer(const DeviceState &state, nvdrv::core::NvMap &nvMap) : state(state), bufferEvent(std::make_shared<kernel::type::KEvent>(state, true)), nvMap(nvMap) {}
|
||||
|
||||
void GraphicBufferProducer::FreeGraphicBufferNvMap(GraphicBuffer &buffer) {
|
||||
auto surface{buffer.graphicHandle.surfaces.at(0)};
|
||||
u32 nvMapHandleId{surface.nvmapHandle ? surface.nvmapHandle : buffer.graphicHandle.nvmapId};
|
||||
nvMap.FreeHandle(nvMapHandleId, true);
|
||||
}
|
||||
|
||||
u32 GraphicBufferProducer::GetPendingBufferCount() {
|
||||
u32 count{};
|
||||
@ -64,6 +69,12 @@ namespace skyline::service::hosbinder {
|
||||
for (auto &slot : queue) {
|
||||
slot.state = BufferState::Free;
|
||||
slot.frameNumber = std::numeric_limits<u32>::max();
|
||||
|
||||
if (slot.texture) {
|
||||
slot.texture = {};
|
||||
FreeGraphicBufferNvMap(*slot.graphicBuffer);
|
||||
}
|
||||
|
||||
slot.graphicBuffer = nullptr;
|
||||
}
|
||||
} else if (preallocatedBufferCount < count) {
|
||||
@ -160,6 +171,12 @@ namespace skyline::service::hosbinder {
|
||||
|
||||
bufferSlot.state = BufferState::Free;
|
||||
bufferSlot.frameNumber = std::numeric_limits<u32>::max();
|
||||
|
||||
if (bufferSlot.texture) {
|
||||
bufferSlot.texture = {};
|
||||
FreeGraphicBufferNvMap(*bufferSlot.graphicBuffer);
|
||||
}
|
||||
|
||||
bufferSlot.graphicBuffer = nullptr;
|
||||
|
||||
bufferEvent->Signal();
|
||||
@ -183,6 +200,12 @@ namespace skyline::service::hosbinder {
|
||||
|
||||
bufferSlot->state = BufferState::Free;
|
||||
bufferSlot->frameNumber = std::numeric_limits<u32>::max();
|
||||
|
||||
if (bufferSlot->texture) {
|
||||
bufferSlot->texture = {};
|
||||
FreeGraphicBufferNvMap(*bufferSlot->graphicBuffer);
|
||||
}
|
||||
|
||||
graphicBuffer = *std::exchange(bufferSlot->graphicBuffer, nullptr);
|
||||
fence = AndroidFence{};
|
||||
|
||||
@ -202,6 +225,11 @@ namespace skyline::service::hosbinder {
|
||||
}
|
||||
}
|
||||
|
||||
if (bufferSlot->texture) {
|
||||
bufferSlot->texture = {};
|
||||
FreeGraphicBufferNvMap(*bufferSlot->graphicBuffer);
|
||||
}
|
||||
|
||||
if (bufferSlot == queue.end()) {
|
||||
state.logger->Warn("Could not find any free slots to attach the graphic buffer to");
|
||||
return AndroidStatus::NoMemory;
|
||||
@ -304,27 +332,13 @@ namespace skyline::service::hosbinder {
|
||||
if (surface.scanFormat != NvDisplayScanFormat::Progressive)
|
||||
throw exception("Non-Progressive surfaces are not supported: {}", ToString(surface.scanFormat));
|
||||
|
||||
std::shared_ptr<nvdrv::device::NvMap::NvMapObject> nvBuffer{};
|
||||
{
|
||||
auto driver{nvdrv::driver.lock()};
|
||||
auto nvmap{driver->nvMap.lock()};
|
||||
if (surface.nvmapHandle) {
|
||||
nvBuffer = nvmap->GetObject(surface.nvmapHandle);
|
||||
} else {
|
||||
std::shared_lock nvmapLock(nvmap->mapMutex);
|
||||
for (const auto &object : nvmap->maps) {
|
||||
if (object->id == handle.nvmapId) {
|
||||
nvBuffer = object;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!nvBuffer)
|
||||
throw exception("A QueueBuffer request has an invalid NvMap Handle ({}) and ID ({})", surface.nvmapHandle, handle.nvmapId);
|
||||
}
|
||||
}
|
||||
// Duplicate the handle so it can't be freed by the guest
|
||||
auto nvMapHandleObj{nvMap.GetHandle(surface.nvmapHandle ? surface.nvmapHandle : handle.nvmapId)};
|
||||
if (auto err{nvMapHandleObj->Duplicate(true)}; err != PosixResult::Success)
|
||||
throw exception("Failed to duplicate graphic buffer NvMap handle: {}!", static_cast<i32>(err));
|
||||
|
||||
if (surface.size > (nvBuffer->size - surface.offset))
|
||||
throw exception("Surface doesn't fit into NvMap mapping of size 0x{:X} when mapped at 0x{:X} -> 0x{:X}", nvBuffer->size, surface.offset, surface.offset + surface.size);
|
||||
if (surface.size > (nvMapHandleObj->origSize - surface.offset))
|
||||
throw exception("Surface doesn't fit into NvMap mapping of size 0x{:X} when mapped at 0x{:X} -> 0x{:X}", nvMapHandleObj->origSize, surface.offset, surface.offset + surface.size);
|
||||
|
||||
gpu::texture::TileMode tileMode;
|
||||
gpu::texture::TileConfig tileConfig{};
|
||||
@ -344,7 +358,7 @@ namespace skyline::service::hosbinder {
|
||||
throw exception("Legacy 16Bx16 tiled surfaces are not supported");
|
||||
}
|
||||
|
||||
auto guestTexture{std::make_shared<gpu::GuestTexture>(state, nvBuffer->ptr + surface.offset, gpu::texture::Dimensions(surface.width, surface.height), format, tileMode, tileConfig)};
|
||||
auto guestTexture{std::make_shared<gpu::GuestTexture>(state, nvMapHandleObj->GetPointer() + surface.offset, gpu::texture::Dimensions(surface.width, surface.height), format, tileMode, tileConfig)};
|
||||
buffer.texture = guestTexture->CreateTexture({}, vk::ImageTiling::eLinear);
|
||||
}
|
||||
|
||||
@ -529,6 +543,12 @@ namespace skyline::service::hosbinder {
|
||||
for (auto &slot : queue) {
|
||||
slot.state = BufferState::Free;
|
||||
slot.frameNumber = std::numeric_limits<u32>::max();
|
||||
|
||||
if (slot.texture) {
|
||||
slot.texture = {};
|
||||
FreeGraphicBufferNvMap(*slot.graphicBuffer);
|
||||
}
|
||||
|
||||
slot.graphicBuffer = nullptr;
|
||||
}
|
||||
|
||||
@ -544,12 +564,16 @@ namespace skyline::service::hosbinder {
|
||||
}
|
||||
|
||||
auto &buffer{queue[slot]};
|
||||
if (buffer.texture) {
|
||||
buffer.texture = {};
|
||||
FreeGraphicBufferNvMap(*buffer.graphicBuffer);
|
||||
}
|
||||
|
||||
buffer.state = BufferState::Free;
|
||||
buffer.frameNumber = 0;
|
||||
buffer.wasBufferRequested = false;
|
||||
buffer.isPreallocated = graphicBuffer != nullptr;
|
||||
buffer.graphicBuffer = graphicBuffer ? std::make_unique<GraphicBuffer>(*graphicBuffer) : nullptr;
|
||||
buffer.texture = {};
|
||||
|
||||
if (graphicBuffer) {
|
||||
if (graphicBuffer->magic != GraphicBuffer::Magic)
|
||||
|
@ -14,6 +14,10 @@ namespace skyline::gpu {
|
||||
class Texture;
|
||||
}
|
||||
|
||||
namespace skyline::service::nvdrv::core {
|
||||
class NvMap;
|
||||
}
|
||||
|
||||
namespace skyline::service::hosbinder {
|
||||
/**
|
||||
* @url https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferSlot.h;l=52-91
|
||||
@ -66,6 +70,9 @@ namespace skyline::service::hosbinder {
|
||||
AndroidPixelFormat defaultFormat{AndroidPixelFormat::RGBA8888}; //!< The assumed format of a buffer if none is supplied in DequeueBuffer
|
||||
NativeWindowApi connectedApi{NativeWindowApi::None}; //!< The API that the producer is currently connected to
|
||||
u64 frameNumber{}; //!< The amount of frames that have been presented so far
|
||||
nvdrv::core::NvMap &nvMap;
|
||||
|
||||
void FreeGraphicBufferNvMap(GraphicBuffer &buffer);
|
||||
|
||||
/**
|
||||
* @return The amount of buffers which have been queued onto the consumer
|
||||
@ -180,7 +187,7 @@ namespace skyline::service::hosbinder {
|
||||
SetPreallocatedBuffer = 14, //!< A transaction specific to HOS, see the implementation for a description of its functionality
|
||||
};
|
||||
|
||||
GraphicBufferProducer(const DeviceState &state);
|
||||
GraphicBufferProducer(const DeviceState &state, nvdrv::core::NvMap &nvmap);
|
||||
|
||||
/**
|
||||
* @brief The handler for Binder IPC transactions with IGraphicBufferProducer
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "GraphicBufferProducer.h"
|
||||
|
||||
namespace skyline::service::hosbinder {
|
||||
IHOSBinderDriver::IHOSBinderDriver(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {}
|
||||
IHOSBinderDriver::IHOSBinderDriver(const DeviceState &state, ServiceManager &manager, nvdrv::core::NvMap &nvMap) : BaseService(state, manager), nvMap(nvMap) {}
|
||||
|
||||
Result IHOSBinderDriver::TransactParcel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
// 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
|
||||
@ -122,7 +122,7 @@ namespace skyline::service::hosbinder {
|
||||
|
||||
layerStrongReferenceCount = InitialStrongReferenceCount;
|
||||
layerWeakReferenceCount = 0;
|
||||
layer.emplace(state);
|
||||
layer.emplace(state, nvMap);
|
||||
|
||||
return DefaultLayerId;
|
||||
}
|
||||
|
@ -42,8 +42,10 @@ namespace skyline::service::hosbinder {
|
||||
constexpr static u32 DefaultBinderLayerHandle{1}; //!< The handle as assigned by SurfaceFlinger of the default layer
|
||||
std::optional<GraphicBufferProducer> layer; //!< The IGraphicBufferProducer backing the layer (NativeWindow)
|
||||
|
||||
nvdrv::core::NvMap &nvMap;
|
||||
|
||||
public:
|
||||
IHOSBinderDriver(const DeviceState &state, ServiceManager &manager);
|
||||
IHOSBinderDriver(const DeviceState &state, ServiceManager &manager, nvdrv::core::NvMap &nvMap);
|
||||
|
||||
/**
|
||||
* @brief Emulates the transaction of parcels between a IGraphicBufferProducer and the application
|
||||
|
Loading…
Reference in New Issue
Block a user