diff options
Diffstat (limited to 'src/core/hle/service/nvflinger')
29 files changed, 0 insertions, 3040 deletions
diff --git a/src/core/hle/service/nvflinger/binder.h b/src/core/hle/service/nvflinger/binder.h deleted file mode 100644 index aef1477e3..000000000 --- a/src/core/hle/service/nvflinger/binder.h +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2014 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/binder/IBinder.h - -#pragma once - -#include "common/common_types.h" - -namespace Kernel { -class KReadableEvent; -} // namespace Kernel - -namespace Service { -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(HLERequestContext& ctx, android::TransactionId code, u32 flags) = 0; - virtual Kernel::KReadableEvent& GetNativeHandle() = 0; -}; - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_item.h b/src/core/hle/service/nvflinger/buffer_item.h deleted file mode 100644 index f73dec4f1..000000000 --- a/src/core/hle/service/nvflinger/buffer_item.h +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2014 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferItem.h - -#pragma once - -#include <memory> - -#include "common/common_types.h" -#include "common/math_util.h" -#include "core/hle/service/nvflinger/ui/fence.h" -#include "core/hle/service/nvflinger/window.h" - -namespace Service::android { - -class GraphicBuffer; - -class BufferItem final { -public: - constexpr BufferItem() = default; - - std::shared_ptr<GraphicBuffer> graphic_buffer; - Fence fence; - Common::Rectangle<s32> crop; - NativeWindowTransform transform{}; - u32 scaling_mode{}; - s64 timestamp{}; - bool is_auto_timestamp{}; - u64 frame_number{}; - - // The default value for buf, used to indicate this doesn't correspond to a slot. - static constexpr s32 INVALID_BUFFER_SLOT = -1; - union { - s32 slot{INVALID_BUFFER_SLOT}; - s32 buf; - }; - - bool is_droppable{}; - bool acquire_called{}; - bool transform_to_display_inverse{}; - s32 swap_interval{}; -}; - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp deleted file mode 100644 index 152bb5bdf..000000000 --- a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2012 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferItemConsumer.cpp - -#include "common/assert.h" -#include "common/logging/log.h" -#include "core/hle/service/nvflinger/buffer_item.h" -#include "core/hle/service/nvflinger/buffer_item_consumer.h" -#include "core/hle/service/nvflinger/buffer_queue_consumer.h" - -namespace Service::android { - -BufferItemConsumer::BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer_) - : ConsumerBase{std::move(consumer_)} {} - -Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, - bool wait_for_fence) { - if (!item) { - return Status::BadValue; - } - - std::scoped_lock lock{mutex}; - - if (const auto status = AcquireBufferLocked(item, present_when); status != Status::NoError) { - if (status != Status::NoBufferAvailable) { - LOG_ERROR(Service_NVFlinger, "Failed to acquire buffer: {}", status); - } - return status; - } - - if (wait_for_fence) { - UNIMPLEMENTED(); - } - - item->graphic_buffer = slots[item->slot].graphic_buffer; - - return Status::NoError; -} - -Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, const Fence& release_fence) { - std::scoped_lock lock{mutex}; - - if (const auto status = AddReleaseFenceLocked(item.buf, item.graphic_buffer, release_fence); - status != Status::NoError) { - LOG_ERROR(Service_NVFlinger, "Failed to add fence: {}", status); - } - - if (const auto status = ReleaseBufferLocked(item.buf, item.graphic_buffer); - status != Status::NoError) { - LOG_WARNING(Service_NVFlinger, "Failed to release buffer: {}", status); - return status; - } - - return Status::NoError; -} - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.h b/src/core/hle/service/nvflinger/buffer_item_consumer.h deleted file mode 100644 index a5c655d9e..000000000 --- a/src/core/hle/service/nvflinger/buffer_item_consumer.h +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2012 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferItemConsumer.h - -#pragma once - -#include <chrono> -#include <memory> - -#include "common/common_types.h" -#include "core/hle/service/nvflinger/consumer_base.h" -#include "core/hle/service/nvflinger/status.h" - -namespace Service::android { - -class BufferItem; - -class BufferItemConsumer final : public ConsumerBase { -public: - explicit BufferItemConsumer(std::unique_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); -}; - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp deleted file mode 100644 index 0767e548d..000000000 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp +++ /dev/null @@ -1,213 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2014 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// 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/logging/log.h" -#include "core/hle/service/nvdrv/core/nvmap.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/producer_listener.h" -#include "core/hle/service/nvflinger/ui/graphic_buffer.h" - -namespace Service::android { - -BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_, - Service::Nvidia::NvCore::NvMap& nvmap_) - : core{std::move(core_)}, slots{core->slots}, nvmap(nvmap_) {} - -BufferQueueConsumer::~BufferQueueConsumer() = default; - -Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, - std::chrono::nanoseconds expected_present) { - std::scoped_lock lock{core->mutex}; - - // Check that the consumer doesn't currently have the maximum number of buffers acquired. - const s32 num_acquired_buffers{ - static_cast<s32>(std::count_if(slots.begin(), slots.end(), [](const auto& slot) { - return slot.buffer_state == BufferState::Acquired; - }))}; - - if (num_acquired_buffers >= core->max_acquired_buffer_count + 1) { - LOG_ERROR(Service_NVFlinger, "max acquired buffer count reached: {} (max {})", - num_acquired_buffers, core->max_acquired_buffer_count); - return Status::InvalidOperation; - } - - // Check if the queue is empty. - if (core->queue.empty()) { - return Status::NoBufferAvailable; - } - - auto front(core->queue.begin()); - - // If expected_present is specified, we may not want to return a buffer yet. - if (expected_present.count() != 0) { - constexpr auto MAX_REASONABLE_NSEC = 1000000000LL; // 1 second - - // The expected_present argument indicates when the buffer is expected to be presented - // on-screen. - while (core->queue.size() > 1 && !core->queue[0].is_auto_timestamp) { - const auto& buffer_item{core->queue[1]}; - - // If entry[1] is timely, drop entry[0] (and repeat). - const auto desired_present = buffer_item.timestamp; - if (desired_present < expected_present.count() - MAX_REASONABLE_NSEC || - desired_present > expected_present.count()) { - // This buffer is set to display in the near future, or desired_present is garbage. - LOG_DEBUG(Service_NVFlinger, "nodrop desire={} expect={}", desired_present, - expected_present.count()); - break; - } - - LOG_DEBUG(Service_NVFlinger, "drop desire={} expect={} size={}", desired_present, - expected_present.count(), core->queue.size()); - - if (core->StillTracking(*front)) { - // Front buffer is still in mSlots, so mark the slot as free - slots[front->slot].buffer_state = BufferState::Free; - } - - core->queue.erase(front); - front = core->queue.begin(); - } - - // See if the front buffer is ready to be acquired. - const auto desired_present = front->timestamp; - if (desired_present > expected_present.count() && - desired_present < expected_present.count() + MAX_REASONABLE_NSEC) { - LOG_DEBUG(Service_NVFlinger, "defer desire={} expect={}", desired_present, - expected_present.count()); - return Status::PresentLater; - } - - LOG_DEBUG(Service_NVFlinger, "accept desire={} expect={}", desired_present, - expected_present.count()); - } - - const auto slot = front->slot; - *out_buffer = *front; - - LOG_DEBUG(Service_NVFlinger, "acquiring slot={}", slot); - - // If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr to - // avoid unnecessarily remapping this buffer on the consumer side. - if (out_buffer->acquire_called) { - out_buffer->graphic_buffer = nullptr; - } - - core->queue.erase(front); - - // We might have freed a slot while dropping old buffers, or the producer may be blocked - // waiting for the number of buffers in the queue to decrease. - core->SignalDequeueCondition(); - - return Status::NoError; -} - -Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence) { - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - LOG_ERROR(Service_NVFlinger, "slot {} out of range", slot); - return Status::BadValue; - } - - std::shared_ptr<IProducerListener> listener; - { - std::scoped_lock lock{core->mutex}; - - // If the frame number has changed because the buffer has been reallocated, we can ignore - // this ReleaseBuffer for the old buffer. - if (frame_number != slots[slot].frame_number) { - return Status::StaleBufferSlot; - } - - // Make sure this buffer hasn't been queued while acquired by the consumer. - auto current(core->queue.begin()); - while (current != core->queue.end()) { - if (current->slot == slot) { - LOG_ERROR(Service_NVFlinger, "buffer slot {} pending release is currently queued", - slot); - return Status::BadValue; - } - ++current; - } - - slots[slot].buffer_state = BufferState::Free; - - nvmap.FreeHandle(slots[slot].graphic_buffer->BufferId(), true); - - listener = core->connected_producer_listener; - - LOG_DEBUG(Service_NVFlinger, "releasing slot {}", slot); - - core->SignalDequeueCondition(); - } - - // Call back without lock held - if (listener != nullptr) { - listener->OnBufferReleased(); - } - - return Status::NoError; -} - -Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_listener, - bool controlled_by_app) { - if (consumer_listener == nullptr) { - LOG_ERROR(Service_NVFlinger, "consumer_listener may not be nullptr"); - return Status::BadValue; - } - - LOG_DEBUG(Service_NVFlinger, "controlled_by_app={}", controlled_by_app); - - std::scoped_lock lock{core->mutex}; - - if (core->is_abandoned) { - LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); - return Status::NoInit; - } - - core->consumer_listener = std::move(consumer_listener); - core->consumer_controlled_by_app = controlled_by_app; - - return Status::NoError; -} - -Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) { - if (out_slot_mask == nullptr) { - LOG_ERROR(Service_NVFlinger, "out_slot_mask may not be nullptr"); - return Status::BadValue; - } - - std::scoped_lock lock{core->mutex}; - - if (core->is_abandoned) { - LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); - return Status::NoInit; - } - - u64 mask = 0; - for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (!slots[s].acquire_called) { - mask |= (1ULL << s); - } - } - - // Remove from the mask queued buffers for which acquire has been called, since the consumer - // will not receive their buffer addresses and so must retain their cached information - auto current(core->queue.begin()); - while (current != core->queue.end()) { - if (current->acquire_called) { - mask &= ~(1ULL << current->slot); - } - ++current; - } - - LOG_DEBUG(Service_NVFlinger, "returning mask {}", mask); - *out_slot_mask = mask; - return Status::NoError; -} - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.h b/src/core/hle/service/nvflinger/buffer_queue_consumer.h deleted file mode 100644 index 4ec06ca13..000000000 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.h +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2014 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueConsumer.h - -#pragma once - -#include <chrono> -#include <memory> - -#include "common/common_types.h" -#include "core/hle/service/nvflinger/buffer_queue_defs.h" -#include "core/hle/service/nvflinger/status.h" - -namespace Service::Nvidia::NvCore { -class NvMap; -} // namespace Service::Nvidia::NvCore - -namespace Service::android { - -class BufferItem; -class BufferQueueCore; -class IConsumerListener; - -class BufferQueueConsumer final { -public: - explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_, - Service::Nvidia::NvCore::NvMap& nvmap_); - ~BufferQueueConsumer(); - - Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present); - Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence); - Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app); - Status GetReleasedBuffers(u64* out_slot_mask); - -private: - std::shared_ptr<BufferQueueCore> core; - BufferQueueDefs::SlotsType& slots; - Service::Nvidia::NvCore::NvMap& nvmap; -}; - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp deleted file mode 100644 index 3d1338e66..000000000 --- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2014 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueCore.cpp - -#include "common/assert.h" - -#include "core/hle/service/nvflinger/buffer_queue_core.h" - -namespace Service::android { - -BufferQueueCore::BufferQueueCore() = default; - -BufferQueueCore::~BufferQueueCore() = default; - -void BufferQueueCore::NotifyShutdown() { - std::scoped_lock lock{mutex}; - - is_shutting_down = true; - - SignalDequeueCondition(); -} - -void BufferQueueCore::SignalDequeueCondition() { - dequeue_possible.store(true); - dequeue_condition.notify_all(); -} - -bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) { - if (is_shutting_down) { - return false; - } - - dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); }); - dequeue_possible.store(false); - - return true; -} - -s32 BufferQueueCore::GetMinUndequeuedBufferCountLocked(bool async) const { - // If DequeueBuffer is allowed to error out, we don't have to add an extra buffer. - if (!use_async_buffer) { - return max_acquired_buffer_count; - } - - if (dequeue_buffer_cannot_block || async) { - return max_acquired_buffer_count + 1; - } - - return max_acquired_buffer_count; -} - -s32 BufferQueueCore::GetMinMaxBufferCountLocked(bool async) const { - return GetMinUndequeuedBufferCountLocked(async) + 1; -} - -s32 BufferQueueCore::GetMaxBufferCountLocked(bool async) const { - const auto min_buffer_count = GetMinMaxBufferCountLocked(async); - auto max_buffer_count = std::max(default_max_buffer_count, min_buffer_count); - - if (override_max_buffer_count != 0) { - ASSERT(override_max_buffer_count >= min_buffer_count); - max_buffer_count = override_max_buffer_count; - } - - // Any buffers that are dequeued by the producer or sitting in the queue waiting to be consumed - // need to have their slots preserved. - for (s32 slot = max_buffer_count; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { - const auto state = slots[slot].buffer_state; - if (state == BufferState::Queued || state == BufferState::Dequeued) { - max_buffer_count = slot + 1; - } - } - - return max_buffer_count; -} - -s32 BufferQueueCore::GetPreallocatedBufferCountLocked() const { - return static_cast<s32>(std::count_if(slots.begin(), slots.end(), - [](const auto& slot) { return slot.is_preallocated; })); -} - -void BufferQueueCore::FreeBufferLocked(s32 slot) { - LOG_DEBUG(Service_NVFlinger, "slot {}", slot); - - slots[slot].graphic_buffer.reset(); - - slots[slot].buffer_state = BufferState::Free; - slots[slot].frame_number = UINT32_MAX; - slots[slot].acquire_called = false; - slots[slot].fence = Fence::NoFence(); -} - -void BufferQueueCore::FreeAllBuffersLocked() { - buffer_has_been_queued = false; - - for (s32 slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { - FreeBufferLocked(slot); - } -} - -bool BufferQueueCore::StillTracking(const BufferItem& item) const { - const BufferSlot& slot = slots[item.slot]; - - return (slot.graphic_buffer != nullptr) && (item.graphic_buffer == slot.graphic_buffer); -} - -void BufferQueueCore::WaitWhileAllocatingLocked() const { - while (is_allocating) { - is_allocating_condition.wait(mutex); - } -} - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h deleted file mode 100644 index 85b3bc4c1..000000000 --- a/src/core/hle/service/nvflinger/buffer_queue_core.h +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2014 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueCore.h - -#pragma once - -#include <condition_variable> -#include <list> -#include <memory> -#include <mutex> -#include <set> -#include <vector> - -#include "core/hle/service/nvflinger/buffer_item.h" -#include "core/hle/service/nvflinger/buffer_queue_defs.h" -#include "core/hle/service/nvflinger/pixel_format.h" -#include "core/hle/service/nvflinger/status.h" -#include "core/hle/service/nvflinger/window.h" - -namespace Service::android { - -class IConsumerListener; -class IProducerListener; - -class BufferQueueCore final { - friend class BufferQueueProducer; - friend class BufferQueueConsumer; - -public: - static constexpr s32 INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT; - - BufferQueueCore(); - ~BufferQueueCore(); - - void NotifyShutdown(); - -private: - void SignalDequeueCondition(); - bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk); - - s32 GetMinUndequeuedBufferCountLocked(bool async) const; - s32 GetMinMaxBufferCountLocked(bool async) const; - s32 GetMaxBufferCountLocked(bool async) const; - s32 GetPreallocatedBufferCountLocked() const; - void FreeBufferLocked(s32 slot); - void FreeAllBuffersLocked(); - bool StillTracking(const BufferItem& item) const; - void WaitWhileAllocatingLocked() const; - -private: - mutable std::mutex mutex; - bool is_abandoned{}; - bool consumer_controlled_by_app{}; - std::shared_ptr<IConsumerListener> consumer_listener; - u32 consumer_usage_bit{}; - NativeWindowApi connected_api{NativeWindowApi::NoConnectedApi}; - std::shared_ptr<IProducerListener> connected_producer_listener; - BufferQueueDefs::SlotsType slots{}; - std::vector<BufferItem> queue; - s32 override_max_buffer_count{}; - std::condition_variable dequeue_condition; - std::atomic<bool> dequeue_possible{}; - const bool use_async_buffer{}; // This is always disabled on HOS - bool dequeue_buffer_cannot_block{}; - PixelFormat default_buffer_format{PixelFormat::Rgba8888}; - u32 default_width{1}; - u32 default_height{1}; - s32 default_max_buffer_count{2}; - const s32 max_acquired_buffer_count{}; // This is always zero on HOS - bool buffer_has_been_queued{}; - u64 frame_counter{}; - u32 transform_hint{}; - bool is_allocating{}; - mutable std::condition_variable_any is_allocating_condition; - bool is_shutting_down{}; -}; - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_defs.h b/src/core/hle/service/nvflinger/buffer_queue_defs.h deleted file mode 100644 index 334445213..000000000 --- a/src/core/hle/service/nvflinger/buffer_queue_defs.h +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2014 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueDefs.h - -#pragma once - -#include <array> - -#include "common/common_types.h" -#include "core/hle/service/nvflinger/buffer_slot.h" - -namespace Service::android::BufferQueueDefs { - -// BufferQueue will keep track of at most this value of buffers. -constexpr s32 NUM_BUFFER_SLOTS = 64; - -using SlotsType = std::array<BufferSlot, NUM_BUFFER_SLOTS>; - -} // namespace Service::android::BufferQueueDefs diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp deleted file mode 100644 index ad73edd66..000000000 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ /dev/null @@ -1,933 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2014 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueProducer.cpp - -#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/nvdrv/core/nvmap.h" -#include "core/hle/service/nvflinger/buffer_queue_core.h" -#include "core/hle/service/nvflinger/buffer_queue_producer.h" -#include "core/hle/service/nvflinger/consumer_listener.h" -#include "core/hle/service/nvflinger/parcel.h" -#include "core/hle/service/nvflinger/ui/graphic_buffer.h" -#include "core/hle/service/nvflinger/window.h" -#include "core/hle/service/vi/vi.h" - -namespace Service::android { - -BufferQueueProducer::BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_, - std::shared_ptr<BufferQueueCore> buffer_queue_core_, - Service::Nvidia::NvCore::NvMap& nvmap_) - : service_context{service_context_}, core{std::move(buffer_queue_core_)}, slots(core->slots), - nvmap(nvmap_) { - buffer_wait_event = service_context.CreateEvent("BufferQueue:WaitEvent"); -} - -BufferQueueProducer::~BufferQueueProducer() { - service_context.CloseEvent(buffer_wait_event); -} - -Status BufferQueueProducer::RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf) { - LOG_DEBUG(Service_NVFlinger, "slot {}", slot); - - std::scoped_lock lock{core->mutex}; - - if (core->is_abandoned) { - LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); - return Status::NoInit; - } - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot, - BufferQueueDefs::NUM_BUFFER_SLOTS); - return Status::BadValue; - } else if (slots[slot].buffer_state != BufferState::Dequeued) { - LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot, - slots[slot].buffer_state); - return Status::BadValue; - } - - slots[slot].request_buffer_called = true; - *buf = slots[slot].graphic_buffer; - - return Status::NoError; -} - -Status BufferQueueProducer::SetBufferCount(s32 buffer_count) { - LOG_DEBUG(Service_NVFlinger, "count = {}", buffer_count); - - std::shared_ptr<IConsumerListener> listener; - { - std::scoped_lock lock{core->mutex}; - core->WaitWhileAllocatingLocked(); - - if (core->is_abandoned) { - LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); - return Status::NoInit; - } - - if (buffer_count > BufferQueueDefs::NUM_BUFFER_SLOTS) { - LOG_ERROR(Service_NVFlinger, "buffer_count {} too large (max {})", buffer_count, - BufferQueueDefs::NUM_BUFFER_SLOTS); - return Status::BadValue; - } - - // There must be no dequeued buffers when changing the buffer count. - for (s32 s{}; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (slots[s].buffer_state == BufferState::Dequeued) { - LOG_ERROR(Service_NVFlinger, "buffer owned by producer"); - return Status::BadValue; - } - } - - if (buffer_count == 0) { - core->override_max_buffer_count = 0; - core->SignalDequeueCondition(); - return Status::NoError; - } - - const s32 min_buffer_slots = core->GetMinMaxBufferCountLocked(false); - if (buffer_count < min_buffer_slots) { - LOG_ERROR(Service_NVFlinger, "requested buffer count {} is less than minimum {}", - buffer_count, min_buffer_slots); - return Status::BadValue; - } - - // Here we are guaranteed that the producer doesn't have any dequeued buffers and will - // release all of its buffer references. - if (core->GetPreallocatedBufferCountLocked() <= 0) { - core->FreeAllBuffersLocked(); - } - - core->override_max_buffer_count = buffer_count; - core->SignalDequeueCondition(); - buffer_wait_event->Signal(); - listener = core->consumer_listener; - } - - // Call back without lock held - if (listener != nullptr) { - listener->OnBuffersReleased(); - } - - return Status::NoError; -} - -Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags, - std::unique_lock<std::mutex>& lk) const { - bool try_again = true; - - while (try_again) { - if (core->is_abandoned) { - LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); - return Status::NoInit; - } - - const s32 max_buffer_count = core->GetMaxBufferCountLocked(async); - if (async && core->override_max_buffer_count) { - if (core->override_max_buffer_count < max_buffer_count) { - LOG_ERROR(Service_NVFlinger, "async mode is invalid with buffer count override"); - return Status::BadValue; - } - } - - // Free up any buffers that are in slots beyond the max buffer count - for (s32 s = max_buffer_count; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - ASSERT(slots[s].buffer_state == BufferState::Free); - if (slots[s].graphic_buffer != nullptr) { - core->FreeBufferLocked(s); - *return_flags |= Status::ReleaseAllBuffers; - } - } - - // Look for a free buffer to give to the client - *found = BufferQueueCore::INVALID_BUFFER_SLOT; - s32 dequeued_count{}; - s32 acquired_count{}; - for (s32 s{}; s < max_buffer_count; ++s) { - switch (slots[s].buffer_state) { - case BufferState::Dequeued: - ++dequeued_count; - break; - case BufferState::Acquired: - ++acquired_count; - break; - case BufferState::Free: - // We return the oldest of the free buffers to avoid stalling the producer if - // possible, since the consumer may still have pending reads of in-flight buffers - if (*found == BufferQueueCore::INVALID_BUFFER_SLOT || - slots[s].frame_number < slots[*found].frame_number) { - *found = s; - } - break; - default: - break; - } - } - - // Producers are not allowed to dequeue more than one buffer if they did not set a buffer - // count - if (!core->override_max_buffer_count && dequeued_count) { - LOG_ERROR(Service_NVFlinger, - "can't dequeue multiple buffers without setting the buffer count"); - return Status::InvalidOperation; - } - - // See whether a buffer has been queued since the last SetBufferCount so we know whether to - // perform the min undequeued buffers check below - if (core->buffer_has_been_queued) { - // Make sure the producer is not trying to dequeue more buffers than allowed - const s32 new_undequeued_count = max_buffer_count - (dequeued_count + 1); - const s32 min_undequeued_count = core->GetMinUndequeuedBufferCountLocked(async); - if (new_undequeued_count < min_undequeued_count) { - LOG_ERROR(Service_NVFlinger, - "min undequeued buffer count({}) exceeded (dequeued={} undequeued={})", - min_undequeued_count, dequeued_count, new_undequeued_count); - return Status::InvalidOperation; - } - } - - // If we disconnect and reconnect quickly, we can be in a state where our slots are empty - // but we have many buffers in the queue. This can cause us to run out of memory if we - // outrun the consumer. Wait here if it looks like we have too many buffers queued up. - const bool too_many_buffers = core->queue.size() > static_cast<size_t>(max_buffer_count); - if (too_many_buffers) { - LOG_ERROR(Service_NVFlinger, "queue size is {}, waiting", core->queue.size()); - } - - // If no buffer is found, or if the queue has too many buffers outstanding, wait for a - // buffer to be acquired or released, or for the max buffer count to change. - try_again = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || too_many_buffers; - if (try_again) { - // Return an error if we're in non-blocking mode (producer and consumer are controlled - // by the application). - if (core->dequeue_buffer_cannot_block && - (acquired_count <= core->max_acquired_buffer_count)) { - return Status::WouldBlock; - } - - if (!core->WaitForDequeueCondition(lk)) { - // We are no longer running - return Status::NoError; - } - } - } - - return Status::NoError; -} - -Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool async, u32 width, - u32 height, PixelFormat format, u32 usage) { - LOG_DEBUG(Service_NVFlinger, "async={} w={} h={} format={}, usage={}", async ? "true" : "false", - width, height, format, usage); - - if ((width != 0 && height == 0) || (width == 0 && height != 0)) { - LOG_ERROR(Service_NVFlinger, "invalid size: w={} h={}", width, height); - return Status::BadValue; - } - - Status return_flags = Status::NoError; - bool attached_by_consumer = false; - { - std::unique_lock lock{core->mutex}; - core->WaitWhileAllocatingLocked(); - - if (format == PixelFormat::NoFormat) { - format = core->default_buffer_format; - } - - // Enable the usage bits the consumer requested - usage |= core->consumer_usage_bit; - - s32 found{}; - Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags, lock); - if (status != Status::NoError) { - return status; - } - - // This should not happen - if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { - LOG_ERROR(Service_NVFlinger, "no available buffer slots"); - return Status::Busy; - } - - *out_slot = found; - - attached_by_consumer = slots[found].attached_by_consumer; - - const bool use_default_size = !width && !height; - if (use_default_size) { - width = core->default_width; - height = core->default_height; - } - - slots[found].buffer_state = BufferState::Dequeued; - - const std::shared_ptr<GraphicBuffer>& buffer(slots[found].graphic_buffer); - if ((buffer == nullptr) || (buffer->Width() != width) || (buffer->Height() != height) || - (buffer->Format() != format) || ((buffer->Usage() & usage) != usage)) { - slots[found].acquire_called = false; - slots[found].graphic_buffer = nullptr; - slots[found].request_buffer_called = false; - slots[found].fence = Fence::NoFence(); - - return_flags |= Status::BufferNeedsReallocation; - } - - *out_fence = slots[found].fence; - slots[found].fence = Fence::NoFence(); - } - - if ((return_flags & Status::BufferNeedsReallocation) != Status::None) { - LOG_DEBUG(Service_NVFlinger, "allocating a new buffer for slot {}", *out_slot); - - auto graphic_buffer = std::make_shared<GraphicBuffer>(width, height, format, usage); - if (graphic_buffer == nullptr) { - LOG_ERROR(Service_NVFlinger, "creating GraphicBuffer failed"); - return Status::NoMemory; - } - - { - std::scoped_lock lock{core->mutex}; - - if (core->is_abandoned) { - LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); - return Status::NoInit; - } - - slots[*out_slot].frame_number = UINT32_MAX; - slots[*out_slot].graphic_buffer = graphic_buffer; - } - } - - if (attached_by_consumer) { - return_flags |= Status::BufferNeedsReallocation; - } - - LOG_DEBUG(Service_NVFlinger, "returning slot={} frame={}, flags={}", *out_slot, - slots[*out_slot].frame_number, return_flags); - - return return_flags; -} - -Status BufferQueueProducer::DetachBuffer(s32 slot) { - LOG_DEBUG(Service_NVFlinger, "slot {}", slot); - - std::scoped_lock lock{core->mutex}; - - if (core->is_abandoned) { - LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); - return Status::NoInit; - } - - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - LOG_ERROR(Service_NVFlinger, "slot {} out of range [0, {})", slot, - BufferQueueDefs::NUM_BUFFER_SLOTS); - return Status::BadValue; - } else if (slots[slot].buffer_state != BufferState::Dequeued) { - LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot, - slots[slot].buffer_state); - return Status::BadValue; - } else if (!slots[slot].request_buffer_called) { - LOG_ERROR(Service_NVFlinger, "buffer in slot {} has not been requested", slot); - return Status::BadValue; - } - - core->FreeBufferLocked(slot); - core->SignalDequeueCondition(); - - return Status::NoError; -} - -Status BufferQueueProducer::DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out_buffer, - Fence* out_fence) { - if (out_buffer == nullptr) { - LOG_ERROR(Service_NVFlinger, "out_buffer must not be nullptr"); - return Status::BadValue; - } else if (out_fence == nullptr) { - LOG_ERROR(Service_NVFlinger, "out_fence must not be nullptr"); - return Status::BadValue; - } - - std::scoped_lock lock{core->mutex}; - core->WaitWhileAllocatingLocked(); - - if (core->is_abandoned) { - LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); - return Status::NoInit; - } - - // Find the oldest valid slot - int found = BufferQueueCore::INVALID_BUFFER_SLOT; - for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (slots[s].buffer_state == BufferState::Free && slots[s].graphic_buffer != nullptr) { - if (found == BufferQueueCore::INVALID_BUFFER_SLOT || - slots[s].frame_number < slots[found].frame_number) { - found = s; - } - } - } - - if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { - return Status::NoMemory; - } - - LOG_DEBUG(Service_NVFlinger, "Detached slot {}", found); - - *out_buffer = slots[found].graphic_buffer; - *out_fence = slots[found].fence; - - core->FreeBufferLocked(found); - - return Status::NoError; -} - -Status BufferQueueProducer::AttachBuffer(s32* out_slot, - const std::shared_ptr<GraphicBuffer>& buffer) { - if (out_slot == nullptr) { - LOG_ERROR(Service_NVFlinger, "out_slot must not be nullptr"); - return Status::BadValue; - } else if (buffer == nullptr) { - LOG_ERROR(Service_NVFlinger, "Cannot attach nullptr buffer"); - return Status::BadValue; - } - - std::unique_lock lock{core->mutex}; - core->WaitWhileAllocatingLocked(); - - Status return_flags = Status::NoError; - s32 found{}; - - const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags, lock); - if (status != Status::NoError) { - return status; - } - - // This should not happen - if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { - LOG_ERROR(Service_NVFlinger, "No available buffer slots"); - return Status::Busy; - } - - *out_slot = found; - - LOG_DEBUG(Service_NVFlinger, "Returning slot {} flags={}", *out_slot, return_flags); - - slots[*out_slot].graphic_buffer = buffer; - slots[*out_slot].buffer_state = BufferState::Dequeued; - slots[*out_slot].fence = Fence::NoFence(); - slots[*out_slot].request_buffer_called = true; - - return return_flags; -} - -Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input, - QueueBufferOutput* output) { - s64 timestamp{}; - bool is_auto_timestamp{}; - Common::Rectangle<s32> crop; - NativeWindowScalingMode scaling_mode{}; - NativeWindowTransform transform; - u32 sticky_transform_{}; - bool async{}; - s32 swap_interval{}; - Fence fence{}; - - input.Deflate(×tamp, &is_auto_timestamp, &crop, &scaling_mode, &transform, - &sticky_transform_, &async, &swap_interval, &fence); - - switch (scaling_mode) { - case NativeWindowScalingMode::Freeze: - case NativeWindowScalingMode::ScaleToWindow: - case NativeWindowScalingMode::ScaleCrop: - case NativeWindowScalingMode::NoScaleCrop: - break; - default: - LOG_ERROR(Service_NVFlinger, "unknown scaling mode {}", scaling_mode); - return Status::BadValue; - } - - std::shared_ptr<IConsumerListener> frame_available_listener; - std::shared_ptr<IConsumerListener> frame_replaced_listener; - s32 callback_ticket{}; - BufferItem item; - - { - std::scoped_lock lock{core->mutex}; - - if (core->is_abandoned) { - LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); - return Status::NoInit; - } - - const s32 max_buffer_count = core->GetMaxBufferCountLocked(async); - if (async && core->override_max_buffer_count) { - if (core->override_max_buffer_count < max_buffer_count) { - LOG_ERROR(Service_NVFlinger, "async mode is invalid with " - "buffer count override"); - return Status::BadValue; - } - } - - if (slot < 0 || slot >= max_buffer_count) { - LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot, - max_buffer_count); - return Status::BadValue; - } else if (slots[slot].buffer_state != BufferState::Dequeued) { - LOG_ERROR(Service_NVFlinger, - "slot {} is not owned by the producer " - "(state = {})", - slot, slots[slot].buffer_state); - return Status::BadValue; - } else if (!slots[slot].request_buffer_called) { - LOG_ERROR(Service_NVFlinger, - "slot {} was queued without requesting " - "a buffer", - slot); - return Status::BadValue; - } - - LOG_DEBUG(Service_NVFlinger, - "slot={} frame={} time={} crop=[{},{},{},{}] transform={} scale={}", slot, - core->frame_counter + 1, timestamp, crop.Left(), crop.Top(), crop.Right(), - crop.Bottom(), transform, scaling_mode); - - const std::shared_ptr<GraphicBuffer>& graphic_buffer(slots[slot].graphic_buffer); - Common::Rectangle<s32> buffer_rect(graphic_buffer->Width(), graphic_buffer->Height()); - Common::Rectangle<s32> cropped_rect; - [[maybe_unused]] const bool unused = crop.Intersect(buffer_rect, &cropped_rect); - - if (cropped_rect != crop) { - LOG_ERROR(Service_NVFlinger, "crop rect is not contained within the buffer in slot {}", - slot); - return Status::BadValue; - } - - slots[slot].fence = fence; - slots[slot].buffer_state = BufferState::Queued; - ++core->frame_counter; - slots[slot].frame_number = core->frame_counter; - - item.acquire_called = slots[slot].acquire_called; - item.graphic_buffer = slots[slot].graphic_buffer; - item.crop = crop; - item.transform = transform & ~NativeWindowTransform::InverseDisplay; - item.transform_to_display_inverse = - (transform & NativeWindowTransform::InverseDisplay) != NativeWindowTransform::None; - item.scaling_mode = static_cast<u32>(scaling_mode); - item.timestamp = timestamp; - item.is_auto_timestamp = is_auto_timestamp; - item.frame_number = core->frame_counter; - item.slot = slot; - item.fence = fence; - item.is_droppable = core->dequeue_buffer_cannot_block || async; - item.swap_interval = swap_interval; - - nvmap.DuplicateHandle(item.graphic_buffer->BufferId(), true); - - sticky_transform = sticky_transform_; - - if (core->queue.empty()) { - // When the queue is empty, we can simply queue this buffer - core->queue.push_back(item); - frame_available_listener = core->consumer_listener; - } else { - // When the queue is not empty, we need to look at the front buffer - // state to see if we need to replace it - auto front(core->queue.begin()); - - if (front->is_droppable) { - // If the front queued buffer is still being tracked, we first - // mark it as freed - if (core->StillTracking(*front)) { - slots[front->slot].buffer_state = BufferState::Free; - // Reset the frame number of the freed buffer so that it is the first in line to - // be dequeued again - slots[front->slot].frame_number = 0; - } - // Overwrite the droppable buffer with the incoming one - *front = item; - frame_replaced_listener = core->consumer_listener; - } else { - core->queue.push_back(item); - frame_available_listener = core->consumer_listener; - } - } - - core->buffer_has_been_queued = true; - core->SignalDequeueCondition(); - output->Inflate(core->default_width, core->default_height, core->transform_hint, - static_cast<u32>(core->queue.size())); - - // Take a ticket for the callback functions - callback_ticket = next_callback_ticket++; - } - - // Don't send the GraphicBuffer through the callback, and don't send the slot number, since the - // consumer shouldn't need it - item.graphic_buffer.reset(); - item.slot = BufferItem::INVALID_BUFFER_SLOT; - - // Call back without the main BufferQueue lock held, but with the callback lock held so we can - // ensure that callbacks occur in order - { - std::scoped_lock lock{callback_mutex}; - while (callback_ticket != current_callback_ticket) { - callback_condition.wait(callback_mutex); - } - - if (frame_available_listener != nullptr) { - frame_available_listener->OnFrameAvailable(item); - } else if (frame_replaced_listener != nullptr) { - frame_replaced_listener->OnFrameReplaced(item); - } - - ++current_callback_ticket; - callback_condition.notify_all(); - } - - return Status::NoError; -} - -void BufferQueueProducer::CancelBuffer(s32 slot, const Fence& fence) { - LOG_DEBUG(Service_NVFlinger, "slot {}", slot); - - std::scoped_lock lock{core->mutex}; - - if (core->is_abandoned) { - LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); - return; - } - - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot, - BufferQueueDefs::NUM_BUFFER_SLOTS); - return; - } else if (slots[slot].buffer_state != BufferState::Dequeued) { - LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot, - slots[slot].buffer_state); - return; - } - - slots[slot].buffer_state = BufferState::Free; - slots[slot].frame_number = 0; - slots[slot].fence = fence; - - core->SignalDequeueCondition(); - buffer_wait_event->Signal(); -} - -Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) { - std::scoped_lock lock{core->mutex}; - - if (out_value == nullptr) { - LOG_ERROR(Service_NVFlinger, "outValue was nullptr"); - return Status::BadValue; - } - - if (core->is_abandoned) { - LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); - return Status::NoInit; - } - - u32 value{}; - switch (what) { - case NativeWindow::Width: - value = core->default_width; - break; - case NativeWindow::Height: - value = core->default_height; - break; - case NativeWindow::Format: - value = static_cast<u32>(core->default_buffer_format); - break; - case NativeWindow::MinUndequeedBuffers: - value = core->GetMinUndequeuedBufferCountLocked(false); - break; - case NativeWindow::StickyTransform: - value = sticky_transform; - break; - case NativeWindow::ConsumerRunningBehind: - value = (core->queue.size() > 1); - break; - case NativeWindow::ConsumerUsageBits: - value = core->consumer_usage_bit; - break; - default: - ASSERT(false); - return Status::BadValue; - } - - LOG_DEBUG(Service_NVFlinger, "what = {}, value = {}", what, value); - - *out_value = static_cast<s32>(value); - - return Status::NoError; -} - -Status BufferQueueProducer::Connect(const std::shared_ptr<IProducerListener>& listener, - NativeWindowApi api, bool producer_controlled_by_app, - QueueBufferOutput* output) { - std::scoped_lock lock{core->mutex}; - - LOG_DEBUG(Service_NVFlinger, "api = {} producer_controlled_by_app = {}", api, - producer_controlled_by_app); - - if (core->is_abandoned) { - LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); - return Status::NoInit; - } - - if (core->consumer_listener == nullptr) { - LOG_ERROR(Service_NVFlinger, "BufferQueue has no consumer"); - return Status::NoInit; - } - - if (output == nullptr) { - LOG_ERROR(Service_NVFlinger, "output was nullptr"); - return Status::BadValue; - } - - if (core->connected_api != NativeWindowApi::NoConnectedApi) { - LOG_ERROR(Service_NVFlinger, "already connected (cur = {} req = {})", core->connected_api, - api); - return Status::BadValue; - } - - Status status = Status::NoError; - switch (api) { - case NativeWindowApi::Egl: - case NativeWindowApi::Cpu: - case NativeWindowApi::Media: - case NativeWindowApi::Camera: - core->connected_api = api; - output->Inflate(core->default_width, core->default_height, core->transform_hint, - static_cast<u32>(core->queue.size())); - core->connected_producer_listener = listener; - break; - default: - LOG_ERROR(Service_NVFlinger, "unknown api = {}", api); - status = Status::BadValue; - break; - } - - core->buffer_has_been_queued = false; - core->dequeue_buffer_cannot_block = - core->consumer_controlled_by_app && producer_controlled_by_app; - - return status; -} - -Status BufferQueueProducer::Disconnect(NativeWindowApi api) { - LOG_DEBUG(Service_NVFlinger, "api = {}", api); - - Status status = Status::NoError; - std::shared_ptr<IConsumerListener> listener; - - { - std::scoped_lock lock{core->mutex}; - - core->WaitWhileAllocatingLocked(); - - if (core->is_abandoned) { - // Disconnecting after the surface has been abandoned is a no-op. - return Status::NoError; - } - - // HACK: We are not Android. Remove handle for items in queue, and clear queue. - // Allows synchronous destruction of nvmap handles. - for (auto& item : core->queue) { - nvmap.FreeHandle(item.graphic_buffer->BufferId(), true); - } - core->queue.clear(); - - switch (api) { - case NativeWindowApi::Egl: - case NativeWindowApi::Cpu: - case NativeWindowApi::Media: - case NativeWindowApi::Camera: - if (core->connected_api == api) { - core->FreeAllBuffersLocked(); - core->connected_producer_listener = nullptr; - core->connected_api = NativeWindowApi::NoConnectedApi; - core->SignalDequeueCondition(); - buffer_wait_event->Signal(); - listener = core->consumer_listener; - } else { - LOG_ERROR(Service_NVFlinger, "still connected to another api (cur = {} req = {})", - core->connected_api, api); - status = Status::BadValue; - } - break; - default: - LOG_ERROR(Service_NVFlinger, "unknown api = {}", api); - status = Status::BadValue; - break; - } - } - - // Call back without lock held - if (listener != nullptr) { - listener->OnBuffersReleased(); - } - - return status; -} - -Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot, - const std::shared_ptr<GraphicBuffer>& buffer) { - LOG_DEBUG(Service_NVFlinger, "slot {}", slot); - - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - return Status::BadValue; - } - - std::scoped_lock lock{core->mutex}; - - slots[slot] = {}; - slots[slot].graphic_buffer = buffer; - slots[slot].frame_number = 0; - - // Most games preallocate a buffer and pass a valid buffer here. However, it is possible for - // this to be called with an empty buffer, Naruto Ultimate Ninja Storm is a game that does this. - if (buffer) { - slots[slot].is_preallocated = true; - - core->override_max_buffer_count = core->GetPreallocatedBufferCountLocked(); - core->default_width = buffer->Width(); - core->default_height = buffer->Height(); - core->default_buffer_format = buffer->Format(); - } - - core->SignalDequeueCondition(); - buffer_wait_event->Signal(); - - return Status::NoError; -} - -void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u32 flags) { - Status status{Status::NoError}; - InputParcel parcel_in{ctx.ReadBuffer()}; - OutputParcel parcel_out{}; - - switch (code) { - case TransactionId::Connect: { - const auto enable_listener = parcel_in.Read<bool>(); - const auto api = parcel_in.Read<NativeWindowApi>(); - const auto producer_controlled_by_app = parcel_in.Read<bool>(); - - UNIMPLEMENTED_IF_MSG(enable_listener, "Listener is unimplemented!"); - - std::shared_ptr<IProducerListener> listener; - QueueBufferOutput output{}; - - status = Connect(listener, api, producer_controlled_by_app, &output); - - parcel_out.Write(output); - break; - } - case TransactionId::SetPreallocatedBuffer: { - const auto slot = parcel_in.Read<s32>(); - const auto buffer = parcel_in.ReadObject<GraphicBuffer>(); - - status = SetPreallocatedBuffer(slot, buffer); - break; - } - case TransactionId::DequeueBuffer: { - const auto is_async = parcel_in.Read<bool>(); - const auto width = parcel_in.Read<u32>(); - const auto height = parcel_in.Read<u32>(); - const auto pixel_format = parcel_in.Read<PixelFormat>(); - const auto usage = parcel_in.Read<u32>(); - - s32 slot{}; - Fence fence{}; - - status = DequeueBuffer(&slot, &fence, is_async, width, height, pixel_format, usage); - - parcel_out.Write(slot); - parcel_out.WriteObject(&fence); - break; - } - case TransactionId::RequestBuffer: { - const auto slot = parcel_in.Read<s32>(); - - std::shared_ptr<GraphicBuffer> buf; - - status = RequestBuffer(slot, &buf); - - parcel_out.WriteObject(buf); - break; - } - case TransactionId::QueueBuffer: { - const auto slot = parcel_in.Read<s32>(); - - QueueBufferInput input{parcel_in}; - QueueBufferOutput output; - - status = QueueBuffer(slot, input, &output); - - parcel_out.Write(output); - break; - } - case TransactionId::Query: { - const auto what = parcel_in.Read<NativeWindow>(); - - s32 value{}; - - status = Query(what, &value); - - parcel_out.Write(value); - break; - } - case TransactionId::CancelBuffer: { - const auto slot = parcel_in.Read<s32>(); - const auto fence = parcel_in.ReadFlattened<Fence>(); - - CancelBuffer(slot, fence); - break; - } - case TransactionId::Disconnect: { - const auto api = parcel_in.Read<NativeWindowApi>(); - - status = Disconnect(api); - break; - } - case TransactionId::DetachBuffer: { - const auto slot = parcel_in.Read<s32>(); - - status = DetachBuffer(slot); - break; - } - case TransactionId::SetBufferCount: { - const auto buffer_count = parcel_in.Read<s32>(); - - status = SetBufferCount(buffer_count); - break; - } - case TransactionId::GetBufferHistory: - LOG_WARNING(Service_NVFlinger, "(STUBBED) called, transaction=GetBufferHistory"); - break; - default: - ASSERT_MSG(false, "Unimplemented TransactionId {}", code); - break; - } - - parcel_out.Write(status); - - ctx.WriteBuffer(parcel_out.Serialize()); -} - -Kernel::KReadableEvent& BufferQueueProducer::GetNativeHandle() { - return buffer_wait_event->GetReadableEvent(); -} - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h deleted file mode 100644 index 16189fa6f..000000000 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.h +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2014 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueProducer.h - -#pragma once - -#include <condition_variable> -#include <memory> -#include <mutex> - -#include "common/common_funcs.h" -#include "core/hle/service/nvdrv/nvdata.h" -#include "core/hle/service/nvflinger/binder.h" -#include "core/hle/service/nvflinger/buffer_queue_defs.h" -#include "core/hle/service/nvflinger/buffer_slot.h" -#include "core/hle/service/nvflinger/graphic_buffer_producer.h" -#include "core/hle/service/nvflinger/pixel_format.h" -#include "core/hle/service/nvflinger/status.h" -#include "core/hle/service/nvflinger/window.h" - -namespace Kernel { -class KernelCore; -class KEvent; -class KReadableEvent; -} // namespace Kernel - -namespace Service::KernelHelpers { -class ServiceContext; -} // namespace Service::KernelHelpers - -namespace Service::Nvidia::NvCore { -class NvMap; -} // namespace Service::Nvidia::NvCore - -namespace Service::android { - -class BufferQueueCore; -class IProducerListener; - -class BufferQueueProducer final : public IBinder { -public: - explicit BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_, - std::shared_ptr<BufferQueueCore> buffer_queue_core_, - Service::Nvidia::NvCore::NvMap& nvmap_); - ~BufferQueueProducer(); - - void Transact(HLERequestContext& ctx, android::TransactionId code, u32 flags) override; - - Kernel::KReadableEvent& GetNativeHandle() override; - -public: - Status RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf); - Status SetBufferCount(s32 buffer_count); - Status DequeueBuffer(s32* out_slot, android::Fence* out_fence, bool async, u32 width, - u32 height, PixelFormat format, u32 usage); - Status DetachBuffer(s32 slot); - Status DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out_buffer, Fence* out_fence); - Status AttachBuffer(s32* outSlot, const std::shared_ptr<GraphicBuffer>& buffer); - Status QueueBuffer(s32 slot, const QueueBufferInput& input, QueueBufferOutput* output); - void CancelBuffer(s32 slot, const Fence& fence); - Status Query(NativeWindow what, s32* out_value); - Status Connect(const std::shared_ptr<IProducerListener>& listener, NativeWindowApi api, - bool producer_controlled_by_app, QueueBufferOutput* output); - - Status Disconnect(NativeWindowApi api); - Status SetPreallocatedBuffer(s32 slot, const std::shared_ptr<GraphicBuffer>& buffer); - -private: - BufferQueueProducer(const BufferQueueProducer&) = delete; - - Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags, - std::unique_lock<std::mutex>& lk) const; - - Kernel::KEvent* buffer_wait_event{}; - Service::KernelHelpers::ServiceContext& service_context; - - std::shared_ptr<BufferQueueCore> core; - BufferQueueDefs::SlotsType& slots; - u32 sticky_transform{}; - std::mutex callback_mutex; - s32 next_callback_ticket{}; - s32 current_callback_ticket{}; - std::condition_variable_any callback_condition; - - Service::Nvidia::NvCore::NvMap& nvmap; -}; - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_slot.h b/src/core/hle/service/nvflinger/buffer_slot.h deleted file mode 100644 index 0cd0e9964..000000000 --- a/src/core/hle/service/nvflinger/buffer_slot.h +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2014 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferSlot.h - -#pragma once - -#include <memory> - -#include "common/common_types.h" -#include "core/hle/service/nvflinger/ui/fence.h" - -namespace Service::android { - -class GraphicBuffer; - -enum class BufferState : u32 { - Free = 0, - Dequeued = 1, - Queued = 2, - Acquired = 3, -}; - -struct BufferSlot final { - constexpr BufferSlot() = default; - - std::shared_ptr<GraphicBuffer> graphic_buffer; - BufferState buffer_state{BufferState::Free}; - bool request_buffer_called{}; - u64 frame_number{}; - Fence fence; - bool acquire_called{}; - bool attached_by_consumer{}; - bool is_preallocated{}; -}; - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_transform_flags.h b/src/core/hle/service/nvflinger/buffer_transform_flags.h deleted file mode 100644 index 67aa5dad6..000000000 --- a/src/core/hle/service/nvflinger/buffer_transform_flags.h +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/common_types.h" - -namespace Service::android { - -enum class BufferTransformFlags : u32 { - /// No transform flags are set - Unset = 0x00, - /// Flip source image horizontally (around the vertical axis) - FlipH = 0x01, - /// Flip source image vertically (around the horizontal axis) - FlipV = 0x02, - /// Rotate source image 90 degrees clockwise - Rotate90 = 0x04, - /// Rotate source image 180 degrees - Rotate180 = 0x03, - /// Rotate source image 270 degrees clockwise - Rotate270 = 0x07, -}; - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvflinger/consumer_base.cpp deleted file mode 100644 index 982531e2d..000000000 --- a/src/core/hle/service/nvflinger/consumer_base.cpp +++ /dev/null @@ -1,133 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2010 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based 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 Service::android { - -ConsumerBase::ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_) - : consumer{std::move(consumer_)} {} - -ConsumerBase::~ConsumerBase() { - std::scoped_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) { - LOG_DEBUG(Service_NVFlinger, "called"); -} - -void ConsumerBase::OnFrameReplaced(const BufferItem& item) { - LOG_DEBUG(Service_NVFlinger, "called"); -} - -void ConsumerBase::OnBuffersReleased() { - std::scoped_lock lock{mutex}; - - LOG_DEBUG(Service_NVFlinger, "called"); - - if (is_abandoned) { - // Nothing to do if we're already abandoned. - return; - } - - u64 mask = 0; - consumer->GetReleasedBuffers(&mask); - for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) { - if (mask & (1ULL << i)) { - FreeBufferLocked(i); - } - } -} - -void ConsumerBase::OnSidebandStreamChanged() {} - -Status ConsumerBase::AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when) { - Status err = consumer->AcquireBuffer(item, present_when); - if (err != Status::NoError) { - return err; - } - - if (item->graphic_buffer != nullptr) { - 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) const { - 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 Service::android diff --git a/src/core/hle/service/nvflinger/consumer_base.h b/src/core/hle/service/nvflinger/consumer_base.h deleted file mode 100644 index 9a8a5f6bb..000000000 --- a/src/core/hle/service/nvflinger/consumer_base.h +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2010 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/ConsumerBase.h - -#pragma once - -#include <array> -#include <chrono> -#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 Service::android { - -class BufferItem; -class BufferQueueConsumer; - -class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this<ConsumerBase> { -public: - void Connect(bool controlled_by_app); - -protected: - explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_); - ~ConsumerBase() override; - - void OnFrameAvailable(const BufferItem& item) override; - void OnFrameReplaced(const BufferItem& item) override; - void OnBuffersReleased() override; - void OnSidebandStreamChanged() override; - - void FreeBufferLocked(s32 slot_index); - Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when); - Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer); - bool StillTracking(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer) const; - 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 Service::android diff --git a/src/core/hle/service/nvflinger/consumer_listener.h b/src/core/hle/service/nvflinger/consumer_listener.h deleted file mode 100644 index 74a193988..000000000 --- a/src/core/hle/service/nvflinger/consumer_listener.h +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2014 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IConsumerListener.h - -#pragma once - -namespace Service::android { - -class BufferItem; - -/// ConsumerListener is the interface through which the BufferQueue notifies the consumer of events -/// that the consumer may wish to react to. -class IConsumerListener { -public: - IConsumerListener() = default; - virtual ~IConsumerListener() = default; - - virtual void OnFrameAvailable(const BufferItem& item) = 0; - virtual void OnFrameReplaced(const BufferItem& item) = 0; - virtual void OnBuffersReleased() = 0; - virtual void OnSidebandStreamChanged() = 0; -}; - -}; // namespace Service::android diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp deleted file mode 100644 index 769e8c0a3..000000000 --- a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2010 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/IGraphicBufferProducer.cpp - -#include "core/hle/service/nvflinger/graphic_buffer_producer.h" -#include "core/hle/service/nvflinger/parcel.h" - -namespace Service::android { - -QueueBufferInput::QueueBufferInput(InputParcel& parcel) { - parcel.ReadFlattened(*this); -} - -QueueBufferOutput::QueueBufferOutput() = default; - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.h b/src/core/hle/service/nvflinger/graphic_buffer_producer.h deleted file mode 100644 index 2969f0fd5..000000000 --- a/src/core/hle/service/nvflinger/graphic_buffer_producer.h +++ /dev/null @@ -1,76 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2010 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IGraphicBufferProducer.h - -#pragma once - -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/math_util.h" -#include "core/hle/service/nvflinger/ui/fence.h" -#include "core/hle/service/nvflinger/window.h" - -namespace Service::android { - -class InputParcel; - -#pragma pack(push, 1) -struct QueueBufferInput final { - explicit QueueBufferInput(InputParcel& parcel); - - void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle<s32>* crop_, - NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_, - u32* sticky_transform_, bool* async_, s32* swap_interval_, Fence* fence_) const { - *timestamp_ = timestamp; - *is_auto_timestamp_ = static_cast<bool>(is_auto_timestamp); - *crop_ = crop; - *scaling_mode_ = scaling_mode; - *transform_ = transform; - *sticky_transform_ = sticky_transform; - *async_ = static_cast<bool>(async); - *swap_interval_ = swap_interval; - *fence_ = fence; - } - -private: - s64 timestamp{}; - s32 is_auto_timestamp{}; - Common::Rectangle<s32> crop{}; - NativeWindowScalingMode scaling_mode{}; - NativeWindowTransform transform{}; - u32 sticky_transform{}; - s32 async{}; - s32 swap_interval{}; - Fence fence{}; -}; -#pragma pack(pop) -static_assert(sizeof(QueueBufferInput) == 84, "QueueBufferInput has wrong size"); - -struct QueueBufferOutput final { - QueueBufferOutput(); - - void Deflate(u32* width_, u32* height_, u32* transform_hint_, u32* num_pending_buffers_) const { - *width_ = width; - *height_ = height; - *transform_hint_ = transform_hint; - *num_pending_buffers_ = num_pending_buffers; - } - - void Inflate(u32 width_, u32 height_, u32 transform_hint_, u32 num_pending_buffers_) { - width = width_; - height = height_; - transform_hint = transform_hint_; - num_pending_buffers = num_pending_buffers_; - } - -private: - u32 width{}; - u32 height{}; - u32 transform_hint{}; - u32 num_pending_buffers{}; -}; -static_assert(sizeof(QueueBufferOutput) == 16, "QueueBufferOutput has wrong size"); - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp b/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp deleted file mode 100644 index dc9b2a9ec..000000000 --- a/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include <mutex> - -#include "common/common_types.h" -#include "core/hle/service/nvflinger/hos_binder_driver_server.h" - -namespace Service::NVFlinger { - -HosBinderDriverServer::HosBinderDriverServer(Core::System& system_) - : service_context(system_, "HosBinderDriverServer") {} - -HosBinderDriverServer::~HosBinderDriverServer() {} - -u64 HosBinderDriverServer::RegisterProducer(std::unique_ptr<android::IBinder>&& binder) { - std::scoped_lock lk{lock}; - - last_id++; - - producers[last_id] = std::move(binder); - - return last_id; -} - -android::IBinder* HosBinderDriverServer::TryGetProducer(u64 id) { - std::scoped_lock lk{lock}; - - if (auto search = producers.find(id); search != producers.end()) { - return search->second.get(); - } - - return {}; -} - -} // namespace Service::NVFlinger diff --git a/src/core/hle/service/nvflinger/hos_binder_driver_server.h b/src/core/hle/service/nvflinger/hos_binder_driver_server.h deleted file mode 100644 index 8fddc1206..000000000 --- a/src/core/hle/service/nvflinger/hos_binder_driver_server.h +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include <memory> -#include <mutex> -#include <unordered_map> - -#include "common/common_types.h" -#include "core/hle/service/kernel_helpers.h" -#include "core/hle/service/nvflinger/binder.h" - -namespace Core { -class System; -} - -namespace Service::NVFlinger { - -class HosBinderDriverServer final { -public: - explicit HosBinderDriverServer(Core::System& system_); - ~HosBinderDriverServer(); - - u64 RegisterProducer(std::unique_ptr<android::IBinder>&& binder); - - android::IBinder* TryGetProducer(u64 id); - -private: - KernelHelpers::ServiceContext service_context; - - std::unordered_map<u64, std::unique_ptr<android::IBinder>> producers; - std::mutex lock; - u64 last_id{}; -}; - -} // namespace Service::NVFlinger diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp deleted file mode 100644 index f4416f5b2..000000000 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ /dev/null @@ -1,335 +0,0 @@ -// 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/nvflinger/buffer_item_consumer.h" -#include "core/hle/service/nvflinger/buffer_queue_core.h" -#include "core/hle/service/nvflinger/hos_binder_driver_server.h" -#include "core/hle/service/nvflinger/nvflinger.h" -#include "core/hle/service/nvflinger/ui/graphic_buffer.h" -#include "core/hle/service/vi/display/vi_display.h" -#include "core/hle/service/vi/layer/vi_layer.h" -#include "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" - -namespace Service::NVFlinger { - -constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60}; - -void NVFlinger::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(false); - vsync_signal.store(false); - - guard->lock(); - - Compose(); - - guard->unlock(); - } -} - -NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_) - : system(system_), service_context(system_, "nvflinger"), - hos_binder_driver_server(hos_binder_driver_server_) { - displays.emplace_back(0, "Default", hos_binder_driver_server, service_context, system); - displays.emplace_back(1, "External", hos_binder_driver_server, service_context, system); - displays.emplace_back(2, "Edid", hos_binder_driver_server, service_context, system); - displays.emplace_back(3, "Internal", hos_binder_driver_server, service_context, system); - displays.emplace_back(4, "Null", hos_binder_driver_server, service_context, system); - guard = std::make_shared<std::mutex>(); - - // Schedule the screen composition events - multi_composition_event = Core::Timing::CreateEvent( - "ScreenComposition", - [this](std::uintptr_t, s64 time, - std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { - vsync_signal.store(true); - vsync_signal.notify_all(); - return std::chrono::nanoseconds(GetNextTicks()); - }); - - single_composition_event = Core::Timing::CreateEvent( - "ScreenComposition", - [this](std::uintptr_t, 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); - } -} - -NVFlinger::~NVFlinger() { - if (system.IsMulticore()) { - system.CoreTiming().UnscheduleEvent(multi_composition_event, {}); - vsync_thread.request_stop(); - vsync_signal.store(true); - vsync_signal.notify_all(); - } else { - system.CoreTiming().UnscheduleEvent(single_composition_event, {}); - } - - ShutdownLayers(); - - if (nvdrv) { - nvdrv->Close(disp_fd); - } -} - -void NVFlinger::ShutdownLayers() { - for (auto& display : displays) { - for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { - display.GetLayer(layer).Core().NotifyShutdown(); - } - } -} - -void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { - nvdrv = std::move(instance); - disp_fd = nvdrv->Open("/dev/nvdisp_disp0"); -} - -std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { - const auto lock_guard = Lock(); - - LOG_DEBUG(Service_NVFlinger, "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 NVFlinger::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> NVFlinger::CreateLayer(u64 display_id) { - 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); - return layer_id; -} - -void NVFlinger::CreateLayerAtId(VI::Display& display, u64 layer_id) { - const auto buffer_id = next_buffer_queue_id++; - display.CreateLayer(layer_id, buffer_id, nvdrv->container); -} - -void NVFlinger::CloseLayer(u64 layer_id) { - const auto lock_guard = Lock(); - - for (auto& display : displays) { - display.CloseLayer(layer_id); - } -} - -std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) { - const auto lock_guard = Lock(); - const auto* const layer = FindOrCreateLayer(display_id, layer_id); - - if (layer == nullptr) { - return std::nullopt; - } - - return layer->GetBinderId(); -} - -ResultVal<Kernel::KReadableEvent*> NVFlinger::FindVsyncEvent(u64 display_id) { - const auto lock_guard = Lock(); - auto* const display = FindDisplay(display_id); - - if (display == nullptr) { - return VI::ResultNotFound; - } - - return display->GetVSyncEvent(); -} - -VI::Display* NVFlinger::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* NVFlinger::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* NVFlinger::FindLayer(u64 display_id, u64 layer_id) { - auto* const display = FindDisplay(display_id); - - if (display == nullptr) { - return nullptr; - } - - return display->FindLayer(layer_id); -} - -const VI::Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) const { - const auto* const display = FindDisplay(display_id); - - if (display == nullptr) { - return nullptr; - } - - return display->FindLayer(layer_id); -} - -VI::Layer* NVFlinger::FindOrCreateLayer(u64 display_id, u64 layer_id) { - auto* const display = FindDisplay(display_id); - - if (display == nullptr) { - return nullptr; - } - - auto* layer = display->FindLayer(layer_id); - - if (layer == nullptr) { - LOG_DEBUG(Service_NVFlinger, "Layer at id {} not found. Trying to create it.", layer_id); - CreateLayerAtId(*display, layer_id); - return display->FindLayer(layer_id); - } - - return layer; -} - -void NVFlinger::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; - - // TODO(Subv): Support more than 1 layer. - VI::Layer& layer = display.GetLayer(0); - - android::BufferItem buffer{}; - const auto status = layer.GetConsumer().AcquireBuffer(&buffer, {}, false); - - if (status != android::Status::NoError) { - continue; - } - - const auto& igbp_buffer = *buffer.graphic_buffer; - - if (!system.IsPoweredOn()) { - return; // We are likely shutting down - } - - // Now send the buffer to the GPU for drawing. - // TODO(Subv): Support more than just disp0. The display device selection is probably based - // on which display we're drawing (Default, Internal, External, etc) - auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd); - ASSERT(nvdisp); - - guard->unlock(); - Common::Rectangle<int> crop_rect{ - static_cast<int>(buffer.crop.Left()), static_cast<int>(buffer.crop.Top()), - static_cast<int>(buffer.crop.Right()), static_cast<int>(buffer.crop.Bottom())}; - - nvdisp->flip(igbp_buffer.BufferId(), igbp_buffer.Offset(), igbp_buffer.ExternalFormat(), - igbp_buffer.Width(), igbp_buffer.Height(), igbp_buffer.Stride(), - static_cast<android::BufferTransformFlags>(buffer.transform), crop_rect, - buffer.fence.fences, buffer.fence.num_fences); - - MicroProfileFlip(); - guard->lock(); - - swap_interval = buffer.swap_interval; - - layer.GetConsumer().ReleaseBuffer(buffer, android::Fence::NoFence()); - } -} - -s64 NVFlinger::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; - } - } - - // As an extension, treat nonpositive swap interval as framerate multiplier. - const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval) - : 60.f / static_cast<f32>(swap_interval); - - return static_cast<s64>(speed_scale * (1000000000.f / effective_fps)); -} - -} // namespace Service::NVFlinger diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h deleted file mode 100644 index 3828cf272..000000000 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ /dev/null @@ -1,155 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#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 "core/hle/result.h" -#include "core/hle/service/kernel_helpers.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 Service::NVFlinger { - -class NVFlinger final { -public: - explicit NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_); - ~NVFlinger(); - - 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); - - /// Closes a layer on all displays for the given layer ID. - void CloseLayer(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]] ResultVal<Kernel::KReadableEvent*> FindVsyncEvent(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: - struct Layer { - std::unique_ptr<android::BufferQueueCore> core; - std::unique_ptr<android::BufferQueueProducer> producer; - }; - -private: - [[nodiscard]] std::unique_lock<std::mutex> Lock() const { - return std::unique_lock{*guard}; - } - - /// 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); - - /// Finds the layer identified by the specified ID in the desired display. - [[nodiscard]] const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const; - - /// Finds the layer identified by the specified ID in the desired display, - /// or creates the layer if it is not found. - /// To be used when the system expects the specified ID to already exist. - [[nodiscard]] VI::Layer* FindOrCreateLayer(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); - - 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; - - /// 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; - - std::atomic<bool> vsync_signal; - - std::jthread vsync_thread; - - KernelHelpers::ServiceContext service_context; - - HosBinderDriverServer& hos_binder_driver_server; -}; - -} // namespace Service::NVFlinger diff --git a/src/core/hle/service/nvflinger/parcel.h b/src/core/hle/service/nvflinger/parcel.h deleted file mode 100644 index d1b6201e0..000000000 --- a/src/core/hle/service/nvflinger/parcel.h +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include <memory> -#include <span> -#include <vector> - -#include "common/alignment.h" -#include "common/assert.h" -#include "common/common_types.h" - -namespace Service::android { - -struct ParcelHeader { - u32 data_size; - u32 data_offset; - u32 objects_size; - u32 objects_offset; -}; -static_assert(sizeof(ParcelHeader) == 16, "ParcelHeader has wrong size"); - -class InputParcel final { -public: - explicit InputParcel(std::span<const u8> in_data) : read_buffer(std::move(in_data)) { - DeserializeHeader(); - [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); - } - - template <typename T> - void Read(T& val) { - static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); - ASSERT(read_index + sizeof(T) <= read_buffer.size()); - - std::memcpy(&val, read_buffer.data() + read_index, sizeof(T)); - read_index += sizeof(T); - read_index = Common::AlignUp(read_index, 4); - } - - template <typename T> - T Read() { - T val; - Read(val); - return val; - } - - template <typename T> - void ReadFlattened(T& val) { - const auto flattened_size = Read<s64>(); - ASSERT(sizeof(T) == flattened_size); - Read(val); - } - - template <typename T> - T ReadFlattened() { - T val; - ReadFlattened(val); - return val; - } - - template <typename T> - T ReadUnaligned() { - static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); - ASSERT(read_index + sizeof(T) <= read_buffer.size()); - - T val; - std::memcpy(&val, read_buffer.data() + read_index, sizeof(T)); - read_index += sizeof(T); - return val; - } - - template <typename T> - const std::shared_ptr<T> ReadObject() { - static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); - - const auto is_valid{Read<bool>()}; - - if (is_valid) { - auto result = std::make_shared<T>(); - ReadFlattened(*result); - return result; - } - - return {}; - } - - std::u16string ReadInterfaceToken() { - [[maybe_unused]] const u32 unknown = Read<u32>(); - const u32 length = Read<u32>(); - - std::u16string token; - token.reserve(length + 1); - - for (u32 ch = 0; ch < length + 1; ++ch) { - token.push_back(ReadUnaligned<u16>()); - } - - read_index = Common::AlignUp(read_index, 4); - - return token; - } - - void DeserializeHeader() { - ASSERT(read_buffer.size() > sizeof(ParcelHeader)); - - ParcelHeader header{}; - std::memcpy(&header, read_buffer.data(), sizeof(ParcelHeader)); - - read_index = header.data_offset; - } - -private: - std::span<const u8> read_buffer; - std::size_t read_index = 0; -}; - -class OutputParcel final { -public: - static constexpr std::size_t DefaultBufferSize = 0x40; - - OutputParcel() : buffer(DefaultBufferSize) {} - - template <typename T> - explicit OutputParcel(const T& out_data) : buffer(DefaultBufferSize) { - Write(out_data); - } - - template <typename T> - void Write(const T& val) { - static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); - - if (buffer.size() < write_index + sizeof(T)) { - buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize); - } - - std::memcpy(buffer.data() + write_index, &val, sizeof(T)); - write_index += sizeof(T); - write_index = Common::AlignUp(write_index, 4); - } - - template <typename T> - void WriteObject(const T* ptr) { - static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); - - if (!ptr) { - Write<u32>(0); - return; - } - - Write<u32>(1); - Write<s64>(sizeof(T)); - Write(*ptr); - } - - template <typename T> - void WriteObject(const std::shared_ptr<T> ptr) { - WriteObject(ptr.get()); - } - - std::vector<u8> Serialize() const { - ParcelHeader header{}; - header.data_size = static_cast<u32>(write_index - sizeof(ParcelHeader)); - header.data_offset = sizeof(ParcelHeader); - header.objects_size = 4; - header.objects_offset = static_cast<u32>(sizeof(ParcelHeader) + header.data_size); - std::memcpy(buffer.data(), &header, sizeof(ParcelHeader)); - - return buffer; - } - -private: - mutable std::vector<u8> buffer; - std::size_t write_index = sizeof(ParcelHeader); -}; - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/pixel_format.h b/src/core/hle/service/nvflinger/pixel_format.h deleted file mode 100644 index f77d0acfb..000000000 --- a/src/core/hle/service/nvflinger/pixel_format.h +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/common_types.h" - -namespace Service::android { - -enum class PixelFormat : u32 { - NoFormat = 0, - Rgba8888 = 1, - Rgbx8888 = 2, - Rgb888 = 3, - Rgb565 = 4, - Bgra8888 = 5, - Rgba5551 = 6, - Rgba4444 = 7, -}; - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/producer_listener.h b/src/core/hle/service/nvflinger/producer_listener.h deleted file mode 100644 index 6bf8aaf1e..000000000 --- a/src/core/hle/service/nvflinger/producer_listener.h +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2014 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IProducerListener.h - -#pragma once - -namespace Service::android { - -class IProducerListener { -public: - virtual ~IProducerListener() = default; - virtual void OnBufferReleased() = 0; -}; - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/status.h b/src/core/hle/service/nvflinger/status.h deleted file mode 100644 index 7af166c40..000000000 --- a/src/core/hle/service/nvflinger/status.h +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/common_funcs.h" -#include "common/common_types.h" - -namespace Service::android { - -enum class Status : s32 { - None = 0, - NoError = 0, - StaleBufferSlot = 1, - NoBufferAvailable = 2, - PresentLater = 3, - WouldBlock = -11, - NoMemory = -12, - Busy = -16, - NoInit = -19, - BadValue = -22, - InvalidOperation = -37, - BufferNeedsReallocation = 1, - ReleaseAllBuffers = 2, -}; -DECLARE_ENUM_FLAG_OPERATORS(Status); - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/ui/fence.h b/src/core/hle/service/nvflinger/ui/fence.h deleted file mode 100644 index 536e8156d..000000000 --- a/src/core/hle/service/nvflinger/ui/fence.h +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2012 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/ui/Fence.h - -#pragma once - -#include <array> - -#include "common/common_types.h" -#include "core/hle/service/nvdrv/nvdata.h" - -namespace Service::android { - -class Fence { -public: - constexpr Fence() = default; - - static constexpr Fence NoFence() { - Fence fence; - fence.fences[0].id = -1; - return fence; - } - -public: - u32 num_fences{}; - std::array<Service::Nvidia::NvFence, 4> fences{}; -}; -static_assert(sizeof(Fence) == 36, "Fence has wrong size"); - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/ui/graphic_buffer.h b/src/core/hle/service/nvflinger/ui/graphic_buffer.h deleted file mode 100644 index 9a27f8f02..000000000 --- a/src/core/hle/service/nvflinger/ui/graphic_buffer.h +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2007 The Android Open Source Project -// SPDX-License-Identifier: GPL-3.0-or-later -// Parts of this implementation were based on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/ui/GraphicBuffer.h - -#pragma once - -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "core/hle/service/nvflinger/pixel_format.h" - -namespace Service::android { - -class GraphicBuffer final { -public: - constexpr GraphicBuffer() = default; - - constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_) - : width{static_cast<s32>(width_)}, height{static_cast<s32>(height_)}, format{format_}, - usage{static_cast<s32>(usage_)} {} - - constexpr u32 Width() const { - return static_cast<u32>(width); - } - - constexpr u32 Height() const { - return static_cast<u32>(height); - } - - constexpr u32 Stride() const { - return static_cast<u32>(stride); - } - - constexpr u32 Usage() const { - return static_cast<u32>(usage); - } - - constexpr PixelFormat Format() const { - return format; - } - - constexpr u32 BufferId() const { - return buffer_id; - } - - constexpr PixelFormat ExternalFormat() const { - return external_format; - } - - constexpr u32 Handle() const { - return handle; - } - - constexpr u32 Offset() const { - return offset; - } - - constexpr bool NeedsReallocation(u32 width_, u32 height_, PixelFormat format_, - u32 usage_) const { - if (static_cast<s32>(width_) != width) { - return true; - } - - if (static_cast<s32>(height_) != height) { - return true; - } - - if (format_ != format) { - return true; - } - - if ((static_cast<u32>(usage) & usage_) != usage_) { - return true; - } - - return false; - } - -private: - u32 magic{}; - s32 width{}; - s32 height{}; - s32 stride{}; - PixelFormat format{}; - s32 usage{}; - INSERT_PADDING_WORDS(1); - u32 index{}; - INSERT_PADDING_WORDS(3); - u32 buffer_id{}; - INSERT_PADDING_WORDS(6); - PixelFormat external_format{}; - INSERT_PADDING_WORDS(10); - u32 handle{}; - u32 offset{}; - INSERT_PADDING_WORDS(60); -}; -static_assert(sizeof(GraphicBuffer) == 0x16C, "GraphicBuffer has wrong size"); - -} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/window.h b/src/core/hle/service/nvflinger/window.h deleted file mode 100644 index 61cca5b01..000000000 --- a/src/core/hle/service/nvflinger/window.h +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/common_funcs.h" -#include "common/common_types.h" - -namespace Service::android { - -/// Attributes queryable with Query -enum class NativeWindow : s32 { - Width = 0, - Height = 1, - Format = 2, - MinUndequeedBuffers = 3, - QueuesToWindowComposer = 4, - ConcreteType = 5, - DefaultWidth = 6, - DefaultHeight = 7, - TransformHint = 8, - ConsumerRunningBehind = 9, - ConsumerUsageBits = 10, - StickyTransform = 11, - DefaultDataSpace = 12, - BufferAge = 13, -}; - -/// Parameter for Connect/Disconnect -enum class NativeWindowApi : s32 { - NoConnectedApi = 0, - Egl = 1, - Cpu = 2, - Media = 3, - Camera = 4, -}; - -/// Scaling mode parameter for QueueBuffer -enum class NativeWindowScalingMode : s32 { - Freeze = 0, - ScaleToWindow = 1, - ScaleCrop = 2, - NoScaleCrop = 3, -}; - -/// Transform parameter for QueueBuffer -enum class NativeWindowTransform : u32 { - None = 0x0, - InverseDisplay = 0x08, -}; -DECLARE_ENUM_FLAG_OPERATORS(NativeWindowTransform); - -} // namespace Service::android |