Przeglądaj źródła

vi: Remove DequeueBuffer and wait until next available buffer.

bunnei 8 lat temu
rodzic
commit
c1c92c30f9

+ 20 - 5
src/core/hle/service/nvflinger/buffer_queue.cpp

@@ -26,24 +26,30 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) {
     LOG_WARNING(Service, "Adding graphics buffer %u", slot);
     LOG_WARNING(Service, "Adding graphics buffer %u", slot);
 
 
     queue.emplace_back(buffer);
     queue.emplace_back(buffer);
+
+    if (buffer_wait_event) {
+        buffer_wait_event->Signal();
+    }
 }
 }
 
 
-u32 BufferQueue::DequeueBuffer(u32 pixel_format, u32 width, u32 height) {
+boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
     auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) {
     auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) {
         // Only consider free buffers. Buffers become free once again after they've been Acquired
         // Only consider free buffers. Buffers become free once again after they've been Acquired
         // and Released by the compositor, see the NVFlinger::Compose method.
         // and Released by the compositor, see the NVFlinger::Compose method.
-        if (buffer.status != Buffer::Status::Free)
+        if (buffer.status != Buffer::Status::Free) {
             return false;
             return false;
+        }
 
 
         // Make sure that the parameters match.
         // Make sure that the parameters match.
         return buffer.igbp_buffer.width == width && buffer.igbp_buffer.height == height;
         return buffer.igbp_buffer.width == width && buffer.igbp_buffer.height == height;
     });
     });
+
     if (itr == queue.end()) {
     if (itr == queue.end()) {
-        LOG_CRITICAL(Service_NVDRV, "no free buffers for pixel_format=%d, width=%d, height=%d",
-                     pixel_format, width, height);
-        itr = queue.begin();
+        return boost::none;
     }
     }
 
 
+    buffer_wait_event = nullptr;
+
     itr->status = Buffer::Status::Dequeued;
     itr->status = Buffer::Status::Dequeued;
     return itr->slot;
     return itr->slot;
 }
 }
@@ -81,6 +87,10 @@ void BufferQueue::ReleaseBuffer(u32 slot) {
     ASSERT(itr != queue.end());
     ASSERT(itr != queue.end());
     ASSERT(itr->status == Buffer::Status::Acquired);
     ASSERT(itr->status == Buffer::Status::Acquired);
     itr->status = Buffer::Status::Free;
     itr->status = Buffer::Status::Free;
+
+    if (buffer_wait_event) {
+        buffer_wait_event->Signal();
+    }
 }
 }
 
 
 u32 BufferQueue::Query(QueryType type) {
 u32 BufferQueue::Query(QueryType type) {
@@ -96,5 +106,10 @@ u32 BufferQueue::Query(QueryType type) {
     return 0;
     return 0;
 }
 }
 
 
+void BufferQueue::SetBufferWaitEvent(Kernel::SharedPtr<Kernel::Event>&& wait_event) {
+    ASSERT_MSG(!buffer_wait_event, "buffer_wait_event only supports a single waiting thread!");
+    buffer_wait_event = std::move(wait_event);
+}
+
 } // namespace NVFlinger
 } // namespace NVFlinger
 } // namespace Service
 } // namespace Service

+ 5 - 1
src/core/hle/service/nvflinger/buffer_queue.h

@@ -69,12 +69,13 @@ public:
     };
     };
 
 
     void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer);
     void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer);
-    u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height);
+    boost::optional<u32> DequeueBuffer(u32 width, u32 height);
     const IGBPBuffer& RequestBuffer(u32 slot) const;
     const IGBPBuffer& RequestBuffer(u32 slot) const;
     void QueueBuffer(u32 slot, BufferTransformFlags transform);
     void QueueBuffer(u32 slot, BufferTransformFlags transform);
     boost::optional<const Buffer&> AcquireBuffer();
     boost::optional<const Buffer&> AcquireBuffer();
     void ReleaseBuffer(u32 slot);
     void ReleaseBuffer(u32 slot);
     u32 Query(QueryType type);
     u32 Query(QueryType type);
+    void SetBufferWaitEvent(Kernel::SharedPtr<Kernel::Event>&& wait_event);
 
 
     u32 GetId() const {
     u32 GetId() const {
         return id;
         return id;
@@ -90,6 +91,9 @@ private:
 
 
     std::vector<Buffer> queue;
     std::vector<Buffer> queue;
     Kernel::SharedPtr<Kernel::Event> native_handle;
     Kernel::SharedPtr<Kernel::Event> native_handle;
+
+    /// Used to signal waiting thread when no buffers are available
+    Kernel::SharedPtr<Kernel::Event> buffer_wait_event;
 };
 };
 
 
 } // namespace NVFlinger
 } // namespace NVFlinger

+ 24 - 6
src/core/hle/service/vi/vi.cpp

@@ -486,12 +486,30 @@ private:
             ctx.WriteBuffer(response.Serialize());
             ctx.WriteBuffer(response.Serialize());
         } else if (transaction == TransactionId::DequeueBuffer) {
         } else if (transaction == TransactionId::DequeueBuffer) {
             IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
             IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
-
-            u32 slot = buffer_queue->DequeueBuffer(request.data.pixel_format, request.data.width,
-                                                   request.data.height);
-
-            IGBPDequeueBufferResponseParcel response{slot};
-            ctx.WriteBuffer(response.Serialize());
+            const u32 width{request.data.width};
+            const u32 height{request.data.height};
+            boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
+
+            if (slot != boost::none) {
+                // Buffer is available
+                IGBPDequeueBufferResponseParcel response{*slot};
+                ctx.WriteBuffer(response.Serialize());
+            } else {
+                // Wait the current thread until a buffer becomes available
+                auto wait_event = ctx.SleepClientThread(
+                    Kernel::GetCurrentThread(), "IHOSBinderDriver::DequeueBuffer", -1,
+                    [=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
+                        ThreadWakeupReason reason) {
+                        // Repeat TransactParcel DequeueBuffer when a buffer is available
+                        auto buffer_queue = nv_flinger->GetBufferQueue(id);
+                        boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
+                        IGBPDequeueBufferResponseParcel response{*slot};
+                        ctx.WriteBuffer(response.Serialize());
+                        IPC::ResponseBuilder rb{ctx, 2};
+                        rb.Push(RESULT_SUCCESS);
+                    });
+                buffer_queue->SetBufferWaitEvent(std::move(wait_event));
+            }
         } else if (transaction == TransactionId::RequestBuffer) {
         } else if (transaction == TransactionId::RequestBuffer) {
             IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
             IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};