1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "C2BqBuffer"
19 #include <utils/Log.h>
20
21 #include <ui/BufferQueueDefs.h>
22 #include <ui/GraphicBuffer.h>
23 #include <ui/Fence.h>
24
25 #include <types.h>
26
27 #include <hidl/HidlSupport.h>
28
29 #include <C2AllocatorGralloc.h>
30 #include <C2BqBufferPriv.h>
31 #include <C2BlockInternal.h>
32
33 #include <list>
34 #include <map>
35 #include <mutex>
36
37 using ::android::BufferQueueDefs::NUM_BUFFER_SLOTS;
38 using ::android::C2AllocatorGralloc;
39 using ::android::C2AndroidMemoryUsage;
40 using ::android::Fence;
41 using ::android::GraphicBuffer;
42 using ::android::sp;
43 using ::android::status_t;
44 using ::android::wp;
45 using ::android::hardware::hidl_handle;
46 using ::android::hardware::Return;
47
48 using HBuffer = ::android::hardware::graphics::common::V1_2::HardwareBuffer;
49 using HStatus = ::android::hardware::graphics::bufferqueue::V2_0::Status;
50 using ::android::hardware::graphics::bufferqueue::V2_0::utils::b2h;
51 using ::android::hardware::graphics::bufferqueue::V2_0::utils::h2b;
52 using ::android::hardware::graphics::bufferqueue::V2_0::utils::HFenceWrapper;
53
54 using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::V2_0
55 ::IGraphicBufferProducer;
56
57 struct C2BufferQueueBlockPoolData : public _C2BlockPoolData {
58
59 bool held;
60 bool local;
61 uint32_t generation;
62 uint64_t bqId;
63 int32_t bqSlot;
64 bool transfer; // local transfer to remote
65 bool attach; // attach on remote
66 bool display; // display on remote;
67 std::weak_ptr<int> owner;
68 sp<HGraphicBufferProducer> igbp;
69 std::shared_ptr<C2BufferQueueBlockPool::Impl> localPool;
70 mutable std::mutex lock;
71
getTypeC2BufferQueueBlockPoolData72 virtual type_t getType() const override {
73 return TYPE_BUFFERQUEUE;
74 }
75
76 // Create a remote BlockPoolData.
77 C2BufferQueueBlockPoolData(
78 uint32_t generation, uint64_t bqId, int32_t bqSlot,
79 const std::shared_ptr<int> &owner,
80 const sp<HGraphicBufferProducer>& producer);
81
82 // Create a local BlockPoolData.
83 C2BufferQueueBlockPoolData(
84 uint32_t generation, uint64_t bqId, int32_t bqSlot,
85 const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool);
86
87 virtual ~C2BufferQueueBlockPoolData() override;
88
89 int migrate(const sp<HGraphicBufferProducer>& producer,
90 uint32_t toGeneration, uint64_t toBqId,
91 sp<GraphicBuffer> *buffers, uint32_t oldGeneration);
92 };
93
GetBufferQueueData(const std::shared_ptr<const _C2BlockPoolData> & data,uint32_t * generation,uint64_t * bqId,int32_t * bqSlot)94 bool _C2BlockFactory::GetBufferQueueData(
95 const std::shared_ptr<const _C2BlockPoolData>& data,
96 uint32_t* generation, uint64_t* bqId, int32_t* bqSlot) {
97 if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERQUEUE) {
98 if (generation) {
99 const std::shared_ptr<const C2BufferQueueBlockPoolData> poolData =
100 std::static_pointer_cast<const C2BufferQueueBlockPoolData>(data);
101 std::scoped_lock<std::mutex> lock(poolData->lock);
102 *generation = poolData->generation;
103 if (bqId) {
104 *bqId = poolData->bqId;
105 }
106 if (bqSlot) {
107 *bqSlot = poolData->bqSlot;
108 }
109 }
110 return true;
111 }
112 return false;
113 }
114
HoldBlockFromBufferQueue(const std::shared_ptr<_C2BlockPoolData> & data,const std::shared_ptr<int> & owner,const sp<HGraphicBufferProducer> & igbp)115 bool _C2BlockFactory::HoldBlockFromBufferQueue(
116 const std::shared_ptr<_C2BlockPoolData>& data,
117 const std::shared_ptr<int>& owner,
118 const sp<HGraphicBufferProducer>& igbp) {
119 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
120 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
121 std::scoped_lock<std::mutex> lock(poolData->lock);
122 if (!poolData->local) {
123 poolData->owner = owner;
124 poolData->igbp = igbp;
125 }
126 if (poolData->held) {
127 poolData->held = true;
128 return false;
129 }
130 poolData->held = true;
131 return true;
132 }
133
BeginTransferBlockToClient(const std::shared_ptr<_C2BlockPoolData> & data)134 bool _C2BlockFactory::BeginTransferBlockToClient(
135 const std::shared_ptr<_C2BlockPoolData>& data) {
136 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
137 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
138 std::scoped_lock<std::mutex> lock(poolData->lock);
139 poolData->transfer = true;
140 return true;
141 }
142
EndTransferBlockToClient(const std::shared_ptr<_C2BlockPoolData> & data,bool transfer)143 bool _C2BlockFactory::EndTransferBlockToClient(
144 const std::shared_ptr<_C2BlockPoolData>& data,
145 bool transfer) {
146 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
147 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
148 std::scoped_lock<std::mutex> lock(poolData->lock);
149 poolData->transfer = false;
150 if (transfer) {
151 poolData->held = false;
152 }
153 return true;
154 }
155
BeginAttachBlockToBufferQueue(const std::shared_ptr<_C2BlockPoolData> & data)156 bool _C2BlockFactory::BeginAttachBlockToBufferQueue(
157 const std::shared_ptr<_C2BlockPoolData>& data) {
158 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
159 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
160 std::scoped_lock<std::mutex> lock(poolData->lock);
161 if (poolData->local || poolData->display ||
162 poolData->attach || !poolData->held) {
163 return false;
164 }
165 if (poolData->bqId == 0) {
166 return false;
167 }
168 poolData->attach = true;
169 return true;
170 }
171
172 // if display was tried during attach, buffer should be retired ASAP.
EndAttachBlockToBufferQueue(const std::shared_ptr<_C2BlockPoolData> & data,const std::shared_ptr<int> & owner,const sp<HGraphicBufferProducer> & igbp,uint32_t generation,uint64_t bqId,int32_t bqSlot)173 bool _C2BlockFactory::EndAttachBlockToBufferQueue(
174 const std::shared_ptr<_C2BlockPoolData>& data,
175 const std::shared_ptr<int>& owner,
176 const sp<HGraphicBufferProducer>& igbp,
177 uint32_t generation,
178 uint64_t bqId,
179 int32_t bqSlot) {
180 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
181 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
182 std::scoped_lock<std::mutex> lock(poolData->lock);
183 if (poolData->local || !poolData->attach ) {
184 return false;
185 }
186 if (poolData->display) {
187 poolData->attach = false;
188 poolData->held = false;
189 return false;
190 }
191 poolData->attach = false;
192 poolData->held = true;
193 poolData->owner = owner;
194 poolData->igbp = igbp;
195 poolData->generation = generation;
196 poolData->bqId = bqId;
197 poolData->bqSlot = bqSlot;
198 return true;
199 }
200
DisplayBlockToBufferQueue(const std::shared_ptr<_C2BlockPoolData> & data)201 bool _C2BlockFactory::DisplayBlockToBufferQueue(
202 const std::shared_ptr<_C2BlockPoolData>& data) {
203 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
204 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
205 std::scoped_lock<std::mutex> lock(poolData->lock);
206 if (poolData->local || poolData->display || !poolData->held) {
207 return false;
208 }
209 if (poolData->bqId == 0) {
210 return false;
211 }
212 poolData->display = true;
213 if (poolData->attach) {
214 return false;
215 }
216 poolData->held = false;
217 return true;
218 }
219
CreateGraphicBlock(const C2Handle * handle)220 std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
221 const C2Handle *handle) {
222 // TODO: get proper allocator? and mutex?
223 static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0);
224
225 std::shared_ptr<C2GraphicAllocation> alloc;
226 if (C2AllocatorGralloc::isValid(handle)) {
227 uint32_t width;
228 uint32_t height;
229 uint32_t format;
230 uint64_t usage;
231 uint32_t stride;
232 uint32_t generation;
233 uint64_t bqId;
234 uint32_t bqSlot;
235 android::_UnwrapNativeCodec2GrallocMetadata(
236 handle, &width, &height, &format, &usage, &stride, &generation, &bqId, &bqSlot);
237 c2_status_t err = sAllocator->priorGraphicAllocation(handle, &alloc);
238 if (err == C2_OK) {
239 std::shared_ptr<C2GraphicBlock> block;
240 if (bqId || bqSlot) {
241 // BQBBP
242 std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
243 std::make_shared<C2BufferQueueBlockPoolData>(generation,
244 bqId,
245 (int32_t)bqSlot,
246 nullptr,
247 nullptr);
248 block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
249 } else {
250 block = _C2BlockFactory::CreateGraphicBlock(alloc);
251 }
252 return block;
253 }
254 }
255 return nullptr;
256 }
257
258 namespace {
259
getTimestampNow()260 int64_t getTimestampNow() {
261 int64_t stamp;
262 struct timespec ts;
263 // TODO: CLOCK_MONOTONIC_COARSE?
264 clock_gettime(CLOCK_MONOTONIC, &ts);
265 stamp = ts.tv_nsec / 1000;
266 stamp += (ts.tv_sec * 1000000LL);
267 return stamp;
268 }
269
getGenerationNumber(const sp<HGraphicBufferProducer> & producer,uint32_t * generation)270 bool getGenerationNumber(const sp<HGraphicBufferProducer> &producer,
271 uint32_t *generation) {
272 status_t status{};
273 int slot{};
274 bool bufferNeedsReallocation{};
275 sp<Fence> fence = new Fence();
276
277 using Input = HGraphicBufferProducer::DequeueBufferInput;
278 using Output = HGraphicBufferProducer::DequeueBufferOutput;
279 Return<void> transResult = producer->dequeueBuffer(
280 Input{640, 480, HAL_PIXEL_FORMAT_YCBCR_420_888, 0},
281 [&status, &slot, &bufferNeedsReallocation, &fence]
282 (HStatus hStatus, int32_t hSlot, Output const& hOutput) {
283 slot = static_cast<int>(hSlot);
284 if (!h2b(hStatus, &status) || !h2b(hOutput.fence, &fence)) {
285 status = ::android::BAD_VALUE;
286 } else {
287 bufferNeedsReallocation =
288 hOutput.bufferNeedsReallocation;
289 }
290 });
291 if (!transResult.isOk() || status != android::OK) {
292 return false;
293 }
294 HFenceWrapper hFenceWrapper{};
295 if (!b2h(fence, &hFenceWrapper)) {
296 (void)producer->detachBuffer(static_cast<int32_t>(slot)).isOk();
297 ALOGE("Invalid fence received from dequeueBuffer.");
298 return false;
299 }
300 sp<GraphicBuffer> slotBuffer = new GraphicBuffer();
301 // N.B. This assumes requestBuffer# returns an existing allocation
302 // instead of a new allocation.
303 transResult = producer->requestBuffer(
304 slot,
305 [&status, &slotBuffer, &generation](
306 HStatus hStatus,
307 HBuffer const& hBuffer,
308 uint32_t generationNumber){
309 if (h2b(hStatus, &status) &&
310 h2b(hBuffer, &slotBuffer) &&
311 slotBuffer) {
312 *generation = generationNumber;
313 slotBuffer->setGenerationNumber(generationNumber);
314 } else {
315 status = android::BAD_VALUE;
316 }
317 });
318 if (!transResult.isOk()) {
319 return false;
320 } else if (status != android::NO_ERROR) {
321 (void)producer->detachBuffer(static_cast<int32_t>(slot)).isOk();
322 return false;
323 }
324 (void)producer->detachBuffer(static_cast<int32_t>(slot)).isOk();
325 return true;
326 }
327
328 };
329
330 class C2BufferQueueBlockPool::Impl
331 : public std::enable_shared_from_this<C2BufferQueueBlockPool::Impl> {
332 private:
fetchFromIgbp_l(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)333 c2_status_t fetchFromIgbp_l(
334 uint32_t width,
335 uint32_t height,
336 uint32_t format,
337 C2MemoryUsage usage,
338 std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
339 // We have an IGBP now.
340 C2AndroidMemoryUsage androidUsage = usage;
341 status_t status{};
342 int slot{};
343 bool bufferNeedsReallocation{};
344 sp<Fence> fence = new Fence();
345 ALOGV("tries to dequeue buffer");
346
347 { // Call dequeueBuffer().
348 using Input = HGraphicBufferProducer::DequeueBufferInput;
349 using Output = HGraphicBufferProducer::DequeueBufferOutput;
350 Return<void> transResult = mProducer->dequeueBuffer(
351 Input{
352 width,
353 height,
354 format,
355 androidUsage.asGrallocUsage()},
356 [&status, &slot, &bufferNeedsReallocation,
357 &fence](HStatus hStatus,
358 int32_t hSlot,
359 Output const& hOutput) {
360 slot = static_cast<int>(hSlot);
361 if (!h2b(hStatus, &status) ||
362 !h2b(hOutput.fence, &fence)) {
363 status = ::android::BAD_VALUE;
364 } else {
365 bufferNeedsReallocation =
366 hOutput.bufferNeedsReallocation;
367 }
368 });
369 if (!transResult.isOk() || status != android::OK) {
370 if (transResult.isOk()) {
371 ++mDqFailure;
372 if (status == android::INVALID_OPERATION ||
373 status == android::TIMED_OUT ||
374 status == android::WOULD_BLOCK) {
375 // Dequeue buffer is blocked temporarily. Retrying is
376 // required.
377 return C2_BLOCKING;
378 }
379 }
380 ALOGD("cannot dequeue buffer %d", status);
381 return C2_BAD_VALUE;
382 }
383 mDqFailure = 0;
384 mLastDqTs = getTimestampNow();
385 }
386 HFenceWrapper hFenceWrapper{};
387 if (!b2h(fence, &hFenceWrapper)) {
388 ALOGE("Invalid fence received from dequeueBuffer.");
389 return C2_BAD_VALUE;
390 }
391 ALOGV("dequeued a buffer successfully");
392 if (fence) {
393 static constexpr int kFenceWaitTimeMs = 10;
394
395 status_t status = fence->wait(kFenceWaitTimeMs);
396 if (status == -ETIME) {
397 // fence is not signalled yet.
398 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
399 return C2_BLOCKING;
400 }
401 if (status != android::NO_ERROR) {
402 ALOGD("buffer fence wait error %d", status);
403 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
404 return C2_BAD_VALUE;
405 } else if (mRenderCallback) {
406 nsecs_t signalTime = fence->getSignalTime();
407 if (signalTime >= 0 && signalTime < INT64_MAX) {
408 mRenderCallback(mProducerId, slot, signalTime);
409 } else {
410 ALOGV("got fence signal time of %lld", (long long)signalTime);
411 }
412 }
413 }
414
415 sp<GraphicBuffer> &slotBuffer = mBuffers[slot];
416 uint32_t outGeneration;
417 if (bufferNeedsReallocation || !slotBuffer) {
418 if (!slotBuffer) {
419 slotBuffer = new GraphicBuffer();
420 }
421 // N.B. This assumes requestBuffer# returns an existing allocation
422 // instead of a new allocation.
423 Return<void> transResult = mProducer->requestBuffer(
424 slot,
425 [&status, &slotBuffer, &outGeneration](
426 HStatus hStatus,
427 HBuffer const& hBuffer,
428 uint32_t generationNumber){
429 if (h2b(hStatus, &status) &&
430 h2b(hBuffer, &slotBuffer) &&
431 slotBuffer) {
432 slotBuffer->setGenerationNumber(generationNumber);
433 outGeneration = generationNumber;
434 } else {
435 status = android::BAD_VALUE;
436 }
437 });
438 if (!transResult.isOk()) {
439 slotBuffer.clear();
440 return C2_BAD_VALUE;
441 } else if (status != android::NO_ERROR) {
442 slotBuffer.clear();
443 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
444 return C2_BAD_VALUE;
445 }
446 if (mGeneration == 0) {
447 // getting generation # lazily due to dequeue failure.
448 mGeneration = outGeneration;
449 }
450 }
451 if (slotBuffer) {
452 ALOGV("buffer wraps %llu %d", (unsigned long long)mProducerId, slot);
453 C2Handle *c2Handle = android::WrapNativeCodec2GrallocHandle(
454 slotBuffer->handle,
455 slotBuffer->width,
456 slotBuffer->height,
457 slotBuffer->format,
458 slotBuffer->usage,
459 slotBuffer->stride,
460 slotBuffer->getGenerationNumber(),
461 mProducerId, slot);
462 if (c2Handle) {
463 std::shared_ptr<C2GraphicAllocation> alloc;
464 c2_status_t err = mAllocator->priorGraphicAllocation(c2Handle, &alloc);
465 if (err != C2_OK) {
466 return err;
467 }
468 std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
469 std::make_shared<C2BufferQueueBlockPoolData>(
470 slotBuffer->getGenerationNumber(),
471 mProducerId, slot,
472 shared_from_this());
473 mPoolDatas[slot] = poolData;
474 *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
475 return C2_OK;
476 }
477 // Block was not created. call requestBuffer# again next time.
478 slotBuffer.clear();
479 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
480 }
481 return C2_BAD_VALUE;
482 }
483
484 public:
Impl(const std::shared_ptr<C2Allocator> & allocator)485 Impl(const std::shared_ptr<C2Allocator> &allocator)
486 : mInit(C2_OK), mProducerId(0), mGeneration(0),
487 mDqFailure(0), mLastDqTs(0), mLastDqLogTs(0),
488 mAllocator(allocator) {
489 }
490
~Impl()491 ~Impl() {
492 bool noInit = false;
493 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
494 if (!noInit && mProducer) {
495 Return<HStatus> transResult =
496 mProducer->detachBuffer(static_cast<int32_t>(i));
497 noInit = !transResult.isOk() ||
498 static_cast<HStatus>(transResult) == HStatus::NO_INIT;
499 }
500 mBuffers[i].clear();
501 }
502 }
503
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)504 c2_status_t fetchGraphicBlock(
505 uint32_t width,
506 uint32_t height,
507 uint32_t format,
508 C2MemoryUsage usage,
509 std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
510 block->reset();
511 if (mInit != C2_OK) {
512 return mInit;
513 }
514
515 static int kMaxIgbpRetryDelayUs = 10000;
516
517 std::unique_lock<std::mutex> lock(mMutex);
518 if (mLastDqLogTs == 0) {
519 mLastDqLogTs = getTimestampNow();
520 } else {
521 int64_t now = getTimestampNow();
522 if (now >= mLastDqLogTs + 5000000) {
523 if (now >= mLastDqTs + 1000000 || mDqFailure > 5) {
524 ALOGW("last successful dequeue was %lld us ago, "
525 "%zu consecutive failures",
526 (long long)(now - mLastDqTs), mDqFailure);
527 }
528 mLastDqLogTs = now;
529 }
530 }
531 if (mProducerId == 0) {
532 std::shared_ptr<C2GraphicAllocation> alloc;
533 c2_status_t err = mAllocator->newGraphicAllocation(
534 width, height, format, usage, &alloc);
535 if (err != C2_OK) {
536 return err;
537 }
538 std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
539 std::make_shared<C2BufferQueueBlockPoolData>(
540 0, (uint64_t)0, ~0, shared_from_this());
541 *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
542 ALOGV("allocated a buffer successfully");
543
544 return C2_OK;
545 }
546 c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block);
547 if (status == C2_BLOCKING) {
548 lock.unlock();
549 // in order not to drain cpu from component's spinning
550 ::usleep(kMaxIgbpRetryDelayUs);
551 }
552 return status;
553 }
554
setRenderCallback(const OnRenderCallback & renderCallback)555 void setRenderCallback(const OnRenderCallback &renderCallback) {
556 std::scoped_lock<std::mutex> lock(mMutex);
557 mRenderCallback = renderCallback;
558 }
559
configureProducer(const sp<HGraphicBufferProducer> & producer)560 void configureProducer(const sp<HGraphicBufferProducer> &producer) {
561 uint64_t producerId = 0;
562 uint32_t generation = 0;
563 bool haveGeneration = false;
564 if (producer) {
565 Return<uint64_t> transResult = producer->getUniqueId();
566 if (!transResult.isOk()) {
567 ALOGD("configureProducer -- failed to connect to the producer");
568 return;
569 }
570 producerId = static_cast<uint64_t>(transResult);
571 // TODO: provide gneration number from parameter.
572 haveGeneration = getGenerationNumber(producer, &generation);
573 if (!haveGeneration) {
574 ALOGW("get generationNumber failed %llu",
575 (unsigned long long)producerId);
576 }
577 }
578 int migrated = 0;
579 {
580 sp<GraphicBuffer> buffers[NUM_BUFFER_SLOTS];
581 std::weak_ptr<C2BufferQueueBlockPoolData>
582 poolDatas[NUM_BUFFER_SLOTS];
583 std::scoped_lock<std::mutex> lock(mMutex);
584 bool noInit = false;
585 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
586 if (!noInit && mProducer) {
587 Return<HStatus> transResult =
588 mProducer->detachBuffer(static_cast<int32_t>(i));
589 noInit = !transResult.isOk() ||
590 static_cast<HStatus>(transResult) == HStatus::NO_INIT;
591 }
592 }
593 int32_t oldGeneration = mGeneration;
594 if (producer) {
595 mProducer = producer;
596 mProducerId = producerId;
597 mGeneration = haveGeneration ? generation : 0;
598 } else {
599 mProducer = nullptr;
600 mProducerId = 0;
601 mGeneration = 0;
602 ALOGW("invalid producer producer(%d), generation(%d)",
603 (bool)producer, haveGeneration);
604 }
605 if (mProducer && haveGeneration) { // migrate buffers
606 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
607 std::shared_ptr<C2BufferQueueBlockPoolData> data =
608 mPoolDatas[i].lock();
609 if (data) {
610 int slot = data->migrate(
611 mProducer, generation,
612 producerId, mBuffers, oldGeneration);
613 if (slot >= 0) {
614 buffers[slot] = mBuffers[i];
615 poolDatas[slot] = data;
616 ++migrated;
617 }
618 }
619 }
620 }
621 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
622 mBuffers[i] = buffers[i];
623 mPoolDatas[i] = poolDatas[i];
624 }
625 }
626 if (producer && haveGeneration) {
627 ALOGD("local generation change %u , "
628 "bqId: %llu migrated buffers # %d",
629 generation, (unsigned long long)producerId, migrated);
630 }
631 }
632
633 private:
634 friend struct C2BufferQueueBlockPoolData;
635
cancel(uint32_t generation,uint64_t igbp_id,int32_t igbp_slot)636 void cancel(uint32_t generation, uint64_t igbp_id, int32_t igbp_slot) {
637 bool cancelled = false;
638 {
639 std::scoped_lock<std::mutex> lock(mMutex);
640 if (generation == mGeneration && igbp_id == mProducerId && mProducer) {
641 (void)mProducer->cancelBuffer(igbp_slot, hidl_handle{}).isOk();
642 cancelled = true;
643 }
644 }
645 }
646
647 c2_status_t mInit;
648 uint64_t mProducerId;
649 uint32_t mGeneration;
650 OnRenderCallback mRenderCallback;
651
652 size_t mDqFailure;
653 int64_t mLastDqTs;
654 int64_t mLastDqLogTs;
655
656 const std::shared_ptr<C2Allocator> mAllocator;
657
658 std::mutex mMutex;
659 sp<HGraphicBufferProducer> mProducer;
660 sp<HGraphicBufferProducer> mSavedProducer;
661
662 sp<GraphicBuffer> mBuffers[NUM_BUFFER_SLOTS];
663 std::weak_ptr<C2BufferQueueBlockPoolData> mPoolDatas[NUM_BUFFER_SLOTS];
664 };
665
C2BufferQueueBlockPoolData(uint32_t generation,uint64_t bqId,int32_t bqSlot,const std::shared_ptr<int> & owner,const sp<HGraphicBufferProducer> & producer)666 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
667 uint32_t generation, uint64_t bqId, int32_t bqSlot,
668 const std::shared_ptr<int>& owner,
669 const sp<HGraphicBufferProducer>& producer) :
670 held(producer && bqId != 0), local(false),
671 generation(generation), bqId(bqId), bqSlot(bqSlot),
672 transfer(false), attach(false), display(false),
673 owner(owner), igbp(producer),
674 localPool() {
675 }
676
C2BufferQueueBlockPoolData(uint32_t generation,uint64_t bqId,int32_t bqSlot,const std::shared_ptr<C2BufferQueueBlockPool::Impl> & pool)677 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
678 uint32_t generation, uint64_t bqId, int32_t bqSlot,
679 const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool) :
680 held(true), local(true),
681 generation(generation), bqId(bqId), bqSlot(bqSlot),
682 transfer(false), attach(false), display(false),
683 igbp(pool ? pool->mProducer : nullptr),
684 localPool(pool) {
685 }
686
~C2BufferQueueBlockPoolData()687 C2BufferQueueBlockPoolData::~C2BufferQueueBlockPoolData() {
688 if (!held || bqId == 0) {
689 return;
690 }
691 if (local) {
692 if (localPool) {
693 localPool->cancel(generation, bqId, bqSlot);
694 }
695 } else if (igbp && !owner.expired()) {
696 igbp->cancelBuffer(bqSlot, hidl_handle{}).isOk();
697 }
698 }
migrate(const sp<HGraphicBufferProducer> & producer,uint32_t toGeneration,uint64_t toBqId,sp<GraphicBuffer> * buffers,uint32_t oldGeneration)699 int C2BufferQueueBlockPoolData::migrate(
700 const sp<HGraphicBufferProducer>& producer,
701 uint32_t toGeneration, uint64_t toBqId,
702 sp<GraphicBuffer> *buffers, uint32_t oldGeneration) {
703 std::scoped_lock<std::mutex> l(lock);
704 if (!held || bqId == 0) {
705 ALOGV("buffer is not owned");
706 return -1;
707 }
708 if (!local || !localPool) {
709 ALOGV("pool is not local");
710 return -1;
711 }
712 if (bqSlot < 0 || bqSlot >= NUM_BUFFER_SLOTS || !buffers[bqSlot]) {
713 ALOGV("slot is not in effect");
714 return -1;
715 }
716 if (toGeneration == generation && bqId == toBqId) {
717 ALOGV("cannot migrate to same bufferqueue");
718 return -1;
719 }
720 if (oldGeneration != generation) {
721 ALOGV("cannot migrate stale buffer");
722 }
723 if (transfer) {
724 // either transferred or detached.
725 ALOGV("buffer is in transfer");
726 return -1;
727 }
728 sp<GraphicBuffer> const& graphicBuffer = buffers[bqSlot];
729 graphicBuffer->setGenerationNumber(toGeneration);
730
731 HBuffer hBuffer{};
732 uint32_t hGenerationNumber{};
733 if (!b2h(graphicBuffer, &hBuffer, &hGenerationNumber)) {
734 ALOGD("I to O conversion failed");
735 return -1;
736 }
737
738 bool converted{};
739 status_t bStatus{};
740 int slot;
741 int *outSlot = &slot;
742 Return<void> transResult =
743 producer->attachBuffer(hBuffer, hGenerationNumber,
744 [&converted, &bStatus, outSlot](
745 HStatus hStatus, int32_t hSlot, bool releaseAll) {
746 converted = h2b(hStatus, &bStatus);
747 *outSlot = static_cast<int>(hSlot);
748 if (converted && releaseAll && bStatus == android::OK) {
749 bStatus = android::INVALID_OPERATION;
750 }
751 });
752 if (!transResult.isOk() || !converted || bStatus != android::OK) {
753 ALOGD("attach failed %d", static_cast<int>(bStatus));
754 return -1;
755 }
756 ALOGV("local migration from gen %u : %u slot %d : %d",
757 generation, toGeneration, bqSlot, slot);
758 generation = toGeneration;
759 bqId = toBqId;
760 bqSlot = slot;
761 return slot;
762 }
763
C2BufferQueueBlockPool(const std::shared_ptr<C2Allocator> & allocator,const local_id_t localId)764 C2BufferQueueBlockPool::C2BufferQueueBlockPool(
765 const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId)
766 : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {}
767
~C2BufferQueueBlockPool()768 C2BufferQueueBlockPool::~C2BufferQueueBlockPool() {}
769
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)770 c2_status_t C2BufferQueueBlockPool::fetchGraphicBlock(
771 uint32_t width,
772 uint32_t height,
773 uint32_t format,
774 C2MemoryUsage usage,
775 std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
776 if (mImpl) {
777 return mImpl->fetchGraphicBlock(width, height, format, usage, block);
778 }
779 return C2_CORRUPTED;
780 }
781
configureProducer(const sp<HGraphicBufferProducer> & producer)782 void C2BufferQueueBlockPool::configureProducer(const sp<HGraphicBufferProducer> &producer) {
783 if (mImpl) {
784 mImpl->configureProducer(producer);
785 }
786 }
787
setRenderCallback(const OnRenderCallback & renderCallback)788 void C2BufferQueueBlockPool::setRenderCallback(const OnRenderCallback &renderCallback) {
789 if (mImpl) {
790 mImpl->setRenderCallback(renderCallback);
791 }
792 }
793