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 <gui/BufferQueueDefs.h>
     22 #include <list>
     23 #include <map>
     24 #include <mutex>
     25 
     26 #include <C2AllocatorGralloc.h>
     27 #include <C2BqBufferPriv.h>
     28 #include <C2BlockInternal.h>
     29 
     30 using ::android::AnwBuffer;
     31 using ::android::BufferQueueDefs::NUM_BUFFER_SLOTS;
     32 using ::android::C2AllocatorGralloc;
     33 using ::android::C2AndroidMemoryUsage;
     34 using ::android::Fence;
     35 using ::android::GraphicBuffer;
     36 using ::android::HGraphicBufferProducer;
     37 using ::android::IGraphicBufferProducer;
     38 using ::android::hardware::graphics::common::V1_0::PixelFormat;
     39 using ::android::hidl_handle;
     40 using ::android::sp;
     41 using ::android::status_t;
     42 using ::android::wp;
     43 
     44 struct C2BufferQueueBlockPoolData : public _C2BlockPoolData {
     45 
     46     bool held;
     47     bool local;
     48     uint64_t bqId;
     49     int32_t bqSlot;
     50     sp<HGraphicBufferProducer> igbp;
     51     std::shared_ptr<C2BufferQueueBlockPool::Impl> localPool;
     52 
     53     virtual type_t getType() const override {
     54         return TYPE_BUFFERQUEUE;
     55     }
     56 
     57     // Create a remote BlockPoolData.
     58     C2BufferQueueBlockPoolData(
     59             uint64_t bqId, int32_t bqSlot,
     60             const sp<HGraphicBufferProducer>& producer = nullptr);
     61 
     62     // Create a local BlockPoolData.
     63     C2BufferQueueBlockPoolData(
     64             uint64_t bqId, int32_t bqSlot,
     65             const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool);
     66 
     67     virtual ~C2BufferQueueBlockPoolData() override;
     68 
     69 };
     70 
     71 bool _C2BlockFactory::GetBufferQueueData(
     72         const std::shared_ptr<_C2BlockPoolData>& data,
     73         uint64_t* bqId, int32_t* bqSlot) {
     74     if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERQUEUE) {
     75         if (bqId) {
     76             const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
     77                     std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
     78             *bqId = poolData->bqId;
     79             if (bqSlot) {
     80                 *bqSlot = poolData->bqSlot;
     81             }
     82         }
     83         return true;
     84     }
     85     return false;
     86 }
     87 
     88 bool _C2BlockFactory::AssignBlockToBufferQueue(
     89         const std::shared_ptr<_C2BlockPoolData>& data,
     90         const sp<HGraphicBufferProducer>& igbp,
     91         uint64_t bqId,
     92         int32_t bqSlot,
     93         bool held) {
     94     if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERQUEUE) {
     95         const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
     96                 std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
     97         poolData->igbp = igbp;
     98         poolData->bqId = bqId;
     99         poolData->bqSlot = bqSlot;
    100         poolData->held = held;
    101         return true;
    102     }
    103     return false;
    104 }
    105 
    106 bool _C2BlockFactory::HoldBlockFromBufferQueue(
    107         const std::shared_ptr<_C2BlockPoolData>& data,
    108         const sp<HGraphicBufferProducer>& igbp) {
    109     const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
    110             std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
    111     if (!poolData->local) {
    112         poolData->igbp = igbp;
    113     }
    114     if (poolData->held) {
    115         poolData->held = true;
    116         return false;
    117     }
    118     poolData->held = true;
    119     return true;
    120 }
    121 
    122 bool _C2BlockFactory::YieldBlockToBufferQueue(
    123         const std::shared_ptr<_C2BlockPoolData>& data) {
    124     const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
    125             std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
    126     if (!poolData->held) {
    127         poolData->held = false;
    128         return false;
    129     }
    130     poolData->held = false;
    131     return true;
    132 }
    133 
    134 std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
    135         const C2Handle *handle) {
    136     // TODO: get proper allocator? and mutex?
    137     static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0);
    138 
    139     std::shared_ptr<C2GraphicAllocation> alloc;
    140     if (C2AllocatorGralloc::isValid(handle)) {
    141         uint32_t width;
    142         uint32_t height;
    143         uint32_t format;
    144         uint64_t usage;
    145         uint32_t stride;
    146         uint64_t igbp_id;
    147         uint32_t igbp_slot;
    148         android::_UnwrapNativeCodec2GrallocMetadata(
    149                 handle, &width, &height, &format, &usage, &stride, &igbp_id, &igbp_slot);
    150         c2_status_t err = sAllocator->priorGraphicAllocation(handle, &alloc);
    151         if (err == C2_OK) {
    152             std::shared_ptr<C2GraphicBlock> block;
    153             if (igbp_id || igbp_slot) {
    154                 // BQBBP
    155                 std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
    156                         std::make_shared<C2BufferQueueBlockPoolData>(igbp_id, (int32_t)igbp_slot);
    157                 block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
    158             } else {
    159                 block = _C2BlockFactory::CreateGraphicBlock(alloc);
    160             }
    161             return block;
    162         }
    163     }
    164     return nullptr;
    165 }
    166 
    167 class C2BufferQueueBlockPool::Impl
    168         : public std::enable_shared_from_this<C2BufferQueueBlockPool::Impl> {
    169 private:
    170     c2_status_t fetchFromIgbp_l(
    171             uint32_t width,
    172             uint32_t height,
    173             uint32_t format,
    174             C2MemoryUsage usage,
    175             std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
    176         // We have an IGBP now.
    177         sp<Fence> fence = new Fence();
    178         C2AndroidMemoryUsage androidUsage = usage;
    179         status_t status;
    180         PixelFormat pixelFormat = static_cast<PixelFormat>(format);
    181         int slot;
    182         ALOGV("tries to dequeue buffer");
    183         mProducer->dequeueBuffer(
    184                 width, height, pixelFormat, androidUsage.asGrallocUsage(), true,
    185                 [&status, &slot, &fence](
    186                         int32_t tStatus, int32_t tSlot, hidl_handle const& tFence,
    187                         HGraphicBufferProducer::FrameEventHistoryDelta const& tTs) {
    188                     status = tStatus;
    189                     slot = tSlot;
    190                     if (!android::conversion::convertTo(fence.get(), tFence) &&
    191                             status == android::NO_ERROR) {
    192                         status = android::BAD_VALUE;
    193                     }
    194                     (void) tTs;
    195                 });
    196         // dequeueBuffer returns flag.
    197         if (status < android::OK) {
    198             ALOGD("cannot dequeue buffer %d", status);
    199             if (status == android::INVALID_OPERATION) {
    200               // Too many buffer dequeued. retrying after some time is required.
    201               return C2_TIMED_OUT;
    202             } else {
    203               return C2_BAD_VALUE;
    204             }
    205         }
    206         ALOGV("dequeued a buffer successfully");
    207         native_handle_t* nh = nullptr;
    208         hidl_handle fenceHandle;
    209         if (fence) {
    210             android::conversion::wrapAs(&fenceHandle, &nh, *fence);
    211         }
    212         if (fence) {
    213             static constexpr int kFenceWaitTimeMs = 10;
    214 
    215             status_t status = fence->wait(kFenceWaitTimeMs);
    216             if (status == -ETIME) {
    217                 // fence is not signalled yet.
    218                 mProducer->cancelBuffer(slot, fenceHandle);
    219                 return C2_TIMED_OUT;
    220             }
    221             if (status != android::NO_ERROR) {
    222                 ALOGD("buffer fence wait error %d", status);
    223                 mProducer->cancelBuffer(slot, fenceHandle);
    224                 return C2_BAD_VALUE;
    225             } else if (mRenderCallback) {
    226                 nsecs_t signalTime = fence->getSignalTime();
    227                 if (signalTime >= 0 && signalTime < INT64_MAX) {
    228                     mRenderCallback(mProducerId, slot, signalTime);
    229                 } else {
    230                     ALOGV("got fence signal time of %lld", (long long)signalTime);
    231                 }
    232             }
    233         }
    234 
    235         sp<GraphicBuffer> &slotBuffer = mBuffers[slot];
    236         if (status & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION || !slotBuffer) {
    237             if (!slotBuffer) {
    238                 slotBuffer = new GraphicBuffer();
    239             }
    240             // N.B. This assumes requestBuffer# returns an existing allocation
    241             // instead of a new allocation.
    242             mProducer->requestBuffer(
    243                     slot,
    244                     [&status, &slotBuffer](int32_t tStatus, AnwBuffer const& tBuffer){
    245                         status = tStatus;
    246                         if (!android::conversion::convertTo(slotBuffer.get(), tBuffer) &&
    247                                 status == android::NO_ERROR) {
    248                             status = android::BAD_VALUE;
    249                         }
    250                     });
    251 
    252             if (status != android::NO_ERROR) {
    253                 mBuffers[slot].clear();
    254                 mProducer->cancelBuffer(slot, fenceHandle);
    255                 return C2_BAD_VALUE;
    256             }
    257         }
    258         if (mBuffers[slot]) {
    259             native_handle_t *grallocHandle = native_handle_clone(mBuffers[slot]->handle);
    260 
    261             if (grallocHandle) {
    262                 ALOGV("buffer wraps %llu %d", (unsigned long long)mProducerId, slot);
    263                 C2Handle *c2Handle = android::WrapNativeCodec2GrallocHandle(
    264                         grallocHandle,
    265                         mBuffers[slot]->width,
    266                         mBuffers[slot]->height,
    267                         mBuffers[slot]->format,
    268                         mBuffers[slot]->usage,
    269                         mBuffers[slot]->stride,
    270                         mProducerId, slot);
    271                 if (c2Handle) {
    272                     // Moved everything to c2Handle.
    273                     native_handle_delete(grallocHandle);
    274                     std::shared_ptr<C2GraphicAllocation> alloc;
    275                     c2_status_t err = mAllocator->priorGraphicAllocation(c2Handle, &alloc);
    276                     if (err != C2_OK) {
    277                         return err;
    278                     }
    279                     std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
    280                             std::make_shared<C2BufferQueueBlockPoolData>(
    281                                     mProducerId, slot, shared_from_this());
    282                     *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
    283                     return C2_OK;
    284                 }
    285                 native_handle_close(grallocHandle);
    286                 native_handle_delete(grallocHandle);
    287             }
    288             // Block was not created. call requestBuffer# again next time.
    289             mBuffers[slot].clear();
    290             mProducer->cancelBuffer(slot, fenceHandle);
    291         }
    292         return C2_BAD_VALUE;
    293     }
    294 
    295 public:
    296     Impl(const std::shared_ptr<C2Allocator> &allocator)
    297         : mInit(C2_OK), mProducerId(0), mAllocator(allocator) {
    298     }
    299 
    300     ~Impl() {
    301         std::lock_guard<std::mutex> lock(mMutex);
    302         bool noInit = false;
    303         for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
    304             if (!noInit && mProducer) {
    305                 noInit = mProducer->detachBuffer(i) == android::NO_INIT;
    306             }
    307             mBuffers[i].clear();
    308         }
    309     }
    310 
    311     c2_status_t fetchGraphicBlock(
    312             uint32_t width,
    313             uint32_t height,
    314             uint32_t format,
    315             C2MemoryUsage usage,
    316             std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
    317         block->reset();
    318         if (mInit != C2_OK) {
    319             return mInit;
    320         }
    321 
    322         static int kMaxIgbpRetry = 20; // TODO: small number can cause crash in releasing.
    323         static int kMaxIgbpRetryDelayUs = 10000;
    324 
    325         int curTry = 0;
    326 
    327         while (curTry++ < kMaxIgbpRetry) {
    328             std::unique_lock<std::mutex> lock(mMutex);
    329             // TODO: return C2_NO_INIT
    330             if (mProducerId == 0) {
    331                 std::shared_ptr<C2GraphicAllocation> alloc;
    332                 c2_status_t err = mAllocator->newGraphicAllocation(
    333                         width, height, format, usage, &alloc);
    334                 if (err != C2_OK) {
    335                     return err;
    336                 }
    337                 std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
    338                         std::make_shared<C2BufferQueueBlockPoolData>(
    339                                 (uint64_t)0, ~0, shared_from_this());
    340                 // TODO: config?
    341                 *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
    342                 ALOGV("allocated a buffer successfully");
    343 
    344                 return C2_OK;
    345             }
    346             c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block);
    347             if (status == C2_TIMED_OUT) {
    348                 lock.unlock();
    349                 ::usleep(kMaxIgbpRetryDelayUs);
    350                 continue;
    351             }
    352             return status;
    353         }
    354         return C2_TIMED_OUT;
    355     }
    356 
    357     void setRenderCallback(const OnRenderCallback &renderCallback) {
    358         std::lock_guard<std::mutex> lock(mMutex);
    359         mRenderCallback = renderCallback;
    360     }
    361 
    362     void configureProducer(const sp<HGraphicBufferProducer> &producer) {
    363         int32_t status = android::OK;
    364         uint64_t producerId = 0;
    365         if (producer) {
    366             producer->getUniqueId(
    367                     [&status, &producerId](int32_t tStatus, int64_t tProducerId) {
    368                 status = tStatus;
    369                 producerId = tProducerId;
    370                     });
    371         }
    372         {
    373             std::lock_guard<std::mutex> lock(mMutex);
    374             if (status == android::OK && producerId == mProducerId) {
    375                 // producer is not changed.
    376                 return;
    377             }
    378             bool noInit = false;
    379             for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
    380                 if (!noInit && mProducer) {
    381                     noInit = mProducer->detachBuffer(i) == android::NO_INIT;
    382                 }
    383                 mBuffers[i].clear();
    384             }
    385             if (producer && status == android::OK) {
    386                 mProducer = producer;
    387                 mProducerId = producerId;
    388             } else {
    389                 mProducer = nullptr;
    390                 mProducerId = 0;
    391             }
    392         }
    393     }
    394 
    395 private:
    396     friend struct C2BufferQueueBlockPoolData;
    397 
    398     void cancel(uint64_t igbp_id, int32_t igbp_slot) {
    399         std::lock_guard<std::mutex> lock(mMutex);
    400         if (igbp_id == mProducerId && mProducer) {
    401             mProducer->cancelBuffer(igbp_slot, nullptr);
    402         }
    403     }
    404 
    405     c2_status_t mInit;
    406     uint64_t mProducerId;
    407     OnRenderCallback mRenderCallback;
    408 
    409     const std::shared_ptr<C2Allocator> mAllocator;
    410 
    411     std::mutex mMutex;
    412     sp<HGraphicBufferProducer> mProducer;
    413 
    414     sp<GraphicBuffer> mBuffers[NUM_BUFFER_SLOTS];
    415 };
    416 
    417 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
    418         uint64_t bqId, int32_t bqSlot,
    419         const sp<HGraphicBufferProducer>& producer) :
    420         held(producer && bqId != 0), local(false),
    421         bqId(bqId), bqSlot(bqSlot),
    422         igbp(producer),
    423         localPool() {
    424 }
    425 
    426 C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
    427         uint64_t bqId, int32_t bqSlot,
    428         const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool) :
    429         held(true), local(true),
    430         bqId(bqId), bqSlot(bqSlot),
    431         igbp(pool ? pool->mProducer : nullptr),
    432         localPool(pool) {
    433 }
    434 
    435 C2BufferQueueBlockPoolData::~C2BufferQueueBlockPoolData() {
    436     if (!held || bqId == 0) {
    437         return;
    438     }
    439     if (local && localPool) {
    440         localPool->cancel(bqId, bqSlot);
    441     } else if (igbp) {
    442         igbp->cancelBuffer(bqSlot, nullptr);
    443     }
    444 }
    445 
    446 C2BufferQueueBlockPool::C2BufferQueueBlockPool(
    447         const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId)
    448         : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {}
    449 
    450 C2BufferQueueBlockPool::~C2BufferQueueBlockPool() {}
    451 
    452 c2_status_t C2BufferQueueBlockPool::fetchGraphicBlock(
    453         uint32_t width,
    454         uint32_t height,
    455         uint32_t format,
    456         C2MemoryUsage usage,
    457         std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
    458     if (mImpl) {
    459         return mImpl->fetchGraphicBlock(width, height, format, usage, block);
    460     }
    461     return C2_CORRUPTED;
    462 }
    463 
    464 void C2BufferQueueBlockPool::configureProducer(const sp<HGraphicBufferProducer> &producer) {
    465     if (mImpl) {
    466         mImpl->configureProducer(producer);
    467     }
    468 }
    469 
    470 void C2BufferQueueBlockPool::setRenderCallback(const OnRenderCallback &renderCallback) {
    471     if (mImpl) {
    472         mImpl->setRenderCallback(renderCallback);
    473     }
    474 }
    475