diff options
-rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/core/hle/service/nvflinger/consumer_base.cpp | 129 | ||||
-rw-r--r-- | src/core/hle/service/nvflinger/consumer_base.h | 59 |
3 files changed, 190 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index fd2777b11..44d6b3cf7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -542,6 +542,8 @@ add_library(core STATIC hle/service/nvflinger/buffer_queue_defs.h hle/service/nvflinger/buffer_slot.h hle/service/nvflinger/buffer_transform_flags.h + hle/service/nvflinger/consumer_base.cpp + hle/service/nvflinger/consumer_base.h hle/service/nvflinger/consumer_listener.h hle/service/nvflinger/nvflinger.cpp hle/service/nvflinger/nvflinger.h diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvflinger/consumer_base.cpp new file mode 100644 index 000000000..127e5930b --- /dev/null +++ b/src/core/hle/service/nvflinger/consumer_base.cpp @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2010 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/ConsumerBase.cpp + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/hle/service/nvflinger/buffer_item.h" +#include "core/hle/service/nvflinger/buffer_queue_consumer.h" +#include "core/hle/service/nvflinger/buffer_queue_core.h" +#include "core/hle/service/nvflinger/consumer_base.h" +#include "core/hle/service/nvflinger/ui/graphic_buffer.h" + +namespace android { + +ConsumerBase::ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_) + : consumer{std::move(consumer_)} {} + +ConsumerBase::~ConsumerBase() { + std::unique_lock lock(mutex); + + ASSERT_MSG(is_abandoned, "consumer is not abandoned!"); +} + +void ConsumerBase::Connect(bool controlled_by_app) { + consumer->Connect(shared_from_this(), controlled_by_app); +} + +void ConsumerBase::FreeBufferLocked(s32 slot_index) { + LOG_DEBUG(Service_NVFlinger, "slot_index={}", slot_index); + + slots[slot_index].graphic_buffer = nullptr; + slots[slot_index].fence = Fence::NoFence(); + slots[slot_index].frame_number = 0; +} + +void ConsumerBase::OnFrameAvailable(const BufferItem& item) { + std::unique_lock lock(mutex); + LOG_DEBUG(Service_NVFlinger, "called"); +} + +void ConsumerBase::OnFrameReplaced(const BufferItem& item) { + std::unique_lock lock(mutex); + LOG_DEBUG(Service_NVFlinger, "called"); +} + +void ConsumerBase::OnBuffersReleased() { + std::unique_lock lock(mutex); + LOG_DEBUG(Service_NVFlinger, "called"); +} + +void ConsumerBase::OnSidebandStreamChanged() {} + +Status ConsumerBase::AcquireBufferLocked(BufferItem* item, u64 present_when_ns, + u64 max_frame_number) { + if (is_abandoned) { + LOG_ERROR(Service_NVFlinger, "consumer is abandoned!"); + return Status::NoInit; + } + + Status err = consumer->AcquireBuffer(item, present_when_ns, max_frame_number); + if (err != Status::NoError) { + return err; + } + + if (item->graphic_buffer != nullptr) { + if (slots[item->slot].graphic_buffer != nullptr) { + FreeBufferLocked(item->slot); + } + slots[item->slot].graphic_buffer = item->graphic_buffer; + } + + slots[item->slot].frame_number = item->frame_number; + slots[item->slot].fence = item->fence; + + LOG_DEBUG(Service_NVFlinger, "slot={}", item->slot); + + return Status::NoError; +} + +Status ConsumerBase::AddReleaseFenceLocked(s32 slot, + const std::shared_ptr<GraphicBuffer> graphic_buffer, + const Fence& fence) { + LOG_DEBUG(Service_NVFlinger, "slot={}", slot); + + // If consumer no longer tracks this graphic_buffer, we can safely + // drop this fence, as it will never be received by the producer. + + if (!StillTracking(slot, graphic_buffer)) { + return Status::NoError; + } + + slots[slot].fence = fence; + + return Status::NoError; +} + +Status ConsumerBase::ReleaseBufferLocked(s32 slot, + const std::shared_ptr<GraphicBuffer> graphic_buffer) { + // If consumer no longer tracks this graphic_buffer (we received a new + // buffer on the same slot), the buffer producer is definitely no longer + // tracking it. + + if (!StillTracking(slot, graphic_buffer)) { + return Status::NoError; + } + + LOG_DEBUG(Service_NVFlinger, "slot={}", slot); + Status err = consumer->ReleaseBuffer(slot, slots[slot].frame_number, slots[slot].fence); + if (err == Status::StaleBufferSlot) { + FreeBufferLocked(slot); + } + + slots[slot].fence = Fence::NoFence(); + + return err; +} + +bool ConsumerBase::StillTracking(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer) { + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { + return false; + } + + return (slots[slot].graphic_buffer != nullptr && + slots[slot].graphic_buffer->Handle() == graphic_buffer->Handle()); +} + +} // namespace android diff --git a/src/core/hle/service/nvflinger/consumer_base.h b/src/core/hle/service/nvflinger/consumer_base.h new file mode 100644 index 000000000..574ea9781 --- /dev/null +++ b/src/core/hle/service/nvflinger/consumer_base.h @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2010 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/ConsumerBase.h + +#pragma once + +#include <array> +#include <memory> +#include <mutex> + +#include "common/common_types.h" +#include "core/hle/service/nvflinger/buffer_queue_defs.h" +#include "core/hle/service/nvflinger/consumer_listener.h" +#include "core/hle/service/nvflinger/status.h" + +namespace android { + +class BufferItem; +class BufferQueueConsumer; + +class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this<ConsumerBase> { +public: + void Connect(bool controlled_by_app); + +protected: + ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_); + virtual ~ConsumerBase(); + + virtual void OnFrameAvailable(const BufferItem& item) override; + virtual void OnFrameReplaced(const BufferItem& item) override; + virtual void OnBuffersReleased() override; + virtual void OnSidebandStreamChanged() override; + + void FreeBufferLocked(s32 slot_index); + Status AcquireBufferLocked(BufferItem* item, u64 present_when_ns, u64 max_frame_number = 0); + Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer); + bool StillTracking(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer); + Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer, + const Fence& fence); + + struct Slot final { + std::shared_ptr<GraphicBuffer> graphic_buffer; + Fence fence; + u64 frame_number{}; + }; + +protected: + std::array<Slot, BufferQueueDefs::NUM_BUFFER_SLOTS> slots; + + bool is_abandoned{}; + + std::unique_ptr<BufferQueueConsumer> consumer; + + mutable std::mutex mutex; +}; + +} // namespace android |