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