diff options
18 files changed, 131 insertions, 58 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 555807e19..597890655 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -725,6 +725,7 @@ add_library(core STATIC hle/service/nvnflinger/producer_listener.h hle/service/nvnflinger/status.h hle/service/nvnflinger/ui/fence.h + hle/service/nvnflinger/ui/graphic_buffer.cpp hle/service/nvnflinger/ui/graphic_buffer.h hle/service/nvnflinger/window.h hle/service/olsc/olsc.cpp diff --git a/src/core/hle/service/nvnflinger/buffer_item.h b/src/core/hle/service/nvnflinger/buffer_item.h index 3da8cc3aa..7fd808f54 100644 --- a/src/core/hle/service/nvnflinger/buffer_item.h +++ b/src/core/hle/service/nvnflinger/buffer_item.h @@ -15,7 +15,7 @@ namespace Service::android { -struct GraphicBuffer; +class GraphicBuffer; class BufferItem final { public: diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp index 51291539d..d91886bed 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp @@ -5,7 +5,6 @@ // https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp #include "common/logging/log.h" -#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvnflinger/buffer_item.h" #include "core/hle/service/nvnflinger/buffer_queue_consumer.h" #include "core/hle/service/nvnflinger/buffer_queue_core.h" @@ -14,9 +13,8 @@ namespace Service::android { -BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_, - Service::Nvidia::NvCore::NvMap& nvmap_) - : core{std::move(core_)}, slots{core->slots}, nvmap(nvmap_) {} +BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_) + : core{std::move(core_)}, slots{core->slots} {} BufferQueueConsumer::~BufferQueueConsumer() = default; @@ -136,8 +134,6 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc slots[slot].buffer_state = BufferState::Free; - nvmap.FreeHandle(slots[slot].graphic_buffer->BufferId(), true); - listener = core->connected_producer_listener; LOG_DEBUG(Service_Nvnflinger, "releasing slot {}", slot); @@ -175,6 +171,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"); diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h index 50ed0bb5f..0a61e8dbd 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h +++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h @@ -13,10 +13,6 @@ #include "core/hle/service/nvnflinger/buffer_queue_defs.h" #include "core/hle/service/nvnflinger/status.h" -namespace Service::Nvidia::NvCore { -class NvMap; -} // namespace Service::Nvidia::NvCore - namespace Service::android { class BufferItem; @@ -25,19 +21,18 @@ class IConsumerListener; class BufferQueueConsumer final { public: - explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_, - Service::Nvidia::NvCore::NvMap& nvmap_); + explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_); ~BufferQueueConsumer(); 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: std::shared_ptr<BufferQueueCore> core; BufferQueueDefs::SlotsType& slots; - Service::Nvidia::NvCore::NvMap& nvmap; }; } // namespace Service::android 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; 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); 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: 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 diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp index 6e7a49658..5d8762d25 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp @@ -13,7 +13,6 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/service/hle_ipc.h" #include "core/hle/service/kernel_helpers.h" -#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvnflinger/buffer_queue_core.h" #include "core/hle/service/nvnflinger/buffer_queue_producer.h" #include "core/hle/service/nvnflinger/consumer_listener.h" @@ -533,8 +532,6 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input, item.is_droppable = core->dequeue_buffer_cannot_block || async; item.swap_interval = swap_interval; - nvmap.DuplicateHandle(item.graphic_buffer->BufferId(), true); - sticky_transform = sticky_transform_; if (core->queue.empty()) { @@ -744,19 +741,13 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) { return Status::NoError; } - // HACK: We are not Android. Remove handle for items in queue, and clear queue. - // Allows synchronous destruction of nvmap handles. - for (auto& item : core->queue) { - nvmap.FreeHandle(item.graphic_buffer->BufferId(), true); - } - core->queue.clear(); - switch (api) { case NativeWindowApi::Egl: case NativeWindowApi::Cpu: case NativeWindowApi::Media: case NativeWindowApi::Camera: if (core->connected_api == api) { + core->queue.clear(); core->FreeAllBuffersLocked(); core->connected_producer_listener = nullptr; core->connected_api = NativeWindowApi::NoConnectedApi; @@ -785,7 +776,7 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) { } Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot, - const std::shared_ptr<GraphicBuffer>& buffer) { + const std::shared_ptr<NvGraphicBuffer>& buffer) { LOG_DEBUG(Service_Nvnflinger, "slot {}", slot); if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { @@ -796,7 +787,7 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot, slots[slot] = {}; slots[slot].fence = Fence::NoFence(); - slots[slot].graphic_buffer = buffer; + slots[slot].graphic_buffer = std::make_shared<GraphicBuffer>(nvmap, buffer); slots[slot].frame_number = 0; // Most games preallocate a buffer and pass a valid buffer here. However, it is possible for @@ -839,7 +830,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u } case TransactionId::SetPreallocatedBuffer: { const auto slot = parcel_in.Read<s32>(); - const auto buffer = parcel_in.ReadObject<GraphicBuffer>(); + const auto buffer = parcel_in.ReadObject<NvGraphicBuffer>(); status = SetPreallocatedBuffer(slot, buffer); break; @@ -867,7 +858,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u status = RequestBuffer(slot, &buf); - parcel_out.WriteFlattenedObject(buf); + parcel_out.WriteFlattenedObject<NvGraphicBuffer>(buf.get()); break; } case TransactionId::QueueBuffer: { diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.h b/src/core/hle/service/nvnflinger/buffer_queue_producer.h index d4201c104..64c17d56c 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_producer.h +++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.h @@ -38,6 +38,7 @@ namespace Service::android { class BufferQueueCore; class IProducerListener; +struct NvGraphicBuffer; class BufferQueueProducer final : public IBinder { public: @@ -65,7 +66,7 @@ public: bool producer_controlled_by_app, QueueBufferOutput* output); Status Disconnect(NativeWindowApi api); - Status SetPreallocatedBuffer(s32 slot, const std::shared_ptr<GraphicBuffer>& buffer); + Status SetPreallocatedBuffer(s32 slot, const std::shared_ptr<NvGraphicBuffer>& buffer); private: BufferQueueProducer(const BufferQueueProducer&) = delete; diff --git a/src/core/hle/service/nvnflinger/buffer_slot.h b/src/core/hle/service/nvnflinger/buffer_slot.h index d8c9dec3b..d25bca049 100644 --- a/src/core/hle/service/nvnflinger/buffer_slot.h +++ b/src/core/hle/service/nvnflinger/buffer_slot.h @@ -13,7 +13,7 @@ namespace Service::android { -struct GraphicBuffer; +class GraphicBuffer; enum class BufferState : u32 { Free = 0, 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) { 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); 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; 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); diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp index 6dc327b8b..d7db24f42 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp @@ -166,7 +166,7 @@ constexpr SharedMemoryPoolLayout SharedBufferPoolLayout = [] { }(); void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) { - auto buffer = std::make_shared<android::GraphicBuffer>(); + auto buffer = std::make_shared<android::NvGraphicBuffer>(); buffer->width = SharedBufferWidth; buffer->height = SharedBufferHeight; buffer->stride = SharedBufferBlockLinearStride; 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) { 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) { 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: 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; diff --git a/src/core/hle/service/nvnflinger/status.h b/src/core/hle/service/nvnflinger/status.h index 7af166c40..3fa0fe15b 100644 --- a/src/core/hle/service/nvnflinger/status.h +++ b/src/core/hle/service/nvnflinger/status.h @@ -19,7 +19,7 @@ enum class Status : s32 { Busy = -16, NoInit = -19, BadValue = -22, - InvalidOperation = -37, + InvalidOperation = -38, BufferNeedsReallocation = 1, ReleaseAllBuffers = 2, }; diff --git a/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp b/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp new file mode 100644 index 000000000..ce70946ec --- /dev/null +++ b/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/service/nvdrv/core/nvmap.h" +#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" + +namespace Service::android { + +static NvGraphicBuffer GetBuffer(std::shared_ptr<NvGraphicBuffer>& buffer) { + if (buffer) { + return *buffer; + } else { + return {}; + } +} + +GraphicBuffer::GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_) + : NvGraphicBuffer(width_, height_, format_, usage_), m_nvmap(nullptr) {} + +GraphicBuffer::GraphicBuffer(Service::Nvidia::NvCore::NvMap& nvmap, + std::shared_ptr<NvGraphicBuffer> buffer) + : NvGraphicBuffer(GetBuffer(buffer)), m_nvmap(std::addressof(nvmap)) { + if (this->BufferId() > 0) { + m_nvmap->DuplicateHandle(this->BufferId(), true); + } +} + +GraphicBuffer::~GraphicBuffer() { + if (m_nvmap != nullptr && this->BufferId() > 0) { + m_nvmap->FreeHandle(this->BufferId(), true); + } +} + +} // namespace Service::android diff --git a/src/core/hle/service/nvnflinger/ui/graphic_buffer.h b/src/core/hle/service/nvnflinger/ui/graphic_buffer.h index 3eac5cedd..da430aa75 100644 --- a/src/core/hle/service/nvnflinger/ui/graphic_buffer.h +++ b/src/core/hle/service/nvnflinger/ui/graphic_buffer.h @@ -6,16 +6,22 @@ #pragma once +#include <memory> + #include "common/common_funcs.h" #include "common/common_types.h" #include "core/hle/service/nvnflinger/pixel_format.h" +namespace Service::Nvidia::NvCore { +class NvMap; +} // namespace Service::Nvidia::NvCore + namespace Service::android { -struct GraphicBuffer final { - constexpr GraphicBuffer() = default; +struct NvGraphicBuffer { + constexpr NvGraphicBuffer() = default; - constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_) + constexpr NvGraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_) : width{static_cast<s32>(width_)}, height{static_cast<s32>(height_)}, format{format_}, usage{static_cast<s32>(usage_)} {} @@ -93,6 +99,17 @@ struct GraphicBuffer final { u32 offset{}; INSERT_PADDING_WORDS(60); }; -static_assert(sizeof(GraphicBuffer) == 0x16C, "GraphicBuffer has wrong size"); +static_assert(sizeof(NvGraphicBuffer) == 0x16C, "NvGraphicBuffer has wrong size"); + +class GraphicBuffer final : public NvGraphicBuffer { +public: + explicit GraphicBuffer(u32 width, u32 height, PixelFormat format, u32 usage); + explicit GraphicBuffer(Service::Nvidia::NvCore::NvMap& nvmap, + std::shared_ptr<NvGraphicBuffer> buffer); + ~GraphicBuffer(); + +private: + Service::Nvidia::NvCore::NvMap* m_nvmap{}; +}; } // namespace Service::android diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index f0b5eff8a..d30f49877 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp @@ -35,7 +35,7 @@ static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_cont return { buffer_queue_core, std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core, nvmap), - std::make_unique<android::BufferQueueConsumer>(buffer_queue_core, nvmap)}; + std::make_unique<android::BufferQueueConsumer>(buffer_queue_core)}; } Display::Display(u64 id, std::string name_, |