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 #include <C2FenceFactory.h>
33 #include <C2SurfaceSyncObj.h>
34
35 #include <list>
36 #include <map>
37 #include <mutex>
38
39 using ::android::BufferQueueDefs::NUM_BUFFER_SLOTS;
40 using ::android::C2AllocatorGralloc;
41 using ::android::C2AndroidMemoryUsage;
42 using ::android::Fence;
43 using ::android::GraphicBuffer;
44 using ::android::sp;
45 using ::android::status_t;
46 using ::android::wp;
47 using ::android::hardware::hidl_handle;
48 using ::android::hardware::Return;
49
50 using HBuffer = ::android::hardware::graphics::common::V1_2::HardwareBuffer;
51 using HStatus = ::android::hardware::graphics::bufferqueue::V2_0::Status;
52 using ::android::hardware::graphics::bufferqueue::V2_0::utils::b2h;
53 using ::android::hardware::graphics::bufferqueue::V2_0::utils::h2b;
54 using ::android::hardware::graphics::bufferqueue::V2_0::utils::HFenceWrapper;
55
56 using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::V2_0
57 ::IGraphicBufferProducer;
58
GetBufferQueueData(const std::shared_ptr<const _C2BlockPoolData> & data,uint32_t * generation,uint64_t * bqId,int32_t * bqSlot)59 bool _C2BlockFactory::GetBufferQueueData(
60 const std::shared_ptr<const _C2BlockPoolData>& data,
61 uint32_t* generation, uint64_t* bqId, int32_t* bqSlot) {
62 if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERQUEUE) {
63 const std::shared_ptr<const C2BufferQueueBlockPoolData> poolData =
64 std::static_pointer_cast<const C2BufferQueueBlockPoolData>(data);
65 poolData->getBufferQueueData(generation, bqId, bqSlot);
66 return true;
67 }
68 return false;
69 }
70
HoldBlockFromBufferQueue(const std::shared_ptr<_C2BlockPoolData> & data,const std::shared_ptr<int> & owner,const sp<HGraphicBufferProducer> & igbp,std::shared_ptr<C2SurfaceSyncMemory> syncMem)71 bool _C2BlockFactory::HoldBlockFromBufferQueue(
72 const std::shared_ptr<_C2BlockPoolData>& data,
73 const std::shared_ptr<int>& owner,
74 const sp<HGraphicBufferProducer>& igbp,
75 std::shared_ptr<C2SurfaceSyncMemory> syncMem) {
76 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
77 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
78 return poolData->holdBlockFromBufferQueue(owner, igbp, syncMem);
79 }
80
BeginTransferBlockToClient(const std::shared_ptr<_C2BlockPoolData> & data)81 bool _C2BlockFactory::BeginTransferBlockToClient(
82 const std::shared_ptr<_C2BlockPoolData>& data) {
83 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
84 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
85 return poolData->beginTransferBlockToClient();
86 }
87
EndTransferBlockToClient(const std::shared_ptr<_C2BlockPoolData> & data,bool transfer)88 bool _C2BlockFactory::EndTransferBlockToClient(
89 const std::shared_ptr<_C2BlockPoolData>& data,
90 bool transfer) {
91 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
92 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
93 return poolData->endTransferBlockToClient(transfer);
94 }
95
BeginAttachBlockToBufferQueue(const std::shared_ptr<_C2BlockPoolData> & data)96 bool _C2BlockFactory::BeginAttachBlockToBufferQueue(
97 const std::shared_ptr<_C2BlockPoolData>& data) {
98 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
99 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
100 return poolData->beginAttachBlockToBufferQueue();
101 }
102
103 // 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,std::shared_ptr<C2SurfaceSyncMemory> syncMem,uint32_t generation,uint64_t bqId,int32_t bqSlot)104 bool _C2BlockFactory::EndAttachBlockToBufferQueue(
105 const std::shared_ptr<_C2BlockPoolData>& data,
106 const std::shared_ptr<int>& owner,
107 const sp<HGraphicBufferProducer>& igbp,
108 std::shared_ptr<C2SurfaceSyncMemory> syncMem,
109 uint32_t generation,
110 uint64_t bqId,
111 int32_t bqSlot) {
112 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
113 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
114 return poolData->endAttachBlockToBufferQueue(owner, igbp, syncMem, generation, bqId, bqSlot);
115 }
116
DisplayBlockToBufferQueue(const std::shared_ptr<_C2BlockPoolData> & data)117 bool _C2BlockFactory::DisplayBlockToBufferQueue(
118 const std::shared_ptr<_C2BlockPoolData>& data) {
119 const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
120 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
121 return poolData->displayBlockToBufferQueue();
122 }
123
CreateGraphicBlock(const C2Handle * handle)124 std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
125 const C2Handle *handle) {
126 // TODO: get proper allocator? and mutex?
127 static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0);
128
129 std::shared_ptr<C2GraphicAllocation> alloc;
130 if (C2AllocatorGralloc::CheckHandle(handle)) {
131 uint32_t width;
132 uint32_t height;
133 uint32_t format;
134 uint64_t usage;
135 uint32_t stride;
136 uint32_t generation;
137 uint64_t bqId;
138 uint32_t bqSlot;
139 android::_UnwrapNativeCodec2GrallocMetadata(
140 handle, &width, &height, &format, &usage, &stride, &generation, &bqId, &bqSlot);
141 c2_status_t err = sAllocator->priorGraphicAllocation(handle, &alloc);
142 if (err == C2_OK) {
143 std::shared_ptr<C2GraphicBlock> block;
144 if (bqId || bqSlot) {
145 // BQBBP
146 std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
147 std::make_shared<C2BufferQueueBlockPoolData>(generation,
148 bqId,
149 (int32_t)bqSlot,
150 nullptr,
151 nullptr);
152 block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
153 } else {
154 block = _C2BlockFactory::CreateGraphicBlock(alloc);
155 }
156 return block;
157 }
158 }
159 return nullptr;
160 }
161
162 namespace {
163
getTimestampNow()164 int64_t getTimestampNow() {
165 int64_t stamp;
166 struct timespec ts;
167 // TODO: CLOCK_MONOTONIC_COARSE?
168 clock_gettime(CLOCK_MONOTONIC, &ts);
169 stamp = ts.tv_nsec / 1000;
170 stamp += (ts.tv_sec * 1000000LL);
171 return stamp;
172 }
173
getGenerationNumberAndUsage(const sp<HGraphicBufferProducer> & producer,uint32_t * generation,uint64_t * usage)174 bool getGenerationNumberAndUsage(const sp<HGraphicBufferProducer> &producer,
175 uint32_t *generation, uint64_t *usage) {
176 status_t status{};
177 int slot{};
178 bool bufferNeedsReallocation{};
179 sp<Fence> fence = new Fence();
180
181 using Input = HGraphicBufferProducer::DequeueBufferInput;
182 using Output = HGraphicBufferProducer::DequeueBufferOutput;
183 Return<void> transResult = producer->dequeueBuffer(
184 Input{640, 480, HAL_PIXEL_FORMAT_YCBCR_420_888, 0},
185 [&status, &slot, &bufferNeedsReallocation, &fence]
186 (HStatus hStatus, int32_t hSlot, Output const& hOutput) {
187 slot = static_cast<int>(hSlot);
188 if (!h2b(hStatus, &status) || !h2b(hOutput.fence, &fence)) {
189 status = ::android::BAD_VALUE;
190 } else {
191 bufferNeedsReallocation =
192 hOutput.bufferNeedsReallocation;
193 }
194 });
195 if (!transResult.isOk() || status != android::OK) {
196 return false;
197 }
198 HFenceWrapper hFenceWrapper{};
199 if (!b2h(fence, &hFenceWrapper)) {
200 (void)producer->detachBuffer(static_cast<int32_t>(slot)).isOk();
201 ALOGE("Invalid fence received from dequeueBuffer.");
202 return false;
203 }
204 sp<GraphicBuffer> slotBuffer = new GraphicBuffer();
205 // N.B. This assumes requestBuffer# returns an existing allocation
206 // instead of a new allocation.
207 transResult = producer->requestBuffer(
208 slot,
209 [&status, &slotBuffer, &generation, &usage](
210 HStatus hStatus,
211 HBuffer const& hBuffer,
212 uint32_t generationNumber){
213 if (h2b(hStatus, &status) &&
214 h2b(hBuffer, &slotBuffer) &&
215 slotBuffer) {
216 *generation = generationNumber;
217 *usage = slotBuffer->getUsage();
218 slotBuffer->setGenerationNumber(generationNumber);
219 } else {
220 status = android::BAD_VALUE;
221 }
222 });
223 if (!transResult.isOk()) {
224 return false;
225 } else if (status != android::NO_ERROR) {
226 (void)producer->detachBuffer(static_cast<int32_t>(slot)).isOk();
227 return false;
228 }
229 (void)producer->detachBuffer(static_cast<int32_t>(slot)).isOk();
230 return true;
231 }
232
233 };
234
235 class C2BufferQueueBlockPool::Impl
236 : public std::enable_shared_from_this<C2BufferQueueBlockPool::Impl> {
237 private:
dequeueBuffer(uint32_t width,uint32_t height,uint32_t format,C2AndroidMemoryUsage androidUsage,int * slot,bool * needsRealloc,sp<Fence> * fence)238 c2_status_t dequeueBuffer(
239 uint32_t width,
240 uint32_t height,
241 uint32_t format,
242 C2AndroidMemoryUsage androidUsage,
243 int *slot, bool *needsRealloc, sp<Fence> *fence) {
244 status_t status{};
245 using Input = HGraphicBufferProducer::DequeueBufferInput;
246 using Output = HGraphicBufferProducer::DequeueBufferOutput;
247 Return<void> transResult = mProducer->dequeueBuffer(
248 Input{
249 width,
250 height,
251 format,
252 androidUsage.asGrallocUsage()},
253 [&status, slot, needsRealloc,
254 fence](HStatus hStatus,
255 int32_t hSlot,
256 Output const& hOutput) {
257 *slot = static_cast<int>(hSlot);
258 if (!h2b(hStatus, &status) ||
259 !h2b(hOutput.fence, fence)) {
260 status = ::android::BAD_VALUE;
261 } else {
262 *needsRealloc =
263 hOutput.bufferNeedsReallocation;
264 }
265 });
266 if (!transResult.isOk() || status != android::OK) {
267 if (transResult.isOk()) {
268 ++mDqFailure;
269 if (status == android::INVALID_OPERATION ||
270 status == android::TIMED_OUT ||
271 status == android::WOULD_BLOCK) {
272 // Dequeue buffer is blocked temporarily. Retrying is
273 // required.
274 return C2_BLOCKING;
275 }
276 }
277 ALOGD("cannot dequeue buffer %d", status);
278 return C2_BAD_VALUE;
279 }
280 return C2_OK;
281 }
282
fetchFromIgbp_l(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block,C2Fence * c2Fence)283 c2_status_t fetchFromIgbp_l(
284 uint32_t width,
285 uint32_t height,
286 uint32_t format,
287 C2MemoryUsage usage,
288 std::shared_ptr<C2GraphicBlock> *block /* nonnull */,
289 C2Fence *c2Fence) {
290 // We have an IGBP now.
291 C2AndroidMemoryUsage androidUsage = usage;
292 status_t status{};
293 int slot{};
294 bool bufferNeedsReallocation{};
295 sp<Fence> fence = new Fence();
296 ALOGV("tries to dequeue buffer");
297
298 C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem(): nullptr;
299 { // Call dequeueBuffer().
300 c2_status_t c2Status;
301 if (syncVar) {
302 uint32_t waitId;
303 syncVar->lock();
304 if (!syncVar->isDequeueableLocked(&waitId)) {
305 syncVar->unlock();
306 if (c2Fence) {
307 *c2Fence = _C2FenceFactory::CreateSurfaceFence(mSyncMem, waitId);
308 }
309 return C2_BLOCKING;
310 }
311 if (syncVar->getSyncStatusLocked() != C2SyncVariables::STATUS_ACTIVE) {
312 waitId = syncVar->getWaitIdLocked();
313 syncVar->unlock();
314 if (c2Fence) {
315 *c2Fence = _C2FenceFactory::CreateSurfaceFence(mSyncMem, waitId);
316 }
317 return C2_BLOCKING;
318 }
319 syncVar->notifyDequeuedLocked();
320 syncVar->unlock();
321 c2Status = dequeueBuffer(width, height, format, androidUsage,
322 &slot, &bufferNeedsReallocation, &fence);
323 if (c2Status != C2_OK) {
324 syncVar->lock();
325 syncVar->notifyQueuedLocked();
326 syncVar->unlock();
327 }
328 } else {
329 c2Status = dequeueBuffer(width, height, format, usage,
330 &slot, &bufferNeedsReallocation, &fence);
331 }
332 if (c2Status != C2_OK) {
333 return c2Status;
334 }
335 mDqFailure = 0;
336 mLastDqTs = getTimestampNow();
337 }
338 HFenceWrapper hFenceWrapper{};
339 if (!b2h(fence, &hFenceWrapper)) {
340 ALOGE("Invalid fence received from dequeueBuffer.");
341 return C2_BAD_VALUE;
342 }
343 ALOGV("dequeued a buffer successfully");
344 bool dequeueable = false;
345 uint32_t waitId;
346 if (fence) {
347 static constexpr int kFenceWaitTimeMs = 10;
348
349 status_t status = fence->wait(kFenceWaitTimeMs);
350 if (status == -ETIME) {
351 // fence is not signalled yet.
352 if (syncVar) {
353 syncVar->lock();
354 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
355 dequeueable = syncVar->notifyQueuedLocked(&waitId);
356 syncVar->unlock();
357 if (c2Fence) {
358 *c2Fence = dequeueable ? C2Fence() :
359 _C2FenceFactory::CreateSurfaceFence(mSyncMem, waitId);
360 }
361 } else {
362 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
363 }
364 return C2_BLOCKING;
365 }
366 if (status != android::NO_ERROR) {
367 ALOGD("buffer fence wait error %d", status);
368 if (syncVar) {
369 syncVar->lock();
370 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
371 syncVar->notifyQueuedLocked();
372 syncVar->unlock();
373 if (c2Fence) {
374 *c2Fence = C2Fence();
375 }
376 } else {
377 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
378 }
379 return C2_BAD_VALUE;
380 } else if (mRenderCallback) {
381 nsecs_t signalTime = fence->getSignalTime();
382 if (signalTime >= 0 && signalTime < INT64_MAX) {
383 mRenderCallback(mProducerId, slot, signalTime);
384 } else {
385 ALOGV("got fence signal time of %lld", (long long)signalTime);
386 }
387 }
388 }
389
390 sp<GraphicBuffer> &slotBuffer = mBuffers[slot];
391 uint32_t outGeneration;
392 if (bufferNeedsReallocation || !slotBuffer) {
393 if (!slotBuffer) {
394 slotBuffer = new GraphicBuffer();
395 }
396 // N.B. This assumes requestBuffer# returns an existing allocation
397 // instead of a new allocation.
398 Return<void> transResult = mProducer->requestBuffer(
399 slot,
400 [&status, &slotBuffer, &outGeneration](
401 HStatus hStatus,
402 HBuffer const& hBuffer,
403 uint32_t generationNumber){
404 if (h2b(hStatus, &status) &&
405 h2b(hBuffer, &slotBuffer) &&
406 slotBuffer) {
407 slotBuffer->setGenerationNumber(generationNumber);
408 outGeneration = generationNumber;
409 } else {
410 status = android::BAD_VALUE;
411 }
412 });
413 if (!transResult.isOk()) {
414 slotBuffer.clear();
415 return C2_BAD_VALUE;
416 } else if (status != android::NO_ERROR) {
417 slotBuffer.clear();
418 if (syncVar) {
419 syncVar->lock();
420 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
421 syncVar->notifyQueuedLocked();
422 syncVar->unlock();
423 if (c2Fence) {
424 *c2Fence = C2Fence();
425 }
426 } else {
427 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
428 }
429 return C2_BAD_VALUE;
430 }
431 if (mGeneration == 0) {
432 // getting generation # lazily due to dequeue failure.
433 mGeneration = outGeneration;
434 }
435 }
436 if (slotBuffer) {
437 ALOGV("buffer wraps %llu %d", (unsigned long long)mProducerId, slot);
438 C2Handle *c2Handle = android::WrapNativeCodec2GrallocHandle(
439 slotBuffer->handle,
440 slotBuffer->width,
441 slotBuffer->height,
442 slotBuffer->format,
443 slotBuffer->usage,
444 slotBuffer->stride,
445 slotBuffer->getGenerationNumber(),
446 mProducerId, slot);
447 if (c2Handle) {
448 std::shared_ptr<C2GraphicAllocation> alloc;
449 c2_status_t err = mAllocator->priorGraphicAllocation(c2Handle, &alloc);
450 if (err != C2_OK) {
451 native_handle_close(c2Handle);
452 native_handle_delete(c2Handle);
453 return err;
454 }
455 std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
456 std::make_shared<C2BufferQueueBlockPoolData>(
457 slotBuffer->getGenerationNumber(),
458 mProducerId, slot,
459 mProducer, mSyncMem, 0);
460 mPoolDatas[slot] = poolData;
461 *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
462 return C2_OK;
463 }
464 // Block was not created. call requestBuffer# again next time.
465 slotBuffer.clear();
466 if (syncVar) {
467 syncVar->lock();
468 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
469 syncVar->notifyQueuedLocked();
470 syncVar->unlock();
471 if (c2Fence) {
472 *c2Fence = C2Fence();
473 }
474 } else {
475 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
476 }
477 return C2_BAD_VALUE;
478 }
479 if (c2Fence) {
480 *c2Fence = C2Fence();
481 }
482 return C2_BAD_VALUE;
483 }
484
485 public:
Impl(const std::shared_ptr<C2Allocator> & allocator)486 Impl(const std::shared_ptr<C2Allocator> &allocator)
487 : mInit(C2_OK), mProducerId(0), mGeneration(0),
488 mDqFailure(0), mLastDqTs(0), mLastDqLogTs(0),
489 mAllocator(allocator) {
490 }
491
~Impl()492 ~Impl() {
493 bool noInit = false;
494 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
495 if (!noInit && mProducer) {
496 Return<HStatus> transResult =
497 mProducer->detachBuffer(static_cast<int32_t>(i));
498 noInit = !transResult.isOk() ||
499 static_cast<HStatus>(transResult) == HStatus::NO_INIT;
500 }
501 mBuffers[i].clear();
502 }
503 }
504
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block,C2Fence * fence)505 c2_status_t fetchGraphicBlock(
506 uint32_t width,
507 uint32_t height,
508 uint32_t format,
509 C2MemoryUsage usage,
510 std::shared_ptr<C2GraphicBlock> *block /* nonnull */,
511 C2Fence *fence) {
512 block->reset();
513 if (mInit != C2_OK) {
514 return mInit;
515 }
516
517 static int kMaxIgbpRetryDelayUs = 10000;
518
519 std::unique_lock<std::mutex> lock(mMutex);
520 if (mLastDqLogTs == 0) {
521 mLastDqLogTs = getTimestampNow();
522 } else {
523 int64_t now = getTimestampNow();
524 if (now >= mLastDqLogTs + 5000000) {
525 if (now >= mLastDqTs + 1000000 || mDqFailure > 5) {
526 ALOGW("last successful dequeue was %lld us ago, "
527 "%zu consecutive failures",
528 (long long)(now - mLastDqTs), mDqFailure);
529 }
530 mLastDqLogTs = now;
531 }
532 }
533 if (mProducerId == 0) {
534 std::shared_ptr<C2GraphicAllocation> alloc;
535 c2_status_t err = mAllocator->newGraphicAllocation(
536 width, height, format, usage, &alloc);
537 if (err != C2_OK) {
538 return err;
539 }
540 std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
541 std::make_shared<C2BufferQueueBlockPoolData>(
542 0, (uint64_t)0, ~0, nullptr, nullptr, 0);
543 *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
544 ALOGV("allocated a buffer successfully");
545
546 return C2_OK;
547 }
548 c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block, fence);
549 if (status == C2_BLOCKING) {
550 lock.unlock();
551 if (!fence) {
552 // in order not to drain cpu from component's spinning
553 ::usleep(kMaxIgbpRetryDelayUs);
554 }
555 }
556 return status;
557 }
558
setRenderCallback(const OnRenderCallback & renderCallback)559 void setRenderCallback(const OnRenderCallback &renderCallback) {
560 std::scoped_lock<std::mutex> lock(mMutex);
561 mRenderCallback = renderCallback;
562 }
563
564 /* This is for Old HAL request for compatibility */
configureProducer(const sp<HGraphicBufferProducer> & producer)565 void configureProducer(const sp<HGraphicBufferProducer> &producer) {
566 uint64_t producerId = 0;
567 uint32_t generation = 0;
568 uint64_t usage = 0;
569 bool bqInformation = false;
570 if (producer) {
571 Return<uint64_t> transResult = producer->getUniqueId();
572 if (!transResult.isOk()) {
573 ALOGD("configureProducer -- failed to connect to the producer");
574 return;
575 }
576 producerId = static_cast<uint64_t>(transResult);
577 bqInformation = getGenerationNumberAndUsage(producer, &generation, &usage);
578 if (!bqInformation) {
579 ALOGW("get generationNumber failed %llu",
580 (unsigned long long)producerId);
581 }
582 }
583 configureProducer(producer, nullptr, producerId, generation, usage, bqInformation);
584 }
585
configureProducer(const sp<HGraphicBufferProducer> & producer,native_handle_t * syncHandle,uint64_t producerId,uint32_t generation,uint64_t usage,bool bqInformation)586 void configureProducer(const sp<HGraphicBufferProducer> &producer,
587 native_handle_t *syncHandle,
588 uint64_t producerId,
589 uint32_t generation,
590 uint64_t usage,
591 bool bqInformation) {
592 std::shared_ptr<C2SurfaceSyncMemory> c2SyncMem;
593 if (syncHandle) {
594 if (!producer) {
595 native_handle_close(syncHandle);
596 native_handle_delete(syncHandle);
597 } else {
598 c2SyncMem = C2SurfaceSyncMemory::Import(syncHandle);
599 }
600 }
601 int migrated = 0;
602 std::shared_ptr<C2SurfaceSyncMemory> oldMem;
603 // poolDatas dtor should not be called during lock is held.
604 std::shared_ptr<C2BufferQueueBlockPoolData>
605 poolDatas[NUM_BUFFER_SLOTS];
606 {
607 sp<GraphicBuffer> buffers[NUM_BUFFER_SLOTS];
608 std::scoped_lock<std::mutex> lock(mMutex);
609 bool noInit = false;
610 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
611 if (!noInit && mProducer) {
612 Return<HStatus> transResult =
613 mProducer->detachBuffer(static_cast<int32_t>(i));
614 noInit = !transResult.isOk() ||
615 static_cast<HStatus>(transResult) == HStatus::NO_INIT;
616 }
617 }
618 int32_t oldGeneration = mGeneration;
619 if (producer) {
620 mProducer = producer;
621 mProducerId = producerId;
622 mGeneration = bqInformation ? generation : 0;
623 } else {
624 mProducer = nullptr;
625 mProducerId = 0;
626 mGeneration = 0;
627 ALOGW("invalid producer producer(%d), generation(%d)",
628 (bool)producer, bqInformation);
629 }
630 oldMem = mSyncMem; // preven destruction while locked.
631 mSyncMem = c2SyncMem;
632 C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
633 if (syncVar) {
634 syncVar->lock();
635 syncVar->setSyncStatusLocked(C2SyncVariables::STATUS_ACTIVE);
636 syncVar->unlock();
637 }
638 if (mProducer && bqInformation) { // migrate buffers
639 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
640 std::shared_ptr<C2BufferQueueBlockPoolData> data =
641 mPoolDatas[i].lock();
642 if (data) {
643 int slot = data->migrate(
644 mProducer, generation, usage,
645 producerId, mBuffers[i], oldGeneration, mSyncMem);
646 if (slot >= 0) {
647 buffers[slot] = mBuffers[i];
648 poolDatas[slot] = data;
649 ++migrated;
650 }
651 }
652 }
653 }
654 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
655 mBuffers[i] = buffers[i];
656 mPoolDatas[i] = poolDatas[i];
657 }
658 }
659 if (producer && bqInformation) {
660 ALOGD("local generation change %u , "
661 "bqId: %llu migrated buffers # %d",
662 generation, (unsigned long long)producerId, migrated);
663 }
664 }
665
666 private:
667 friend struct C2BufferQueueBlockPoolData;
668
669 c2_status_t mInit;
670 uint64_t mProducerId;
671 uint32_t mGeneration;
672 OnRenderCallback mRenderCallback;
673
674 size_t mDqFailure;
675 int64_t mLastDqTs;
676 int64_t mLastDqLogTs;
677
678 const std::shared_ptr<C2Allocator> mAllocator;
679
680 std::mutex mMutex;
681 sp<HGraphicBufferProducer> mProducer;
682 sp<HGraphicBufferProducer> mSavedProducer;
683
684 sp<GraphicBuffer> mBuffers[NUM_BUFFER_SLOTS];
685 std::weak_ptr<C2BufferQueueBlockPoolData> mPoolDatas[NUM_BUFFER_SLOTS];
686
687 std::shared_ptr<C2SurfaceSyncMemory> mSyncMem;
688 };
689
C2BufferQueueBlockPoolData(uint32_t generation,uint64_t bqId,int32_t bqSlot,const std::shared_ptr<int> & owner,const sp<HGraphicBufferProducer> & producer)690 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
691 uint32_t generation, uint64_t bqId, int32_t bqSlot,
692 const std::shared_ptr<int>& owner,
693 const sp<HGraphicBufferProducer>& producer) :
694 mLocal(false), mHeld(producer && bqId != 0),
695 mGeneration(generation), mBqId(bqId), mBqSlot(bqSlot),
696 mCurrentGeneration(generation), mCurrentBqId(bqId),
697 mTransfer(false), mAttach(false), mDisplay(false),
698 mOwner(owner), mIgbp(producer) {
699 }
700
C2BufferQueueBlockPoolData(uint32_t generation,uint64_t bqId,int32_t bqSlot,const android::sp<HGraphicBufferProducer> & producer,std::shared_ptr<C2SurfaceSyncMemory> syncMem,int noUse)701 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
702 uint32_t generation, uint64_t bqId, int32_t bqSlot,
703 const android::sp<HGraphicBufferProducer>& producer,
704 std::shared_ptr<C2SurfaceSyncMemory> syncMem, int noUse) :
705 mLocal(true), mHeld(true),
706 mGeneration(generation), mBqId(bqId), mBqSlot(bqSlot),
707 mCurrentGeneration(generation), mCurrentBqId(bqId),
708 mTransfer(false), mAttach(false), mDisplay(false),
709 mIgbp(producer), mSyncMem(syncMem) {
710 (void)noUse;
711 }
712
~C2BufferQueueBlockPoolData()713 C2BufferQueueBlockPoolData::~C2BufferQueueBlockPoolData() {
714 if (!mHeld || mBqId == 0 || !mIgbp) {
715 return;
716 }
717
718 if (mLocal) {
719 if (mGeneration == mCurrentGeneration && mBqId == mCurrentBqId) {
720 C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
721 if (syncVar) {
722 syncVar->lock();
723 if (syncVar->getSyncStatusLocked() == C2SyncVariables::STATUS_ACTIVE) {
724 mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
725 syncVar->notifyQueuedLocked();
726 }
727 syncVar->unlock();
728 } else {
729 mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
730 }
731 }
732 } else if (!mOwner.expired()) {
733 C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
734 if (syncVar) {
735 syncVar->lock();
736 if (syncVar->getSyncStatusLocked() != C2SyncVariables::STATUS_SWITCHING) {
737 mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
738 syncVar->notifyQueuedLocked();
739 }
740 syncVar->unlock();
741 } else {
742 mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
743 }
744 }
745 }
746
getType() const747 C2BufferQueueBlockPoolData::type_t C2BufferQueueBlockPoolData::getType() const {
748 return TYPE_BUFFERQUEUE;
749 }
750
migrate(const sp<HGraphicBufferProducer> & producer,uint32_t toGeneration,uint64_t toUsage,uint64_t toBqId,sp<GraphicBuffer> & graphicBuffer,uint32_t oldGeneration,std::shared_ptr<C2SurfaceSyncMemory> syncMem)751 int C2BufferQueueBlockPoolData::migrate(
752 const sp<HGraphicBufferProducer>& producer,
753 uint32_t toGeneration, uint64_t toUsage, uint64_t toBqId,
754 sp<GraphicBuffer>& graphicBuffer, uint32_t oldGeneration,
755 std::shared_ptr<C2SurfaceSyncMemory> syncMem) {
756 std::scoped_lock<std::mutex> l(mLock);
757
758 mCurrentBqId = toBqId;
759 mCurrentGeneration = toGeneration;
760
761 if (!mHeld || mBqId == 0) {
762 ALOGV("buffer is not owned");
763 return -1;
764 }
765 if (!mLocal) {
766 ALOGV("pool is not local");
767 return -1;
768 }
769 if (mBqSlot < 0 || mBqSlot >= NUM_BUFFER_SLOTS) {
770 ALOGV("slot is not in effect");
771 return -1;
772 }
773 if (!graphicBuffer) {
774 ALOGV("buffer is null");
775 return -1;
776 }
777 if (toGeneration == mGeneration && mBqId == toBqId) {
778 ALOGV("cannot migrate to same bufferqueue");
779 return -1;
780 }
781 if (oldGeneration != mGeneration) {
782 ALOGV("cannot migrate stale buffer");
783 return -1;
784 }
785 if (mTransfer) {
786 // either transferred or detached.
787 ALOGV("buffer is in transfer");
788 return -1;
789 }
790
791 if (toUsage != graphicBuffer->getUsage()) {
792 sp<GraphicBuffer> newBuffer = new GraphicBuffer(
793 graphicBuffer->handle, GraphicBuffer::CLONE_HANDLE,
794 graphicBuffer->width, graphicBuffer->height, graphicBuffer->format,
795 graphicBuffer->layerCount, toUsage | graphicBuffer->getUsage(), graphicBuffer->stride);
796 if (newBuffer->initCheck() == android::NO_ERROR) {
797 graphicBuffer = std::move(newBuffer);
798 } else {
799 ALOGW("%s() failed to update usage, original usage=%" PRIx64 ", toUsage=%" PRIx64,
800 __func__, graphicBuffer->getUsage(), toUsage);
801 }
802 }
803 graphicBuffer->setGenerationNumber(toGeneration);
804
805 HBuffer hBuffer{};
806 uint32_t hGenerationNumber{};
807 if (!b2h(graphicBuffer, &hBuffer, &hGenerationNumber)) {
808 ALOGD("I to O conversion failed");
809 return -1;
810 }
811
812 bool converted{};
813 status_t bStatus{};
814 int slot;
815 int *outSlot = &slot;
816 Return<void> transResult =
817 producer->attachBuffer(hBuffer, hGenerationNumber,
818 [&converted, &bStatus, outSlot](
819 HStatus hStatus, int32_t hSlot, bool releaseAll) {
820 converted = h2b(hStatus, &bStatus);
821 *outSlot = static_cast<int>(hSlot);
822 if (converted && releaseAll && bStatus == android::OK) {
823 bStatus = android::INVALID_OPERATION;
824 }
825 });
826 if (!transResult.isOk() || !converted || bStatus != android::OK) {
827 ALOGD("attach failed %d", static_cast<int>(bStatus));
828 return -1;
829 }
830 ALOGV("local migration from gen %u : %u slot %d : %d",
831 mGeneration, toGeneration, mBqSlot, slot);
832 mIgbp = producer;
833 mGeneration = toGeneration;
834 mBqId = toBqId;
835 mBqSlot = slot;
836 mSyncMem = syncMem;
837
838 C2SyncVariables *syncVar = syncMem ? syncMem->mem() : nullptr;
839 if (syncVar) {
840 syncVar->lock();
841 syncVar->notifyDequeuedLocked();
842 syncVar->unlock();
843 }
844 return slot;
845 }
846
getBufferQueueData(uint32_t * generation,uint64_t * bqId,int32_t * bqSlot) const847 void C2BufferQueueBlockPoolData::getBufferQueueData(
848 uint32_t* generation, uint64_t* bqId, int32_t* bqSlot) const {
849 if (generation) {
850 std::scoped_lock<std::mutex> lock(mLock);
851 *generation = mGeneration;
852 if (bqId) {
853 *bqId = mBqId;
854 }
855 if (bqSlot) {
856 *bqSlot = mBqSlot;
857 }
858 }
859 }
860
holdBlockFromBufferQueue(const std::shared_ptr<int> & owner,const sp<HGraphicBufferProducer> & igbp,std::shared_ptr<C2SurfaceSyncMemory> syncMem)861 bool C2BufferQueueBlockPoolData::holdBlockFromBufferQueue(
862 const std::shared_ptr<int>& owner,
863 const sp<HGraphicBufferProducer>& igbp,
864 std::shared_ptr<C2SurfaceSyncMemory> syncMem) {
865 std::scoped_lock<std::mutex> lock(mLock);
866 if (!mLocal) {
867 mOwner = owner;
868 mIgbp = igbp;
869 mSyncMem = syncMem;
870 }
871 if (mHeld) {
872 return false;
873 }
874 mHeld = true;
875 return true;
876 }
877
beginTransferBlockToClient()878 bool C2BufferQueueBlockPoolData::beginTransferBlockToClient() {
879 std::scoped_lock<std::mutex> lock(mLock);
880 mTransfer = true;
881 return true;
882 }
883
endTransferBlockToClient(bool transfer)884 bool C2BufferQueueBlockPoolData::endTransferBlockToClient(bool transfer) {
885 std::scoped_lock<std::mutex> lock(mLock);
886 mTransfer = false;
887 if (transfer) {
888 mHeld = false;
889 }
890 return true;
891 }
892
beginAttachBlockToBufferQueue()893 bool C2BufferQueueBlockPoolData::beginAttachBlockToBufferQueue() {
894 std::scoped_lock<std::mutex> lock(mLock);
895 if (mLocal || mDisplay ||
896 mAttach || !mHeld) {
897 return false;
898 }
899 if (mBqId == 0) {
900 return false;
901 }
902 mAttach = true;
903 return true;
904 }
905
endAttachBlockToBufferQueue(const std::shared_ptr<int> & owner,const sp<HGraphicBufferProducer> & igbp,std::shared_ptr<C2SurfaceSyncMemory> syncMem,uint32_t generation,uint64_t bqId,int32_t bqSlot)906 bool C2BufferQueueBlockPoolData::endAttachBlockToBufferQueue(
907 const std::shared_ptr<int>& owner,
908 const sp<HGraphicBufferProducer>& igbp,
909 std::shared_ptr<C2SurfaceSyncMemory> syncMem,
910 uint32_t generation,
911 uint64_t bqId,
912 int32_t bqSlot) {
913 std::scoped_lock<std::mutex> lock(mLock);
914 if (mLocal || !mAttach) {
915 return false;
916 }
917 if (mDisplay) {
918 mAttach = false;
919 mHeld = false;
920 return false;
921 }
922 mAttach = false;
923 mHeld = true;
924 mOwner = owner;
925 mIgbp = igbp;
926 mSyncMem = syncMem;
927 mGeneration = generation;
928 mBqId = bqId;
929 mBqSlot = bqSlot;
930 return true;
931 }
932
displayBlockToBufferQueue()933 bool C2BufferQueueBlockPoolData::displayBlockToBufferQueue() {
934 std::scoped_lock<std::mutex> lock(mLock);
935 if (mLocal || mDisplay || !mHeld) {
936 return false;
937 }
938 if (mBqId == 0) {
939 return false;
940 }
941 mDisplay = true;
942 if (mAttach) {
943 return false;
944 }
945 mHeld = false;
946 return true;
947 }
948
C2BufferQueueBlockPool(const std::shared_ptr<C2Allocator> & allocator,const local_id_t localId)949 C2BufferQueueBlockPool::C2BufferQueueBlockPool(
950 const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId)
951 : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {}
952
~C2BufferQueueBlockPool()953 C2BufferQueueBlockPool::~C2BufferQueueBlockPool() {}
954
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)955 c2_status_t C2BufferQueueBlockPool::fetchGraphicBlock(
956 uint32_t width,
957 uint32_t height,
958 uint32_t format,
959 C2MemoryUsage usage,
960 std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
961 if (mImpl) {
962 return mImpl->fetchGraphicBlock(width, height, format, usage, block, nullptr);
963 }
964 return C2_CORRUPTED;
965 }
966
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block,C2Fence * fence)967 c2_status_t C2BufferQueueBlockPool::fetchGraphicBlock(
968 uint32_t width,
969 uint32_t height,
970 uint32_t format,
971 C2MemoryUsage usage,
972 std::shared_ptr<C2GraphicBlock> *block /* nonnull */,
973 C2Fence *fence /* nonnull */) {
974 if (mImpl) {
975 return mImpl->fetchGraphicBlock(width, height, format, usage, block, fence);
976 }
977 return C2_CORRUPTED;
978 }
979
configureProducer(const sp<HGraphicBufferProducer> & producer)980 void C2BufferQueueBlockPool::configureProducer(const sp<HGraphicBufferProducer> &producer) {
981 if (mImpl) {
982 mImpl->configureProducer(producer);
983 }
984 }
985
configureProducer(const sp<HGraphicBufferProducer> & producer,native_handle_t * syncMemory,uint64_t bqId,uint32_t generationId,uint64_t consumerUsage)986 void C2BufferQueueBlockPool::configureProducer(
987 const sp<HGraphicBufferProducer> &producer,
988 native_handle_t *syncMemory,
989 uint64_t bqId,
990 uint32_t generationId,
991 uint64_t consumerUsage) {
992 if (mImpl) {
993 mImpl->configureProducer(
994 producer, syncMemory, bqId, generationId, consumerUsage, true);
995 }
996 }
997
setRenderCallback(const OnRenderCallback & renderCallback)998 void C2BufferQueueBlockPool::setRenderCallback(const OnRenderCallback &renderCallback) {
999 if (mImpl) {
1000 mImpl->setRenderCallback(renderCallback);
1001 }
1002 }
1003