/* * 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. */ #undef LOG_TAG #define LOG_TAG "Gralloc1On0Adapter" //#define LOG_NDEBUG 0 #include <hardware/gralloc.h> #include <ui/Gralloc1On0Adapter.h> #include <utils/Log.h> #include <inttypes.h> template <typename PFN, typename T> static gralloc1_function_pointer_t asFP(T function) { static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer"); return reinterpret_cast<gralloc1_function_pointer_t>(function); } namespace android { Gralloc1On0Adapter::Gralloc1On0Adapter(const hw_module_t* module) : mModule(reinterpret_cast<const gralloc_module_t*>(module)), mMinorVersion(mModule->common.module_api_version & 0xFF), mDevice(nullptr) { ALOGV("Constructing"); getCapabilities = getCapabilitiesHook; getFunction = getFunctionHook; int error = ::gralloc_open(&(mModule->common), &mDevice); if (error) { ALOGE("Failed to open gralloc0 module: %d", error); } ALOGV("Opened gralloc0 device %p", mDevice); } Gralloc1On0Adapter::~Gralloc1On0Adapter() { ALOGV("Destructing"); if (mDevice) { ALOGV("Closing gralloc0 device %p", mDevice); ::gralloc_close(mDevice); } } void Gralloc1On0Adapter::doGetCapabilities(uint32_t* outCount, int32_t* outCapabilities) { if (outCapabilities == nullptr) { *outCount = 1; return; } if (*outCount >= 1) { *outCapabilities = GRALLOC1_CAPABILITY_ON_ADAPTER; *outCount = 1; } } gralloc1_function_pointer_t Gralloc1On0Adapter::doGetFunction( int32_t intDescriptor) { constexpr auto lastDescriptor = static_cast<int32_t>(GRALLOC1_LAST_ADAPTER_FUNCTION); if (intDescriptor < 0 || intDescriptor > lastDescriptor) { ALOGE("Invalid function descriptor"); return nullptr; } auto descriptor = static_cast<gralloc1_function_descriptor_t>(intDescriptor); switch (descriptor) { case GRALLOC1_FUNCTION_DUMP: return asFP<GRALLOC1_PFN_DUMP>(dumpHook); case GRALLOC1_FUNCTION_CREATE_DESCRIPTOR: return asFP<GRALLOC1_PFN_CREATE_DESCRIPTOR>(createDescriptorHook); case GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR: return asFP<GRALLOC1_PFN_DESTROY_DESCRIPTOR>(destroyDescriptorHook); case GRALLOC1_FUNCTION_SET_CONSUMER_USAGE: return asFP<GRALLOC1_PFN_SET_CONSUMER_USAGE>(setConsumerUsageHook); case GRALLOC1_FUNCTION_SET_DIMENSIONS: return asFP<GRALLOC1_PFN_SET_DIMENSIONS>(setDimensionsHook); case GRALLOC1_FUNCTION_SET_FORMAT: return asFP<GRALLOC1_PFN_SET_FORMAT>(setFormatHook); case GRALLOC1_FUNCTION_SET_PRODUCER_USAGE: return asFP<GRALLOC1_PFN_SET_PRODUCER_USAGE>(setProducerUsageHook); case GRALLOC1_FUNCTION_GET_BACKING_STORE: return asFP<GRALLOC1_PFN_GET_BACKING_STORE>( bufferHook<decltype(&Buffer::getBackingStore), &Buffer::getBackingStore, gralloc1_backing_store_t*>); case GRALLOC1_FUNCTION_GET_CONSUMER_USAGE: return asFP<GRALLOC1_PFN_GET_CONSUMER_USAGE>(getConsumerUsageHook); case GRALLOC1_FUNCTION_GET_DIMENSIONS: return asFP<GRALLOC1_PFN_GET_DIMENSIONS>( bufferHook<decltype(&Buffer::getDimensions), &Buffer::getDimensions, uint32_t*, uint32_t*>); case GRALLOC1_FUNCTION_GET_FORMAT: return asFP<GRALLOC1_PFN_GET_FORMAT>( bufferHook<decltype(&Buffer::getFormat), &Buffer::getFormat, int32_t*>); case GRALLOC1_FUNCTION_GET_PRODUCER_USAGE: return asFP<GRALLOC1_PFN_GET_PRODUCER_USAGE>(getProducerUsageHook); case GRALLOC1_FUNCTION_GET_STRIDE: return asFP<GRALLOC1_PFN_GET_STRIDE>( bufferHook<decltype(&Buffer::getStride), &Buffer::getStride, uint32_t*>); case GRALLOC1_FUNCTION_ALLOCATE: // Not provided, since we'll use ALLOCATE_WITH_ID return nullptr; case GRALLOC1_FUNCTION_ALLOCATE_WITH_ID: if (mDevice != nullptr) { return asFP<GRALLOC1_PFN_ALLOCATE_WITH_ID>(allocateWithIdHook); } else { return nullptr; } case GRALLOC1_FUNCTION_RETAIN: return asFP<GRALLOC1_PFN_RETAIN>( managementHook<&Gralloc1On0Adapter::retain>); case GRALLOC1_FUNCTION_RELEASE: return asFP<GRALLOC1_PFN_RELEASE>( managementHook<&Gralloc1On0Adapter::release>); case GRALLOC1_FUNCTION_RETAIN_GRAPHIC_BUFFER: return asFP<GRALLOC1_PFN_RETAIN_GRAPHIC_BUFFER>( retainGraphicBufferHook); case GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES: return asFP<GRALLOC1_PFN_GET_NUM_FLEX_PLANES>( bufferHook<decltype(&Buffer::getNumFlexPlanes), &Buffer::getNumFlexPlanes, uint32_t*>); case GRALLOC1_FUNCTION_LOCK: return asFP<GRALLOC1_PFN_LOCK>( lockHook<void*, &Gralloc1On0Adapter::lock>); case GRALLOC1_FUNCTION_LOCK_FLEX: return asFP<GRALLOC1_PFN_LOCK_FLEX>( lockHook<struct android_flex_layout, &Gralloc1On0Adapter::lockFlex>); case GRALLOC1_FUNCTION_LOCK_YCBCR: return asFP<GRALLOC1_PFN_LOCK_YCBCR>( lockHook<struct android_ycbcr, &Gralloc1On0Adapter::lockYCbCr>); case GRALLOC1_FUNCTION_UNLOCK: return asFP<GRALLOC1_PFN_UNLOCK>(unlockHook); case GRALLOC1_FUNCTION_INVALID: ALOGE("Invalid function descriptor"); return nullptr; } ALOGE("Unknown function descriptor: %d", intDescriptor); return nullptr; } void Gralloc1On0Adapter::dump(uint32_t* outSize, char* outBuffer) { ALOGV("dump(%u (%p), %p", outSize ? *outSize : 0, outSize, outBuffer); if (!mDevice->dump) { // dump is optional on gralloc0 implementations *outSize = 0; return; } if (!outBuffer) { constexpr int32_t BUFFER_LENGTH = 4096; char buffer[BUFFER_LENGTH] = {}; mDevice->dump(mDevice, buffer, BUFFER_LENGTH); buffer[BUFFER_LENGTH - 1] = 0; // Ensure the buffer is null-terminated size_t actualLength = std::strlen(buffer); mCachedDump.resize(actualLength); std::copy_n(buffer, actualLength, mCachedDump.begin()); *outSize = static_cast<uint32_t>(actualLength); } else { *outSize = std::min(*outSize, static_cast<uint32_t>(mCachedDump.size())); outBuffer = std::copy_n(mCachedDump.cbegin(), *outSize, outBuffer); } } gralloc1_error_t Gralloc1On0Adapter::createDescriptor( gralloc1_buffer_descriptor_t* outDescriptor) { auto descriptorId = sNextBufferDescriptorId++; std::lock_guard<std::mutex> lock(mDescriptorMutex); mDescriptors.emplace(descriptorId, std::make_shared<Descriptor>(this, descriptorId)); ALOGV("Created descriptor %" PRIu64, descriptorId); *outDescriptor = descriptorId; return GRALLOC1_ERROR_NONE; } gralloc1_error_t Gralloc1On0Adapter::destroyDescriptor( gralloc1_buffer_descriptor_t descriptor) { ALOGV("Destroying descriptor %" PRIu64, descriptor); std::lock_guard<std::mutex> lock(mDescriptorMutex); if (mDescriptors.count(descriptor) == 0) { return GRALLOC1_ERROR_BAD_DESCRIPTOR; } mDescriptors.erase(descriptor); return GRALLOC1_ERROR_NONE; } Gralloc1On0Adapter::Buffer::Buffer(buffer_handle_t handle, gralloc1_backing_store_t store, const Descriptor& descriptor, uint32_t stride, bool wasAllocated) : mHandle(handle), mReferenceCount(1), mStore(store), mDescriptor(descriptor), mStride(stride), mWasAllocated(wasAllocated) {} gralloc1_error_t Gralloc1On0Adapter::allocate( const std::shared_ptr<Descriptor>& descriptor, gralloc1_backing_store_t store, buffer_handle_t* outBufferHandle) { ALOGV("allocate(%" PRIu64 ", %#" PRIx64 ")", descriptor->id, store); // If this function is being called, it's because we handed out its function // pointer, which only occurs when mDevice has been loaded successfully and // we are permitted to allocate int usage = static_cast<int>(descriptor->producerUsage) | static_cast<int>(descriptor->consumerUsage); buffer_handle_t handle = nullptr; int stride = 0; ALOGV("Calling alloc(%p, %u, %u, %i, %u)", mDevice, descriptor->width, descriptor->height, descriptor->format, usage); auto error = mDevice->alloc(mDevice, static_cast<int>(descriptor->width), static_cast<int>(descriptor->height), descriptor->format, usage, &handle, &stride); if (error != 0) { ALOGE("gralloc0 allocation failed: %d (%s)", error, strerror(-error)); return GRALLOC1_ERROR_NO_RESOURCES; } *outBufferHandle = handle; auto buffer = std::make_shared<Buffer>(handle, store, *descriptor, stride, true); std::lock_guard<std::mutex> lock(mBufferMutex); mBuffers.emplace(handle, std::move(buffer)); return GRALLOC1_ERROR_NONE; } gralloc1_error_t Gralloc1On0Adapter::allocateWithIdHook( gralloc1_device_t* device, gralloc1_buffer_descriptor_t descriptorId, gralloc1_backing_store_t store, buffer_handle_t* outBuffer) { auto adapter = getAdapter(device); auto descriptor = adapter->getDescriptor(descriptorId); if (!descriptor) { return GRALLOC1_ERROR_BAD_DESCRIPTOR; } buffer_handle_t bufferHandle = nullptr; auto error = adapter->allocate(descriptor, store, &bufferHandle); if (error != GRALLOC1_ERROR_NONE) { return error; } *outBuffer = bufferHandle; return error; } gralloc1_error_t Gralloc1On0Adapter::retain( const std::shared_ptr<Buffer>& buffer) { buffer->retain(); return GRALLOC1_ERROR_NONE; } gralloc1_error_t Gralloc1On0Adapter::release( const std::shared_ptr<Buffer>& buffer) { if (!buffer->release()) { return GRALLOC1_ERROR_NONE; } buffer_handle_t handle = buffer->getHandle(); if (buffer->wasAllocated()) { ALOGV("Calling free(%p)", handle); int result = mDevice->free(mDevice, handle); if (result != 0) { ALOGE("gralloc0 free failed: %d", result); } } else { ALOGV("Calling unregisterBuffer(%p)", handle); int result = mModule->unregisterBuffer(mModule, handle); if (result != 0) { ALOGE("gralloc0 unregister failed: %d", result); } } std::lock_guard<std::mutex> lock(mBufferMutex); mBuffers.erase(handle); return GRALLOC1_ERROR_NONE; } gralloc1_error_t Gralloc1On0Adapter::retain( const android::GraphicBuffer* graphicBuffer) { ALOGV("retainGraphicBuffer(%p, %#" PRIx64 ")", graphicBuffer->getNativeBuffer()->handle, graphicBuffer->getId()); buffer_handle_t handle = graphicBuffer->getNativeBuffer()->handle; std::lock_guard<std::mutex> lock(mBufferMutex); if (mBuffers.count(handle) != 0) { mBuffers[handle]->retain(); return GRALLOC1_ERROR_NONE; } ALOGV("Calling registerBuffer(%p)", handle); int result = mModule->registerBuffer(mModule, handle); if (result != 0) { ALOGE("gralloc0 register failed: %d", result); return GRALLOC1_ERROR_NO_RESOURCES; } Descriptor descriptor{this, sNextBufferDescriptorId++}; descriptor.setDimensions(graphicBuffer->getWidth(), graphicBuffer->getHeight()); descriptor.setFormat(graphicBuffer->getPixelFormat()); descriptor.setProducerUsage( static_cast<gralloc1_producer_usage_t>(graphicBuffer->getUsage())); descriptor.setConsumerUsage( static_cast<gralloc1_consumer_usage_t>(graphicBuffer->getUsage())); auto buffer = std::make_shared<Buffer>(handle, static_cast<gralloc1_backing_store_t>(graphicBuffer->getId()), descriptor, graphicBuffer->getStride(), false); mBuffers.emplace(handle, std::move(buffer)); return GRALLOC1_ERROR_NONE; } gralloc1_error_t Gralloc1On0Adapter::lock( const std::shared_ptr<Buffer>& buffer, gralloc1_producer_usage_t producerUsage, gralloc1_consumer_usage_t consumerUsage, const gralloc1_rect_t& accessRegion, void** outData, const sp<Fence>& acquireFence) { if (mMinorVersion >= 3) { int result = mModule->lockAsync(mModule, buffer->getHandle(), static_cast<int32_t>(producerUsage | consumerUsage), accessRegion.left, accessRegion.top, accessRegion.width, accessRegion.height, outData, acquireFence->dup()); if (result != 0) { return GRALLOC1_ERROR_UNSUPPORTED; } } else { acquireFence->waitForever("Gralloc1On0Adapter::lock"); int result = mModule->lock(mModule, buffer->getHandle(), static_cast<int32_t>(producerUsage | consumerUsage), accessRegion.left, accessRegion.top, accessRegion.width, accessRegion.height, outData); ALOGV("gralloc0 lock returned %d", result); if (result != 0) { return GRALLOC1_ERROR_UNSUPPORTED; } } return GRALLOC1_ERROR_NONE; } gralloc1_error_t Gralloc1On0Adapter::lockFlex( const std::shared_ptr<Buffer>& /*buffer*/, gralloc1_producer_usage_t /*producerUsage*/, gralloc1_consumer_usage_t /*consumerUsage*/, const gralloc1_rect_t& /*accessRegion*/, struct android_flex_layout* /*outData*/, const sp<Fence>& /*acquireFence*/) { // TODO return GRALLOC1_ERROR_UNSUPPORTED; } gralloc1_error_t Gralloc1On0Adapter::lockYCbCr( const std::shared_ptr<Buffer>& buffer, gralloc1_producer_usage_t producerUsage, gralloc1_consumer_usage_t consumerUsage, const gralloc1_rect_t& accessRegion, struct android_ycbcr* outData, const sp<Fence>& acquireFence) { if (mMinorVersion >= 3 && mModule->lockAsync_ycbcr) { int result = mModule->lockAsync_ycbcr(mModule, buffer->getHandle(), static_cast<int>(producerUsage | consumerUsage), accessRegion.left, accessRegion.top, accessRegion.width, accessRegion.height, outData, acquireFence->dup()); if (result != 0) { return GRALLOC1_ERROR_UNSUPPORTED; } } else if (mModule->lock_ycbcr) { acquireFence->waitForever("Gralloc1On0Adapter::lockYCbCr"); int result = mModule->lock_ycbcr(mModule, buffer->getHandle(), static_cast<int>(producerUsage | consumerUsage), accessRegion.left, accessRegion.top, accessRegion.width, accessRegion.height, outData); ALOGV("gralloc0 lockYCbCr returned %d", result); if (result != 0) { return GRALLOC1_ERROR_UNSUPPORTED; } } else { return GRALLOC1_ERROR_UNSUPPORTED; } return GRALLOC1_ERROR_NONE; } gralloc1_error_t Gralloc1On0Adapter::unlock( const std::shared_ptr<Buffer>& buffer, sp<Fence>* outReleaseFence) { if (mMinorVersion >= 3) { int fenceFd = -1; int result = mModule->unlockAsync(mModule, buffer->getHandle(), &fenceFd); if (result != 0) { close(fenceFd); ALOGE("gralloc0 unlockAsync failed: %d", result); } else { *outReleaseFence = new Fence(fenceFd); } } else { int result = mModule->unlock(mModule, buffer->getHandle()); if (result != 0) { ALOGE("gralloc0 unlock failed: %d", result); } } return GRALLOC1_ERROR_NONE; } std::shared_ptr<Gralloc1On0Adapter::Descriptor> Gralloc1On0Adapter::getDescriptor(gralloc1_buffer_descriptor_t descriptorId) { std::lock_guard<std::mutex> lock(mDescriptorMutex); if (mDescriptors.count(descriptorId) == 0) { return nullptr; } return mDescriptors[descriptorId]; } std::shared_ptr<Gralloc1On0Adapter::Buffer> Gralloc1On0Adapter::getBuffer( buffer_handle_t bufferHandle) { std::lock_guard<std::mutex> lock(mBufferMutex); if (mBuffers.count(bufferHandle) == 0) { return nullptr; } return mBuffers[bufferHandle]; } std::atomic<gralloc1_buffer_descriptor_t> Gralloc1On0Adapter::sNextBufferDescriptorId(1); } // namespace android