diff options
Diffstat (limited to '')
22 files changed, 588 insertions, 701 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..40aa59787 --- /dev/null +++ b/src/core/hle/service/nvnflinger/display.h @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#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::vector<std::shared_ptr<Layer>> layers; + + std::shared_ptr<Layer> FindLayer(s32 consumer_id) { + for (auto& layer : layers) { + if (layer->consumer_id == consumer_id) { + return layer; + } + } + + return nullptr; + } + + bool HasLayers() { + return !layers.empty(); + } +}; + +struct Display { + explicit Display(u64 id_) { + id = id_; + } + + 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..f2dfe85a9 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. @@ -135,10 +134,10 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, continue; } - if (auto* layer = display.FindLayer(layer_id); layer != nullptr) { + if (const auto layer = display.stack.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); + const auto layer = display.stack.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/vi/hos_binder_driver.cpp b/src/core/hle/service/nvnflinger/hos_binder_driver.cpp index ba0317245..8629a2e89 100644 --- a/src/core/hle/service/vi/hos_binder_driver.cpp +++ b/src/core/hle/service/nvnflinger/hos_binder_driver.cpp @@ -3,13 +3,16 @@ #include "core/hle/service/cmif_serialization.h" #include "core/hle/service/nvnflinger/binder.h" +#include "core/hle/service/nvnflinger/hos_binder_driver.h" #include "core/hle/service/nvnflinger/hos_binder_driver_server.h" -#include "core/hle/service/vi/hos_binder_driver.h" -namespace Service::VI { +namespace Service::Nvnflinger { -IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderDriverServer& server) - : ServiceFramework{system_, "IHOSBinderDriver"}, m_server(server) { +IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, + std::shared_ptr<HosBinderDriverServer> server, + std::shared_ptr<SurfaceFlinger> surface_flinger) + : ServiceFramework{system_, "IHOSBinderDriver"}, m_server(server), + m_surface_flinger(surface_flinger) { static const FunctionInfo functions[] = { {0, C<&IHOSBinderDriver::TransactParcel>, "TransactParcel"}, {1, C<&IHOSBinderDriver::AdjustRefcount>, "AdjustRefcount"}, @@ -21,13 +24,18 @@ IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderD 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(); } @@ -39,15 +47,20 @@ 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) { R_RETURN(this->TransactParcel(binder_id, transaction_id, parcel_data, parcel_reply, flags)); } -} // namespace Service::VI +} // namespace Service::Nvnflinger diff --git a/src/core/hle/service/vi/hos_binder_driver.h b/src/core/hle/service/nvnflinger/hos_binder_driver.h index ed6e8cdbe..b7fb07bd2 100644 --- a/src/core/hle/service/vi/hos_binder_driver.h +++ b/src/core/hle/service/nvnflinger/hos_binder_driver.h @@ -2,29 +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 Service::VI { +namespace Kernel { +class KReadableEvent; +} + +namespace Service::Nvnflinger { + +class HosBinderDriverServer; +class SurfaceFlinger; class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { public: - explicit IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderDriverServer& server); + explicit IHOSBinderDriver(Core::System& system_, std::shared_ptr<HosBinderDriverServer> server, + std::shared_ptr<SurfaceFlinger> surface_flinger); ~IHOSBinderDriver() override; + 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: - Nvnflinger::HosBinderDriverServer& m_server; + const std::shared_ptr<HosBinderDriverServer> m_server; + const std::shared_ptr<SurfaceFlinger> m_surface_flinger; }; -} // namespace Service::VI +} // 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 687ccc9f9..9e3b68b8a 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -1,335 +1,24 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -#include <algorithm> -#include <optional> - -#include "common/assert.h" -#include "common/logging/log.h" -#include "common/microprofile.h" -#include "common/scope_exit.h" -#include "common/settings.h" -#include "common/thread.h" #include "core/core.h" -#include "core/core_timing.h" -#include "core/hle/kernel/k_readable_event.h" -#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" -#include "core/hle/service/nvdrv/nvdrv.h" -#include "core/hle/service/nvnflinger/buffer_item_consumer.h" -#include "core/hle/service/nvnflinger/buffer_queue_core.h" -#include "core/hle/service/nvnflinger/fb_share_buffer_manager.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/ui/graphic_buffer.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" -#include "video_core/gpu.h" -#include "video_core/host1x/host1x.h" -#include "video_core/host1x/syncpoint_manager.h" +#include "core/hle/service/nvnflinger/surface_flinger.h" +#include "core/hle/service/server_manager.h" +#include "core/hle/service/sm/sm.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(); - - 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>(); - - // 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; - } - - // Join the vsync thread, if it exists. - vsync_thread = {}; -} - -void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { - nvdrv = std::move(instance); - disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {}); -} - -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)); -} - -FbShareBufferManager& Nvnflinger::GetSystemBufferManager() { - const auto lock_guard = Lock(); - - if (!system_buffer_manager) { - system_buffer_manager = std::make_unique<FbShareBufferManager>(system, *this, nvdrv); - } +void LoopProcess(Core::System& system) { + const auto binder_server = std::make_shared<HosBinderDriverServer>(); + const auto surface_flinger = std::make_shared<SurfaceFlinger>(system, *binder_server); - return *system_buffer_manager; + auto server_manager = std::make_unique<ServerManager>(system); + server_manager->RegisterNamedService( + "dispdrv", std::make_shared<IHOSBinderDriver>(system, binder_server, surface_flinger)); + ServerManager::RunServer(std::move(server_manager)); } } // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index 4cf4f069d..5c41f3013 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h @@ -3,170 +3,12 @@ #pragma once -#include <list> -#include <memory> -#include <mutex> -#include <optional> -#include <thread> -#include <vector> - -#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 Layer; -} // namespace Service::VI - -namespace Service::android { -class BufferQueueCore; -class BufferQueueProducer; -} // namespace Service::android +namespace Core { +class System; +} namespace Service::Nvnflinger { -class FbShareBufferManager; -class HardwareComposer; -class HosBinderDriverServer; - -class Nvnflinger final { -public: - explicit Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_); - ~Nvnflinger(); - - void ShutdownLayers(); - - /// Sets the NVDrv module instance to use to send buffers to the GPU. - void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance); - - /// 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; - - FbShareBufferManager& GetSystemBufferManager(); - -private: - struct Layer { - std::unique_ptr<android::BufferQueueCore> core; - std::unique_ptr<android::BufferQueueProducer> producer; - }; - - friend class FbShareBufferManager; - -private: - [[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::unique_ptr<FbShareBufferManager> system_buffer_manager; - - 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..8362b65e5 --- /dev/null +++ b/src/core/hle/service/nvnflinger/surface_flinger.cpp @@ -0,0 +1,139 @@ +// 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; }); +} + +bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, + u64 display_id) { + auto* const display = this->FindDisplay(display_id); + if (!display || !display->stack.HasLayers()) { + return false; + } + + *out_swap_interval = + m_composer.ComposeLocked(out_compose_speed_scale, *display, + *nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd)); + return true; +} + +void SurfaceFlinger::CreateLayer(s32 consumer_binder_id) { + auto binder = std::static_pointer_cast<android::BufferQueueConsumer>( + m_server.TryGetBinder(consumer_binder_id)); + if (!binder) { + return; + } + + auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(binder)); + buffer_item_consumer->Connect(false); + + m_layers.layers.emplace_back( + std::make_shared<Layer>(std::move(buffer_item_consumer), consumer_binder_id)); +} + +void SurfaceFlinger::DestroyLayer(s32 consumer_binder_id) { + std::erase_if(m_layers.layers, + [&](auto& layer) { return layer->consumer_id == consumer_binder_id; }); +} + +void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) { + auto* const display = this->FindDisplay(display_id); + auto layer = this->FindLayer(consumer_binder_id); + + if (!display || !layer) { + return; + } + + display->stack.layers.emplace_back(std::move(layer)); +} + +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 (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) { + layer->visible = visible; + return; + } +} + +void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) { + if (const 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; +} + +std::shared_ptr<Layer> SurfaceFlinger::FindLayer(s32 consumer_binder_id) { + for (auto& layer : m_layers.layers) { + if (layer->consumer_id == consumer_binder_id) { + 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..406281c83 --- /dev/null +++ b/src/core/hle/service/nvnflinger/surface_flinger.h @@ -0,0 +1,69 @@ +// 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); + bool ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id); + + void CreateLayer(s32 consumer_binder_id); + void DestroyLayer(s32 consumer_binder_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); + std::shared_ptr<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; + LayerStack m_layers; + std::shared_ptr<Nvidia::Module> nvdrv; + s32 disp_fd; + HardwareComposer m_composer; +}; + +} // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/vi/shared_buffer_manager.cpp index 90f7248a0..12cba16fa 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/vi/shared_buffer_manager.cpp @@ -9,15 +9,15 @@ #include "core/hle/service/nvdrv/devices/nvmap.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvnflinger/buffer_queue_producer.h" -#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" #include "core/hle/service/nvnflinger/pixel_format.h" #include "core/hle/service/nvnflinger/ui/graphic_buffer.h" -#include "core/hle/service/vi/layer/vi_layer.h" +#include "core/hle/service/vi/container.h" +#include "core/hle/service/vi/shared_buffer_manager.h" #include "core/hle/service/vi/vi_results.h" #include "video_core/gpu.h" #include "video_core/host1x/host1x.h" -namespace Service::Nvnflinger { +namespace Service::VI { namespace { @@ -26,7 +26,6 @@ Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_ using Core::Memory::YUZU_PAGESIZE; // Allocate memory for the system shared buffer. - // FIXME: This memory belongs to vi's .data section. auto& kernel = system.Kernel(); // Hold a temporary page group reference while we try to map it. @@ -204,15 +203,15 @@ void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 han } // namespace -FbShareBufferManager::FbShareBufferManager(Core::System& system, Nvnflinger& flinger, - std::shared_ptr<Nvidia::Module> nvdrv) - : m_system(system), m_flinger(flinger), m_nvdrv(std::move(nvdrv)) {} +SharedBufferManager::SharedBufferManager(Core::System& system, Container& container, + std::shared_ptr<Nvidia::Module> nvdrv) + : m_system(system), m_container(container), m_nvdrv(std::move(nvdrv)) {} -FbShareBufferManager::~FbShareBufferManager() = default; +SharedBufferManager::~SharedBufferManager() = default; -Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, - u64* out_layer_handle, u64 display_id, - LayerBlending blending) { +Result SharedBufferManager::CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id, + u64* out_layer_handle, u64 display_id, + bool enable_blending) { std::scoped_lock lk{m_guard}; // Ensure we haven't already created. @@ -237,7 +236,7 @@ Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou owner_process, m_system)); // Create new session. - auto [it, was_emplaced] = m_sessions.emplace(aruid, FbShareSession{}); + auto [it, was_emplaced] = m_sessions.emplace(aruid, SharedBufferSession{}); auto& session = it->second; auto& container = m_nvdrv->GetContainer(); @@ -249,17 +248,18 @@ Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou session.nvmap_fd, map_address, SharedBufferSize)); // Create and open a layer for the display. - session.layer_id = m_flinger.CreateLayer(m_display_id, blending).value(); - m_flinger.OpenLayer(session.layer_id); + s32 producer_binder_id; + R_TRY(m_container.CreateStrayLayer(std::addressof(producer_binder_id), + std::addressof(session.layer_id), display_id)); - // Get the layer. - VI::Layer* layer = m_flinger.FindLayer(m_display_id, session.layer_id); - ASSERT(layer != nullptr); + // Configure blending. + R_ASSERT(m_container.SetLayerBlending(session.layer_id, enable_blending)); // Get the producer and set preallocated buffers. - auto& producer = layer->GetBufferQueue(); - MakeGraphicBuffer(producer, 0, session.buffer_nvmap_handle); - MakeGraphicBuffer(producer, 1, session.buffer_nvmap_handle); + std::shared_ptr<android::BufferQueueProducer> producer; + R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), session.layer_id)); + MakeGraphicBuffer(*producer, 0, session.buffer_nvmap_handle); + MakeGraphicBuffer(*producer, 1, session.buffer_nvmap_handle); // Assign outputs. *out_buffer_id = m_buffer_id; @@ -269,7 +269,7 @@ Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou R_SUCCEED(); } -void FbShareBufferManager::Finalize(Kernel::KProcess* owner_process) { +void SharedBufferManager::DestroySession(Kernel::KProcess* owner_process) { std::scoped_lock lk{m_guard}; if (m_buffer_id == 0) { @@ -285,7 +285,7 @@ void FbShareBufferManager::Finalize(Kernel::KProcess* owner_process) { auto& session = it->second; // Destroy the layer. - m_flinger.DestroyLayer(session.layer_id); + m_container.DestroyStrayLayer(session.layer_id); // Close nvmap handle. FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd); @@ -301,11 +301,11 @@ void FbShareBufferManager::Finalize(Kernel::KProcess* owner_process) { m_sessions.erase(it); } -Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, - s32* out_nvmap_handle, - SharedMemoryPoolLayout* out_pool_layout, - u64 buffer_id, - u64 applet_resource_user_id) { +Result SharedBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, + s32* out_nvmap_handle, + SharedMemoryPoolLayout* out_pool_layout, + u64 buffer_id, + u64 applet_resource_user_id) { std::scoped_lock lk{m_guard}; R_UNLESS(m_buffer_id > 0, VI::ResultNotFound); @@ -319,36 +319,18 @@ Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, R_SUCCEED(); } -Result FbShareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) { - // Ensure the layer id is valid. - R_UNLESS(layer_id > 0, VI::ResultNotFound); - - // Get the layer. - VI::Layer* layer = m_flinger.FindLayer(m_display_id, layer_id); - R_UNLESS(layer != nullptr, VI::ResultNotFound); - - // We succeeded. - *out_layer = layer; - R_SUCCEED(); -} - -Result FbShareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence, - std::array<s32, 4>& out_slot_indexes, - s64* out_target_slot, u64 layer_id) { - std::scoped_lock lk{m_guard}; - - // Get the layer. - VI::Layer* layer; - R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); - +Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence, + std::array<s32, 4>& out_slot_indexes, + s64* out_target_slot, u64 layer_id) { // Get the producer. - auto& producer = layer->GetBufferQueue(); + std::shared_ptr<android::BufferQueueProducer> producer; + R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); // Get the next buffer from the producer. s32 slot; - R_UNLESS(producer.DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0, - SharedBufferWidth, SharedBufferHeight, - SharedBufferBlockLinearFormat, 0) == android::Status::NoError, + R_UNLESS(producer->DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0, + SharedBufferWidth, SharedBufferHeight, + SharedBufferBlockLinearFormat, 0) == android::Status::NoError, VI::ResultOperationFailed); // Assign remaining outputs. @@ -359,27 +341,22 @@ Result FbShareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence, R_SUCCEED(); } -Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence, - Common::Rectangle<s32> crop_region, - u32 transform, s32 swap_interval, - u64 layer_id, s64 slot) { - std::scoped_lock lk{m_guard}; - - // Get the layer. - VI::Layer* layer; - R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); - +Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence, + Common::Rectangle<s32> crop_region, + u32 transform, s32 swap_interval, u64 layer_id, + s64 slot) { // Get the producer. - auto& producer = layer->GetBufferQueue(); + std::shared_ptr<android::BufferQueueProducer> producer; + R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); // Request to queue the buffer. std::shared_ptr<android::GraphicBuffer> buffer; - R_UNLESS(producer.RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) == + R_UNLESS(producer->RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) == android::Status::NoError, VI::ResultOperationFailed); ON_RESULT_FAILURE { - producer.CancelBuffer(static_cast<s32>(slot), fence); + producer->CancelBuffer(static_cast<s32>(slot), fence); }; // Queue the buffer to the producer. @@ -389,7 +366,7 @@ Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence, input.fence = fence; input.transform = static_cast<android::NativeWindowTransform>(transform); input.swap_interval = swap_interval; - R_UNLESS(producer.QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) == + R_UNLESS(producer->QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) == android::Status::NoError, VI::ResultOperationFailed); @@ -397,25 +374,32 @@ Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence, R_SUCCEED(); } -Result FbShareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, - u64 layer_id) { - std::scoped_lock lk{m_guard}; +Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) { + // Get the producer. + std::shared_ptr<android::BufferQueueProducer> producer; + R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); - // Get the layer. - VI::Layer* layer; - R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); + // Cancel. + producer->CancelBuffer(static_cast<s32>(slot), android::Fence::NoFence()); + + // We succeeded. + R_SUCCEED(); +} +Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, + u64 layer_id) { // Get the producer. - auto& producer = layer->GetBufferQueue(); + std::shared_ptr<android::BufferQueueProducer> producer; + R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); // Set the event. - *out_event = std::addressof(producer.GetNativeHandle()); + *out_event = producer->GetNativeHandle({}); // We succeeded. R_SUCCEED(); } -Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) { +Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) { std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer()); Common::ScratchBuffer<u32> scratch; @@ -444,4 +428,4 @@ Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32 R_SUCCEED(); } -} // namespace Service::Nvnflinger +} // namespace Service::VI diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h b/src/core/hle/service/vi/shared_buffer_manager.h index b79a7d23a..7c9bb7199 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h +++ b/src/core/hle/service/vi/shared_buffer_manager.h @@ -8,15 +8,27 @@ #include "common/math_util.h" #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/nvdata.h" -#include "core/hle/service/nvnflinger/hwc_layer.h" #include "core/hle/service/nvnflinger/nvnflinger.h" #include "core/hle/service/nvnflinger/ui/fence.h" namespace Kernel { class KPageGroup; +class KReadableEvent; +} // namespace Kernel + +namespace Service::android { +class BufferQueueProducer; +} + +namespace Service::Nvidia { +class Module; } -namespace Service::Nvnflinger { +union Result; + +namespace Service::VI { + +class Container; struct SharedMemorySlot { u64 buffer_offset; @@ -32,17 +44,17 @@ struct SharedMemoryPoolLayout { }; static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size"); -struct FbShareSession; +struct SharedBufferSession; -class FbShareBufferManager final { +class SharedBufferManager final { public: - explicit FbShareBufferManager(Core::System& system, Nvnflinger& flinger, - std::shared_ptr<Nvidia::Module> nvdrv); - ~FbShareBufferManager(); + explicit SharedBufferManager(Core::System& system, Container& container, + std::shared_ptr<Nvidia::Module> nvdrv); + ~SharedBufferManager(); - Result Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle, - u64 display_id, LayerBlending blending); - void Finalize(Kernel::KProcess* owner_process); + Result CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle, + u64 display_id, bool enable_blending); + void DestroySession(Kernel::KProcess* owner_process); Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle, SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id, @@ -51,32 +63,30 @@ public: s64* out_target_slot, u64 layer_id); Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region, u32 transform, s32 swap_interval, u64 layer_id, s64 slot); + Result CancelSharedFrameBuffer(u64 layer_id, s64 slot); Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id); Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index); private: - Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id); - -private: u64 m_next_buffer_id = 1; u64 m_display_id = 0; u64 m_buffer_id = 0; SharedMemoryPoolLayout m_pool_layout = {}; - std::map<u64, FbShareSession> m_sessions; + std::map<u64, SharedBufferSession> m_sessions; std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group; std::mutex m_guard; Core::System& m_system; - Nvnflinger& m_flinger; - std::shared_ptr<Nvidia::Module> m_nvdrv; + Container& m_container; + const std::shared_ptr<Nvidia::Module> m_nvdrv; }; -struct FbShareSession { +struct SharedBufferSession { Nvidia::DeviceFD nvmap_fd = {}; Nvidia::NvCore::SessionId session_id = {}; u64 layer_id = {}; u32 buffer_nvmap_handle = 0; }; -} // namespace Service::Nvnflinger +} // namespace Service::VI |