Home | History | Annotate | Download | only in vndk
      1 /*
      2  * Copyright (C) 2016 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 "C2Buffer"
     19 #include <utils/Log.h>
     20 
     21 #include <list>
     22 #include <map>
     23 #include <mutex>
     24 
     25 #include <C2AllocatorIon.h>
     26 #include <C2AllocatorGralloc.h>
     27 #include <C2BufferPriv.h>
     28 #include <C2BlockInternal.h>
     29 #include <bufferpool/ClientManager.h>
     30 
     31 namespace {
     32 
     33 using android::C2AllocatorGralloc;
     34 using android::C2AllocatorIon;
     35 using android::hardware::media::bufferpool::BufferPoolData;
     36 using android::hardware::media::bufferpool::V1_0::ResultStatus;
     37 using android::hardware::media::bufferpool::V1_0::implementation::BufferPoolAllocation;
     38 using android::hardware::media::bufferpool::V1_0::implementation::BufferPoolAllocator;
     39 using android::hardware::media::bufferpool::V1_0::implementation::ClientManager;
     40 using android::hardware::media::bufferpool::V1_0::implementation::ConnectionId;
     41 using android::hardware::media::bufferpool::V1_0::implementation::INVALID_CONNECTIONID;
     42 
     43 // This anonymous namespace contains the helper classes that allow our implementation to create
     44 // block/buffer objects.
     45 //
     46 // Inherit from the parent, share with the friend.
     47 class ReadViewBuddy : public C2ReadView {
     48     using C2ReadView::C2ReadView;
     49     friend class ::C2ConstLinearBlock;
     50 };
     51 
     52 class WriteViewBuddy : public C2WriteView {
     53     using C2WriteView::C2WriteView;
     54     friend class ::C2LinearBlock;
     55 };
     56 
     57 class ConstLinearBlockBuddy : public C2ConstLinearBlock {
     58     using C2ConstLinearBlock::C2ConstLinearBlock;
     59     friend class ::C2LinearBlock;
     60 };
     61 
     62 class LinearBlockBuddy : public C2LinearBlock {
     63     using C2LinearBlock::C2LinearBlock;
     64     friend class ::C2BasicLinearBlockPool;
     65 };
     66 
     67 class AcquirableReadViewBuddy : public C2Acquirable<C2ReadView> {
     68     using C2Acquirable::C2Acquirable;
     69     friend class ::C2ConstLinearBlock;
     70 };
     71 
     72 class AcquirableWriteViewBuddy : public C2Acquirable<C2WriteView> {
     73     using C2Acquirable::C2Acquirable;
     74     friend class ::C2LinearBlock;
     75 };
     76 
     77 class GraphicViewBuddy : public C2GraphicView {
     78     using C2GraphicView::C2GraphicView;
     79     friend class ::C2ConstGraphicBlock;
     80     friend class ::C2GraphicBlock;
     81 };
     82 
     83 class AcquirableConstGraphicViewBuddy : public C2Acquirable<const C2GraphicView> {
     84     using C2Acquirable::C2Acquirable;
     85     friend class ::C2ConstGraphicBlock;
     86 };
     87 
     88 class AcquirableGraphicViewBuddy : public C2Acquirable<C2GraphicView> {
     89     using C2Acquirable::C2Acquirable;
     90     friend class ::C2GraphicBlock;
     91 };
     92 
     93 class ConstGraphicBlockBuddy : public C2ConstGraphicBlock {
     94     using C2ConstGraphicBlock::C2ConstGraphicBlock;
     95     friend class ::C2GraphicBlock;
     96 };
     97 
     98 class GraphicBlockBuddy : public C2GraphicBlock {
     99     using C2GraphicBlock::C2GraphicBlock;
    100     friend class ::C2BasicGraphicBlockPool;
    101 };
    102 
    103 class BufferDataBuddy : public C2BufferData {
    104     using C2BufferData::C2BufferData;
    105     friend class ::C2Buffer;
    106 };
    107 
    108 }  // namespace
    109 
    110 /* ========================================== 1D BLOCK ========================================= */
    111 
    112 /**
    113  * This class is the base class for all 1D block and view implementations.
    114  *
    115  * This is basically just a placeholder for the underlying 1D allocation and the range of the
    116  * alloted portion to this block. There is also a placeholder for a blockpool data.
    117  */
    118 class C2_HIDE _C2Block1DImpl : public _C2LinearRangeAspect {
    119 public:
    120     _C2Block1DImpl(const std::shared_ptr<C2LinearAllocation> &alloc,
    121             const std::shared_ptr<_C2BlockPoolData> &poolData = nullptr,
    122             size_t offset = 0, size_t size = ~(size_t)0)
    123         : _C2LinearRangeAspect(alloc.get(), offset, size),
    124           mAllocation(alloc),
    125           mPoolData(poolData) { }
    126 
    127     _C2Block1DImpl(const _C2Block1DImpl &other, size_t offset = 0, size_t size = ~(size_t)0)
    128         : _C2LinearRangeAspect(&other, offset, size),
    129           mAllocation(other.mAllocation),
    130           mPoolData(other.mPoolData) { }
    131 
    132     /** returns pool data  */
    133     std::shared_ptr<_C2BlockPoolData> poolData() const {
    134         return mPoolData;
    135     }
    136 
    137     /** returns native handle */
    138     const C2Handle *handle() const {
    139         return mAllocation ? mAllocation->handle() : nullptr;
    140     }
    141 
    142     /** returns the allocator's ID */
    143     C2Allocator::id_t getAllocatorId() const {
    144         // BAD_ID can only happen if this Impl class is initialized for a view - never for a block.
    145         return mAllocation ? mAllocation->getAllocatorId() : C2Allocator::BAD_ID;
    146     }
    147 
    148     std::shared_ptr<C2LinearAllocation> getAllocation() const {
    149         return mAllocation;
    150     }
    151 
    152 private:
    153     std::shared_ptr<C2LinearAllocation> mAllocation;
    154     std::shared_ptr<_C2BlockPoolData> mPoolData;
    155 };
    156 
    157 /**
    158  * This class contains the mapped data pointer, and the potential error.
    159  *
    160  * range is the mapped range of the underlying allocation (which is part of the allotted
    161  * range).
    162  */
    163 class C2_HIDE _C2MappedBlock1DImpl : public _C2Block1DImpl {
    164 public:
    165     _C2MappedBlock1DImpl(const _C2Block1DImpl &block, uint8_t *data,
    166                          size_t offset = 0, size_t size = ~(size_t)0)
    167         : _C2Block1DImpl(block, offset, size), mData(data), mError(C2_OK) { }
    168 
    169     _C2MappedBlock1DImpl(c2_status_t error)
    170         : _C2Block1DImpl(nullptr), mData(nullptr), mError(error) {
    171         // CHECK(error != C2_OK);
    172     }
    173 
    174     const uint8_t *data() const {
    175         return mData;
    176     }
    177 
    178     uint8_t *data() {
    179         return mData;
    180     }
    181 
    182     c2_status_t error() const {
    183         return mError;
    184     }
    185 
    186 private:
    187     uint8_t *mData;
    188     c2_status_t mError;
    189 };
    190 
    191 /**
    192  * Block implementation.
    193  */
    194 class C2Block1D::Impl : public _C2Block1DImpl {
    195     using _C2Block1DImpl::_C2Block1DImpl;
    196 };
    197 
    198 const C2Handle *C2Block1D::handle() const {
    199     return mImpl->handle();
    200 };
    201 
    202 C2Allocator::id_t C2Block1D::getAllocatorId() const {
    203     return mImpl->getAllocatorId();
    204 };
    205 
    206 C2Block1D::C2Block1D(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range)
    207     // always clamp subrange to parent (impl) range for safety
    208     : _C2LinearRangeAspect(impl.get(), range.offset(), range.size()), mImpl(impl) {
    209 }
    210 
    211 /**
    212  * Read view implementation.
    213  *
    214  * range of Impl is the mapped range of the underlying allocation (which is part of the allotted
    215  * range). range of View is 0 to capacity() (not represented as an actual range). This maps to a
    216  * subrange of Impl range starting at mImpl->offset() + _mOffset.
    217  */
    218 class C2ReadView::Impl : public _C2MappedBlock1DImpl {
    219     using _C2MappedBlock1DImpl::_C2MappedBlock1DImpl;
    220 };
    221 
    222 C2ReadView::C2ReadView(std::shared_ptr<Impl> impl, uint32_t offset, uint32_t size)
    223     : _C2LinearCapacityAspect(C2LinearCapacity(impl->size()).range(offset, size).size()),
    224       mImpl(impl),
    225       mOffset(C2LinearCapacity(impl->size()).range(offset, size).offset()) { }
    226 
    227 C2ReadView::C2ReadView(c2_status_t error)
    228     : _C2LinearCapacityAspect(0u), mImpl(std::make_shared<Impl>(error)), mOffset(0u) {
    229     // CHECK(error != C2_OK);
    230 }
    231 
    232 const uint8_t *C2ReadView::data() const {
    233     return mImpl->error() ? nullptr : mImpl->data() + mOffset;
    234 }
    235 
    236 c2_status_t C2ReadView::error() const {
    237     return mImpl->error();
    238 }
    239 
    240 C2ReadView C2ReadView::subView(size_t offset, size_t size) const {
    241     C2LinearRange subRange(*this, offset, size);
    242     return C2ReadView(mImpl, mOffset + subRange.offset(), subRange.size());
    243 }
    244 
    245 /**
    246  * Write view implementation.
    247  */
    248 class C2WriteView::Impl : public _C2MappedBlock1DImpl {
    249     using _C2MappedBlock1DImpl::_C2MappedBlock1DImpl;
    250 };
    251 
    252 C2WriteView::C2WriteView(std::shared_ptr<Impl> impl)
    253 // UGLY: _C2LinearRangeAspect requires a bona-fide object for capacity to prevent spoofing, so
    254 // this is what we have to do.
    255 // TODO: use childRange
    256     : _C2EditableLinearRangeAspect(std::make_unique<C2LinearCapacity>(impl->size()).get()), mImpl(impl) { }
    257 
    258 C2WriteView::C2WriteView(c2_status_t error)
    259     : _C2EditableLinearRangeAspect(nullptr), mImpl(std::make_shared<Impl>(error)) {}
    260 
    261 uint8_t *C2WriteView::base() { return mImpl->data(); }
    262 
    263 uint8_t *C2WriteView::data() { return mImpl->data() + offset(); }
    264 
    265 c2_status_t C2WriteView::error() const { return mImpl->error(); }
    266 
    267 /**
    268  * Const linear block implementation.
    269  */
    270 C2ConstLinearBlock::C2ConstLinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range, C2Fence fence)
    271     : C2Block1D(impl, range), mFence(fence) { }
    272 
    273 C2Acquirable<C2ReadView> C2ConstLinearBlock::map() const {
    274     void *base = nullptr;
    275     uint32_t len = size();
    276     c2_status_t error = mImpl->getAllocation()->map(
    277             offset(), len, { C2MemoryUsage::CPU_READ, 0 }, nullptr, &base);
    278     // TODO: wait on fence
    279     if (error == C2_OK) {
    280         std::shared_ptr<ReadViewBuddy::Impl> rvi = std::shared_ptr<ReadViewBuddy::Impl>(
    281                 new ReadViewBuddy::Impl(*mImpl, (uint8_t *)base, offset(), len),
    282                 [base, len](ReadViewBuddy::Impl *i) {
    283                     (void)i->getAllocation()->unmap(base, len, nullptr);
    284                     delete i;
    285         });
    286         return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(rvi, 0, len));
    287     } else {
    288         return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(error));
    289     }
    290 }
    291 
    292 C2ConstLinearBlock C2ConstLinearBlock::subBlock(size_t offset_, size_t size_) const {
    293     C2LinearRange subRange(*mImpl, offset_, size_);
    294     return C2ConstLinearBlock(mImpl, subRange, mFence);
    295 }
    296 
    297 /**
    298  * Linear block implementation.
    299  */
    300 C2LinearBlock::C2LinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range)
    301     : C2Block1D(impl, range) { }
    302 
    303 C2Acquirable<C2WriteView> C2LinearBlock::map() {
    304     void *base = nullptr;
    305     uint32_t len = size();
    306     c2_status_t error = mImpl->getAllocation()->map(
    307             offset(), len, { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, nullptr, &base);
    308     // TODO: wait on fence
    309     if (error == C2_OK) {
    310         std::shared_ptr<WriteViewBuddy::Impl> rvi = std::shared_ptr<WriteViewBuddy::Impl>(
    311                 new WriteViewBuddy::Impl(*mImpl, (uint8_t *)base, 0, len),
    312                 [base, len](WriteViewBuddy::Impl *i) {
    313                     (void)i->getAllocation()->unmap(base, len, nullptr);
    314                     delete i;
    315         });
    316         return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(rvi));
    317     } else {
    318         return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(error));
    319     }
    320 }
    321 
    322 C2ConstLinearBlock C2LinearBlock::share(size_t offset_, size_t size_, C2Fence fence) {
    323     return ConstLinearBlockBuddy(mImpl, C2LinearRange(*this, offset_, size_), fence);
    324 }
    325 
    326 C2BasicLinearBlockPool::C2BasicLinearBlockPool(
    327         const std::shared_ptr<C2Allocator> &allocator)
    328   : mAllocator(allocator) { }
    329 
    330 c2_status_t C2BasicLinearBlockPool::fetchLinearBlock(
    331         uint32_t capacity,
    332         C2MemoryUsage usage,
    333         std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
    334     block->reset();
    335 
    336     std::shared_ptr<C2LinearAllocation> alloc;
    337     c2_status_t err = mAllocator->newLinearAllocation(capacity, usage, &alloc);
    338     if (err != C2_OK) {
    339         return err;
    340     }
    341 
    342     *block = _C2BlockFactory::CreateLinearBlock(alloc);
    343 
    344     return C2_OK;
    345 }
    346 
    347 struct C2_HIDE C2PooledBlockPoolData : _C2BlockPoolData {
    348 
    349     virtual type_t getType() const override {
    350         return TYPE_BUFFERPOOL;
    351     }
    352 
    353     void getBufferPoolData(std::shared_ptr<BufferPoolData> *data) const {
    354         *data = mData;
    355     }
    356 
    357     C2PooledBlockPoolData(const std::shared_ptr<BufferPoolData> &data) : mData(data) {}
    358 
    359     virtual ~C2PooledBlockPoolData() override {}
    360 
    361 private:
    362     std::shared_ptr<BufferPoolData> mData;
    363 };
    364 
    365 bool _C2BlockFactory::GetBufferPoolData(
    366         const std::shared_ptr<const _C2BlockPoolData> &data,
    367         std::shared_ptr<BufferPoolData> *bufferPoolData) {
    368     if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERPOOL) {
    369         const std::shared_ptr<const C2PooledBlockPoolData> poolData =
    370                 std::static_pointer_cast<const C2PooledBlockPoolData>(data);
    371         poolData->getBufferPoolData(bufferPoolData);
    372         return true;
    373     }
    374     return false;
    375 }
    376 
    377 std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
    378         const std::shared_ptr<C2LinearAllocation> &alloc,
    379         const std::shared_ptr<_C2BlockPoolData> &data, size_t offset, size_t size) {
    380     std::shared_ptr<C2Block1D::Impl> impl =
    381         std::make_shared<C2Block1D::Impl>(alloc, data, offset, size);
    382     return std::shared_ptr<C2LinearBlock>(new C2LinearBlock(impl, *impl));
    383 }
    384 
    385 std::shared_ptr<_C2BlockPoolData> _C2BlockFactory::GetLinearBlockPoolData(
    386         const C2Block1D &block) {
    387     if (block.mImpl) {
    388         return block.mImpl->poolData();
    389     }
    390     return nullptr;
    391 }
    392 
    393 std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
    394         const C2Handle *handle) {
    395     // TODO: get proper allocator? and mutex?
    396     static std::unique_ptr<C2AllocatorIon> sAllocator = std::make_unique<C2AllocatorIon>(0);
    397 
    398     std::shared_ptr<C2LinearAllocation> alloc;
    399     if (C2AllocatorIon::isValid(handle)) {
    400         c2_status_t err = sAllocator->priorLinearAllocation(handle, &alloc);
    401         if (err == C2_OK) {
    402             std::shared_ptr<C2LinearBlock> block = _C2BlockFactory::CreateLinearBlock(alloc);
    403             return block;
    404         }
    405     }
    406     return nullptr;
    407 }
    408 
    409 std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
    410         const C2Handle *cHandle, const std::shared_ptr<BufferPoolData> &data) {
    411     // TODO: get proper allocator? and mutex?
    412     static std::unique_ptr<C2AllocatorIon> sAllocator = std::make_unique<C2AllocatorIon>(0);
    413 
    414     std::shared_ptr<C2LinearAllocation> alloc;
    415     if (C2AllocatorIon::isValid(cHandle)) {
    416         native_handle_t *handle = native_handle_clone(cHandle);
    417         if (handle) {
    418             c2_status_t err = sAllocator->priorLinearAllocation(handle, &alloc);
    419             const std::shared_ptr<C2PooledBlockPoolData> poolData =
    420                     std::make_shared<C2PooledBlockPoolData>(data);
    421             if (err == C2_OK && poolData) {
    422                 // TODO: config params?
    423                 std::shared_ptr<C2LinearBlock> block =
    424                         _C2BlockFactory::CreateLinearBlock(alloc, poolData);
    425                 return block;
    426             }
    427         }
    428     }
    429     return nullptr;
    430 };
    431 
    432 /**
    433  * Wrapped C2Allocator which is injected to buffer pool on behalf of
    434  * C2BlockPool.
    435  */
    436 class _C2BufferPoolAllocator : public BufferPoolAllocator {
    437 public:
    438     _C2BufferPoolAllocator(const std::shared_ptr<C2Allocator> &allocator)
    439         : mAllocator(allocator) {}
    440 
    441     ~_C2BufferPoolAllocator() override {}
    442 
    443     ResultStatus allocate(const std::vector<uint8_t> &params,
    444                           std::shared_ptr<BufferPoolAllocation> *alloc,
    445                           size_t *allocSize) override;
    446 
    447     bool compatible(const std::vector<uint8_t> &newParams,
    448                     const std::vector<uint8_t> &oldParams) override;
    449 
    450     // Methods for codec2 component (C2BlockPool).
    451     /**
    452      * Transforms linear allocation parameters for C2Allocator to parameters
    453      * for buffer pool.
    454      *
    455      * @param capacity      size of linear allocation
    456      * @param usage         memory usage pattern for linear allocation
    457      * @param params        allocation parameters for buffer pool
    458      */
    459     void getLinearParams(uint32_t capacity, C2MemoryUsage usage,
    460                          std::vector<uint8_t> *params);
    461 
    462     /**
    463      * Transforms graphic allocation parameters for C2Allocator to parameters
    464      * for buffer pool.
    465      *
    466      * @param width         width of graphic allocation
    467      * @param height        height of graphic allocation
    468      * @param format        color format of graphic allocation
    469      * @param params        allocation parameter for buffer pool
    470      */
    471     void getGraphicParams(uint32_t width, uint32_t height,
    472                           uint32_t format, C2MemoryUsage usage,
    473                           std::vector<uint8_t> *params);
    474 
    475     /**
    476      * Transforms an existing native handle to an C2LinearAllcation.
    477      * Wrapper to C2Allocator#priorLinearAllocation
    478      */
    479     c2_status_t priorLinearAllocation(
    480             const C2Handle *handle,
    481             std::shared_ptr<C2LinearAllocation> *c2Allocation);
    482 
    483     /**
    484      * Transforms an existing native handle to an C2GraphicAllcation.
    485      * Wrapper to C2Allocator#priorGraphicAllocation
    486      */
    487     c2_status_t priorGraphicAllocation(
    488             const C2Handle *handle,
    489             std::shared_ptr<C2GraphicAllocation> *c2Allocation);
    490 
    491 private:
    492     static constexpr int kMaxIntParams = 5; // large enough number;
    493 
    494     enum AllocType : uint8_t {
    495         ALLOC_NONE = 0,
    496 
    497         ALLOC_LINEAR,
    498         ALLOC_GRAPHIC,
    499     };
    500 
    501     union AllocParams {
    502         struct {
    503             AllocType allocType;
    504             C2MemoryUsage usage;
    505             uint32_t params[kMaxIntParams];
    506         } data;
    507         uint8_t array[0];
    508 
    509         AllocParams() : data{ALLOC_NONE, {0, 0}, {0}} {}
    510         AllocParams(C2MemoryUsage usage, uint32_t capacity)
    511             : data{ALLOC_LINEAR, usage, {[0] = capacity}} {}
    512         AllocParams(
    513                 C2MemoryUsage usage,
    514                 uint32_t width, uint32_t height, uint32_t format)
    515                 : data{ALLOC_GRAPHIC, usage, {width, height, format}} {}
    516     };
    517 
    518     const std::shared_ptr<C2Allocator> mAllocator;
    519 };
    520 
    521 struct LinearAllocationDtor {
    522     LinearAllocationDtor(const std::shared_ptr<C2LinearAllocation> &alloc)
    523         : mAllocation(alloc) {}
    524 
    525     void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
    526 
    527     const std::shared_ptr<C2LinearAllocation> mAllocation;
    528 };
    529 
    530 struct GraphicAllocationDtor {
    531     GraphicAllocationDtor(const std::shared_ptr<C2GraphicAllocation> &alloc)
    532         : mAllocation(alloc) {}
    533 
    534     void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
    535 
    536     const std::shared_ptr<C2GraphicAllocation> mAllocation;
    537 };
    538 
    539 ResultStatus _C2BufferPoolAllocator::allocate(
    540         const std::vector<uint8_t>  &params,
    541         std::shared_ptr<BufferPoolAllocation> *alloc,
    542         size_t *allocSize) {
    543     AllocParams c2Params;
    544     memcpy(&c2Params, params.data(), std::min(sizeof(AllocParams), params.size()));
    545     c2_status_t status = C2_BAD_VALUE;
    546     switch(c2Params.data.allocType) {
    547         case ALLOC_NONE:
    548             break;
    549         case ALLOC_LINEAR: {
    550             std::shared_ptr<C2LinearAllocation> c2Linear;
    551             status = mAllocator->newLinearAllocation(
    552                     c2Params.data.params[0], c2Params.data.usage, &c2Linear);
    553             if (status == C2_OK && c2Linear) {
    554                 BufferPoolAllocation *ptr = new BufferPoolAllocation(c2Linear->handle());
    555                 if (ptr) {
    556                     *alloc = std::shared_ptr<BufferPoolAllocation>(
    557                             ptr, LinearAllocationDtor(c2Linear));
    558                     if (*alloc) {
    559                         *allocSize = (size_t)c2Params.data.params[0];
    560                         return ResultStatus::OK;
    561                     }
    562                     delete ptr;
    563                 }
    564                 return ResultStatus::NO_MEMORY;
    565             }
    566             break;
    567         }
    568         case ALLOC_GRAPHIC: {
    569             std::shared_ptr<C2GraphicAllocation> c2Graphic;
    570             status = mAllocator->newGraphicAllocation(
    571                     c2Params.data.params[0],
    572                     c2Params.data.params[1],
    573                     c2Params.data.params[2],
    574                     c2Params.data.usage, &c2Graphic);
    575             if (status == C2_OK && c2Graphic) {
    576                 BufferPoolAllocation *ptr = new BufferPoolAllocation(c2Graphic->handle());
    577                 if (ptr) {
    578                     *alloc = std::shared_ptr<BufferPoolAllocation>(
    579                             ptr, GraphicAllocationDtor(c2Graphic));
    580                     if (*alloc) {
    581                         *allocSize = c2Params.data.params[0] * c2Params.data.params[1];
    582                         return ResultStatus::OK;
    583                     }
    584                     delete ptr;
    585                 }
    586                 return ResultStatus::NO_MEMORY;
    587             }
    588             break;
    589         }
    590         default:
    591             break;
    592     }
    593     return ResultStatus::CRITICAL_ERROR;
    594 }
    595 
    596 bool _C2BufferPoolAllocator::compatible(
    597         const std::vector<uint8_t>  &newParams,
    598         const std::vector<uint8_t>  &oldParams) {
    599     AllocParams newAlloc;
    600     AllocParams oldAlloc;
    601     memcpy(&newAlloc, newParams.data(), std::min(sizeof(AllocParams), newParams.size()));
    602     memcpy(&oldAlloc, oldParams.data(), std::min(sizeof(AllocParams), oldParams.size()));
    603 
    604     // TODO: support not exact matching. e.g) newCapacity < oldCapacity
    605     if (newAlloc.data.allocType == oldAlloc.data.allocType &&
    606             newAlloc.data.usage.expected == oldAlloc.data.usage.expected) {
    607         for (int i = 0; i < kMaxIntParams; ++i) {
    608             if (newAlloc.data.params[i] != oldAlloc.data.params[i]) {
    609                 return false;
    610             }
    611         }
    612         return true;
    613     }
    614     return false;
    615 }
    616 
    617 void _C2BufferPoolAllocator::getLinearParams(
    618         uint32_t capacity, C2MemoryUsage usage, std::vector<uint8_t> *params) {
    619     AllocParams c2Params(usage, capacity);
    620     params->assign(c2Params.array, c2Params.array + sizeof(AllocParams));
    621 }
    622 
    623 void _C2BufferPoolAllocator::getGraphicParams(
    624         uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
    625         std::vector<uint8_t> *params) {
    626     AllocParams c2Params(usage, width, height, format);
    627     params->assign(c2Params.array, c2Params.array + sizeof(AllocParams));
    628 }
    629 
    630 c2_status_t _C2BufferPoolAllocator::priorLinearAllocation(
    631         const C2Handle *handle,
    632         std::shared_ptr<C2LinearAllocation> *c2Allocation) {
    633     return mAllocator->priorLinearAllocation(handle, c2Allocation);
    634 }
    635 
    636 c2_status_t _C2BufferPoolAllocator::priorGraphicAllocation(
    637         const C2Handle *handle,
    638         std::shared_ptr<C2GraphicAllocation> *c2Allocation) {
    639     return mAllocator->priorGraphicAllocation(handle, c2Allocation);
    640 }
    641 
    642 class C2PooledBlockPool::Impl {
    643 public:
    644     Impl(const std::shared_ptr<C2Allocator> &allocator)
    645             : mInit(C2_OK),
    646               mBufferPoolManager(ClientManager::getInstance()),
    647               mAllocator(std::make_shared<_C2BufferPoolAllocator>(allocator)) {
    648         if (mAllocator && mBufferPoolManager) {
    649             if (mBufferPoolManager->create(
    650                     mAllocator, &mConnectionId) == ResultStatus::OK) {
    651                 return;
    652             }
    653         }
    654         mInit = C2_NO_INIT;
    655     }
    656 
    657     ~Impl() {
    658         if (mInit == C2_OK) {
    659             mBufferPoolManager->close(mConnectionId);
    660         }
    661     }
    662 
    663     c2_status_t fetchLinearBlock(
    664             uint32_t capacity, C2MemoryUsage usage,
    665             std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
    666         block->reset();
    667         if (mInit != C2_OK) {
    668             return mInit;
    669         }
    670         std::vector<uint8_t> params;
    671         mAllocator->getLinearParams(capacity, usage, &params);
    672         std::shared_ptr<BufferPoolData> bufferPoolData;
    673         native_handle_t *cHandle = nullptr;
    674         ResultStatus status = mBufferPoolManager->allocate(
    675                 mConnectionId, params, &cHandle, &bufferPoolData);
    676         if (status == ResultStatus::OK) {
    677             native_handle_t *handle = native_handle_clone(cHandle);
    678             if (handle) {
    679                 std::shared_ptr<C2LinearAllocation> alloc;
    680                 std::shared_ptr<C2PooledBlockPoolData> poolData =
    681                         std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
    682                 c2_status_t err = mAllocator->priorLinearAllocation(handle, &alloc);
    683                 if (err == C2_OK && poolData && alloc) {
    684                     *block = _C2BlockFactory::CreateLinearBlock(alloc, poolData, 0, capacity);
    685                     if (*block) {
    686                         return C2_OK;
    687                     }
    688                 }
    689             }
    690             return C2_NO_MEMORY;
    691         }
    692         if (status == ResultStatus::NO_MEMORY) {
    693             return C2_NO_MEMORY;
    694         }
    695         return C2_CORRUPTED;
    696     }
    697 
    698     c2_status_t fetchGraphicBlock(
    699             uint32_t width, uint32_t height, uint32_t format,
    700             C2MemoryUsage usage,
    701             std::shared_ptr<C2GraphicBlock> *block) {
    702         block->reset();
    703         if (mInit != C2_OK) {
    704             return mInit;
    705         }
    706         std::vector<uint8_t> params;
    707         mAllocator->getGraphicParams(width, height, format, usage, &params);
    708         std::shared_ptr<BufferPoolData> bufferPoolData;
    709         native_handle_t *cHandle = nullptr;
    710         ResultStatus status = mBufferPoolManager->allocate(
    711                 mConnectionId, params, &cHandle, &bufferPoolData);
    712         if (status == ResultStatus::OK) {
    713             native_handle_t *handle = native_handle_clone(cHandle);
    714             if (handle) {
    715                 std::shared_ptr<C2GraphicAllocation> alloc;
    716                 std::shared_ptr<C2PooledBlockPoolData> poolData =
    717                     std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
    718                 c2_status_t err = mAllocator->priorGraphicAllocation(
    719                         handle, &alloc);
    720                 if (err == C2_OK && poolData && alloc) {
    721                     *block = _C2BlockFactory::CreateGraphicBlock(
    722                             alloc, poolData, C2Rect(width, height));
    723                     if (*block) {
    724                         return C2_OK;
    725                     }
    726                 }
    727             }
    728             return C2_NO_MEMORY;
    729         }
    730         if (status == ResultStatus::NO_MEMORY) {
    731             return C2_NO_MEMORY;
    732         }
    733         return C2_CORRUPTED;
    734     }
    735 
    736     ConnectionId getConnectionId() {
    737         return mInit != C2_OK ? INVALID_CONNECTIONID : mConnectionId;
    738     }
    739 
    740 private:
    741     c2_status_t mInit;
    742     const android::sp<ClientManager> mBufferPoolManager;
    743     ConnectionId mConnectionId; // locally
    744     const std::shared_ptr<_C2BufferPoolAllocator> mAllocator;
    745 };
    746 
    747 C2PooledBlockPool::C2PooledBlockPool(
    748         const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId)
    749         : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {}
    750 
    751 C2PooledBlockPool::~C2PooledBlockPool() {
    752 }
    753 
    754 c2_status_t C2PooledBlockPool::fetchLinearBlock(
    755         uint32_t capacity,
    756         C2MemoryUsage usage,
    757         std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
    758     if (mImpl) {
    759         return mImpl->fetchLinearBlock(capacity, usage, block);
    760     }
    761     return C2_CORRUPTED;
    762 }
    763 
    764 c2_status_t C2PooledBlockPool::fetchGraphicBlock(
    765         uint32_t width,
    766         uint32_t height,
    767         uint32_t format,
    768         C2MemoryUsage usage,
    769         std::shared_ptr<C2GraphicBlock> *block) {
    770     if (mImpl) {
    771         return mImpl->fetchGraphicBlock(width, height, format, usage, block);
    772     }
    773     return C2_CORRUPTED;
    774 }
    775 
    776 int64_t C2PooledBlockPool::getConnectionId() {
    777     if (mImpl) {
    778         return mImpl->getConnectionId();
    779     }
    780     return 0;
    781 }
    782 
    783 /* ========================================== 2D BLOCK ========================================= */
    784 
    785 /**
    786  * Implementation that is shared between all 2D blocks and views.
    787  *
    788  * For blocks' Impl's crop is always the allotted crop, even if it is a sub block.
    789  *
    790  * For views' Impl's crop is the mapped portion - which for now is always the
    791  * allotted crop.
    792  */
    793 class C2_HIDE _C2Block2DImpl : public _C2PlanarSectionAspect {
    794 public:
    795     /**
    796      * Impl's crop is always the or part of the allotted crop of the allocation.
    797      */
    798     _C2Block2DImpl(const std::shared_ptr<C2GraphicAllocation> &alloc,
    799             const std::shared_ptr<_C2BlockPoolData> &poolData = nullptr,
    800             const C2Rect &allottedCrop = C2Rect(~0u, ~0u))
    801         : _C2PlanarSectionAspect(alloc.get(), allottedCrop),
    802           mAllocation(alloc),
    803           mPoolData(poolData) { }
    804 
    805     virtual ~_C2Block2DImpl() = default;
    806 
    807     /** returns pool data  */
    808     std::shared_ptr<_C2BlockPoolData> poolData() const {
    809         return mPoolData;
    810     }
    811 
    812     /** returns native handle */
    813     const C2Handle *handle() const {
    814         return mAllocation ? mAllocation->handle() : nullptr;
    815     }
    816 
    817     /** returns the allocator's ID */
    818     C2Allocator::id_t getAllocatorId() const {
    819         // BAD_ID can only happen if this Impl class is initialized for a view - never for a block.
    820         return mAllocation ? mAllocation->getAllocatorId() : C2Allocator::BAD_ID;
    821     }
    822 
    823     std::shared_ptr<C2GraphicAllocation> getAllocation() const {
    824         return mAllocation;
    825     }
    826 
    827 private:
    828     std::shared_ptr<C2GraphicAllocation> mAllocation;
    829     std::shared_ptr<_C2BlockPoolData> mPoolData;
    830 };
    831 
    832 class C2_HIDE _C2MappingBlock2DImpl
    833     : public _C2Block2DImpl, public std::enable_shared_from_this<_C2MappingBlock2DImpl> {
    834 public:
    835     using _C2Block2DImpl::_C2Block2DImpl;
    836 
    837     virtual ~_C2MappingBlock2DImpl() override = default;
    838 
    839     /**
    840      * This class contains the mapped data pointer, and the potential error.
    841      */
    842     struct Mapped {
    843     private:
    844         friend class _C2MappingBlock2DImpl;
    845 
    846         Mapped(const std::shared_ptr<_C2Block2DImpl> &impl, bool writable, C2Fence *fence __unused)
    847             : mImpl(impl), mWritable(writable) {
    848             memset(mData, 0, sizeof(mData));
    849             const C2Rect crop = mImpl->crop();
    850             // gralloc requires mapping the whole region of interest as we cannot
    851             // map multiple regions
    852             mError = mImpl->getAllocation()->map(
    853                     crop,
    854                     { C2MemoryUsage::CPU_READ, writable ? C2MemoryUsage::CPU_WRITE : 0 },
    855                     nullptr,
    856                     &mLayout,
    857                     mData);
    858             if (mError != C2_OK) {
    859                 memset(&mLayout, 0, sizeof(mLayout));
    860                 memset(mData, 0, sizeof(mData));
    861                 memset(mOffsetData, 0, sizeof(mData));
    862             } else {
    863                 // TODO: validate plane layout and
    864                 // adjust data pointers to the crop region's top left corner.
    865                 // fail if it is not on a subsampling boundary
    866                 for (size_t planeIx = 0; planeIx < mLayout.numPlanes; ++planeIx) {
    867                     const uint32_t colSampling = mLayout.planes[planeIx].colSampling;
    868                     const uint32_t rowSampling = mLayout.planes[planeIx].rowSampling;
    869                     if (crop.left % colSampling || crop.right() % colSampling
    870                             || crop.top % rowSampling || crop.bottom() % rowSampling) {
    871                         // cannot calculate data pointer
    872                         mImpl->getAllocation()->unmap(mData, crop, nullptr);
    873                         memset(&mLayout, 0, sizeof(mLayout));
    874                         memset(mData, 0, sizeof(mData));
    875                         memset(mOffsetData, 0, sizeof(mData));
    876                         mError = C2_BAD_VALUE;
    877                         return;
    878                     }
    879                     mOffsetData[planeIx] =
    880                         mData[planeIx] + (ssize_t)crop.left * mLayout.planes[planeIx].colInc
    881                                 + (ssize_t)crop.top * mLayout.planes[planeIx].rowInc;
    882                 }
    883             }
    884         }
    885 
    886         explicit Mapped(c2_status_t error)
    887             : mImpl(nullptr), mWritable(false), mError(error) {
    888             // CHECK(error != C2_OK);
    889             memset(&mLayout, 0, sizeof(mLayout));
    890             memset(mData, 0, sizeof(mData));
    891             memset(mOffsetData, 0, sizeof(mData));
    892         }
    893 
    894     public:
    895         ~Mapped() {
    896             if (mData[0] != nullptr) {
    897                 mImpl->getAllocation()->unmap(mData, mImpl->crop(), nullptr);
    898             }
    899         }
    900 
    901         /** returns mapping status */
    902         c2_status_t error() const { return mError; }
    903 
    904         /** returns data pointer */
    905         uint8_t *const *data() const { return mOffsetData; }
    906 
    907         /** returns the plane layout */
    908         C2PlanarLayout layout() const { return mLayout; }
    909 
    910         /** returns whether the mapping is writable */
    911         bool writable() const { return mWritable; }
    912 
    913     private:
    914         const std::shared_ptr<_C2Block2DImpl> mImpl;
    915         bool mWritable;
    916         c2_status_t mError;
    917         uint8_t *mData[C2PlanarLayout::MAX_NUM_PLANES];
    918         uint8_t *mOffsetData[C2PlanarLayout::MAX_NUM_PLANES];
    919         C2PlanarLayout mLayout;
    920     };
    921 
    922     /**
    923      * Maps the allotted region.
    924      *
    925      * If already mapped and it is currently in use, returns the existing mapping.
    926      * If fence is provided, an acquire fence is stored there.
    927      */
    928     std::shared_ptr<Mapped> map(bool writable, C2Fence *fence) {
    929         std::lock_guard<std::mutex> lock(mMappedLock);
    930         std::shared_ptr<Mapped> existing = mMapped.lock();
    931         if (!existing) {
    932             existing = std::shared_ptr<Mapped>(new Mapped(shared_from_this(), writable, fence));
    933             mMapped = existing;
    934         } else {
    935             // if we mapped the region read-only, we cannot remap it read-write
    936             if (writable && !existing->writable()) {
    937                 existing = std::shared_ptr<Mapped>(new Mapped(C2_CANNOT_DO));
    938             }
    939             if (fence != nullptr) {
    940                 *fence = C2Fence();
    941             }
    942         }
    943         return existing;
    944     }
    945 
    946 private:
    947     std::weak_ptr<Mapped> mMapped;
    948     std::mutex mMappedLock;
    949 };
    950 
    951 class C2_HIDE _C2MappedBlock2DImpl : public _C2Block2DImpl {
    952 public:
    953     _C2MappedBlock2DImpl(const _C2Block2DImpl &impl,
    954                          std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping)
    955         : _C2Block2DImpl(impl), mMapping(mapping) {
    956     }
    957 
    958     virtual ~_C2MappedBlock2DImpl() override = default;
    959 
    960     std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping() const { return mMapping; }
    961 
    962 private:
    963     std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mMapping;
    964 };
    965 
    966 /**
    967  * Block implementation.
    968  */
    969 class C2Block2D::Impl : public _C2MappingBlock2DImpl {
    970 public:
    971     using _C2MappingBlock2DImpl::_C2MappingBlock2DImpl;
    972     virtual ~Impl() override = default;
    973 };
    974 
    975 const C2Handle *C2Block2D::handle() const {
    976     return mImpl->handle();
    977 }
    978 
    979 C2Allocator::id_t C2Block2D::getAllocatorId() const {
    980     return mImpl->getAllocatorId();
    981 }
    982 
    983 C2Block2D::C2Block2D(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section)
    984     // always clamp subsection to parent (impl) crop for safety
    985     : _C2PlanarSectionAspect(impl.get(), section.crop()), mImpl(impl) {
    986 }
    987 
    988 /**
    989  * Graphic view implementation.
    990  *
    991  * range of Impl is the mapped range of the underlying allocation. range of View is the current
    992  * crop.
    993  */
    994 class C2GraphicView::Impl : public _C2MappedBlock2DImpl {
    995 public:
    996     using _C2MappedBlock2DImpl::_C2MappedBlock2DImpl;
    997     virtual ~Impl() override = default;
    998 };
    999 
   1000 C2GraphicView::C2GraphicView(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section)
   1001     : _C2EditablePlanarSectionAspect(impl.get(), section.crop()), mImpl(impl) {
   1002 }
   1003 
   1004 const uint8_t *const *C2GraphicView::data() const {
   1005     return mImpl->mapping()->data();
   1006 }
   1007 
   1008 uint8_t *const *C2GraphicView::data() {
   1009     return mImpl->mapping()->data();
   1010 }
   1011 
   1012 const C2PlanarLayout C2GraphicView::layout() const {
   1013     return mImpl->mapping()->layout();
   1014 }
   1015 
   1016 const C2GraphicView C2GraphicView::subView(const C2Rect &rect) const {
   1017     return C2GraphicView(mImpl, C2PlanarSection(*mImpl, rect));
   1018 }
   1019 
   1020 C2GraphicView C2GraphicView::subView(const C2Rect &rect) {
   1021     return C2GraphicView(mImpl, C2PlanarSection(*mImpl, rect));
   1022 }
   1023 
   1024 c2_status_t C2GraphicView::error() const {
   1025     return mImpl->mapping()->error();
   1026 }
   1027 
   1028 /**
   1029  * Const graphic block implementation.
   1030  */
   1031 C2ConstGraphicBlock::C2ConstGraphicBlock(
   1032         std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section, C2Fence fence)
   1033     : C2Block2D(impl, section), mFence(fence) { }
   1034 
   1035 C2Acquirable<const C2GraphicView> C2ConstGraphicBlock::map() const {
   1036     C2Fence fence;
   1037     std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping =
   1038         mImpl->map(false /* writable */, &fence);
   1039     std::shared_ptr<GraphicViewBuddy::Impl> gvi =
   1040         std::shared_ptr<GraphicViewBuddy::Impl>(new GraphicViewBuddy::Impl(*mImpl, mapping));
   1041     return AcquirableConstGraphicViewBuddy(
   1042             mapping->error(), fence, GraphicViewBuddy(gvi, C2PlanarSection(*mImpl, crop())));
   1043 }
   1044 
   1045 C2ConstGraphicBlock C2ConstGraphicBlock::subBlock(const C2Rect &rect) const {
   1046     return C2ConstGraphicBlock(mImpl, C2PlanarSection(*mImpl, crop().intersect(rect)), mFence);
   1047 }
   1048 
   1049 /**
   1050  * Graphic block implementation.
   1051  */
   1052 C2GraphicBlock::C2GraphicBlock(
   1053     std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section)
   1054     : C2Block2D(impl, section) { }
   1055 
   1056 C2Acquirable<C2GraphicView> C2GraphicBlock::map() {
   1057     C2Fence fence;
   1058     std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping =
   1059         mImpl->map(true /* writable */, &fence);
   1060     std::shared_ptr<GraphicViewBuddy::Impl> gvi =
   1061         std::shared_ptr<GraphicViewBuddy::Impl>(new GraphicViewBuddy::Impl(*mImpl, mapping));
   1062     return AcquirableGraphicViewBuddy(
   1063             mapping->error(), fence, GraphicViewBuddy(gvi, C2PlanarSection(*mImpl, crop())));
   1064 }
   1065 
   1066 C2ConstGraphicBlock C2GraphicBlock::share(const C2Rect &crop, C2Fence fence) {
   1067     return ConstGraphicBlockBuddy(mImpl, C2PlanarSection(*mImpl, crop), fence);
   1068 }
   1069 
   1070 /**
   1071  * Basic block pool implementations.
   1072  */
   1073 C2BasicGraphicBlockPool::C2BasicGraphicBlockPool(
   1074         const std::shared_ptr<C2Allocator> &allocator)
   1075   : mAllocator(allocator) {}
   1076 
   1077 c2_status_t C2BasicGraphicBlockPool::fetchGraphicBlock(
   1078         uint32_t width,
   1079         uint32_t height,
   1080         uint32_t format,
   1081         C2MemoryUsage usage,
   1082         std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
   1083     block->reset();
   1084 
   1085     std::shared_ptr<C2GraphicAllocation> alloc;
   1086     c2_status_t err = mAllocator->newGraphicAllocation(width, height, format, usage, &alloc);
   1087     if (err != C2_OK) {
   1088         return err;
   1089     }
   1090 
   1091     *block = _C2BlockFactory::CreateGraphicBlock(alloc);
   1092 
   1093     return C2_OK;
   1094 }
   1095 
   1096 std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
   1097         const std::shared_ptr<C2GraphicAllocation> &alloc,
   1098         const std::shared_ptr<_C2BlockPoolData> &data, const C2Rect &allottedCrop) {
   1099     std::shared_ptr<C2Block2D::Impl> impl =
   1100         std::make_shared<C2Block2D::Impl>(alloc, data, allottedCrop);
   1101     return std::shared_ptr<C2GraphicBlock>(new C2GraphicBlock(impl, *impl));
   1102 }
   1103 
   1104 std::shared_ptr<_C2BlockPoolData> _C2BlockFactory::GetGraphicBlockPoolData(
   1105         const C2Block2D &block) {
   1106     if (block.mImpl) {
   1107         return block.mImpl->poolData();
   1108     }
   1109     return nullptr;
   1110 }
   1111 
   1112 std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
   1113         const C2Handle *cHandle,
   1114         const std::shared_ptr<BufferPoolData> &data) {
   1115     // TODO: get proper allocator? and mutex?
   1116     static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0);
   1117 
   1118     std::shared_ptr<C2GraphicAllocation> alloc;
   1119     if (C2AllocatorGralloc::isValid(cHandle)) {
   1120         native_handle_t *handle = native_handle_clone(cHandle);
   1121         if (handle) {
   1122             c2_status_t err = sAllocator->priorGraphicAllocation(handle, &alloc);
   1123             const std::shared_ptr<C2PooledBlockPoolData> poolData =
   1124                     std::make_shared<C2PooledBlockPoolData>(data);
   1125             if (err == C2_OK && poolData) {
   1126                 // TODO: config setup?
   1127                 std::shared_ptr<C2GraphicBlock> block =
   1128                         _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
   1129                 return block;
   1130             }
   1131         }
   1132     }
   1133     return nullptr;
   1134 };
   1135 
   1136 
   1137 /* ========================================== BUFFER ========================================= */
   1138 
   1139 class C2BufferData::Impl {
   1140 public:
   1141     explicit Impl(const std::vector<C2ConstLinearBlock> &blocks)
   1142         : mType(blocks.size() == 1 ? LINEAR : LINEAR_CHUNKS),
   1143           mLinearBlocks(blocks) {
   1144     }
   1145 
   1146     explicit Impl(const std::vector<C2ConstGraphicBlock> &blocks)
   1147         : mType(blocks.size() == 1 ? GRAPHIC : GRAPHIC_CHUNKS),
   1148           mGraphicBlocks(blocks) {
   1149     }
   1150 
   1151     type_t type() const { return mType; }
   1152     const std::vector<C2ConstLinearBlock> &linearBlocks() const { return mLinearBlocks; }
   1153     const std::vector<C2ConstGraphicBlock> &graphicBlocks() const { return mGraphicBlocks; }
   1154 
   1155 private:
   1156     type_t mType;
   1157     std::vector<C2ConstLinearBlock> mLinearBlocks;
   1158     std::vector<C2ConstGraphicBlock> mGraphicBlocks;
   1159 };
   1160 
   1161 C2BufferData::C2BufferData(const std::vector<C2ConstLinearBlock> &blocks) : mImpl(new Impl(blocks)) {}
   1162 C2BufferData::C2BufferData(const std::vector<C2ConstGraphicBlock> &blocks) : mImpl(new Impl(blocks)) {}
   1163 
   1164 C2BufferData::type_t C2BufferData::type() const { return mImpl->type(); }
   1165 
   1166 const std::vector<C2ConstLinearBlock> C2BufferData::linearBlocks() const {
   1167     return mImpl->linearBlocks();
   1168 }
   1169 
   1170 const std::vector<C2ConstGraphicBlock> C2BufferData::graphicBlocks() const {
   1171     return mImpl->graphicBlocks();
   1172 }
   1173 
   1174 class C2Buffer::Impl {
   1175 public:
   1176     Impl(C2Buffer *thiz, const std::vector<C2ConstLinearBlock> &blocks)
   1177         : mThis(thiz), mData(blocks) {}
   1178     Impl(C2Buffer *thiz, const std::vector<C2ConstGraphicBlock> &blocks)
   1179         : mThis(thiz), mData(blocks) {}
   1180 
   1181     ~Impl() {
   1182         for (const auto &pair : mNotify) {
   1183             pair.first(mThis, pair.second);
   1184         }
   1185     }
   1186 
   1187     const C2BufferData &data() const { return mData; }
   1188 
   1189     c2_status_t registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
   1190         auto it = std::find_if(
   1191                 mNotify.begin(), mNotify.end(),
   1192                 [onDestroyNotify, arg] (const auto &pair) {
   1193                     return pair.first == onDestroyNotify && pair.second == arg;
   1194                 });
   1195         if (it != mNotify.end()) {
   1196             return C2_DUPLICATE;
   1197         }
   1198         mNotify.emplace_back(onDestroyNotify, arg);
   1199         return C2_OK;
   1200     }
   1201 
   1202     c2_status_t unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
   1203         auto it = std::find_if(
   1204                 mNotify.begin(), mNotify.end(),
   1205                 [onDestroyNotify, arg] (const auto &pair) {
   1206                     return pair.first == onDestroyNotify && pair.second == arg;
   1207                 });
   1208         if (it == mNotify.end()) {
   1209             return C2_NOT_FOUND;
   1210         }
   1211         mNotify.erase(it);
   1212         return C2_OK;
   1213     }
   1214 
   1215     std::vector<std::shared_ptr<const C2Info>> info() const {
   1216         std::vector<std::shared_ptr<const C2Info>> result(mInfos.size());
   1217         std::transform(
   1218                 mInfos.begin(), mInfos.end(), result.begin(),
   1219                 [] (const auto &elem) { return elem.second; });
   1220         return result;
   1221     }
   1222 
   1223     c2_status_t setInfo(const std::shared_ptr<C2Info> &info) {
   1224         // To "update" you need to erase the existing one if any, and then insert.
   1225         (void) mInfos.erase(info->coreIndex());
   1226         (void) mInfos.insert({ info->coreIndex(), info });
   1227         return C2_OK;
   1228     }
   1229 
   1230     bool hasInfo(C2Param::Type index) const {
   1231         return mInfos.count(index.coreIndex()) > 0;
   1232     }
   1233 
   1234     std::shared_ptr<const C2Info> getInfo(C2Param::Type index) const {
   1235         auto it = mInfos.find(index.coreIndex());
   1236         if (it == mInfos.end()) {
   1237             return nullptr;
   1238         }
   1239         return std::const_pointer_cast<const C2Info>(it->second);
   1240     }
   1241 
   1242     std::shared_ptr<C2Info> removeInfo(C2Param::Type index) {
   1243         auto it = mInfos.find(index.coreIndex());
   1244         if (it == mInfos.end()) {
   1245             return nullptr;
   1246         }
   1247         std::shared_ptr<C2Info> ret = it->second;
   1248         (void) mInfos.erase(it);
   1249         return ret;
   1250     }
   1251 
   1252 private:
   1253     C2Buffer * const mThis;
   1254     BufferDataBuddy mData;
   1255     std::map<C2Param::CoreIndex, std::shared_ptr<C2Info>> mInfos;
   1256     std::list<std::pair<OnDestroyNotify, void *>> mNotify;
   1257 };
   1258 
   1259 C2Buffer::C2Buffer(const std::vector<C2ConstLinearBlock> &blocks)
   1260     : mImpl(new Impl(this, blocks)) {}
   1261 
   1262 C2Buffer::C2Buffer(const std::vector<C2ConstGraphicBlock> &blocks)
   1263     : mImpl(new Impl(this, blocks)) {}
   1264 
   1265 const C2BufferData C2Buffer::data() const { return mImpl->data(); }
   1266 
   1267 c2_status_t C2Buffer::registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
   1268     return mImpl->registerOnDestroyNotify(onDestroyNotify, arg);
   1269 }
   1270 
   1271 c2_status_t C2Buffer::unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
   1272     return mImpl->unregisterOnDestroyNotify(onDestroyNotify, arg);
   1273 }
   1274 
   1275 const std::vector<std::shared_ptr<const C2Info>> C2Buffer::info() const {
   1276     return mImpl->info();
   1277 }
   1278 
   1279 c2_status_t C2Buffer::setInfo(const std::shared_ptr<C2Info> &info) {
   1280     return mImpl->setInfo(info);
   1281 }
   1282 
   1283 bool C2Buffer::hasInfo(C2Param::Type index) const {
   1284     return mImpl->hasInfo(index);
   1285 }
   1286 
   1287 std::shared_ptr<const C2Info> C2Buffer::getInfo(C2Param::Type index) const {
   1288     return mImpl->getInfo(index);
   1289 }
   1290 
   1291 std::shared_ptr<C2Info> C2Buffer::removeInfo(C2Param::Type index) {
   1292     return mImpl->removeInfo(index);
   1293 }
   1294 
   1295 // static
   1296 std::shared_ptr<C2Buffer> C2Buffer::CreateLinearBuffer(const C2ConstLinearBlock &block) {
   1297     return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
   1298 }
   1299 
   1300 // static
   1301 std::shared_ptr<C2Buffer> C2Buffer::CreateGraphicBuffer(const C2ConstGraphicBlock &block) {
   1302     return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
   1303 }
   1304 
   1305