• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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