/* * 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 "C2AllocatorGralloc" #include <utils/Log.h> #include <android/hardware/graphics/allocator/2.0/IAllocator.h> #include <android/hardware/graphics/mapper/2.0/IMapper.h> #include <cutils/native_handle.h> #include <hardware/gralloc.h> #include <C2AllocatorGralloc.h> #include <C2Buffer.h> #include <C2PlatformSupport.h> namespace android { namespace { enum : uint64_t { /** * Usage mask that is passed through from gralloc to Codec 2.0 usage. */ PASSTHROUGH_USAGE_MASK = ~(GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_PROTECTED) }; // verify that passthrough mask is within the platform mask static_assert((~C2MemoryUsage::PLATFORM_MASK & PASSTHROUGH_USAGE_MASK) == 0, ""); } C2MemoryUsage C2AndroidMemoryUsage::FromGrallocUsage(uint64_t usage) { // gralloc does not support WRITE_PROTECTED return C2MemoryUsage( ((usage & GRALLOC_USAGE_SW_READ_MASK) ? C2MemoryUsage::CPU_READ : 0) | ((usage & GRALLOC_USAGE_SW_WRITE_MASK) ? C2MemoryUsage::CPU_WRITE : 0) | ((usage & GRALLOC_USAGE_PROTECTED) ? C2MemoryUsage::READ_PROTECTED : 0) | (usage & PASSTHROUGH_USAGE_MASK)); } uint64_t C2AndroidMemoryUsage::asGrallocUsage() const { // gralloc does not support WRITE_PROTECTED return (((expected & C2MemoryUsage::CPU_READ) ? GRALLOC_USAGE_SW_READ_OFTEN : 0) | ((expected & C2MemoryUsage::CPU_WRITE) ? GRALLOC_USAGE_SW_WRITE_OFTEN : 0) | ((expected & C2MemoryUsage::READ_PROTECTED) ? GRALLOC_USAGE_PROTECTED : 0) | (expected & PASSTHROUGH_USAGE_MASK)); } using ::android::hardware::graphics::allocator::V2_0::IAllocator; using ::android::hardware::graphics::common::V1_0::BufferUsage; using ::android::hardware::graphics::common::V1_0::PixelFormat; using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor; using ::android::hardware::graphics::mapper::V2_0::Error; using ::android::hardware::graphics::mapper::V2_0::IMapper; using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout; using ::android::hardware::hidl_handle; using ::android::hardware::hidl_vec; namespace { struct BufferDescriptorInfo { IMapper::BufferDescriptorInfo mapperInfo; uint32_t stride; }; } /* ===================================== GRALLOC ALLOCATION ==================================== */ static c2_status_t maperr2error(Error maperr) { switch (maperr) { case Error::NONE: return C2_OK; case Error::BAD_DESCRIPTOR: return C2_BAD_VALUE; case Error::BAD_BUFFER: return C2_BAD_VALUE; case Error::BAD_VALUE: return C2_BAD_VALUE; case Error::NO_RESOURCES: return C2_NO_MEMORY; case Error::UNSUPPORTED: return C2_CANNOT_DO; } return C2_CORRUPTED; } static bool native_handle_is_invalid(const native_handle_t *const handle) { // perform basic validation of a native handle if (handle == nullptr) { // null handle is considered valid return false; } return ((size_t)handle->version != sizeof(native_handle_t) || handle->numFds < 0 || handle->numInts < 0 || // for sanity assume handles must occupy less memory than INT_MAX bytes handle->numFds > int((INT_MAX - handle->version) / sizeof(int)) - handle->numInts); } class C2HandleGralloc : public C2Handle { private: struct ExtraData { uint32_t width; uint32_t height; uint32_t format; uint32_t usage_lo; uint32_t usage_hi; uint32_t stride; uint32_t igbp_id_lo; uint32_t igbp_id_hi; uint32_t igbp_slot; uint32_t magic; }; enum { NUM_INTS = sizeof(ExtraData) / sizeof(int), }; const static uint32_t MAGIC = '\xc2gr\x00'; static const ExtraData* getExtraData(const C2Handle *const handle) { if (handle == nullptr || native_handle_is_invalid(handle) || handle->numInts < NUM_INTS) { return nullptr; } return reinterpret_cast<const ExtraData*>( &handle->data[handle->numFds + handle->numInts - NUM_INTS]); } static ExtraData *getExtraData(C2Handle *const handle) { return const_cast<ExtraData *>(getExtraData(const_cast<const C2Handle *const>(handle))); } public: void getIgbpData(uint64_t *igbp_id, uint32_t *igbp_slot) const { const ExtraData *ed = getExtraData(this); *igbp_id = unsigned(ed->igbp_id_lo) | uint64_t(unsigned(ed->igbp_id_hi)) << 32; *igbp_slot = ed->igbp_slot; } static bool isValid(const C2Handle *const o) { if (o == nullptr) { // null handle is always valid return true; } const ExtraData *xd = getExtraData(o); // we cannot validate width/height/format/usage without accessing gralloc driver return xd != nullptr && xd->magic == MAGIC; } static C2HandleGralloc* WrapNativeHandle( const native_handle_t *const handle, uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride, uint64_t igbp_id = 0, uint32_t igbp_slot = 0) { //CHECK(handle != nullptr); if (native_handle_is_invalid(handle) || handle->numInts > int((INT_MAX - handle->version) / sizeof(int)) - NUM_INTS - handle->numFds) { return nullptr; } ExtraData xd = { width, height, format, uint32_t(usage & 0xFFFFFFFF), uint32_t(usage >> 32), stride, uint32_t(igbp_id & 0xFFFFFFFF), uint32_t(igbp_id >> 32), igbp_slot, MAGIC }; native_handle_t *res = native_handle_create(handle->numFds, handle->numInts + NUM_INTS); if (res != nullptr) { memcpy(&res->data, &handle->data, sizeof(int) * (handle->numFds + handle->numInts)); *getExtraData(res) = xd; } return reinterpret_cast<C2HandleGralloc *>(res); } static native_handle_t* UnwrapNativeHandle( const C2Handle *const handle) { const ExtraData *xd = getExtraData(handle); if (xd == nullptr || xd->magic != MAGIC) { return nullptr; } native_handle_t *res = native_handle_create(handle->numFds, handle->numInts - NUM_INTS); if (res != nullptr) { memcpy(&res->data, &handle->data, sizeof(int) * (res->numFds + res->numInts)); } return res; } static native_handle_t* UnwrapNativeHandle( const C2Handle *const handle, uint64_t *igbp_id, uint32_t *igbp_slot) { const ExtraData *xd = getExtraData(handle); if (xd == nullptr || xd->magic != MAGIC) { return nullptr; } *igbp_id = unsigned(xd->igbp_id_lo) | uint64_t(unsigned(xd->igbp_id_hi)) << 32; *igbp_slot = xd->igbp_slot; native_handle_t *res = native_handle_create(handle->numFds, handle->numInts - NUM_INTS); if (res != nullptr) { memcpy(&res->data, &handle->data, sizeof(int) * (res->numFds + res->numInts)); } return res; } static const C2HandleGralloc* Import( const C2Handle *const handle, uint32_t *width, uint32_t *height, uint32_t *format, uint64_t *usage, uint32_t *stride, uint64_t *igbp_id, uint32_t *igbp_slot) { const ExtraData *xd = getExtraData(handle); if (xd == nullptr) { return nullptr; } *width = xd->width; *height = xd->height; *format = xd->format; *usage = xd->usage_lo | (uint64_t(xd->usage_hi) << 32); *stride = xd->stride; *igbp_id = xd->igbp_id_lo | (uint64_t(xd->igbp_id_hi) << 32); *igbp_slot = xd->igbp_slot; return reinterpret_cast<const C2HandleGralloc *>(handle); } }; native_handle_t *UnwrapNativeCodec2GrallocHandle(const C2Handle *const handle) { return C2HandleGralloc::UnwrapNativeHandle(handle); } native_handle_t *UnwrapNativeCodec2GrallocHandle( const C2Handle *const handle, uint64_t *igbp_id, uint32_t *igbp_slot) { return C2HandleGralloc::UnwrapNativeHandle(handle, igbp_id, igbp_slot); } C2Handle *WrapNativeCodec2GrallocHandle( const native_handle_t *const handle, uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride, uint64_t igbp_id, uint32_t igbp_slot) { return C2HandleGralloc::WrapNativeHandle(handle, width, height, format, usage, stride, igbp_id, igbp_slot); } class C2AllocationGralloc : public C2GraphicAllocation { public: virtual ~C2AllocationGralloc() override; virtual c2_status_t map( C2Rect rect, C2MemoryUsage usage, C2Fence *fence, C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override; virtual c2_status_t unmap( uint8_t **addr /* nonnull */, C2Rect rect, C2Fence *fence /* nullable */) override; virtual C2Allocator::id_t getAllocatorId() const override { return mAllocatorId; } virtual const C2Handle *handle() const override { return mLockedHandle ? : mHandle; } virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override; // internal methods // |handle| will be moved. C2AllocationGralloc( const BufferDescriptorInfo &info, const sp<IMapper> &mapper, hidl_handle &hidlHandle, const C2HandleGralloc *const handle, C2Allocator::id_t allocatorId); int dup() const; c2_status_t status() const; private: const BufferDescriptorInfo mInfo; const sp<IMapper> mMapper; const hidl_handle mHidlHandle; const C2HandleGralloc *mHandle; buffer_handle_t mBuffer; const C2HandleGralloc *mLockedHandle; bool mLocked; C2Allocator::id_t mAllocatorId; }; C2AllocationGralloc::C2AllocationGralloc( const BufferDescriptorInfo &info, const sp<IMapper> &mapper, hidl_handle &hidlHandle, const C2HandleGralloc *const handle, C2Allocator::id_t allocatorId) : C2GraphicAllocation(info.mapperInfo.width, info.mapperInfo.height), mInfo(info), mMapper(mapper), mHidlHandle(std::move(hidlHandle)), mHandle(handle), mBuffer(nullptr), mLockedHandle(nullptr), mLocked(false), mAllocatorId(allocatorId) { } C2AllocationGralloc::~C2AllocationGralloc() { if (!mBuffer) { return; } if (mLocked) { // implementation ignores addresss and rect uint8_t* addr[C2PlanarLayout::MAX_NUM_PLANES] = {}; unmap(addr, C2Rect(), nullptr); } mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer)); native_handle_delete(const_cast<native_handle_t*>( reinterpret_cast<const native_handle_t*>(mHandle))); } c2_status_t C2AllocationGralloc::map( C2Rect rect, C2MemoryUsage usage, C2Fence *fence, C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) { uint64_t grallocUsage = static_cast<C2AndroidMemoryUsage>(usage).asGrallocUsage(); ALOGV("mapping buffer with usage %#llx => %#llx", (long long)usage.expected, (long long)grallocUsage); // TODO (void) fence; if (mBuffer && mLocked) { ALOGD("already mapped"); return C2_DUPLICATE; } if (!layout || !addr) { ALOGD("wrong param"); return C2_BAD_VALUE; } c2_status_t err = C2_OK; if (!mBuffer) { mMapper->importBuffer( mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) { err = maperr2error(maperr); if (err == C2_OK) { mBuffer = static_cast<buffer_handle_t>(buffer); } }); if (err != C2_OK) { ALOGD("importBuffer failed: %d", err); return err; } if (mBuffer == nullptr) { ALOGD("importBuffer returned null buffer"); return C2_CORRUPTED; } uint64_t igbp_id = 0; uint32_t igbp_slot = 0; if (mHandle) { mHandle->getIgbpData(&igbp_id, &igbp_slot); } mLockedHandle = C2HandleGralloc::WrapNativeHandle( mBuffer, mInfo.mapperInfo.width, mInfo.mapperInfo.height, (uint32_t)mInfo.mapperInfo.format, mInfo.mapperInfo.usage, mInfo.stride, igbp_id, igbp_slot); } switch (mInfo.mapperInfo.format) { case PixelFormat::YCBCR_420_888: case PixelFormat::YV12: { YCbCrLayout ycbcrLayout; mMapper->lockYCbCr( const_cast<native_handle_t *>(mBuffer), grallocUsage, { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height }, // TODO: fence hidl_handle(), [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) { err = maperr2error(maperr); if (err == C2_OK) { ycbcrLayout = mapLayout; } }); if (err != C2_OK) { ALOGD("lockYCbCr failed: %d", err); return err; } addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y; addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb; addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr; layout->type = C2PlanarLayout::TYPE_YUV; layout->numPlanes = 3; layout->rootPlanes = 3; layout->planes[C2PlanarLayout::PLANE_Y] = { C2PlaneInfo::CHANNEL_Y, // channel 1, // colInc (int32_t)ycbcrLayout.yStride, // rowInc 1, // mColSampling 1, // mRowSampling 8, // allocatedDepth 8, // bitDepth 0, // rightShift C2PlaneInfo::NATIVE, // endianness C2PlanarLayout::PLANE_Y, // rootIx 0, // offset }; layout->planes[C2PlanarLayout::PLANE_U] = { C2PlaneInfo::CHANNEL_CB, // channel (int32_t)ycbcrLayout.chromaStep, // colInc (int32_t)ycbcrLayout.cStride, // rowInc 2, // mColSampling 2, // mRowSampling 8, // allocatedDepth 8, // bitDepth 0, // rightShift C2PlaneInfo::NATIVE, // endianness C2PlanarLayout::PLANE_U, // rootIx 0, // offset }; layout->planes[C2PlanarLayout::PLANE_V] = { C2PlaneInfo::CHANNEL_CR, // channel (int32_t)ycbcrLayout.chromaStep, // colInc (int32_t)ycbcrLayout.cStride, // rowInc 2, // mColSampling 2, // mRowSampling 8, // allocatedDepth 8, // bitDepth 0, // rightShift C2PlaneInfo::NATIVE, // endianness C2PlanarLayout::PLANE_V, // rootIx 0, // offset }; // handle interleaved formats intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U]; if (uvOffset > 0 && uvOffset < (intptr_t)ycbcrLayout.chromaStep) { layout->rootPlanes = 2; layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U; layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset; } else if (uvOffset < 0 && uvOffset > -(intptr_t)ycbcrLayout.chromaStep) { layout->rootPlanes = 2; layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V; layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset; } break; } case PixelFormat::RGBA_8888: // TODO: alpha channel // fall-through case PixelFormat::RGBX_8888: { void *pointer = nullptr; mMapper->lock( const_cast<native_handle_t *>(mBuffer), grallocUsage, { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height }, // TODO: fence hidl_handle(), [&err, &pointer](const auto &maperr, const auto &mapPointer) { err = maperr2error(maperr); if (err == C2_OK) { pointer = mapPointer; } }); if (err != C2_OK) { ALOGD("lock failed: %d", err); return err; } addr[C2PlanarLayout::PLANE_R] = (uint8_t *)pointer; addr[C2PlanarLayout::PLANE_G] = (uint8_t *)pointer + 1; addr[C2PlanarLayout::PLANE_B] = (uint8_t *)pointer + 2; layout->type = C2PlanarLayout::TYPE_RGB; layout->numPlanes = 3; layout->rootPlanes = 1; layout->planes[C2PlanarLayout::PLANE_R] = { C2PlaneInfo::CHANNEL_R, // channel 4, // colInc 4 * (int32_t)mInfo.stride, // rowInc 1, // mColSampling 1, // mRowSampling 8, // allocatedDepth 8, // bitDepth 0, // rightShift C2PlaneInfo::NATIVE, // endianness C2PlanarLayout::PLANE_R, // rootIx 0, // offset }; layout->planes[C2PlanarLayout::PLANE_G] = { C2PlaneInfo::CHANNEL_G, // channel 4, // colInc 4 * (int32_t)mInfo.stride, // rowInc 1, // mColSampling 1, // mRowSampling 8, // allocatedDepth 8, // bitDepth 0, // rightShift C2PlaneInfo::NATIVE, // endianness C2PlanarLayout::PLANE_R, // rootIx 1, // offset }; layout->planes[C2PlanarLayout::PLANE_B] = { C2PlaneInfo::CHANNEL_B, // channel 4, // colInc 4 * (int32_t)mInfo.stride, // rowInc 1, // mColSampling 1, // mRowSampling 8, // allocatedDepth 8, // bitDepth 0, // rightShift C2PlaneInfo::NATIVE, // endianness C2PlanarLayout::PLANE_R, // rootIx 2, // offset }; break; } default: { ALOGD("unsupported pixel format: %d", mInfo.mapperInfo.format); return C2_OMITTED; } } mLocked = true; return C2_OK; } c2_status_t C2AllocationGralloc::unmap( uint8_t **addr, C2Rect rect, C2Fence *fence /* nullable */) { // TODO: check addr and size, use fence (void)addr; (void)rect; c2_status_t err = C2_OK; mMapper->unlock( const_cast<native_handle_t *>(mBuffer), [&err, &fence](const auto &maperr, const auto &releaseFence) { // TODO (void) fence; (void) releaseFence; err = maperr2error(maperr); if (err == C2_OK) { // TODO: fence } }); if (err == C2_OK) { mLocked = false; } return err; } bool C2AllocationGralloc::equals(const std::shared_ptr<const C2GraphicAllocation> &other) const { return other && other->handle() == handle(); } /* ===================================== GRALLOC ALLOCATOR ==================================== */ class C2AllocatorGralloc::Impl { public: Impl(id_t id, bool bufferQueue); id_t getId() const { return mTraits->id; } C2String getName() const { return mTraits->name; } std::shared_ptr<const C2Allocator::Traits> getTraits() const { return mTraits; } c2_status_t newGraphicAllocation( uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage, std::shared_ptr<C2GraphicAllocation> *allocation); c2_status_t priorGraphicAllocation( const C2Handle *handle, std::shared_ptr<C2GraphicAllocation> *allocation); c2_status_t status() const { return mInit; } private: std::shared_ptr<C2Allocator::Traits> mTraits; c2_status_t mInit; sp<IAllocator> mAllocator; sp<IMapper> mMapper; const bool mBufferQueue; }; void _UnwrapNativeCodec2GrallocMetadata( const C2Handle *const handle, uint32_t *width, uint32_t *height, uint32_t *format,uint64_t *usage, uint32_t *stride, uint64_t *igbp_id, uint32_t *igbp_slot) { (void)C2HandleGralloc::Import(handle, width, height, format, usage, stride, igbp_id, igbp_slot); } C2AllocatorGralloc::Impl::Impl(id_t id, bool bufferQueue) : mInit(C2_OK), mBufferQueue(bufferQueue) { // TODO: get this from allocator C2MemoryUsage minUsage = { 0, 0 }, maxUsage = { ~(uint64_t)0, ~(uint64_t)0 }; Traits traits = { "android.allocator.gralloc", id, C2Allocator::GRAPHIC, minUsage, maxUsage }; mTraits = std::make_shared<C2Allocator::Traits>(traits); // gralloc allocator is a singleton, so all objects share a global service mAllocator = IAllocator::getService(); mMapper = IMapper::getService(); if (mAllocator == nullptr || mMapper == nullptr) { mInit = C2_CORRUPTED; } } c2_status_t C2AllocatorGralloc::Impl::newGraphicAllocation( uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage, std::shared_ptr<C2GraphicAllocation> *allocation) { uint64_t grallocUsage = static_cast<C2AndroidMemoryUsage>(usage).asGrallocUsage(); ALOGV("allocating buffer with usage %#llx => %#llx", (long long)usage.expected, (long long)grallocUsage); BufferDescriptorInfo info = { { width, height, 1u, // layerCount (PixelFormat)format, grallocUsage, }, 0u, // stride placeholder }; c2_status_t err = C2_OK; BufferDescriptor desc; mMapper->createDescriptor( info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) { err = maperr2error(maperr); if (err == C2_OK) { desc = descriptor; } }); if (err != C2_OK) { return err; } // IAllocator shares IMapper error codes. hidl_handle buffer; mAllocator->allocate( desc, 1u, [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) { err = maperr2error(maperr); if (err != C2_OK) { return; } if (buffers.size() != 1u) { err = C2_CORRUPTED; return; } info.stride = stride; buffer = std::move(buffers[0]); }); if (err != C2_OK) { return err; } allocation->reset(new C2AllocationGralloc( info, mMapper, buffer, C2HandleGralloc::WrapNativeHandle( buffer.getNativeHandle(), info.mapperInfo.width, info.mapperInfo.height, (uint32_t)info.mapperInfo.format, info.mapperInfo.usage, info.stride, 0, mBufferQueue ? ~0 : 0), mTraits->id)); return C2_OK; } c2_status_t C2AllocatorGralloc::Impl::priorGraphicAllocation( const C2Handle *handle, std::shared_ptr<C2GraphicAllocation> *allocation) { BufferDescriptorInfo info; info.mapperInfo.layerCount = 1u; uint64_t igbp_id; uint32_t igbp_slot; const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import( handle, &info.mapperInfo.width, &info.mapperInfo.height, (uint32_t *)&info.mapperInfo.format, (uint64_t *)&info.mapperInfo.usage, &info.stride, &igbp_id, &igbp_slot); if (grallocHandle == nullptr) { return C2_BAD_VALUE; } hidl_handle hidlHandle; hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true); allocation->reset(new C2AllocationGralloc(info, mMapper, hidlHandle, grallocHandle, mTraits->id)); return C2_OK; } C2AllocatorGralloc::C2AllocatorGralloc(id_t id, bool bufferQueue) : mImpl(new Impl(id, bufferQueue)) {} C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; } C2Allocator::id_t C2AllocatorGralloc::getId() const { return mImpl->getId(); } C2String C2AllocatorGralloc::getName() const { return mImpl->getName(); } std::shared_ptr<const C2Allocator::Traits> C2AllocatorGralloc::getTraits() const { return mImpl->getTraits(); } c2_status_t C2AllocatorGralloc::newGraphicAllocation( uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage, std::shared_ptr<C2GraphicAllocation> *allocation) { return mImpl->newGraphicAllocation(width, height, format, usage, allocation); } c2_status_t C2AllocatorGralloc::priorGraphicAllocation( const C2Handle *handle, std::shared_ptr<C2GraphicAllocation> *allocation) { return mImpl->priorGraphicAllocation(handle, allocation); } c2_status_t C2AllocatorGralloc::status() const { return mImpl->status(); } bool C2AllocatorGralloc::isValid(const C2Handle* const o) { return C2HandleGralloc::isValid(o); } } // namespace android