forked from eden-emu/eden
		
	hle: nvflinger: Add implementation for BufferQueueCore class.
This commit is contained in:
		
							parent
							
								
									6e7f687df4
								
							
						
					
					
						commit
						bfff7b58fd
					
				
					 3 changed files with 235 additions and 0 deletions
				
			
		|  | @ -543,6 +543,8 @@ add_library(core STATIC | ||||||
|     hle/service/nvflinger/buffer_item_consumer.h |     hle/service/nvflinger/buffer_item_consumer.h | ||||||
|     hle/service/nvflinger/buffer_queue_consumer.cpp |     hle/service/nvflinger/buffer_queue_consumer.cpp | ||||||
|     hle/service/nvflinger/buffer_queue_consumer.h |     hle/service/nvflinger/buffer_queue_consumer.h | ||||||
|  |     hle/service/nvflinger/buffer_queue_core.cpp | ||||||
|  |     hle/service/nvflinger/buffer_queue_core.h | ||||||
|     hle/service/nvflinger/buffer_queue_defs.h |     hle/service/nvflinger/buffer_queue_defs.h | ||||||
|     hle/service/nvflinger/buffer_slot.h |     hle/service/nvflinger/buffer_slot.h | ||||||
|     hle/service/nvflinger/buffer_transform_flags.h |     hle/service/nvflinger/buffer_transform_flags.h | ||||||
|  |  | ||||||
							
								
								
									
										135
									
								
								src/core/hle/service/nvflinger/buffer_queue_core.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								src/core/hle/service/nvflinger/buffer_queue_core.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,135 @@ | ||||||
|  | // SPDX-License-Identifier: GPL-3.0-or-later
 | ||||||
|  | // Copyright 2021 yuzu Emulator Project
 | ||||||
|  | // Copyright 2014 The Android Open Source Project
 | ||||||
|  | // Parts of this implementation were base on:
 | ||||||
|  | // https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueCore.cpp
 | ||||||
|  | 
 | ||||||
|  | #include "common/assert.h" | ||||||
|  | 
 | ||||||
|  | #include "core/hle/service/nvflinger/buffer_queue_core.h" | ||||||
|  | 
 | ||||||
|  | namespace android { | ||||||
|  | 
 | ||||||
|  | BufferQueueCore::BufferQueueCore() : lock{mutex} { | ||||||
|  |     // This is locked on creation, so unlock.
 | ||||||
|  |     lock.unlock(); | ||||||
|  | 
 | ||||||
|  |     for (s32 slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { | ||||||
|  |         free_slots.insert(slot); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void BufferQueueCore::NotifyShutdown() { | ||||||
|  |     std::unique_lock<std::mutex> lk(mutex); | ||||||
|  | 
 | ||||||
|  |     is_shutting_down = true; | ||||||
|  | 
 | ||||||
|  |     SignalDequeueCondition(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void BufferQueueCore::SignalDequeueCondition() { | ||||||
|  |     dequeue_condition.notify_all(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool BufferQueueCore::WaitForDequeueCondition() { | ||||||
|  |     if (is_shutting_down) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     dequeue_condition.wait(lock); | ||||||
|  | 
 | ||||||
|  |     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); | ||||||
|  | 
 | ||||||
|  |     const auto had_buffer = slots[slot].graphic_buffer != nullptr; | ||||||
|  | 
 | ||||||
|  |     slots[slot].graphic_buffer.reset(); | ||||||
|  | 
 | ||||||
|  |     if (slots[slot].buffer_state == BufferState::Acquired) { | ||||||
|  |         slots[slot].needs_cleanup_on_release = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (slots[slot].buffer_state != BufferState::Free) { | ||||||
|  |         free_slots.insert(slot); | ||||||
|  |     } else if (had_buffer) { | ||||||
|  |         // If the slot was FREE, but we had a buffer, we need to move this slot from the free
 | ||||||
|  |         // buffers list to the the free slots list.
 | ||||||
|  |         free_buffers.remove(slot); | ||||||
|  |         free_slots.insert(slot); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     slots[slot].buffer_state = BufferState::Free; | ||||||
|  |     slots[slot].acquire_called = false; | ||||||
|  |     slots[slot].frame_number = 0; | ||||||
|  |     slots[slot].fence = Fence::NoFence(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void BufferQueueCore::FreeAllBuffersLocked() { | ||||||
|  |     queue.clear(); | ||||||
|  |     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) { | ||||||
|  |         std::unique_lock<std::mutex> lk(mutex); | ||||||
|  |         is_allocating_condition.wait(lk); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace android
 | ||||||
							
								
								
									
										98
									
								
								src/core/hle/service/nvflinger/buffer_queue_core.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/core/hle/service/nvflinger/buffer_queue_core.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,98 @@ | ||||||
|  | // SPDX-License-Identifier: GPL-3.0-or-later
 | ||||||
|  | // Copyright 2021 yuzu Emulator Project
 | ||||||
|  | // Copyright 2014 The Android Open Source Project
 | ||||||
|  | // Parts of this implementation were base on:
 | ||||||
|  | // https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/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 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(); | ||||||
|  | 
 | ||||||
|  |     void NotifyShutdown(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     void SignalDequeueCondition(); | ||||||
|  |     bool WaitForDequeueCondition(); | ||||||
|  | 
 | ||||||
|  |     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: | ||||||
|  |     class AutoLock final { | ||||||
|  |     public: | ||||||
|  |         AutoLock(std::shared_ptr<BufferQueueCore>& core_) : core{core_} { | ||||||
|  |             core->lock.lock(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ~AutoLock() { | ||||||
|  |             core->lock.unlock(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     private: | ||||||
|  |         std::shared_ptr<BufferQueueCore>& core; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     mutable std::mutex mutex; | ||||||
|  |     mutable std::unique_lock<std::mutex> lock; | ||||||
|  |     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; | ||||||
|  |     std::set<s32> free_slots; | ||||||
|  |     std::list<s32> free_buffers; | ||||||
|  |     s32 override_max_buffer_count{}; | ||||||
|  |     mutable std::condition_variable dequeue_condition; | ||||||
|  |     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 is_allocating_condition; | ||||||
|  |     bool allow_allocation{true}; | ||||||
|  |     u64 buffer_age{}; | ||||||
|  |     bool is_shutting_down{}; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace android
 | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bunnei
						bunnei