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