summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/nvflinger
diff options
context:
space:
mode:
authorLiam <byteslice@airmail.cc>2023-02-19 21:05:34 +0100
committerLiam <byteslice@airmail.cc>2023-03-01 16:39:49 +0100
commit809148e1a58296ab88c9d3c6719d345f35ce0279 (patch)
tree8db1dcd33eabde75ca55ceafc6fb380d5f007e50 /src/core/hle/service/nvflinger
parentservice: move hle_ipc from kernel (diff)
downloadyuzu-809148e1a58296ab88c9d3c6719d345f35ce0279.tar
yuzu-809148e1a58296ab88c9d3c6719d345f35ce0279.tar.gz
yuzu-809148e1a58296ab88c9d3c6719d345f35ce0279.tar.bz2
yuzu-809148e1a58296ab88c9d3c6719d345f35ce0279.tar.lz
yuzu-809148e1a58296ab88c9d3c6719d345f35ce0279.tar.xz
yuzu-809148e1a58296ab88c9d3c6719d345f35ce0279.tar.zst
yuzu-809148e1a58296ab88c9d3c6719d345f35ce0279.zip
Diffstat (limited to 'src/core/hle/service/nvflinger')
-rw-r--r--src/core/hle/service/nvflinger/binder.h45
-rw-r--r--src/core/hle/service/nvflinger/buffer_item.h46
-rw-r--r--src/core/hle/service/nvflinger/buffer_item_consumer.cpp59
-rw-r--r--src/core/hle/service/nvflinger/buffer_item_consumer.h28
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_consumer.cpp213
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_consumer.h43
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.cpp115
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.h80
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_defs.h21
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.cpp933
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.h90
-rw-r--r--src/core/hle/service/nvflinger/buffer_slot.h38
-rw-r--r--src/core/hle/service/nvflinger/buffer_transform_flags.h25
-rw-r--r--src/core/hle/service/nvflinger/consumer_base.cpp133
-rw-r--r--src/core/hle/service/nvflinger/consumer_base.h60
-rw-r--r--src/core/hle/service/nvflinger/consumer_listener.h26
-rw-r--r--src/core/hle/service/nvflinger/graphic_buffer_producer.cpp18
-rw-r--r--src/core/hle/service/nvflinger/graphic_buffer_producer.h76
-rw-r--r--src/core/hle/service/nvflinger/hos_binder_driver_server.cpp36
-rw-r--r--src/core/hle/service/nvflinger/hos_binder_driver_server.h37
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp335
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h155
-rw-r--r--src/core/hle/service/nvflinger/parcel.h177
-rw-r--r--src/core/hle/service/nvflinger/pixel_format.h21
-rw-r--r--src/core/hle/service/nvflinger/producer_listener.h17
-rw-r--r--src/core/hle/service/nvflinger/status.h28
-rw-r--r--src/core/hle/service/nvflinger/ui/fence.h32
-rw-r--r--src/core/hle/service/nvflinger/ui/graphic_buffer.h100
-rw-r--r--src/core/hle/service/nvflinger/window.h53
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(&timestamp, &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