libui: Add Gralloc1On0Adapter
Adds an adapter which provides the gralloc1 interface on top of a
gralloc 0.x device.
Bug: 28401203
Change-Id: I0eeafc998b56e2e2fc39de6fad41e3ed2e19658a
diff --git a/libs/ui/Gralloc1On0Adapter.cpp b/libs/ui/Gralloc1On0Adapter.cpp
new file mode 100644
index 0000000..6e69df1
--- /dev/null
+++ b/libs/ui/Gralloc1On0Adapter.cpp
@@ -0,0 +1,469 @@
+/*
+ * 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++;
+ 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);
+
+ 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);
+ 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);
+ }
+ }
+ 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;
+ 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)
+{
+ if (mDescriptors.count(descriptorId) == 0) {
+ return nullptr;
+ }
+
+ return mDescriptors[descriptorId];
+}
+
+std::shared_ptr<Gralloc1On0Adapter::Buffer> Gralloc1On0Adapter::getBuffer(
+ buffer_handle_t bufferHandle)
+{
+ if (mBuffers.count(bufferHandle) == 0) {
+ return nullptr;
+ }
+
+ return mBuffers[bufferHandle];
+}
+
+std::atomic<gralloc1_buffer_descriptor_t>
+ Gralloc1On0Adapter::sNextBufferDescriptorId(1);
+
+} // namespace android