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