diff options
Diffstat (limited to 'src/core/hle/service/nvnflinger')
20 files changed, 451 insertions, 568 deletions
diff --git a/src/core/hle/service/nvnflinger/binder.h b/src/core/hle/service/nvnflinger/binder.h index 179938192..124accb94 100644 --- a/src/core/hle/service/nvnflinger/binder.h +++ b/src/core/hle/service/nvnflinger/binder.h @@ -20,29 +20,12 @@ class HLERequestContext; namespace Service::android { -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, -}; - class IBinder { public: virtual ~IBinder() = default; - virtual void Transact(android::TransactionId code, u32 flags, std::span<const u8> parcel_data, - std::span<u8> parcel_reply) = 0; - virtual Kernel::KReadableEvent& GetNativeHandle() = 0; + virtual void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply, + u32 flags) = 0; + virtual Kernel::KReadableEvent* GetNativeHandle(u32 type_id) = 0; }; } // namespace Service::android diff --git a/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp index cf151ea3a..123507123 100644 --- a/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp +++ b/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp @@ -12,7 +12,7 @@ namespace Service::android { -BufferItemConsumer::BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer_) +BufferItemConsumer::BufferItemConsumer(std::shared_ptr<BufferQueueConsumer> consumer_) : ConsumerBase{std::move(consumer_)} {} Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, diff --git a/src/core/hle/service/nvnflinger/buffer_item_consumer.h b/src/core/hle/service/nvnflinger/buffer_item_consumer.h index e0c6b3604..9f95c9280 100644 --- a/src/core/hle/service/nvnflinger/buffer_item_consumer.h +++ b/src/core/hle/service/nvnflinger/buffer_item_consumer.h @@ -19,7 +19,7 @@ class BufferItem; class BufferItemConsumer final : public ConsumerBase { public: - explicit BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer); + explicit BufferItemConsumer(std::shared_ptr<BufferQueueConsumer> consumer); Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, bool wait_for_fence = true); Status ReleaseBuffer(const BufferItem& item, const Fence& release_fence); diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp index bbe8e06d4..3bc23aa97 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp @@ -4,12 +4,13 @@ // Parts of this implementation were based on: // https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp +#include "common/assert.h" #include "common/logging/log.h" #include "core/hle/service/nvnflinger/buffer_item.h" #include "core/hle/service/nvnflinger/buffer_queue_consumer.h" #include "core/hle/service/nvnflinger/buffer_queue_core.h" +#include "core/hle/service/nvnflinger/parcel.h" #include "core/hle/service/nvnflinger/producer_listener.h" -#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" namespace Service::android { @@ -254,4 +255,77 @@ Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) { return Status::NoError; } +void BufferQueueConsumer::Transact(u32 code, std::span<const u8> parcel_data, + std::span<u8> parcel_reply, u32 flags) { + // Values used by BnGraphicBufferConsumer onTransact + enum class TransactionId { + AcquireBuffer = 1, + DetachBuffer = 2, + AttachBuffer = 3, + ReleaseBuffer = 4, + ConsumerConnect = 5, + ConsumerDisconnect = 6, + GetReleasedBuffers = 7, + SetDefaultBufferSize = 8, + SetDefaultMaxBufferCount = 9, + DisableAsyncBuffer = 10, + SetMaxAcquiredBufferCount = 11, + SetConsumerName = 12, + SetDefaultBufferFormat = 13, + SetConsumerUsageBits = 14, + SetTransformHint = 15, + GetSidebandStream = 16, + Unknown18 = 18, + Unknown20 = 20, + }; + + Status status{Status::NoError}; + InputParcel parcel_in{parcel_data}; + OutputParcel parcel_out{}; + + switch (static_cast<TransactionId>(code)) { + case TransactionId::AcquireBuffer: { + BufferItem item; + const s64 present_when = parcel_in.Read<s64>(); + + status = AcquireBuffer(&item, std::chrono::nanoseconds{present_when}); + + // TODO: can't write this directly, needs a flattener for the sp<GraphicBuffer> + // parcel_out.WriteFlattened(item); + UNREACHABLE(); + } + case TransactionId::ReleaseBuffer: { + const s32 slot = parcel_in.Read<s32>(); + const u64 frame_number = parcel_in.Read<u64>(); + const auto release_fence = parcel_in.ReadFlattened<Fence>(); + + status = ReleaseBuffer(slot, frame_number, release_fence); + + break; + } + case TransactionId::GetReleasedBuffers: { + u64 slot_mask = 0; + + status = GetReleasedBuffers(&slot_mask); + + parcel_out.Write(slot_mask); + break; + } + default: + ASSERT_MSG(false, "called, code={} flags={}", code, flags); + break; + } + + parcel_out.Write(status); + + const auto serialized = parcel_out.Serialize(); + std::memcpy(parcel_reply.data(), serialized.data(), + std::min(parcel_reply.size(), serialized.size())); +} + +Kernel::KReadableEvent* BufferQueueConsumer::GetNativeHandle(u32 type_id) { + ASSERT_MSG(false, "called, type_id={}", type_id); + return nullptr; +} + } // namespace Service::android diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h index 0a61e8dbd..a9226f1c3 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h +++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h @@ -10,6 +10,7 @@ #include <memory> #include "common/common_types.h" +#include "core/hle/service/nvnflinger/binder.h" #include "core/hle/service/nvnflinger/buffer_queue_defs.h" #include "core/hle/service/nvnflinger/status.h" @@ -19,10 +20,10 @@ class BufferItem; class BufferQueueCore; class IConsumerListener; -class BufferQueueConsumer final { +class BufferQueueConsumer final : public IBinder { public: explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_); - ~BufferQueueConsumer(); + ~BufferQueueConsumer() override; Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present); Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence); @@ -30,6 +31,11 @@ public: Status Disconnect(); Status GetReleasedBuffers(u64* out_slot_mask); + void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply, + u32 flags) override; + + Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override; + private: std::shared_ptr<BufferQueueCore> core; BufferQueueDefs::SlotsType& slots; diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp index ec83beb9b..9e5091eeb 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp @@ -6,12 +6,9 @@ #include "common/assert.h" #include "common/logging/log.h" -#include "common/settings.h" -#include "core/core.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/service/hle_ipc.h" #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/nvnflinger/buffer_queue_core.h" #include "core/hle/service/nvnflinger/buffer_queue_producer.h" @@ -19,7 +16,6 @@ #include "core/hle/service/nvnflinger/parcel.h" #include "core/hle/service/nvnflinger/ui/graphic_buffer.h" #include "core/hle/service/nvnflinger/window.h" -#include "core/hle/service/vi/vi.h" namespace Service::android { @@ -807,13 +803,31 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot, return Status::NoError; } -void BufferQueueProducer::Transact(TransactionId code, u32 flags, std::span<const u8> parcel_data, - std::span<u8> parcel_reply) { +void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data, + std::span<u8> parcel_reply, u32 flags) { + // Values used by BnGraphicBufferProducer onTransact + 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, + }; + Status status{Status::NoError}; InputParcel parcel_in{parcel_data}; OutputParcel parcel_out{}; - switch (code) { + switch (static_cast<TransactionId>(code)) { case TransactionId::Connect: { const auto enable_listener = parcel_in.Read<bool>(); const auto api = parcel_in.Read<NativeWindowApi>(); @@ -923,8 +937,8 @@ void BufferQueueProducer::Transact(TransactionId code, u32 flags, std::span<cons std::min(parcel_reply.size(), serialized.size())); } -Kernel::KReadableEvent& BufferQueueProducer::GetNativeHandle() { - return buffer_wait_event->GetReadableEvent(); +Kernel::KReadableEvent* BufferQueueProducer::GetNativeHandle(u32 type_id) { + return &buffer_wait_event->GetReadableEvent(); } } // namespace Service::android diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.h b/src/core/hle/service/nvnflinger/buffer_queue_producer.h index 4682b0f84..048523514 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_producer.h +++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.h @@ -45,12 +45,12 @@ public: explicit BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_, std::shared_ptr<BufferQueueCore> buffer_queue_core_, Service::Nvidia::NvCore::NvMap& nvmap_); - ~BufferQueueProducer(); + ~BufferQueueProducer() override; - void Transact(android::TransactionId code, u32 flags, std::span<const u8> parcel_data, - std::span<u8> parcel_reply) override; + void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply, + u32 flags) override; - Kernel::KReadableEvent& GetNativeHandle() override; + Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override; public: Status RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf); diff --git a/src/core/hle/service/nvnflinger/consumer_base.cpp b/src/core/hle/service/nvnflinger/consumer_base.cpp index 1059e72bf..e360ebfd8 100644 --- a/src/core/hle/service/nvnflinger/consumer_base.cpp +++ b/src/core/hle/service/nvnflinger/consumer_base.cpp @@ -14,7 +14,7 @@ namespace Service::android { -ConsumerBase::ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_) +ConsumerBase::ConsumerBase(std::shared_ptr<BufferQueueConsumer> consumer_) : consumer{std::move(consumer_)} {} ConsumerBase::~ConsumerBase() { diff --git a/src/core/hle/service/nvnflinger/consumer_base.h b/src/core/hle/service/nvnflinger/consumer_base.h index ea3e9e97a..b29c16f86 100644 --- a/src/core/hle/service/nvnflinger/consumer_base.h +++ b/src/core/hle/service/nvnflinger/consumer_base.h @@ -27,7 +27,7 @@ public: void Abandon(); protected: - explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_); + explicit ConsumerBase(std::shared_ptr<BufferQueueConsumer> consumer_); ~ConsumerBase() override; void OnFrameAvailable(const BufferItem& item) override; @@ -54,7 +54,7 @@ protected: bool is_abandoned{}; - std::unique_ptr<BufferQueueConsumer> consumer; + std::shared_ptr<BufferQueueConsumer> consumer; mutable std::mutex mutex; }; diff --git a/src/core/hle/service/nvnflinger/display.h b/src/core/hle/service/nvnflinger/display.h new file mode 100644 index 000000000..8a1956fe0 --- /dev/null +++ b/src/core/hle/service/nvnflinger/display.h @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <list> + +#include "core/hle/service/nvnflinger/buffer_item_consumer.h" +#include "core/hle/service/nvnflinger/hwc_layer.h" + +namespace Service::Nvnflinger { + +struct Layer { + explicit Layer(std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer_, + s32 consumer_id_) + : buffer_item_consumer(std::move(buffer_item_consumer_)), consumer_id(consumer_id_), + blending(LayerBlending::None), visible(true) {} + ~Layer() { + buffer_item_consumer->Abandon(); + } + + std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer; + s32 consumer_id; + LayerBlending blending; + bool visible; +}; + +struct LayerStack { + std::list<Layer> layers; +}; + +struct Display { + explicit Display(u64 id_) { + id = id_; + } + + Layer* FindLayer(s32 consumer_id) { + for (auto& layer : stack.layers) { + if (layer.consumer_id == consumer_id) { + return &layer; + } + } + + return nullptr; + } + + u64 id; + LayerStack stack; +}; + +} // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp index be7eb97a3..02215a786 100644 --- a/src/core/hle/service/nvnflinger/hardware_composer.cpp +++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp @@ -10,8 +10,6 @@ #include "core/hle/service/nvnflinger/hardware_composer.h" #include "core/hle/service/nvnflinger/hwc_layer.h" #include "core/hle/service/nvnflinger/ui/graphic_buffer.h" -#include "core/hle/service/vi/display/vi_display.h" -#include "core/hle/service/vi/layer/vi_layer.h" namespace Service::Nvnflinger { @@ -44,7 +42,7 @@ s32 NormalizeSwapInterval(f32* out_speed_scale, s32 swap_interval) { HardwareComposer::HardwareComposer() = default; HardwareComposer::~HardwareComposer() = default; -u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, +u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display, Nvidia::Devices::nvdisp_disp0& nvdisp) { boost::container::small_vector<HwcLayer, 2> composition_stack; @@ -56,12 +54,11 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, bool has_acquired_buffer{}; // Acquire all necessary framebuffers. - for (size_t i = 0; i < display.GetNumLayers(); i++) { - auto& layer = display.GetLayer(i); - auto layer_id = layer.GetLayerId(); + for (auto& layer : display.stack.layers) { + auto consumer_id = layer.consumer_id; // Try to fetch the framebuffer (either new or stale). - const auto result = this->CacheFramebufferLocked(layer, layer_id); + const auto result = this->CacheFramebufferLocked(layer, consumer_id); // If we failed, skip this layer. if (result == CacheStatus::NoBufferAvailable) { @@ -73,24 +70,26 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, has_acquired_buffer = true; } - const auto& buffer = m_framebuffers[layer_id]; + const auto& buffer = m_framebuffers[consumer_id]; const auto& item = buffer.item; const auto& igbp_buffer = *item.graphic_buffer; // TODO: get proper Z-index from layer - composition_stack.emplace_back(HwcLayer{ - .buffer_handle = igbp_buffer.BufferId(), - .offset = igbp_buffer.Offset(), - .format = igbp_buffer.ExternalFormat(), - .width = igbp_buffer.Width(), - .height = igbp_buffer.Height(), - .stride = igbp_buffer.Stride(), - .z_index = 0, - .blending = layer.GetBlending(), - .transform = static_cast<android::BufferTransformFlags>(item.transform), - .crop_rect = item.crop, - .acquire_fence = item.fence, - }); + if (layer.visible) { + composition_stack.emplace_back(HwcLayer{ + .buffer_handle = igbp_buffer.BufferId(), + .offset = igbp_buffer.Offset(), + .format = igbp_buffer.ExternalFormat(), + .width = igbp_buffer.Width(), + .height = igbp_buffer.Height(), + .stride = igbp_buffer.Stride(), + .z_index = 0, + .blending = layer.blending, + .transform = static_cast<android::BufferTransformFlags>(item.transform), + .crop_rect = item.crop, + .acquire_fence = item.fence, + }); + } // We need to compose again either before this frame is supposed to // be released, or exactly on the vsync period it should be released. @@ -138,7 +137,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, if (auto* layer = display.FindLayer(layer_id); layer != nullptr) { // TODO: support release fence // This is needed to prevent screen tearing - layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence()); + layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence()); framebuffer.is_acquired = false; } } @@ -146,26 +145,26 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, return frame_advance; } -void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) { - // Check if we are tracking a slot with this layer_id. - const auto it = m_framebuffers.find(layer_id); +void HardwareComposer::RemoveLayerLocked(Display& display, ConsumerId consumer_id) { + // Check if we are tracking a slot with this consumer_id. + const auto it = m_framebuffers.find(consumer_id); if (it == m_framebuffers.end()) { return; } // Try to release the buffer item. - auto* const layer = display.FindLayer(layer_id); + auto* const layer = display.FindLayer(consumer_id); if (layer && it->second.is_acquired) { - layer->GetConsumer().ReleaseBuffer(it->second.item, android::Fence::NoFence()); + layer->buffer_item_consumer->ReleaseBuffer(it->second.item, android::Fence::NoFence()); } // Erase the slot. m_framebuffers.erase(it); } -bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer) { +bool HardwareComposer::TryAcquireFramebufferLocked(Layer& layer, Framebuffer& framebuffer) { // Attempt the update. - const auto status = layer.GetConsumer().AcquireBuffer(&framebuffer.item, {}, false); + const auto status = layer.buffer_item_consumer->AcquireBuffer(&framebuffer.item, {}, false); if (status != android::Status::NoError) { return false; } @@ -178,10 +177,10 @@ bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer return true; } -HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer& layer, - LayerId layer_id) { +HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(Layer& layer, + ConsumerId consumer_id) { // Check if this framebuffer is already present. - const auto it = m_framebuffers.find(layer_id); + const auto it = m_framebuffers.find(consumer_id); if (it != m_framebuffers.end()) { // If it's currently still acquired, we are done. if (it->second.is_acquired) { @@ -203,7 +202,7 @@ HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer if (this->TryAcquireFramebufferLocked(layer, framebuffer)) { // Move the buffer item into a new slot. - m_framebuffers.emplace(layer_id, std::move(framebuffer)); + m_framebuffers.emplace(consumer_id, std::move(framebuffer)); // We succeeded. return CacheStatus::BufferAcquired; diff --git a/src/core/hle/service/nvnflinger/hardware_composer.h b/src/core/hle/service/nvnflinger/hardware_composer.h index 28392c512..c5b830468 100644 --- a/src/core/hle/service/nvnflinger/hardware_composer.h +++ b/src/core/hle/service/nvnflinger/hardware_composer.h @@ -3,35 +3,29 @@ #pragma once -#include <memory> #include <boost/container/flat_map.hpp> #include "core/hle/service/nvnflinger/buffer_item.h" +#include "core/hle/service/nvnflinger/display.h" namespace Service::Nvidia::Devices { class nvdisp_disp0; } -namespace Service::VI { -class Display; -class Layer; -} // namespace Service::VI - namespace Service::Nvnflinger { -using LayerId = u64; +using ConsumerId = s32; class HardwareComposer { public: explicit HardwareComposer(); ~HardwareComposer(); - u32 ComposeLocked(f32* out_speed_scale, VI::Display& display, + u32 ComposeLocked(f32* out_speed_scale, Display& display, Nvidia::Devices::nvdisp_disp0& nvdisp); - void RemoveLayerLocked(VI::Display& display, LayerId layer_id); + void RemoveLayerLocked(Display& display, ConsumerId consumer_id); private: - // TODO: do we want to track frame number in vi instead? u64 m_frame_number{0}; private: @@ -49,11 +43,11 @@ private: CachedBufferReused, }; - boost::container::flat_map<LayerId, Framebuffer> m_framebuffers{}; + boost::container::flat_map<ConsumerId, Framebuffer> m_framebuffers{}; private: - bool TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer); - CacheStatus CacheFramebufferLocked(VI::Layer& layer, LayerId layer_id); + bool TryAcquireFramebufferLocked(Layer& layer, Framebuffer& framebuffer); + CacheStatus CacheFramebufferLocked(Layer& layer, ConsumerId consumer_id); }; } // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver.cpp b/src/core/hle/service/nvnflinger/hos_binder_driver.cpp index e09d72047..8629a2e89 100644 --- a/src/core/hle/service/nvnflinger/hos_binder_driver.cpp +++ b/src/core/hle/service/nvnflinger/hos_binder_driver.cpp @@ -10,7 +10,7 @@ namespace Service::Nvnflinger { IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, std::shared_ptr<HosBinderDriverServer> server, - std::shared_ptr<Nvnflinger> surface_flinger) + std::shared_ptr<SurfaceFlinger> surface_flinger) : ServiceFramework{system_, "IHOSBinderDriver"}, m_server(server), m_surface_flinger(surface_flinger) { static const FunctionInfo functions[] = { @@ -24,13 +24,18 @@ IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, IHOSBinderDriver::~IHOSBinderDriver() = default; -Result IHOSBinderDriver::TransactParcel(s32 binder_id, android::TransactionId transaction_id, +Result IHOSBinderDriver::TransactParcel(s32 binder_id, u32 transaction_id, InBuffer<BufferAttr_HipcMapAlias> parcel_data, OutBuffer<BufferAttr_HipcMapAlias> parcel_reply, u32 flags) { LOG_DEBUG(Service_VI, "called. id={} transaction={}, flags={}", binder_id, transaction_id, flags); - m_server->TryGetProducer(binder_id)->Transact(transaction_id, flags, parcel_data, parcel_reply); + + const auto binder = m_server->TryGetBinder(binder_id); + R_SUCCEED_IF(binder == nullptr); + + binder->Transact(transaction_id, parcel_data, parcel_reply, flags); + R_SUCCEED(); } @@ -42,11 +47,16 @@ Result IHOSBinderDriver::AdjustRefcount(s32 binder_id, s32 addval, s32 type) { Result IHOSBinderDriver::GetNativeHandle(s32 binder_id, u32 type_id, OutCopyHandle<Kernel::KReadableEvent> out_handle) { LOG_WARNING(Service_VI, "(STUBBED) called id={}, type_id={}", binder_id, type_id); - *out_handle = &m_server->TryGetProducer(binder_id)->GetNativeHandle(); + + const auto binder = m_server->TryGetBinder(binder_id); + R_UNLESS(binder != nullptr, ResultUnknown); + + *out_handle = binder->GetNativeHandle(type_id); + R_SUCCEED(); } -Result IHOSBinderDriver::TransactParcelAuto(s32 binder_id, android::TransactionId transaction_id, +Result IHOSBinderDriver::TransactParcelAuto(s32 binder_id, u32 transaction_id, InBuffer<BufferAttr_HipcAutoSelect> parcel_data, OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply, u32 flags) { diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver.h b/src/core/hle/service/nvnflinger/hos_binder_driver.h index aa9e3121a..b7fb07bd2 100644 --- a/src/core/hle/service/nvnflinger/hos_binder_driver.h +++ b/src/core/hle/service/nvnflinger/hos_binder_driver.h @@ -2,38 +2,45 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/service/cmif_types.h" -#include "core/hle/service/nvnflinger/binder.h" #include "core/hle/service/service.h" +namespace Kernel { +class KReadableEvent; +} + namespace Service::Nvnflinger { class HosBinderDriverServer; -class Nvnflinger; +class SurfaceFlinger; class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { public: explicit IHOSBinderDriver(Core::System& system_, std::shared_ptr<HosBinderDriverServer> server, - std::shared_ptr<Nvnflinger> surface_flinger); + std::shared_ptr<SurfaceFlinger> surface_flinger); ~IHOSBinderDriver() override; - std::shared_ptr<Nvnflinger> GetSurfaceFlinger() { + std::shared_ptr<SurfaceFlinger> GetSurfaceFlinger() { return m_surface_flinger; } + std::shared_ptr<HosBinderDriverServer> GetServer() { + return m_server; + } + private: - Result TransactParcel(s32 binder_id, android::TransactionId transaction_id, + Result TransactParcel(s32 binder_id, u32 transaction_id, InBuffer<BufferAttr_HipcMapAlias> parcel_data, OutBuffer<BufferAttr_HipcMapAlias> parcel_reply, u32 flags); Result AdjustRefcount(s32 binder_id, s32 addval, s32 type); Result GetNativeHandle(s32 binder_id, u32 type_id, OutCopyHandle<Kernel::KReadableEvent> out_handle); - Result TransactParcelAuto(s32 binder_id, android::TransactionId transaction_id, + Result TransactParcelAuto(s32 binder_id, u32 transaction_id, InBuffer<BufferAttr_HipcAutoSelect> parcel_data, OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply, u32 flags); private: const std::shared_ptr<HosBinderDriverServer> m_server; - const std::shared_ptr<Nvnflinger> m_surface_flinger; + const std::shared_ptr<SurfaceFlinger> m_surface_flinger; }; } // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp b/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp index b86a79ec9..29addda44 100644 --- a/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp +++ b/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp @@ -8,26 +8,30 @@ namespace Service::Nvnflinger { -HosBinderDriverServer::HosBinderDriverServer(Core::System& system_) - : service_context(system_, "HosBinderDriverServer") {} +HosBinderDriverServer::HosBinderDriverServer() = default; +HosBinderDriverServer::~HosBinderDriverServer() = default; -HosBinderDriverServer::~HosBinderDriverServer() {} - -u64 HosBinderDriverServer::RegisterProducer(std::unique_ptr<android::IBinder>&& binder) { +s32 HosBinderDriverServer::RegisterBinder(std::shared_ptr<android::IBinder>&& binder) { std::scoped_lock lk{lock}; last_id++; - producers[last_id] = std::move(binder); + binders[last_id] = std::move(binder); return last_id; } -android::IBinder* HosBinderDriverServer::TryGetProducer(u64 id) { +void HosBinderDriverServer::UnregisterBinder(s32 binder_id) { + std::scoped_lock lk{lock}; + + binders.erase(binder_id); +} + +std::shared_ptr<android::IBinder> HosBinderDriverServer::TryGetBinder(s32 id) const { std::scoped_lock lk{lock}; - if (auto search = producers.find(id); search != producers.end()) { - return search->second.get(); + if (auto search = binders.find(id); search != binders.end()) { + return search->second; } return {}; diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver_server.h b/src/core/hle/service/nvnflinger/hos_binder_driver_server.h index 58bb9469a..d72b50833 100644 --- a/src/core/hle/service/nvnflinger/hos_binder_driver_server.h +++ b/src/core/hle/service/nvnflinger/hos_binder_driver_server.h @@ -8,7 +8,6 @@ #include <unordered_map> #include "common/common_types.h" -#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/nvnflinger/binder.h" namespace Core { @@ -19,19 +18,18 @@ namespace Service::Nvnflinger { class HosBinderDriverServer final { public: - explicit HosBinderDriverServer(Core::System& system_); + explicit HosBinderDriverServer(); ~HosBinderDriverServer(); - u64 RegisterProducer(std::unique_ptr<android::IBinder>&& binder); + s32 RegisterBinder(std::shared_ptr<android::IBinder>&& binder); + void UnregisterBinder(s32 binder_id); - android::IBinder* TryGetProducer(u64 id); + std::shared_ptr<android::IBinder> TryGetBinder(s32 id) const; private: - KernelHelpers::ServiceContext service_context; - - std::unordered_map<u64, std::unique_ptr<android::IBinder>> producers; - std::mutex lock; - u64 last_id{}; + std::unordered_map<s32, std::shared_ptr<android::IBinder>> binders; + mutable std::mutex lock; + s32 last_id{}; }; } // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index a20ef14af..9e3b68b8a 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -1,318 +1,19 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -#include "common/microprofile.h" -#include "common/scope_exit.h" -#include "common/settings.h" #include "core/core.h" -#include "core/core_timing.h" -#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" -#include "core/hle/service/nvdrv/nvdrv.h" -#include "core/hle/service/nvdrv/nvdrv_interface.h" -#include "core/hle/service/nvnflinger/hardware_composer.h" #include "core/hle/service/nvnflinger/hos_binder_driver.h" #include "core/hle/service/nvnflinger/hos_binder_driver_server.h" #include "core/hle/service/nvnflinger/nvnflinger.h" +#include "core/hle/service/nvnflinger/surface_flinger.h" #include "core/hle/service/server_manager.h" #include "core/hle/service/sm/sm.h" -#include "core/hle/service/vi/display/vi_display.h" -#include "core/hle/service/vi/layer/vi_layer.h" -#include "core/hle/service/vi/vi_results.h" namespace Service::Nvnflinger { -constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60}; - -void Nvnflinger::SplitVSync(std::stop_token stop_token) { - system.RegisterHostThread(); - std::string name = "VSyncThread"; - MicroProfileOnThreadCreate(name.c_str()); - - // Cleanup - SCOPE_EXIT({ MicroProfileOnThreadExit(); }); - - Common::SetCurrentThreadName(name.c_str()); - Common::SetCurrentThreadPriority(Common::ThreadPriority::High); - - while (!stop_token.stop_requested()) { - vsync_signal.Wait(); - - if (system.IsShuttingDown()) { - ShutdownLayers(); - return; - } - - const auto lock_guard = Lock(); - - if (!is_abandoned) { - Compose(); - } - } -} - -Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_) - : system(system_), service_context(system_, "nvnflinger"), - 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>(); - - nvdrv = system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule(); - disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {}); - - // Schedule the screen composition events - multi_composition_event = Core::Timing::CreateEvent( - "ScreenComposition", - [this](s64 time, - std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { - vsync_signal.Set(); - return std::chrono::nanoseconds(GetNextTicks()); - }); - - single_composition_event = Core::Timing::CreateEvent( - "ScreenComposition", - [this](s64 time, - std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { - const auto lock_guard = Lock(); - Compose(); - - return std::chrono::nanoseconds(GetNextTicks()); - }); - - if (system.IsMulticore()) { - system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, multi_composition_event); - vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); }); - } else { - system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, single_composition_event); - } -} - -Nvnflinger::~Nvnflinger() { - if (system.IsMulticore()) { - system.CoreTiming().UnscheduleEvent(multi_composition_event); - vsync_thread.request_stop(); - vsync_signal.Set(); - } else { - system.CoreTiming().UnscheduleEvent(single_composition_event); - } - - ShutdownLayers(); - - if (nvdrv) { - nvdrv->Close(disp_fd); - } -} - -void Nvnflinger::ShutdownLayers() { - // Abandon consumers. - const auto lock_guard = Lock(); - for (auto& display : displays) { - display.Abandon(); - } - - is_abandoned = true; -} - -std::optional<u64> Nvnflinger::OpenDisplay(std::string_view name) { - const auto lock_guard = Lock(); - - LOG_DEBUG(Service_Nvnflinger, "Opening \"{}\" display", name); - - const auto itr = - std::find_if(displays.begin(), displays.end(), - [&](const VI::Display& display) { return display.GetName() == name; }); - - if (itr == displays.end()) { - return std::nullopt; - } - - return itr->GetID(); -} - -bool Nvnflinger::CloseDisplay(u64 display_id) { - const auto lock_guard = Lock(); - auto* const display = FindDisplay(display_id); - - if (display == nullptr) { - return false; - } - - display->Reset(); - - return true; -} - -std::optional<u64> Nvnflinger::CreateLayer(u64 display_id, LayerBlending blending) { - const auto lock_guard = Lock(); - auto* const display = FindDisplay(display_id); - - if (display == nullptr) { - return std::nullopt; - } - - const u64 layer_id = next_layer_id++; - CreateLayerAtId(*display, layer_id, blending); - return layer_id; -} - -void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending) { - const auto buffer_id = next_buffer_queue_id++; - display.CreateLayer(layer_id, buffer_id, nvdrv->container); - display.FindLayer(layer_id)->SetBlending(blending); -} - -bool Nvnflinger::OpenLayer(u64 layer_id) { - const auto lock_guard = Lock(); - - for (auto& display : displays) { - if (auto* layer = display.FindLayer(layer_id); layer) { - return layer->Open(); - } - } - - return false; -} - -bool Nvnflinger::CloseLayer(u64 layer_id) { - const auto lock_guard = Lock(); - - for (auto& display : displays) { - if (auto* layer = display.FindLayer(layer_id); layer) { - return layer->Close(); - } - } - - return false; -} - -void Nvnflinger::SetLayerVisibility(u64 layer_id, bool visible) { - const auto lock_guard = Lock(); - - for (auto& display : displays) { - if (auto* layer = display.FindLayer(layer_id); layer) { - layer->SetVisibility(visible); - } - } -} - -void Nvnflinger::DestroyLayer(u64 layer_id) { - const auto lock_guard = Lock(); - - for (auto& display : displays) { - display.DestroyLayer(layer_id); - } -} - -std::optional<u32> Nvnflinger::FindBufferQueueId(u64 display_id, u64 layer_id) { - const auto lock_guard = Lock(); - const auto* const layer = FindLayer(display_id, layer_id); - - if (layer == nullptr) { - return std::nullopt; - } - - return layer->GetBinderId(); -} - -Result Nvnflinger::FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id) { - const auto lock_guard = Lock(); - auto* const display = FindDisplay(display_id); - - if (display == nullptr) { - return VI::ResultNotFound; - } - - *out_vsync_event = display->GetVSyncEvent(); - return ResultSuccess; -} - -VI::Display* Nvnflinger::FindDisplay(u64 display_id) { - const auto itr = - std::find_if(displays.begin(), displays.end(), - [&](const VI::Display& display) { return display.GetID() == display_id; }); - - if (itr == displays.end()) { - return nullptr; - } - - return &*itr; -} - -const VI::Display* Nvnflinger::FindDisplay(u64 display_id) const { - const auto itr = - std::find_if(displays.begin(), displays.end(), - [&](const VI::Display& display) { return display.GetID() == display_id; }); - - if (itr == displays.end()) { - return nullptr; - } - - return &*itr; -} - -VI::Layer* Nvnflinger::FindLayer(u64 display_id, u64 layer_id) { - auto* const display = FindDisplay(display_id); - - if (display == nullptr) { - return nullptr; - } - - return display->FindLayer(layer_id); -} - -void Nvnflinger::Compose() { - for (auto& display : displays) { - // Trigger vsync for this display at the end of drawing - SCOPE_EXIT({ display.SignalVSyncEvent(); }); - - // Don't do anything for displays without layers. - if (!display.HasLayers()) { - continue; - } - - if (!system.IsPoweredOn()) { - return; // We are likely shutting down - } - - auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd); - ASSERT(nvdisp); - - swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp); - } -} - -s64 Nvnflinger::GetNextTicks() const { - const auto& settings = Settings::values; - auto speed_scale = 1.f; - if (settings.use_multi_core.GetValue()) { - if (settings.use_speed_limit.GetValue()) { - // Scales the speed based on speed_limit setting on MC. SC is handled by - // SpeedLimiter::DoSpeedLimiting. - speed_scale = 100.f / settings.speed_limit.GetValue(); - } else { - // Run at unlocked framerate. - speed_scale = 0.01f; - } - } - - // Adjust by speed limit determined during composition. - speed_scale /= compose_speed_scale; - - if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) { - // Run at intended presentation rate during video playback. - speed_scale = 1.f; - } - - const f32 effective_fps = 60.f / static_cast<f32>(swap_interval); - return static_cast<s64>(speed_scale * (1000000000.f / effective_fps)); -} - void LoopProcess(Core::System& system) { - const auto binder_server = std::make_shared<HosBinderDriverServer>(system); - const auto surface_flinger = std::make_shared<Nvnflinger>(system, *binder_server); + const auto binder_server = std::make_shared<HosBinderDriverServer>(); + const auto surface_flinger = std::make_shared<SurfaceFlinger>(system, *binder_server); auto server_manager = std::make_unique<ServerManager>(system); server_manager->RegisterNamedService( diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index 941a98418..5c41f3013 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h @@ -3,158 +3,12 @@ #pragma once -#include <list> -#include <memory> -#include <mutex> -#include <optional> -#include <thread> - -#include "common/common_types.h" -#include "common/polyfill_thread.h" -#include "common/thread.h" -#include "core/hle/result.h" -#include "core/hle/service/kernel_helpers.h" -#include "core/hle/service/nvnflinger/hwc_layer.h" - -namespace Common { -class Event; -} // namespace Common - -namespace Core::Timing { -class CoreTiming; -struct EventType; -} // namespace Core::Timing - -namespace Kernel { -class KReadableEvent; -} // namespace Kernel - -namespace Service::Nvidia { -class Module; -} // namespace Service::Nvidia - -namespace Service::VI { -class Display; -class FbshareBufferManager; -class Layer; -} // namespace Service::VI - -namespace Service::android { -class BufferQueueCore; -class BufferQueueProducer; -} // namespace Service::android +namespace Core { +class System; +} namespace Service::Nvnflinger { -class HardwareComposer; -class HosBinderDriverServer; - -class Nvnflinger final { -public: - explicit Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_); - ~Nvnflinger(); - - void ShutdownLayers(); - - /// Opens the specified display and returns the ID. - /// - /// If an invalid display name is provided, then an empty optional is returned. - [[nodiscard]] std::optional<u64> OpenDisplay(std::string_view name); - - /// Closes the specified display by its ID. - /// - /// Returns false if an invalid display ID is provided. - [[nodiscard]] bool CloseDisplay(u64 display_id); - - /// Creates a layer on the specified display and returns the layer ID. - /// - /// If an invalid display ID is specified, then an empty optional is returned. - [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id, - LayerBlending blending = LayerBlending::None); - - /// Opens a layer on all displays for the given layer ID. - bool OpenLayer(u64 layer_id); - - /// Closes a layer on all displays for the given layer ID. - bool CloseLayer(u64 layer_id); - - /// Makes a layer visible on all displays for the given layer ID. - void SetLayerVisibility(u64 layer_id, bool visible); - - /// Destroys the given layer ID. - void DestroyLayer(u64 layer_id); - - /// Finds the buffer queue ID of the specified layer in the specified display. - /// - /// If an invalid display ID or layer ID is provided, then an empty optional is returned. - [[nodiscard]] std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id); - - /// Gets the vsync event for the specified display. - /// - /// If an invalid display ID is provided, then VI::ResultNotFound is returned. - /// If the vsync event has already been retrieved, then VI::ResultPermissionDenied is returned. - [[nodiscard]] Result FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id); - - /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when - /// finished. - void Compose(); - - [[nodiscard]] s64 GetNextTicks() const; - -private: - friend class VI::FbshareBufferManager; - - [[nodiscard]] std::unique_lock<std::mutex> Lock() const { - return std::unique_lock{*guard}; - } - - /// Finds the display identified by the specified ID. - [[nodiscard]] VI::Display* FindDisplay(u64 display_id); - - /// Finds the display identified by the specified ID. - [[nodiscard]] const VI::Display* FindDisplay(u64 display_id) const; - - /// Finds the layer identified by the specified ID in the desired display. - [[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id); - - /// Creates a layer with the specified layer ID in the desired display. - void CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending); - - void SplitVSync(std::stop_token stop_token); - - std::shared_ptr<Nvidia::Module> nvdrv; - s32 disp_fd; - - std::list<VI::Display> displays; - - /// Id to use for the next layer that is created, this counter is shared among all displays. - u64 next_layer_id = 1; - /// Id to use for the next buffer queue that is created, this counter is shared among all - /// layers. - u32 next_buffer_queue_id = 1; - - s32 swap_interval = 1; - f32 compose_speed_scale = 1.0f; - - bool is_abandoned = false; - - /// Event that handles screen composition. - std::shared_ptr<Core::Timing::EventType> multi_composition_event; - std::shared_ptr<Core::Timing::EventType> single_composition_event; - - std::shared_ptr<std::mutex> guard; - - Core::System& system; - - Common::Event vsync_signal; - - std::jthread vsync_thread; - - KernelHelpers::ServiceContext service_context; - - HosBinderDriverServer& hos_binder_driver_server; -}; - void LoopProcess(Core::System& system); } // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/surface_flinger.cpp b/src/core/hle/service/nvnflinger/surface_flinger.cpp new file mode 100644 index 000000000..0e9714a03 --- /dev/null +++ b/src/core/hle/service/nvnflinger/surface_flinger.cpp @@ -0,0 +1,123 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" +#include "core/hle/service/nvdrv/nvdrv_interface.h" +#include "core/hle/service/nvnflinger/display.h" +#include "core/hle/service/nvnflinger/hos_binder_driver_server.h" +#include "core/hle/service/nvnflinger/surface_flinger.h" +#include "core/hle/service/sm/sm.h" + +#include "core/hle/service/nvnflinger/buffer_queue_consumer.h" +#include "core/hle/service/nvnflinger/buffer_queue_core.h" +#include "core/hle/service/nvnflinger/buffer_queue_producer.h" + +namespace Service::Nvnflinger { + +SurfaceFlinger::SurfaceFlinger(Core::System& system, HosBinderDriverServer& server) + : m_system(system), m_server(server), m_context(m_system, "SurfaceFlinger") { + nvdrv = m_system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule(); + disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {}); +} + +SurfaceFlinger::~SurfaceFlinger() { + nvdrv->Close(disp_fd); +} + +void SurfaceFlinger::AddDisplay(u64 display_id) { + m_displays.emplace_back(display_id); +} + +void SurfaceFlinger::RemoveDisplay(u64 display_id) { + std::erase_if(m_displays, [&](auto& display) { return display.id == display_id; }); +} + +void SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, + u64 display_id) { + auto* const display = this->FindDisplay(display_id); + if (!display) { + return; + } + + *out_swap_interval = + m_composer.ComposeLocked(out_compose_speed_scale, *display, + *nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd)); +} + +void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) { + auto* const display = this->FindDisplay(display_id); + auto binder = std::static_pointer_cast<android::BufferQueueConsumer>( + m_server.TryGetBinder(consumer_binder_id)); + + if (!display || !binder) { + return; + } + + auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(binder)); + buffer_item_consumer->Connect(false); + + display->stack.layers.emplace_back(std::move(buffer_item_consumer), consumer_binder_id); +} + +void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id) { + auto* const display = this->FindDisplay(display_id); + if (!display) { + return; + } + + m_composer.RemoveLayerLocked(*display, consumer_binder_id); + std::erase_if(display->stack.layers, + [&](auto& layer) { return layer.consumer_id == consumer_binder_id; }); +} + +void SurfaceFlinger::SetLayerVisibility(s32 consumer_binder_id, bool visible) { + if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) { + layer->visible = visible; + return; + } +} + +void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) { + if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) { + layer->blending = blending; + return; + } +} + +Display* SurfaceFlinger::FindDisplay(u64 display_id) { + for (auto& display : m_displays) { + if (display.id == display_id) { + return &display; + } + } + + return nullptr; +} + +Layer* SurfaceFlinger::FindLayer(s32 consumer_binder_id) { + for (auto& display : m_displays) { + if (auto* layer = display.FindLayer(consumer_binder_id); layer != nullptr) { + return layer; + } + } + + return nullptr; +} + +void SurfaceFlinger::CreateBufferQueue(s32* out_consumer_binder_id, s32* out_producer_binder_id) { + auto& nvmap = nvdrv->GetContainer().GetNvMapFile(); + auto core = std::make_shared<android::BufferQueueCore>(); + auto producer = std::make_shared<android::BufferQueueProducer>(m_context, core, nvmap); + auto consumer = std::make_shared<android::BufferQueueConsumer>(core); + + *out_consumer_binder_id = m_server.RegisterBinder(std::move(consumer)); + *out_producer_binder_id = m_server.RegisterBinder(std::move(producer)); +} + +void SurfaceFlinger::DestroyBufferQueue(s32 consumer_binder_id, s32 producer_binder_id) { + m_server.UnregisterBinder(producer_binder_id); + m_server.UnregisterBinder(consumer_binder_id); +} + +} // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/surface_flinger.h b/src/core/hle/service/nvnflinger/surface_flinger.h new file mode 100644 index 000000000..a2e661430 --- /dev/null +++ b/src/core/hle/service/nvnflinger/surface_flinger.h @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <vector> + +#include "common/common_types.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/nvnflinger/hardware_composer.h" + +namespace Core { +class System; +} + +namespace Service::Nvidia { +class Module; +} + +// TODO: ISurfaceComposer +// TODO: ISurfaceComposerClient + +namespace Service::Nvnflinger { + +struct Display; +class HosBinderDriverServer; +enum class LayerBlending : u32; +struct Layer; + +class SurfaceFlinger { +public: + explicit SurfaceFlinger(Core::System& system, HosBinderDriverServer& server); + ~SurfaceFlinger(); + + void AddDisplay(u64 display_id); + void RemoveDisplay(u64 display_id); + void ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id); + + void AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id); + void RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id); + + void SetLayerVisibility(s32 consumer_binder_id, bool visible); + void SetLayerBlending(s32 consumer_binder_id, LayerBlending blending); + +private: + Display* FindDisplay(u64 display_id); + Layer* FindLayer(s32 consumer_binder_id); + +public: + // TODO: these don't belong here + void CreateBufferQueue(s32* out_consumer_binder_id, s32* out_producer_binder_id); + void DestroyBufferQueue(s32 consumer_binder_id, s32 producer_binder_id); + +private: + Core::System& m_system; + HosBinderDriverServer& m_server; + KernelHelpers::ServiceContext m_context; + + std::vector<Display> m_displays; + std::shared_ptr<Nvidia::Module> nvdrv; + s32 disp_fd; + HardwareComposer m_composer; +}; + +} // namespace Service::Nvnflinger |