diff options
Diffstat (limited to 'src')
8 files changed, 60 insertions, 21 deletions
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp index 51291539d..215c1ea80 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp | |||
| @@ -175,6 +175,25 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_ | |||
| 175 | return Status::NoError; | 175 | return Status::NoError; |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | Status BufferQueueConsumer::Disconnect() { | ||
| 179 | LOG_DEBUG(Service_Nvnflinger, "called"); | ||
| 180 | |||
| 181 | std::scoped_lock lock{core->mutex}; | ||
| 182 | |||
| 183 | if (core->consumer_listener == nullptr) { | ||
| 184 | LOG_ERROR(Service_Nvnflinger, "no consumer is connected"); | ||
| 185 | return Status::BadValue; | ||
| 186 | } | ||
| 187 | |||
| 188 | core->is_abandoned = true; | ||
| 189 | core->consumer_listener = nullptr; | ||
| 190 | core->queue.clear(); | ||
| 191 | core->FreeAllBuffersLocked(); | ||
| 192 | core->SignalDequeueCondition(); | ||
| 193 | |||
| 194 | return Status::NoError; | ||
| 195 | } | ||
| 196 | |||
| 178 | Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) { | 197 | Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) { |
| 179 | if (out_slot_mask == nullptr) { | 198 | if (out_slot_mask == nullptr) { |
| 180 | LOG_ERROR(Service_Nvnflinger, "out_slot_mask may not be nullptr"); | 199 | LOG_ERROR(Service_Nvnflinger, "out_slot_mask may not be nullptr"); |
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h index 50ed0bb5f..9a6968dfa 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h +++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h | |||
| @@ -32,6 +32,7 @@ public: | |||
| 32 | Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present); | 32 | Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present); |
| 33 | Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence); | 33 | Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence); |
| 34 | Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app); | 34 | Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app); |
| 35 | Status Disconnect(); | ||
| 35 | Status GetReleasedBuffers(u64* out_slot_mask); | 36 | Status GetReleasedBuffers(u64* out_slot_mask); |
| 36 | 37 | ||
| 37 | private: | 38 | private: |
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_core.cpp b/src/core/hle/service/nvnflinger/buffer_queue_core.cpp index ed66f6f5b..4ed5e5978 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvnflinger/buffer_queue_core.cpp | |||
| @@ -14,24 +14,12 @@ BufferQueueCore::BufferQueueCore() = default; | |||
| 14 | 14 | ||
| 15 | BufferQueueCore::~BufferQueueCore() = default; | 15 | BufferQueueCore::~BufferQueueCore() = default; |
| 16 | 16 | ||
| 17 | void BufferQueueCore::NotifyShutdown() { | ||
| 18 | std::scoped_lock lock{mutex}; | ||
| 19 | |||
| 20 | is_shutting_down = true; | ||
| 21 | |||
| 22 | SignalDequeueCondition(); | ||
| 23 | } | ||
| 24 | |||
| 25 | void BufferQueueCore::SignalDequeueCondition() { | 17 | void BufferQueueCore::SignalDequeueCondition() { |
| 26 | dequeue_possible.store(true); | 18 | dequeue_possible.store(true); |
| 27 | dequeue_condition.notify_all(); | 19 | dequeue_condition.notify_all(); |
| 28 | } | 20 | } |
| 29 | 21 | ||
| 30 | bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) { | 22 | bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) { |
| 31 | if (is_shutting_down) { | ||
| 32 | return false; | ||
| 33 | } | ||
| 34 | |||
| 35 | dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); }); | 23 | dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); }); |
| 36 | dequeue_possible.store(false); | 24 | dequeue_possible.store(false); |
| 37 | 25 | ||
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_core.h b/src/core/hle/service/nvnflinger/buffer_queue_core.h index 9164f08a0..e513d183b 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_core.h +++ b/src/core/hle/service/nvnflinger/buffer_queue_core.h | |||
| @@ -34,8 +34,6 @@ public: | |||
| 34 | BufferQueueCore(); | 34 | BufferQueueCore(); |
| 35 | ~BufferQueueCore(); | 35 | ~BufferQueueCore(); |
| 36 | 36 | ||
| 37 | void NotifyShutdown(); | ||
| 38 | |||
| 39 | private: | 37 | private: |
| 40 | void SignalDequeueCondition(); | 38 | void SignalDequeueCondition(); |
| 41 | bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk); | 39 | bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk); |
| @@ -74,7 +72,6 @@ private: | |||
| 74 | u32 transform_hint{}; | 72 | u32 transform_hint{}; |
| 75 | bool is_allocating{}; | 73 | bool is_allocating{}; |
| 76 | mutable std::condition_variable_any is_allocating_condition; | 74 | mutable std::condition_variable_any is_allocating_condition; |
| 77 | bool is_shutting_down{}; | ||
| 78 | }; | 75 | }; |
| 79 | 76 | ||
| 80 | } // namespace Service::android | 77 | } // namespace Service::android |
diff --git a/src/core/hle/service/nvnflinger/consumer_base.cpp b/src/core/hle/service/nvnflinger/consumer_base.cpp index 4dcda8dac..1059e72bf 100644 --- a/src/core/hle/service/nvnflinger/consumer_base.cpp +++ b/src/core/hle/service/nvnflinger/consumer_base.cpp | |||
| @@ -27,6 +27,26 @@ void ConsumerBase::Connect(bool controlled_by_app) { | |||
| 27 | consumer->Connect(shared_from_this(), controlled_by_app); | 27 | consumer->Connect(shared_from_this(), controlled_by_app); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | void ConsumerBase::Abandon() { | ||
| 31 | LOG_DEBUG(Service_Nvnflinger, "called"); | ||
| 32 | |||
| 33 | std::scoped_lock lock{mutex}; | ||
| 34 | |||
| 35 | if (!is_abandoned) { | ||
| 36 | this->AbandonLocked(); | ||
| 37 | is_abandoned = true; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | void ConsumerBase::AbandonLocked() { | ||
| 42 | for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) { | ||
| 43 | this->FreeBufferLocked(i); | ||
| 44 | } | ||
| 45 | // disconnect from the BufferQueue | ||
| 46 | consumer->Disconnect(); | ||
| 47 | consumer = nullptr; | ||
| 48 | } | ||
| 49 | |||
| 30 | void ConsumerBase::FreeBufferLocked(s32 slot_index) { | 50 | void ConsumerBase::FreeBufferLocked(s32 slot_index) { |
| 31 | LOG_DEBUG(Service_Nvnflinger, "slot_index={}", slot_index); | 51 | LOG_DEBUG(Service_Nvnflinger, "slot_index={}", slot_index); |
| 32 | 52 | ||
diff --git a/src/core/hle/service/nvnflinger/consumer_base.h b/src/core/hle/service/nvnflinger/consumer_base.h index 264829414..ea3e9e97a 100644 --- a/src/core/hle/service/nvnflinger/consumer_base.h +++ b/src/core/hle/service/nvnflinger/consumer_base.h | |||
| @@ -24,6 +24,7 @@ class BufferQueueConsumer; | |||
| 24 | class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this<ConsumerBase> { | 24 | class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this<ConsumerBase> { |
| 25 | public: | 25 | public: |
| 26 | void Connect(bool controlled_by_app); | 26 | void Connect(bool controlled_by_app); |
| 27 | void Abandon(); | ||
| 27 | 28 | ||
| 28 | protected: | 29 | protected: |
| 29 | explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_); | 30 | explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_); |
| @@ -34,6 +35,7 @@ protected: | |||
| 34 | void OnBuffersReleased() override; | 35 | void OnBuffersReleased() override; |
| 35 | void OnSidebandStreamChanged() override; | 36 | void OnSidebandStreamChanged() override; |
| 36 | 37 | ||
| 38 | void AbandonLocked(); | ||
| 37 | void FreeBufferLocked(s32 slot_index); | 39 | void FreeBufferLocked(s32 slot_index); |
| 38 | Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when); | 40 | Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when); |
| 39 | Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer); | 41 | Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer); |
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index bebb45eae..0745434c5 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp | |||
| @@ -47,7 +47,10 @@ void Nvnflinger::SplitVSync(std::stop_token stop_token) { | |||
| 47 | vsync_signal.Wait(); | 47 | vsync_signal.Wait(); |
| 48 | 48 | ||
| 49 | const auto lock_guard = Lock(); | 49 | const auto lock_guard = Lock(); |
| 50 | Compose(); | 50 | |
| 51 | if (!is_abandoned) { | ||
| 52 | Compose(); | ||
| 53 | } | ||
| 51 | } | 54 | } |
| 52 | } | 55 | } |
| 53 | 56 | ||
| @@ -98,7 +101,6 @@ Nvnflinger::~Nvnflinger() { | |||
| 98 | } | 101 | } |
| 99 | 102 | ||
| 100 | ShutdownLayers(); | 103 | ShutdownLayers(); |
| 101 | vsync_thread = {}; | ||
| 102 | 104 | ||
| 103 | if (nvdrv) { | 105 | if (nvdrv) { |
| 104 | nvdrv->Close(disp_fd); | 106 | nvdrv->Close(disp_fd); |
| @@ -106,12 +108,20 @@ Nvnflinger::~Nvnflinger() { | |||
| 106 | } | 108 | } |
| 107 | 109 | ||
| 108 | void Nvnflinger::ShutdownLayers() { | 110 | void Nvnflinger::ShutdownLayers() { |
| 109 | const auto lock_guard = Lock(); | 111 | // Abandon consumers. |
| 110 | for (auto& display : displays) { | 112 | { |
| 111 | for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { | 113 | const auto lock_guard = Lock(); |
| 112 | display.GetLayer(layer).Core().NotifyShutdown(); | 114 | for (auto& display : displays) { |
| 115 | for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { | ||
| 116 | display.GetLayer(layer).GetConsumer().Abandon(); | ||
| 117 | } | ||
| 113 | } | 118 | } |
| 119 | |||
| 120 | is_abandoned = true; | ||
| 114 | } | 121 | } |
| 122 | |||
| 123 | // Join the vsync thread, if it exists. | ||
| 124 | vsync_thread = {}; | ||
| 115 | } | 125 | } |
| 116 | 126 | ||
| 117 | void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { | 127 | void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { |
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index 959d8b46b..f5d73acdb 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h | |||
| @@ -140,6 +140,8 @@ private: | |||
| 140 | 140 | ||
| 141 | s32 swap_interval = 1; | 141 | s32 swap_interval = 1; |
| 142 | 142 | ||
| 143 | bool is_abandoned = false; | ||
| 144 | |||
| 143 | /// Event that handles screen composition. | 145 | /// Event that handles screen composition. |
| 144 | std::shared_ptr<Core::Timing::EventType> multi_composition_event; | 146 | std::shared_ptr<Core::Timing::EventType> multi_composition_event; |
| 145 | std::shared_ptr<Core::Timing::EventType> single_composition_event; | 147 | std::shared_ptr<Core::Timing::EventType> single_composition_event; |