/*
 * 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::setLayerCount(uint32_t layerCount)
{
    if (mShimDevice.hasCapability(GRALLOC1_CAPABILITY_LAYERED_BUFFERS)) {
        return setHelper<uint32_t>(mShimDevice.mFunctions.setLayerCount.pfn,
                mShimDevice.mDevice, mDeviceId, layerCount, &mLayerCount);
    } else {
        // Layered buffers are not supported on this device.
        return GRALLOC1_ERROR_UNSUPPORTED;
    }
}

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;
}

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::getDimensions(buffer_handle_t buffer,
        uint32_t* outWidth, uint32_t* outHeight)
{
    uint32_t width = 0;
    uint32_t height = 0;
    int32_t intError = mFunctions.getDimensions(mDevice, buffer, &width,
            &height);
    auto error = static_cast<gralloc1_error_t>(intError);
    if (error == GRALLOC1_ERROR_NONE) {
        *outWidth = width;
        *outHeight = height;
    }
    return error;
}

gralloc1_error_t Device::getFormat(buffer_handle_t buffer,
        int32_t* outFormat)
{
    int32_t format = 0;
    int32_t intError = mFunctions.getFormat(mDevice, buffer, &format);
    auto error = static_cast<gralloc1_error_t>(intError);
    if (error == GRALLOC1_ERROR_NONE) {
        *outFormat = format;
    }
    return error;
}

gralloc1_error_t Device::getLayerCount(buffer_handle_t buffer,
        uint32_t* outLayerCount)
{
    if (hasCapability(GRALLOC1_CAPABILITY_LAYERED_BUFFERS)) {
        uint32_t layerCount = 0;
        int32_t intError = mFunctions.getLayerCount(mDevice, buffer,
                &layerCount);
        auto error = static_cast<gralloc1_error_t>(intError);
        if (error == GRALLOC1_ERROR_NONE) {
            *outLayerCount = layerCount;
        }
        return error;
    } else {
        // Layered buffers are not supported on this device.
        return GRALLOC1_ERROR_UNSUPPORTED;
    }
}

gralloc1_error_t Device::getProducerUsage(buffer_handle_t buffer,
        uint64_t* outProducerUsage)
{
    uint64_t usage = 0;
    int32_t intError = mFunctions.getProducerUsage(mDevice, buffer, &usage);
    auto error = static_cast<gralloc1_error_t>(intError);
    if (error == GRALLOC1_ERROR_NONE) {
        *outProducerUsage = usage;
    }
    return error;
}

gralloc1_error_t Device::getConsumerUsage(buffer_handle_t buffer,
        uint64_t* outConsumerUsage)
{
    uint64_t usage = 0;
    int32_t intError = mFunctions.getConsumerUsage(mDevice, buffer, &usage);
    auto error = static_cast<gralloc1_error_t>(intError);
    if (error == GRALLOC1_ERROR_NONE) {
        *outConsumerUsage = usage;
    }
    return error;
}

gralloc1_error_t Device::getBackingStore(buffer_handle_t buffer,
        uint64_t* outBackingStore)
{
    uint64_t store = 0;
    int32_t intError = mFunctions.getBackingStore(mDevice, buffer, &store);
    auto error = static_cast<gralloc1_error_t>(intError);
    if (error == GRALLOC1_ERROR_NONE) {
        *outBackingStore = store;
    }
    return error;
}

gralloc1_error_t Device::getStride(buffer_handle_t buffer,
        uint32_t* outStride)
{
    uint32_t stride = 0;
    int32_t intError = mFunctions.getStride(mDevice, buffer, &stride);
    auto error = static_cast<gralloc1_error_t>(intError);
    if (error == GRALLOC1_ERROR_NONE) {
        *outStride = stride;
    }
    return error;
}

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, 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, 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, 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);
    }

    if (hasCapability(GRALLOC1_CAPABILITY_LAYERED_BUFFERS)) {
        if (!mFunctions.setLayerCount.load(mDevice, true)) {
            return false;
        }
        if (!mFunctions.getLayerCount.load(mDevice, true)) {
            return 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
