hle: vi: Integrate new NVFlinger and HosBinderDriverServer service.

merge-requests/60/head
bunnei 2021-11-11 19:15:51 +07:00
parent a87812c6a1
commit 7f4165fc05
17 changed files with 286 additions and 723 deletions

@ -1,6 +1,5 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright 2021 yuzu Emulator Project
#include <algorithm>
#include <optional>
@ -16,8 +15,11 @@
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
#include "core/hle/service/nvflinger/buffer_item_consumer.h"
#include "core/hle/service/nvflinger/buffer_queue_core.h"
#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
#include "core/hle/service/nvflinger/nvflinger.h"
#include "core/hle/service/nvflinger/ui/graphic_buffer.h"
#include "core/hle/service/vi/display/vi_display.h"
#include "core/hle/service/vi/layer/vi_layer.h"
#include "video_core/gpu.h"
@ -53,13 +55,14 @@ void NVFlinger::SplitVSync(std::stop_token stop_token) {
}
}
NVFlinger::NVFlinger(Core::System& system_)
: system(system_), service_context(system_, "nvflinger") {
displays.emplace_back(0, "Default", service_context, system);
displays.emplace_back(1, "External", service_context, system);
displays.emplace_back(2, "Edid", service_context, system);
displays.emplace_back(3, "Internal", service_context, system);
displays.emplace_back(4, "Null", service_context, system);
NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_)
: system(system_), service_context(system_, "nvflinger"),
hos_binder_driver_server(hos_binder_driver_server_) {
displays.emplace_back(0, "Default", hos_binder_driver_server, service_context, system);
displays.emplace_back(1, "External", hos_binder_driver_server, service_context, system);
displays.emplace_back(2, "Edid", hos_binder_driver_server, service_context, system);
displays.emplace_back(3, "Internal", hos_binder_driver_server, service_context, system);
displays.emplace_back(4, "Null", hos_binder_driver_server, service_context, system);
guard = std::make_shared<std::mutex>();
// Schedule the screen composition events
@ -83,12 +86,15 @@ NVFlinger::NVFlinger(Core::System& system_)
}
NVFlinger::~NVFlinger() {
for (auto& buffer_queue : buffer_queues) {
buffer_queue->Disconnect();
}
if (!system.IsMulticore()) {
system.CoreTiming().UnscheduleEvent(composition_event, 0);
}
for (auto& display : displays) {
for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
display.GetLayer(layer).Core().NotifyShutdown();
}
}
}
void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
@ -125,10 +131,8 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
}
void NVFlinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
const u32 buffer_queue_id = next_buffer_queue_id++;
buffer_queues.emplace_back(
std::make_unique<BufferQueue>(system.Kernel(), buffer_queue_id, layer_id, service_context));
display.CreateLayer(layer_id, *buffer_queues.back());
const auto buffer_id = next_buffer_queue_id++;
display.CreateLayer(layer_id, buffer_id);
}
void NVFlinger::CloseLayer(u64 layer_id) {
@ -147,7 +151,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
return std::nullopt;
}
return layer->GetBufferQueue().GetId();
return layer->GetBinderId();
}
Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) {
@ -161,18 +165,6 @@ Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) {
return &display->GetVSyncEvent();
}
BufferQueue* NVFlinger::FindBufferQueue(u32 id) {
const auto lock_guard = Lock();
const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
[id](const auto& queue) { return queue->GetId() == id; });
if (itr == buffer_queues.end()) {
return nullptr;
}
return itr->get();
}
VI::Display* NVFlinger::FindDisplay(u64 display_id) {
const auto itr =
std::find_if(displays.begin(), displays.end(),
@ -246,23 +238,22 @@ void NVFlinger::Compose() {
// TODO(Subv): Support more than 1 layer.
VI::Layer& layer = display.GetLayer(0);
auto& buffer_queue = layer.GetBufferQueue();
// Search for a queued buffer and acquire it
auto buffer = buffer_queue.AcquireBuffer();
android::BufferItem buffer{};
const auto status = layer.GetConsumer().AcquireBuffer(&buffer, 0, false);
if (!buffer) {
if (status != android::Status::NoError) {
continue;
}
const auto& igbp_buffer = buffer->get().igbp_buffer;
const auto& igbp_buffer = *buffer.graphic_buffer;
if (!system.IsPoweredOn()) {
return; // We are likely shutting down
}
auto& gpu = system.GPU();
const auto& multi_fence = buffer->get().multi_fence;
const auto& multi_fence = buffer.fence;
guard->unlock();
for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) {
const auto& fence = multi_fence.fences[fence_id];
@ -278,12 +269,18 @@ void NVFlinger::Compose() {
auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0");
ASSERT(nvdisp);
nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.external_format,
igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride,
buffer->get().transform, buffer->get().crop_rect);
Common::Rectangle<int> crop_rect{
static_cast<int>(buffer.crop.Left()), static_cast<int>(buffer.crop.Top()),
static_cast<int>(buffer.crop.Right()), static_cast<int>(buffer.crop.Bottom())};
swap_interval = buffer->get().swap_interval;
buffer_queue.ReleaseBuffer(buffer->get().slot);
nvdisp->flip(igbp_buffer.BufferId(), igbp_buffer.Offset(), igbp_buffer.ExternalFormat(),
igbp_buffer.Width(), igbp_buffer.Height(), igbp_buffer.Stride(),
static_cast<android::BufferTransformFlags>(buffer.transform), crop_rect);
swap_interval = buffer.swap_interval;
auto fence = android::Fence::NoFence();
layer.GetConsumer().ReleaseBuffer(buffer, fence);
}
}

@ -1,6 +1,5 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright 2021 yuzu Emulator Project
#pragma once
@ -9,6 +8,7 @@
#include <mutex>
#include <optional>
#include <thread>
#include <unordered_map>
#include <vector>
#include "common/common_types.h"
@ -37,13 +37,16 @@ class Display;
class Layer;
} // namespace Service::VI
namespace Service::NVFlinger {
namespace android {
class BufferQueueCore;
class BufferQueueProducer;
} // namespace android
class BufferQueue;
namespace Service::NVFlinger {
class NVFlinger final {
public:
explicit NVFlinger(Core::System& system_);
explicit NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
~NVFlinger();
/// Sets the NVDrv module instance to use to send buffers to the GPU.
@ -72,15 +75,18 @@ public:
/// If an invalid display ID is provided, then nullptr is returned.
[[nodiscard]] Kernel::KReadableEvent* FindVsyncEvent(u64 display_id);
/// Obtains a buffer queue identified by the ID.
[[nodiscard]] BufferQueue* FindBufferQueue(u32 id);
/// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
/// finished.
void Compose();
[[nodiscard]] s64 GetNextTicks() const;
private:
struct Layer {
std::unique_ptr<android::BufferQueueCore> core;
std::unique_ptr<android::BufferQueueProducer> producer;
};
private:
[[nodiscard]] std::unique_lock<std::mutex> Lock() const {
return std::unique_lock{*guard};
@ -111,7 +117,6 @@ private:
std::shared_ptr<Nvidia::Module> nvdrv;
std::list<VI::Display> displays;
std::vector<std::unique_ptr<BufferQueue>> buffer_queues;
/// Id to use for the next layer that is created, this counter is shared among all displays.
u64 next_layer_id = 1;
@ -131,6 +136,8 @@ private:
std::jthread vsync_thread;
KernelHelpers::ServiceContext service_context;
HosBinderDriverServer& hos_binder_driver_server;
};
} // namespace Service::NVFlinger

@ -49,6 +49,7 @@
#include "core/hle/service/npns/npns.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
#include "core/hle/service/nvflinger/nvflinger.h"
#include "core/hle/service/olsc/olsc.h"
#include "core/hle/service/pcie/pcie.h"
@ -230,7 +231,8 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& sessi
/// Initialize Services
Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system)
: nv_flinger{std::make_unique<NVFlinger::NVFlinger>(system)} {
: hos_binder_driver_server{std::make_unique<NVFlinger::HosBinderDriverServer>(system)},
nv_flinger{std::make_unique<NVFlinger::NVFlinger>(system, *hos_binder_driver_server)} {
// NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
// here and pass it into the respective InstallInterfaces functions.
@ -290,7 +292,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
SSL::InstallInterfaces(*sm, system);
Time::InstallInterfaces(system);
USB::InstallInterfaces(*sm, system);
VI::InstallInterfaces(*sm, system, *nv_flinger);
VI::InstallInterfaces(*sm, system, *nv_flinger, *hos_binder_driver_server);
WLAN::InstallInterfaces(*sm, system);
}

@ -33,8 +33,9 @@ class FileSystemController;
}
namespace NVFlinger {
class HosBinderDriverServer;
class NVFlinger;
}
} // namespace NVFlinger
namespace SM {
class ServiceManager;
@ -236,6 +237,7 @@ public:
~Services();
private:
std::unique_ptr<NVFlinger::HosBinderDriverServer> hos_binder_driver_server;
std::unique_ptr<NVFlinger::NVFlinger> nv_flinger;
};

@ -13,14 +13,34 @@
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_writable_event.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nvflinger/buffer_item_consumer.h"
#include "core/hle/service/nvflinger/buffer_queue_consumer.h"
#include "core/hle/service/nvflinger/buffer_queue_core.h"
#include "core/hle/service/nvflinger/buffer_queue_producer.h"
#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
#include "core/hle/service/vi/display/vi_display.h"
#include "core/hle/service/vi/layer/vi_layer.h"
namespace Service::VI {
Display::Display(u64 id, std::string name_, KernelHelpers::ServiceContext& service_context_,
Core::System& system_)
: display_id{id}, name{std::move(name_)}, service_context{service_context_} {
struct BufferQueue {
std::shared_ptr<android::BufferQueueCore> core;
std::unique_ptr<android::BufferQueueProducer> producer;
std::unique_ptr<android::BufferQueueConsumer> consumer;
};
static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_context) {
auto buffer_queue_core = std::make_shared<android::BufferQueueCore>();
return {buffer_queue_core,
std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core),
std::make_unique<android::BufferQueueConsumer>(buffer_queue_core)};
}
Display::Display(u64 id, std::string name_,
NVFlinger::HosBinderDriverServer& hos_binder_driver_server_,
KernelHelpers::ServiceContext& service_context_, Core::System& system_)
: display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_},
service_context{service_context_} {
vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id));
}
@ -44,21 +64,29 @@ void Display::SignalVSyncEvent() {
vsync_event->GetWritableEvent().Signal();
}
void Display::CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue) {
// TODO(Subv): Support more than 1 layer.
void Display::CreateLayer(u64 layer_id, u32 binder_id) {
ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment");
layers.emplace_back(std::make_shared<Layer>(layer_id, buffer_queue));
auto [core, producer, consumer] = CreateBufferQueue(service_context);
auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(consumer));
buffer_item_consumer->Connect(false);
layers.emplace_back(std::make_unique<Layer>(layer_id, binder_id, *core, *producer,
std::move(buffer_item_consumer)));
hos_binder_driver_server.RegisterProducer(std::move(producer));
}
void Display::CloseLayer(u64 layer_id) {
std::erase_if(layers, [layer_id](const auto& layer) { return layer->GetID() == layer_id; });
std::erase_if(layers,
[layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; });
}
Layer* Display::FindLayer(u64 layer_id) {
const auto itr =
std::find_if(layers.begin(), layers.end(), [layer_id](const std::shared_ptr<Layer>& layer) {
return layer->GetID() == layer_id;
std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {
return layer->GetLayerId() == layer_id;
});
if (itr == layers.end()) {
@ -70,8 +98,8 @@ Layer* Display::FindLayer(u64 layer_id) {
const Layer* Display::FindLayer(u64 layer_id) const {
const auto itr =
std::find_if(layers.begin(), layers.end(), [layer_id](const std::shared_ptr<Layer>& layer) {
return layer->GetID() == layer_id;
std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {
return layer->GetLayerId() == layer_id;
});
if (itr == layers.end()) {

@ -15,12 +15,17 @@ namespace Kernel {
class KEvent;
}
namespace Service::NVFlinger {
class BufferQueue;
namespace android {
class BufferQueueProducer;
}
namespace Service::KernelHelpers {
class ServiceContext;
} // namespace Service::KernelHelpers
}
namespace Service::NVFlinger {
class HosBinderDriverServer;
}
namespace Service::VI {
@ -35,12 +40,13 @@ public:
/// Constructs a display with a given unique ID and name.
///
/// @param id The unique ID for this display.
/// @param hos_binder_driver_server_ NVFlinger HOSBinderDriver server instance.
/// @param service_context_ The ServiceContext for the owning service.
/// @param name_ The name for this display.
/// @param system_ The global system instance.
///
Display(u64 id, std::string name_, KernelHelpers::ServiceContext& service_context_,
Core::System& system_);
Display(u64 id, std::string name_, NVFlinger::HosBinderDriverServer& hos_binder_driver_server_,
KernelHelpers::ServiceContext& service_context_, Core::System& system_);
~Display();
/// Gets the unique ID assigned to this display.
@ -64,6 +70,10 @@ public:
/// Gets a layer for this display based off an index.
const Layer& GetLayer(std::size_t index) const;
std::size_t GetNumLayers() const {
return layers.size();
}
/// Gets the readable vsync event.
Kernel::KReadableEvent& GetVSyncEvent();
@ -72,10 +82,10 @@ public:
/// Creates and adds a layer to this display with the given ID.
///
/// @param layer_id The ID to assign to the created layer.
/// @param buffer_queue The buffer queue for the layer instance to use.
/// @param layer_id The ID to assign to the created layer.
/// @param binder_id The ID assigned to the buffer queue.
///
void CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue);
void CreateLayer(u64 layer_id, u32 binder_id);
/// Closes and removes a layer from this display with the given ID.
///
@ -104,9 +114,10 @@ public:
private:
u64 display_id;
std::string name;
NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
KernelHelpers::ServiceContext& service_context;
std::vector<std::shared_ptr<Layer>> layers;
std::vector<std::unique_ptr<Layer>> layers;
Kernel::KEvent* vsync_event{};
};

@ -6,7 +6,11 @@
namespace Service::VI {
Layer::Layer(u64 id, NVFlinger::BufferQueue& queue) : layer_id{id}, buffer_queue{queue} {}
Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
android::BufferQueueProducer& binder_,
std::shared_ptr<android::BufferItemConsumer>&& consumer_)
: layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move(
consumer_)} {}
Layer::~Layer() = default;

@ -4,11 +4,15 @@
#pragma once
#include <memory>
#include "common/common_types.h"
namespace Service::NVFlinger {
class BufferQueue;
}
namespace android {
class BufferItemConsumer;
class BufferQueueCore;
class BufferQueueProducer;
} // namespace android
namespace Service::VI {
@ -17,10 +21,13 @@ class Layer {
public:
/// Constructs a layer with a given ID and buffer queue.
///
/// @param id The ID to assign to this layer.
/// @param queue The buffer queue for this layer to use.
/// @param layer_id_ The ID to assign to this layer.
/// @param binder_id_ The binder ID to assign to this layer.
/// @param binder_ The buffer producer queue for this layer to use.
///
Layer(u64 id, NVFlinger::BufferQueue& queue);
Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
android::BufferQueueProducer& binder_,
std::shared_ptr<android::BufferItemConsumer>&& consumer_);
~Layer();
Layer(const Layer&) = delete;
@ -30,23 +37,47 @@ public:
Layer& operator=(Layer&&) = delete;
/// Gets the ID for this layer.
u64 GetID() const {
u64 GetLayerId() const {
return layer_id;
}
/// Gets the binder ID for this layer.
u32 GetBinderId() const {
return binder_id;
}
/// Gets a reference to the buffer queue this layer is using.
NVFlinger::BufferQueue& GetBufferQueue() {
return buffer_queue;
android::BufferQueueProducer& GetBufferQueue() {
return binder;
}
/// Gets a const reference to the buffer queue this layer is using.
const NVFlinger::BufferQueue& GetBufferQueue() const {
return buffer_queue;
const android::BufferQueueProducer& GetBufferQueue() const {
return binder;
}
android::BufferItemConsumer& GetConsumer() {
return *consumer;
}
const android::BufferItemConsumer& GetConsumer() const {
return *consumer;
}
android::BufferQueueCore& Core() {
return core;
}
const android::BufferQueueCore& Core() const {
return core;
}
private:
u64 layer_id;
NVFlinger::BufferQueue& buffer_queue;
const u64 layer_id;
const u32 binder_id;
android::BufferQueueCore& core;
android::BufferQueueProducer& binder;
std::shared_ptr<android::BufferItemConsumer> consumer;
};
} // namespace Service::VI

@ -22,8 +22,11 @@
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/service/nvdrv/nvdata.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
#include "core/hle/service/nvflinger/binder.h"
#include "core/hle/service/nvflinger/buffer_queue_producer.h"
#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
#include "core/hle/service/nvflinger/nvflinger.h"
#include "core/hle/service/nvflinger/parcel.h"
#include "core/hle/service/service.h"
#include "core/hle/service/vi/vi.h"
#include "core/hle/service/vi/vi_m.h"
@ -57,447 +60,24 @@ struct DisplayInfo {
};
static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
class Parcel {
class NativeWindow final {
public:
// This default size was chosen arbitrarily.
static constexpr std::size_t DefaultBufferSize = 0x40;
Parcel() : buffer(DefaultBufferSize) {}
explicit Parcel(std::vector<u8> data) : buffer(std::move(data)) {}
virtual ~Parcel() = default;
template <typename T>
T Read() {
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
ASSERT(read_index + sizeof(T) <= buffer.size());
T val;
std::memcpy(&val, buffer.data() + read_index, sizeof(T));
read_index += sizeof(T);
read_index = Common::AlignUp(read_index, 4);
return val;
}
template <typename T>
T ReadUnaligned() {
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
ASSERT(read_index + sizeof(T) <= buffer.size());
T val;
std::memcpy(&val, buffer.data() + read_index, sizeof(T));
read_index += sizeof(T);
return val;
}
std::vector<u8> ReadBlock(std::size_t length) {
ASSERT(read_index + length <= buffer.size());
const u8* const begin = buffer.data() + read_index;
const u8* const end = begin + length;
std::vector<u8> data(begin, end);
read_index += length;
read_index = Common::AlignUp(read_index, 4);
return data;
}
std::u16string ReadInterfaceToken() {
[[maybe_unused]] const u32 unknown = Read<u32_le>();
const u32 length = Read<u32_le>();
std::u16string token{};
for (u32 ch = 0; ch < length + 1; ++ch) {
token.push_back(ReadUnaligned<u16_le>());
}
read_index = Common::AlignUp(read_index, 4);
return token;
}
template <typename T>
void Write(const T& val) {
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
if (buffer.size() < write_index + sizeof(T)) {
buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize);
}
std::memcpy(buffer.data() + write_index, &val, sizeof(T));
write_index += sizeof(T);
write_index = Common::AlignUp(write_index, 4);
}
template <typename T>
void WriteObject(const T& val) {
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
const u32_le size = static_cast<u32>(sizeof(val));
Write(size);
// TODO(Subv): Support file descriptors.
Write<u32_le>(0); // Fd count.
Write(val);
}
void Deserialize() {
ASSERT(buffer.size() > sizeof(Header));
Header header{};
std::memcpy(&header, buffer.data(), sizeof(Header));
read_index = header.data_offset;
DeserializeData();
}
std::vector<u8> Serialize() {
ASSERT(read_index == 0);
write_index = sizeof(Header);
SerializeData();
Header header{};
header.data_size = static_cast<u32_le>(write_index - sizeof(Header));
header.data_offset = sizeof(Header);
header.objects_size = 4;
header.objects_offset = static_cast<u32>(sizeof(Header) + header.data_size);
std::memcpy(buffer.data(), &header, sizeof(Header));
return buffer;
}
protected:
virtual void SerializeData() {}
virtual void DeserializeData() {}
constexpr explicit NativeWindow(u32 id_) : id{id_} {}
private:
struct Header {
u32_le data_size;
u32_le data_offset;
u32_le objects_size;
u32_le objects_offset;
};
static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size");
std::vector<u8> buffer;
std::size_t read_index = 0;
std::size_t write_index = 0;
};
class NativeWindow : public Parcel {
public:
explicit NativeWindow(u32 id) {
data.id = id;
}
~NativeWindow() override = default;
protected:
void SerializeData() override {
Write(data);
}
private:
struct Data {
u32_le magic = 2;
u32_le process_id = 1;
u32_le id;
INSERT_PADDING_WORDS(3);
std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
INSERT_PADDING_WORDS(2);
};
static_assert(sizeof(Data) == 0x28, "ParcelData has wrong size");
Data data{};
};
class IGBPConnectRequestParcel : public Parcel {
public:
explicit IGBPConnectRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
Deserialize();
}
void DeserializeData() override {
[[maybe_unused]] const std::u16string token = ReadInterfaceToken();
data = Read<Data>();
}
struct Data {
u32_le unk;
u32_le api;
u32_le producer_controlled_by_app;
};
Data data;
};
class IGBPConnectResponseParcel : public Parcel {
public:
explicit IGBPConnectResponseParcel(u32 width, u32 height) {
data.width = width;
data.height = height;
}
~IGBPConnectResponseParcel() override = default;
protected:
void SerializeData() override {
Write(data);
}
private:
struct Data {
u32_le width;
u32_le height;
u32_le transform_hint;
u32_le num_pending_buffers;
u32_le status;
};
static_assert(sizeof(Data) == 20, "ParcelData has wrong size");
Data data{};
};
/// Represents a parcel containing one int '0' as its data
/// Used by DetachBuffer and Disconnect
class IGBPEmptyResponseParcel : public Parcel {
protected:
void SerializeData() override {
Write(data);
}
private:
struct Data {
u32_le unk_0{};
};
Data data{};
};
class IGBPSetPreallocatedBufferRequestParcel : public Parcel {
public:
explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer_)
: Parcel(std::move(buffer_)) {
Deserialize();
}
void DeserializeData() override {
[[maybe_unused]] const std::u16string token = ReadInterfaceToken();
data = Read<Data>();
if (data.contains_object != 0) {
buffer_container = Read<BufferContainer>();
}
}
struct Data {
u32_le slot;
u32_le contains_object;
};
struct BufferContainer {
u32_le graphic_buffer_length;
INSERT_PADDING_WORDS(1);
NVFlinger::IGBPBuffer buffer{};
};
Data data{};
BufferContainer buffer_container{};
};
class IGBPSetPreallocatedBufferResponseParcel : public Parcel {
protected:
void SerializeData() override {
// TODO(Subv): Find out what this means
Write<u32>(0);
}
};
class IGBPCancelBufferRequestParcel : public Parcel {
public:
explicit IGBPCancelBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
Deserialize();
}
void DeserializeData() override {
[[maybe_unused]] const std::u16string token = ReadInterfaceToken();
data = Read<Data>();
}
struct Data {
u32_le slot;
Service::Nvidia::MultiFence multi_fence;
};
Data data;
};
class IGBPCancelBufferResponseParcel : public Parcel {
protected:
void SerializeData() override {
Write<u32>(0); // Success
}
};
class IGBPDequeueBufferRequestParcel : public Parcel {
public:
explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
Deserialize();
}
void DeserializeData() override {
[[maybe_unused]] const std::u16string token = ReadInterfaceToken();
data = Read<Data>();
}
struct Data {
u32_le pixel_format;
u32_le width;
u32_le height;
u32_le get_frame_timestamps;
u32_le usage;
};
Data data;
};
class IGBPDequeueBufferResponseParcel : public Parcel {
public:
explicit IGBPDequeueBufferResponseParcel(u32 slot_, Nvidia::MultiFence& multi_fence_)
: slot(slot_), multi_fence(multi_fence_) {}
protected:
void SerializeData() override {
Write(slot);
Write<u32_le>(1);
WriteObject(multi_fence);
Write<u32_le>(0);
}
u32_le slot;
Service::Nvidia::MultiFence multi_fence;
};
class IGBPRequestBufferRequestParcel : public Parcel {
public:
explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
Deserialize();
}
void DeserializeData() override {
[[maybe_unused]] const std::u16string token = ReadInterfaceToken();
slot = Read<u32_le>();
}
u32_le slot;
};
class IGBPRequestBufferResponseParcel : public Parcel {
public:
explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer_) : buffer(buffer_) {}
~IGBPRequestBufferResponseParcel() override = default;
protected:
void SerializeData() override {
// TODO(Subv): Figure out what this value means, writing non-zero here will make libnx
// try to read an IGBPBuffer object from the parcel.
Write<u32_le>(1);
WriteObject(buffer);
Write<u32_le>(0);
}
NVFlinger::IGBPBuffer buffer;
};
class IGBPQueueBufferRequestParcel : public Parcel {
public:
explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
Deserialize();
}
void DeserializeData() override {
[[maybe_unused]] const std::u16string token = ReadInterfaceToken();
data = Read<Data>();
}
struct Data {
u32_le slot;
INSERT_PADDING_WORDS(3);
u32_le timestamp;
s32_le is_auto_timestamp;
s32_le crop_top;
s32_le crop_left;
s32_le crop_right;
s32_le crop_bottom;
s32_le scaling_mode;
NVFlinger::BufferQueue::BufferTransformFlags transform;
u32_le sticky_transform;
INSERT_PADDING_WORDS(1);
u32_le swap_interval;
Service::Nvidia::MultiFence multi_fence;
Common::Rectangle<int> GetCropRect() const {
return {crop_left, crop_top, crop_right, crop_bottom};
}
};
static_assert(sizeof(Data) == 96, "ParcelData has wrong size");
Data data;
};
class IGBPQueueBufferResponseParcel : public Parcel {
public:
explicit IGBPQueueBufferResponseParcel(u32 width, u32 height) {
data.width = width;
data.height = height;
}
~IGBPQueueBufferResponseParcel() override = default;
protected:
void SerializeData() override {
Write(data);
}
private:
struct Data {
u32_le width;
u32_le height;
u32_le transform_hint;
u32_le num_pending_buffers;
u32_le status;
};
static_assert(sizeof(Data) == 20, "ParcelData has wrong size");
Data data{};
};
class IGBPQueryRequestParcel : public Parcel {
public:
explicit IGBPQueryRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
Deserialize();
}
void DeserializeData() override {
[[maybe_unused]] const std::u16string token = ReadInterfaceToken();
type = Read<u32_le>();
}
u32 type;
};
class IGBPQueryResponseParcel : public Parcel {
public:
explicit IGBPQueryResponseParcel(u32 value_) : value{value_} {}
~IGBPQueryResponseParcel() override = default;
protected:
void SerializeData() override {
Write(value);
}
private:
u32_le value;
const u32 magic = 2;
const u32 process_id = 1;
const u32 id;
const INSERT_PADDING_WORDS(3);
const std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
const INSERT_PADDING_WORDS(2);
};
static_assert(sizeof(NativeWindow) == 0x28, "ParcelData has wrong size");
class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
public:
explicit IHOSBinderDriver(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_)
: ServiceFramework{system_, "IHOSBinderDriver"}, nv_flinger(nv_flinger_) {
explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_)
: ServiceFramework{system_, "IHOSBinderDriver"}, server(server_) {
static const FunctionInfo functions[] = {
{0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
{1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
@ -508,147 +88,16 @@ public:
}
private:
enum class TransactionId {
RequestBuffer = 1,
SetBufferCount = 2,
DequeueBuffer = 3,
DetachBuffer = 4,
DetachNextBuffer = 5,
AttachBuffer = 6,
QueueBuffer = 7,
CancelBuffer = 8,
Query = 9,
Connect = 10,
Disconnect = 11,
AllocateBuffers = 13,
SetPreallocatedBuffer = 14,
GetBufferHistory = 17
};
void TransactParcel(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 id = rp.Pop<u32>();
const auto transaction = static_cast<TransactionId>(rp.Pop<u32>());
const auto transaction = static_cast<android::TransactionId>(rp.Pop<u32>());
const u32 flags = rp.Pop<u32>();
LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
transaction, flags);
auto& buffer_queue = *nv_flinger.FindBufferQueue(id);
switch (transaction) {
case TransactionId::Connect: {
IGBPConnectRequestParcel request{ctx.ReadBuffer()};
IGBPConnectResponseParcel response{static_cast<u32>(DisplayResolution::UndockedWidth),
static_cast<u32>(DisplayResolution::UndockedHeight)};
buffer_queue.Connect();
ctx.WriteBuffer(response.Serialize());
break;
}
case TransactionId::SetPreallocatedBuffer: {
IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
buffer_queue.SetPreallocatedBuffer(request.data.slot, request.buffer_container.buffer);
IGBPSetPreallocatedBufferResponseParcel response{};
ctx.WriteBuffer(response.Serialize());
break;
}
case TransactionId::DequeueBuffer: {
IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
const u32 width{request.data.width};
const u32 height{request.data.height};
do {
if (auto result = buffer_queue.DequeueBuffer(width, height); result) {
// Buffer is available
IGBPDequeueBufferResponseParcel response{result->first, *result->second};
ctx.WriteBuffer(response.Serialize());
break;
}
} while (buffer_queue.IsConnected());
break;
}
case TransactionId::RequestBuffer: {
IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
auto& buffer = buffer_queue.RequestBuffer(request.slot);
IGBPRequestBufferResponseParcel response{buffer};
ctx.WriteBuffer(response.Serialize());
break;
}
case TransactionId::QueueBuffer: {
IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()};
buffer_queue.QueueBuffer(request.data.slot, request.data.transform,
request.data.GetCropRect(), request.data.swap_interval,
request.data.multi_fence);
IGBPQueueBufferResponseParcel response{1280, 720};
ctx.WriteBuffer(response.Serialize());
break;
}
case TransactionId::Query: {
IGBPQueryRequestParcel request{ctx.ReadBuffer()};
const u32 value =
buffer_queue.Query(static_cast<NVFlinger::BufferQueue::QueryType>(request.type));
IGBPQueryResponseParcel response{value};
ctx.WriteBuffer(response.Serialize());
break;
}
case TransactionId::CancelBuffer: {
IGBPCancelBufferRequestParcel request{ctx.ReadBuffer()};
buffer_queue.CancelBuffer(request.data.slot, request.data.multi_fence);
IGBPCancelBufferResponseParcel response{};
ctx.WriteBuffer(response.Serialize());
break;
}
case TransactionId::Disconnect: {
LOG_WARNING(Service_VI, "(STUBBED) called, transaction=Disconnect");
const auto buffer = ctx.ReadBuffer();
buffer_queue.Disconnect();
IGBPEmptyResponseParcel response{};
ctx.WriteBuffer(response.Serialize());
break;
}
case TransactionId::DetachBuffer: {
const auto buffer = ctx.ReadBuffer();
IGBPEmptyResponseParcel response{};
ctx.WriteBuffer(response.Serialize());
break;
}
case TransactionId::SetBufferCount: {
LOG_WARNING(Service_VI, "(STUBBED) called, transaction=SetBufferCount");
[[maybe_unused]] const auto buffer = ctx.ReadBuffer();
IGBPEmptyResponseParcel response{};
ctx.WriteBuffer(response.Serialize());
break;
}
case TransactionId::GetBufferHistory: {
LOG_WARNING(Service_VI, "(STUBBED) called, transaction=GetBufferHistory");
[[maybe_unused]] const auto buffer = ctx.ReadBuffer();
IGBPEmptyResponseParcel response{};
ctx.WriteBuffer(response.Serialize());
break;
}
default:
ASSERT_MSG(false, "Unimplemented");
}
server.TryGetProducer(id)->Transact(ctx, transaction, flags);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@ -674,13 +123,13 @@ private:
LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
// TODO(Subv): Find out what this actually is.
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(nv_flinger.FindBufferQueue(id)->GetBufferWaitEvent());
rb.PushCopyObjects(server.TryGetProducer(id)->GetNativeHandle());
}
NVFlinger::NVFlinger& nv_flinger;
private:
NVFlinger::HosBinderDriverServer& server;
};
class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
@ -937,7 +386,40 @@ private:
class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
public:
explicit IApplicationDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_);
IApplicationDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
: ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_},
hos_binder_driver_server{hos_binder_driver_server_} {
static const FunctionInfo functions[] = {
{100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},
{101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"},
{102, &IApplicationDisplayService::GetManagerDisplayService,
"GetManagerDisplayService"},
{103, &IApplicationDisplayService::GetIndirectDisplayTransactionService,
"GetIndirectDisplayTransactionService"},
{1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
{1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
{1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"},
{1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
{1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"},
{1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"},
{2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
{2021, &IApplicationDisplayService::CloseLayer, "CloseLayer"},
{2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"},
{2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
{2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
{2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"},
{2450, &IApplicationDisplayService::GetIndirectLayerImageMap,
"GetIndirectLayerImageMap"},
{2451, nullptr, "GetIndirectLayerImageCropMap"},
{2460, &IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo,
"GetIndirectLayerImageRequiredMemoryInfo"},
{5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"},
{5203, nullptr, "GetDisplayVsyncEventForDebug"},
};
RegisterHandlers(functions);
}
private:
enum class ConvertedScaleMode : u64 {
@ -961,7 +443,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IHOSBinderDriver>(system, nv_flinger);
rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server);
}
void GetSystemDisplayService(Kernel::HLERequestContext& ctx) {
@ -985,7 +467,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IHOSBinderDriver>(system, nv_flinger);
rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server);
}
void OpenDisplay(Kernel::HLERequestContext& ctx) {
@ -1089,7 +571,7 @@ private:
void ListDisplays(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_VI, "(STUBBED) called");
DisplayInfo display_info;
const DisplayInfo display_info;
ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
@ -1124,8 +606,8 @@ private:
return;
}
NativeWindow native_window{*buffer_queue_id};
const auto buffer_size = ctx.WriteBuffer(native_window.Serialize());
const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}};
const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
@ -1170,8 +652,8 @@ private:
return;
}
NativeWindow native_window{*buffer_queue_id};
const auto buffer_size = ctx.WriteBuffer(native_window.Serialize());
const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}};
const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
@ -1287,39 +769,9 @@ private:
}
NVFlinger::NVFlinger& nv_flinger;
NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
};
IApplicationDisplayService::IApplicationDisplayService(Core::System& system_,
NVFlinger::NVFlinger& nv_flinger_)
: ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_} {
static const FunctionInfo functions[] = {
{100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},
{101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"},
{102, &IApplicationDisplayService::GetManagerDisplayService, "GetManagerDisplayService"},
{103, &IApplicationDisplayService::GetIndirectDisplayTransactionService,
"GetIndirectDisplayTransactionService"},
{1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
{1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
{1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"},
{1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
{1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"},
{1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"},
{2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
{2021, &IApplicationDisplayService::CloseLayer, "CloseLayer"},
{2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"},
{2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
{2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
{2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"},
{2450, &IApplicationDisplayService::GetIndirectLayerImageMap, "GetIndirectLayerImageMap"},
{2451, nullptr, "GetIndirectLayerImageCropMap"},
{2460, &IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo,
"GetIndirectLayerImageRequiredMemoryInfo"},
{5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"},
{5203, nullptr, "GetDisplayVsyncEventForDebug"},
};
RegisterHandlers(functions);
}
static bool IsValidServiceAccess(Permission permission, Policy policy) {
if (permission == Permission::User) {
return policy == Policy::User;
@ -1333,7 +785,9 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {
}
void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system,
NVFlinger::NVFlinger& nv_flinger, Permission permission) {
NVFlinger::NVFlinger& nv_flinger,
NVFlinger::HosBinderDriverServer& hos_binder_driver_server,
Permission permission) {
IPC::RequestParser rp{ctx};
const auto policy = rp.PopEnum<Policy>();
@ -1346,14 +800,18 @@ void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System&
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger);
rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger, hos_binder_driver_server);
}
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system,
NVFlinger::NVFlinger& nv_flinger) {
std::make_shared<VI_M>(system, nv_flinger)->InstallAsService(service_manager);
std::make_shared<VI_S>(system, nv_flinger)->InstallAsService(service_manager);
std::make_shared<VI_U>(system, nv_flinger)->InstallAsService(service_manager);
NVFlinger::NVFlinger& nv_flinger,
NVFlinger::HosBinderDriverServer& hos_binder_driver_server) {
std::make_shared<VI_M>(system, nv_flinger, hos_binder_driver_server)
->InstallAsService(service_manager);
std::make_shared<VI_S>(system, nv_flinger, hos_binder_driver_server)
->InstallAsService(service_manager);
std::make_shared<VI_U>(system, nv_flinger, hos_binder_driver_server)
->InstallAsService(service_manager);
}
} // namespace Service::VI

@ -15,8 +15,9 @@ class HLERequestContext;
}
namespace Service::NVFlinger {
class HosBinderDriverServer;
class NVFlinger;
}
} // namespace Service::NVFlinger
namespace Service::SM {
class ServiceManager;
@ -47,11 +48,14 @@ enum class Policy {
namespace detail {
void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system,
NVFlinger::NVFlinger& nv_flinger, Permission permission);
NVFlinger::NVFlinger& nv_flinger,
NVFlinger::HosBinderDriverServer& hos_binder_driver_server,
Permission permission);
} // namespace detail
/// Registers all VI services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system,
NVFlinger::NVFlinger& nv_flinger);
NVFlinger::NVFlinger& nv_flinger,
NVFlinger::HosBinderDriverServer& hos_binder_driver_server);
} // namespace Service::VI

@ -8,8 +8,10 @@
namespace Service::VI {
VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_)
: ServiceFramework{system_, "vi:m"}, nv_flinger{nv_flinger_} {
VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
: ServiceFramework{system_, "vi:m"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
hos_binder_driver_server_} {
static const FunctionInfo functions[] = {
{2, &VI_M::GetDisplayService, "GetDisplayService"},
{3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@ -22,7 +24,8 @@ VI_M::~VI_M() = default;
void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_VI, "called");
detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::Manager);
detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
Permission::Manager);
}
} // namespace Service::VI

@ -15,20 +15,23 @@ class HLERequestContext;
}
namespace Service::NVFlinger {
class HosBinderDriverServer;
class NVFlinger;
}
} // namespace Service::NVFlinger
namespace Service::VI {
class VI_M final : public ServiceFramework<VI_M> {
public:
explicit VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_);
explicit VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
~VI_M() override;
private:
void GetDisplayService(Kernel::HLERequestContext& ctx);
NVFlinger::NVFlinger& nv_flinger;
NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
};
} // namespace Service::VI

@ -8,8 +8,10 @@
namespace Service::VI {
VI_S::VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_)
: ServiceFramework{system_, "vi:s"}, nv_flinger{nv_flinger_} {
VI_S::VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
: ServiceFramework{system_, "vi:s"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
hos_binder_driver_server_} {
static const FunctionInfo functions[] = {
{1, &VI_S::GetDisplayService, "GetDisplayService"},
{3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@ -22,7 +24,8 @@ VI_S::~VI_S() = default;
void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_VI, "called");
detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::System);
detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
Permission::System);
}
} // namespace Service::VI

@ -15,20 +15,23 @@ class HLERequestContext;
}
namespace Service::NVFlinger {
class HosBinderDriverServer;
class NVFlinger;
}
} // namespace Service::NVFlinger
namespace Service::VI {
class VI_S final : public ServiceFramework<VI_S> {
public:
explicit VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_);
explicit VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
~VI_S() override;
private:
void GetDisplayService(Kernel::HLERequestContext& ctx);
NVFlinger::NVFlinger& nv_flinger;
NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
};
} // namespace Service::VI

@ -8,8 +8,10 @@
namespace Service::VI {
VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_)
: ServiceFramework{system_, "vi:u"}, nv_flinger{nv_flinger_} {
VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
: ServiceFramework{system_, "vi:u"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
hos_binder_driver_server_} {
static const FunctionInfo functions[] = {
{0, &VI_U::GetDisplayService, "GetDisplayService"},
{1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@ -22,7 +24,8 @@ VI_U::~VI_U() = default;
void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_VI, "called");
detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::User);
detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
Permission::User);
}
} // namespace Service::VI

@ -15,20 +15,23 @@ class HLERequestContext;
}
namespace Service::NVFlinger {
class HosBinderDriverServer;
class NVFlinger;
}
} // namespace Service::NVFlinger
namespace Service::VI {
class VI_U final : public ServiceFramework<VI_U> {
public:
explicit VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_);
explicit VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
~VI_U() override;
private:
void GetDisplayService(Kernel::HLERequestContext& ctx);
NVFlinger::NVFlinger& nv_flinger;
NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
};
} // namespace Service::VI

@ -8,6 +8,7 @@
#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/hle/service/nvdrv/nvdata.h"
#include "video_core/cdma_pusher.h"
#include "video_core/framebuffer_config.h"