| /* |
| * 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 <mutex> |
| |
| #include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h> |
| #include <android/hardware/graphics/common/1.2/types.h> |
| #include <cutils/native_handle.h> |
| #include <drm/drm_fourcc.h> |
| #include <gralloctypes/Gralloc4.h> |
| #include <hardware/gralloc.h> |
| #include <ui/GraphicBufferAllocator.h> |
| #include <ui/GraphicBufferMapper.h> |
| #include <ui/Rect.h> |
| |
| #include <C2AllocatorGralloc.h> |
| #include <C2Buffer.h> |
| #include <C2Debug.h> |
| #include <C2PlatformSupport.h> |
| |
| 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<uint64_t>(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 |
| |
| static bool isAtLeastT() { |
| return android_get_device_api_level() >= __ANDROID_API_T__; |
| } |
| |
| 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<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(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<C2HandleGralloc *>(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 uint32_t getPixelFormat(const C2Handle *const handle) { |
| if (handle == nullptr) { |
| return 0; |
| } |
| const ExtraData *xd = GetExtraData(handle); |
| return xd->format; |
| } |
| |
| 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<const C2HandleGralloc *>(handle); |
| } |
| }; |
| |
| class C2HandleAhwb : public C2Handle { |
| private: |
| // TODO: remove extradata and use AHardwareBuffer directly. |
| struct ExtraData { |
| uint32_t width; |
| uint32_t height; |
| uint32_t format; |
| uint32_t usage_lo; |
| uint32_t usage_hi; |
| uint32_t stride; |
| uint32_t origId_lo; |
| uint32_t origId_hi; |
| uint32_t magic; |
| }; |
| |
| enum { |
| NUM_INTS = sizeof(ExtraData) / sizeof(int), |
| }; |
| const static uint32_t MAGIC = '\xc2hw\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 getOrigId(uint64_t *origId) const { |
| const ExtraData *ed = GetExtraData(this); |
| *origId = unsigned(ed->origId_lo) | uint64_t(unsigned(ed->origId_hi)) << 32; |
| } |
| |
| 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 C2HandleAhwb* WrapAndMoveNativeHandle( |
| const native_handle_t *const handle, |
| uint32_t width, uint32_t height, uint32_t format, uint64_t usage, |
| uint32_t stride, uint64_t origId) { |
| //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(origId & 0xFFFFFFFF), uint32_t(origId >> 32), 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<C2HandleAhwb *>(res); |
| } |
| |
| static C2HandleAhwb* WrapNativeHandle( |
| const native_handle_t *const handle, |
| uint32_t width, uint32_t height, uint32_t format, uint64_t usage, |
| uint32_t stride, uint64_t origId) { |
| if (handle == nullptr) { |
| return nullptr; |
| } |
| native_handle_t *clone = native_handle_clone(handle); |
| if (clone == nullptr) { |
| return nullptr; |
| } |
| C2HandleAhwb *res = WrapAndMoveNativeHandle( |
| clone, width, height, format, usage, stride, origId); |
| if (res == nullptr) { |
| native_handle_close(clone); |
| } |
| native_handle_delete(clone); |
| return 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 const C2HandleAhwb* Import( |
| const C2Handle *const handle, |
| uint32_t *width, uint32_t *height, uint32_t *format, |
| uint64_t *usage, uint32_t *stride, |
| uint64_t *origId) { |
| 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; |
| *origId = xd->origId_lo | (uint64_t(xd->origId_hi) << 32); |
| return reinterpret_cast<const C2HandleAhwb *>(handle); |
| } |
| }; |
| |
| static |
| c2_status_t Gralloc4Mapper_lock(native_handle_t *handle, uint64_t usage, const Rect& bounds, |
| C2PlanarLayout *layout, uint8_t **addr) { |
| GraphicBufferMapper &mapper = GraphicBufferMapper::get(); |
| |
| std::vector<ui::PlaneLayout> planes; |
| // this method is only supported on Gralloc 4 or later |
| status_t err = mapper.getPlaneLayouts(handle, &planes); |
| if (err != NO_ERROR || planes.empty()) { |
| return C2_CANNOT_DO; |
| } |
| |
| uint8_t *pointer = nullptr; |
| err = mapper.lock(handle, usage, bounds, (void **)&pointer, nullptr, nullptr); |
| if (err != NO_ERROR || pointer == nullptr) { |
| return C2_CORRUPTED; |
| } |
| |
| using aidl::android::hardware::graphics::common::PlaneLayoutComponentType; |
| using aidl::android::hardware::graphics::common::PlaneLayoutComponent; |
| |
| layout->type = C2PlanarLayout::TYPE_YUV; |
| layout->numPlanes = 0; |
| layout->rootPlanes = 0; |
| |
| for (const ui::PlaneLayout &plane : planes) { |
| layout->rootPlanes++; |
| uint32_t lastOffsetInBits = 0; |
| uint32_t rootIx = layout->numPlanes; |
| |
| for (const PlaneLayoutComponent &component : plane.components) { |
| if (!gralloc4::isStandardPlaneLayoutComponentType(component.type)) { |
| mapper.unlock(handle); |
| return C2_CANNOT_DO; |
| } |
| |
| uint32_t rightShiftBits = component.offsetInBits - lastOffsetInBits; |
| uint32_t allocatedDepthInBits = component.sizeInBits + rightShiftBits; |
| C2PlanarLayout::plane_index_t planeId; |
| C2PlaneInfo::channel_t channel; |
| |
| switch (static_cast<PlaneLayoutComponentType>(component.type.value)) { |
| case PlaneLayoutComponentType::Y: |
| planeId = C2PlanarLayout::PLANE_Y; |
| channel = C2PlaneInfo::CHANNEL_Y; |
| break; |
| case PlaneLayoutComponentType::CB: |
| planeId = C2PlanarLayout::PLANE_U; |
| channel = C2PlaneInfo::CHANNEL_CB; |
| break; |
| case PlaneLayoutComponentType::CR: |
| planeId = C2PlanarLayout::PLANE_V; |
| channel = C2PlaneInfo::CHANNEL_CR; |
| break; |
| default: |
| mapper.unlock(handle); |
| return C2_CORRUPTED; |
| } |
| |
| addr[planeId] = pointer + plane.offsetInBytes + (component.offsetInBits / 8); |
| layout->planes[planeId] = { |
| channel, // channel |
| static_cast<int32_t>(plane.sampleIncrementInBits / 8), // colInc |
| static_cast<int32_t>(plane.strideInBytes), // rowInc |
| static_cast<uint32_t>(plane.horizontalSubsampling), // mColSampling |
| static_cast<uint32_t>(plane.verticalSubsampling), // mRowSampling |
| allocatedDepthInBits, // allocatedDepth (bits) |
| static_cast<uint32_t>(component.sizeInBits), // bitDepth (bits) |
| rightShiftBits, // rightShift (bits) |
| C2PlaneInfo::NATIVE, // endianness |
| rootIx, // rootIx |
| static_cast<uint32_t>(component.offsetInBits / 8), // offset (bytes) |
| }; |
| |
| layout->numPlanes++; |
| lastOffsetInBits = component.offsetInBits + component.sizeInBits; |
| } |
| } |
| return C2_OK; |
| } |
| |
| static c2_status_t PopulatePlaneLayout( |
| buffer_handle_t buffer, |
| const Rect &rect, |
| uint32_t format, |
| uint64_t grallocUsage, |
| uint32_t stride, |
| C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) { |
| // 'NATIVE' on Android means LITTLE_ENDIAN |
| constexpr C2PlaneInfo::endianness_t kEndianness = C2PlaneInfo::NATIVE; |
| |
| // Try to resolve IMPLEMENTATION_DEFINED format to accurate format if |
| // possible. |
| uint32_t fourCc; |
| if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED && |
| !GraphicBufferMapper::get().getPixelFormatFourCC(buffer, &fourCc)) { |
| switch (fourCc) { |
| case DRM_FORMAT_XBGR8888: |
| format = static_cast<uint32_t>(PixelFormat4::RGBX_8888); |
| break; |
| case DRM_FORMAT_ABGR8888: |
| format = static_cast<uint32_t>(PixelFormat4::RGBA_8888); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| switch (format) { |
| case static_cast<uint32_t>(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<native_handle_t *>(buffer), 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<int32_t>(4 * stride), // 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<int32_t>(4 * stride), // 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<int32_t>(4 * stride), // 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<int32_t>(4 * stride), // 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<uint32_t>(PixelFormat4::RGBA_8888): |
| // TODO: alpha channel |
| // fall-through |
| case static_cast<uint32_t>(PixelFormat4::RGBX_8888): { |
| void *pointer = nullptr; |
| // TODO: fence |
| status_t err = GraphicBufferMapper::get().lock( |
| const_cast<native_handle_t*>(buffer), 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<int32_t>(4 * 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 |
| static_cast<int32_t>(4 * 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 |
| static_cast<int32_t>(4 * stride), // rowInc |
| 1, // mColSampling |
| 1, // mRowSampling |
| 8, // allocatedDepth |
| 8, // bitDepth |
| 0, // rightShift |
| C2PlaneInfo::NATIVE, // endianness |
| C2PlanarLayout::PLANE_R, // rootIx |
| 2, // offset |
| }; |
| break; |
| } |
| |
| case static_cast<uint32_t>(PixelFormat4::BLOB): { |
| void *pointer = nullptr; |
| // TODO: fence |
| status_t err = GraphicBufferMapper::get().lock( |
| const_cast<native_handle_t*>(buffer), grallocUsage, rect, &pointer); |
| if (err) { |
| ALOGE("failed transaction: lock(BLOB)"); |
| return C2_CORRUPTED; |
| } |
| *addr = (uint8_t *)pointer; |
| break; |
| } |
| |
| case static_cast<uint32_t>(PixelFormat4::YCBCR_422_SP): |
| // fall-through |
| case static_cast<uint32_t>(PixelFormat4::YCRCB_420_SP): |
| // fall-through |
| case static_cast<uint32_t>(PixelFormat4::YCBCR_422_I): |
| // fall-through |
| case static_cast<uint32_t>(PixelFormat4::YCBCR_420_888): |
| // fall-through |
| case static_cast<uint32_t>(PixelFormat4::YV12): { |
| android_ycbcr ycbcrLayout; |
| |
| status_t err = GraphicBufferMapper::get().lockYCbCr( |
| const_cast<native_handle_t*>(buffer), 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 |
| }; |
| break; |
| } |
| |
| case static_cast<uint32_t>(PixelFormat4::YCBCR_P010): { |
| // In Android T, P010 is relaxed to allow arbitrary stride for the Y and UV planes, |
| // try locking with the gralloc4 mapper first. |
| c2_status_t status = Gralloc4Mapper_lock( |
| const_cast<native_handle_t*>(buffer), grallocUsage, rect, layout, addr); |
| if (status == C2_OK) { |
| break; |
| } |
| |
| void *pointer = nullptr; |
| status_t err = GraphicBufferMapper::get().lock( |
| const_cast<native_handle_t *>(buffer), 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 + stride * 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<int32_t>(2 * stride), // rowInc |
| 1, // mColSampling |
| 1, // mRowSampling |
| 16, // allocatedDepth |
| 10, // bitDepth |
| 6, // rightShift |
| kEndianness, // endianness |
| C2PlanarLayout::PLANE_Y, // rootIx |
| 0, // offset |
| }; |
| layout->planes[C2PlanarLayout::PLANE_U] = { |
| C2PlaneInfo::CHANNEL_CB, // channel |
| 4, // colInc |
| static_cast<int32_t>(2 * stride), // rowInc |
| 2, // mColSampling |
| 2, // mRowSampling |
| 16, // allocatedDepth |
| 10, // bitDepth |
| 6, // rightShift |
| kEndianness, // endianness |
| C2PlanarLayout::PLANE_U, // rootIx |
| 0, // offset |
| }; |
| layout->planes[C2PlanarLayout::PLANE_V] = { |
| C2PlaneInfo::CHANNEL_CR, // channel |
| 4, // colInc |
| static_cast<int32_t>(2 * stride), // rowInc |
| 2, // mColSampling |
| 2, // mRowSampling |
| 16, // allocatedDepth |
| 10, // bitDepth |
| 6, // rightShift |
| kEndianness, // endianness |
| C2PlanarLayout::PLANE_U, // rootIx |
| 2, // offset |
| }; |
| break; |
| } |
| |
| default: { |
| // We don't know what it is, let's try to lock it with gralloc4 |
| android_ycbcr ycbcrLayout; |
| if (isAtLeastT()) { |
| c2_status_t status = Gralloc4Mapper_lock( |
| const_cast<native_handle_t*>(buffer), grallocUsage, rect, layout, addr); |
| if (status == C2_OK) { |
| break; |
| } |
| } |
| |
| // fallback to lockYCbCr |
| status_t err = GraphicBufferMapper::get().lockYCbCr( |
| const_cast<native_handle_t*>(buffer), 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 |
| }; |
| 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(buffer); |
| if (err) { |
| ALOGE("failed transaction: unlock"); |
| return C2_CORRUPTED; |
| } |
| } |
| |
| void *pointer = nullptr; |
| err = GraphicBufferMapper::get().lock( |
| const_cast<native_handle_t *>(buffer), grallocUsage, rect, &pointer); |
| if (err) { |
| ALOGE("failed transaction: lock(??? %x)", format); |
| 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(stride), // rowInc |
| 1, // mColSampling |
| 1, // mRowSampling |
| 8, // allocatedDepth |
| 8, // bitDepth |
| 0, // rightShift |
| C2PlaneInfo::NATIVE, // endianness |
| 0, // rootIx |
| 0, // offset |
| }; |
| break; |
| } |
| } |
| return C2_OK; |
| } |
| |
| static void HandleInterleavedPlanes( |
| C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) { |
| if (layout->type == C2PlanarLayout::TYPE_YUV && layout->rootPlanes == 3) { |
| intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U]; |
| intptr_t uvColInc = layout->planes[C2PlanarLayout::PLANE_U].colInc; |
| if (uvOffset > 0 && uvOffset < uvColInc) { |
| layout->rootPlanes = 2; |
| layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U; |
| layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset; |
| } else if (uvOffset < 0 && uvOffset > -uvColInc) { |
| layout->rootPlanes = 2; |
| layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V; |
| layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset; |
| } |
| } |
| } |
| |
| } // 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); |
| } |
| |
| uint32_t ExtractFormatFromCodec2GrallocHandle(const C2Handle *const handle) { |
| return C2HandleGralloc::getPixelFormat(handle); |
| } |
| |
| 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<const C2GraphicAllocation> &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 address 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<native_handle_t *>(reinterpret_cast<const native_handle_t *>(mHandle))); |
| } |
| if (mLockedHandle) { |
| native_handle_delete( |
| const_cast<native_handle_t *>( |
| reinterpret_cast<const native_handle_t *>(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<C2AndroidMemoryUsage>(usage).asGrallocUsage(); |
| ALOGV("mapping buffer with usage %#llx => %#llx", |
| (long long)usage.expected, (long long)grallocUsage); |
| |
| // TODO |
| (void)fence; |
| |
| std::lock_guard<std::mutex> 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); |
| } |
| |
| c2_status_t ret = PopulatePlaneLayout( |
| mBuffer, rect, mFormat, grallocUsage, mStride, layout, addr); |
| if (ret != C2_OK) { |
| return ret; |
| } |
| mLocked = true; |
| |
| HandleInterleavedPlanes(layout, addr); |
| |
| ALOGV("C2AllocationGralloc::map: layout: type=%d numPlanes=%d rootPlanes=%d", |
| layout->type, layout->numPlanes, layout->rootPlanes); |
| for (int i = 0; i < layout->numPlanes; ++i) { |
| const C2PlaneInfo &plane = layout->planes[i]; |
| ALOGV("C2AllocationGralloc::map: plane[%d]: colInc=%d rowInc=%d rootIx=%u offset=%u", |
| i, plane.colInc, plane.rowInc, plane.rootIx, plane.offset); |
| } |
| |
| 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<std::mutex> 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<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; |
| 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<C2Allocator::Traits>(traits); |
| } |
| |
| 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); |
| |
| 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<native_handle_t*>(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<C2GraphicAllocation> *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<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(); |
| } |
| |
| // static |
| bool C2AllocatorGralloc::CheckHandle(const C2Handle* const o) { |
| return C2HandleGralloc::IsValid(o); |
| } |
| |
| |
| native_handle_t *UnwrapNativeCodec2AhwbHandle(const C2Handle *const handle) { |
| return C2HandleAhwb::UnwrapNativeHandle(handle); |
| } |
| |
| C2Handle *WrapNativeCodec2AhwbHandle( |
| const native_handle_t *const handle, |
| uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride, |
| uint64_t origId) { |
| return C2HandleAhwb::WrapNativeHandle(handle, width, height, format, usage, stride, |
| origId); |
| } |
| |
| class C2AllocationAhwb : public C2GraphicAllocation { |
| public: |
| virtual ~C2AllocationAhwb() 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<const C2GraphicAllocation> &other) const override; |
| |
| // internal methods |
| // |handle| will be moved. |
| |
| C2AllocationAhwb( |
| uint32_t width, uint32_t height, |
| uint32_t format, uint32_t layerCount, |
| uint64_t grallocUsage, uint32_t stride, |
| const C2HandleAhwb *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 native_handle_t *mRawHandle; |
| const C2HandleAhwb *mHandle; |
| buffer_handle_t mBuffer; |
| const C2HandleAhwb *mLockedHandle; |
| bool mLocked; |
| C2Allocator::id_t mAllocatorId; |
| std::mutex mMappedLock; |
| }; |
| |
| C2AllocationAhwb::C2AllocationAhwb( |
| uint32_t width, uint32_t height, |
| uint32_t format, uint32_t layerCount, |
| uint64_t grallocUsage, uint32_t stride, |
| const C2HandleAhwb *const handle, |
| C2Allocator::id_t allocatorId) |
| : C2GraphicAllocation(width, height), |
| mWidth(width), |
| mHeight(height), |
| mFormat(format), |
| mLayerCount(layerCount), |
| mGrallocUsage(grallocUsage), |
| mStride(stride), |
| mRawHandle(C2HandleAhwb::UnwrapNativeHandle(handle)), |
| mHandle(handle), |
| mBuffer(nullptr), |
| mLockedHandle(nullptr), |
| mLocked(false), |
| mAllocatorId(allocatorId) { |
| } |
| |
| C2AllocationAhwb::~C2AllocationAhwb() { |
| if (mBuffer && mLocked) { |
| // implementation ignores address 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 (mRawHandle) { |
| native_handle_close( |
| const_cast<native_handle_t *>( |
| reinterpret_cast<const native_handle_t *>(mRawHandle))); |
| native_handle_delete( |
| const_cast<native_handle_t *>( |
| reinterpret_cast<const native_handle_t *>(mRawHandle))); |
| } |
| if (mHandle) { |
| native_handle_delete( |
| const_cast<native_handle_t *>(reinterpret_cast<const native_handle_t *>(mHandle))); |
| } |
| if (mLockedHandle) { |
| native_handle_delete( |
| const_cast<native_handle_t *>( |
| reinterpret_cast<const native_handle_t *>(mLockedHandle))); |
| } |
| } |
| |
| c2_status_t C2AllocationAhwb::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<C2AndroidMemoryUsage>(usage).asGrallocUsage(); |
| ALOGV("mapping buffer with usage %#llx => %#llx", |
| (long long)usage.expected, (long long)grallocUsage); |
| |
| // TODO |
| (void)fence; |
| |
| std::lock_guard<std::mutex> lock(mMappedLock); |
| if (mBuffer && mLocked) { |
| ALOGD("already mapped"); |
| return C2_DUPLICATE; |
| } |
| if (!layout || !addr) { |
| ALOGD("wrong param"); |
| return C2_BAD_VALUE; |
| } |
| |
| if (!mBuffer) { |
| // TODO: libui/libgui dependency removal (b/214400477) |
| status_t err = GraphicBufferMapper::get().importBuffer( |
| mRawHandle, 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; |
| } |
| uint64_t origId = 0; |
| if (mHandle) { |
| mHandle->getOrigId(&origId); |
| } |
| |
| mLockedHandle = C2HandleAhwb::WrapAndMoveNativeHandle( |
| mBuffer, mWidth, mHeight, mFormat, mGrallocUsage, |
| mStride, origId); |
| } |
| |
| c2_status_t ret = PopulatePlaneLayout( |
| mBuffer, rect, mFormat, grallocUsage, mStride, layout, addr); |
| if (ret != C2_OK) { |
| return ret; |
| } |
| mLocked = true; |
| |
| HandleInterleavedPlanes(layout, addr); |
| |
| ALOGV("C2AllocationGralloc::map: layout: type=%d numPlanes=%d rootPlanes=%d", |
| layout->type, layout->numPlanes, layout->rootPlanes); |
| for (int i = 0; i < layout->numPlanes; ++i) { |
| const C2PlaneInfo &plane = layout->planes[i]; |
| ALOGV("C2AllocationGralloc::map: plane[%d]: colInc=%d rowInc=%d rootIx=%u offset=%u", |
| i, plane.colInc, plane.rowInc, plane.rootIx, plane.offset); |
| } |
| |
| return C2_OK; |
| } |
| |
| c2_status_t C2AllocationAhwb::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<std::mutex> 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 C2AllocationAhwb::equals(const std::shared_ptr<const C2GraphicAllocation> &other) const { |
| return other && other->handle() == handle(); |
| } |
| |
| /* ===================================== AHARDWAREBUFFER ALLOCATOR ============================= */ |
| class C2AllocatorAhwb::Impl { |
| public: |
| Impl(id_t id); |
| |
| 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; |
| }; |
| |
| void _UnwrapNativeCodec2AhwbMetadata( |
| const C2Handle *const handle, |
| uint32_t *width, uint32_t *height, uint32_t *format,uint64_t *usage, uint32_t *stride, |
| uint64_t *origId) { |
| (void)C2HandleAhwb::Import(handle, width, height, format, usage, stride, origId); |
| } |
| |
| C2AllocatorAhwb::Impl::Impl(id_t id) |
| : mInit(C2_OK) { |
| // TODO: get this from allocator |
| C2MemoryUsage minUsage = { 0, 0 }, maxUsage = { ~(uint64_t)0, ~(uint64_t)0 }; |
| Traits traits = { "android.allocator.ahwb", id, C2Allocator::GRAPHIC, minUsage, maxUsage }; |
| mTraits = std::make_shared<C2Allocator::Traits>(traits); |
| } |
| |
| c2_status_t C2AllocatorAhwb::Impl::newGraphicAllocation( |
| uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage, |
| std::shared_ptr<C2GraphicAllocation> *allocation) { |
| // TODO: for client side usage |
| // HAL side Ahwb allocation should be done via IGBA currently. |
| (void) width; |
| (void) height; |
| (void) format; |
| (void) usage; |
| (void) allocation; |
| return C2_OMITTED; |
| } |
| |
| c2_status_t C2AllocatorAhwb::Impl::priorGraphicAllocation( |
| const C2Handle *handle, |
| std::shared_ptr<C2GraphicAllocation> *allocation) { |
| |
| uint32_t width; |
| uint32_t height; |
| uint32_t format; |
| uint32_t layerCount = 1; |
| uint64_t grallocUsage; |
| uint32_t stride; |
| uint64_t origId; |
| |
| const C2HandleAhwb *ahwbHandle = C2HandleAhwb::Import( |
| handle, &width, &height, &format, &grallocUsage, &stride, &origId); |
| if (ahwbHandle == nullptr) { |
| return C2_BAD_VALUE; |
| } |
| |
| allocation->reset(new C2AllocationAhwb( |
| width, height, format, layerCount, |
| grallocUsage, stride, ahwbHandle, mTraits->id)); |
| return C2_OK; |
| } |
| |
| C2AllocatorAhwb::C2AllocatorAhwb(id_t id) |
| : mImpl(new Impl(id)) {} |
| |
| C2AllocatorAhwb::~C2AllocatorAhwb() { delete mImpl; } |
| |
| C2Allocator::id_t C2AllocatorAhwb::getId() const { |
| return mImpl->getId(); |
| } |
| |
| C2String C2AllocatorAhwb::getName() const { |
| return mImpl->getName(); |
| } |
| |
| std::shared_ptr<const C2Allocator::Traits> C2AllocatorAhwb::getTraits() const { |
| return mImpl->getTraits(); |
| } |
| |
| c2_status_t C2AllocatorAhwb::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 C2AllocatorAhwb::priorGraphicAllocation( |
| const C2Handle *handle, |
| std::shared_ptr<C2GraphicAllocation> *allocation) { |
| return mImpl->priorGraphicAllocation(handle, allocation); |
| } |
| |
| c2_status_t C2AllocatorAhwb::status() const { |
| return mImpl->status(); |
| } |
| |
| // static |
| bool C2AllocatorAhwb::CheckHandle(const C2Handle* const o) { |
| return C2HandleAhwb::IsValid(o); |
| } |
| } // namespace android |