exynos4: android.hardware.graphics.mapper@2.0 for Exynos4

Change-Id: Ic3156237063e72b3a3745491685d3e5cbedd908d
This commit is contained in:
Dominggoes Isakh 2018-08-12 22:05:06 +02:00
parent d50cd57a75
commit 58db5d59b0
8 changed files with 1097 additions and 0 deletions

View file

@ -0,0 +1,40 @@
//
// 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.
cc_library_shared {
name: "android.hardware.graphics.mapper@2.0-impl-exynos4",
defaults: ["hidl_defaults"],
vendor: true,
relative_install_path: "hw",
srcs: ["GrallocMapper.cpp", "Gralloc0Mapper.cpp", "Gralloc1Mapper.cpp"],
cppflags: ["-Wall", "-Wextra"],
shared_libs: [
"android.hardware.graphics.mapper@2.0",
"libbase",
"libcutils",
"libhardware",
"libhidlbase",
"libhidltransport",
"liblog",
"libsync",
"libutils",
],
}
cc_library_headers {
name: "libgrallocmapperincludes",
vendor: true,
export_include_dirs: ["."],
}

View file

@ -0,0 +1,156 @@
/*
* Copyright 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_TAG "Gralloc0Mapper"
#include "Gralloc0Mapper.h"
#include <log/log.h>
namespace android {
namespace hardware {
namespace graphics {
namespace mapper {
namespace V2_0 {
namespace implementation {
Gralloc0Mapper::Gralloc0Mapper(const hw_module_t* module)
: mModule(reinterpret_cast<const gralloc_module_t*>(module)),
mMinor(module->module_api_version & 0xff) {
mCapabilities.highUsageBits = false;
mCapabilities.layeredBuffers = false;
mCapabilities.unregisterImplyDelete = false;
}
Error Gralloc0Mapper::registerBuffer(buffer_handle_t bufferHandle) {
int result = mModule->registerBuffer(mModule, bufferHandle);
return result ? Error::BAD_BUFFER : Error::NONE;
}
void Gralloc0Mapper::unregisterBuffer(buffer_handle_t bufferHandle) {
mModule->unregisterBuffer(mModule, bufferHandle);
}
Error Gralloc0Mapper::lockBuffer(buffer_handle_t bufferHandle,
uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
void** outData) {
int result;
void* data = nullptr;
if (mMinor >= 3 && mModule->lockAsync) {
// Dup fenceFd as it is going to be owned by gralloc. Note that it is
// gralloc's responsibility to close it, even on locking errors.
if (fenceFd >= 0) {
fenceFd = dup(fenceFd);
if (fenceFd < 0) {
return Error::NO_RESOURCES;
}
}
result = mModule->lockAsync(mModule, bufferHandle, cpuUsage,
accessRegion.left, accessRegion.top,
accessRegion.width, accessRegion.height,
&data, fenceFd);
} else {
waitFenceFd(fenceFd, "Gralloc0Mapper::lock");
result = mModule->lock(mModule, bufferHandle, cpuUsage,
accessRegion.left, accessRegion.top,
accessRegion.width, accessRegion.height, &data);
}
if (result) {
return Error::BAD_VALUE;
} else {
*outData = data;
return Error::NONE;
}
}
Error Gralloc0Mapper::lockBuffer(buffer_handle_t bufferHandle,
uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
YCbCrLayout* outLayout) {
int result;
android_ycbcr ycbcr = {};
if (mMinor >= 3 && mModule->lockAsync_ycbcr) {
// Dup fenceFd as it is going to be owned by gralloc. Note that it is
// gralloc's responsibility to close it, even on locking errors.
if (fenceFd >= 0) {
fenceFd = dup(fenceFd);
if (fenceFd < 0) {
return Error::NO_RESOURCES;
}
}
result = mModule->lockAsync_ycbcr(mModule, bufferHandle, cpuUsage,
accessRegion.left, accessRegion.top,
accessRegion.width,
accessRegion.height, &ycbcr, fenceFd);
} else {
waitFenceFd(fenceFd, "Gralloc0Mapper::lockYCbCr");
if (mModule->lock_ycbcr) {
result = mModule->lock_ycbcr(mModule, bufferHandle, cpuUsage,
accessRegion.left, accessRegion.top,
accessRegion.width,
accessRegion.height, &ycbcr);
} else {
result = -EINVAL;
}
}
if (result) {
return Error::BAD_VALUE;
} else {
outLayout->y = ycbcr.y;
outLayout->cb = ycbcr.cb;
outLayout->cr = ycbcr.cr;
outLayout->yStride = ycbcr.ystride;
outLayout->cStride = ycbcr.cstride;
outLayout->chromaStep = ycbcr.chroma_step;
return Error::NONE;
}
}
Error Gralloc0Mapper::unlockBuffer(buffer_handle_t bufferHandle,
int* outFenceFd) {
int result;
int fenceFd = -1;
if (mMinor >= 3 && mModule->unlockAsync) {
result = mModule->unlockAsync(mModule, bufferHandle, &fenceFd);
} else {
result = mModule->unlock(mModule, bufferHandle);
}
if (result) {
// we always own the fenceFd even when unlock failed
if (fenceFd >= 0) {
close(fenceFd);
}
return Error::BAD_VALUE;
} else {
*outFenceFd = fenceFd;
return Error::NONE;
}
}
} // namespace implementation
} // namespace V2_0
} // namespace mapper
} // namespace graphics
} // namespace hardware
} // namespace android

View file

@ -0,0 +1,56 @@
/*
* Copyright 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.
*/
#ifndef ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC0MAPPER_H
#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC0MAPPER_H
#include "GrallocMapper.h"
#include <hardware/gralloc.h>
namespace android {
namespace hardware {
namespace graphics {
namespace mapper {
namespace V2_0 {
namespace implementation {
class Gralloc0Mapper : public GrallocMapper {
public:
Gralloc0Mapper(const hw_module_t* module);
private:
Error registerBuffer(buffer_handle_t bufferHandle) override;
void unregisterBuffer(buffer_handle_t bufferHandle) override;
Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
void** outData) override;
Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
YCbCrLayout* outLayout) override;
Error unlockBuffer(buffer_handle_t bufferHandle, int* outFenceFd) override;
const gralloc_module_t* mModule;
uint8_t mMinor;
};
} // namespace implementation
} // namespace V2_0
} // namespace mapper
} // namespace graphics
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC0MAPPER_H

View file

@ -0,0 +1,273 @@
/*
* Copyright 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_TAG "Gralloc1Mapper"
#include "Gralloc1Mapper.h"
#include <vector>
#include <log/log.h>
namespace android {
namespace hardware {
namespace graphics {
namespace mapper {
namespace V2_0 {
namespace implementation {
using android::hardware::graphics::common::V1_0::BufferUsage;
Gralloc1Mapper::Gralloc1Mapper(const hw_module_t* module)
: mDevice(nullptr), mDispatch() {
int result = gralloc1_open(module, &mDevice);
if (result) {
LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s",
strerror(-result));
}
initCapabilities();
initDispatch();
}
Gralloc1Mapper::~Gralloc1Mapper() {
gralloc1_close(mDevice);
}
void Gralloc1Mapper::initCapabilities() {
mCapabilities.highUsageBits = true;
mCapabilities.layeredBuffers = false;
mCapabilities.unregisterImplyDelete = false;
uint32_t count = 0;
mDevice->getCapabilities(mDevice, &count, nullptr);
std::vector<int32_t> capabilities(count);
mDevice->getCapabilities(mDevice, &count, capabilities.data());
capabilities.resize(count);
for (auto capability : capabilities) {
switch (capability) {
case GRALLOC1_CAPABILITY_LAYERED_BUFFERS:
mCapabilities.layeredBuffers = true;
break;
case GRALLOC1_CAPABILITY_RELEASE_IMPLY_DELETE:
mCapabilities.unregisterImplyDelete = true;
break;
}
}
}
template <typename T>
void Gralloc1Mapper::initDispatch(gralloc1_function_descriptor_t desc,
T* outPfn) {
auto pfn = mDevice->getFunction(mDevice, desc);
if (!pfn) {
LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc);
}
*outPfn = reinterpret_cast<T>(pfn);
}
void Gralloc1Mapper::initDispatch() {
initDispatch(GRALLOC1_FUNCTION_RETAIN, &mDispatch.retain);
initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release);
initDispatch(GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES,
&mDispatch.getNumFlexPlanes);
initDispatch(GRALLOC1_FUNCTION_LOCK, &mDispatch.lock);
initDispatch(GRALLOC1_FUNCTION_LOCK_FLEX, &mDispatch.lockFlex);
initDispatch(GRALLOC1_FUNCTION_UNLOCK, &mDispatch.unlock);
}
Error Gralloc1Mapper::toError(int32_t error) {
switch (error) {
case GRALLOC1_ERROR_NONE:
return Error::NONE;
case GRALLOC1_ERROR_BAD_DESCRIPTOR:
return Error::BAD_DESCRIPTOR;
case GRALLOC1_ERROR_BAD_HANDLE:
return Error::BAD_BUFFER;
case GRALLOC1_ERROR_BAD_VALUE:
return Error::BAD_VALUE;
case GRALLOC1_ERROR_NOT_SHARED:
return Error::NONE; // this is fine
case GRALLOC1_ERROR_NO_RESOURCES:
return Error::NO_RESOURCES;
case GRALLOC1_ERROR_UNDEFINED:
case GRALLOC1_ERROR_UNSUPPORTED:
default:
return Error::UNSUPPORTED;
}
}
bool Gralloc1Mapper::toYCbCrLayout(const android_flex_layout& flex,
YCbCrLayout* outLayout) {
// must be YCbCr
if (flex.format != FLEX_FORMAT_YCbCr || flex.num_planes < 3) {
return false;
}
for (int i = 0; i < 3; i++) {
const auto& plane = flex.planes[i];
// must have 8-bit depth
if (plane.bits_per_component != 8 || plane.bits_used != 8) {
return false;
}
if (plane.component == FLEX_COMPONENT_Y) {
// Y must not be interleaved
if (plane.h_increment != 1) {
return false;
}
} else {
// Cb and Cr can be interleaved
if (plane.h_increment != 1 && plane.h_increment != 2) {
return false;
}
}
if (!plane.v_increment) {
return false;
}
}
if (flex.planes[0].component != FLEX_COMPONENT_Y ||
flex.planes[1].component != FLEX_COMPONENT_Cb ||
flex.planes[2].component != FLEX_COMPONENT_Cr) {
return false;
}
const auto& y = flex.planes[0];
const auto& cb = flex.planes[1];
const auto& cr = flex.planes[2];
if (cb.h_increment != cr.h_increment || cb.v_increment != cr.v_increment) {
return false;
}
outLayout->y = y.top_left;
outLayout->cb = cb.top_left;
outLayout->cr = cr.top_left;
outLayout->yStride = y.v_increment;
outLayout->cStride = cb.v_increment;
outLayout->chromaStep = cb.h_increment;
return true;
}
gralloc1_rect_t Gralloc1Mapper::asGralloc1Rect(const IMapper::Rect& rect) {
return gralloc1_rect_t{rect.left, rect.top, rect.width, rect.height};
}
Error Gralloc1Mapper::registerBuffer(buffer_handle_t bufferHandle) {
return toError(mDispatch.retain(mDevice, bufferHandle));
}
void Gralloc1Mapper::unregisterBuffer(buffer_handle_t bufferHandle) {
mDispatch.release(mDevice, bufferHandle);
}
Error Gralloc1Mapper::lockBuffer(buffer_handle_t bufferHandle,
uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
void** outData) {
// Dup fenceFd as it is going to be owned by gralloc. Note that it is
// gralloc's responsibility to close it, even on locking errors.
if (fenceFd >= 0) {
fenceFd = dup(fenceFd);
if (fenceFd < 0) {
return Error::NO_RESOURCES;
}
}
const uint64_t consumerUsage =
cpuUsage & ~static_cast<uint64_t>(BufferUsage::CPU_WRITE_MASK);
const auto accessRect = asGralloc1Rect(accessRegion);
void* data = nullptr;
int32_t error = mDispatch.lock(mDevice, bufferHandle, cpuUsage,
consumerUsage, &accessRect, &data, fenceFd);
if (error == GRALLOC1_ERROR_NONE) {
*outData = data;
}
return toError(error);
}
Error Gralloc1Mapper::lockBuffer(buffer_handle_t bufferHandle,
uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
YCbCrLayout* outLayout) {
// prepare flex layout
android_flex_layout flex = {};
int32_t error =
mDispatch.getNumFlexPlanes(mDevice, bufferHandle, &flex.num_planes);
if (error != GRALLOC1_ERROR_NONE) {
return toError(error);
}
std::vector<android_flex_plane_t> flexPlanes(flex.num_planes);
flex.planes = flexPlanes.data();
// Dup fenceFd as it is going to be owned by gralloc. Note that it is
// gralloc's responsibility to close it, even on locking errors.
if (fenceFd >= 0) {
fenceFd = dup(fenceFd);
if (fenceFd < 0) {
return Error::NO_RESOURCES;
}
}
const uint64_t consumerUsage =
cpuUsage & ~static_cast<uint64_t>(BufferUsage::CPU_WRITE_MASK);
const auto accessRect = asGralloc1Rect(accessRegion);
error = mDispatch.lockFlex(mDevice, bufferHandle, cpuUsage, consumerUsage,
&accessRect, &flex, fenceFd);
if (error == GRALLOC1_ERROR_NONE && !toYCbCrLayout(flex, outLayout)) {
ALOGD("unable to convert android_flex_layout to YCbCrLayout");
// undo the lock
fenceFd = -1;
mDispatch.unlock(mDevice, bufferHandle, &fenceFd);
if (fenceFd >= 0) {
close(fenceFd);
}
error = GRALLOC1_ERROR_BAD_HANDLE;
}
return toError(error);
}
Error Gralloc1Mapper::unlockBuffer(buffer_handle_t bufferHandle,
int* outFenceFd) {
int fenceFd = -1;
int32_t error = mDispatch.unlock(mDevice, bufferHandle, &fenceFd);
if (error == GRALLOC1_ERROR_NONE) {
*outFenceFd = fenceFd;
} else if (fenceFd >= 0) {
// we always own the fenceFd even when unlock failed
close(fenceFd);
}
return toError(error);
}
} // namespace implementation
} // namespace V2_0
} // namespace mapper
} // namespace graphics
} // namespace hardware
} // namespace android

View file

@ -0,0 +1,76 @@
/*
* Copyright 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.
*/
#ifndef ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC1MAPPER_H
#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC1MAPPER_H
#include "GrallocMapper.h"
#include <hardware/gralloc1.h>
namespace android {
namespace hardware {
namespace graphics {
namespace mapper {
namespace V2_0 {
namespace implementation {
class Gralloc1Mapper : public GrallocMapper {
public:
Gralloc1Mapper(const hw_module_t* module);
~Gralloc1Mapper();
private:
void initCapabilities();
template <typename T>
void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn);
void initDispatch();
static Error toError(int32_t error);
static bool toYCbCrLayout(const android_flex_layout& flex,
YCbCrLayout* outLayout);
static gralloc1_rect_t asGralloc1Rect(const IMapper::Rect& rect);
Error registerBuffer(buffer_handle_t bufferHandle) override;
void unregisterBuffer(buffer_handle_t bufferHandle) override;
Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
void** outData) override;
Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
YCbCrLayout* outLayout) override;
Error unlockBuffer(buffer_handle_t bufferHandle, int* outFenceFd) override;
gralloc1_device_t* mDevice;
struct {
GRALLOC1_PFN_RETAIN retain;
GRALLOC1_PFN_RELEASE release;
GRALLOC1_PFN_GET_NUM_FLEX_PLANES getNumFlexPlanes;
GRALLOC1_PFN_LOCK lock;
GRALLOC1_PFN_LOCK_FLEX lockFlex;
GRALLOC1_PFN_UNLOCK unlock;
} mDispatch;
};
} // namespace implementation
} // namespace V2_0
} // namespace mapper
} // namespace graphics
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC1MAPPER_H

View file

@ -0,0 +1,79 @@
/*
* Copyright 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.
*/
#ifndef ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOCBUFFERDESCRIPTOR_H
#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOCBUFFERDESCRIPTOR_H
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
namespace android {
namespace hardware {
namespace graphics {
namespace mapper {
namespace V2_0 {
namespace implementation {
using android::hardware::graphics::common::V1_0::PixelFormat;
/**
* BufferDescriptor is created by IMapper and consumed by IAllocator. It is
* versioned so that IMapper and IAllocator can be updated independently.
*/
constexpr uint32_t grallocBufferDescriptorSize = 7;
constexpr uint32_t grallocBufferDescriptorMagicVersion = ((0x9487 << 16) | 0);
inline BufferDescriptor grallocEncodeBufferDescriptor(
const IMapper::BufferDescriptorInfo& descriptorInfo) {
BufferDescriptor descriptor;
descriptor.resize(grallocBufferDescriptorSize);
descriptor[0] = grallocBufferDescriptorMagicVersion;
descriptor[1] = descriptorInfo.width;
descriptor[2] = descriptorInfo.height;
descriptor[3] = descriptorInfo.layerCount;
descriptor[4] = static_cast<uint32_t>(descriptorInfo.format);
descriptor[5] = static_cast<uint32_t>(descriptorInfo.usage);
descriptor[6] = static_cast<uint32_t>(descriptorInfo.usage >> 32);
return descriptor;
}
inline bool grallocDecodeBufferDescriptor(
const BufferDescriptor& descriptor,
IMapper::BufferDescriptorInfo* outDescriptorInfo) {
if (descriptor.size() != grallocBufferDescriptorSize ||
descriptor[0] != grallocBufferDescriptorMagicVersion) {
return false;
}
*outDescriptorInfo = IMapper::BufferDescriptorInfo{
descriptor[1],
descriptor[2],
descriptor[3],
static_cast<PixelFormat>(descriptor[4]),
(static_cast<uint64_t>(descriptor[6]) << 32) | descriptor[5],
};
return true;
}
} // namespace implementation
} // namespace V2_0
} // namespace mapper
} // namespace graphics
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOCBUFFERDESCRIPTOR_H

View file

@ -0,0 +1,321 @@
/*
* Copyright 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_TAG "GrallocMapperPassthrough"
#include "GrallocMapper.h"
#include "Gralloc0Mapper.h"
#include "Gralloc1Mapper.h"
#include "GrallocBufferDescriptor.h"
#include <inttypes.h>
#include <log/log.h>
#include <sync/sync.h>
namespace android {
namespace hardware {
namespace graphics {
namespace mapper {
namespace V2_0 {
namespace implementation {
using android::hardware::graphics::common::V1_0::BufferUsage;
using android::hardware::graphics::common::V1_0::PixelFormat;
namespace {
class RegisteredHandlePool {
public:
bool add(buffer_handle_t bufferHandle) {
std::lock_guard<std::mutex> lock(mMutex);
return mHandles.insert(bufferHandle).second;
}
native_handle_t* pop(void* buffer) {
auto bufferHandle = static_cast<native_handle_t*>(buffer);
std::lock_guard<std::mutex> lock(mMutex);
return mHandles.erase(bufferHandle) == 1 ? bufferHandle : nullptr;
}
buffer_handle_t get(const void* buffer) {
auto bufferHandle = static_cast<buffer_handle_t>(buffer);
std::lock_guard<std::mutex> lock(mMutex);
return mHandles.count(bufferHandle) == 1 ? bufferHandle : nullptr;
}
private:
std::mutex mMutex;
std::unordered_set<buffer_handle_t> mHandles;
};
// GraphicBufferMapper is expected to be valid (and leaked) during process
// termination. We need to make sure IMapper, and in turn, gRegisteredHandles
// are valid as well. Create the registered handle pool on the heap, and let
// it leak for simplicity.
//
// However, there is no way to make sure gralloc0/gralloc1 are valid. Any use
// of static/global object in gralloc0/gralloc1 that may have been destructed
// is potentially broken.
RegisteredHandlePool* gRegisteredHandles = new RegisteredHandlePool;
} // anonymous namespace
bool GrallocMapper::validateDescriptorInfo(
const BufferDescriptorInfo& descriptorInfo) const {
const uint64_t validUsageBits =
BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
BufferUsage::GPU_TEXTURE | BufferUsage::GPU_RENDER_TARGET |
BufferUsage::COMPOSER_OVERLAY | BufferUsage::COMPOSER_CLIENT_TARGET |
BufferUsage::PROTECTED | BufferUsage::COMPOSER_CURSOR |
BufferUsage::VIDEO_ENCODER | BufferUsage::CAMERA_OUTPUT |
BufferUsage::CAMERA_INPUT | BufferUsage::RENDERSCRIPT |
BufferUsage::VIDEO_DECODER | BufferUsage::SENSOR_DIRECT_DATA |
BufferUsage::GPU_DATA_BUFFER | BufferUsage::VENDOR_MASK |
(mCapabilities.highUsageBits ? BufferUsage::VENDOR_MASK_HI
: static_cast<BufferUsage>(0));
if (!descriptorInfo.width || !descriptorInfo.height ||
!descriptorInfo.layerCount) {
return false;
}
if (!mCapabilities.layeredBuffers && descriptorInfo.layerCount > 1) {
return false;
}
if (descriptorInfo.format == static_cast<PixelFormat>(0)) {
return false;
}
if (descriptorInfo.usage & ~validUsageBits) {
// could not fail as gralloc may use the reserved bits...
ALOGW("buffer descriptor with invalid usage bits 0x%" PRIx64,
descriptorInfo.usage & ~validUsageBits);
}
return true;
}
Return<void> GrallocMapper::createDescriptor(
const BufferDescriptorInfo& descriptorInfo, createDescriptor_cb hidl_cb) {
if (validateDescriptorInfo(descriptorInfo)) {
hidl_cb(Error::NONE, grallocEncodeBufferDescriptor(descriptorInfo));
} else {
hidl_cb(Error::BAD_VALUE, BufferDescriptor());
}
return Void();
}
Return<void> GrallocMapper::importBuffer(const hidl_handle& rawHandle,
importBuffer_cb hidl_cb) {
// because of passthrough HALs, we must not generate an error when
// rawHandle has been imported
if (!rawHandle.getNativeHandle()) {
hidl_cb(Error::BAD_BUFFER, nullptr);
return Void();
}
native_handle_t* bufferHandle =
native_handle_clone(rawHandle.getNativeHandle());
if (!bufferHandle) {
hidl_cb(Error::NO_RESOURCES, nullptr);
return Void();
}
Error error = registerBuffer(bufferHandle);
if (error != Error::NONE) {
native_handle_close(bufferHandle);
native_handle_delete(bufferHandle);
hidl_cb(error, nullptr);
return Void();
}
// The newly cloned handle is already registered? This can only happen
// when a handle previously registered was native_handle_delete'd instead
// of freeBuffer'd.
if (!gRegisteredHandles->add(bufferHandle)) {
ALOGE("handle %p has already been imported; potential fd leaking",
bufferHandle);
unregisterBuffer(bufferHandle);
if (!mCapabilities.unregisterImplyDelete) {
native_handle_close(bufferHandle);
native_handle_delete(bufferHandle);
}
hidl_cb(Error::NO_RESOURCES, nullptr);
return Void();
}
hidl_cb(Error::NONE, bufferHandle);
return Void();
}
Return<Error> GrallocMapper::freeBuffer(void* buffer) {
native_handle_t* bufferHandle = gRegisteredHandles->pop(buffer);
if (!bufferHandle) {
return Error::BAD_BUFFER;
}
unregisterBuffer(bufferHandle);
if (!mCapabilities.unregisterImplyDelete) {
native_handle_close(bufferHandle);
native_handle_delete(bufferHandle);
}
return Error::NONE;
}
void GrallocMapper::waitFenceFd(int fenceFd, const char* logname) {
if (fenceFd < 0) {
return;
}
const int warningTimeout = 3500;
const int error = sync_wait(fenceFd, warningTimeout);
if (error < 0 && errno == ETIME) {
ALOGE("%s: fence %d didn't signal in %u ms", logname, fenceFd,
warningTimeout);
sync_wait(fenceFd, -1);
}
}
bool GrallocMapper::getFenceFd(const hidl_handle& fenceHandle,
int* outFenceFd) {
auto handle = fenceHandle.getNativeHandle();
if (handle && handle->numFds > 1) {
ALOGE("invalid fence handle with %d fds", handle->numFds);
return false;
}
*outFenceFd = (handle && handle->numFds == 1) ? handle->data[0] : -1;
return true;
}
hidl_handle GrallocMapper::getFenceHandle(int fenceFd, char* handleStorage) {
native_handle_t* handle = nullptr;
if (fenceFd >= 0) {
handle = native_handle_init(handleStorage, 1, 0);
handle->data[0] = fenceFd;
}
return hidl_handle(handle);
}
Return<void> GrallocMapper::lock(void* buffer, uint64_t cpuUsage,
const IMapper::Rect& accessRegion,
const hidl_handle& acquireFence,
lock_cb hidl_cb) {
buffer_handle_t bufferHandle = gRegisteredHandles->get(buffer);
if (!bufferHandle) {
hidl_cb(Error::BAD_BUFFER, nullptr);
return Void();
}
int fenceFd;
if (!getFenceFd(acquireFence, &fenceFd)) {
hidl_cb(Error::BAD_VALUE, nullptr);
return Void();
}
void* data = nullptr;
Error error =
lockBuffer(bufferHandle, cpuUsage, accessRegion, fenceFd, &data);
hidl_cb(error, data);
return Void();
}
Return<void> GrallocMapper::lockYCbCr(void* buffer, uint64_t cpuUsage,
const IMapper::Rect& accessRegion,
const hidl_handle& acquireFence,
lockYCbCr_cb hidl_cb) {
YCbCrLayout layout = {};
buffer_handle_t bufferHandle = gRegisteredHandles->get(buffer);
if (!bufferHandle) {
hidl_cb(Error::BAD_BUFFER, layout);
return Void();
}
int fenceFd;
if (!getFenceFd(acquireFence, &fenceFd)) {
hidl_cb(Error::BAD_VALUE, layout);
return Void();
}
Error error =
lockBuffer(bufferHandle, cpuUsage, accessRegion, fenceFd, &layout);
hidl_cb(error, layout);
return Void();
}
Return<void> GrallocMapper::unlock(void* buffer, unlock_cb hidl_cb) {
buffer_handle_t bufferHandle = gRegisteredHandles->get(buffer);
if (!bufferHandle) {
hidl_cb(Error::BAD_BUFFER, nullptr);
return Void();
}
int fenceFd;
Error error = unlockBuffer(bufferHandle, &fenceFd);
if (error == Error::NONE) {
NATIVE_HANDLE_DECLARE_STORAGE(fenceStorage, 1, 0);
hidl_cb(error, getFenceHandle(fenceFd, fenceStorage));
if (fenceFd >= 0) {
close(fenceFd);
}
} else {
hidl_cb(error, nullptr);
}
return Void();
}
IMapper* HIDL_FETCH_IMapper(const char* /* name */) {
const hw_module_t* module = nullptr;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
if (err) {
ALOGE("failed to get gralloc module");
return nullptr;
}
uint8_t major = (module->module_api_version >> 8) & 0xff;
switch (major) {
case 1:
return new Gralloc1Mapper(module);
case 0:
return new Gralloc0Mapper(module);
default:
ALOGE("unknown gralloc module major version %d", major);
return nullptr;
}
}
} // namespace implementation
} // namespace V2_0
} // namespace mapper
} // namespace graphics
} // namespace hardware
} // namespace android

View file

@ -0,0 +1,96 @@
/*
* Copyright 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.
*/
#ifndef ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H
#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <cutils/native_handle.h>
#include <mutex>
#include <unordered_set>
namespace android {
namespace hardware {
namespace graphics {
namespace mapper {
namespace V2_0 {
namespace implementation {
class GrallocMapper : public IMapper {
public:
// IMapper interface
Return<void> createDescriptor(const BufferDescriptorInfo& descriptorInfo,
createDescriptor_cb hidl_cb) override;
Return<void> importBuffer(const hidl_handle& rawHandle,
importBuffer_cb hidl_cb) override;
Return<Error> freeBuffer(void* buffer) override;
Return<void> lock(void* buffer, uint64_t cpuUsage,
const IMapper::Rect& accessRegion,
const hidl_handle& acquireFence,
lock_cb hidl_cb) override;
Return<void> lockYCbCr(void* buffer, uint64_t cpuUsage,
const IMapper::Rect& accessRegion,
const hidl_handle& acquireFence,
lockYCbCr_cb hidl_cb) override;
Return<void> unlock(void* buffer, unlock_cb hidl_cb) override;
protected:
static void waitFenceFd(int fenceFd, const char* logname);
struct {
bool highUsageBits;
bool layeredBuffers;
bool unregisterImplyDelete;
} mCapabilities = {};
private:
virtual bool validateDescriptorInfo(
const BufferDescriptorInfo& descriptorInfo) const;
// Register a buffer. The handle is already cloned by the caller.
virtual Error registerBuffer(buffer_handle_t bufferHandle) = 0;
// Unregister a buffer. The handle is closed and deleted by the
// callee if and only if mCapabilities.unregisterImplyDelete is set.
virtual void unregisterBuffer(buffer_handle_t bufferHandle) = 0;
// Lock a buffer. The fence is owned by the caller.
virtual Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
void** outData) = 0;
virtual Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
YCbCrLayout* outLayout) = 0;
// Unlock a buffer. The returned fence is owned by the caller.
virtual Error unlockBuffer(buffer_handle_t bufferHandle,
int* outFenceFd) = 0;
static bool getFenceFd(const hidl_handle& fenceHandle, int* outFenceFd);
static hidl_handle getFenceHandle(int fenceFd, char* handleStorage);
};
extern "C" IMapper* HIDL_FETCH_IMapper(const char* name);
} // namespace implementation
} // namespace V2_0
} // namespace mapper
} // namespace graphics
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H