nvnflinger: implement consumer abandonment

This commit is contained in:
Liam 2023-10-29 23:38:24 -04:00
parent adb0900906
commit a872030a35
8 changed files with 60 additions and 21 deletions

View file

@ -175,6 +175,25 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_
return Status::NoError; 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) { Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) {
if (out_slot_mask == nullptr) { if (out_slot_mask == nullptr) {
LOG_ERROR(Service_Nvnflinger, "out_slot_mask may not be nullptr"); LOG_ERROR(Service_Nvnflinger, "out_slot_mask may not be nullptr");

View file

@ -32,6 +32,7 @@ public:
Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present); Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present);
Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence); Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence);
Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app); Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app);
Status Disconnect();
Status GetReleasedBuffers(u64* out_slot_mask); Status GetReleasedBuffers(u64* out_slot_mask);
private: private:

View file

@ -14,24 +14,12 @@ BufferQueueCore::BufferQueueCore() = default;
BufferQueueCore::~BufferQueueCore() = default; BufferQueueCore::~BufferQueueCore() = default;
void BufferQueueCore::NotifyShutdown() {
std::scoped_lock lock{mutex};
is_shutting_down = true;
SignalDequeueCondition();
}
void BufferQueueCore::SignalDequeueCondition() { void BufferQueueCore::SignalDequeueCondition() {
dequeue_possible.store(true); dequeue_possible.store(true);
dequeue_condition.notify_all(); dequeue_condition.notify_all();
} }
bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) { bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) {
if (is_shutting_down) {
return false;
}
dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); }); dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); });
dequeue_possible.store(false); dequeue_possible.store(false);

View file

@ -34,8 +34,6 @@ public:
BufferQueueCore(); BufferQueueCore();
~BufferQueueCore(); ~BufferQueueCore();
void NotifyShutdown();
private: private:
void SignalDequeueCondition(); void SignalDequeueCondition();
bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk); bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk);
@ -74,7 +72,6 @@ private:
u32 transform_hint{}; u32 transform_hint{};
bool is_allocating{}; bool is_allocating{};
mutable std::condition_variable_any is_allocating_condition; mutable std::condition_variable_any is_allocating_condition;
bool is_shutting_down{};
}; };
} // namespace Service::android } // namespace Service::android

View file

@ -27,6 +27,26 @@ void ConsumerBase::Connect(bool controlled_by_app) {
consumer->Connect(shared_from_this(), 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) { void ConsumerBase::FreeBufferLocked(s32 slot_index) {
LOG_DEBUG(Service_Nvnflinger, "slot_index={}", slot_index); LOG_DEBUG(Service_Nvnflinger, "slot_index={}", slot_index);

View file

@ -24,6 +24,7 @@ class BufferQueueConsumer;
class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this<ConsumerBase> { class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this<ConsumerBase> {
public: public:
void Connect(bool controlled_by_app); void Connect(bool controlled_by_app);
void Abandon();
protected: protected:
explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_); explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_);
@ -34,6 +35,7 @@ protected:
void OnBuffersReleased() override; void OnBuffersReleased() override;
void OnSidebandStreamChanged() override; void OnSidebandStreamChanged() override;
void AbandonLocked();
void FreeBufferLocked(s32 slot_index); void FreeBufferLocked(s32 slot_index);
Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when); Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when);
Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer); Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer);

View file

@ -47,9 +47,12 @@ void Nvnflinger::SplitVSync(std::stop_token stop_token) {
vsync_signal.Wait(); vsync_signal.Wait();
const auto lock_guard = Lock(); const auto lock_guard = Lock();
if (!is_abandoned) {
Compose(); Compose();
} }
} }
}
Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_) Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_)
: system(system_), service_context(system_, "nvnflinger"), : system(system_), service_context(system_, "nvnflinger"),
@ -98,7 +101,6 @@ Nvnflinger::~Nvnflinger() {
} }
ShutdownLayers(); ShutdownLayers();
vsync_thread = {};
if (nvdrv) { if (nvdrv) {
nvdrv->Close(disp_fd); nvdrv->Close(disp_fd);
@ -106,12 +108,20 @@ Nvnflinger::~Nvnflinger() {
} }
void Nvnflinger::ShutdownLayers() { void Nvnflinger::ShutdownLayers() {
// Abandon consumers.
{
const auto lock_guard = Lock(); const auto lock_guard = Lock();
for (auto& display : displays) { for (auto& display : displays) {
for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
display.GetLayer(layer).Core().NotifyShutdown(); 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) { void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {

View file

@ -140,6 +140,8 @@ private:
s32 swap_interval = 1; s32 swap_interval = 1;
bool is_abandoned = false;
/// Event that handles screen composition. /// Event that handles screen composition.
std::shared_ptr<Core::Timing::EventType> multi_composition_event; std::shared_ptr<Core::Timing::EventType> multi_composition_event;
std::shared_ptr<Core::Timing::EventType> single_composition_event; std::shared_ptr<Core::Timing::EventType> single_composition_event;