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