blob: 816019309f297d4ff72fc057b28d13900df93ce4 [file] [log] [blame]
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08001#include "producer_channel.h"
2
Alex Vakulenko4fe60582017-02-02 11:35:59 -08003#include <log/log.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08004#include <sync/sync.h>
Corey Tabaka52ea25c2017-09-13 18:02:48 -07005#include <sys/epoll.h>
6#include <sys/eventfd.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08007#include <sys/poll.h>
8#include <utils/Trace.h>
9
10#include <algorithm>
11#include <atomic>
12#include <thread>
13
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080014#include <private/dvr/bufferhub_rpc.h>
15#include "consumer_channel.h"
16
17using android::pdx::BorrowedHandle;
Corey Tabakacd52dd92017-04-07 18:03:57 -070018using android::pdx::ErrorStatus;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080019using android::pdx::Message;
20using android::pdx::RemoteChannelHandle;
Corey Tabakacd52dd92017-04-07 18:03:57 -070021using android::pdx::Status;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080022using android::pdx::rpc::BufferWrapper;
23using android::pdx::rpc::DispatchRemoteMethod;
24using android::pdx::rpc::WrapBuffer;
25
26namespace android {
27namespace dvr {
28
Corey Tabaka52ea25c2017-09-13 18:02:48 -070029namespace {
30
31static inline uint64_t FindNextClearedBit(uint64_t bits) {
32 return ~bits - (~bits & (~bits - 1));
33}
34
35} // namespace
36
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080037ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id,
Corey Tabakacd52dd92017-04-07 18:03:57 -070038 uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070039 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -070040 uint64_t usage, size_t user_metadata_size,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070041 int* error)
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080042 : BufferHubChannel(service, channel_id, channel_id, kProducerType),
43 pending_consumers_(0),
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080044 producer_owns_(true),
Corey Tabaka52ea25c2017-09-13 18:02:48 -070045 user_metadata_size_(user_metadata_size),
46 metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
47 user_metadata_size) {
48 if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -070049 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
50 strerror(-ret));
51 *error = ret;
52 return;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080053 }
54
Corey Tabaka52ea25c2017-09-13 18:02:48 -070055 if (int ret = metadata_buffer_.Alloc(metadata_buf_size_, /*height=*/1,
56 /*layer_count=*/1,
57 BufferHubDefs::kMetadataFormat,
58 BufferHubDefs::kMetadataUsage)) {
59 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate metadata: %s",
60 strerror(-ret));
61 *error = ret;
62 return;
63 }
64
65 void* metadata_ptr = nullptr;
66 if (int ret = metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
67 /*y=*/0, metadata_buf_size_,
68 /*height=*/1, &metadata_ptr)) {
69 ALOGE("ProducerChannel::ProducerChannel: Failed to lock metadata.");
70 *error = -ret;
71 return;
72 }
73 metadata_header_ =
74 reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
75
76 // Using placement new here to reuse shared memory instead of new allocation
77 // and also initialize the value to zero.
78 buffer_state_ =
79 new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0);
80 fence_state_ =
81 new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
82
83 acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
84 release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
85 if (!acquire_fence_fd_ || !release_fence_fd_) {
86 ALOGE("ProducerChannel::ProducerChannel: Failed to create shared fences.");
87 *error = -EIO;
88 return;
89 }
90
91 dummy_fence_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
92 if (!dummy_fence_fd_) {
93 ALOGE("ProducerChannel::ProducerChannel: Failed to create dummy fences.");
94 *error = -EIO;
95 return;
96 }
97
98 epoll_event event;
99 event.events = 0;
100 event.data.u64 = 0ULL;
101 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_ADD, dummy_fence_fd_.Get(),
102 &event) < 0) {
103 ALOGE(
104 "ProducerChannel::ProducerChannel: Failed to modify the shared "
105 "release fence to include the dummy fence: %s",
106 strerror(errno));
107 *error = -EIO;
108 return;
109 }
110
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800111 // Success.
112 *error = 0;
113}
114
Corey Tabakacd52dd92017-04-07 18:03:57 -0700115Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
116 BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700117 uint32_t layer_count, uint32_t format, uint64_t usage,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700118 size_t user_metadata_size) {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700119 int error;
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700120 std::shared_ptr<ProducerChannel> producer(
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700121 new ProducerChannel(service, channel_id, width, height, layer_count,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700122 format, usage, user_metadata_size, &error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700123 if (error < 0)
124 return ErrorStatus(-error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800125 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700126 return {std::move(producer)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800127}
128
129ProducerChannel::~ProducerChannel() {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800130 ALOGD_IF(TRACE,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700131 "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
132 "state=%" PRIx64 ".",
133 channel_id(), buffer_id(), buffer_state_->load());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800134 for (auto consumer : consumer_channels_)
135 consumer->OnProducerClosed();
136}
137
138BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700139 // Derive the mask of signaled buffers in this producer / consumer set.
140 uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0;
141 for (const ConsumerChannel* consumer : consumer_channels_) {
142 signaled_mask |= consumer->signaled() ? consumer->consumer_state_bit() : 0;
143 }
144
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -0700145 return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700146 buffer_.height(), buffer_.layer_count(), buffer_.format(),
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700147 buffer_.usage(), pending_consumers_, buffer_state_->load(),
Jiwen 'Steve' Cai2f260332018-02-15 18:39:47 -0800148 signaled_mask, metadata_header_->queue_index);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800149}
150
151void ProducerChannel::HandleImpulse(Message& message) {
152 ATRACE_NAME("ProducerChannel::HandleImpulse");
153 switch (message.GetOp()) {
154 case BufferHubRPC::ProducerGain::Opcode:
155 OnProducerGain(message);
156 break;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700157 case BufferHubRPC::ProducerPost::Opcode:
158 OnProducerPost(message, {});
159 break;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800160 }
161}
162
163bool ProducerChannel::HandleMessage(Message& message) {
164 ATRACE_NAME("ProducerChannel::HandleMessage");
165 switch (message.GetOp()) {
166 case BufferHubRPC::GetBuffer::Opcode:
167 DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
168 *this, &ProducerChannel::OnGetBuffer, message);
169 return true;
170
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800171 case BufferHubRPC::NewConsumer::Opcode:
172 DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
173 *this, &ProducerChannel::OnNewConsumer, message);
174 return true;
175
176 case BufferHubRPC::ProducerPost::Opcode:
177 DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
178 *this, &ProducerChannel::OnProducerPost, message);
179 return true;
180
181 case BufferHubRPC::ProducerGain::Opcode:
182 DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
183 *this, &ProducerChannel::OnProducerGain, message);
184 return true;
185
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800186 default:
187 return false;
188 }
189}
190
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700191BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
192 uint64_t buffer_state_bit) {
193 return {
194 buffer_, metadata_buffer_, buffer_id(),
195 buffer_state_bit, acquire_fence_fd_.Borrow(), release_fence_fd_.Borrow()};
196}
197
198Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
Corey Tabakad53870c2017-07-06 18:04:27 -0700199 Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800200 ATRACE_NAME("ProducerChannel::OnGetBuffer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700201 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
202 buffer_id(), buffer_state_->load());
203 return {GetBuffer(BufferHubDefs::kProducerStateBit)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800204}
205
Corey Tabakacd52dd92017-04-07 18:03:57 -0700206Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800207 ATRACE_NAME("ProducerChannel::CreateConsumer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700208 ALOGD_IF(TRACE,
209 "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
210 buffer_id(), producer_owns_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800211
212 int channel_id;
213 auto status = message.PushChannel(0, nullptr, &channel_id);
214 if (!status) {
215 ALOGE(
Corey Tabakacd52dd92017-04-07 18:03:57 -0700216 "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800217 status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700218 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800219 }
220
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700221 // Try find the next consumer state bit which has not been claimed by any
222 // consumer yet.
223 uint64_t consumer_state_bit = FindNextClearedBit(
224 active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
225 BufferHubDefs::kProducerStateBit);
226 if (consumer_state_bit == 0ULL) {
227 ALOGE(
228 "ProducerChannel::CreateConsumer: reached the maximum mumber of "
229 "consumers per producer: 63.");
230 return ErrorStatus(E2BIG);
231 }
232
233 auto consumer =
234 std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
235 consumer_state_bit, shared_from_this());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700236 const auto channel_status = service()->SetChannel(channel_id, consumer);
237 if (!channel_status) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800238 ALOGE(
239 "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
240 "%s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700241 channel_status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700242 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800243 }
244
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700245 if (!producer_owns_ &&
246 !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800247 // Signal the new consumer when adding it to a posted producer.
248 if (consumer->OnProducerPosted())
249 pending_consumers_++;
250 }
251
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700252 active_consumer_bit_mask_ |= consumer_state_bit;
Corey Tabakacd52dd92017-04-07 18:03:57 -0700253 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800254}
255
Corey Tabakacd52dd92017-04-07 18:03:57 -0700256Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800257 ATRACE_NAME("ProducerChannel::OnNewConsumer");
258 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700259 return CreateConsumer(message);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800260}
261
Corey Tabakacd52dd92017-04-07 18:03:57 -0700262Status<void> ProducerChannel::OnProducerPost(
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700263 Message&, LocalFence acquire_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800264 ATRACE_NAME("ProducerChannel::OnProducerPost");
265 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
266 if (!producer_owns_) {
267 ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700268 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800269 }
270
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700271 epoll_event event;
272 event.events = 0;
273 event.data.u64 = 0ULL;
274 int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
275 dummy_fence_fd_.Get(), &event);
276 ALOGE_IF(ret < 0,
277 "ProducerChannel::OnProducerPost: Failed to modify the shared "
278 "release fence to include the dummy fence: %s",
279 strerror(errno));
280
281 eventfd_t dummy_fence_count = 0ULL;
282 if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
283 const int error = errno;
284 if (error != EAGAIN) {
285 ALOGE(
286 "ProducerChannel::ProducerChannel: Failed to read dummy fence, "
287 "error: %s",
288 strerror(error));
289 return ErrorStatus(error);
290 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700291 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800292
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700293 ALOGW_IF(dummy_fence_count > 0,
294 "ProducerChannel::ProducerChannel: %" PRIu64
295 " dummy fence(s) was signaled during last release/gain cycle "
296 "buffer_id=%d.",
297 dummy_fence_count, buffer_id());
298
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800299 post_fence_ = std::move(acquire_fence);
300 producer_owns_ = false;
301
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700302 // Signal any interested consumers. If there are none, the buffer will stay
303 // in posted state until a consumer comes online. This behavior guarantees
304 // that no frame is silently dropped.
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800305 pending_consumers_ = 0;
306 for (auto consumer : consumer_channels_) {
307 if (consumer->OnProducerPosted())
308 pending_consumers_++;
309 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800310 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
311 pending_consumers_);
312
Corey Tabakacd52dd92017-04-07 18:03:57 -0700313 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800314}
315
Corey Tabakad53870c2017-07-06 18:04:27 -0700316Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800317 ATRACE_NAME("ProducerChannel::OnGain");
318 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
319 if (producer_owns_) {
320 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
321 channel_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700322 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800323 }
324
325 // There are still pending consumers, return busy.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700326 if (pending_consumers_ > 0) {
327 ALOGE(
328 "ProducerChannel::OnGain: Producer (id=%d) is gaining a buffer that "
329 "still has %d pending consumer(s).",
330 buffer_id(), pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700331 return ErrorStatus(EBUSY);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700332 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800333
334 ClearAvailable();
335 producer_owns_ = true;
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700336 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700337 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800338}
339
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700340Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800341 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
342 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
343 buffer_id());
344 if (producer_owns_) {
345 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700346 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800347 }
348
349 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
350 // Serialization just needs to read the handle.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700351 return {std::move(post_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800352}
353
Corey Tabakacd52dd92017-04-07 18:03:57 -0700354Status<void> ProducerChannel::OnConsumerRelease(Message&,
355 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800356 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
357 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
358 buffer_id());
359 if (producer_owns_) {
360 ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700361 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800362 }
363
364 // Attempt to merge the fences if necessary.
365 if (release_fence) {
366 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800367 LocalFence merged_fence(sync_merge("bufferhub_merged",
368 returned_fence_.get_fd(),
369 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800370 const int error = errno;
371 if (!merged_fence) {
372 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
373 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700374 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800375 }
376 returned_fence_ = std::move(merged_fence);
377 } else {
378 returned_fence_ = std::move(release_fence);
379 }
380 }
381
382 OnConsumerIgnored();
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700383 if (pending_consumers_ == 0) {
384 // Clear the producer bit atomically to transit into released state. This
385 // has to done by BufferHub as it requries synchronization among all
386 // consumers.
387 BufferHubDefs::ModifyBufferState(buffer_state_,
388 BufferHubDefs::kProducerStateBit, 0ULL);
389 ALOGD_IF(TRACE,
390 "ProducerChannel::OnConsumerRelease: releasing last consumer: "
391 "buffer_id=%d state=%" PRIx64 ".",
392 buffer_id(), buffer_state_->load());
393
394 if (orphaned_consumer_bit_mask_) {
395 ALOGW(
396 "ProducerChannel::OnConsumerRelease: orphaned buffer detected "
397 "during the this acquire/release cycle: id=%d orphaned=0x%" PRIx64
398 " queue_index=%" PRIu64 ".",
399 buffer_id(), orphaned_consumer_bit_mask_,
400 metadata_header_->queue_index);
401 orphaned_consumer_bit_mask_ = 0;
402 }
403
404 SignalAvailable();
405 }
406
407 ALOGE_IF(pending_consumers_ &&
408 BufferHubDefs::IsBufferReleased(buffer_state_->load()),
409 "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
410 "pending_consumers=%d, buffer buffer is in releaed state.",
411 pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700412 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800413}
414
415void ProducerChannel::OnConsumerIgnored() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700416 if (pending_consumers_ == 0) {
417 ALOGE("ProducerChannel::OnConsumerIgnored: no pending consumer.");
418 return;
419 }
420
421 --pending_consumers_;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800422 ALOGD_IF(TRACE,
423 "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
424 buffer_id(), pending_consumers_);
425}
426
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700427void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) {
428 // Ignore the orphaned consumer.
429 OnConsumerIgnored();
430
431 const uint64_t consumer_state_bit = channel->consumer_state_bit();
432 ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
433 "ProducerChannel::OnConsumerOrphaned: Consumer "
434 "(consumer_state_bit=%" PRIx64 ") is already orphaned.",
435 consumer_state_bit);
436 orphaned_consumer_bit_mask_ |= consumer_state_bit;
437
438 // Atomically clear the fence state bit as an orphaned consumer will never
439 // signal a release fence. Also clear the buffer state as it won't be released
440 // as well.
441 fence_state_->fetch_and(~consumer_state_bit);
442 BufferHubDefs::ModifyBufferState(buffer_state_, consumer_state_bit, 0ULL);
443
444 ALOGW(
445 "ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer "
446 "buffer_id=%d consumer_state_bit=%" PRIx64 " queue_index=%" PRIu64
447 " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
448 buffer_id(), consumer_state_bit, metadata_header_->queue_index,
449 buffer_state_->load(), fence_state_->load());
450}
451
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800452void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
453 consumer_channels_.push_back(channel);
454}
455
456void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
457 consumer_channels_.erase(
458 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700459 active_consumer_bit_mask_ &= ~channel->consumer_state_bit();
460
461 const uint64_t buffer_state = buffer_state_->load();
462 if (BufferHubDefs::IsBufferPosted(buffer_state) ||
463 BufferHubDefs::IsBufferAcquired(buffer_state)) {
464 // The consumer client is being destoryed without releasing. This could
465 // happen in corner cases when the consumer crashes. Here we mark it
466 // orphaned before remove it from producer.
467 OnConsumerOrphaned(channel);
468 }
469
470 if (BufferHubDefs::IsBufferReleased(buffer_state) ||
471 BufferHubDefs::IsBufferGained(buffer_state)) {
472 // The consumer is being close while it is suppose to signal a release
473 // fence. Signal the dummy fence here.
474 if (fence_state_->load() & channel->consumer_state_bit()) {
475 epoll_event event;
476 event.events = EPOLLIN;
477 event.data.u64 = channel->consumer_state_bit();
478 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
479 dummy_fence_fd_.Get(), &event) < 0) {
480 ALOGE(
481 "ProducerChannel::RemoveConsumer: Failed to modify the shared "
482 "release fence to include the dummy fence: %s",
483 strerror(errno));
484 return;
485 }
486 ALOGW(
487 "ProducerChannel::RemoveConsumer: signal dummy release fence "
488 "buffer_id=%d",
489 buffer_id());
490 eventfd_write(dummy_fence_fd_.Get(), 1);
491 }
492 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800493}
494
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800495// Returns true if the given parameters match the underlying buffer parameters.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700496bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700497 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700498 uint64_t usage,
499 size_t user_metadata_size) {
500 return user_metadata_size == user_metadata_size_ &&
501 buffer_.width() == width && buffer_.height() == height &&
502 buffer_.layer_count() == layer_count && buffer_.format() == format &&
503 buffer_.usage() == usage;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800504}
505
506} // namespace dvr
507} // namespace android