diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index fab7a12e4..67d82c2bf 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "common/alignment.h" +#include "common/scope_exit.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" #include "core/hle/service/vi/vi.h" @@ -721,8 +722,30 @@ Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) { void NVFlinger::Compose() { for (auto& display : displays) { - // TODO(Subv): Gather the surfaces and forward them to the GPU for drawing. - display.vsync_event->Signal(); + // Trigger vsync for this display at the end of drawing + SCOPE_EXIT({ display.vsync_event->Signal(); }); + + // Don't do anything for displays without layers. + if (display.layers.empty()) + continue; + + // TODO(Subv): Support more than 1 layer. + ASSERT_MSG(display.layers.size() == 1, "Max 1 layer per display is supported"); + + Layer& layer = display.layers[0]; + auto& buffer_queue = layer.buffer_queue; + + // Search for a queued buffer and acquire it + auto buffer = buffer_queue->AcquireBuffer(); + + if (buffer == boost::none) { + // There was no queued buffer to draw. + continue; + } + + // TODO(Subv): Send the buffer to the GPU for drawing. + + buffer_queue->ReleaseBuffer(buffer->slot); } } @@ -732,7 +755,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) { Buffer buffer{}; buffer.slot = slot; buffer.igbp_buffer = igbp_buffer; - buffer.status = Buffer::Status::Queued; + buffer.status = Buffer::Status::Free; LOG_WARNING(Service, "Adding graphics buffer %u", slot); @@ -741,8 +764,9 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) { u32 BufferQueue::DequeueBuffer(u32 pixel_format, u32 width, u32 height) { auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { - // Only consider enqueued buffers - if (buffer.status != Buffer::Status::Queued) + // Only consider free buffers. Buffers become free once again after they've been Acquired + // and Released by the compositor, see the NVFlinger::Compose method. + if (buffer.status != Buffer::Status::Free) return false; // Make sure that the parameters match. @@ -772,6 +796,24 @@ void BufferQueue::QueueBuffer(u32 slot) { itr->status = Buffer::Status::Queued; } +boost::optional BufferQueue::AcquireBuffer() { + auto itr = std::find_if(queue.begin(), queue.end(), [](const Buffer& buffer) { + return buffer.status == Buffer::Status::Queued; + }); + if (itr == queue.end()) + return boost::none; + itr->status = Buffer::Status::Acquired; + return *itr; +} + +void BufferQueue::ReleaseBuffer(u32 slot) { + auto itr = std::find_if(queue.begin(), queue.end(), + [&](const Buffer& buffer) { return buffer.slot == slot; }); + ASSERT(itr != queue.end()); + ASSERT(itr->status == Buffer::Status::Acquired); + itr->status = Buffer::Status::Free; +} + Layer::Layer(u64 id, std::shared_ptr queue) : id(id), buffer_queue(std::move(queue)) {} Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index 1bd8f7472..576c4ce32 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "core/hle/kernel/event.h" #include "core/hle/service/service.h" @@ -34,10 +35,20 @@ public: BufferQueue(u32 id, u64 layer_id); ~BufferQueue() = default; + struct Buffer { + enum class Status { Free = 0, Queued = 1, Dequeued = 2, Acquired = 3 }; + + u32 slot; + Status status = Status::Free; + IGBPBuffer igbp_buffer; + }; + void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer); u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height); const IGBPBuffer& RequestBuffer(u32 slot) const; void QueueBuffer(u32 slot); + boost::optional AcquireBuffer(); + void ReleaseBuffer(u32 slot); u32 GetId() const { return id; @@ -47,14 +58,6 @@ private: u32 id; u64 layer_id; - struct Buffer { - enum class Status { None = 0, Queued = 1, Dequeued = 2 }; - - u32 slot; - Status status = Status::None; - IGBPBuffer igbp_buffer; - }; - std::vector queue; };