Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright 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 "Codec2-block_helper"
     19 #include <android-base/logging.h>
     20 
     21 #include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
     22 #include <codec2/hidl/1.0/ClientBlockHelper.h>
     23 #include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
     24 
     25 #include <C2AllocatorGralloc.h>
     26 #include <C2BlockInternal.h>
     27 #include <C2Buffer.h>
     28 #include <C2PlatformSupport.h>
     29 
     30 #include <iomanip>
     31 
     32 namespace android {
     33 namespace hardware {
     34 namespace media {
     35 namespace c2 {
     36 namespace V1_0 {
     37 namespace utils {
     38 
     39 using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
     40         V2_0::IGraphicBufferProducer;
     41 using B2HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
     42         V2_0::utils::B2HGraphicBufferProducer;
     43 
     44 namespace /* unnamed */ {
     45 
     46 // Create a GraphicBuffer object from a graphic block.
     47 sp<GraphicBuffer> createGraphicBuffer(const C2ConstGraphicBlock& block) {
     48     uint32_t width;
     49     uint32_t height;
     50     uint32_t format;
     51     uint64_t usage;
     52     uint32_t stride;
     53     uint32_t generation;
     54     uint64_t bqId;
     55     int32_t bqSlot;
     56     _UnwrapNativeCodec2GrallocMetadata(
     57             block.handle(), &width, &height, &format, &usage,
     58             &stride, &generation, &bqId, reinterpret_cast<uint32_t*>(&bqSlot));
     59     native_handle_t *grallocHandle =
     60             UnwrapNativeCodec2GrallocHandle(block.handle());
     61     sp<GraphicBuffer> graphicBuffer =
     62             new GraphicBuffer(grallocHandle,
     63                               GraphicBuffer::CLONE_HANDLE,
     64                               width, height, format,
     65                               1, usage, stride);
     66     native_handle_delete(grallocHandle);
     67     return graphicBuffer;
     68 }
     69 
     70 template <typename BlockProcessor>
     71 void forEachBlock(C2FrameData& frameData,
     72                   BlockProcessor process) {
     73     for (const std::shared_ptr<C2Buffer>& buffer : frameData.buffers) {
     74         if (buffer) {
     75             for (const C2ConstGraphicBlock& block :
     76                     buffer->data().graphicBlocks()) {
     77                 process(block);
     78             }
     79         }
     80     }
     81 }
     82 
     83 template <typename BlockProcessor>
     84 void forEachBlock(const std::list<std::unique_ptr<C2Work>>& workList,
     85                   BlockProcessor process) {
     86     for (const std::unique_ptr<C2Work>& work : workList) {
     87         if (!work) {
     88             continue;
     89         }
     90         for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
     91             if (worklet) {
     92                 forEachBlock(worklet->output, process);
     93             }
     94         }
     95     }
     96 }
     97 
     98 sp<HGraphicBufferProducer> getHgbp(const sp<IGraphicBufferProducer>& igbp) {
     99     sp<HGraphicBufferProducer> hgbp =
    100             igbp->getHalInterface<HGraphicBufferProducer>();
    101     return hgbp ? hgbp :
    102             new B2HGraphicBufferProducer(igbp);
    103 }
    104 
    105 status_t attachToBufferQueue(const C2ConstGraphicBlock& block,
    106                              const sp<IGraphicBufferProducer>& igbp,
    107                              uint32_t generation,
    108                              int32_t* bqSlot) {
    109     if (!igbp) {
    110         LOG(WARNING) << "attachToBufferQueue -- null producer.";
    111         return NO_INIT;
    112     }
    113 
    114     sp<GraphicBuffer> graphicBuffer = createGraphicBuffer(block);
    115     graphicBuffer->setGenerationNumber(generation);
    116 
    117     LOG(VERBOSE) << "attachToBufferQueue -- attaching buffer:"
    118             << " block dimension " << block.width() << "x"
    119                                    << block.height()
    120             << ", graphicBuffer dimension " << graphicBuffer->getWidth() << "x"
    121                                            << graphicBuffer->getHeight()
    122             << std::hex << std::setfill('0')
    123             << ", format 0x" << std::setw(8) << graphicBuffer->getPixelFormat()
    124             << ", usage 0x" << std::setw(16) << graphicBuffer->getUsage()
    125             << std::dec << std::setfill(' ')
    126             << ", stride " << graphicBuffer->getStride()
    127             << ", generation " << graphicBuffer->getGenerationNumber();
    128 
    129     status_t result = igbp->attachBuffer(bqSlot, graphicBuffer);
    130     if (result != OK) {
    131         LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
    132                         "status = " << result << ".";
    133         return result;
    134     }
    135     LOG(VERBOSE) << "attachToBufferQueue -- attachBuffer returned slot #"
    136                  << *bqSlot << ".";
    137     return OK;
    138 }
    139 
    140 bool getBufferQueueAssignment(const C2ConstGraphicBlock& block,
    141                               uint32_t* generation,
    142                               uint64_t* bqId,
    143                               int32_t* bqSlot) {
    144     return _C2BlockFactory::GetBufferQueueData(
    145             _C2BlockFactory::GetGraphicBlockPoolData(block),
    146             generation, bqId, bqSlot);
    147 }
    148 } // unnamed namespace
    149 
    150 class OutputBufferQueue::Impl {
    151     std::mutex mMutex;
    152     sp<IGraphicBufferProducer> mIgbp;
    153     uint32_t mGeneration;
    154     uint64_t mBqId;
    155     std::shared_ptr<int> mOwner;
    156     // To migrate existing buffers
    157     sp<GraphicBuffer> mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS]; // find a better way
    158     std::weak_ptr<_C2BlockPoolData>
    159                     mPoolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
    160 
    161 public:
    162     Impl(): mGeneration(0), mBqId(0) {}
    163 
    164     bool configure(const sp<IGraphicBufferProducer>& igbp,
    165                    uint32_t generation,
    166                    uint64_t bqId) {
    167         size_t tryNum = 0;
    168         size_t success = 0;
    169         sp<GraphicBuffer> buffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
    170         std::weak_ptr<_C2BlockPoolData>
    171                 poolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
    172         {
    173             std::scoped_lock<std::mutex> l(mMutex);
    174             if (generation == mGeneration) {
    175                 return false;
    176             }
    177             mIgbp = igbp;
    178             mGeneration = generation;
    179             mBqId = bqId;
    180             mOwner = std::make_shared<int>(0);
    181             for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; ++i) {
    182                 if (mBqId == 0 || !mBuffers[i]) {
    183                     continue;
    184                 }
    185                 std::shared_ptr<_C2BlockPoolData> data = mPoolDatas[i].lock();
    186                 if (!data ||
    187                     !_C2BlockFactory::BeginAttachBlockToBufferQueue(data)) {
    188                     continue;
    189                 }
    190                 ++tryNum;
    191                 int bqSlot;
    192                 mBuffers[i]->setGenerationNumber(generation);
    193                 status_t result = igbp->attachBuffer(&bqSlot, mBuffers[i]);
    194                 if (result != OK) {
    195                     continue;
    196                 }
    197                 bool attach =
    198                         _C2BlockFactory::EndAttachBlockToBufferQueue(
    199                                 data, mOwner, getHgbp(mIgbp),
    200                                 generation, bqId, bqSlot);
    201                 if (!attach) {
    202                     igbp->cancelBuffer(bqSlot, Fence::NO_FENCE);
    203                     continue;
    204                 }
    205                 buffers[bqSlot] = mBuffers[i];
    206                 poolDatas[bqSlot] = data;
    207                 ++success;
    208             }
    209             for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; ++i) {
    210                 mBuffers[i] = buffers[i];
    211                 mPoolDatas[i] = poolDatas[i];
    212             }
    213         }
    214         ALOGD("remote graphic buffer migration %zu/%zu", success, tryNum);
    215         return true;
    216     }
    217 
    218     bool registerBuffer(const C2ConstGraphicBlock& block) {
    219         std::shared_ptr<_C2BlockPoolData> data =
    220                 _C2BlockFactory::GetGraphicBlockPoolData(block);
    221         if (!data) {
    222             return false;
    223         }
    224         std::scoped_lock<std::mutex> l(mMutex);
    225 
    226         if (!mIgbp) {
    227             return false;
    228         }
    229 
    230         uint32_t oldGeneration;
    231         uint64_t oldId;
    232         int32_t oldSlot;
    233         // If the block is not bufferqueue-based, do nothing.
    234         if (!_C2BlockFactory::GetBufferQueueData(
    235                 data, &oldGeneration, &oldId, &oldSlot) || (oldId == 0)) {
    236             return false;
    237         }
    238         // If the block's bqId is the same as the desired bqId, just hold.
    239         if ((oldId == mBqId) && (oldGeneration == mGeneration)) {
    240             LOG(VERBOSE) << "holdBufferQueueBlock -- import without attaching:"
    241                          << " bqId " << oldId
    242                          << ", bqSlot " << oldSlot
    243                          << ", generation " << mGeneration
    244                          << ".";
    245             _C2BlockFactory::HoldBlockFromBufferQueue(data, mOwner, getHgbp(mIgbp));
    246             mPoolDatas[oldSlot] = data;
    247             mBuffers[oldSlot] = createGraphicBuffer(block);
    248             mBuffers[oldSlot]->setGenerationNumber(mGeneration);
    249             return true;
    250         }
    251         int32_t d = (int32_t) mGeneration - (int32_t) oldGeneration;
    252         LOG(WARNING) << "receiving stale buffer: generation "
    253                      << mGeneration << " , diff " << d  << " : slot "
    254                      << oldSlot;
    255         return false;
    256     }
    257 
    258     status_t outputBuffer(
    259             const C2ConstGraphicBlock& block,
    260             const BnGraphicBufferProducer::QueueBufferInput& input,
    261             BnGraphicBufferProducer::QueueBufferOutput* output) {
    262         uint32_t generation;
    263         uint64_t bqId;
    264         int32_t bqSlot;
    265         bool display = displayBufferQueueBlock(block);
    266         if (!getBufferQueueAssignment(block, &generation, &bqId, &bqSlot) ||
    267             bqId == 0) {
    268             // Block not from bufferqueue -- it must be attached before queuing.
    269 
    270             mMutex.lock();
    271             sp<IGraphicBufferProducer> outputIgbp = mIgbp;
    272             uint32_t outputGeneration = mGeneration;
    273             mMutex.unlock();
    274 
    275             status_t status = attachToBufferQueue(
    276                     block, outputIgbp, outputGeneration, &bqSlot);
    277             if (status != OK) {
    278                 LOG(WARNING) << "outputBuffer -- attaching failed.";
    279                 return INVALID_OPERATION;
    280             }
    281 
    282             status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
    283                                          input, output);
    284             if (status != OK) {
    285                 LOG(ERROR) << "outputBuffer -- queueBuffer() failed "
    286                            "on non-bufferqueue-based block. "
    287                            "Error = " << status << ".";
    288                 return status;
    289             }
    290             return OK;
    291         }
    292 
    293         mMutex.lock();
    294         sp<IGraphicBufferProducer> outputIgbp = mIgbp;
    295         uint32_t outputGeneration = mGeneration;
    296         uint64_t outputBqId = mBqId;
    297         mMutex.unlock();
    298 
    299         if (!outputIgbp) {
    300             LOG(VERBOSE) << "outputBuffer -- output surface is null.";
    301             return NO_INIT;
    302         }
    303 
    304         if (!display) {
    305             LOG(WARNING) << "outputBuffer -- cannot display "
    306                          "bufferqueue-based block to the bufferqueue.";
    307             return UNKNOWN_ERROR;
    308         }
    309         if (bqId != outputBqId || generation != outputGeneration) {
    310             int32_t diff = (int32_t) outputGeneration - (int32_t) generation;
    311             LOG(WARNING) << "outputBuffer -- buffers from old generation to "
    312                          << outputGeneration << " , diff: " << diff
    313                          << " , slot: " << bqSlot;
    314             return DEAD_OBJECT;
    315         }
    316 
    317         status_t status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
    318                                               input, output);
    319         if (status != OK) {
    320             LOG(ERROR) << "outputBuffer -- queueBuffer() failed "
    321                        "on bufferqueue-based block. "
    322                        "Error = " << status << ".";
    323             return status;
    324         }
    325         return OK;
    326     }
    327 
    328     Impl *getPtr() {
    329         return this;
    330     }
    331 
    332     ~Impl() {}
    333 };
    334 
    335 OutputBufferQueue::OutputBufferQueue(): mImpl(new Impl()) {}
    336 
    337 OutputBufferQueue::~OutputBufferQueue() {}
    338 
    339 bool OutputBufferQueue::configure(const sp<IGraphicBufferProducer>& igbp,
    340                                   uint32_t generation,
    341                                   uint64_t bqId) {
    342     return mImpl && mImpl->configure(igbp, generation, bqId);
    343 }
    344 
    345 status_t OutputBufferQueue::outputBuffer(
    346     const C2ConstGraphicBlock& block,
    347     const BnGraphicBufferProducer::QueueBufferInput& input,
    348     BnGraphicBufferProducer::QueueBufferOutput* output) {
    349     if (mImpl) {
    350         return mImpl->outputBuffer(block, input, output);
    351     }
    352     return DEAD_OBJECT;
    353 }
    354 
    355 void OutputBufferQueue::holdBufferQueueBlocks(
    356         const std::list<std::unique_ptr<C2Work>>& workList) {
    357     if (!mImpl) {
    358         return;
    359     }
    360     forEachBlock(workList,
    361                  std::bind(&OutputBufferQueue::Impl::registerBuffer,
    362                            mImpl->getPtr(), std::placeholders::_1));
    363 }
    364 
    365 }  // namespace utils
    366 }  // namespace V1_0
    367 }  // namespace c2
    368 }  // namespace media
    369 }  // namespace hardware
    370 }  // namespace android
    371 
    372