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