1348 lines
46 KiB
C++
1348 lines
46 KiB
C++
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
//#define LOG_NDEBUG 0
|
|
#define LOG_TAG "C2Buffer"
|
|
#include <utils/Log.h>
|
|
|
|
#include <list>
|
|
#include <map>
|
|
#include <mutex>
|
|
|
|
#include <C2AllocatorBlob.h>
|
|
#include <C2AllocatorGralloc.h>
|
|
#include <C2AllocatorIon.h>
|
|
#include <C2BufferPriv.h>
|
|
#include <C2BlockInternal.h>
|
|
#include <C2PlatformSupport.h>
|
|
#include <bufferpool/ClientManager.h>
|
|
|
|
namespace {
|
|
|
|
using android::C2AllocatorBlob;
|
|
using android::C2AllocatorGralloc;
|
|
using android::C2AllocatorIon;
|
|
using android::hardware::media::bufferpool::BufferPoolData;
|
|
using android::hardware::media::bufferpool::V2_0::ResultStatus;
|
|
using android::hardware::media::bufferpool::V2_0::implementation::BufferPoolAllocation;
|
|
using android::hardware::media::bufferpool::V2_0::implementation::BufferPoolAllocator;
|
|
using android::hardware::media::bufferpool::V2_0::implementation::ClientManager;
|
|
using android::hardware::media::bufferpool::V2_0::implementation::ConnectionId;
|
|
using android::hardware::media::bufferpool::V2_0::implementation::INVALID_CONNECTIONID;
|
|
|
|
// This anonymous namespace contains the helper classes that allow our implementation to create
|
|
// block/buffer objects.
|
|
//
|
|
// Inherit from the parent, share with the friend.
|
|
class ReadViewBuddy : public C2ReadView {
|
|
using C2ReadView::C2ReadView;
|
|
friend class ::C2ConstLinearBlock;
|
|
};
|
|
|
|
class WriteViewBuddy : public C2WriteView {
|
|
using C2WriteView::C2WriteView;
|
|
friend class ::C2LinearBlock;
|
|
};
|
|
|
|
class ConstLinearBlockBuddy : public C2ConstLinearBlock {
|
|
using C2ConstLinearBlock::C2ConstLinearBlock;
|
|
friend class ::C2LinearBlock;
|
|
};
|
|
|
|
class LinearBlockBuddy : public C2LinearBlock {
|
|
using C2LinearBlock::C2LinearBlock;
|
|
friend class ::C2BasicLinearBlockPool;
|
|
};
|
|
|
|
class AcquirableReadViewBuddy : public C2Acquirable<C2ReadView> {
|
|
using C2Acquirable::C2Acquirable;
|
|
friend class ::C2ConstLinearBlock;
|
|
};
|
|
|
|
class AcquirableWriteViewBuddy : public C2Acquirable<C2WriteView> {
|
|
using C2Acquirable::C2Acquirable;
|
|
friend class ::C2LinearBlock;
|
|
};
|
|
|
|
class GraphicViewBuddy : public C2GraphicView {
|
|
using C2GraphicView::C2GraphicView;
|
|
friend class ::C2ConstGraphicBlock;
|
|
friend class ::C2GraphicBlock;
|
|
};
|
|
|
|
class AcquirableConstGraphicViewBuddy : public C2Acquirable<const C2GraphicView> {
|
|
using C2Acquirable::C2Acquirable;
|
|
friend class ::C2ConstGraphicBlock;
|
|
};
|
|
|
|
class AcquirableGraphicViewBuddy : public C2Acquirable<C2GraphicView> {
|
|
using C2Acquirable::C2Acquirable;
|
|
friend class ::C2GraphicBlock;
|
|
};
|
|
|
|
class ConstGraphicBlockBuddy : public C2ConstGraphicBlock {
|
|
using C2ConstGraphicBlock::C2ConstGraphicBlock;
|
|
friend class ::C2GraphicBlock;
|
|
};
|
|
|
|
class GraphicBlockBuddy : public C2GraphicBlock {
|
|
using C2GraphicBlock::C2GraphicBlock;
|
|
friend class ::C2BasicGraphicBlockPool;
|
|
};
|
|
|
|
class BufferDataBuddy : public C2BufferData {
|
|
using C2BufferData::C2BufferData;
|
|
friend class ::C2Buffer;
|
|
friend class ::C2InfoBuffer;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
/* ========================================== 1D BLOCK ========================================= */
|
|
|
|
/**
|
|
* This class is the base class for all 1D block and view implementations.
|
|
*
|
|
* This is basically just a placeholder for the underlying 1D allocation and the range of the
|
|
* alloted portion to this block. There is also a placeholder for a blockpool data.
|
|
*/
|
|
class C2_HIDE _C2Block1DImpl : public _C2LinearRangeAspect {
|
|
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)
|
|
: _C2LinearRangeAspect(alloc.get(), offset, size),
|
|
mAllocation(alloc),
|
|
mPoolData(poolData) { }
|
|
|
|
_C2Block1DImpl(const _C2Block1DImpl &other, size_t offset = 0, size_t size = ~(size_t)0)
|
|
: _C2LinearRangeAspect(&other, offset, size),
|
|
mAllocation(other.mAllocation),
|
|
mPoolData(other.mPoolData) { }
|
|
|
|
/** returns pool data */
|
|
std::shared_ptr<_C2BlockPoolData> poolData() const {
|
|
return mPoolData;
|
|
}
|
|
|
|
/** returns native handle */
|
|
const C2Handle *handle() const {
|
|
return mAllocation ? mAllocation->handle() : nullptr;
|
|
}
|
|
|
|
/** returns the allocator's ID */
|
|
C2Allocator::id_t getAllocatorId() const {
|
|
// BAD_ID can only happen if this Impl class is initialized for a view - never for a block.
|
|
return mAllocation ? mAllocation->getAllocatorId() : C2Allocator::BAD_ID;
|
|
}
|
|
|
|
std::shared_ptr<C2LinearAllocation> getAllocation() const {
|
|
return mAllocation;
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<C2LinearAllocation> mAllocation;
|
|
std::shared_ptr<_C2BlockPoolData> mPoolData;
|
|
};
|
|
|
|
/**
|
|
* This class contains the mapped data pointer, and the potential error.
|
|
*
|
|
* range is the mapped range of the underlying allocation (which is part of the allotted
|
|
* range).
|
|
*/
|
|
class C2_HIDE _C2MappedBlock1DImpl : public _C2Block1DImpl {
|
|
public:
|
|
_C2MappedBlock1DImpl(const _C2Block1DImpl &block, uint8_t *data,
|
|
size_t offset = 0, size_t size = ~(size_t)0)
|
|
: _C2Block1DImpl(block, offset, size), mData(data), mError(C2_OK) { }
|
|
|
|
_C2MappedBlock1DImpl(c2_status_t error)
|
|
: _C2Block1DImpl(nullptr), mData(nullptr), mError(error) {
|
|
// CHECK(error != C2_OK);
|
|
}
|
|
|
|
const uint8_t *data() const {
|
|
return mData;
|
|
}
|
|
|
|
uint8_t *data() {
|
|
return mData;
|
|
}
|
|
|
|
c2_status_t error() const {
|
|
return mError;
|
|
}
|
|
|
|
private:
|
|
uint8_t *mData;
|
|
c2_status_t mError;
|
|
};
|
|
|
|
/**
|
|
* Block implementation.
|
|
*/
|
|
class C2Block1D::Impl : public _C2Block1DImpl {
|
|
using _C2Block1DImpl::_C2Block1DImpl;
|
|
};
|
|
|
|
const C2Handle *C2Block1D::handle() const {
|
|
return mImpl->handle();
|
|
};
|
|
|
|
C2Allocator::id_t C2Block1D::getAllocatorId() const {
|
|
return mImpl->getAllocatorId();
|
|
};
|
|
|
|
C2Block1D::C2Block1D(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range)
|
|
// always clamp subrange to parent (impl) range for safety
|
|
: _C2LinearRangeAspect(impl.get(), range.offset(), range.size()), mImpl(impl) {
|
|
}
|
|
|
|
/**
|
|
* Read view implementation.
|
|
*
|
|
* range of Impl is the mapped range of the underlying allocation (which is part of the allotted
|
|
* range). range of View is 0 to capacity() (not represented as an actual range). This maps to a
|
|
* subrange of Impl range starting at mImpl->offset() + _mOffset.
|
|
*/
|
|
class C2ReadView::Impl : public _C2MappedBlock1DImpl {
|
|
using _C2MappedBlock1DImpl::_C2MappedBlock1DImpl;
|
|
};
|
|
|
|
C2ReadView::C2ReadView(std::shared_ptr<Impl> impl, uint32_t offset, uint32_t size)
|
|
: _C2LinearCapacityAspect(C2LinearCapacity(impl->size()).range(offset, size).size()),
|
|
mImpl(impl),
|
|
mOffset(C2LinearCapacity(impl->size()).range(offset, size).offset()) { }
|
|
|
|
C2ReadView::C2ReadView(c2_status_t error)
|
|
: _C2LinearCapacityAspect(0u), mImpl(std::make_shared<Impl>(error)), mOffset(0u) {
|
|
// CHECK(error != C2_OK);
|
|
}
|
|
|
|
const uint8_t *C2ReadView::data() const {
|
|
return mImpl->error() ? nullptr : mImpl->data() + mOffset;
|
|
}
|
|
|
|
c2_status_t C2ReadView::error() const {
|
|
return mImpl->error();
|
|
}
|
|
|
|
C2ReadView C2ReadView::subView(size_t offset, size_t size) const {
|
|
C2LinearRange subRange(*this, offset, size);
|
|
return C2ReadView(mImpl, mOffset + subRange.offset(), subRange.size());
|
|
}
|
|
|
|
/**
|
|
* Write view implementation.
|
|
*/
|
|
class C2WriteView::Impl : public _C2MappedBlock1DImpl {
|
|
using _C2MappedBlock1DImpl::_C2MappedBlock1DImpl;
|
|
};
|
|
|
|
C2WriteView::C2WriteView(std::shared_ptr<Impl> impl)
|
|
// UGLY: _C2LinearRangeAspect requires a bona-fide object for capacity to prevent spoofing, so
|
|
// this is what we have to do.
|
|
// TODO: use childRange
|
|
: _C2EditableLinearRangeAspect(std::make_unique<C2LinearCapacity>(impl->size()).get()), mImpl(impl) { }
|
|
|
|
C2WriteView::C2WriteView(c2_status_t error)
|
|
: _C2EditableLinearRangeAspect(nullptr), mImpl(std::make_shared<Impl>(error)) {}
|
|
|
|
uint8_t *C2WriteView::base() { return mImpl->data(); }
|
|
|
|
uint8_t *C2WriteView::data() { return mImpl->data() + offset(); }
|
|
|
|
c2_status_t C2WriteView::error() const { return mImpl->error(); }
|
|
|
|
/**
|
|
* Const linear block implementation.
|
|
*/
|
|
C2ConstLinearBlock::C2ConstLinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range, C2Fence fence)
|
|
: C2Block1D(impl, range), mFence(fence) { }
|
|
|
|
C2Acquirable<C2ReadView> C2ConstLinearBlock::map() const {
|
|
void *base = nullptr;
|
|
uint32_t len = size();
|
|
c2_status_t error = mImpl->getAllocation()->map(
|
|
offset(), len, { C2MemoryUsage::CPU_READ, 0 }, nullptr, &base);
|
|
// TODO: wait on fence
|
|
if (error == C2_OK) {
|
|
std::shared_ptr<ReadViewBuddy::Impl> rvi = std::shared_ptr<ReadViewBuddy::Impl>(
|
|
new ReadViewBuddy::Impl(*mImpl, (uint8_t *)base, offset(), len),
|
|
[base, len](ReadViewBuddy::Impl *i) {
|
|
(void)i->getAllocation()->unmap(base, len, nullptr);
|
|
delete i;
|
|
});
|
|
return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(rvi, 0, len));
|
|
} else {
|
|
return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(error));
|
|
}
|
|
}
|
|
|
|
C2ConstLinearBlock C2ConstLinearBlock::subBlock(size_t offset_, size_t size_) const {
|
|
C2LinearRange subRange(*mImpl, offset_, size_);
|
|
return C2ConstLinearBlock(mImpl, subRange, mFence);
|
|
}
|
|
|
|
/**
|
|
* Linear block implementation.
|
|
*/
|
|
C2LinearBlock::C2LinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range)
|
|
: C2Block1D(impl, range) { }
|
|
|
|
C2Acquirable<C2WriteView> C2LinearBlock::map() {
|
|
void *base = nullptr;
|
|
uint32_t len = size();
|
|
c2_status_t error = mImpl->getAllocation()->map(
|
|
offset(), len, { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, nullptr, &base);
|
|
// TODO: wait on fence
|
|
if (error == C2_OK) {
|
|
std::shared_ptr<WriteViewBuddy::Impl> rvi = std::shared_ptr<WriteViewBuddy::Impl>(
|
|
new WriteViewBuddy::Impl(*mImpl, (uint8_t *)base, 0, len),
|
|
[base, len](WriteViewBuddy::Impl *i) {
|
|
(void)i->getAllocation()->unmap(base, len, nullptr);
|
|
delete i;
|
|
});
|
|
return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(rvi));
|
|
} else {
|
|
return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(error));
|
|
}
|
|
}
|
|
|
|
C2ConstLinearBlock C2LinearBlock::share(size_t offset_, size_t size_, C2Fence fence) {
|
|
return ConstLinearBlockBuddy(mImpl, C2LinearRange(*this, offset_, size_), fence);
|
|
}
|
|
|
|
C2BasicLinearBlockPool::C2BasicLinearBlockPool(
|
|
const std::shared_ptr<C2Allocator> &allocator)
|
|
: mAllocator(allocator) { }
|
|
|
|
c2_status_t C2BasicLinearBlockPool::fetchLinearBlock(
|
|
uint32_t capacity,
|
|
C2MemoryUsage usage,
|
|
std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
|
|
block->reset();
|
|
|
|
std::shared_ptr<C2LinearAllocation> alloc;
|
|
c2_status_t err = mAllocator->newLinearAllocation(capacity, usage, &alloc);
|
|
if (err != C2_OK) {
|
|
return err;
|
|
}
|
|
|
|
*block = _C2BlockFactory::CreateLinearBlock(alloc);
|
|
|
|
return C2_OK;
|
|
}
|
|
|
|
struct C2_HIDE C2PooledBlockPoolData : _C2BlockPoolData {
|
|
|
|
virtual type_t getType() const override {
|
|
return TYPE_BUFFERPOOL;
|
|
}
|
|
|
|
void getBufferPoolData(std::shared_ptr<BufferPoolData> *data) const {
|
|
*data = mData;
|
|
}
|
|
|
|
C2PooledBlockPoolData(const std::shared_ptr<BufferPoolData> &data) : mData(data) {}
|
|
|
|
virtual ~C2PooledBlockPoolData() override {}
|
|
|
|
private:
|
|
std::shared_ptr<BufferPoolData> mData;
|
|
};
|
|
|
|
bool _C2BlockFactory::GetBufferPoolData(
|
|
const std::shared_ptr<const _C2BlockPoolData> &data,
|
|
std::shared_ptr<BufferPoolData> *bufferPoolData) {
|
|
if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERPOOL) {
|
|
const std::shared_ptr<const C2PooledBlockPoolData> poolData =
|
|
std::static_pointer_cast<const C2PooledBlockPoolData>(data);
|
|
poolData->getBufferPoolData(bufferPoolData);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
|
|
const std::shared_ptr<C2LinearAllocation> &alloc,
|
|
const std::shared_ptr<_C2BlockPoolData> &data, size_t offset, size_t size) {
|
|
std::shared_ptr<C2Block1D::Impl> impl =
|
|
std::make_shared<C2Block1D::Impl>(alloc, data, offset, size);
|
|
return std::shared_ptr<C2LinearBlock>(new C2LinearBlock(impl, *impl));
|
|
}
|
|
|
|
std::shared_ptr<_C2BlockPoolData> _C2BlockFactory::GetLinearBlockPoolData(
|
|
const C2Block1D &block) {
|
|
if (block.mImpl) {
|
|
return block.mImpl->poolData();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
|
|
const C2Handle *handle) {
|
|
// TODO: get proper allocator? and mutex?
|
|
static std::shared_ptr<C2Allocator> sAllocator = []{
|
|
std::shared_ptr<C2Allocator> allocator;
|
|
std::shared_ptr<C2AllocatorStore> allocatorStore = android::GetCodec2PlatformAllocatorStore();
|
|
allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
|
|
|
|
return allocator;
|
|
}();
|
|
|
|
if (sAllocator == nullptr)
|
|
return nullptr;
|
|
|
|
bool isValidHandle = sAllocator->checkHandle(handle);
|
|
|
|
std::shared_ptr<C2LinearAllocation> alloc;
|
|
if (isValidHandle) {
|
|
c2_status_t err = sAllocator->priorLinearAllocation(handle, &alloc);
|
|
if (err == C2_OK) {
|
|
std::shared_ptr<C2LinearBlock> block = _C2BlockFactory::CreateLinearBlock(alloc);
|
|
return block;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
|
|
const C2Handle *cHandle, const std::shared_ptr<BufferPoolData> &data) {
|
|
// TODO: get proper allocator? and mutex?
|
|
static std::shared_ptr<C2Allocator> sAllocator = []{
|
|
std::shared_ptr<C2Allocator> allocator;
|
|
std::shared_ptr<C2AllocatorStore> allocatorStore = android::GetCodec2PlatformAllocatorStore();
|
|
allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
|
|
|
|
return allocator;
|
|
}();
|
|
|
|
if (sAllocator == nullptr)
|
|
return nullptr;
|
|
|
|
bool isValidHandle = sAllocator->checkHandle(cHandle);
|
|
|
|
std::shared_ptr<C2LinearAllocation> alloc;
|
|
if (isValidHandle) {
|
|
c2_status_t err = sAllocator->priorLinearAllocation(cHandle, &alloc);
|
|
const std::shared_ptr<C2PooledBlockPoolData> poolData =
|
|
std::make_shared<C2PooledBlockPoolData>(data);
|
|
if (err == C2_OK && poolData) {
|
|
// TODO: config params?
|
|
std::shared_ptr<C2LinearBlock> block =
|
|
_C2BlockFactory::CreateLinearBlock(alloc, poolData);
|
|
return block;
|
|
}
|
|
}
|
|
return nullptr;
|
|
};
|
|
|
|
/**
|
|
* Wrapped C2Allocator which is injected to buffer pool on behalf of
|
|
* C2BlockPool.
|
|
*/
|
|
class _C2BufferPoolAllocator : public BufferPoolAllocator {
|
|
public:
|
|
_C2BufferPoolAllocator(const std::shared_ptr<C2Allocator> &allocator)
|
|
: mAllocator(allocator) {}
|
|
|
|
~_C2BufferPoolAllocator() override {}
|
|
|
|
ResultStatus allocate(const std::vector<uint8_t> ¶ms,
|
|
std::shared_ptr<BufferPoolAllocation> *alloc,
|
|
size_t *allocSize) override;
|
|
|
|
bool compatible(const std::vector<uint8_t> &newParams,
|
|
const std::vector<uint8_t> &oldParams) override;
|
|
|
|
// Methods for codec2 component (C2BlockPool).
|
|
/**
|
|
* Transforms linear allocation parameters for C2Allocator to parameters
|
|
* for buffer pool.
|
|
*
|
|
* @param capacity size of linear allocation
|
|
* @param usage memory usage pattern for linear allocation
|
|
* @param params allocation parameters for buffer pool
|
|
*/
|
|
void getLinearParams(uint32_t capacity, C2MemoryUsage usage,
|
|
std::vector<uint8_t> *params);
|
|
|
|
/**
|
|
* Transforms graphic allocation parameters for C2Allocator to parameters
|
|
* for buffer pool.
|
|
*
|
|
* @param width width of graphic allocation
|
|
* @param height height of graphic allocation
|
|
* @param format color format of graphic allocation
|
|
* @param params allocation parameter for buffer pool
|
|
*/
|
|
void getGraphicParams(uint32_t width, uint32_t height,
|
|
uint32_t format, C2MemoryUsage usage,
|
|
std::vector<uint8_t> *params);
|
|
|
|
/**
|
|
* Transforms an existing native handle to an C2LinearAllcation.
|
|
* Wrapper to C2Allocator#priorLinearAllocation
|
|
*/
|
|
c2_status_t priorLinearAllocation(
|
|
const C2Handle *handle,
|
|
std::shared_ptr<C2LinearAllocation> *c2Allocation);
|
|
|
|
/**
|
|
* Transforms an existing native handle to an C2GraphicAllcation.
|
|
* Wrapper to C2Allocator#priorGraphicAllocation
|
|
*/
|
|
c2_status_t priorGraphicAllocation(
|
|
const C2Handle *handle,
|
|
std::shared_ptr<C2GraphicAllocation> *c2Allocation);
|
|
|
|
private:
|
|
static constexpr int kMaxIntParams = 5; // large enough number;
|
|
|
|
enum AllocType : uint8_t {
|
|
ALLOC_NONE = 0,
|
|
|
|
ALLOC_LINEAR,
|
|
ALLOC_GRAPHIC,
|
|
};
|
|
|
|
union AllocParams {
|
|
struct {
|
|
AllocType allocType;
|
|
C2MemoryUsage usage;
|
|
uint32_t params[kMaxIntParams];
|
|
} data;
|
|
uint8_t array[0];
|
|
|
|
AllocParams() : data{ALLOC_NONE, {0, 0}, {0}} {}
|
|
AllocParams(C2MemoryUsage usage, uint32_t capacity)
|
|
: data{ALLOC_LINEAR, usage, {[0] = capacity}} {}
|
|
AllocParams(
|
|
C2MemoryUsage usage,
|
|
uint32_t width, uint32_t height, uint32_t format)
|
|
: data{ALLOC_GRAPHIC, usage, {width, height, format}} {}
|
|
};
|
|
|
|
const std::shared_ptr<C2Allocator> mAllocator;
|
|
};
|
|
|
|
struct LinearAllocationDtor {
|
|
LinearAllocationDtor(const std::shared_ptr<C2LinearAllocation> &alloc)
|
|
: mAllocation(alloc) {}
|
|
|
|
void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
|
|
|
|
const std::shared_ptr<C2LinearAllocation> mAllocation;
|
|
};
|
|
|
|
struct GraphicAllocationDtor {
|
|
GraphicAllocationDtor(const std::shared_ptr<C2GraphicAllocation> &alloc)
|
|
: mAllocation(alloc) {}
|
|
|
|
void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
|
|
|
|
const std::shared_ptr<C2GraphicAllocation> mAllocation;
|
|
};
|
|
|
|
ResultStatus _C2BufferPoolAllocator::allocate(
|
|
const std::vector<uint8_t> ¶ms,
|
|
std::shared_ptr<BufferPoolAllocation> *alloc,
|
|
size_t *allocSize) {
|
|
AllocParams c2Params;
|
|
memcpy(&c2Params, params.data(), std::min(sizeof(AllocParams), params.size()));
|
|
c2_status_t status = C2_BAD_VALUE;
|
|
switch(c2Params.data.allocType) {
|
|
case ALLOC_NONE:
|
|
break;
|
|
case ALLOC_LINEAR: {
|
|
std::shared_ptr<C2LinearAllocation> c2Linear;
|
|
status = mAllocator->newLinearAllocation(
|
|
c2Params.data.params[0], c2Params.data.usage, &c2Linear);
|
|
if (status == C2_OK && c2Linear) {
|
|
BufferPoolAllocation *ptr = new BufferPoolAllocation(c2Linear->handle());
|
|
if (ptr) {
|
|
*alloc = std::shared_ptr<BufferPoolAllocation>(
|
|
ptr, LinearAllocationDtor(c2Linear));
|
|
if (*alloc) {
|
|
*allocSize = (size_t)c2Params.data.params[0];
|
|
return ResultStatus::OK;
|
|
}
|
|
delete ptr;
|
|
}
|
|
return ResultStatus::NO_MEMORY;
|
|
}
|
|
break;
|
|
}
|
|
case ALLOC_GRAPHIC: {
|
|
std::shared_ptr<C2GraphicAllocation> c2Graphic;
|
|
status = mAllocator->newGraphicAllocation(
|
|
c2Params.data.params[0],
|
|
c2Params.data.params[1],
|
|
c2Params.data.params[2],
|
|
c2Params.data.usage, &c2Graphic);
|
|
if (status == C2_OK && c2Graphic) {
|
|
BufferPoolAllocation *ptr = new BufferPoolAllocation(c2Graphic->handle());
|
|
if (ptr) {
|
|
*alloc = std::shared_ptr<BufferPoolAllocation>(
|
|
ptr, GraphicAllocationDtor(c2Graphic));
|
|
if (*alloc) {
|
|
*allocSize = c2Params.data.params[0] * c2Params.data.params[1];
|
|
return ResultStatus::OK;
|
|
}
|
|
delete ptr;
|
|
}
|
|
return ResultStatus::NO_MEMORY;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return ResultStatus::CRITICAL_ERROR;
|
|
}
|
|
|
|
bool _C2BufferPoolAllocator::compatible(
|
|
const std::vector<uint8_t> &newParams,
|
|
const std::vector<uint8_t> &oldParams) {
|
|
AllocParams newAlloc;
|
|
AllocParams oldAlloc;
|
|
memcpy(&newAlloc, newParams.data(), std::min(sizeof(AllocParams), newParams.size()));
|
|
memcpy(&oldAlloc, oldParams.data(), std::min(sizeof(AllocParams), oldParams.size()));
|
|
|
|
// TODO: support not exact matching. e.g) newCapacity < oldCapacity
|
|
if (newAlloc.data.allocType == oldAlloc.data.allocType &&
|
|
newAlloc.data.usage.expected == oldAlloc.data.usage.expected) {
|
|
for (int i = 0; i < kMaxIntParams; ++i) {
|
|
if (newAlloc.data.params[i] != oldAlloc.data.params[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void _C2BufferPoolAllocator::getLinearParams(
|
|
uint32_t capacity, C2MemoryUsage usage, std::vector<uint8_t> *params) {
|
|
AllocParams c2Params(usage, capacity);
|
|
params->assign(c2Params.array, c2Params.array + sizeof(AllocParams));
|
|
}
|
|
|
|
void _C2BufferPoolAllocator::getGraphicParams(
|
|
uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
|
|
std::vector<uint8_t> *params) {
|
|
AllocParams c2Params(usage, width, height, format);
|
|
params->assign(c2Params.array, c2Params.array + sizeof(AllocParams));
|
|
}
|
|
|
|
c2_status_t _C2BufferPoolAllocator::priorLinearAllocation(
|
|
const C2Handle *handle,
|
|
std::shared_ptr<C2LinearAllocation> *c2Allocation) {
|
|
return mAllocator->priorLinearAllocation(handle, c2Allocation);
|
|
}
|
|
|
|
c2_status_t _C2BufferPoolAllocator::priorGraphicAllocation(
|
|
const C2Handle *handle,
|
|
std::shared_ptr<C2GraphicAllocation> *c2Allocation) {
|
|
return mAllocator->priorGraphicAllocation(handle, c2Allocation);
|
|
}
|
|
|
|
class C2PooledBlockPool::Impl {
|
|
public:
|
|
Impl(const std::shared_ptr<C2Allocator> &allocator)
|
|
: mInit(C2_OK),
|
|
mBufferPoolManager(ClientManager::getInstance()),
|
|
mAllocator(std::make_shared<_C2BufferPoolAllocator>(allocator)) {
|
|
if (mAllocator && mBufferPoolManager) {
|
|
if (mBufferPoolManager->create(
|
|
mAllocator, &mConnectionId) == ResultStatus::OK) {
|
|
return;
|
|
}
|
|
}
|
|
mInit = C2_NO_INIT;
|
|
}
|
|
|
|
~Impl() {
|
|
if (mInit == C2_OK) {
|
|
mBufferPoolManager->close(mConnectionId);
|
|
}
|
|
}
|
|
|
|
c2_status_t fetchLinearBlock(
|
|
uint32_t capacity, C2MemoryUsage usage,
|
|
std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
|
|
block->reset();
|
|
if (mInit != C2_OK) {
|
|
return mInit;
|
|
}
|
|
std::vector<uint8_t> params;
|
|
mAllocator->getLinearParams(capacity, usage, ¶ms);
|
|
std::shared_ptr<BufferPoolData> bufferPoolData;
|
|
native_handle_t *cHandle = nullptr;
|
|
ResultStatus status = mBufferPoolManager->allocate(
|
|
mConnectionId, params, &cHandle, &bufferPoolData);
|
|
if (status == ResultStatus::OK) {
|
|
std::shared_ptr<C2LinearAllocation> alloc;
|
|
std::shared_ptr<C2PooledBlockPoolData> poolData =
|
|
std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
|
|
c2_status_t err = mAllocator->priorLinearAllocation(cHandle, &alloc);
|
|
if (err == C2_OK && poolData && alloc) {
|
|
*block = _C2BlockFactory::CreateLinearBlock(alloc, poolData, 0, capacity);
|
|
if (*block) {
|
|
return C2_OK;
|
|
}
|
|
}
|
|
return C2_NO_MEMORY;
|
|
}
|
|
if (status == ResultStatus::NO_MEMORY) {
|
|
return C2_NO_MEMORY;
|
|
}
|
|
return C2_CORRUPTED;
|
|
}
|
|
|
|
c2_status_t fetchGraphicBlock(
|
|
uint32_t width, uint32_t height, uint32_t format,
|
|
C2MemoryUsage usage,
|
|
std::shared_ptr<C2GraphicBlock> *block) {
|
|
block->reset();
|
|
if (mInit != C2_OK) {
|
|
return mInit;
|
|
}
|
|
std::vector<uint8_t> params;
|
|
mAllocator->getGraphicParams(width, height, format, usage, ¶ms);
|
|
std::shared_ptr<BufferPoolData> bufferPoolData;
|
|
native_handle_t *cHandle = nullptr;
|
|
ResultStatus status = mBufferPoolManager->allocate(
|
|
mConnectionId, params, &cHandle, &bufferPoolData);
|
|
if (status == ResultStatus::OK) {
|
|
std::shared_ptr<C2GraphicAllocation> alloc;
|
|
std::shared_ptr<C2PooledBlockPoolData> poolData =
|
|
std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
|
|
c2_status_t err = mAllocator->priorGraphicAllocation(
|
|
cHandle, &alloc);
|
|
if (err == C2_OK && poolData && alloc) {
|
|
*block = _C2BlockFactory::CreateGraphicBlock(
|
|
alloc, poolData, C2Rect(width, height));
|
|
if (*block) {
|
|
return C2_OK;
|
|
}
|
|
}
|
|
return C2_NO_MEMORY;
|
|
}
|
|
if (status == ResultStatus::NO_MEMORY) {
|
|
return C2_NO_MEMORY;
|
|
}
|
|
return C2_CORRUPTED;
|
|
}
|
|
|
|
ConnectionId getConnectionId() {
|
|
return mInit != C2_OK ? INVALID_CONNECTIONID : mConnectionId;
|
|
}
|
|
|
|
private:
|
|
c2_status_t mInit;
|
|
const android::sp<ClientManager> mBufferPoolManager;
|
|
ConnectionId mConnectionId; // locally
|
|
const std::shared_ptr<_C2BufferPoolAllocator> mAllocator;
|
|
};
|
|
|
|
C2PooledBlockPool::C2PooledBlockPool(
|
|
const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId)
|
|
: mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {}
|
|
|
|
C2PooledBlockPool::~C2PooledBlockPool() {
|
|
}
|
|
|
|
c2_status_t C2PooledBlockPool::fetchLinearBlock(
|
|
uint32_t capacity,
|
|
C2MemoryUsage usage,
|
|
std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
|
|
if (mImpl) {
|
|
return mImpl->fetchLinearBlock(capacity, usage, block);
|
|
}
|
|
return C2_CORRUPTED;
|
|
}
|
|
|
|
c2_status_t C2PooledBlockPool::fetchGraphicBlock(
|
|
uint32_t width,
|
|
uint32_t height,
|
|
uint32_t format,
|
|
C2MemoryUsage usage,
|
|
std::shared_ptr<C2GraphicBlock> *block) {
|
|
if (mImpl) {
|
|
return mImpl->fetchGraphicBlock(width, height, format, usage, block);
|
|
}
|
|
return C2_CORRUPTED;
|
|
}
|
|
|
|
int64_t C2PooledBlockPool::getConnectionId() {
|
|
if (mImpl) {
|
|
return mImpl->getConnectionId();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ========================================== 2D BLOCK ========================================= */
|
|
|
|
/**
|
|
* Implementation that is shared between all 2D blocks and views.
|
|
*
|
|
* For blocks' Impl's crop is always the allotted crop, even if it is a sub block.
|
|
*
|
|
* For views' Impl's crop is the mapped portion - which for now is always the
|
|
* allotted crop.
|
|
*/
|
|
class C2_HIDE _C2Block2DImpl : public _C2PlanarSectionAspect {
|
|
public:
|
|
/**
|
|
* Impl's crop is always the or part of the allotted crop of the allocation.
|
|
*/
|
|
_C2Block2DImpl(const std::shared_ptr<C2GraphicAllocation> &alloc,
|
|
const std::shared_ptr<_C2BlockPoolData> &poolData = nullptr,
|
|
const C2Rect &allottedCrop = C2Rect(~0u, ~0u))
|
|
: _C2PlanarSectionAspect(alloc.get(), allottedCrop),
|
|
mAllocation(alloc),
|
|
mPoolData(poolData) { }
|
|
|
|
virtual ~_C2Block2DImpl() = default;
|
|
|
|
/** returns pool data */
|
|
std::shared_ptr<_C2BlockPoolData> poolData() const {
|
|
return mPoolData;
|
|
}
|
|
|
|
/** returns native handle */
|
|
const C2Handle *handle() const {
|
|
return mAllocation ? mAllocation->handle() : nullptr;
|
|
}
|
|
|
|
/** returns the allocator's ID */
|
|
C2Allocator::id_t getAllocatorId() const {
|
|
// BAD_ID can only happen if this Impl class is initialized for a view - never for a block.
|
|
return mAllocation ? mAllocation->getAllocatorId() : C2Allocator::BAD_ID;
|
|
}
|
|
|
|
std::shared_ptr<C2GraphicAllocation> getAllocation() const {
|
|
return mAllocation;
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<C2GraphicAllocation> mAllocation;
|
|
std::shared_ptr<_C2BlockPoolData> mPoolData;
|
|
};
|
|
|
|
class C2_HIDE _C2MappingBlock2DImpl
|
|
: public _C2Block2DImpl, public std::enable_shared_from_this<_C2MappingBlock2DImpl> {
|
|
public:
|
|
using _C2Block2DImpl::_C2Block2DImpl;
|
|
|
|
virtual ~_C2MappingBlock2DImpl() override = default;
|
|
|
|
/**
|
|
* This class contains the mapped data pointer, and the potential error.
|
|
*/
|
|
struct Mapped {
|
|
private:
|
|
friend class _C2MappingBlock2DImpl;
|
|
|
|
Mapped(const std::shared_ptr<_C2Block2DImpl> &impl, bool writable, C2Fence *fence __unused)
|
|
: mImpl(impl), mWritable(writable) {
|
|
memset(mData, 0, sizeof(mData));
|
|
const C2Rect crop = mImpl->crop();
|
|
// gralloc requires mapping the whole region of interest as we cannot
|
|
// map multiple regions
|
|
mError = mImpl->getAllocation()->map(
|
|
crop,
|
|
{ C2MemoryUsage::CPU_READ, writable ? C2MemoryUsage::CPU_WRITE : 0 },
|
|
nullptr,
|
|
&mLayout,
|
|
mData);
|
|
if (mError != C2_OK) {
|
|
memset(&mLayout, 0, sizeof(mLayout));
|
|
memset(mData, 0, sizeof(mData));
|
|
memset(mOffsetData, 0, sizeof(mData));
|
|
} else {
|
|
// TODO: validate plane layout and
|
|
// adjust data pointers to the crop region's top left corner.
|
|
// fail if it is not on a subsampling boundary
|
|
for (size_t planeIx = 0; planeIx < mLayout.numPlanes; ++planeIx) {
|
|
const uint32_t colSampling = mLayout.planes[planeIx].colSampling;
|
|
const uint32_t rowSampling = mLayout.planes[planeIx].rowSampling;
|
|
if (crop.left % colSampling || crop.right() % colSampling
|
|
|| crop.top % rowSampling || crop.bottom() % rowSampling) {
|
|
// cannot calculate data pointer
|
|
mImpl->getAllocation()->unmap(mData, crop, nullptr);
|
|
memset(&mLayout, 0, sizeof(mLayout));
|
|
memset(mData, 0, sizeof(mData));
|
|
memset(mOffsetData, 0, sizeof(mData));
|
|
mError = C2_BAD_VALUE;
|
|
return;
|
|
}
|
|
mOffsetData[planeIx] =
|
|
mData[planeIx] + (ssize_t)crop.left * mLayout.planes[planeIx].colInc
|
|
+ (ssize_t)crop.top * mLayout.planes[planeIx].rowInc;
|
|
}
|
|
}
|
|
}
|
|
|
|
explicit Mapped(c2_status_t error)
|
|
: mImpl(nullptr), mWritable(false), mError(error) {
|
|
// CHECK(error != C2_OK);
|
|
memset(&mLayout, 0, sizeof(mLayout));
|
|
memset(mData, 0, sizeof(mData));
|
|
memset(mOffsetData, 0, sizeof(mData));
|
|
}
|
|
|
|
public:
|
|
~Mapped() {
|
|
if (mData[0] != nullptr) {
|
|
mImpl->getAllocation()->unmap(mData, mImpl->crop(), nullptr);
|
|
}
|
|
}
|
|
|
|
/** returns mapping status */
|
|
c2_status_t error() const { return mError; }
|
|
|
|
/** returns data pointer */
|
|
uint8_t *const *data() const { return mOffsetData; }
|
|
|
|
/** returns the plane layout */
|
|
C2PlanarLayout layout() const { return mLayout; }
|
|
|
|
/** returns whether the mapping is writable */
|
|
bool writable() const { return mWritable; }
|
|
|
|
private:
|
|
const std::shared_ptr<_C2Block2DImpl> mImpl;
|
|
bool mWritable;
|
|
c2_status_t mError;
|
|
uint8_t *mData[C2PlanarLayout::MAX_NUM_PLANES];
|
|
uint8_t *mOffsetData[C2PlanarLayout::MAX_NUM_PLANES];
|
|
C2PlanarLayout mLayout;
|
|
};
|
|
|
|
/**
|
|
* Maps the allotted region.
|
|
*
|
|
* If already mapped and it is currently in use, returns the existing mapping.
|
|
* If fence is provided, an acquire fence is stored there.
|
|
*/
|
|
std::shared_ptr<Mapped> map(bool writable, C2Fence *fence) {
|
|
std::lock_guard<std::mutex> lock(mMappedLock);
|
|
std::shared_ptr<Mapped> existing = mMapped.lock();
|
|
if (!existing) {
|
|
existing = std::shared_ptr<Mapped>(new Mapped(shared_from_this(), writable, fence));
|
|
mMapped = existing;
|
|
} else {
|
|
// if we mapped the region read-only, we cannot remap it read-write
|
|
if (writable && !existing->writable()) {
|
|
existing = std::shared_ptr<Mapped>(new Mapped(C2_CANNOT_DO));
|
|
}
|
|
if (fence != nullptr) {
|
|
*fence = C2Fence();
|
|
}
|
|
}
|
|
return existing;
|
|
}
|
|
|
|
private:
|
|
std::weak_ptr<Mapped> mMapped;
|
|
std::mutex mMappedLock;
|
|
};
|
|
|
|
class C2_HIDE _C2MappedBlock2DImpl : public _C2Block2DImpl {
|
|
public:
|
|
_C2MappedBlock2DImpl(const _C2Block2DImpl &impl,
|
|
std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping)
|
|
: _C2Block2DImpl(impl), mMapping(mapping) {
|
|
}
|
|
|
|
virtual ~_C2MappedBlock2DImpl() override = default;
|
|
|
|
std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping() const { return mMapping; }
|
|
|
|
private:
|
|
std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mMapping;
|
|
};
|
|
|
|
/**
|
|
* Block implementation.
|
|
*/
|
|
class C2Block2D::Impl : public _C2MappingBlock2DImpl {
|
|
public:
|
|
using _C2MappingBlock2DImpl::_C2MappingBlock2DImpl;
|
|
virtual ~Impl() override = default;
|
|
};
|
|
|
|
const C2Handle *C2Block2D::handle() const {
|
|
return mImpl->handle();
|
|
}
|
|
|
|
C2Allocator::id_t C2Block2D::getAllocatorId() const {
|
|
return mImpl->getAllocatorId();
|
|
}
|
|
|
|
C2Block2D::C2Block2D(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
|
|
// always clamp subsection to parent (impl) crop for safety
|
|
: _C2PlanarSectionAspect(impl.get(), section.crop()), mImpl(impl) {
|
|
}
|
|
|
|
/**
|
|
* Graphic view implementation.
|
|
*
|
|
* range of Impl is the mapped range of the underlying allocation. range of View is the current
|
|
* crop.
|
|
*/
|
|
class C2GraphicView::Impl : public _C2MappedBlock2DImpl {
|
|
public:
|
|
using _C2MappedBlock2DImpl::_C2MappedBlock2DImpl;
|
|
virtual ~Impl() override = default;
|
|
};
|
|
|
|
C2GraphicView::C2GraphicView(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
|
|
: _C2EditablePlanarSectionAspect(impl.get(), section.crop()), mImpl(impl) {
|
|
}
|
|
|
|
const uint8_t *const *C2GraphicView::data() const {
|
|
return mImpl->mapping()->data();
|
|
}
|
|
|
|
uint8_t *const *C2GraphicView::data() {
|
|
return mImpl->mapping()->data();
|
|
}
|
|
|
|
const C2PlanarLayout C2GraphicView::layout() const {
|
|
return mImpl->mapping()->layout();
|
|
}
|
|
|
|
const C2GraphicView C2GraphicView::subView(const C2Rect &rect) const {
|
|
return C2GraphicView(mImpl, C2PlanarSection(*mImpl, rect));
|
|
}
|
|
|
|
C2GraphicView C2GraphicView::subView(const C2Rect &rect) {
|
|
return C2GraphicView(mImpl, C2PlanarSection(*mImpl, rect));
|
|
}
|
|
|
|
c2_status_t C2GraphicView::error() const {
|
|
return mImpl->mapping()->error();
|
|
}
|
|
|
|
/**
|
|
* Const graphic block implementation.
|
|
*/
|
|
C2ConstGraphicBlock::C2ConstGraphicBlock(
|
|
std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion, C2Fence fence)
|
|
: C2Block2D(impl, section), mFence(fence) { }
|
|
|
|
C2Acquirable<const C2GraphicView> C2ConstGraphicBlock::map() const {
|
|
C2Fence fence;
|
|
std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping =
|
|
mImpl->map(false /* writable */, &fence);
|
|
std::shared_ptr<GraphicViewBuddy::Impl> gvi =
|
|
std::shared_ptr<GraphicViewBuddy::Impl>(new GraphicViewBuddy::Impl(*mImpl, mapping));
|
|
return AcquirableConstGraphicViewBuddy(
|
|
mapping->error(), fence, GraphicViewBuddy(gvi, C2PlanarSection(*mImpl, crop())));
|
|
}
|
|
|
|
C2ConstGraphicBlock C2ConstGraphicBlock::subBlock(const C2Rect &rect) const {
|
|
return C2ConstGraphicBlock(mImpl, C2PlanarSection(*mImpl, crop().intersect(rect)), mFence);
|
|
}
|
|
|
|
/**
|
|
* Graphic block implementation.
|
|
*/
|
|
C2GraphicBlock::C2GraphicBlock(
|
|
std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
|
|
: C2Block2D(impl, section) { }
|
|
|
|
C2Acquirable<C2GraphicView> C2GraphicBlock::map() {
|
|
C2Fence fence;
|
|
std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping =
|
|
mImpl->map(true /* writable */, &fence);
|
|
std::shared_ptr<GraphicViewBuddy::Impl> gvi =
|
|
std::shared_ptr<GraphicViewBuddy::Impl>(new GraphicViewBuddy::Impl(*mImpl, mapping));
|
|
return AcquirableGraphicViewBuddy(
|
|
mapping->error(), fence, GraphicViewBuddy(gvi, C2PlanarSection(*mImpl, crop())));
|
|
}
|
|
|
|
C2ConstGraphicBlock C2GraphicBlock::share(const C2Rect &crop, C2Fence fence) {
|
|
return ConstGraphicBlockBuddy(mImpl, C2PlanarSection(*mImpl, crop), fence);
|
|
}
|
|
|
|
/**
|
|
* Basic block pool implementations.
|
|
*/
|
|
C2BasicGraphicBlockPool::C2BasicGraphicBlockPool(
|
|
const std::shared_ptr<C2Allocator> &allocator)
|
|
: mAllocator(allocator) {}
|
|
|
|
c2_status_t C2BasicGraphicBlockPool::fetchGraphicBlock(
|
|
uint32_t width,
|
|
uint32_t height,
|
|
uint32_t format,
|
|
C2MemoryUsage usage,
|
|
std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
|
|
block->reset();
|
|
|
|
std::shared_ptr<C2GraphicAllocation> alloc;
|
|
c2_status_t err = mAllocator->newGraphicAllocation(width, height, format, usage, &alloc);
|
|
if (err != C2_OK) {
|
|
return err;
|
|
}
|
|
|
|
*block = _C2BlockFactory::CreateGraphicBlock(alloc);
|
|
|
|
return C2_OK;
|
|
}
|
|
|
|
std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
|
|
const std::shared_ptr<C2GraphicAllocation> &alloc,
|
|
const std::shared_ptr<_C2BlockPoolData> &data, const C2Rect &allottedCrop) {
|
|
std::shared_ptr<C2Block2D::Impl> impl =
|
|
std::make_shared<C2Block2D::Impl>(alloc, data, allottedCrop);
|
|
return std::shared_ptr<C2GraphicBlock>(new C2GraphicBlock(impl, *impl));
|
|
}
|
|
|
|
std::shared_ptr<_C2BlockPoolData> _C2BlockFactory::GetGraphicBlockPoolData(
|
|
const C2Block2D &block) {
|
|
if (block.mImpl) {
|
|
return block.mImpl->poolData();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
|
|
const C2Handle *cHandle,
|
|
const std::shared_ptr<BufferPoolData> &data) {
|
|
// TODO: get proper allocator? and mutex?
|
|
static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0);
|
|
|
|
std::shared_ptr<C2GraphicAllocation> alloc;
|
|
if (sAllocator->isValid(cHandle)) {
|
|
c2_status_t err = sAllocator->priorGraphicAllocation(cHandle, &alloc);
|
|
const std::shared_ptr<C2PooledBlockPoolData> poolData =
|
|
std::make_shared<C2PooledBlockPoolData>(data);
|
|
if (err == C2_OK && poolData) {
|
|
// TODO: config setup?
|
|
std::shared_ptr<C2GraphicBlock> block =
|
|
_C2BlockFactory::CreateGraphicBlock(alloc, poolData);
|
|
return block;
|
|
}
|
|
}
|
|
return nullptr;
|
|
};
|
|
|
|
|
|
/* ========================================== BUFFER ========================================= */
|
|
|
|
class C2BufferData::Impl {
|
|
public:
|
|
explicit Impl(const std::vector<C2ConstLinearBlock> &blocks)
|
|
: mType(blocks.size() == 1 ? LINEAR : LINEAR_CHUNKS),
|
|
mLinearBlocks(blocks) {
|
|
}
|
|
|
|
explicit Impl(const std::vector<C2ConstGraphicBlock> &blocks)
|
|
: mType(blocks.size() == 1 ? GRAPHIC : GRAPHIC_CHUNKS),
|
|
mGraphicBlocks(blocks) {
|
|
}
|
|
|
|
type_t type() const { return mType; }
|
|
const std::vector<C2ConstLinearBlock> &linearBlocks() const { return mLinearBlocks; }
|
|
const std::vector<C2ConstGraphicBlock> &graphicBlocks() const { return mGraphicBlocks; }
|
|
|
|
private:
|
|
type_t mType;
|
|
std::vector<C2ConstLinearBlock> mLinearBlocks;
|
|
std::vector<C2ConstGraphicBlock> mGraphicBlocks;
|
|
friend class C2InfoBuffer;
|
|
};
|
|
|
|
C2BufferData::C2BufferData(const std::vector<C2ConstLinearBlock> &blocks) : mImpl(new Impl(blocks)) {}
|
|
C2BufferData::C2BufferData(const std::vector<C2ConstGraphicBlock> &blocks) : mImpl(new Impl(blocks)) {}
|
|
|
|
C2BufferData::type_t C2BufferData::type() const { return mImpl->type(); }
|
|
|
|
const std::vector<C2ConstLinearBlock> C2BufferData::linearBlocks() const {
|
|
return mImpl->linearBlocks();
|
|
}
|
|
|
|
const std::vector<C2ConstGraphicBlock> C2BufferData::graphicBlocks() const {
|
|
return mImpl->graphicBlocks();
|
|
}
|
|
|
|
C2InfoBuffer::C2InfoBuffer(
|
|
C2Param::Index index, const std::vector<C2ConstLinearBlock> &blocks)
|
|
: mIndex(index), mData(BufferDataBuddy(blocks)) {
|
|
}
|
|
|
|
C2InfoBuffer::C2InfoBuffer(
|
|
C2Param::Index index, const std::vector<C2ConstGraphicBlock> &blocks)
|
|
: mIndex(index), mData(BufferDataBuddy(blocks)) {
|
|
}
|
|
|
|
C2InfoBuffer::C2InfoBuffer(
|
|
C2Param::Index index, const C2BufferData &data)
|
|
: mIndex(index), mData(data) {
|
|
}
|
|
|
|
// static
|
|
C2InfoBuffer C2InfoBuffer::CreateLinearBuffer(
|
|
C2Param::CoreIndex index, const C2ConstLinearBlock &block) {
|
|
return C2InfoBuffer(index.coreIndex() | C2Param::Index::KIND_INFO | C2Param::Index::DIR_GLOBAL,
|
|
{ block });
|
|
}
|
|
|
|
// static
|
|
C2InfoBuffer C2InfoBuffer::CreateGraphicBuffer(
|
|
C2Param::CoreIndex index, const C2ConstGraphicBlock &block) {
|
|
return C2InfoBuffer(index.coreIndex() | C2Param::Index::KIND_INFO | C2Param::Index::DIR_GLOBAL,
|
|
{ block });
|
|
}
|
|
|
|
class C2Buffer::Impl {
|
|
public:
|
|
Impl(C2Buffer *thiz, const std::vector<C2ConstLinearBlock> &blocks)
|
|
: mThis(thiz), mData(blocks) {}
|
|
Impl(C2Buffer *thiz, const std::vector<C2ConstGraphicBlock> &blocks)
|
|
: mThis(thiz), mData(blocks) {}
|
|
|
|
~Impl() {
|
|
for (const auto &pair : mNotify) {
|
|
pair.first(mThis, pair.second);
|
|
}
|
|
}
|
|
|
|
const C2BufferData &data() const { return mData; }
|
|
|
|
c2_status_t registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
|
|
auto it = std::find_if(
|
|
mNotify.begin(), mNotify.end(),
|
|
[onDestroyNotify, arg] (const auto &pair) {
|
|
return pair.first == onDestroyNotify && pair.second == arg;
|
|
});
|
|
if (it != mNotify.end()) {
|
|
return C2_DUPLICATE;
|
|
}
|
|
mNotify.emplace_back(onDestroyNotify, arg);
|
|
return C2_OK;
|
|
}
|
|
|
|
c2_status_t unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
|
|
auto it = std::find_if(
|
|
mNotify.begin(), mNotify.end(),
|
|
[onDestroyNotify, arg] (const auto &pair) {
|
|
return pair.first == onDestroyNotify && pair.second == arg;
|
|
});
|
|
if (it == mNotify.end()) {
|
|
return C2_NOT_FOUND;
|
|
}
|
|
mNotify.erase(it);
|
|
return C2_OK;
|
|
}
|
|
|
|
std::vector<std::shared_ptr<const C2Info>> info() const {
|
|
std::vector<std::shared_ptr<const C2Info>> result(mInfos.size());
|
|
std::transform(
|
|
mInfos.begin(), mInfos.end(), result.begin(),
|
|
[] (const auto &elem) { return elem.second; });
|
|
return result;
|
|
}
|
|
|
|
c2_status_t setInfo(const std::shared_ptr<C2Info> &info) {
|
|
// To "update" you need to erase the existing one if any, and then insert.
|
|
(void) mInfos.erase(info->coreIndex());
|
|
(void) mInfos.insert({ info->coreIndex(), info });
|
|
return C2_OK;
|
|
}
|
|
|
|
bool hasInfo(C2Param::Type index) const {
|
|
return mInfos.count(index.coreIndex()) > 0;
|
|
}
|
|
|
|
std::shared_ptr<const C2Info> getInfo(C2Param::Type index) const {
|
|
auto it = mInfos.find(index.coreIndex());
|
|
if (it == mInfos.end()) {
|
|
return nullptr;
|
|
}
|
|
return std::const_pointer_cast<const C2Info>(it->second);
|
|
}
|
|
|
|
std::shared_ptr<C2Info> removeInfo(C2Param::Type index) {
|
|
auto it = mInfos.find(index.coreIndex());
|
|
if (it == mInfos.end()) {
|
|
return nullptr;
|
|
}
|
|
std::shared_ptr<C2Info> ret = it->second;
|
|
(void) mInfos.erase(it);
|
|
return ret;
|
|
}
|
|
|
|
private:
|
|
C2Buffer * const mThis;
|
|
BufferDataBuddy mData;
|
|
std::map<C2Param::CoreIndex, std::shared_ptr<C2Info>> mInfos;
|
|
std::list<std::pair<OnDestroyNotify, void *>> mNotify;
|
|
};
|
|
|
|
C2Buffer::C2Buffer(const std::vector<C2ConstLinearBlock> &blocks)
|
|
: mImpl(new Impl(this, blocks)) {}
|
|
|
|
C2Buffer::C2Buffer(const std::vector<C2ConstGraphicBlock> &blocks)
|
|
: mImpl(new Impl(this, blocks)) {}
|
|
|
|
const C2BufferData C2Buffer::data() const { return mImpl->data(); }
|
|
|
|
c2_status_t C2Buffer::registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
|
|
return mImpl->registerOnDestroyNotify(onDestroyNotify, arg);
|
|
}
|
|
|
|
c2_status_t C2Buffer::unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
|
|
return mImpl->unregisterOnDestroyNotify(onDestroyNotify, arg);
|
|
}
|
|
|
|
const std::vector<std::shared_ptr<const C2Info>> C2Buffer::info() const {
|
|
return mImpl->info();
|
|
}
|
|
|
|
c2_status_t C2Buffer::setInfo(const std::shared_ptr<C2Info> &info) {
|
|
return mImpl->setInfo(info);
|
|
}
|
|
|
|
bool C2Buffer::hasInfo(C2Param::Type index) const {
|
|
return mImpl->hasInfo(index);
|
|
}
|
|
|
|
std::shared_ptr<const C2Info> C2Buffer::getInfo(C2Param::Type index) const {
|
|
return mImpl->getInfo(index);
|
|
}
|
|
|
|
std::shared_ptr<C2Info> C2Buffer::removeInfo(C2Param::Type index) {
|
|
return mImpl->removeInfo(index);
|
|
}
|
|
|
|
// static
|
|
std::shared_ptr<C2Buffer> C2Buffer::CreateLinearBuffer(const C2ConstLinearBlock &block) {
|
|
return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
|
|
}
|
|
|
|
// static
|
|
std::shared_ptr<C2Buffer> C2Buffer::CreateGraphicBuffer(const C2ConstGraphicBlock &block) {
|
|
return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
|
|
}
|