hle: vi: Integrate new NVFlinger and HosBinderDriverServer service.

This commit is contained in:
bunnei 2021-11-11 19:15:51 -08:00
parent a87812c6a1
commit 7f4165fc05
17 changed files with 286 additions and 723 deletions

View file

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

View file

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

View file

@ -49,6 +49,7 @@
#include "core/hle/service/npns/npns.h" #include "core/hle/service/npns/npns.h"
#include "core/hle/service/ns/ns.h" #include "core/hle/service/ns/ns.h"
#include "core/hle/service/nvdrv/nvdrv.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/nvflinger/nvflinger.h"
#include "core/hle/service/olsc/olsc.h" #include "core/hle/service/olsc/olsc.h"
#include "core/hle/service/pcie/pcie.h" #include "core/hle/service/pcie/pcie.h"
@ -230,7 +231,8 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& sessi
/// Initialize Services /// Initialize Services
Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) 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 // 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. // 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); SSL::InstallInterfaces(*sm, system);
Time::InstallInterfaces(system); Time::InstallInterfaces(system);
USB::InstallInterfaces(*sm, 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); WLAN::InstallInterfaces(*sm, system);
} }

View file

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

View file

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

View file

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

View file

@ -6,7 +6,11 @@
namespace Service::VI { 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; Layer::~Layer() = default;

View file

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

View file

@ -22,8 +22,11 @@
#include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread.h"
#include "core/hle/service/nvdrv/nvdata.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/nvflinger.h"
#include "core/hle/service/nvflinger/parcel.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi.h"
#include "core/hle/service/vi/vi_m.h" #include "core/hle/service/vi/vi_m.h"
@ -57,447 +60,24 @@ struct DisplayInfo {
}; };
static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size"); static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
class Parcel { class NativeWindow final {
public: public:
// This default size was chosen arbitrarily. constexpr explicit NativeWindow(u32 id_) : id{id_} {}
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() {}
private: private:
struct Header { const u32 magic = 2;
u32_le data_size; const u32 process_id = 1;
u32_le data_offset; const u32 id;
u32_le objects_size; const INSERT_PADDING_WORDS(3);
u32_le objects_offset; const std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
}; const INSERT_PADDING_WORDS(2);
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;
}; };
static_assert(sizeof(NativeWindow) == 0x28, "ParcelData has wrong size");
class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
public: public:
explicit IHOSBinderDriver(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_)
: ServiceFramework{system_, "IHOSBinderDriver"}, nv_flinger(nv_flinger_) { : ServiceFramework{system_, "IHOSBinderDriver"}, server(server_) {
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
{1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
@ -508,147 +88,16 @@ public:
} }
private: 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) { void TransactParcel(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const u32 id = rp.Pop<u32>(); 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>(); const u32 flags = rp.Pop<u32>();
LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id, LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
transaction, flags); transaction, flags);
auto& buffer_queue = *nv_flinger.FindBufferQueue(id); server.TryGetProducer(id)->Transact(ctx, transaction, flags);
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");
}
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
@ -674,13 +123,13 @@ private:
LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); 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}; IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess); 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> { class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
@ -937,7 +386,40 @@ private:
class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
public: 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: private:
enum class ConvertedScaleMode : u64 { enum class ConvertedScaleMode : u64 {
@ -961,7 +443,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.PushIpcInterface<IHOSBinderDriver>(system, nv_flinger); rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server);
} }
void GetSystemDisplayService(Kernel::HLERequestContext& ctx) { void GetSystemDisplayService(Kernel::HLERequestContext& ctx) {
@ -985,7 +467,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.PushIpcInterface<IHOSBinderDriver>(system, nv_flinger); rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server);
} }
void OpenDisplay(Kernel::HLERequestContext& ctx) { void OpenDisplay(Kernel::HLERequestContext& ctx) {
@ -1089,7 +571,7 @@ private:
void ListDisplays(Kernel::HLERequestContext& ctx) { void ListDisplays(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_VI, "(STUBBED) called"); LOG_WARNING(Service_VI, "(STUBBED) called");
DisplayInfo display_info; const DisplayInfo display_info;
ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
@ -1124,8 +606,8 @@ private:
return; return;
} }
NativeWindow native_window{*buffer_queue_id}; const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}};
const auto buffer_size = ctx.WriteBuffer(native_window.Serialize()); const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
@ -1170,8 +652,8 @@ private:
return; return;
} }
NativeWindow native_window{*buffer_queue_id}; const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}};
const auto buffer_size = ctx.WriteBuffer(native_window.Serialize()); const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
IPC::ResponseBuilder rb{ctx, 6}; IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
@ -1287,39 +769,9 @@ private:
} }
NVFlinger::NVFlinger& nv_flinger; 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) { static bool IsValidServiceAccess(Permission permission, Policy policy) {
if (permission == Permission::User) { if (permission == Permission::User) {
return policy == Policy::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, 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}; IPC::RequestParser rp{ctx};
const auto policy = rp.PopEnum<Policy>(); 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}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess); 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, void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system,
NVFlinger::NVFlinger& nv_flinger) { NVFlinger::NVFlinger& nv_flinger,
std::make_shared<VI_M>(system, nv_flinger)->InstallAsService(service_manager); NVFlinger::HosBinderDriverServer& hos_binder_driver_server) {
std::make_shared<VI_S>(system, nv_flinger)->InstallAsService(service_manager); std::make_shared<VI_M>(system, nv_flinger, hos_binder_driver_server)
std::make_shared<VI_U>(system, nv_flinger)->InstallAsService(service_manager); ->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 } // namespace Service::VI

View file

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

View file

@ -8,8 +8,10 @@
namespace Service::VI { namespace Service::VI {
VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
: ServiceFramework{system_, "vi:m"}, nv_flinger{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[] = { static const FunctionInfo functions[] = {
{2, &VI_M::GetDisplayService, "GetDisplayService"}, {2, &VI_M::GetDisplayService, "GetDisplayService"},
{3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@ -22,7 +24,8 @@ VI_M::~VI_M() = default;
void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) { void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_VI, "called"); 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 } // namespace Service::VI

View file

@ -15,20 +15,23 @@ class HLERequestContext;
} }
namespace Service::NVFlinger { namespace Service::NVFlinger {
class HosBinderDriverServer;
class NVFlinger; class NVFlinger;
} } // namespace Service::NVFlinger
namespace Service::VI { namespace Service::VI {
class VI_M final : public ServiceFramework<VI_M> { class VI_M final : public ServiceFramework<VI_M> {
public: 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; ~VI_M() override;
private: private:
void GetDisplayService(Kernel::HLERequestContext& ctx); void GetDisplayService(Kernel::HLERequestContext& ctx);
NVFlinger::NVFlinger& nv_flinger; NVFlinger::NVFlinger& nv_flinger;
NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
}; };
} // namespace Service::VI } // namespace Service::VI

View file

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

View file

@ -15,20 +15,23 @@ class HLERequestContext;
} }
namespace Service::NVFlinger { namespace Service::NVFlinger {
class HosBinderDriverServer;
class NVFlinger; class NVFlinger;
} } // namespace Service::NVFlinger
namespace Service::VI { namespace Service::VI {
class VI_S final : public ServiceFramework<VI_S> { class VI_S final : public ServiceFramework<VI_S> {
public: 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; ~VI_S() override;
private: private:
void GetDisplayService(Kernel::HLERequestContext& ctx); void GetDisplayService(Kernel::HLERequestContext& ctx);
NVFlinger::NVFlinger& nv_flinger; NVFlinger::NVFlinger& nv_flinger;
NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
}; };
} // namespace Service::VI } // namespace Service::VI

View file

@ -8,8 +8,10 @@
namespace Service::VI { namespace Service::VI {
VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
: ServiceFramework{system_, "vi:u"}, nv_flinger{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[] = { static const FunctionInfo functions[] = {
{0, &VI_U::GetDisplayService, "GetDisplayService"}, {0, &VI_U::GetDisplayService, "GetDisplayService"},
{1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, {1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@ -22,7 +24,8 @@ VI_U::~VI_U() = default;
void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) { void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_VI, "called"); 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 } // namespace Service::VI

View file

@ -15,20 +15,23 @@ class HLERequestContext;
} }
namespace Service::NVFlinger { namespace Service::NVFlinger {
class HosBinderDriverServer;
class NVFlinger; class NVFlinger;
} } // namespace Service::NVFlinger
namespace Service::VI { namespace Service::VI {
class VI_U final : public ServiceFramework<VI_U> { class VI_U final : public ServiceFramework<VI_U> {
public: 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; ~VI_U() override;
private: private:
void GetDisplayService(Kernel::HLERequestContext& ctx); void GetDisplayService(Kernel::HLERequestContext& ctx);
NVFlinger::NVFlinger& nv_flinger; NVFlinger::NVFlinger& nv_flinger;
NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
}; };
} // namespace Service::VI } // namespace Service::VI

View file

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