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