Browse Source
Merge pull request #11917 from liamwhite/abandonment
nvnflinger: implement consumer abandonment
pull/15/merge
liamwhite
2 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with
60 additions and
21 deletions
-
src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
-
src/core/hle/service/nvnflinger/buffer_queue_consumer.h
-
src/core/hle/service/nvnflinger/buffer_queue_core.cpp
-
src/core/hle/service/nvnflinger/buffer_queue_core.h
-
src/core/hle/service/nvnflinger/consumer_base.cpp
-
src/core/hle/service/nvnflinger/consumer_base.h
-
src/core/hle/service/nvnflinger/nvnflinger.cpp
-
src/core/hle/service/nvnflinger/nvnflinger.h
|
|
|
@ -175,6 +175,25 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_ |
|
|
|
return Status::NoError; |
|
|
|
} |
|
|
|
|
|
|
|
Status BufferQueueConsumer::Disconnect() { |
|
|
|
LOG_DEBUG(Service_Nvnflinger, "called"); |
|
|
|
|
|
|
|
std::scoped_lock lock{core->mutex}; |
|
|
|
|
|
|
|
if (core->consumer_listener == nullptr) { |
|
|
|
LOG_ERROR(Service_Nvnflinger, "no consumer is connected"); |
|
|
|
return Status::BadValue; |
|
|
|
} |
|
|
|
|
|
|
|
core->is_abandoned = true; |
|
|
|
core->consumer_listener = nullptr; |
|
|
|
core->queue.clear(); |
|
|
|
core->FreeAllBuffersLocked(); |
|
|
|
core->SignalDequeueCondition(); |
|
|
|
|
|
|
|
return Status::NoError; |
|
|
|
} |
|
|
|
|
|
|
|
Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) { |
|
|
|
if (out_slot_mask == nullptr) { |
|
|
|
LOG_ERROR(Service_Nvnflinger, "out_slot_mask may not be nullptr"); |
|
|
|
|
|
|
|
@ -32,6 +32,7 @@ public: |
|
|
|
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 Disconnect(); |
|
|
|
Status GetReleasedBuffers(u64* out_slot_mask); |
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
@ -14,24 +14,12 @@ 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); |
|
|
|
|
|
|
|
|
|
|
|
@ -34,8 +34,6 @@ public: |
|
|
|
BufferQueueCore(); |
|
|
|
~BufferQueueCore(); |
|
|
|
|
|
|
|
void NotifyShutdown(); |
|
|
|
|
|
|
|
private: |
|
|
|
void SignalDequeueCondition(); |
|
|
|
bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk); |
|
|
|
@ -74,7 +72,6 @@ private: |
|
|
|
u32 transform_hint{}; |
|
|
|
bool is_allocating{}; |
|
|
|
mutable std::condition_variable_any is_allocating_condition; |
|
|
|
bool is_shutting_down{}; |
|
|
|
}; |
|
|
|
|
|
|
|
} // namespace Service::android |
|
|
|
@ -27,6 +27,26 @@ void ConsumerBase::Connect(bool controlled_by_app) { |
|
|
|
consumer->Connect(shared_from_this(), controlled_by_app); |
|
|
|
} |
|
|
|
|
|
|
|
void ConsumerBase::Abandon() { |
|
|
|
LOG_DEBUG(Service_Nvnflinger, "called"); |
|
|
|
|
|
|
|
std::scoped_lock lock{mutex}; |
|
|
|
|
|
|
|
if (!is_abandoned) { |
|
|
|
this->AbandonLocked(); |
|
|
|
is_abandoned = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void ConsumerBase::AbandonLocked() { |
|
|
|
for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) { |
|
|
|
this->FreeBufferLocked(i); |
|
|
|
} |
|
|
|
// disconnect from the BufferQueue
|
|
|
|
consumer->Disconnect(); |
|
|
|
consumer = nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
void ConsumerBase::FreeBufferLocked(s32 slot_index) { |
|
|
|
LOG_DEBUG(Service_Nvnflinger, "slot_index={}", slot_index); |
|
|
|
|
|
|
|
|
|
|
|
@ -24,6 +24,7 @@ class BufferQueueConsumer; |
|
|
|
class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this<ConsumerBase> { |
|
|
|
public: |
|
|
|
void Connect(bool controlled_by_app); |
|
|
|
void Abandon(); |
|
|
|
|
|
|
|
protected: |
|
|
|
explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_); |
|
|
|
@ -34,6 +35,7 @@ protected: |
|
|
|
void OnBuffersReleased() override; |
|
|
|
void OnSidebandStreamChanged() override; |
|
|
|
|
|
|
|
void AbandonLocked(); |
|
|
|
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); |
|
|
|
|
|
|
|
@ -47,7 +47,10 @@ void Nvnflinger::SplitVSync(std::stop_token stop_token) { |
|
|
|
vsync_signal.Wait(); |
|
|
|
|
|
|
|
const auto lock_guard = Lock(); |
|
|
|
Compose(); |
|
|
|
|
|
|
|
if (!is_abandoned) { |
|
|
|
Compose(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -98,7 +101,6 @@ Nvnflinger::~Nvnflinger() { |
|
|
|
} |
|
|
|
|
|
|
|
ShutdownLayers(); |
|
|
|
vsync_thread = {}; |
|
|
|
|
|
|
|
if (nvdrv) { |
|
|
|
nvdrv->Close(disp_fd); |
|
|
|
@ -106,12 +108,20 @@ Nvnflinger::~Nvnflinger() { |
|
|
|
} |
|
|
|
|
|
|
|
void Nvnflinger::ShutdownLayers() { |
|
|
|
const auto lock_guard = Lock(); |
|
|
|
for (auto& display : displays) { |
|
|
|
for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { |
|
|
|
display.GetLayer(layer).Core().NotifyShutdown(); |
|
|
|
// Abandon consumers.
|
|
|
|
{ |
|
|
|
const auto lock_guard = Lock(); |
|
|
|
for (auto& display : displays) { |
|
|
|
for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { |
|
|
|
display.GetLayer(layer).GetConsumer().Abandon(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
is_abandoned = true; |
|
|
|
} |
|
|
|
|
|
|
|
// Join the vsync thread, if it exists.
|
|
|
|
vsync_thread = {}; |
|
|
|
} |
|
|
|
|
|
|
|
void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { |
|
|
|
|
|
|
|
@ -140,6 +140,8 @@ private: |
|
|
|
|
|
|
|
s32 swap_interval = 1; |
|
|
|
|
|
|
|
bool is_abandoned = false; |
|
|
|
|
|
|
|
/// Event that handles screen composition. |
|
|
|
std::shared_ptr<Core::Timing::EventType> multi_composition_event; |
|
|
|
std::shared_ptr<Core::Timing::EventType> single_composition_event; |
|
|
|
|