677 lines
23 KiB
C++
677 lines
23 KiB
C++
/*
|
|
* Copyright (C) 2020 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.
|
|
*/
|
|
|
|
#include <android/hardware/graphics/mapper/3.0/IMapper.h>
|
|
#include <cutils/native_handle.h>
|
|
#include <sync/sync.h>
|
|
|
|
#include "cb_handle_30.h"
|
|
#include "host_connection_session.h"
|
|
#include "FormatConversions.h"
|
|
#include "debug.h"
|
|
|
|
#include "android/base/Tracing.h"
|
|
|
|
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
|
|
|
|
const int kOMX_COLOR_FormatYUV420Planar = 19;
|
|
|
|
using ::android::hardware::hidl_handle;
|
|
using ::android::hardware::hidl_vec;
|
|
using ::android::hardware::Return;
|
|
using ::android::hardware::Void;
|
|
|
|
using ::android::hardware::graphics::common::V1_2::PixelFormat;
|
|
using ::android::hardware::graphics::common::V1_0::BufferUsage;
|
|
|
|
namespace MapperV3 = ::android::hardware::graphics::mapper::V3_0;
|
|
|
|
using IMapper3 = MapperV3::IMapper;
|
|
using Error3 = MapperV3::Error;
|
|
using YCbCrLayout3 = MapperV3::YCbCrLayout;
|
|
|
|
namespace {
|
|
size_t align(const size_t v, const size_t a) { return (v + a - 1) & ~(a - 1); }
|
|
|
|
static int waitFenceFd(const int fd, const char* logname) {
|
|
const int warningTimeout = 5000;
|
|
if (sync_wait(fd, warningTimeout) < 0) {
|
|
if (errno == ETIME) {
|
|
ALOGW("%s: fence %d didn't signal in %d ms", logname, fd, warningTimeout);
|
|
if (sync_wait(fd, -1) < 0) {
|
|
RETURN_ERROR(errno);
|
|
} else {
|
|
RETURN(0);
|
|
}
|
|
} else {
|
|
RETURN_ERROR(errno);
|
|
}
|
|
} else {
|
|
RETURN(0);
|
|
}
|
|
}
|
|
|
|
int waitHidlFence(const hidl_handle& hidlHandle, const char* logname) {
|
|
const native_handle_t* nativeHandle = hidlHandle.getNativeHandle();
|
|
|
|
if (!nativeHandle) {
|
|
RETURN(0);
|
|
}
|
|
if (nativeHandle->numFds > 1) {
|
|
RETURN_ERROR(-EINVAL);
|
|
}
|
|
if (nativeHandle->numInts != 0) {
|
|
RETURN_ERROR(-EINVAL);
|
|
}
|
|
|
|
return waitFenceFd(nativeHandle->data[0], logname);
|
|
}
|
|
|
|
constexpr uint64_t one64 = 1;
|
|
|
|
constexpr uint64_t ones(int from, int to) {
|
|
return ((one64 << (to - from + 1)) - 1) << from;
|
|
}
|
|
|
|
class GoldfishMapper : public IMapper3 {
|
|
public:
|
|
GoldfishMapper() : m_hostConn(HostConnection::createUnique()) {
|
|
GoldfishAddressSpaceHostMemoryAllocator host_memory_allocator(false);
|
|
CRASH_IF(!host_memory_allocator.is_opened(),
|
|
"GoldfishAddressSpaceHostMemoryAllocator failed to open");
|
|
|
|
GoldfishAddressSpaceBlock bufferBits;
|
|
CRASH_IF(host_memory_allocator.hostMalloc(&bufferBits, 256),
|
|
"hostMalloc failed");
|
|
|
|
m_physAddrToOffset = bufferBits.physAddr() - bufferBits.offset();
|
|
|
|
host_memory_allocator.hostFree(&bufferBits);
|
|
}
|
|
|
|
Return<void> importBuffer(const hidl_handle& hh,
|
|
importBuffer_cb hidl_cb) {
|
|
native_handle_t* imported = nullptr;
|
|
const Error3 e = importBufferImpl(hh.getNativeHandle(), &imported);
|
|
if (e == Error3::NONE) {
|
|
hidl_cb(Error3::NONE, imported);
|
|
} else {
|
|
hidl_cb(e, nullptr);
|
|
}
|
|
return {};
|
|
}
|
|
|
|
Return<Error3> freeBuffer(void* raw) {
|
|
if (!raw) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
cb_handle_30_t* cb = cb_handle_30_t::from(raw);
|
|
if (!cb) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
|
|
if (cb->hostHandle) {
|
|
const HostConnectionSession conn = getHostConnectionSession();
|
|
ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
|
|
rcEnc->rcCloseColorBuffer(rcEnc, cb->hostHandle);
|
|
}
|
|
|
|
if (cb->mmapedSize > 0) {
|
|
GoldfishAddressSpaceBlock::memoryUnmap(cb->getBufferPtr(), cb->mmapedSize);
|
|
}
|
|
|
|
native_handle_close(cb);
|
|
native_handle_delete(cb);
|
|
|
|
RETURN(Error3::NONE);
|
|
}
|
|
|
|
Return<void> lock(void* raw,
|
|
uint64_t cpuUsage,
|
|
const Rect& accessRegion,
|
|
const hidl_handle& acquireFence,
|
|
lock_cb hidl_cb) {
|
|
void* ptr = nullptr;
|
|
int32_t bytesPerPixel = 0;
|
|
int32_t bytesPerStride = 0;
|
|
|
|
const Error3 e = lockImpl(raw, cpuUsage, accessRegion, acquireFence,
|
|
&ptr, &bytesPerPixel, &bytesPerStride);
|
|
if (e == Error3::NONE) {
|
|
hidl_cb(Error3::NONE, ptr, bytesPerPixel, bytesPerStride);
|
|
} else {
|
|
hidl_cb(e, nullptr, 0, 0);
|
|
}
|
|
return {};
|
|
}
|
|
|
|
Return<void> lockYCbCr(void* raw,
|
|
uint64_t cpuUsage,
|
|
const Rect& accessRegion,
|
|
const hidl_handle& acquireFence,
|
|
lockYCbCr_cb hidl_cb) {
|
|
YCbCrLayout3 ycbcr = {};
|
|
const Error3 e = lockYCbCrImpl(raw, cpuUsage, accessRegion, acquireFence,
|
|
&ycbcr);
|
|
if (e == Error3::NONE) {
|
|
hidl_cb(Error3::NONE, ycbcr);
|
|
} else {
|
|
hidl_cb(e, {});
|
|
}
|
|
return {};
|
|
}
|
|
|
|
Return<void> unlock(void* raw, unlock_cb hidl_cb) {
|
|
hidl_cb(unlockImpl(raw), {});
|
|
return {};
|
|
|
|
}
|
|
|
|
Return<void> createDescriptor(const BufferDescriptorInfo& description,
|
|
createDescriptor_cb hidl_cb) {
|
|
hidl_vec<uint32_t> raw;
|
|
encodeBufferDescriptorInfo(description, &raw);
|
|
hidl_cb(Error3::NONE, raw);
|
|
return {};
|
|
}
|
|
|
|
Return<void> isSupported(const IMapper::BufferDescriptorInfo& description,
|
|
isSupported_cb hidl_cb) {
|
|
hidl_cb(Error3::NONE, isSupportedImpl(description));
|
|
return {};
|
|
}
|
|
|
|
Return<Error3> validateBufferSize(void* buffer,
|
|
const BufferDescriptorInfo& descriptor,
|
|
uint32_t stride) {
|
|
const cb_handle_30_t* cb = cb_handle_30_t::from(buffer);
|
|
if (cb) {
|
|
return validateBufferSizeImpl(*cb, descriptor, stride);
|
|
} else {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
}
|
|
|
|
Return<void> getTransportSize(void* buffer,
|
|
getTransportSize_cb hidl_cb) {
|
|
const cb_handle_30_t* cb = cb_handle_30_t::from(buffer);
|
|
if (cb) {
|
|
hidl_cb(Error3::NONE, cb->numFds, cb->numInts);
|
|
} else {
|
|
hidl_cb(Error3::BAD_BUFFER, 0, 0);
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
private: // **** impl ****
|
|
Error3 importBufferImpl(const native_handle_t* nh, native_handle_t** phandle) {
|
|
if (!nh) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
native_handle_t* imported = native_handle_clone(nh);
|
|
if (!imported) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
cb_handle_30_t* cb = cb_handle_30_t::from(imported);
|
|
if (!cb) {
|
|
native_handle_close(imported);
|
|
native_handle_delete(imported);
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
|
|
if (cb->mmapedSize > 0) {
|
|
void* ptr;
|
|
const int res = GoldfishAddressSpaceBlock::memoryMap(
|
|
cb->getBufferPtr(),
|
|
cb->mmapedSize,
|
|
cb->bufferFd,
|
|
cb->getMmapedOffset(),
|
|
&ptr);
|
|
if (res) {
|
|
native_handle_close(imported);
|
|
native_handle_delete(imported);
|
|
RETURN_ERROR(Error3::NO_RESOURCES);
|
|
}
|
|
cb->setBufferPtr(ptr);
|
|
}
|
|
|
|
if (cb->hostHandle) {
|
|
const HostConnectionSession conn = getHostConnectionSession();
|
|
ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
|
|
rcEnc->rcOpenColorBuffer2(rcEnc, cb->hostHandle);
|
|
}
|
|
|
|
*phandle = imported;
|
|
RETURN(Error3::NONE);
|
|
}
|
|
|
|
Error3 lockImpl(void* raw,
|
|
uint64_t cpuUsage,
|
|
const Rect& accessRegion,
|
|
const hidl_handle& acquireFence,
|
|
void** pptr,
|
|
int32_t* pBytesPerPixel,
|
|
int32_t* pBytesPerStride) {
|
|
if (!raw) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
cb_handle_30_t* cb = cb_handle_30_t::from(raw);
|
|
if (!cb) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
if (!cb->bufferSize) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
char* const bufferBits = static_cast<char*>(cb->getBufferPtr());
|
|
if (!bufferBits) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
if (waitHidlFence(acquireFence, __func__)) {
|
|
RETURN_ERROR(Error3::BAD_VALUE);
|
|
}
|
|
|
|
if (cb->hostHandle) {
|
|
const Error3 e = lockHostImpl(*cb, cpuUsage, accessRegion, bufferBits);
|
|
if (e != Error3::NONE) {
|
|
return e;
|
|
}
|
|
}
|
|
|
|
*pptr = bufferBits;
|
|
*pBytesPerPixel = cb->bytesPerPixel;
|
|
*pBytesPerStride = cb->bytesPerPixel * cb->stride;
|
|
RETURN(Error3::NONE);
|
|
}
|
|
|
|
Error3 lockYCbCrImpl(void* raw,
|
|
uint64_t cpuUsage,
|
|
const Rect& accessRegion,
|
|
const hidl_handle& acquireFence,
|
|
YCbCrLayout3* pYcbcr) {
|
|
if (!raw) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
cb_handle_30_t* cb = cb_handle_30_t::from(raw);
|
|
if (!cb) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
if (!cb->bufferSize) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
char* const bufferBits = static_cast<char*>(cb->getBufferPtr());
|
|
if (!bufferBits) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
if (waitHidlFence(acquireFence, __func__)) {
|
|
RETURN_ERROR(Error3::BAD_VALUE);
|
|
}
|
|
|
|
size_t uOffset;
|
|
size_t vOffset;
|
|
size_t yStride;
|
|
size_t cStride;
|
|
size_t cStep;
|
|
switch (static_cast<PixelFormat>(cb->format)) {
|
|
case PixelFormat::YCRCB_420_SP:
|
|
yStride = cb->width;
|
|
cStride = yStride;
|
|
vOffset = yStride * cb->height;
|
|
uOffset = vOffset + 1;
|
|
cStep = 2;
|
|
break;
|
|
|
|
case PixelFormat::YV12:
|
|
// https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12
|
|
yStride = align(cb->width, 16);
|
|
cStride = align(yStride / 2, 16);
|
|
vOffset = yStride * cb->height;
|
|
uOffset = vOffset + (cStride * cb->height / 2);
|
|
cStep = 1;
|
|
break;
|
|
|
|
case PixelFormat::YCBCR_420_888:
|
|
yStride = cb->width;
|
|
cStride = yStride / 2;
|
|
uOffset = cb->height * yStride;
|
|
vOffset = uOffset + cStride * cb->height / 2;
|
|
cStep = 1;
|
|
break;
|
|
|
|
default:
|
|
if (static_cast<android::hardware::graphics::common::V1_1::PixelFormat>(cb->format) ==
|
|
android::hardware::graphics::common::V1_1::PixelFormat::YCBCR_P010) {
|
|
yStride = cb->width * 2;
|
|
cStride = yStride;
|
|
uOffset = cb->height * yStride;
|
|
vOffset = uOffset + 2;
|
|
cStep = 4;
|
|
break;
|
|
}
|
|
|
|
ALOGE("%s:%d unexpected format (%d)", __func__, __LINE__, cb->format);
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
|
|
if (cb->hostHandle) {
|
|
const Error3 e = lockHostImpl(*cb, cpuUsage, accessRegion, bufferBits);
|
|
if (e != Error3::NONE) {
|
|
return e;
|
|
}
|
|
}
|
|
|
|
pYcbcr->y = bufferBits;
|
|
pYcbcr->cb = bufferBits + uOffset;
|
|
pYcbcr->cr = bufferBits + vOffset;
|
|
pYcbcr->yStride = yStride;
|
|
pYcbcr->cStride = cStride;
|
|
pYcbcr->chromaStep = cStep;
|
|
|
|
RETURN(Error3::NONE);
|
|
}
|
|
|
|
Error3 lockHostImpl(cb_handle_30_t& cb,
|
|
const uint32_t usage,
|
|
const Rect& accessRegion,
|
|
char* const bufferBits) {
|
|
const bool usageSwRead = usage & BufferUsage::CPU_READ_MASK;
|
|
const bool usageSwWrite = usage & BufferUsage::CPU_WRITE_MASK;
|
|
const bool usageHwCamera = usage & (BufferUsage::CAMERA_INPUT | BufferUsage::CAMERA_OUTPUT);
|
|
const bool usageHwCameraWrite = usage & BufferUsage::CAMERA_OUTPUT;
|
|
|
|
const HostConnectionSession conn = getHostConnectionSession();
|
|
ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
|
|
|
|
const int res = rcEnc->rcColorBufferCacheFlush(
|
|
rcEnc, cb.hostHandle, 0, usageSwRead);
|
|
if (res < 0) {
|
|
RETURN_ERROR(Error3::NO_RESOURCES);
|
|
}
|
|
|
|
// camera delivers bits to the buffer directly and does not require
|
|
// an explicit read.
|
|
const bool cbReadable = cb.usage & BufferUsage::CPU_READ_MASK;
|
|
if (usageSwRead && !usageHwCamera && cbReadable) {
|
|
if (gralloc_is_yuv_format(cb.format)) {
|
|
if (rcEnc->hasYUVCache()) {
|
|
uint32_t bufferSize;
|
|
switch (static_cast<PixelFormat>(cb.format)) {
|
|
case PixelFormat::YV12:
|
|
get_yv12_offsets(cb.width, cb.height,
|
|
nullptr, nullptr, &bufferSize);
|
|
break;
|
|
case PixelFormat::YCBCR_420_888:
|
|
get_yuv420p_offsets(cb.width, cb.height,
|
|
nullptr, nullptr, &bufferSize);
|
|
break;
|
|
default:
|
|
CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format");
|
|
break;
|
|
}
|
|
|
|
rcEnc->rcReadColorBufferYUV(rcEnc, cb.hostHandle,
|
|
0, 0, cb.width, cb.height,
|
|
bufferBits, bufferSize);
|
|
} else {
|
|
// We are using RGB888
|
|
std::vector<char> tmpBuf(cb.width * cb.height * 3);
|
|
rcEnc->rcReadColorBuffer(rcEnc, cb.hostHandle,
|
|
0, 0, cb.width, cb.height,
|
|
cb.glFormat, cb.glType,
|
|
tmpBuf.data());
|
|
switch (static_cast<PixelFormat>(cb.format)) {
|
|
case PixelFormat::YV12:
|
|
rgb888_to_yv12(bufferBits, tmpBuf.data(),
|
|
cb.width, cb.height,
|
|
accessRegion.left,
|
|
accessRegion.top,
|
|
accessRegion.left + accessRegion.width - 1,
|
|
accessRegion.top + accessRegion.height - 1);
|
|
break;
|
|
case PixelFormat::YCBCR_420_888:
|
|
rgb888_to_yuv420p(bufferBits, tmpBuf.data(),
|
|
cb.width, cb.height,
|
|
accessRegion.left,
|
|
accessRegion.top,
|
|
accessRegion.left + accessRegion.width - 1,
|
|
accessRegion.top + accessRegion.height - 1);
|
|
break;
|
|
default:
|
|
CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format");
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (rcEnc->featureInfo()->hasReadColorBufferDma) {
|
|
{
|
|
AEMU_SCOPED_TRACE("bindDmaDirectly");
|
|
rcEnc->bindDmaDirectly(bufferBits,
|
|
getMmapedPhysAddr(cb.getMmapedOffset()));
|
|
}
|
|
rcEnc->rcReadColorBufferDMA(rcEnc,
|
|
cb.hostHandle,
|
|
0, 0, cb.width, cb.height,
|
|
cb.glFormat, cb.glType,
|
|
bufferBits, cb.width * cb.height * cb.bytesPerPixel);
|
|
} else {
|
|
rcEnc->rcReadColorBuffer(rcEnc,
|
|
cb.hostHandle,
|
|
0, 0, cb.width, cb.height,
|
|
cb.glFormat, cb.glType,
|
|
bufferBits);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (usageSwWrite || usageHwCameraWrite) {
|
|
cb.lockedLeft = accessRegion.left;
|
|
cb.lockedTop = accessRegion.top;
|
|
cb.lockedWidth = accessRegion.width;
|
|
cb.lockedHeight = accessRegion.height;
|
|
} else {
|
|
cb.lockedLeft = 0;
|
|
cb.lockedTop = 0;
|
|
cb.lockedWidth = cb.width;
|
|
cb.lockedHeight = cb.height;
|
|
}
|
|
|
|
cb.locked = 1;
|
|
cb.lockedUsage = usage;
|
|
|
|
RETURN(Error3::NONE);
|
|
}
|
|
|
|
Error3 unlockImpl(void* raw) {
|
|
AEMU_SCOPED_TRACE("unlockImpl body");
|
|
if (!raw) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
cb_handle_30_t* cb = cb_handle_30_t::from(raw);
|
|
if (!cb) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
if (!cb->bufferSize) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
char* const bufferBits = static_cast<char*>(cb->getBufferPtr());
|
|
if (!bufferBits) {
|
|
RETURN_ERROR(Error3::BAD_BUFFER);
|
|
}
|
|
|
|
if (cb->hostHandle) {
|
|
unlockHostImpl(*cb, bufferBits);
|
|
}
|
|
|
|
RETURN(Error3::NONE);
|
|
}
|
|
|
|
void unlockHostImpl(cb_handle_30_t& cb, char* const bufferBits) {
|
|
AEMU_SCOPED_TRACE("unlockHostImpl body");
|
|
const int bpp = glUtilsPixelBitSize(cb.glFormat, cb.glType) >> 3;
|
|
const uint32_t lockedUsage = cb.lockedUsage;
|
|
const uint32_t rgbSize = cb.width * cb.height * bpp;
|
|
const char* bitsToSend;
|
|
uint32_t sizeToSend;
|
|
|
|
const uint32_t usageSwWrite = (uint32_t)BufferUsage::CPU_WRITE_MASK;
|
|
uint32_t readOnly = (!(lockedUsage & usageSwWrite));
|
|
|
|
if (!readOnly) {
|
|
if (gralloc_is_yuv_format(cb.format)) {
|
|
bitsToSend = bufferBits;
|
|
switch (static_cast<PixelFormat>(cb.format)) {
|
|
case PixelFormat::YV12:
|
|
get_yv12_offsets(cb.width, cb.height, nullptr, nullptr, &sizeToSend);
|
|
break;
|
|
case PixelFormat::YCBCR_420_888:
|
|
get_yuv420p_offsets(cb.width, cb.height, nullptr, nullptr, &sizeToSend);
|
|
break;
|
|
default:
|
|
CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format");
|
|
break;
|
|
}
|
|
} else {
|
|
bitsToSend = bufferBits;
|
|
sizeToSend = rgbSize;
|
|
}
|
|
|
|
{
|
|
const HostConnectionSession conn = getHostConnectionSession();
|
|
ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
|
|
{
|
|
AEMU_SCOPED_TRACE("bindDmaDirectly");
|
|
rcEnc->bindDmaDirectly(bufferBits,
|
|
getMmapedPhysAddr(cb.getMmapedOffset()));
|
|
}
|
|
{
|
|
AEMU_SCOPED_TRACE("updateColorBuffer");
|
|
rcEnc->rcUpdateColorBufferDMA(rcEnc, cb.hostHandle,
|
|
0, 0, cb.width, cb.height,
|
|
cb.glFormat, cb.glType,
|
|
const_cast<char*>(bitsToSend),
|
|
sizeToSend);
|
|
}
|
|
}
|
|
}
|
|
|
|
cb.lockedLeft = 0;
|
|
cb.lockedTop = 0;
|
|
cb.lockedWidth = 0;
|
|
cb.lockedHeight = 0;
|
|
cb.locked = 0;
|
|
cb.lockedUsage = 0;
|
|
}
|
|
|
|
/* BufferUsage bits that must be zero */
|
|
static constexpr uint64_t kReservedUsage =
|
|
(one64 << 10)
|
|
| (one64 << 13)
|
|
| (one64 << 19)
|
|
| (one64 << 21)
|
|
| ones(25, 27) /* bits 25-27 must be zero and are reserved for future versions */
|
|
| ones(32, 47); /* bits 32-47 must be zero and are reserved for future versions */
|
|
|
|
bool isSupportedImpl(const IMapper::BufferDescriptorInfo& descriptor) const {
|
|
if (!descriptor.width) { RETURN(false); }
|
|
if (!descriptor.height) { RETURN(false); }
|
|
if (descriptor.layerCount != 1) { RETURN(false); }
|
|
|
|
const uint64_t usage64 = descriptor.usage;
|
|
if (usage64 & kReservedUsage) {
|
|
RETURN(false);
|
|
}
|
|
|
|
const uint32_t usage = usage64;
|
|
const bool usageSwWrite = usage & BufferUsage::CPU_WRITE_MASK;
|
|
const bool usageSwRead = usage & BufferUsage::CPU_READ_MASK;
|
|
const bool usageHwCamWrite = usage & BufferUsage::CAMERA_OUTPUT;
|
|
const bool usageHwCamRead = usage & BufferUsage::CAMERA_INPUT;
|
|
|
|
switch (descriptor.format) {
|
|
case PixelFormat::RGBA_8888:
|
|
case PixelFormat::RGBX_8888:
|
|
case PixelFormat::BGRA_8888:
|
|
case PixelFormat::RGB_565:
|
|
case PixelFormat::RGBA_FP16:
|
|
case PixelFormat::RGBA_1010102:
|
|
case PixelFormat::YCRCB_420_SP:
|
|
case PixelFormat::YV12:
|
|
case PixelFormat::YCBCR_420_888:
|
|
RETURN(true);
|
|
|
|
case PixelFormat::IMPLEMENTATION_DEFINED:
|
|
if (usage & BufferUsage::CAMERA_OUTPUT) {
|
|
RETURN(true);
|
|
}
|
|
RETURN(false);
|
|
|
|
case PixelFormat::RGB_888:
|
|
RETURN(0 == (usage & (BufferUsage::GPU_TEXTURE |
|
|
BufferUsage::GPU_RENDER_TARGET |
|
|
BufferUsage::COMPOSER_OVERLAY |
|
|
BufferUsage::COMPOSER_CLIENT_TARGET)));
|
|
|
|
case PixelFormat::RAW16:
|
|
case PixelFormat::Y16:
|
|
RETURN((usageSwRead || usageHwCamRead) &&
|
|
(usageSwWrite || usageHwCamWrite));
|
|
|
|
case PixelFormat::BLOB:
|
|
RETURN(usageSwRead);
|
|
|
|
default:
|
|
if (static_cast<int>(descriptor.format) == kOMX_COLOR_FormatYUV420Planar) {
|
|
return (usage & BufferUsage::VIDEO_DECODER) != 0;
|
|
}
|
|
|
|
RETURN(false);
|
|
}
|
|
}
|
|
|
|
Error3 validateBufferSizeImpl(const cb_handle_t& /*cb*/,
|
|
const BufferDescriptorInfo& /*descriptor*/,
|
|
uint32_t /*stride*/) {
|
|
RETURN(Error3::NONE);
|
|
}
|
|
|
|
HostConnectionSession getHostConnectionSession() const {
|
|
return HostConnectionSession(m_hostConn.get());
|
|
}
|
|
|
|
static void encodeBufferDescriptorInfo(const BufferDescriptorInfo& d,
|
|
hidl_vec<uint32_t>* raw) {
|
|
raw->resize(5);
|
|
|
|
(*raw)[0] = d.width;
|
|
(*raw)[1] = d.height;
|
|
(*raw)[2] = d.layerCount;
|
|
(*raw)[3] = static_cast<uint32_t>(d.format);
|
|
(*raw)[4] = d.usage & UINT32_MAX;
|
|
}
|
|
|
|
uint64_t getMmapedPhysAddr(uint64_t offset) const {
|
|
return m_physAddrToOffset + offset;
|
|
}
|
|
|
|
std::unique_ptr<HostConnection> m_hostConn;
|
|
uint64_t m_physAddrToOffset;
|
|
};
|
|
} // namespace
|
|
|
|
extern "C" IMapper3* HIDL_FETCH_IMapper(const char* /*name*/) {
|
|
return new GoldfishMapper;
|
|
}
|