| /* |
| * 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 <algorithm> |
| #include <array> |
| |
| #include <grallocusage/GrallocUsageConversion.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) |
| { |
| constexpr std::array<int32_t, 2> supportedCapabilities = {{ |
| GRALLOC1_CAPABILITY_ON_ADAPTER, |
| GRALLOC1_CAPABILITY_RELEASE_IMPLY_DELETE, |
| }}; |
| |
| if (outCapabilities == nullptr) { |
| *outCount = supportedCapabilities.size(); |
| } else { |
| *outCount = std::min(*outCount, static_cast<uint32_t>( |
| supportedCapabilities.size())); |
| std::copy_n(supportedCapabilities.begin(), |
| *outCount, outCapabilities); |
| } |
| } |
| |
| 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 = android_convertGralloc1To0Usage(descriptor->producerUsage, |
| 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); |
| } |
| |
| native_handle_close(handle); |
| native_handle_delete(const_cast<native_handle_t*>(handle)); |
| } |
| |
| 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(), |
| android_convertGralloc1To0Usage(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(), |
| android_convertGralloc1To0Usage(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(), |
| android_convertGralloc1To0Usage(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(), |
| android_convertGralloc1To0Usage(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 |