| /* | |
| * 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 <ui/Gralloc1On0Adapter.h> | |
| #include <hardware/gralloc.h> | |
| #include <ui/GraphicBuffer.h> | |
| #include <ui/Gralloc1.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_LAYER_COUNT: | |
| return asFP<GRALLOC1_PFN_SET_LAYER_COUNT>(setLayerCountHook); | |
| 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_LAYER_COUNT: | |
| return asFP<GRALLOC1_PFN_GET_LAYER_COUNT>( | |
| bufferHook<decltype(&Buffer::getLayerCount), | |
| &Buffer::getLayerCount, uint32_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) | |
| { | |
| std::lock_guard<std::mutex> lock(mBufferMutex); | |
| buffer->retain(); | |
| return GRALLOC1_ERROR_NONE; | |
| } | |
| gralloc1_error_t Gralloc1On0Adapter::release( | |
| const std::shared_ptr<Buffer>& buffer) | |
| { | |
| std::lock_guard<std::mutex> lock(mBufferMutex); | |
| 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); | |
| } | |
| } | |
| 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 |