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