libui: Adds C++ shim for gralloc1

Adds a C++ shim which wraps a gralloc1 device and provides a somewhat
nicer interface to the rest of the system.

Bug: 28401203
Change-Id: I934ed41999bd4b9aa04d9ad8d40e7f8fba6f30ee
diff --git a/libs/ui/Gralloc1.cpp b/libs/ui/Gralloc1.cpp
new file mode 100644
index 0000000..4c73ce4
--- /dev/null
+++ b/libs/ui/Gralloc1.cpp
@@ -0,0 +1,402 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+
+#include <ui/Gralloc1.h>
+
+#include <vector>
+
+#undef LOG_TAG
+#define LOG_TAG GRALLOC1_LOG_TAG
+
+namespace android {
+
+namespace Gralloc1 {
+
+Descriptor::~Descriptor()
+{
+    int32_t intError = mShimDevice.mFunctions.destroyDescriptor(
+            mShimDevice.mDevice, mDeviceId);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("destroyDescriptor failed: %d", intError);
+    }
+}
+
+gralloc1_error_t Descriptor::setDimensions(uint32_t width, uint32_t height)
+{
+    int32_t intError = mShimDevice.mFunctions.setDimensions(mShimDevice.mDevice,
+            mDeviceId, width, height);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error != GRALLOC1_ERROR_NONE) {
+        return error;
+    }
+    mWidth = width;
+    mHeight = height;
+    return error;
+}
+
+template <typename ApiType>
+struct Setter {
+    typedef int32_t (*Type)(gralloc1_device_t*, gralloc1_buffer_descriptor_t,
+            ApiType);
+};
+
+template <typename ApiType, typename ValueType>
+static inline gralloc1_error_t setHelper(
+        typename Setter<ApiType>::Type setter, gralloc1_device_t* device,
+        gralloc1_buffer_descriptor_t id, ValueType newValue,
+        ValueType* cacheVariable)
+{
+    int32_t intError = setter(device, id, static_cast<ApiType>(newValue));
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error != GRALLOC1_ERROR_NONE) {
+        return error;
+    }
+    *cacheVariable = newValue;
+    return error;
+}
+
+gralloc1_error_t Descriptor::setFormat(android_pixel_format_t format)
+{
+    return setHelper<int32_t>(mShimDevice.mFunctions.setFormat.pfn,
+            mShimDevice.mDevice, mDeviceId, format, &mFormat);
+}
+
+gralloc1_error_t Descriptor::setProducerUsage(gralloc1_producer_usage_t usage)
+{
+    return setHelper<uint64_t>(mShimDevice.mFunctions.setProducerUsage.pfn,
+            mShimDevice.mDevice, mDeviceId, usage, &mProducerUsage);
+}
+
+gralloc1_error_t Descriptor::setConsumerUsage(gralloc1_consumer_usage_t usage)
+{
+    return setHelper<uint64_t>(mShimDevice.mFunctions.setConsumerUsage.pfn,
+            mShimDevice.mDevice, mDeviceId, usage, &mConsumerUsage);
+}
+
+Device::Device(gralloc1_device_t* device)
+  : mDevice(device),
+    mCapabilities(loadCapabilities()),
+    mFunctions()
+{
+    if (!loadFunctions()) {
+        ALOGE("Failed to load a required function, aborting");
+        abort();
+    }
+}
+
+bool Device::hasCapability(gralloc1_capability_t capability) const
+{
+    return mCapabilities.count(capability) > 0;
+}
+
+std::string Device::dump()
+{
+    uint32_t length = 0;
+    mFunctions.dump(mDevice, &length, nullptr);
+
+    std::vector<char> output;
+    output.resize(length);
+    mFunctions.dump(mDevice, &length, output.data());
+
+    return std::string(output.cbegin(), output.cend());
+}
+
+std::shared_ptr<Descriptor> Device::createDescriptor()
+{
+    gralloc1_buffer_descriptor_t descriptorId;
+    int32_t intError = mFunctions.createDescriptor(mDevice, &descriptorId);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error != GRALLOC1_ERROR_NONE) {
+        return nullptr;
+    }
+    auto descriptor = std::make_shared<Descriptor>(*this, descriptorId);
+    return descriptor;
+}
+
+gralloc1_error_t Device::getStride(buffer_handle_t buffer, uint32_t* outStride)
+{
+    int32_t intError = mFunctions.getStride(mDevice, buffer, outStride);
+    return static_cast<gralloc1_error_t>(intError);
+}
+
+static inline bool allocationSucceded(gralloc1_error_t error)
+{
+    return error == GRALLOC1_ERROR_NONE || error == GRALLOC1_ERROR_NOT_SHARED;
+}
+
+gralloc1_error_t Device::allocate(
+        const std::vector<std::shared_ptr<const Descriptor>>& descriptors,
+        std::vector<buffer_handle_t>* outBuffers)
+{
+    if (mFunctions.allocate.pfn == nullptr) {
+        // Allocation is not supported on this device
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+
+    std::vector<gralloc1_buffer_descriptor_t> deviceIds;
+    for (const auto& descriptor : descriptors) {
+        deviceIds.emplace_back(descriptor->getDeviceId());
+    }
+
+    std::vector<buffer_handle_t> buffers(descriptors.size());
+    int32_t intError = mFunctions.allocate(mDevice,
+            static_cast<uint32_t>(descriptors.size()), deviceIds.data(),
+            buffers.data());
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (allocationSucceded(error)) {
+        *outBuffers = std::move(buffers);
+    }
+
+    return error;
+}
+
+gralloc1_error_t Device::allocate(
+        const std::shared_ptr<const Descriptor>& descriptor,
+        gralloc1_backing_store_t id, buffer_handle_t* outBuffer)
+{
+    gralloc1_error_t error = GRALLOC1_ERROR_NONE;
+
+    if (hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+        buffer_handle_t buffer = nullptr;
+        int32_t intError = mFunctions.allocateWithId(mDevice,
+                descriptor->getDeviceId(), id, &buffer);
+        error = static_cast<gralloc1_error_t>(intError);
+        if (allocationSucceded(error)) {
+            *outBuffer = buffer;
+        }
+    } else {
+        std::vector<std::shared_ptr<const Descriptor>> descriptors;
+        descriptors.emplace_back(descriptor);
+        std::vector<buffer_handle_t> buffers;
+        error = allocate(descriptors, &buffers);
+        if (allocationSucceded(error)) {
+            *outBuffer = buffers[0];
+        }
+    }
+
+    return error;
+}
+
+gralloc1_error_t Device::retain(buffer_handle_t buffer)
+{
+    int32_t intError = mFunctions.retain(mDevice, buffer);
+    return static_cast<gralloc1_error_t>(intError);
+}
+
+gralloc1_error_t Device::retain(const GraphicBuffer* buffer)
+{
+    if (hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+        return mFunctions.retainGraphicBuffer(mDevice, buffer);
+    } else {
+        return retain(buffer->getNativeBuffer()->handle);
+    }
+}
+
+gralloc1_error_t Device::release(buffer_handle_t buffer)
+{
+    int32_t intError = mFunctions.release(mDevice, buffer);
+    return static_cast<gralloc1_error_t>(intError);
+}
+
+gralloc1_error_t Device::getNumFlexPlanes(buffer_handle_t buffer,
+        uint32_t* outNumPlanes)
+{
+    uint32_t numPlanes = 0;
+    int32_t intError = mFunctions.getNumFlexPlanes(mDevice, buffer, &numPlanes);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error == GRALLOC1_ERROR_NONE) {
+        *outNumPlanes = numPlanes;
+    }
+    return error;
+}
+
+gralloc1_error_t Device::lock(buffer_handle_t buffer,
+        gralloc1_producer_usage_t producerUsage,
+        gralloc1_consumer_usage_t consumerUsage,
+        const gralloc1_rect_t* accessRegion, void** outData,
+        const sp<Fence>& acquireFence)
+{
+    ALOGV("Calling lock(%p)", buffer);
+    return lockHelper(mFunctions.lock.pfn, buffer, producerUsage,
+            consumerUsage, accessRegion, outData, acquireFence);
+}
+
+gralloc1_error_t Device::lockFlex(buffer_handle_t 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)
+{
+    ALOGV("Calling lockFlex(%p)", buffer);
+    return lockHelper(mFunctions.lockFlex.pfn, buffer, producerUsage,
+            consumerUsage, accessRegion, outData, acquireFence);
+}
+
+gralloc1_error_t Device::lockYCbCr(buffer_handle_t buffer,
+        gralloc1_producer_usage_t producerUsage,
+        gralloc1_consumer_usage_t consumerUsage,
+        const gralloc1_rect_t* accessRegion,
+        struct android_ycbcr* outData,
+        const sp<Fence>& acquireFence)
+{
+    ALOGV("Calling lockYCbCr(%p)", buffer);
+    return lockHelper(mFunctions.lockYCbCr.pfn, buffer, producerUsage,
+            consumerUsage, accessRegion, outData, acquireFence);
+}
+
+gralloc1_error_t Device::unlock(buffer_handle_t buffer, sp<Fence>* outFence)
+{
+    int32_t fenceFd = -1;
+    int32_t intError = mFunctions.unlock(mDevice, buffer, &fenceFd);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error == GRALLOC1_ERROR_NONE) {
+        *outFence = new Fence(fenceFd);
+    }
+    return error;
+}
+
+std::unordered_set<gralloc1_capability_t> Device::loadCapabilities()
+{
+    std::vector<int32_t> intCapabilities;
+    uint32_t numCapabilities = 0;
+    mDevice->getCapabilities(mDevice, &numCapabilities, nullptr);
+
+    intCapabilities.resize(numCapabilities);
+    mDevice->getCapabilities(mDevice, &numCapabilities, intCapabilities.data());
+
+    std::unordered_set<gralloc1_capability_t> capabilities;
+    for (const auto intCapability : intCapabilities) {
+        capabilities.emplace(static_cast<gralloc1_capability_t>(intCapability));
+    }
+    return capabilities;
+}
+
+bool Device::loadFunctions()
+{
+    // Functions which must always be present
+    if (!mFunctions.dump.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.createDescriptor.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.destroyDescriptor.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.setConsumerUsage.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.setDimensions.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.setFormat.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.setProducerUsage.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getBackingStore.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getConsumerUsage.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getDimensions.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getFormat.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getProducerUsage.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getStride.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.retain.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.release.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getNumFlexPlanes.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.lock.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.lockFlex.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.unlock.load(mDevice, true)) {
+        return false;
+    }
+
+    if (hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+        // These should always be present on the adapter
+        if (!mFunctions.retainGraphicBuffer.load(mDevice, true)) {
+            return false;
+        }
+        if (!mFunctions.lockYCbCr.load(mDevice, true)) {
+            return false;
+        }
+
+        // allocateWithId may not be present if we're only able to map in this
+        // process
+        mFunctions.allocateWithId.load(mDevice, false);
+    } else {
+        // allocate may not be present if we're only able to map in this process
+        mFunctions.allocate.load(mDevice, false);
+    }
+
+    return true;
+}
+
+std::unique_ptr<Gralloc1On0Adapter> Loader::mAdapter = nullptr;
+
+Loader::Loader()
+  : mDevice(nullptr)
+{
+    hw_module_t const* module;
+    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+    uint8_t majorVersion = (module->module_api_version >> 8) & 0xFF;
+    uint8_t minorVersion = module->module_api_version & 0xFF;
+    gralloc1_device_t* device = nullptr;
+    if (majorVersion == 1) {
+        gralloc1_open(module, &device);
+    } else {
+        if (!mAdapter) {
+            mAdapter = std::make_unique<Gralloc1On0Adapter>(module);
+        }
+        device = mAdapter->getDevice();
+    }
+    mDevice = std::make_unique<Gralloc1::Device>(device);
+}
+
+Loader::~Loader() {}
+
+std::unique_ptr<Device> Loader::getDevice()
+{
+    return std::move(mDevice);
+}
+
+} // namespace android::Gralloc1
+
+} // namespace android