mirror of
https://github.com/yuzu-mirror/yuzu
synced 2024-11-27 05:10:19 +00:00
Merge pull request #11917 from liamwhite/abandonment
nvnflinger: implement consumer abandonment
This commit is contained in:
commit
6c64d5aff2
8 changed files with 60 additions and 21 deletions
|
@ -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");
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue