blob: ba8fefe7be1ae1e869dd0abf812e2eeb6d3b4b87 [file] [log] [blame]
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08001#include "include/private/dvr/buffer_hub_queue_client.h"
2
Alex Vakulenko4fe60582017-02-02 11:35:59 -08003#include <inttypes.h>
4#include <log/log.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08005#include <sys/epoll.h>
6
7#include <array>
8
9#include <pdx/default_transport/client_channel.h>
10#include <pdx/default_transport/client_channel_factory.h>
11#include <pdx/file_handle.h>
12#include <private/dvr/bufferhub_rpc.h>
13
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070014using android::pdx::ErrorStatus;
15using android::pdx::LocalChannelHandle;
16using android::pdx::Status;
17
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080018namespace android {
19namespace dvr {
20
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070021BufferHubQueue::BufferHubQueue(LocalChannelHandle channel_handle)
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080022 : Client{pdx::default_transport::ClientChannel::Create(
23 std::move(channel_handle))},
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070024 meta_size_(0),
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080025 buffers_(BufferHubQueue::kMaxQueueCapacity),
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -080026 epollhup_pending_(BufferHubQueue::kMaxQueueCapacity, false),
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080027 available_buffers_(BufferHubQueue::kMaxQueueCapacity),
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -070028 fences_(BufferHubQueue::kMaxQueueCapacity),
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070029 capacity_(0),
30 id_(-1) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080031 Initialize();
32}
33
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070034BufferHubQueue::BufferHubQueue(const std::string& endpoint_path)
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080035 : Client{pdx::default_transport::ClientChannelFactory::Create(
36 endpoint_path)},
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070037 meta_size_(0),
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080038 buffers_(BufferHubQueue::kMaxQueueCapacity),
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -080039 epollhup_pending_(BufferHubQueue::kMaxQueueCapacity, false),
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080040 available_buffers_(BufferHubQueue::kMaxQueueCapacity),
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -070041 fences_(BufferHubQueue::kMaxQueueCapacity),
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070042 capacity_(0),
43 id_(-1) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080044 Initialize();
45}
46
47void BufferHubQueue::Initialize() {
48 int ret = epoll_fd_.Create();
49 if (ret < 0) {
Alex Vakulenko4fe60582017-02-02 11:35:59 -080050 ALOGE("BufferHubQueue::BufferHubQueue: Failed to create epoll fd: %s",
51 strerror(-ret));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080052 return;
53 }
54
55 epoll_event event = {.events = EPOLLIN | EPOLLET,
56 .data = {.u64 = static_cast<uint64_t>(
57 BufferHubQueue::kEpollQueueEventIndex)}};
58 ret = epoll_fd_.Control(EPOLL_CTL_ADD, event_fd(), &event);
59 if (ret < 0) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070060 ALOGE("BufferHubQueue::Initialize: Failed to add event fd to epoll set: %s",
Alex Vakulenko4fe60582017-02-02 11:35:59 -080061 strerror(-ret));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080062 }
63}
64
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070065Status<void> BufferHubQueue::ImportQueue() {
66 auto status = InvokeRemoteMethod<BufferHubRPC::GetQueueInfo>();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080067 if (!status) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070068 ALOGE("BufferHubQueue::ImportQueue: Failed to import queue: %s",
69 status.GetErrorMessage().c_str());
70 return ErrorStatus(status.error());
71 } else {
72 SetupQueue(status.get().meta_size_bytes, status.get().id);
73 return {};
74 }
75}
76
77void BufferHubQueue::SetupQueue(size_t meta_size_bytes, int id) {
78 meta_size_ = meta_size_bytes;
79 id_ = id;
80 meta_buffer_tmp_.reset(meta_size_ > 0 ? new uint8_t[meta_size_] : nullptr);
81}
82
83std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateConsumerQueue() {
84 if (auto status = CreateConsumerQueueHandle())
85 return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
86 else
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080087 return nullptr;
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070088}
89
Corey Tabaka8a4e6a92017-04-20 13:42:02 -070090std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateSilentConsumerQueue() {
91 if (auto status = CreateConsumerQueueHandle())
92 return std::unique_ptr<ConsumerQueue>(
93 new ConsumerQueue(status.take(), true));
94 else
95 return nullptr;
96}
97
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070098Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle() {
99 auto status = InvokeRemoteMethod<BufferHubRPC::CreateConsumerQueue>();
100 if (!status) {
101 ALOGE(
102 "BufferHubQueue::CreateConsumerQueue: Failed to create consumer queue: "
103 "%s",
104 status.GetErrorMessage().c_str());
105 return ErrorStatus(status.error());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800106 }
107
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700108 return status;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800109}
110
111bool BufferHubQueue::WaitForBuffers(int timeout) {
112 std::array<epoll_event, kMaxEvents> events;
113
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700114 // Loop at least once to check for hangups.
115 do {
116 ALOGD_IF(TRACE, "BufferHubQueue::WaitForBuffers: count=%zu capacity=%zu",
117 count(), capacity());
118
119 // If there is already a buffer then just check for hangup without waiting.
120 const int ret = epoll_fd_.Wait(events.data(), events.size(),
121 count() == 0 ? timeout : 0);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800122
123 if (ret == 0) {
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700124 ALOGI_IF(TRACE,
125 "BufferHubQueue::WaitForBuffers: No events before timeout.");
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700126 return count() != 0;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800127 }
128
129 if (ret < 0 && ret != -EINTR) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700130 ALOGE("BufferHubQueue::WaitForBuffers: Failed to wait for buffers: %s",
131 strerror(-ret));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800132 return false;
133 }
134
135 const int num_events = ret;
136
137 // A BufferQueue's epoll fd tracks N+1 events, where there are N events,
138 // one for each buffer, in the queue and one extra event for the queue
139 // client itself.
140 for (int i = 0; i < num_events; i++) {
141 int64_t index = static_cast<int64_t>(events[i].data.u64);
142
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700143 ALOGD_IF(TRACE,
144 "BufferHubQueue::WaitForBuffers: event %d: index=%" PRId64, i,
145 index);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800146
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800147 if (is_buffer_event_index(index)) {
148 HandleBufferEvent(static_cast<size_t>(index), events[i]);
149 } else if (is_queue_event_index(index)) {
150 HandleQueueEvent(events[i]);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800151 } else {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700152 ALOGW("BufferHubQueue::WaitForBuffers: Unknown event index: %" PRId64,
153 index);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800154 }
155 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700156 } while (count() == 0 && capacity() > 0 && !hung_up());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800157
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700158 return count() != 0;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800159}
160
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800161void BufferHubQueue::HandleBufferEvent(size_t slot, const epoll_event& event) {
162 auto buffer = buffers_[slot];
163 if (!buffer) {
164 ALOGW("BufferHubQueue::HandleBufferEvent: Invalid buffer slot: %zu", slot);
165 return;
166 }
167
168 auto status = buffer->GetEventMask(event.events);
169 if (!status) {
170 ALOGW("BufferHubQueue::HandleBufferEvent: Failed to get event mask: %s",
171 status.GetErrorMessage().c_str());
172 return;
173 }
174
175 int events = status.get();
176 if (events & EPOLLIN) {
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700177 int ret = OnBufferReady(buffer, &fences_[slot]);
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800178 if (ret < 0) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700179 ALOGE("BufferHubQueue::HandleBufferEvent: Failed to set buffer ready: %s",
180 strerror(-ret));
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800181 return;
182 }
183 Enqueue(buffer, slot);
184 } else if (events & EPOLLHUP) {
185 // This might be caused by producer replacing an existing buffer slot, or
186 // when BufferHubQueue is shutting down. For the first case, currently the
187 // epoll FD is cleaned up when the replacement consumer client is imported,
188 // we shouldn't detach again if |epollhub_pending_[slot]| is set.
189 ALOGW(
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700190 "BufferHubQueue::HandleBufferEvent: Received EPOLLHUP at slot: %zu, "
191 "buffer event fd: %d, EPOLLHUP pending: %d",
Alex Vakulenkoa1336cf2017-03-31 08:29:28 -0700192 slot, buffer->event_fd(), int{epollhup_pending_[slot]});
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800193 if (epollhup_pending_[slot]) {
194 epollhup_pending_[slot] = false;
195 } else {
196 DetachBuffer(slot);
197 }
198 } else {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700199 ALOGW(
200 "BufferHubQueue::HandleBufferEvent: Unknown event, slot=%zu, epoll "
201 "events=%d",
202 slot, events);
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800203 }
204}
205
206void BufferHubQueue::HandleQueueEvent(const epoll_event& event) {
207 auto status = GetEventMask(event.events);
208 if (!status) {
209 ALOGW("BufferHubQueue::HandleQueueEvent: Failed to get event mask: %s",
210 status.GetErrorMessage().c_str());
211 return;
212 }
213
214 int events = status.get();
215 if (events & EPOLLIN) {
216 // Note that after buffer imports, if |count()| still returns 0, epoll
217 // wait will be tried again to acquire the newly imported buffer.
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700218 auto buffer_status = OnBufferAllocated();
219 if (!buffer_status) {
220 ALOGE("BufferHubQueue::HandleQueueEvent: Failed to import buffer: %s",
221 buffer_status.GetErrorMessage().c_str());
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800222 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700223 } else if (events & EPOLLHUP) {
224 ALOGD_IF(TRACE, "BufferHubQueue::HandleQueueEvent: hang up event!");
225 hung_up_ = true;
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800226 } else {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700227 ALOGW("BufferHubQueue::HandleQueueEvent: Unknown epoll events=%d", events);
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800228 }
229}
230
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800231int BufferHubQueue::AddBuffer(const std::shared_ptr<BufferHubBuffer>& buf,
232 size_t slot) {
233 if (is_full()) {
234 // TODO(jwcai) Move the check into Producer's AllocateBuffer and consumer's
235 // import buffer.
Alex Vakulenko4fe60582017-02-02 11:35:59 -0800236 ALOGE("BufferHubQueue::AddBuffer queue is at maximum capacity: %zu",
237 capacity_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800238 return -E2BIG;
239 }
240
241 if (buffers_[slot] != nullptr) {
242 // Replace the buffer if the slot is preoccupied. This could happen when the
243 // producer side replaced the slot with a newly allocated buffer. Detach the
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800244 // buffer before setting up with the new one.
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800245 DetachBuffer(slot);
Jiwen 'Steve' Caidc14e5b2017-01-24 17:05:12 -0800246 epollhup_pending_[slot] = true;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800247 }
248
249 epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u64 = slot}};
250 const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, buf->event_fd(), &event);
251 if (ret < 0) {
Alex Vakulenko4fe60582017-02-02 11:35:59 -0800252 ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s",
253 strerror(-ret));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800254 return ret;
255 }
256
257 buffers_[slot] = buf;
258 capacity_++;
259 return 0;
260}
261
262int BufferHubQueue::DetachBuffer(size_t slot) {
263 auto& buf = buffers_[slot];
264 if (buf == nullptr) {
Alex Vakulenko4fe60582017-02-02 11:35:59 -0800265 ALOGE("BufferHubQueue::DetachBuffer: Invalid slot: %zu", slot);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800266 return -EINVAL;
267 }
268
269 const int ret = epoll_fd_.Control(EPOLL_CTL_DEL, buf->event_fd(), nullptr);
270 if (ret < 0) {
Alex Vakulenko4fe60582017-02-02 11:35:59 -0800271 ALOGE(
272 "BufferHubQueue::DetachBuffer: Failed to detach buffer from epoll set: "
273 "%s",
274 strerror(-ret));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800275 return ret;
276 }
277
278 buffers_[slot] = nullptr;
279 capacity_--;
280 return 0;
281}
282
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700283void BufferHubQueue::Enqueue(const std::shared_ptr<BufferHubBuffer>& buf,
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800284 size_t slot) {
285 if (count() == capacity_) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700286 ALOGE("BufferHubQueue::Enqueue: Buffer queue is full!");
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800287 return;
288 }
289
290 // Set slot buffer back to vector.
291 // TODO(jwcai) Here have to dynamically allocate BufferInfo::metadata due to
292 // the limitation of the RingBuffer we are using. Would be better to refactor
293 // that.
294 BufferInfo buffer_info(slot, meta_size_);
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700295 buffer_info.buffer = buf;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800296 // Swap metadata loaded during onBufferReady into vector.
297 std::swap(buffer_info.metadata, meta_buffer_tmp_);
298
299 available_buffers_.Append(std::move(buffer_info));
300}
301
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700302Status<std::shared_ptr<BufferHubBuffer>> BufferHubQueue::Dequeue(
303 int timeout, size_t* slot, void* meta, LocalHandle* fence) {
Jiwen 'Steve' Cai25fd3fa2017-03-20 15:30:21 -0700304 ALOGD_IF(TRACE, "Dequeue: count=%zu, timeout=%d", count(), timeout);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800305
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700306 if (!WaitForBuffers(timeout))
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700307 return ErrorStatus(ETIMEDOUT);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800308
309 std::shared_ptr<BufferHubBuffer> buf;
310 BufferInfo& buffer_info = available_buffers_.Front();
311
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700312 *fence = std::move(fences_[buffer_info.slot]);
313
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800314 // Report current pos as the output slot.
315 std::swap(buffer_info.slot, *slot);
316 // Swap buffer from vector to be returned later.
317 std::swap(buffer_info.buffer, buf);
318 // Swap metadata from vector into tmp so that we can write out to |meta|.
319 std::swap(buffer_info.metadata, meta_buffer_tmp_);
320
321 available_buffers_.PopFront();
322
323 if (!buf) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700324 ALOGE("BufferHubQueue::Dequeue: Buffer to be dequeued is nullptr");
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700325 return ErrorStatus(ENOBUFS);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800326 }
327
328 if (meta) {
329 std::copy(meta_buffer_tmp_.get(), meta_buffer_tmp_.get() + meta_size_,
330 reinterpret_cast<uint8_t*>(meta));
331 }
332
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700333 return {std::move(buf)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800334}
335
336ProducerQueue::ProducerQueue(size_t meta_size)
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700337 : ProducerQueue(meta_size, 0, 0, 0, 0) {}
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800338
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700339ProducerQueue::ProducerQueue(LocalChannelHandle handle)
340 : BASE(std::move(handle)) {
341 auto status = ImportQueue();
342 if (!status) {
343 ALOGE("ProducerQueue::ProducerQueue: Failed to import queue: %s",
344 status.GetErrorMessage().c_str());
345 Close(-status.error());
346 }
347}
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800348
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700349ProducerQueue::ProducerQueue(size_t meta_size, uint64_t usage_set_mask,
350 uint64_t usage_clear_mask,
351 uint64_t usage_deny_set_mask,
352 uint64_t usage_deny_clear_mask)
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700353 : BASE(BufferHubRPC::kClientPath) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800354 auto status = InvokeRemoteMethod<BufferHubRPC::CreateProducerQueue>(
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700355 meta_size, UsagePolicy{usage_set_mask, usage_clear_mask,
356 usage_deny_set_mask, usage_deny_clear_mask});
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800357 if (!status) {
Alex Vakulenko4fe60582017-02-02 11:35:59 -0800358 ALOGE("ProducerQueue::ProducerQueue: Failed to create producer queue: %s",
359 status.GetErrorMessage().c_str());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800360 Close(-status.error());
361 return;
362 }
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700363
364 SetupQueue(status.get().meta_size_bytes, status.get().id);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800365}
366
Corey Tabakacd52dd92017-04-07 18:03:57 -0700367int ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height,
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700368 uint32_t format, uint64_t usage,
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800369 size_t slice_count, size_t* out_slot) {
370 if (out_slot == nullptr) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700371 ALOGE("ProducerQueue::AllocateBuffer: Parameter out_slot cannot be null.");
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800372 return -EINVAL;
373 }
374
375 if (is_full()) {
Alex Vakulenko4fe60582017-02-02 11:35:59 -0800376 ALOGE("ProducerQueue::AllocateBuffer queue is at maximum capacity: %zu",
377 capacity());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800378 return -E2BIG;
379 }
380
381 const size_t kBufferCount = 1U;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800382 Status<std::vector<std::pair<LocalChannelHandle, size_t>>> status =
383 InvokeRemoteMethod<BufferHubRPC::ProducerQueueAllocateBuffers>(
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700384 width, height, format, usage, slice_count, kBufferCount);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800385 if (!status) {
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700386 ALOGE("ProducerQueue::AllocateBuffer failed to create producer buffer: %s",
387 status.GetErrorMessage().c_str());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800388 return -status.error();
389 }
390
391 auto buffer_handle_slots = status.take();
Alex Vakulenko4fe60582017-02-02 11:35:59 -0800392 LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != kBufferCount,
393 "BufferHubRPC::ProducerQueueAllocateBuffers should "
394 "return one and only one buffer handle.");
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800395
396 // We only allocate one buffer at a time.
397 auto& buffer_handle = buffer_handle_slots[0].first;
398 size_t buffer_slot = buffer_handle_slots[0].second;
Jiwen 'Steve' Cai25fd3fa2017-03-20 15:30:21 -0700399 ALOGD_IF(TRACE,
400 "ProducerQueue::AllocateBuffer, new buffer, channel_handle: %d",
401 buffer_handle.value());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800402
403 *out_slot = buffer_slot;
404 return AddBuffer(BufferProducer::Import(std::move(buffer_handle)),
405 buffer_slot);
406}
407
408int ProducerQueue::AddBuffer(const std::shared_ptr<BufferProducer>& buf,
409 size_t slot) {
410 // For producer buffer, we need to enqueue the newly added buffer
411 // immediately. Producer queue starts with all buffers in available state.
412 const int ret = BufferHubQueue::AddBuffer(buf, slot);
413 if (ret < 0)
414 return ret;
415
416 Enqueue(buf, slot);
417 return 0;
418}
419
420int ProducerQueue::DetachBuffer(size_t slot) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700421 auto status =
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800422 InvokeRemoteMethod<BufferHubRPC::ProducerQueueDetachBuffer>(slot);
423 if (!status) {
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700424 ALOGE("ProducerQueue::DetachBuffer: Failed to detach producer buffer: %s",
425 status.GetErrorMessage().c_str());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800426 return -status.error();
427 }
428
429 return BufferHubQueue::DetachBuffer(slot);
430}
431
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700432Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue(
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700433 int timeout, size_t* slot, LocalHandle* release_fence) {
434 if (slot == nullptr || release_fence == nullptr) {
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700435 ALOGE("ProducerQueue::Dequeue: Invalid parameter: slot=%p release_fence=%p",
436 slot, release_fence);
437 return ErrorStatus(EINVAL);
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700438 }
439
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700440 auto buffer_status =
441 BufferHubQueue::Dequeue(timeout, slot, nullptr, release_fence);
442 if (!buffer_status)
443 return buffer_status.error_status();
444
445 return {std::static_pointer_cast<BufferProducer>(buffer_status.take())};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800446}
447
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700448int ProducerQueue::OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700449 LocalHandle* release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800450 auto buffer = std::static_pointer_cast<BufferProducer>(buf);
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700451 return buffer->Gain(release_fence);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800452}
453
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700454ConsumerQueue::ConsumerQueue(LocalChannelHandle handle, bool ignore_on_import)
455 : BufferHubQueue(std::move(handle)), ignore_on_import_(ignore_on_import) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700456 auto status = ImportQueue();
457 if (!status) {
458 ALOGE("ConsumerQueue::ConsumerQueue: Failed to import queue: %s",
459 status.GetErrorMessage().c_str());
460 Close(-status.error());
461 }
462
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700463 auto import_status = ImportBuffers();
464 if (import_status) {
465 ALOGI("ConsumerQueue::ConsumerQueue: Imported %zu buffers.",
466 import_status.get());
467 } else {
468 ALOGE("ConsumerQueue::ConsumerQueue: Failed to import buffers: %s",
469 import_status.GetErrorMessage().c_str());
470 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800471}
472
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700473Status<size_t> ConsumerQueue::ImportBuffers() {
474 auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800475 if (!status) {
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700476 ALOGE("ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s",
477 status.GetErrorMessage().c_str());
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700478 return ErrorStatus(status.error());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800479 }
480
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700481 int ret;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800482 int last_error = 0;
483 int imported_buffers = 0;
484
485 auto buffer_handle_slots = status.take();
486 for (auto& buffer_handle_slot : buffer_handle_slots) {
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700487 ALOGD_IF(TRACE, "ConsumerQueue::ImportBuffers: buffer_handle=%d",
Jiwen 'Steve' Cai25fd3fa2017-03-20 15:30:21 -0700488 buffer_handle_slot.first.value());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800489
490 std::unique_ptr<BufferConsumer> buffer_consumer =
491 BufferConsumer::Import(std::move(buffer_handle_slot.first));
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700492
493 // Setup ignore state before adding buffer to the queue.
494 if (ignore_on_import_) {
495 ALOGD_IF(TRACE,
496 "ConsumerQueue::ImportBuffers: Setting buffer to ignored state: "
497 "buffer_id=%d",
498 buffer_consumer->id());
499 ret = buffer_consumer->SetIgnore(true);
500 if (ret < 0) {
501 ALOGE(
502 "ConsumerQueue::ImportBuffers: Failed to set ignored state on "
503 "imported buffer buffer_id=%d: %s",
504 buffer_consumer->id(), strerror(-ret));
505 last_error = ret;
506 }
507 }
508
509 ret = AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800510 if (ret < 0) {
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700511 ALOGE("ConsumerQueue::ImportBuffers: Failed to add buffer: %s",
Alex Vakulenko4fe60582017-02-02 11:35:59 -0800512 strerror(-ret));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800513 last_error = ret;
514 continue;
515 } else {
516 imported_buffers++;
517 }
518 }
519
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700520 if (imported_buffers > 0)
521 return {imported_buffers};
522 else
523 return ErrorStatus(-last_error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800524}
525
526int ConsumerQueue::AddBuffer(const std::shared_ptr<BufferConsumer>& buf,
527 size_t slot) {
528 // Consumer queue starts with all buffers in unavailable state.
529 return BufferHubQueue::AddBuffer(buf, slot);
530}
531
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700532Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue(
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700533 int timeout, size_t* slot, void* meta, size_t meta_size,
534 LocalHandle* acquire_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800535 if (meta_size != meta_size_) {
Alex Vakulenko4fe60582017-02-02 11:35:59 -0800536 ALOGE(
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700537 "ConsumerQueue::Dequeue: Metadata size (%zu) for the dequeuing buffer "
538 "does not match metadata size (%zu) for the queue.",
Alex Vakulenko4fe60582017-02-02 11:35:59 -0800539 meta_size, meta_size_);
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700540 return ErrorStatus(EINVAL);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800541 }
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700542
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700543 if (slot == nullptr || acquire_fence == nullptr) {
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700544 ALOGE(
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700545 "ConsumerQueue::Dequeue: Invalid parameter: slot=%p meta=%p "
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700546 "acquire_fence=%p",
547 slot, meta, acquire_fence);
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700548 return ErrorStatus(EINVAL);
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700549 }
550
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700551 auto buffer_status =
552 BufferHubQueue::Dequeue(timeout, slot, meta, acquire_fence);
553 if (!buffer_status)
554 return buffer_status.error_status();
555
556 return {std::static_pointer_cast<BufferConsumer>(buffer_status.take())};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800557}
558
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700559int ConsumerQueue::OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700560 LocalHandle* acquire_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800561 auto buffer = std::static_pointer_cast<BufferConsumer>(buf);
Jiwen 'Steve' Caied654322017-03-13 17:04:43 -0700562 return buffer->Acquire(acquire_fence, meta_buffer_tmp_.get(), meta_size_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800563}
564
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700565Status<void> ConsumerQueue::OnBufferAllocated() {
566 auto status = ImportBuffers();
567 if (!status) {
568 ALOGE("ConsumerQueue::OnBufferAllocated: Failed to import buffers: %s",
569 status.GetErrorMessage().c_str());
570 return ErrorStatus(status.error());
571 } else if (status.get() == 0) {
572 ALOGW("ConsumerQueue::OnBufferAllocated: No new buffers allocated!");
573 return ErrorStatus(ENOBUFS);
574 } else {
Corey Tabaka9d8bd092017-04-25 16:47:44 -0700575 ALOGD_IF(TRACE,
576 "ConsumerQueue::OnBufferAllocated: Imported %zu consumer buffers.",
577 status.get());
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700578 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800579 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800580}
581
582} // namespace dvr
583} // namespace android