summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp114
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h3
-rw-r--r--src/core/hle/service/vi/vi.cpp16
3 files changed, 63 insertions, 70 deletions
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 191286ce9..377f47e8e 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -22,10 +22,11 @@ BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id)
22BufferQueue::~BufferQueue() = default; 22BufferQueue::~BufferQueue() = default;
23 23
24void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { 24void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {
25 ASSERT(slot < buffer_slots);
25 LOG_WARNING(Service, "Adding graphics buffer {}", slot); 26 LOG_WARNING(Service, "Adding graphics buffer {}", slot);
26 27
27 free_buffers.push_back(slot); 28 free_buffers.push_back(slot);
28 queue.push_back({ 29 buffers[slot] = {
29 .slot = slot, 30 .slot = slot,
30 .status = Buffer::Status::Free, 31 .status = Buffer::Status::Free,
31 .igbp_buffer = igbp_buffer, 32 .igbp_buffer = igbp_buffer,
@@ -33,7 +34,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer)
33 .crop_rect = {}, 34 .crop_rect = {},
34 .swap_interval = 0, 35 .swap_interval = 0,
35 .multi_fence = {}, 36 .multi_fence = {},
36 }); 37 };
37 38
38 buffer_wait_event.writable->Signal(); 39 buffer_wait_event.writable->Signal();
39} 40}
@@ -44,73 +45,57 @@ std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::Dequeue
44 if (free_buffers.empty()) { 45 if (free_buffers.empty()) {
45 return std::nullopt; 46 return std::nullopt;
46 } 47 }
47
48 auto f_itr = free_buffers.begin(); 48 auto f_itr = free_buffers.begin();
49 auto itr = queue.end(); 49 auto slot = buffers.size();
50 50
51 while (f_itr != free_buffers.end()) { 51 while (f_itr != free_buffers.end()) {
52 auto slot = *f_itr; 52 const Buffer& buffer = buffers[*f_itr];
53 itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { 53 if (buffer.status == Buffer::Status::Free && buffer.igbp_buffer.width == width &&
54 // Only consider free buffers. Buffers become free once again after they've been 54 buffer.igbp_buffer.height == height) {
55 // Acquired and Released by the compositor, see the NVFlinger::Compose method. 55 slot = *f_itr;
56 if (buffer.status != Buffer::Status::Free) {
57 return false;
58 }
59
60 if (buffer.slot != slot) {
61 return false;
62 }
63
64 // Make sure that the parameters match.
65 return buffer.igbp_buffer.width == width && buffer.igbp_buffer.height == height;
66 });
67
68 if (itr != queue.end()) {
69 free_buffers.erase(f_itr); 56 free_buffers.erase(f_itr);
70 break; 57 break;
71 } 58 }
72 ++f_itr; 59 ++f_itr;
73 } 60 }
74 61 if (slot == buffers.size()) {
75 if (itr == queue.end()) {
76 return std::nullopt; 62 return std::nullopt;
77 } 63 }
78 64 buffers[slot].status = Buffer::Status::Dequeued;
79 itr->status = Buffer::Status::Dequeued; 65 return {{buffers[slot].slot, &buffers[slot].multi_fence}};
80 return {{itr->slot, &itr->multi_fence}};
81} 66}
82 67
83const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { 68const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const {
84 auto itr = std::find_if(queue.begin(), queue.end(), 69 ASSERT(slot < buffers.size());
85 [&](const Buffer& buffer) { return buffer.slot == slot; }); 70 ASSERT(buffers[slot].status == Buffer::Status::Dequeued);
86 ASSERT(itr != queue.end()); 71 ASSERT(buffers[slot].slot == slot);
87 ASSERT(itr->status == Buffer::Status::Dequeued); 72
88 return itr->igbp_buffer; 73 return buffers[slot].igbp_buffer;
89} 74}
90 75
91void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform, 76void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
92 const Common::Rectangle<int>& crop_rect, u32 swap_interval, 77 const Common::Rectangle<int>& crop_rect, u32 swap_interval,
93 Service::Nvidia::MultiFence& multi_fence) { 78 Service::Nvidia::MultiFence& multi_fence) {
94 auto itr = std::find_if(queue.begin(), queue.end(), 79 ASSERT(slot < buffers.size());
95 [&](const Buffer& buffer) { return buffer.slot == slot; }); 80 ASSERT(buffers[slot].status == Buffer::Status::Dequeued);
96 ASSERT(itr != queue.end()); 81 ASSERT(buffers[slot].slot == slot);
97 ASSERT(itr->status == Buffer::Status::Dequeued); 82
98 itr->status = Buffer::Status::Queued; 83 buffers[slot].status = Buffer::Status::Queued;
99 itr->transform = transform; 84 buffers[slot].transform = transform;
100 itr->crop_rect = crop_rect; 85 buffers[slot].crop_rect = crop_rect;
101 itr->swap_interval = swap_interval; 86 buffers[slot].swap_interval = swap_interval;
102 itr->multi_fence = multi_fence; 87 buffers[slot].multi_fence = multi_fence;
103 queue_sequence.push_back(slot); 88 queue_sequence.push_back(slot);
104} 89}
105 90
106void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence) { 91void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence) {
107 const auto itr = std::find_if(queue.begin(), queue.end(), 92 ASSERT(slot < buffers.size());
108 [slot](const Buffer& buffer) { return buffer.slot == slot; }); 93 ASSERT(buffers[slot].status != Buffer::Status::Free);
109 ASSERT(itr != queue.end()); 94 ASSERT(buffers[slot].slot == slot);
110 ASSERT(itr->status != Buffer::Status::Free); 95
111 itr->status = Buffer::Status::Free; 96 buffers[slot].status = Buffer::Status::Free;
112 itr->multi_fence = multi_fence; 97 buffers[slot].multi_fence = multi_fence;
113 itr->swap_interval = 0; 98 buffers[slot].swap_interval = 0;
114 99
115 free_buffers.push_back(slot); 100 free_buffers.push_back(slot);
116 101
@@ -118,38 +103,39 @@ void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& mult
118} 103}
119 104
120std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { 105std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
121 auto itr = queue.end(); 106 std::size_t buffer_slot = buffers.size();
122 // Iterate to find a queued buffer matching the requested slot. 107 // Iterate to find a queued buffer matching the requested slot.
123 while (itr == queue.end() && !queue_sequence.empty()) { 108 while (buffer_slot == buffers.size() && !queue_sequence.empty()) {
124 const u32 slot = queue_sequence.front(); 109 const auto slot = static_cast<std::size_t>(queue_sequence.front());
125 itr = std::find_if(queue.begin(), queue.end(), [&slot](const Buffer& buffer) { 110 ASSERT(slot < buffers.size());
126 return buffer.status == Buffer::Status::Queued && buffer.slot == slot; 111 if (buffers[slot].status == Buffer::Status::Queued) {
127 }); 112 ASSERT(buffers[slot].slot == slot);
113 buffer_slot = slot;
114 }
128 queue_sequence.pop_front(); 115 queue_sequence.pop_front();
129 } 116 }
130 if (itr == queue.end()) { 117 if (buffer_slot == buffers.size()) {
131 return std::nullopt; 118 return std::nullopt;
132 } 119 }
133 itr->status = Buffer::Status::Acquired; 120 buffers[buffer_slot].status = Buffer::Status::Acquired;
134 return *itr; 121 return {{buffers[buffer_slot]}};
135} 122}
136 123
137void BufferQueue::ReleaseBuffer(u32 slot) { 124void BufferQueue::ReleaseBuffer(u32 slot) {
138 auto itr = std::find_if(queue.begin(), queue.end(), 125 ASSERT(slot < buffers.size());
139 [&](const Buffer& buffer) { return buffer.slot == slot; }); 126 ASSERT(buffers[slot].status == Buffer::Status::Acquired);
140 ASSERT(itr != queue.end()); 127 ASSERT(buffers[slot].slot == slot);
141 ASSERT(itr->status == Buffer::Status::Acquired); 128
142 itr->status = Buffer::Status::Free; 129 buffers[slot].status = Buffer::Status::Free;
143 free_buffers.push_back(slot); 130 free_buffers.push_back(slot);
144 131
145 buffer_wait_event.writable->Signal(); 132 buffer_wait_event.writable->Signal();
146} 133}
147 134
148void BufferQueue::Disconnect() { 135void BufferQueue::Disconnect() {
149 queue.clear(); 136 buffers.fill({});
150 queue_sequence.clear(); 137 queue_sequence.clear();
151 id = 1; 138 buffer_wait_event.writable->Signal();
152 layer_id = 1;
153} 139}
154 140
155u32 BufferQueue::Query(QueryType type) { 141u32 BufferQueue::Query(QueryType type) {
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index e7517c7e1..e610923cb 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -21,6 +21,7 @@ class KernelCore;
21 21
22namespace Service::NVFlinger { 22namespace Service::NVFlinger {
23 23
24constexpr u32 buffer_slots = 0x40;
24struct IGBPBuffer { 25struct IGBPBuffer {
25 u32_le magic; 26 u32_le magic;
26 u32_le width; 27 u32_le width;
@@ -114,7 +115,7 @@ private:
114 u64 layer_id; 115 u64 layer_id;
115 116
116 std::list<u32> free_buffers; 117 std::list<u32> free_buffers;
117 std::vector<Buffer> queue; 118 std::array<Buffer, buffer_slots> buffers;
118 std::list<u32> queue_sequence; 119 std::list<u32> queue_sequence;
119 Kernel::EventPair buffer_wait_event; 120 Kernel::EventPair buffer_wait_event;
120}; 121};
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 5d8841ae8..45cfffe06 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -282,18 +282,24 @@ public:
282 void DeserializeData() override { 282 void DeserializeData() override {
283 [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); 283 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
284 data = Read<Data>(); 284 data = Read<Data>();
285 buffer = Read<NVFlinger::IGBPBuffer>(); 285 if (data.contains_object != 0) {
286 buffer_container = Read<BufferContainer>();
287 }
286 } 288 }
287 289
288 struct Data { 290 struct Data {
289 u32_le slot; 291 u32_le slot;
290 INSERT_PADDING_WORDS(1); 292 u32_le contains_object;
293 };
294
295 struct BufferContainer {
291 u32_le graphic_buffer_length; 296 u32_le graphic_buffer_length;
292 INSERT_PADDING_WORDS(1); 297 INSERT_PADDING_WORDS(1);
298 NVFlinger::IGBPBuffer buffer{};
293 }; 299 };
294 300
295 Data data; 301 Data data{};
296 NVFlinger::IGBPBuffer buffer; 302 BufferContainer buffer_container{};
297}; 303};
298 304
299class IGBPSetPreallocatedBufferResponseParcel : public Parcel { 305class IGBPSetPreallocatedBufferResponseParcel : public Parcel {
@@ -547,7 +553,7 @@ private:
547 case TransactionId::SetPreallocatedBuffer: { 553 case TransactionId::SetPreallocatedBuffer: {
548 IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()}; 554 IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
549 555
550 buffer_queue.SetPreallocatedBuffer(request.data.slot, request.buffer); 556 buffer_queue.SetPreallocatedBuffer(request.data.slot, request.buffer_container.buffer);
551 557
552 IGBPSetPreallocatedBufferResponseParcel response{}; 558 IGBPSetPreallocatedBufferResponseParcel response{};
553 ctx.WriteBuffer(response.Serialize()); 559 ctx.WriteBuffer(response.Serialize());