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::V2_0::ResultStatus;
37 using android::hardware::media::bufferpool::V2_0::implementation::BufferPoolAllocation;
38 using android::hardware::media::bufferpool::V2_0::implementation::BufferPoolAllocator;
39 using android::hardware::media::bufferpool::V2_0::implementation::ClientManager;
40 using android::hardware::media::bufferpool::V2_0::implementation::ConnectionId;
41 using android::hardware::media::bufferpool::V2_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 c2_status_t err = sAllocator->priorLinearAllocation(cHandle, &alloc);
417 const std::shared_ptr<C2PooledBlockPoolData> poolData =
418 std::make_shared<C2PooledBlockPoolData>(data);
419 if (err == C2_OK && poolData) {
420 // TODO: config params?
421 std::shared_ptr<C2LinearBlock> block =
422 _C2BlockFactory::CreateLinearBlock(alloc, poolData);
423 return block;
424 }
425 }
426 return nullptr;
427 };
428
429 /**
430 * Wrapped C2Allocator which is injected to buffer pool on behalf of
431 * C2BlockPool.
432 */
433 class _C2BufferPoolAllocator : public BufferPoolAllocator {
434 public:
_C2BufferPoolAllocator(const std::shared_ptr<C2Allocator> & allocator)435 _C2BufferPoolAllocator(const std::shared_ptr<C2Allocator> &allocator)
436 : mAllocator(allocator) {}
437
~_C2BufferPoolAllocator()438 ~_C2BufferPoolAllocator() override {}
439
440 ResultStatus allocate(const std::vector<uint8_t> ¶ms,
441 std::shared_ptr<BufferPoolAllocation> *alloc,
442 size_t *allocSize) override;
443
444 bool compatible(const std::vector<uint8_t> &newParams,
445 const std::vector<uint8_t> &oldParams) override;
446
447 // Methods for codec2 component (C2BlockPool).
448 /**
449 * Transforms linear allocation parameters for C2Allocator to parameters
450 * for buffer pool.
451 *
452 * @param capacity size of linear allocation
453 * @param usage memory usage pattern for linear allocation
454 * @param params allocation parameters for buffer pool
455 */
456 void getLinearParams(uint32_t capacity, C2MemoryUsage usage,
457 std::vector<uint8_t> *params);
458
459 /**
460 * Transforms graphic allocation parameters for C2Allocator to parameters
461 * for buffer pool.
462 *
463 * @param width width of graphic allocation
464 * @param height height of graphic allocation
465 * @param format color format of graphic allocation
466 * @param params allocation parameter for buffer pool
467 */
468 void getGraphicParams(uint32_t width, uint32_t height,
469 uint32_t format, C2MemoryUsage usage,
470 std::vector<uint8_t> *params);
471
472 /**
473 * Transforms an existing native handle to an C2LinearAllcation.
474 * Wrapper to C2Allocator#priorLinearAllocation
475 */
476 c2_status_t priorLinearAllocation(
477 const C2Handle *handle,
478 std::shared_ptr<C2LinearAllocation> *c2Allocation);
479
480 /**
481 * Transforms an existing native handle to an C2GraphicAllcation.
482 * Wrapper to C2Allocator#priorGraphicAllocation
483 */
484 c2_status_t priorGraphicAllocation(
485 const C2Handle *handle,
486 std::shared_ptr<C2GraphicAllocation> *c2Allocation);
487
488 private:
489 static constexpr int kMaxIntParams = 5; // large enough number;
490
491 enum AllocType : uint8_t {
492 ALLOC_NONE = 0,
493
494 ALLOC_LINEAR,
495 ALLOC_GRAPHIC,
496 };
497
498 union AllocParams {
499 struct {
500 AllocType allocType;
501 C2MemoryUsage usage;
502 uint32_t params[kMaxIntParams];
503 } data;
504 uint8_t array[0];
505
AllocParams()506 AllocParams() : data{ALLOC_NONE, {0, 0}, {0}} {}
AllocParams(C2MemoryUsage usage,uint32_t capacity)507 AllocParams(C2MemoryUsage usage, uint32_t capacity)
508 : data{ALLOC_LINEAR, usage, {[0] = capacity}} {}
AllocParams(C2MemoryUsage usage,uint32_t width,uint32_t height,uint32_t format)509 AllocParams(
510 C2MemoryUsage usage,
511 uint32_t width, uint32_t height, uint32_t format)
512 : data{ALLOC_GRAPHIC, usage, {width, height, format}} {}
513 };
514
515 const std::shared_ptr<C2Allocator> mAllocator;
516 };
517
518 struct LinearAllocationDtor {
LinearAllocationDtorLinearAllocationDtor519 LinearAllocationDtor(const std::shared_ptr<C2LinearAllocation> &alloc)
520 : mAllocation(alloc) {}
521
operator ()LinearAllocationDtor522 void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
523
524 const std::shared_ptr<C2LinearAllocation> mAllocation;
525 };
526
527 struct GraphicAllocationDtor {
GraphicAllocationDtorGraphicAllocationDtor528 GraphicAllocationDtor(const std::shared_ptr<C2GraphicAllocation> &alloc)
529 : mAllocation(alloc) {}
530
operator ()GraphicAllocationDtor531 void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
532
533 const std::shared_ptr<C2GraphicAllocation> mAllocation;
534 };
535
allocate(const std::vector<uint8_t> & params,std::shared_ptr<BufferPoolAllocation> * alloc,size_t * allocSize)536 ResultStatus _C2BufferPoolAllocator::allocate(
537 const std::vector<uint8_t> ¶ms,
538 std::shared_ptr<BufferPoolAllocation> *alloc,
539 size_t *allocSize) {
540 AllocParams c2Params;
541 memcpy(&c2Params, params.data(), std::min(sizeof(AllocParams), params.size()));
542 c2_status_t status = C2_BAD_VALUE;
543 switch(c2Params.data.allocType) {
544 case ALLOC_NONE:
545 break;
546 case ALLOC_LINEAR: {
547 std::shared_ptr<C2LinearAllocation> c2Linear;
548 status = mAllocator->newLinearAllocation(
549 c2Params.data.params[0], c2Params.data.usage, &c2Linear);
550 if (status == C2_OK && c2Linear) {
551 BufferPoolAllocation *ptr = new BufferPoolAllocation(c2Linear->handle());
552 if (ptr) {
553 *alloc = std::shared_ptr<BufferPoolAllocation>(
554 ptr, LinearAllocationDtor(c2Linear));
555 if (*alloc) {
556 *allocSize = (size_t)c2Params.data.params[0];
557 return ResultStatus::OK;
558 }
559 delete ptr;
560 }
561 return ResultStatus::NO_MEMORY;
562 }
563 break;
564 }
565 case ALLOC_GRAPHIC: {
566 std::shared_ptr<C2GraphicAllocation> c2Graphic;
567 status = mAllocator->newGraphicAllocation(
568 c2Params.data.params[0],
569 c2Params.data.params[1],
570 c2Params.data.params[2],
571 c2Params.data.usage, &c2Graphic);
572 if (status == C2_OK && c2Graphic) {
573 BufferPoolAllocation *ptr = new BufferPoolAllocation(c2Graphic->handle());
574 if (ptr) {
575 *alloc = std::shared_ptr<BufferPoolAllocation>(
576 ptr, GraphicAllocationDtor(c2Graphic));
577 if (*alloc) {
578 *allocSize = c2Params.data.params[0] * c2Params.data.params[1];
579 return ResultStatus::OK;
580 }
581 delete ptr;
582 }
583 return ResultStatus::NO_MEMORY;
584 }
585 break;
586 }
587 default:
588 break;
589 }
590 return ResultStatus::CRITICAL_ERROR;
591 }
592
compatible(const std::vector<uint8_t> & newParams,const std::vector<uint8_t> & oldParams)593 bool _C2BufferPoolAllocator::compatible(
594 const std::vector<uint8_t> &newParams,
595 const std::vector<uint8_t> &oldParams) {
596 AllocParams newAlloc;
597 AllocParams oldAlloc;
598 memcpy(&newAlloc, newParams.data(), std::min(sizeof(AllocParams), newParams.size()));
599 memcpy(&oldAlloc, oldParams.data(), std::min(sizeof(AllocParams), oldParams.size()));
600
601 // TODO: support not exact matching. e.g) newCapacity < oldCapacity
602 if (newAlloc.data.allocType == oldAlloc.data.allocType &&
603 newAlloc.data.usage.expected == oldAlloc.data.usage.expected) {
604 for (int i = 0; i < kMaxIntParams; ++i) {
605 if (newAlloc.data.params[i] != oldAlloc.data.params[i]) {
606 return false;
607 }
608 }
609 return true;
610 }
611 return false;
612 }
613
getLinearParams(uint32_t capacity,C2MemoryUsage usage,std::vector<uint8_t> * params)614 void _C2BufferPoolAllocator::getLinearParams(
615 uint32_t capacity, C2MemoryUsage usage, std::vector<uint8_t> *params) {
616 AllocParams c2Params(usage, capacity);
617 params->assign(c2Params.array, c2Params.array + sizeof(AllocParams));
618 }
619
getGraphicParams(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::vector<uint8_t> * params)620 void _C2BufferPoolAllocator::getGraphicParams(
621 uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
622 std::vector<uint8_t> *params) {
623 AllocParams c2Params(usage, width, height, format);
624 params->assign(c2Params.array, c2Params.array + sizeof(AllocParams));
625 }
626
priorLinearAllocation(const C2Handle * handle,std::shared_ptr<C2LinearAllocation> * c2Allocation)627 c2_status_t _C2BufferPoolAllocator::priorLinearAllocation(
628 const C2Handle *handle,
629 std::shared_ptr<C2LinearAllocation> *c2Allocation) {
630 return mAllocator->priorLinearAllocation(handle, c2Allocation);
631 }
632
priorGraphicAllocation(const C2Handle * handle,std::shared_ptr<C2GraphicAllocation> * c2Allocation)633 c2_status_t _C2BufferPoolAllocator::priorGraphicAllocation(
634 const C2Handle *handle,
635 std::shared_ptr<C2GraphicAllocation> *c2Allocation) {
636 return mAllocator->priorGraphicAllocation(handle, c2Allocation);
637 }
638
639 class C2PooledBlockPool::Impl {
640 public:
Impl(const std::shared_ptr<C2Allocator> & allocator)641 Impl(const std::shared_ptr<C2Allocator> &allocator)
642 : mInit(C2_OK),
643 mBufferPoolManager(ClientManager::getInstance()),
644 mAllocator(std::make_shared<_C2BufferPoolAllocator>(allocator)) {
645 if (mAllocator && mBufferPoolManager) {
646 if (mBufferPoolManager->create(
647 mAllocator, &mConnectionId) == ResultStatus::OK) {
648 return;
649 }
650 }
651 mInit = C2_NO_INIT;
652 }
653
~Impl()654 ~Impl() {
655 if (mInit == C2_OK) {
656 mBufferPoolManager->close(mConnectionId);
657 }
658 }
659
fetchLinearBlock(uint32_t capacity,C2MemoryUsage usage,std::shared_ptr<C2LinearBlock> * block)660 c2_status_t fetchLinearBlock(
661 uint32_t capacity, C2MemoryUsage usage,
662 std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
663 block->reset();
664 if (mInit != C2_OK) {
665 return mInit;
666 }
667 std::vector<uint8_t> params;
668 mAllocator->getLinearParams(capacity, usage, ¶ms);
669 std::shared_ptr<BufferPoolData> bufferPoolData;
670 native_handle_t *cHandle = nullptr;
671 ResultStatus status = mBufferPoolManager->allocate(
672 mConnectionId, params, &cHandle, &bufferPoolData);
673 if (status == ResultStatus::OK) {
674 std::shared_ptr<C2LinearAllocation> alloc;
675 std::shared_ptr<C2PooledBlockPoolData> poolData =
676 std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
677 c2_status_t err = mAllocator->priorLinearAllocation(cHandle, &alloc);
678 if (err == C2_OK && poolData && alloc) {
679 *block = _C2BlockFactory::CreateLinearBlock(alloc, poolData, 0, capacity);
680 if (*block) {
681 return C2_OK;
682 }
683 }
684 return C2_NO_MEMORY;
685 }
686 if (status == ResultStatus::NO_MEMORY) {
687 return C2_NO_MEMORY;
688 }
689 return C2_CORRUPTED;
690 }
691
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)692 c2_status_t fetchGraphicBlock(
693 uint32_t width, uint32_t height, uint32_t format,
694 C2MemoryUsage usage,
695 std::shared_ptr<C2GraphicBlock> *block) {
696 block->reset();
697 if (mInit != C2_OK) {
698 return mInit;
699 }
700 std::vector<uint8_t> params;
701 mAllocator->getGraphicParams(width, height, format, usage, ¶ms);
702 std::shared_ptr<BufferPoolData> bufferPoolData;
703 native_handle_t *cHandle = nullptr;
704 ResultStatus status = mBufferPoolManager->allocate(
705 mConnectionId, params, &cHandle, &bufferPoolData);
706 if (status == ResultStatus::OK) {
707 std::shared_ptr<C2GraphicAllocation> alloc;
708 std::shared_ptr<C2PooledBlockPoolData> poolData =
709 std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
710 c2_status_t err = mAllocator->priorGraphicAllocation(
711 cHandle, &alloc);
712 if (err == C2_OK && poolData && alloc) {
713 *block = _C2BlockFactory::CreateGraphicBlock(
714 alloc, poolData, C2Rect(width, height));
715 if (*block) {
716 return C2_OK;
717 }
718 }
719 return C2_NO_MEMORY;
720 }
721 if (status == ResultStatus::NO_MEMORY) {
722 return C2_NO_MEMORY;
723 }
724 return C2_CORRUPTED;
725 }
726
getConnectionId()727 ConnectionId getConnectionId() {
728 return mInit != C2_OK ? INVALID_CONNECTIONID : mConnectionId;
729 }
730
731 private:
732 c2_status_t mInit;
733 const android::sp<ClientManager> mBufferPoolManager;
734 ConnectionId mConnectionId; // locally
735 const std::shared_ptr<_C2BufferPoolAllocator> mAllocator;
736 };
737
C2PooledBlockPool(const std::shared_ptr<C2Allocator> & allocator,const local_id_t localId)738 C2PooledBlockPool::C2PooledBlockPool(
739 const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId)
740 : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {}
741
~C2PooledBlockPool()742 C2PooledBlockPool::~C2PooledBlockPool() {
743 }
744
fetchLinearBlock(uint32_t capacity,C2MemoryUsage usage,std::shared_ptr<C2LinearBlock> * block)745 c2_status_t C2PooledBlockPool::fetchLinearBlock(
746 uint32_t capacity,
747 C2MemoryUsage usage,
748 std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
749 if (mImpl) {
750 return mImpl->fetchLinearBlock(capacity, usage, block);
751 }
752 return C2_CORRUPTED;
753 }
754
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)755 c2_status_t C2PooledBlockPool::fetchGraphicBlock(
756 uint32_t width,
757 uint32_t height,
758 uint32_t format,
759 C2MemoryUsage usage,
760 std::shared_ptr<C2GraphicBlock> *block) {
761 if (mImpl) {
762 return mImpl->fetchGraphicBlock(width, height, format, usage, block);
763 }
764 return C2_CORRUPTED;
765 }
766
getConnectionId()767 int64_t C2PooledBlockPool::getConnectionId() {
768 if (mImpl) {
769 return mImpl->getConnectionId();
770 }
771 return 0;
772 }
773
774 /* ========================================== 2D BLOCK ========================================= */
775
776 /**
777 * Implementation that is shared between all 2D blocks and views.
778 *
779 * For blocks' Impl's crop is always the allotted crop, even if it is a sub block.
780 *
781 * For views' Impl's crop is the mapped portion - which for now is always the
782 * allotted crop.
783 */
784 class C2_HIDE _C2Block2DImpl : public _C2PlanarSectionAspect {
785 public:
786 /**
787 * Impl's crop is always the or part of the allotted crop of the allocation.
788 */
_C2Block2DImpl(const std::shared_ptr<C2GraphicAllocation> & alloc,const std::shared_ptr<_C2BlockPoolData> & poolData=nullptr,const C2Rect & allottedCrop=C2Rect (~0u,~0u))789 _C2Block2DImpl(const std::shared_ptr<C2GraphicAllocation> &alloc,
790 const std::shared_ptr<_C2BlockPoolData> &poolData = nullptr,
791 const C2Rect &allottedCrop = C2Rect(~0u, ~0u))
792 : _C2PlanarSectionAspect(alloc.get(), allottedCrop),
793 mAllocation(alloc),
794 mPoolData(poolData) { }
795
796 virtual ~_C2Block2DImpl() = default;
797
798 /** returns pool data */
poolData() const799 std::shared_ptr<_C2BlockPoolData> poolData() const {
800 return mPoolData;
801 }
802
803 /** returns native handle */
handle() const804 const C2Handle *handle() const {
805 return mAllocation ? mAllocation->handle() : nullptr;
806 }
807
808 /** returns the allocator's ID */
getAllocatorId() const809 C2Allocator::id_t getAllocatorId() const {
810 // BAD_ID can only happen if this Impl class is initialized for a view - never for a block.
811 return mAllocation ? mAllocation->getAllocatorId() : C2Allocator::BAD_ID;
812 }
813
getAllocation() const814 std::shared_ptr<C2GraphicAllocation> getAllocation() const {
815 return mAllocation;
816 }
817
818 private:
819 std::shared_ptr<C2GraphicAllocation> mAllocation;
820 std::shared_ptr<_C2BlockPoolData> mPoolData;
821 };
822
823 class C2_HIDE _C2MappingBlock2DImpl
824 : public _C2Block2DImpl, public std::enable_shared_from_this<_C2MappingBlock2DImpl> {
825 public:
826 using _C2Block2DImpl::_C2Block2DImpl;
827
828 virtual ~_C2MappingBlock2DImpl() override = default;
829
830 /**
831 * This class contains the mapped data pointer, and the potential error.
832 */
833 struct Mapped {
834 private:
835 friend class _C2MappingBlock2DImpl;
836
Mapped_C2MappingBlock2DImpl::Mapped837 Mapped(const std::shared_ptr<_C2Block2DImpl> &impl, bool writable, C2Fence *fence __unused)
838 : mImpl(impl), mWritable(writable) {
839 memset(mData, 0, sizeof(mData));
840 const C2Rect crop = mImpl->crop();
841 // gralloc requires mapping the whole region of interest as we cannot
842 // map multiple regions
843 mError = mImpl->getAllocation()->map(
844 crop,
845 { C2MemoryUsage::CPU_READ, writable ? C2MemoryUsage::CPU_WRITE : 0 },
846 nullptr,
847 &mLayout,
848 mData);
849 if (mError != C2_OK) {
850 memset(&mLayout, 0, sizeof(mLayout));
851 memset(mData, 0, sizeof(mData));
852 memset(mOffsetData, 0, sizeof(mData));
853 } else {
854 // TODO: validate plane layout and
855 // adjust data pointers to the crop region's top left corner.
856 // fail if it is not on a subsampling boundary
857 for (size_t planeIx = 0; planeIx < mLayout.numPlanes; ++planeIx) {
858 const uint32_t colSampling = mLayout.planes[planeIx].colSampling;
859 const uint32_t rowSampling = mLayout.planes[planeIx].rowSampling;
860 if (crop.left % colSampling || crop.right() % colSampling
861 || crop.top % rowSampling || crop.bottom() % rowSampling) {
862 // cannot calculate data pointer
863 mImpl->getAllocation()->unmap(mData, crop, nullptr);
864 memset(&mLayout, 0, sizeof(mLayout));
865 memset(mData, 0, sizeof(mData));
866 memset(mOffsetData, 0, sizeof(mData));
867 mError = C2_BAD_VALUE;
868 return;
869 }
870 mOffsetData[planeIx] =
871 mData[planeIx] + (ssize_t)crop.left * mLayout.planes[planeIx].colInc
872 + (ssize_t)crop.top * mLayout.planes[planeIx].rowInc;
873 }
874 }
875 }
876
Mapped_C2MappingBlock2DImpl::Mapped877 explicit Mapped(c2_status_t error)
878 : mImpl(nullptr), mWritable(false), mError(error) {
879 // CHECK(error != C2_OK);
880 memset(&mLayout, 0, sizeof(mLayout));
881 memset(mData, 0, sizeof(mData));
882 memset(mOffsetData, 0, sizeof(mData));
883 }
884
885 public:
~Mapped_C2MappingBlock2DImpl::Mapped886 ~Mapped() {
887 if (mData[0] != nullptr) {
888 mImpl->getAllocation()->unmap(mData, mImpl->crop(), nullptr);
889 }
890 }
891
892 /** returns mapping status */
error_C2MappingBlock2DImpl::Mapped893 c2_status_t error() const { return mError; }
894
895 /** returns data pointer */
data_C2MappingBlock2DImpl::Mapped896 uint8_t *const *data() const { return mOffsetData; }
897
898 /** returns the plane layout */
layout_C2MappingBlock2DImpl::Mapped899 C2PlanarLayout layout() const { return mLayout; }
900
901 /** returns whether the mapping is writable */
writable_C2MappingBlock2DImpl::Mapped902 bool writable() const { return mWritable; }
903
904 private:
905 const std::shared_ptr<_C2Block2DImpl> mImpl;
906 bool mWritable;
907 c2_status_t mError;
908 uint8_t *mData[C2PlanarLayout::MAX_NUM_PLANES];
909 uint8_t *mOffsetData[C2PlanarLayout::MAX_NUM_PLANES];
910 C2PlanarLayout mLayout;
911 };
912
913 /**
914 * Maps the allotted region.
915 *
916 * If already mapped and it is currently in use, returns the existing mapping.
917 * If fence is provided, an acquire fence is stored there.
918 */
map(bool writable,C2Fence * fence)919 std::shared_ptr<Mapped> map(bool writable, C2Fence *fence) {
920 std::lock_guard<std::mutex> lock(mMappedLock);
921 std::shared_ptr<Mapped> existing = mMapped.lock();
922 if (!existing) {
923 existing = std::shared_ptr<Mapped>(new Mapped(shared_from_this(), writable, fence));
924 mMapped = existing;
925 } else {
926 // if we mapped the region read-only, we cannot remap it read-write
927 if (writable && !existing->writable()) {
928 existing = std::shared_ptr<Mapped>(new Mapped(C2_CANNOT_DO));
929 }
930 if (fence != nullptr) {
931 *fence = C2Fence();
932 }
933 }
934 return existing;
935 }
936
937 private:
938 std::weak_ptr<Mapped> mMapped;
939 std::mutex mMappedLock;
940 };
941
942 class C2_HIDE _C2MappedBlock2DImpl : public _C2Block2DImpl {
943 public:
_C2MappedBlock2DImpl(const _C2Block2DImpl & impl,std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping)944 _C2MappedBlock2DImpl(const _C2Block2DImpl &impl,
945 std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping)
946 : _C2Block2DImpl(impl), mMapping(mapping) {
947 }
948
949 virtual ~_C2MappedBlock2DImpl() override = default;
950
mapping() const951 std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping() const { return mMapping; }
952
953 private:
954 std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mMapping;
955 };
956
957 /**
958 * Block implementation.
959 */
960 class C2Block2D::Impl : public _C2MappingBlock2DImpl {
961 public:
962 using _C2MappingBlock2DImpl::_C2MappingBlock2DImpl;
963 virtual ~Impl() override = default;
964 };
965
handle() const966 const C2Handle *C2Block2D::handle() const {
967 return mImpl->handle();
968 }
969
getAllocatorId() const970 C2Allocator::id_t C2Block2D::getAllocatorId() const {
971 return mImpl->getAllocatorId();
972 }
973
C2Block2D(std::shared_ptr<Impl> impl,const _C2PlanarSectionAspect & section)974 C2Block2D::C2Block2D(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
975 // always clamp subsection to parent (impl) crop for safety
976 : _C2PlanarSectionAspect(impl.get(), section.crop()), mImpl(impl) {
977 }
978
979 /**
980 * Graphic view implementation.
981 *
982 * range of Impl is the mapped range of the underlying allocation. range of View is the current
983 * crop.
984 */
985 class C2GraphicView::Impl : public _C2MappedBlock2DImpl {
986 public:
987 using _C2MappedBlock2DImpl::_C2MappedBlock2DImpl;
988 virtual ~Impl() override = default;
989 };
990
C2GraphicView(std::shared_ptr<Impl> impl,const _C2PlanarSectionAspect & section)991 C2GraphicView::C2GraphicView(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
992 : _C2EditablePlanarSectionAspect(impl.get(), section.crop()), mImpl(impl) {
993 }
994
data() const995 const uint8_t *const *C2GraphicView::data() const {
996 return mImpl->mapping()->data();
997 }
998
data()999 uint8_t *const *C2GraphicView::data() {
1000 return mImpl->mapping()->data();
1001 }
1002
layout() const1003 const C2PlanarLayout C2GraphicView::layout() const {
1004 return mImpl->mapping()->layout();
1005 }
1006
subView(const C2Rect & rect) const1007 const C2GraphicView C2GraphicView::subView(const C2Rect &rect) const {
1008 return C2GraphicView(mImpl, C2PlanarSection(*mImpl, rect));
1009 }
1010
subView(const C2Rect & rect)1011 C2GraphicView C2GraphicView::subView(const C2Rect &rect) {
1012 return C2GraphicView(mImpl, C2PlanarSection(*mImpl, rect));
1013 }
1014
error() const1015 c2_status_t C2GraphicView::error() const {
1016 return mImpl->mapping()->error();
1017 }
1018
1019 /**
1020 * Const graphic block implementation.
1021 */
C2ConstGraphicBlock(std::shared_ptr<Impl> impl,const _C2PlanarSectionAspect & section,C2Fence fence)1022 C2ConstGraphicBlock::C2ConstGraphicBlock(
1023 std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion, C2Fence fence)
1024 : C2Block2D(impl, section), mFence(fence) { }
1025
map() const1026 C2Acquirable<const C2GraphicView> C2ConstGraphicBlock::map() const {
1027 C2Fence fence;
1028 std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping =
1029 mImpl->map(false /* writable */, &fence);
1030 std::shared_ptr<GraphicViewBuddy::Impl> gvi =
1031 std::shared_ptr<GraphicViewBuddy::Impl>(new GraphicViewBuddy::Impl(*mImpl, mapping));
1032 return AcquirableConstGraphicViewBuddy(
1033 mapping->error(), fence, GraphicViewBuddy(gvi, C2PlanarSection(*mImpl, crop())));
1034 }
1035
subBlock(const C2Rect & rect) const1036 C2ConstGraphicBlock C2ConstGraphicBlock::subBlock(const C2Rect &rect) const {
1037 return C2ConstGraphicBlock(mImpl, C2PlanarSection(*mImpl, crop().intersect(rect)), mFence);
1038 }
1039
1040 /**
1041 * Graphic block implementation.
1042 */
C2GraphicBlock(std::shared_ptr<Impl> impl,const _C2PlanarSectionAspect & section)1043 C2GraphicBlock::C2GraphicBlock(
1044 std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
1045 : C2Block2D(impl, section) { }
1046
map()1047 C2Acquirable<C2GraphicView> C2GraphicBlock::map() {
1048 C2Fence fence;
1049 std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping =
1050 mImpl->map(true /* writable */, &fence);
1051 std::shared_ptr<GraphicViewBuddy::Impl> gvi =
1052 std::shared_ptr<GraphicViewBuddy::Impl>(new GraphicViewBuddy::Impl(*mImpl, mapping));
1053 return AcquirableGraphicViewBuddy(
1054 mapping->error(), fence, GraphicViewBuddy(gvi, C2PlanarSection(*mImpl, crop())));
1055 }
1056
share(const C2Rect & crop,C2Fence fence)1057 C2ConstGraphicBlock C2GraphicBlock::share(const C2Rect &crop, C2Fence fence) {
1058 return ConstGraphicBlockBuddy(mImpl, C2PlanarSection(*mImpl, crop), fence);
1059 }
1060
1061 /**
1062 * Basic block pool implementations.
1063 */
C2BasicGraphicBlockPool(const std::shared_ptr<C2Allocator> & allocator)1064 C2BasicGraphicBlockPool::C2BasicGraphicBlockPool(
1065 const std::shared_ptr<C2Allocator> &allocator)
1066 : mAllocator(allocator) {}
1067
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)1068 c2_status_t C2BasicGraphicBlockPool::fetchGraphicBlock(
1069 uint32_t width,
1070 uint32_t height,
1071 uint32_t format,
1072 C2MemoryUsage usage,
1073 std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
1074 block->reset();
1075
1076 std::shared_ptr<C2GraphicAllocation> alloc;
1077 c2_status_t err = mAllocator->newGraphicAllocation(width, height, format, usage, &alloc);
1078 if (err != C2_OK) {
1079 return err;
1080 }
1081
1082 *block = _C2BlockFactory::CreateGraphicBlock(alloc);
1083
1084 return C2_OK;
1085 }
1086
CreateGraphicBlock(const std::shared_ptr<C2GraphicAllocation> & alloc,const std::shared_ptr<_C2BlockPoolData> & data,const C2Rect & allottedCrop)1087 std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
1088 const std::shared_ptr<C2GraphicAllocation> &alloc,
1089 const std::shared_ptr<_C2BlockPoolData> &data, const C2Rect &allottedCrop) {
1090 std::shared_ptr<C2Block2D::Impl> impl =
1091 std::make_shared<C2Block2D::Impl>(alloc, data, allottedCrop);
1092 return std::shared_ptr<C2GraphicBlock>(new C2GraphicBlock(impl, *impl));
1093 }
1094
GetGraphicBlockPoolData(const C2Block2D & block)1095 std::shared_ptr<_C2BlockPoolData> _C2BlockFactory::GetGraphicBlockPoolData(
1096 const C2Block2D &block) {
1097 if (block.mImpl) {
1098 return block.mImpl->poolData();
1099 }
1100 return nullptr;
1101 }
1102
CreateGraphicBlock(const C2Handle * cHandle,const std::shared_ptr<BufferPoolData> & data)1103 std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
1104 const C2Handle *cHandle,
1105 const std::shared_ptr<BufferPoolData> &data) {
1106 // TODO: get proper allocator? and mutex?
1107 static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0);
1108
1109 std::shared_ptr<C2GraphicAllocation> alloc;
1110 if (C2AllocatorGralloc::isValid(cHandle)) {
1111 c2_status_t err = sAllocator->priorGraphicAllocation(cHandle, &alloc);
1112 const std::shared_ptr<C2PooledBlockPoolData> poolData =
1113 std::make_shared<C2PooledBlockPoolData>(data);
1114 if (err == C2_OK && poolData) {
1115 // TODO: config setup?
1116 std::shared_ptr<C2GraphicBlock> block =
1117 _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
1118 return block;
1119 }
1120 }
1121 return nullptr;
1122 };
1123
1124
1125 /* ========================================== BUFFER ========================================= */
1126
1127 class C2BufferData::Impl {
1128 public:
Impl(const std::vector<C2ConstLinearBlock> & blocks)1129 explicit Impl(const std::vector<C2ConstLinearBlock> &blocks)
1130 : mType(blocks.size() == 1 ? LINEAR : LINEAR_CHUNKS),
1131 mLinearBlocks(blocks) {
1132 }
1133
Impl(const std::vector<C2ConstGraphicBlock> & blocks)1134 explicit Impl(const std::vector<C2ConstGraphicBlock> &blocks)
1135 : mType(blocks.size() == 1 ? GRAPHIC : GRAPHIC_CHUNKS),
1136 mGraphicBlocks(blocks) {
1137 }
1138
type() const1139 type_t type() const { return mType; }
linearBlocks() const1140 const std::vector<C2ConstLinearBlock> &linearBlocks() const { return mLinearBlocks; }
graphicBlocks() const1141 const std::vector<C2ConstGraphicBlock> &graphicBlocks() const { return mGraphicBlocks; }
1142
1143 private:
1144 type_t mType;
1145 std::vector<C2ConstLinearBlock> mLinearBlocks;
1146 std::vector<C2ConstGraphicBlock> mGraphicBlocks;
1147 };
1148
C2BufferData(const std::vector<C2ConstLinearBlock> & blocks)1149 C2BufferData::C2BufferData(const std::vector<C2ConstLinearBlock> &blocks) : mImpl(new Impl(blocks)) {}
C2BufferData(const std::vector<C2ConstGraphicBlock> & blocks)1150 C2BufferData::C2BufferData(const std::vector<C2ConstGraphicBlock> &blocks) : mImpl(new Impl(blocks)) {}
1151
type() const1152 C2BufferData::type_t C2BufferData::type() const { return mImpl->type(); }
1153
linearBlocks() const1154 const std::vector<C2ConstLinearBlock> C2BufferData::linearBlocks() const {
1155 return mImpl->linearBlocks();
1156 }
1157
graphicBlocks() const1158 const std::vector<C2ConstGraphicBlock> C2BufferData::graphicBlocks() const {
1159 return mImpl->graphicBlocks();
1160 }
1161
1162 class C2Buffer::Impl {
1163 public:
Impl(C2Buffer * thiz,const std::vector<C2ConstLinearBlock> & blocks)1164 Impl(C2Buffer *thiz, const std::vector<C2ConstLinearBlock> &blocks)
1165 : mThis(thiz), mData(blocks) {}
Impl(C2Buffer * thiz,const std::vector<C2ConstGraphicBlock> & blocks)1166 Impl(C2Buffer *thiz, const std::vector<C2ConstGraphicBlock> &blocks)
1167 : mThis(thiz), mData(blocks) {}
1168
~Impl()1169 ~Impl() {
1170 for (const auto &pair : mNotify) {
1171 pair.first(mThis, pair.second);
1172 }
1173 }
1174
data() const1175 const C2BufferData &data() const { return mData; }
1176
registerOnDestroyNotify(OnDestroyNotify onDestroyNotify,void * arg)1177 c2_status_t registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
1178 auto it = std::find_if(
1179 mNotify.begin(), mNotify.end(),
1180 [onDestroyNotify, arg] (const auto &pair) {
1181 return pair.first == onDestroyNotify && pair.second == arg;
1182 });
1183 if (it != mNotify.end()) {
1184 return C2_DUPLICATE;
1185 }
1186 mNotify.emplace_back(onDestroyNotify, arg);
1187 return C2_OK;
1188 }
1189
unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify,void * arg)1190 c2_status_t unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
1191 auto it = std::find_if(
1192 mNotify.begin(), mNotify.end(),
1193 [onDestroyNotify, arg] (const auto &pair) {
1194 return pair.first == onDestroyNotify && pair.second == arg;
1195 });
1196 if (it == mNotify.end()) {
1197 return C2_NOT_FOUND;
1198 }
1199 mNotify.erase(it);
1200 return C2_OK;
1201 }
1202
info() const1203 std::vector<std::shared_ptr<const C2Info>> info() const {
1204 std::vector<std::shared_ptr<const C2Info>> result(mInfos.size());
1205 std::transform(
1206 mInfos.begin(), mInfos.end(), result.begin(),
1207 [] (const auto &elem) { return elem.second; });
1208 return result;
1209 }
1210
setInfo(const std::shared_ptr<C2Info> & info)1211 c2_status_t setInfo(const std::shared_ptr<C2Info> &info) {
1212 // To "update" you need to erase the existing one if any, and then insert.
1213 (void) mInfos.erase(info->coreIndex());
1214 (void) mInfos.insert({ info->coreIndex(), info });
1215 return C2_OK;
1216 }
1217
hasInfo(C2Param::Type index) const1218 bool hasInfo(C2Param::Type index) const {
1219 return mInfos.count(index.coreIndex()) > 0;
1220 }
1221
getInfo(C2Param::Type index) const1222 std::shared_ptr<const C2Info> getInfo(C2Param::Type index) const {
1223 auto it = mInfos.find(index.coreIndex());
1224 if (it == mInfos.end()) {
1225 return nullptr;
1226 }
1227 return std::const_pointer_cast<const C2Info>(it->second);
1228 }
1229
removeInfo(C2Param::Type index)1230 std::shared_ptr<C2Info> removeInfo(C2Param::Type index) {
1231 auto it = mInfos.find(index.coreIndex());
1232 if (it == mInfos.end()) {
1233 return nullptr;
1234 }
1235 std::shared_ptr<C2Info> ret = it->second;
1236 (void) mInfos.erase(it);
1237 return ret;
1238 }
1239
1240 private:
1241 C2Buffer * const mThis;
1242 BufferDataBuddy mData;
1243 std::map<C2Param::CoreIndex, std::shared_ptr<C2Info>> mInfos;
1244 std::list<std::pair<OnDestroyNotify, void *>> mNotify;
1245 };
1246
C2Buffer(const std::vector<C2ConstLinearBlock> & blocks)1247 C2Buffer::C2Buffer(const std::vector<C2ConstLinearBlock> &blocks)
1248 : mImpl(new Impl(this, blocks)) {}
1249
C2Buffer(const std::vector<C2ConstGraphicBlock> & blocks)1250 C2Buffer::C2Buffer(const std::vector<C2ConstGraphicBlock> &blocks)
1251 : mImpl(new Impl(this, blocks)) {}
1252
data() const1253 const C2BufferData C2Buffer::data() const { return mImpl->data(); }
1254
registerOnDestroyNotify(OnDestroyNotify onDestroyNotify,void * arg)1255 c2_status_t C2Buffer::registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
1256 return mImpl->registerOnDestroyNotify(onDestroyNotify, arg);
1257 }
1258
unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify,void * arg)1259 c2_status_t C2Buffer::unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
1260 return mImpl->unregisterOnDestroyNotify(onDestroyNotify, arg);
1261 }
1262
info() const1263 const std::vector<std::shared_ptr<const C2Info>> C2Buffer::info() const {
1264 return mImpl->info();
1265 }
1266
setInfo(const std::shared_ptr<C2Info> & info)1267 c2_status_t C2Buffer::setInfo(const std::shared_ptr<C2Info> &info) {
1268 return mImpl->setInfo(info);
1269 }
1270
hasInfo(C2Param::Type index) const1271 bool C2Buffer::hasInfo(C2Param::Type index) const {
1272 return mImpl->hasInfo(index);
1273 }
1274
getInfo(C2Param::Type index) const1275 std::shared_ptr<const C2Info> C2Buffer::getInfo(C2Param::Type index) const {
1276 return mImpl->getInfo(index);
1277 }
1278
removeInfo(C2Param::Type index)1279 std::shared_ptr<C2Info> C2Buffer::removeInfo(C2Param::Type index) {
1280 return mImpl->removeInfo(index);
1281 }
1282
1283 // static
CreateLinearBuffer(const C2ConstLinearBlock & block)1284 std::shared_ptr<C2Buffer> C2Buffer::CreateLinearBuffer(const C2ConstLinearBlock &block) {
1285 return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
1286 }
1287
1288 // static
CreateGraphicBuffer(const C2ConstGraphicBlock & block)1289 std::shared_ptr<C2Buffer> C2Buffer::CreateGraphicBuffer(const C2ConstGraphicBlock &block) {
1290 return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
1291 }
1292
1293