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 // poolDatas dtor should not be called during lock is held.
580 std::shared_ptr<C2BufferQueueBlockPoolData>
581 poolDatas[NUM_BUFFER_SLOTS];
582 {
583 sp<GraphicBuffer> buffers[NUM_BUFFER_SLOTS];
584 std::scoped_lock<std::mutex> lock(mMutex);
585 bool noInit = false;
586 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
587 if (!noInit && mProducer) {
588 Return<HStatus> transResult =
589 mProducer->detachBuffer(static_cast<int32_t>(i));
590 noInit = !transResult.isOk() ||
591 static_cast<HStatus>(transResult) == HStatus::NO_INIT;
592 }
593 }
594 int32_t oldGeneration = mGeneration;
595 if (producer) {
596 mProducer = producer;
597 mProducerId = producerId;
598 mGeneration = haveGeneration ? generation : 0;
599 } else {
600 mProducer = nullptr;
601 mProducerId = 0;
602 mGeneration = 0;
603 ALOGW("invalid producer producer(%d), generation(%d)",
604 (bool)producer, haveGeneration);
605 }
606 if (mProducer && haveGeneration) { // migrate buffers
607 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
608 std::shared_ptr<C2BufferQueueBlockPoolData> data =
609 mPoolDatas[i].lock();
610 if (data) {
611 int slot = data->migrate(
612 mProducer, generation,
613 producerId, mBuffers, oldGeneration);
614 if (slot >= 0) {
615 buffers[slot] = mBuffers[i];
616 poolDatas[slot] = data;
617 ++migrated;
618 }
619 }
620 }
621 }
622 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
623 mBuffers[i] = buffers[i];
624 mPoolDatas[i] = poolDatas[i];
625 }
626 }
627 if (producer && haveGeneration) {
628 ALOGD("local generation change %u , "
629 "bqId: %llu migrated buffers # %d",
630 generation, (unsigned long long)producerId, migrated);
631 }
632 }
633
634 private:
635 friend struct C2BufferQueueBlockPoolData;
636
cancel(uint32_t generation,uint64_t igbp_id,int32_t igbp_slot)637 void cancel(uint32_t generation, uint64_t igbp_id, int32_t igbp_slot) {
638 bool cancelled = false;
639 {
640 std::scoped_lock<std::mutex> lock(mMutex);
641 if (generation == mGeneration && igbp_id == mProducerId && mProducer) {
642 (void)mProducer->cancelBuffer(igbp_slot, hidl_handle{}).isOk();
643 cancelled = true;
644 }
645 }
646 }
647
648 c2_status_t mInit;
649 uint64_t mProducerId;
650 uint32_t mGeneration;
651 OnRenderCallback mRenderCallback;
652
653 size_t mDqFailure;
654 int64_t mLastDqTs;
655 int64_t mLastDqLogTs;
656
657 const std::shared_ptr<C2Allocator> mAllocator;
658
659 std::mutex mMutex;
660 sp<HGraphicBufferProducer> mProducer;
661 sp<HGraphicBufferProducer> mSavedProducer;
662
663 sp<GraphicBuffer> mBuffers[NUM_BUFFER_SLOTS];
664 std::weak_ptr<C2BufferQueueBlockPoolData> mPoolDatas[NUM_BUFFER_SLOTS];
665 };
666
C2BufferQueueBlockPoolData(uint32_t generation,uint64_t bqId,int32_t bqSlot,const std::shared_ptr<int> & owner,const sp<HGraphicBufferProducer> & producer)667 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
668 uint32_t generation, uint64_t bqId, int32_t bqSlot,
669 const std::shared_ptr<int>& owner,
670 const sp<HGraphicBufferProducer>& producer) :
671 held(producer && bqId != 0), local(false),
672 generation(generation), bqId(bqId), bqSlot(bqSlot),
673 transfer(false), attach(false), display(false),
674 owner(owner), igbp(producer),
675 localPool() {
676 }
677
C2BufferQueueBlockPoolData(uint32_t generation,uint64_t bqId,int32_t bqSlot,const std::shared_ptr<C2BufferQueueBlockPool::Impl> & pool)678 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
679 uint32_t generation, uint64_t bqId, int32_t bqSlot,
680 const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool) :
681 held(true), local(true),
682 generation(generation), bqId(bqId), bqSlot(bqSlot),
683 transfer(false), attach(false), display(false),
684 igbp(pool ? pool->mProducer : nullptr),
685 localPool(pool) {
686 }
687
~C2BufferQueueBlockPoolData()688 C2BufferQueueBlockPoolData::~C2BufferQueueBlockPoolData() {
689 if (!held || bqId == 0) {
690 return;
691 }
692 if (local) {
693 if (localPool) {
694 localPool->cancel(generation, bqId, bqSlot);
695 }
696 } else if (igbp && !owner.expired()) {
697 igbp->cancelBuffer(bqSlot, hidl_handle{}).isOk();
698 }
699 }
migrate(const sp<HGraphicBufferProducer> & producer,uint32_t toGeneration,uint64_t toBqId,sp<GraphicBuffer> * buffers,uint32_t oldGeneration)700 int C2BufferQueueBlockPoolData::migrate(
701 const sp<HGraphicBufferProducer>& producer,
702 uint32_t toGeneration, uint64_t toBqId,
703 sp<GraphicBuffer> *buffers, uint32_t oldGeneration) {
704 std::scoped_lock<std::mutex> l(lock);
705 if (!held || bqId == 0) {
706 ALOGV("buffer is not owned");
707 return -1;
708 }
709 if (!local || !localPool) {
710 ALOGV("pool is not local");
711 return -1;
712 }
713 if (bqSlot < 0 || bqSlot >= NUM_BUFFER_SLOTS || !buffers[bqSlot]) {
714 ALOGV("slot is not in effect");
715 return -1;
716 }
717 if (toGeneration == generation && bqId == toBqId) {
718 ALOGV("cannot migrate to same bufferqueue");
719 return -1;
720 }
721 if (oldGeneration != generation) {
722 ALOGV("cannot migrate stale buffer");
723 }
724 if (transfer) {
725 // either transferred or detached.
726 ALOGV("buffer is in transfer");
727 return -1;
728 }
729 sp<GraphicBuffer> const& graphicBuffer = buffers[bqSlot];
730 graphicBuffer->setGenerationNumber(toGeneration);
731
732 HBuffer hBuffer{};
733 uint32_t hGenerationNumber{};
734 if (!b2h(graphicBuffer, &hBuffer, &hGenerationNumber)) {
735 ALOGD("I to O conversion failed");
736 return -1;
737 }
738
739 bool converted{};
740 status_t bStatus{};
741 int slot;
742 int *outSlot = &slot;
743 Return<void> transResult =
744 producer->attachBuffer(hBuffer, hGenerationNumber,
745 [&converted, &bStatus, outSlot](
746 HStatus hStatus, int32_t hSlot, bool releaseAll) {
747 converted = h2b(hStatus, &bStatus);
748 *outSlot = static_cast<int>(hSlot);
749 if (converted && releaseAll && bStatus == android::OK) {
750 bStatus = android::INVALID_OPERATION;
751 }
752 });
753 if (!transResult.isOk() || !converted || bStatus != android::OK) {
754 ALOGD("attach failed %d", static_cast<int>(bStatus));
755 return -1;
756 }
757 ALOGV("local migration from gen %u : %u slot %d : %d",
758 generation, toGeneration, bqSlot, slot);
759 generation = toGeneration;
760 bqId = toBqId;
761 bqSlot = slot;
762 return slot;
763 }
764
C2BufferQueueBlockPool(const std::shared_ptr<C2Allocator> & allocator,const local_id_t localId)765 C2BufferQueueBlockPool::C2BufferQueueBlockPool(
766 const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId)
767 : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {}
768
~C2BufferQueueBlockPool()769 C2BufferQueueBlockPool::~C2BufferQueueBlockPool() {}
770
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)771 c2_status_t C2BufferQueueBlockPool::fetchGraphicBlock(
772 uint32_t width,
773 uint32_t height,
774 uint32_t format,
775 C2MemoryUsage usage,
776 std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
777 if (mImpl) {
778 return mImpl->fetchGraphicBlock(width, height, format, usage, block);
779 }
780 return C2_CORRUPTED;
781 }
782
configureProducer(const sp<HGraphicBufferProducer> & producer)783 void C2BufferQueueBlockPool::configureProducer(const sp<HGraphicBufferProducer> &producer) {
784 if (mImpl) {
785 mImpl->configureProducer(producer);
786 }
787 }
788
setRenderCallback(const OnRenderCallback & renderCallback)789 void C2BufferQueueBlockPool::setRenderCallback(const OnRenderCallback &renderCallback) {
790 if (mImpl) {
791 mImpl->setRenderCallback(renderCallback);
792 }
793 }
794