/* * 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 "Gralloc2" #include #include #include #include #include #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wzero-length-array" #include #pragma clang diagnostic pop using android::hardware::graphics::allocator::V2_0::IAllocator; using android::hardware::graphics::common::V1_1::BufferUsage; using android::hardware::graphics::common::V1_1::PixelFormat; using android::hardware::graphics::mapper::V2_0::BufferDescriptor; using android::hardware::graphics::mapper::V2_0::Error; using android::hardware::graphics::mapper::V2_0::YCbCrLayout; using android::hardware::graphics::mapper::V2_1::IMapper; namespace android { namespace { static constexpr Error kTransactionError = Error::NO_RESOURCES; uint64_t getValid10UsageBits() { static const uint64_t valid10UsageBits = []() -> uint64_t { using hardware::graphics::common::V1_0::BufferUsage; uint64_t bits = 0; for (const auto bit : hardware::hidl_enum_range()) { bits = bits | bit; } return bits; }(); return valid10UsageBits; } uint64_t getValid11UsageBits() { static const uint64_t valid11UsageBits = []() -> uint64_t { using hardware::graphics::common::V1_1::BufferUsage; uint64_t bits = 0; for (const auto bit : hardware::hidl_enum_range()) { bits = bits | bit; } return bits; }(); return valid11UsageBits; } static inline IMapper::Rect sGralloc2Rect(const Rect& rect) { IMapper::Rect outRect{}; outRect.left = rect.left; outRect.top = rect.top; outRect.width = rect.width(); outRect.height = rect.height(); return outRect; } } // anonymous namespace void Gralloc2Mapper::preload() { android::hardware::preloadPassthroughService(); } Gralloc2Mapper::Gralloc2Mapper() { mMapper = hardware::graphics::mapper::V2_0::IMapper::getService(); if (mMapper == nullptr) { ALOGW("mapper 2.x is not supported"); return; } if (mMapper->isRemote()) { LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode"); } // IMapper 2.1 is optional mMapperV2_1 = IMapper::castFrom(mMapper); } bool Gralloc2Mapper::isLoaded() const { return mMapper != nullptr; } status_t Gralloc2Mapper::validateBufferDescriptorInfo( IMapper::BufferDescriptorInfo* descriptorInfo) const { uint64_t validUsageBits = getValid10UsageBits(); if (mMapperV2_1 != nullptr) { validUsageBits = validUsageBits | getValid11UsageBits(); } if (descriptorInfo->usage & ~validUsageBits) { ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64, descriptorInfo->usage & ~validUsageBits); return BAD_VALUE; } return NO_ERROR; } status_t Gralloc2Mapper::createDescriptor(void* bufferDescriptorInfo, void* outBufferDescriptor) const { IMapper::BufferDescriptorInfo* descriptorInfo = static_cast(bufferDescriptorInfo); BufferDescriptor* outDescriptor = static_cast(outBufferDescriptor); status_t status = validateBufferDescriptorInfo(descriptorInfo); if (status != NO_ERROR) { return status; } Error error; auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor) { error = tmpError; if (error != Error::NONE) { return; } *outDescriptor = tmpDescriptor; }; hardware::Return ret; if (mMapperV2_1 != nullptr) { ret = mMapperV2_1->createDescriptor_2_1(*descriptorInfo, hidl_cb); } else { const hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo info = { descriptorInfo->width, descriptorInfo->height, descriptorInfo->layerCount, static_cast(descriptorInfo->format), descriptorInfo->usage, }; ret = mMapper->createDescriptor(info, hidl_cb); } return static_cast((ret.isOk()) ? error : kTransactionError); } status_t Gralloc2Mapper::importBuffer(const hardware::hidl_handle& rawHandle, buffer_handle_t* outBufferHandle) const { Error error; auto ret = mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) { error = tmpError; if (error != Error::NONE) { return; } *outBufferHandle = static_cast(tmpBuffer); }); return static_cast((ret.isOk()) ? error : kTransactionError); } void Gralloc2Mapper::freeBuffer(buffer_handle_t bufferHandle) const { auto buffer = const_cast(bufferHandle); auto ret = mMapper->freeBuffer(buffer); auto error = (ret.isOk()) ? static_cast(ret) : kTransactionError; ALOGE_IF(error != Error::NONE, "freeBuffer(%p) failed with %d", buffer, error); } status_t Gralloc2Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32_t width, uint32_t height, android::PixelFormat format, uint32_t layerCount, uint64_t usage, uint32_t stride) const { if (mMapperV2_1 == nullptr) { return NO_ERROR; } IMapper::BufferDescriptorInfo descriptorInfo = {}; descriptorInfo.width = width; descriptorInfo.height = height; descriptorInfo.layerCount = layerCount; descriptorInfo.format = static_cast(format); descriptorInfo.usage = usage; auto buffer = const_cast(bufferHandle); auto ret = mMapperV2_1->validateBufferSize(buffer, descriptorInfo, stride); return static_cast((ret.isOk()) ? static_cast(ret) : kTransactionError); } void Gralloc2Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds, uint32_t* outNumInts) const { *outNumFds = uint32_t(bufferHandle->numFds); *outNumInts = uint32_t(bufferHandle->numInts); if (mMapperV2_1 == nullptr) { return; } Error error; auto buffer = const_cast(bufferHandle); auto ret = mMapperV2_1->getTransportSize(buffer, [&](const auto& tmpError, const auto& tmpNumFds, const auto& tmpNumInts) { error = tmpError; if (error != Error::NONE) { return; } *outNumFds = tmpNumFds; *outNumInts = tmpNumInts; }); error = (ret.isOk()) ? error : kTransactionError; ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d", buffer, error); } status_t Gralloc2Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds, int acquireFence, void** outData, int32_t* outBytesPerPixel, int32_t* outBytesPerStride) const { if (outBytesPerPixel) { *outBytesPerPixel = -1; } if (outBytesPerStride) { *outBytesPerStride = -1; } auto buffer = const_cast(bufferHandle); IMapper::Rect accessRegion = sGralloc2Rect(bounds); // put acquireFence in a hidl_handle hardware::hidl_handle acquireFenceHandle; NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0); if (acquireFence >= 0) { auto h = native_handle_init(acquireFenceStorage, 1, 0); h->data[0] = acquireFence; acquireFenceHandle = h; } Error error; auto ret = mMapper->lock(buffer, usage, accessRegion, acquireFenceHandle, [&](const auto& tmpError, const auto& tmpData) { error = tmpError; if (error != Error::NONE) { return; } *outData = tmpData; }); // we own acquireFence even on errors if (acquireFence >= 0) { close(acquireFence); } error = (ret.isOk()) ? error : kTransactionError; ALOGW_IF(error != Error::NONE, "lock(%p, ...) failed: %d", bufferHandle, error); return static_cast(error); } status_t Gralloc2Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds, int acquireFence, android_ycbcr* ycbcr) const { auto buffer = const_cast(bufferHandle); IMapper::Rect accessRegion = sGralloc2Rect(bounds); // put acquireFence in a hidl_handle hardware::hidl_handle acquireFenceHandle; NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0); if (acquireFence >= 0) { auto h = native_handle_init(acquireFenceStorage, 1, 0); h->data[0] = acquireFence; acquireFenceHandle = h; } YCbCrLayout layout; Error error; auto ret = mMapper->lockYCbCr(buffer, usage, accessRegion, acquireFenceHandle, [&](const auto& tmpError, const auto& tmpLayout) { error = tmpError; if (error != Error::NONE) { return; } layout = tmpLayout; }); if (error == Error::NONE) { ycbcr->y = layout.y; ycbcr->cb = layout.cb; ycbcr->cr = layout.cr; ycbcr->ystride = static_cast(layout.yStride); ycbcr->cstride = static_cast(layout.cStride); ycbcr->chroma_step = static_cast(layout.chromaStep); } // we own acquireFence even on errors if (acquireFence >= 0) { close(acquireFence); } return static_cast((ret.isOk()) ? error : kTransactionError); } int Gralloc2Mapper::unlock(buffer_handle_t bufferHandle) const { auto buffer = const_cast(bufferHandle); int releaseFence = -1; Error error; auto ret = mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) { error = tmpError; if (error != Error::NONE) { return; } auto fenceHandle = tmpReleaseFence.getNativeHandle(); if (fenceHandle && fenceHandle->numFds == 1) { int fd = dup(fenceHandle->data[0]); if (fd >= 0) { releaseFence = fd; } else { ALOGD("failed to dup unlock release fence"); sync_wait(fenceHandle->data[0], -1); } } }); error = (ret.isOk()) ? error : kTransactionError; if (error != Error::NONE) { ALOGE("unlock(%p) failed with %d", buffer, error); } return releaseFence; } Gralloc2Allocator::Gralloc2Allocator(const Gralloc2Mapper& mapper) : mMapper(mapper) { mAllocator = IAllocator::getService(); if (mAllocator == nullptr) { ALOGW("allocator 2.x is not supported"); return; } } bool Gralloc2Allocator::isLoaded() const { return mAllocator != nullptr; } std::string Gralloc2Allocator::dumpDebugInfo(bool /*less*/) const { std::string debugInfo; mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); }); return debugInfo; } status_t Gralloc2Allocator::allocate(std::string /*requestorName*/, uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, uint32_t bufferCount, uint32_t* outStride, buffer_handle_t* outBufferHandles, bool importBuffers) const { IMapper::BufferDescriptorInfo descriptorInfo = {}; descriptorInfo.width = width; descriptorInfo.height = height; descriptorInfo.layerCount = layerCount; descriptorInfo.format = static_cast(format); descriptorInfo.usage = usage; BufferDescriptor descriptor; status_t error = mMapper.createDescriptor(static_cast(&descriptorInfo), static_cast(&descriptor)); if (error != NO_ERROR) { return error; } auto ret = mAllocator->allocate(descriptor, bufferCount, [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) { error = static_cast(tmpError); if (tmpError != Error::NONE) { return; } if (importBuffers) { for (uint32_t i = 0; i < bufferCount; i++) { error = mMapper.importBuffer(tmpBuffers[i], &outBufferHandles[i]); if (error != NO_ERROR) { for (uint32_t j = 0; j < i; j++) { mMapper.freeBuffer(outBufferHandles[j]); outBufferHandles[j] = nullptr; } return; } } } else { for (uint32_t i = 0; i < bufferCount; i++) { outBufferHandles[i] = native_handle_clone( tmpBuffers[i].getNativeHandle()); if (!outBufferHandles[i]) { for (uint32_t j = 0; j < i; j++) { auto buffer = const_cast( outBufferHandles[j]); native_handle_close(buffer); native_handle_delete(buffer); outBufferHandles[j] = nullptr; } } } } *outStride = tmpStride; }); // make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now hardware::IPCThreadState::self()->flushCommands(); return (ret.isOk()) ? error : static_cast(kTransactionError); } } // namespace android