summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_consumer.cpp213
1 files changed, 0 insertions, 213 deletions
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