From 58db5d59b0f86538baab7d99c30807ac23e10967 Mon Sep 17 00:00:00 2001 From: Dominggoes Isakh Date: Sun, 12 Aug 2018 22:05:06 +0200 Subject: [PATCH] exynos4: android.hardware.graphics.mapper@2.0 for Exynos4 Change-Id: Ic3156237063e72b3a3745491685d3e5cbedd908d --- exynos4/interfaces/mapper/Android.bp | 40 +++ exynos4/interfaces/mapper/Gralloc0Mapper.cpp | 156 +++++++++ exynos4/interfaces/mapper/Gralloc0Mapper.h | 56 +++ exynos4/interfaces/mapper/Gralloc1Mapper.cpp | 273 +++++++++++++++ exynos4/interfaces/mapper/Gralloc1Mapper.h | 76 +++++ .../mapper/GrallocBufferDescriptor.h | 79 +++++ exynos4/interfaces/mapper/GrallocMapper.cpp | 321 ++++++++++++++++++ exynos4/interfaces/mapper/GrallocMapper.h | 96 ++++++ 8 files changed, 1097 insertions(+) create mode 100644 exynos4/interfaces/mapper/Android.bp create mode 100644 exynos4/interfaces/mapper/Gralloc0Mapper.cpp create mode 100644 exynos4/interfaces/mapper/Gralloc0Mapper.h create mode 100644 exynos4/interfaces/mapper/Gralloc1Mapper.cpp create mode 100644 exynos4/interfaces/mapper/Gralloc1Mapper.h create mode 100644 exynos4/interfaces/mapper/GrallocBufferDescriptor.h create mode 100644 exynos4/interfaces/mapper/GrallocMapper.cpp create mode 100644 exynos4/interfaces/mapper/GrallocMapper.h diff --git a/exynos4/interfaces/mapper/Android.bp b/exynos4/interfaces/mapper/Android.bp new file mode 100644 index 0000000..f73529f --- /dev/null +++ b/exynos4/interfaces/mapper/Android.bp @@ -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: ["."], +} diff --git a/exynos4/interfaces/mapper/Gralloc0Mapper.cpp b/exynos4/interfaces/mapper/Gralloc0Mapper.cpp new file mode 100644 index 0000000..28f5016 --- /dev/null +++ b/exynos4/interfaces/mapper/Gralloc0Mapper.cpp @@ -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 + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V2_0 { +namespace implementation { + +Gralloc0Mapper::Gralloc0Mapper(const hw_module_t* module) + : mModule(reinterpret_cast(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 diff --git a/exynos4/interfaces/mapper/Gralloc0Mapper.h b/exynos4/interfaces/mapper/Gralloc0Mapper.h new file mode 100644 index 0000000..e792a69 --- /dev/null +++ b/exynos4/interfaces/mapper/Gralloc0Mapper.h @@ -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 + +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 diff --git a/exynos4/interfaces/mapper/Gralloc1Mapper.cpp b/exynos4/interfaces/mapper/Gralloc1Mapper.cpp new file mode 100644 index 0000000..c1e5adc --- /dev/null +++ b/exynos4/interfaces/mapper/Gralloc1Mapper.cpp @@ -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 + +#include + +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 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 +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(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(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 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(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 diff --git a/exynos4/interfaces/mapper/Gralloc1Mapper.h b/exynos4/interfaces/mapper/Gralloc1Mapper.h new file mode 100644 index 0000000..452afdf --- /dev/null +++ b/exynos4/interfaces/mapper/Gralloc1Mapper.h @@ -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 + +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 + 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 diff --git a/exynos4/interfaces/mapper/GrallocBufferDescriptor.h b/exynos4/interfaces/mapper/GrallocBufferDescriptor.h new file mode 100644 index 0000000..9b5ab04 --- /dev/null +++ b/exynos4/interfaces/mapper/GrallocBufferDescriptor.h @@ -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 + +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(descriptorInfo.format); + descriptor[5] = static_cast(descriptorInfo.usage); + descriptor[6] = static_cast(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(descriptor[4]), + (static_cast(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 diff --git a/exynos4/interfaces/mapper/GrallocMapper.cpp b/exynos4/interfaces/mapper/GrallocMapper.cpp new file mode 100644 index 0000000..d16143d --- /dev/null +++ b/exynos4/interfaces/mapper/GrallocMapper.cpp @@ -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 + +#include +#include + +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 lock(mMutex); + return mHandles.insert(bufferHandle).second; + } + + native_handle_t* pop(void* buffer) { + auto bufferHandle = static_cast(buffer); + + std::lock_guard lock(mMutex); + return mHandles.erase(bufferHandle) == 1 ? bufferHandle : nullptr; + } + + buffer_handle_t get(const void* buffer) { + auto bufferHandle = static_cast(buffer); + + std::lock_guard lock(mMutex); + return mHandles.count(bufferHandle) == 1 ? bufferHandle : nullptr; + } + + private: + std::mutex mMutex; + std::unordered_set 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(0)); + + if (!descriptorInfo.width || !descriptorInfo.height || + !descriptorInfo.layerCount) { + return false; + } + + if (!mCapabilities.layeredBuffers && descriptorInfo.layerCount > 1) { + return false; + } + + if (descriptorInfo.format == static_cast(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 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 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 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 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 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 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 diff --git a/exynos4/interfaces/mapper/GrallocMapper.h b/exynos4/interfaces/mapper/GrallocMapper.h new file mode 100644 index 0000000..e876fe4 --- /dev/null +++ b/exynos4/interfaces/mapper/GrallocMapper.h @@ -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 +#include + +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V2_0 { +namespace implementation { + +class GrallocMapper : public IMapper { + public: + // IMapper interface + Return createDescriptor(const BufferDescriptorInfo& descriptorInfo, + createDescriptor_cb hidl_cb) override; + Return importBuffer(const hidl_handle& rawHandle, + importBuffer_cb hidl_cb) override; + Return freeBuffer(void* buffer) override; + Return lock(void* buffer, uint64_t cpuUsage, + const IMapper::Rect& accessRegion, + const hidl_handle& acquireFence, + lock_cb hidl_cb) override; + Return lockYCbCr(void* buffer, uint64_t cpuUsage, + const IMapper::Rect& accessRegion, + const hidl_handle& acquireFence, + lockYCbCr_cb hidl_cb) override; + Return 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