/* * 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 #include #include #include #include #include #include #include #include #include #include using ::android::hardware::hidl_handle; using PixelFormat4 = ::android::hardware::graphics::common::V1_2::PixelFormat; namespace android { namespace /* unnamed */ { enum : uint64_t { /** * Usage mask that is passed through from gralloc to Codec 2.0 usage. */ PASSTHROUGH_USAGE_MASK = ~static_cast(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, ""); } // unnamed 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)); } namespace /* unnamed */ { /* ===================================== GRALLOC ALLOCATION ==================================== */ 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 generation; 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( &handle->data[handle->numFds + handle->numInts - NUM_INTS]); } static ExtraData *GetExtraData(C2Handle *const handle) { return const_cast(GetExtraData(const_cast(handle))); } public: void getIgbpData(uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot) const { const ExtraData *ed = GetExtraData(this); *generation = ed->generation; *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* WrapAndMoveNativeHandle( const native_handle_t *const handle, uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride, uint32_t generation, 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, generation, 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(res); } static C2HandleGralloc* WrapNativeHandle( const native_handle_t *const handle, uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride, uint32_t generation, uint64_t igbp_id = 0, uint32_t igbp_slot = 0) { if (handle == nullptr) { return nullptr; } native_handle_t *clone = native_handle_clone(handle); if (clone == nullptr) { return nullptr; } C2HandleGralloc *res = WrapAndMoveNativeHandle( clone, width, height, format, usage, stride, generation, igbp_id, igbp_slot); if (res == nullptr) { native_handle_close(clone); } native_handle_delete(clone); return res; } static bool MigrateNativeHandle( native_handle_t *handle, uint32_t generation, uint64_t igbp_id, uint32_t igbp_slot) { if (handle == nullptr || !IsValid(handle)) { return false; } ExtraData *ed = GetExtraData(handle); if (!ed) return false; ed->generation = generation; ed->igbp_id_lo = uint32_t(igbp_id & 0xFFFFFFFF); ed->igbp_id_hi = uint32_t(igbp_id >> 32); ed->igbp_slot = igbp_slot; return true; } 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 const C2HandleGralloc* Import( const C2Handle *const handle, uint32_t *width, uint32_t *height, uint32_t *format, uint64_t *usage, uint32_t *stride, uint32_t *generation, 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; *generation = xd->generation; *igbp_id = xd->igbp_id_lo | (uint64_t(xd->igbp_id_hi) << 32); *igbp_slot = xd->igbp_slot; return reinterpret_cast(handle); } }; } // unnamed namespace native_handle_t *UnwrapNativeCodec2GrallocHandle(const C2Handle *const handle) { return C2HandleGralloc::UnwrapNativeHandle(handle); } C2Handle *WrapNativeCodec2GrallocHandle( const native_handle_t *const handle, uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride, uint32_t generation, uint64_t igbp_id, uint32_t igbp_slot) { return C2HandleGralloc::WrapNativeHandle(handle, width, height, format, usage, stride, generation, igbp_id, igbp_slot); } bool MigrateNativeCodec2GrallocHandle( native_handle_t *handle, uint32_t generation, uint64_t igbp_id, uint32_t igbp_slot) { return C2HandleGralloc::MigrateNativeHandle(handle, generation, igbp_id, igbp_slot); } class C2AllocationGralloc : public C2GraphicAllocation { public: virtual ~C2AllocationGralloc() override; virtual c2_status_t map( C2Rect c2Rect, 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 &other) const override; // internal methods // |handle| will be moved. C2AllocationGralloc( uint32_t width, uint32_t height, uint32_t format, uint32_t layerCount, uint64_t grallocUsage, uint32_t stride, hidl_handle &hidlHandle, const C2HandleGralloc *const handle, C2Allocator::id_t allocatorId); int dup() const; c2_status_t status() const; private: const uint32_t mWidth; const uint32_t mHeight; const uint32_t mFormat; const uint32_t mLayerCount; const uint64_t mGrallocUsage; const uint32_t mStride; const hidl_handle mHidlHandle; const C2HandleGralloc *mHandle; buffer_handle_t mBuffer; const C2HandleGralloc *mLockedHandle; bool mLocked; C2Allocator::id_t mAllocatorId; std::mutex mMappedLock; }; C2AllocationGralloc::C2AllocationGralloc( uint32_t width, uint32_t height, uint32_t format, uint32_t layerCount, uint64_t grallocUsage, uint32_t stride, hidl_handle &hidlHandle, const C2HandleGralloc *const handle, C2Allocator::id_t allocatorId) : C2GraphicAllocation(width, height), mWidth(width), mHeight(height), mFormat(format), mLayerCount(layerCount), mGrallocUsage(grallocUsage), mStride(stride), mHidlHandle(std::move(hidlHandle)), mHandle(handle), mBuffer(nullptr), mLockedHandle(nullptr), mLocked(false), mAllocatorId(allocatorId) { } C2AllocationGralloc::~C2AllocationGralloc() { if (mBuffer && mLocked) { // implementation ignores addresss and rect uint8_t* addr[C2PlanarLayout::MAX_NUM_PLANES] = {}; unmap(addr, C2Rect(), nullptr); } if (mBuffer) { status_t err = GraphicBufferMapper::get().freeBuffer(mBuffer); if (err) { ALOGE("failed transaction: freeBuffer"); } } if (mHandle) { native_handle_delete( const_cast(reinterpret_cast(mHandle))); } if (mLockedHandle) { native_handle_delete( const_cast( reinterpret_cast(mLockedHandle))); } } c2_status_t C2AllocationGralloc::map( C2Rect c2Rect, C2MemoryUsage usage, C2Fence *fence, C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) { const Rect rect{(int32_t)c2Rect.left, (int32_t)c2Rect.top, (int32_t)(c2Rect.left + c2Rect.width) /* right */, (int32_t)(c2Rect.top + c2Rect.height) /* bottom */}; uint64_t grallocUsage = static_cast(usage).asGrallocUsage(); ALOGV("mapping buffer with usage %#llx => %#llx", (long long)usage.expected, (long long)grallocUsage); // TODO (void)fence; std::lock_guard lock(mMappedLock); if (mBuffer && mLocked) { ALOGD("already mapped"); return C2_DUPLICATE; } if (!layout || !addr) { ALOGD("wrong param"); return C2_BAD_VALUE; } if (!mBuffer) { status_t err = GraphicBufferMapper::get().importBuffer( mHidlHandle.getNativeHandle(), mWidth, mHeight, mLayerCount, mFormat, mGrallocUsage, mStride, &mBuffer); if (err) { ALOGE("failed transaction: importBuffer"); return C2_CORRUPTED; } if (mBuffer == nullptr) { ALOGD("importBuffer returned null buffer"); return C2_CORRUPTED; } uint32_t generation = 0; uint64_t igbp_id = 0; uint32_t igbp_slot = 0; if (mHandle) { mHandle->getIgbpData(&generation, &igbp_id, &igbp_slot); } mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle( mBuffer, mWidth, mHeight, mFormat, mGrallocUsage, mStride, generation, igbp_id, igbp_slot); } switch (mFormat) { case static_cast(PixelFormat4::RGBA_1010102): { // TRICKY: this is used for media as YUV444 in the case when it is queued directly to a // Surface. In all other cases it is RGBA. We don't know which case it is here, so // default to YUV for now. void *pointer = nullptr; // TODO: fence status_t err = GraphicBufferMapper::get().lock( const_cast(mBuffer), grallocUsage, rect, &pointer); if (err) { ALOGE("failed transaction: lock(RGBA_1010102)"); return C2_CORRUPTED; } // treat as 32-bit values addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer; addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer; addr[C2PlanarLayout::PLANE_V] = (uint8_t *)pointer; addr[C2PlanarLayout::PLANE_A] = (uint8_t *)pointer; layout->type = C2PlanarLayout::TYPE_YUVA; layout->numPlanes = 4; layout->rootPlanes = 1; layout->planes[C2PlanarLayout::PLANE_Y] = { C2PlaneInfo::CHANNEL_Y, // channel 4, // colInc static_cast(4 * mStride), // rowInc 1, // mColSampling 1, // mRowSampling 32, // allocatedDepth 10, // bitDepth 10, // rightShift C2PlaneInfo::LITTLE_END, // endianness C2PlanarLayout::PLANE_Y, // rootIx 0, // offset }; layout->planes[C2PlanarLayout::PLANE_U] = { C2PlaneInfo::CHANNEL_CB, // channel 4, // colInc static_cast(4 * mStride), // rowInc 1, // mColSampling 1, // mRowSampling 32, // allocatedDepth 10, // bitDepth 0, // rightShift C2PlaneInfo::LITTLE_END, // endianness C2PlanarLayout::PLANE_Y, // rootIx 0, // offset }; layout->planes[C2PlanarLayout::PLANE_V] = { C2PlaneInfo::CHANNEL_CR, // channel 4, // colInc static_cast(4 * mStride), // rowInc 1, // mColSampling 1, // mRowSampling 32, // allocatedDepth 10, // bitDepth 20, // rightShift C2PlaneInfo::LITTLE_END, // endianness C2PlanarLayout::PLANE_Y, // rootIx 0, // offset }; layout->planes[C2PlanarLayout::PLANE_A] = { C2PlaneInfo::CHANNEL_A, // channel 4, // colInc static_cast(4 * mStride), // rowInc 1, // mColSampling 1, // mRowSampling 32, // allocatedDepth 2, // bitDepth 30, // rightShift C2PlaneInfo::LITTLE_END, // endianness C2PlanarLayout::PLANE_Y, // rootIx 0, // offset }; break; } case static_cast(PixelFormat4::RGBA_8888): // TODO: alpha channel // fall-through case static_cast(PixelFormat4::RGBX_8888): { void *pointer = nullptr; // TODO: fence status_t err = GraphicBufferMapper::get().lock( const_cast(mBuffer), grallocUsage, rect, &pointer); if (err) { ALOGE("failed transaction: lock(RGBA_8888)"); return C2_CORRUPTED; } 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 static_cast(4 * mStride), // 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 static_cast(4 * mStride), // 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 static_cast(4 * mStride), // rowInc 1, // mColSampling 1, // mRowSampling 8, // allocatedDepth 8, // bitDepth 0, // rightShift C2PlaneInfo::NATIVE, // endianness C2PlanarLayout::PLANE_R, // rootIx 2, // offset }; break; } case static_cast(PixelFormat4::BLOB): { void *pointer = nullptr; // TODO: fence status_t err = GraphicBufferMapper::get().lock( const_cast(mBuffer), grallocUsage, rect, &pointer); if (err) { ALOGE("failed transaction: lock(BLOB)"); return C2_CORRUPTED; } *addr = (uint8_t *)pointer; break; } case static_cast(PixelFormat4::YCBCR_422_SP): // fall-through case static_cast(PixelFormat4::YCRCB_420_SP): // fall-through case static_cast(PixelFormat4::YCBCR_422_I): // fall-through case static_cast(PixelFormat4::YCBCR_420_888): // fall-through case static_cast(PixelFormat4::YV12): { android_ycbcr ycbcrLayout; status_t err = GraphicBufferMapper::get().lockYCbCr( const_cast(mBuffer), grallocUsage, rect, &ycbcrLayout); if (err) { ALOGE("failed transaction: lockYCbCr (err=%d)", err); return C2_CORRUPTED; } if (!ycbcrLayout.y || !ycbcrLayout.cb || !ycbcrLayout.cr || ycbcrLayout.ystride == 0 || ycbcrLayout.cstride == 0 || ycbcrLayout.chroma_step == 0) { ALOGE("invalid layout: lockYCbCr (y=%s cb=%s cr=%s " "ystride=%zu cstride=%zu chroma_step=%zu)", ycbcrLayout.y ? "(non-null)" : "(null)", ycbcrLayout.cb ? "(non-null)" : "(null)", ycbcrLayout.cr ? "(non-null)" : "(null)", ycbcrLayout.ystride, ycbcrLayout.cstride, ycbcrLayout.chroma_step); return C2_CORRUPTED; } 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.chroma_step, // 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.chroma_step, // 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.chroma_step) { 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.chroma_step) { layout->rootPlanes = 2; layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V; layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset; } break; } case static_cast(PixelFormat4::YCBCR_P010): { void *pointer = nullptr; status_t err = GraphicBufferMapper::get().lock( const_cast(mBuffer), grallocUsage, rect, &pointer); if (err) { ALOGE("failed transaction: lock(YCBCR_P010)"); return C2_CORRUPTED; } addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer; addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer + mStride * 2 * rect.height(); addr[C2PlanarLayout::PLANE_V] = addr[C2PlanarLayout::PLANE_U] + 2; layout->type = C2PlanarLayout::TYPE_YUV; layout->numPlanes = 3; layout->rootPlanes = 2; layout->planes[C2PlanarLayout::PLANE_Y] = { C2PlaneInfo::CHANNEL_Y, // channel 2, // colInc static_cast(2 * mStride), // rowInc 1, // mColSampling 1, // mRowSampling 16, // allocatedDepth 10, // bitDepth 6, // rightShift C2PlaneInfo::LITTLE_END, // endianness C2PlanarLayout::PLANE_Y, // rootIx 0, // offset }; layout->planes[C2PlanarLayout::PLANE_U] = { C2PlaneInfo::CHANNEL_CB, // channel 4, // colInc static_cast(2 * mStride), // rowInc 2, // mColSampling 2, // mRowSampling 16, // allocatedDepth 10, // bitDepth 6, // rightShift C2PlaneInfo::LITTLE_END, // endianness C2PlanarLayout::PLANE_U, // rootIx 0, // offset }; layout->planes[C2PlanarLayout::PLANE_V] = { C2PlaneInfo::CHANNEL_CR, // channel 4, // colInc static_cast(2 * mStride), // rowInc 2, // mColSampling 2, // mRowSampling 16, // allocatedDepth 10, // bitDepth 6, // rightShift C2PlaneInfo::LITTLE_END, // endianness C2PlanarLayout::PLANE_U, // rootIx 2, // offset }; break; } default: { // We don't know what it is, but let's try to lock it. android_ycbcr ycbcrLayout; status_t err = GraphicBufferMapper::get().lockYCbCr( const_cast(mBuffer), grallocUsage, rect, &ycbcrLayout); if (err == OK && ycbcrLayout.y && ycbcrLayout.cb && ycbcrLayout.cr && ycbcrLayout.ystride > 0 && ycbcrLayout.cstride > 0 && ycbcrLayout.chroma_step > 0) { 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.chroma_step, // 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.chroma_step, // 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.chroma_step) { 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.chroma_step) { layout->rootPlanes = 2; layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V; layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset; } break; } // We really don't know what this is; lock the buffer and pass it through --- // the client may know how to interpret it. // unlock previous allocation if it was successful if (err == OK) { err = GraphicBufferMapper::get().unlock(mBuffer); if (err) { ALOGE("failed transaction: unlock"); return C2_CORRUPTED; } } void *pointer = nullptr; err = GraphicBufferMapper::get().lock( const_cast(mBuffer), grallocUsage, rect, &pointer); if (err) { ALOGE("failed transaction: lock(??? %x)", mFormat); return C2_CORRUPTED; } addr[0] = (uint8_t *)pointer; layout->type = C2PlanarLayout::TYPE_UNKNOWN; layout->numPlanes = 1; layout->rootPlanes = 1; layout->planes[0] = { // TODO: CHANNEL_UNKNOWN? C2PlaneInfo::channel_t(0xFF), // channel 1, // colInc int32_t(mStride), // rowInc 1, // mColSampling 1, // mRowSampling 8, // allocatedDepth 8, // bitDepth 0, // rightShift C2PlaneInfo::NATIVE, // endianness 0, // rootIx 0, // offset }; break; } } 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; (void)fence; std::lock_guard lock(mMappedLock); // TODO: fence status_t err = GraphicBufferMapper::get().unlock(mBuffer); if (err) { ALOGE("failed transaction: unlock"); return C2_CORRUPTED; } mLocked = false; return C2_OK; } bool C2AllocationGralloc::equals(const std::shared_ptr &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 getTraits() const { return mTraits; } c2_status_t newGraphicAllocation( uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage, std::shared_ptr *allocation); c2_status_t priorGraphicAllocation( const C2Handle *handle, std::shared_ptr *allocation); c2_status_t status() const { return mInit; } private: std::shared_ptr mTraits; c2_status_t mInit; const bool mBufferQueue; }; void _UnwrapNativeCodec2GrallocMetadata( const C2Handle *const handle, uint32_t *width, uint32_t *height, uint32_t *format,uint64_t *usage, uint32_t *stride, uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot) { (void)C2HandleGralloc::Import(handle, width, height, format, usage, stride, generation, 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(traits); } c2_status_t C2AllocatorGralloc::Impl::newGraphicAllocation( uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage, std::shared_ptr *allocation) { uint64_t grallocUsage = static_cast(usage).asGrallocUsage(); ALOGV("allocating buffer with usage %#llx => %#llx", (long long)usage.expected, (long long)grallocUsage); buffer_handle_t buffer; uint32_t stride = 0; status_t err = GraphicBufferAllocator::get().allocateRawHandle(width, height, format, 1u /* layer count */, grallocUsage, &buffer, &stride, "C2GrallocAllocation"); if (err) { ALOGE("failed transaction: allocate"); return C2_CORRUPTED; } hidl_handle hidlHandle; hidlHandle.setTo(const_cast(buffer), true); allocation->reset(new C2AllocationGralloc( width, height, format, 1u /* layer count */, grallocUsage, stride, hidlHandle, C2HandleGralloc::WrapAndMoveNativeHandle( hidlHandle, width, height, format, grallocUsage, stride, 0, 0, mBufferQueue ? ~0 : 0), mTraits->id)); return C2_OK; } c2_status_t C2AllocatorGralloc::Impl::priorGraphicAllocation( const C2Handle *handle, std::shared_ptr *allocation) { uint32_t generation; uint64_t igbp_id; uint32_t igbp_slot; uint32_t width; uint32_t height; uint32_t format; uint32_t layerCount = 1; uint64_t grallocUsage; uint32_t stride; const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import( handle, &width, &height, &format, &grallocUsage, &stride, &generation, &igbp_id, &igbp_slot); if (grallocHandle == nullptr) { return C2_BAD_VALUE; } hidl_handle hidlHandle; hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true); allocation->reset(new C2AllocationGralloc( width, height, format, layerCount, grallocUsage, stride, 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 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 *allocation) { return mImpl->newGraphicAllocation(width, height, format, usage, allocation); } c2_status_t C2AllocatorGralloc::priorGraphicAllocation( const C2Handle *handle, std::shared_ptr *allocation) { return mImpl->priorGraphicAllocation(handle, allocation); } c2_status_t C2AllocatorGralloc::status() const { return mImpl->status(); } // static bool C2AllocatorGralloc::CheckHandle(const C2Handle* const o) { return C2HandleGralloc::IsValid(o); } } // namespace android