From e21fbd9ae5d8139d585019228e1fb1a6229f244c Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 8 Jan 2018 20:28:06 -0500 Subject: [PATCH] NV: Determine what buffer to draw for each layer of each display. Don't try to draw buffers that the guest application is using, only queued buffers are eligible for drawing. Drawing actual pixels is still not implemented. --- src/core/hle/service/vi/vi.cpp | 52 ++++++++++++++++++++++++++++++---- src/core/hle/service/vi/vi.h | 19 +++++++------ 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index fab7a12e46..67d82c2bf7 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 1bd8f74729..576c4ce32b 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; };