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