You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
969 lines
40 KiB
969 lines
40 KiB
/*
|
|
* 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 <android/hardware/graphics/common/1.2/types.h>
|
|
#include <cutils/native_handle.h>
|
|
#include <hardware/gralloc.h>
|
|
#include <ui/GraphicBufferAllocator.h>
|
|
#include <ui/GraphicBufferMapper.h>
|
|
#include <ui/Rect.h>
|
|
|
|
#include <C2AllocatorGralloc.h>
|
|
#include <C2Buffer.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
|
|
|
|
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 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);
|
|
}
|
|
};
|
|
|
|
} // 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<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 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<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);
|
|
}
|
|
switch (mFormat) {
|
|
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 *>(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<int32_t>(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<int32_t>(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<int32_t>(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<int32_t>(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<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*>(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<int32_t>(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<int32_t>(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<int32_t>(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<uint32_t>(PixelFormat4::BLOB): {
|
|
void *pointer = nullptr;
|
|
// TODO: fence
|
|
status_t err = GraphicBufferMapper::get().lock(
|
|
const_cast<native_handle_t*>(mBuffer), 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*>(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<uint32_t>(PixelFormat4::YCBCR_P010): {
|
|
void *pointer = nullptr;
|
|
status_t err = GraphicBufferMapper::get().lock(
|
|
const_cast<native_handle_t *>(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<int32_t>(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<int32_t>(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<int32_t>(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<native_handle_t*>(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<native_handle_t *>(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<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);
|
|
}
|
|
|
|
} // namespace android
|