Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 422b94e0 authored by Chia-I Wu's avatar Chia-I Wu
Browse files

graphics: make allocator passthrough library header-only

android.hardware.graphics.allocator@2.0-passthrough should be a
header-only library to be fully reusable by vendor HALs.

This also allows us to switch from virtual inheritance to templates,
which is more straightforward.  This changes nothing to the users
and we still have these relations

 - AllocatorHal is an abstract class to be implemented by vendors or
   the default implementations
 - Gralloc[01]Hal are our default implementations
 - Allocator implements HIDL IAllocator interface on top of
   AllocatorHal

What we do not like about virtual inheritance is that, given

  // abstract class B and D
  class B {
    virtual void foo() = 0;
    virtual void bar() = 0;
  };
  class D : public virtual B {
    // foo is superceded by fooEnhanced in D
    void foo() { fooEnhanced(); }
    virtual void fooEnhanced() = 0;
  };

  // an implementation of B
  class BImpl : public virtual B {
    void foo() {}
    void bar() {}
  };

  // an implementation of D on top of BImpl
  class DImpl : public virtual D, public virtual BImpl {
    void fooEnhanced() {}
  };

we get "no unique final overrider" becase both D and BImpl implement
foo.  With non-virtual inheritance, on the other hand, we get "DImpl
is abstract" because foo is still pure virtual implemented in DImpl.
Templates solve the issue by allowing

  namespace detail{
  template<typename T>
  class BImpl : public T { ... };

  template<typename T>
  class DImpl : public BImpl<T> { ... };
  } // namespace detail

  using BImpl = detail::BImpl<B>;
  using DImpl = detail::DImpl<D>;

Test: boots
Change-Id: Iccb513e4fc751e9a687a1ed2d9fb2192c8324a50
parent de542acb
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -4,11 +4,8 @@ cc_library_shared {
    vendor: true,
    relative_install_path: "hw",
    srcs: ["passthrough.cpp"],
    static_libs: [
        "android.hardware.graphics.allocator@2.0-passthrough",
    ],
    header_libs: [
        "android.hardware.graphics.allocator@2.0-hal",
        "android.hardware.graphics.allocator@2.0-passthrough",
    ],
    shared_libs: [
        "android.hardware.graphics.allocator@2.0",
@@ -20,6 +17,7 @@ cc_library_shared {
        "liblog",
        "libutils",
    ],
    cflags: ["-DLOG_TAG=\"AllocatorHal\""],
}

cc_binary {
+5 −5
Original line number Diff line number Diff line
@@ -39,11 +39,11 @@ using mapper::V2_0::Error;

namespace detail {

// AllocatorImpl implements IAllocator on top of AllocatorHal
template <typename IALLOCATOR, typename ALLOCATOR_HAL>
class AllocatorImpl : public IALLOCATOR {
// AllocatorImpl implements V2_*::IAllocator on top of V2_*::hal::AllocatorHal
template <typename Interface, typename Hal>
class AllocatorImpl : public Interface {
   public:
    bool init(std::unique_ptr<ALLOCATOR_HAL> hal) {
    bool init(std::unique_ptr<Hal> hal) {
        mHal = std::move(hal);
        return true;
    }
@@ -74,7 +74,7 @@ class AllocatorImpl : public IALLOCATOR {
    }

   protected:
    std::unique_ptr<ALLOCATOR_HAL> mHal;
    std::unique_ptr<Hal> mHal;
};

}  // namespace detail
+2 −7
Original line number Diff line number Diff line
cc_library_static {
cc_library_headers {
    name: "android.hardware.graphics.allocator@2.0-passthrough",
    defaults: ["hidl_defaults"],
    vendor: true,
    srcs: [
        "Gralloc0Hal.cpp",
        "Gralloc1Hal.cpp",
        "GrallocLoader.cpp",
    ],
    shared_libs: [
        "android.hardware.graphics.allocator@2.0",
        "android.hardware.graphics.mapper@2.0",
@@ -23,7 +18,7 @@ cc_library_static {
    ],
    export_header_lib_headers: [
        "android.hardware.graphics.allocator@2.0-hal",
        "libgrallocmapperincludes",
    ],
    export_include_dirs: ["include"],
    cflags: ["-DLOG_TAG=\"AllocatorHal\""],
}
+0 −141
Original line number Diff line number Diff line
/*
 * 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.
 */

#include <allocator-passthrough/2.0/Gralloc0Hal.h>

#include <string.h>

#include <GrallocBufferDescriptor.h>
#include <hardware/gralloc.h>
#include <log/log.h>

namespace android {
namespace hardware {
namespace graphics {
namespace allocator {
namespace V2_0 {
namespace passthrough {

using mapper::V2_0::implementation::grallocDecodeBufferDescriptor;

Gralloc0Hal::~Gralloc0Hal() {
    if (mDevice) {
        gralloc_close(mDevice);
    }
}

bool Gralloc0Hal::initWithModule(const hw_module_t* module) {
    int result = gralloc_open(module, &mDevice);
    if (result) {
        ALOGE("failed to open gralloc0 device: %s", strerror(-result));
        mDevice = nullptr;
        return false;
    }

    return true;
}

std::string Gralloc0Hal::dumpDebugInfo() {
    char buf[4096] = {};
    if (mDevice->dump) {
        mDevice->dump(mDevice, buf, sizeof(buf));
        buf[sizeof(buf) - 1] = '\0';
    }

    return buf;
}

Error Gralloc0Hal::allocateBuffers(const BufferDescriptor& descriptor, uint32_t count,
                                   uint32_t* outStride,
                                   std::vector<const native_handle_t*>* outBuffers) {
    mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo;
    if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
        return Error::BAD_DESCRIPTOR;
    }

    Error error = Error::NONE;
    uint32_t stride = 0;
    std::vector<const native_handle_t*> buffers;
    buffers.reserve(count);

    // allocate the buffers
    for (uint32_t i = 0; i < count; i++) {
        const native_handle_t* tmpBuffer;
        uint32_t tmpStride;
        error = allocateOneBuffer(descriptorInfo, &tmpBuffer, &tmpStride);
        if (error != Error::NONE) {
            break;
        }

        buffers.push_back(tmpBuffer);

        if (stride == 0) {
            stride = tmpStride;
        } else if (stride != tmpStride) {
            // non-uniform strides
            error = Error::UNSUPPORTED;
            break;
        }
    }

    if (error != Error::NONE) {
        freeBuffers(buffers);
        return error;
    }

    *outStride = stride;
    *outBuffers = std::move(buffers);

    return Error::NONE;
}

void Gralloc0Hal::freeBuffers(const std::vector<const native_handle_t*>& buffers) {
    for (auto buffer : buffers) {
        int result = mDevice->free(mDevice, buffer);
        if (result != 0) {
            ALOGE("failed to free buffer %p: %d", buffer, result);
        }
    }
}

Error Gralloc0Hal::allocateOneBuffer(const mapper::V2_0::IMapper::BufferDescriptorInfo& info,
                                     const native_handle_t** outBuffer, uint32_t* outStride) {
    if (info.layerCount > 1 || (info.usage >> 32) != 0) {
        return Error::BAD_VALUE;
    }

    const native_handle_t* buffer = nullptr;
    int stride = 0;
    int result = mDevice->alloc(mDevice, info.width, info.height, static_cast<int>(info.format),
                                info.usage, &buffer, &stride);
    switch (result) {
        case 0:
            *outBuffer = buffer;
            *outStride = stride;
            return Error::NONE;
        case -EINVAL:
            return Error::BAD_VALUE;
        default:
            return Error::NO_RESOURCES;
    }
}

}  // namespace passthrough
}  // namespace V2_0
}  // namespace allocator
}  // namespace graphics
}  // namespace hardware
}  // namespace android
+0 −323
Original line number Diff line number Diff line
/*
 * 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.
 */

#include <allocator-passthrough/2.0/Gralloc1Hal.h>

#include <string.h>

#include <GrallocBufferDescriptor.h>
#include <log/log.h>

namespace android {
namespace hardware {
namespace graphics {
namespace allocator {
namespace V2_0 {
namespace passthrough {

using android::hardware::graphics::common::V1_0::BufferUsage;
using mapper::V2_0::implementation::grallocDecodeBufferDescriptor;

Gralloc1Hal::~Gralloc1Hal() {
    if (mDevice) {
        gralloc1_close(mDevice);
    }
}

bool Gralloc1Hal::initWithModule(const hw_module_t* module) {
    int result = gralloc1_open(module, &mDevice);
    if (result) {
        ALOGE("failed to open gralloc1 device: %s", strerror(-result));
        mDevice = nullptr;
        return false;
    }

    initCapabilities();
    if (!initDispatch()) {
        gralloc1_close(mDevice);
        mDevice = nullptr;
        return false;
    }

    return true;
}

void Gralloc1Hal::initCapabilities() {
    uint32_t count = 0;
    mDevice->getCapabilities(mDevice, &count, nullptr);

    std::vector<int32_t> capabilities(count);
    mDevice->getCapabilities(mDevice, &count, capabilities.data());
    capabilities.resize(count);

    for (auto capability : capabilities) {
        if (capability == GRALLOC1_CAPABILITY_LAYERED_BUFFERS) {
            mCapabilities.layeredBuffers = true;
            break;
        }
    }
}

gralloc1_function_pointer_t Gralloc1Hal::getDispatchFunction(
    gralloc1_function_descriptor_t desc) const {
    auto pfn = mDevice->getFunction(mDevice, desc);
    if (!pfn) {
        ALOGE("failed to get gralloc1 function %d", desc);
        return nullptr;
    }
    return pfn;
}

bool Gralloc1Hal::initDispatch() {
    if (!initDispatchFunction(GRALLOC1_FUNCTION_DUMP, &mDispatch.dump) ||
        !initDispatchFunction(GRALLOC1_FUNCTION_CREATE_DESCRIPTOR, &mDispatch.createDescriptor) ||
        !initDispatchFunction(GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR, &mDispatch.destroyDescriptor) ||
        !initDispatchFunction(GRALLOC1_FUNCTION_SET_DIMENSIONS, &mDispatch.setDimensions) ||
        !initDispatchFunction(GRALLOC1_FUNCTION_SET_FORMAT, &mDispatch.setFormat) ||
        !initDispatchFunction(GRALLOC1_FUNCTION_SET_CONSUMER_USAGE, &mDispatch.setConsumerUsage) ||
        !initDispatchFunction(GRALLOC1_FUNCTION_SET_PRODUCER_USAGE, &mDispatch.setProducerUsage) ||
        !initDispatchFunction(GRALLOC1_FUNCTION_GET_STRIDE, &mDispatch.getStride) ||
        !initDispatchFunction(GRALLOC1_FUNCTION_ALLOCATE, &mDispatch.allocate) ||
        !initDispatchFunction(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release)) {
        return false;
    }

    if (mCapabilities.layeredBuffers) {
        if (!initDispatchFunction(GRALLOC1_FUNCTION_SET_LAYER_COUNT, &mDispatch.setLayerCount)) {
            return false;
        }
    }

    return true;
}

std::string Gralloc1Hal::dumpDebugInfo() {
    uint32_t len = 0;
    mDispatch.dump(mDevice, &len, nullptr);

    std::vector<char> buf(len + 1);
    mDispatch.dump(mDevice, &len, buf.data());
    buf.resize(len + 1);
    buf[len] = '\0';

    return buf.data();
}

Error Gralloc1Hal::allocateBuffers(const BufferDescriptor& descriptor, uint32_t count,
                                   uint32_t* outStride,
                                   std::vector<const native_handle_t*>* outBuffers) {
    mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo;
    if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
        return Error::BAD_DESCRIPTOR;
    }

    gralloc1_buffer_descriptor_t desc;
    Error error = createDescriptor(descriptorInfo, &desc);
    if (error != Error::NONE) {
        return error;
    }

    uint32_t stride = 0;
    std::vector<const native_handle_t*> buffers;
    buffers.reserve(count);

    // allocate the buffers
    for (uint32_t i = 0; i < count; i++) {
        const native_handle_t* tmpBuffer;
        uint32_t tmpStride;
        error = allocateOneBuffer(desc, &tmpBuffer, &tmpStride);
        if (error != Error::NONE) {
            break;
        }

        buffers.push_back(tmpBuffer);

        if (stride == 0) {
            stride = tmpStride;
        } else if (stride != tmpStride) {
            // non-uniform strides
            error = Error::UNSUPPORTED;
            break;
        }
    }

    mDispatch.destroyDescriptor(mDevice, desc);

    if (error != Error::NONE) {
        freeBuffers(buffers);
        return error;
    }

    *outStride = stride;
    *outBuffers = std::move(buffers);

    return Error::NONE;
}

void Gralloc1Hal::freeBuffers(const std::vector<const native_handle_t*>& buffers) {
    for (auto buffer : buffers) {
        int32_t error = mDispatch.release(mDevice, buffer);
        if (error != GRALLOC1_ERROR_NONE) {
            ALOGE("failed to free buffer %p: %d", buffer, error);
        }
    }
}

Error Gralloc1Hal::toError(int32_t error) {
    switch (error) {
        case GRALLOC1_ERROR_NONE:
            return Error::NONE;
        case GRALLOC1_ERROR_BAD_DESCRIPTOR:
            return Error::BAD_DESCRIPTOR;
        case GRALLOC1_ERROR_BAD_HANDLE:
            return Error::BAD_BUFFER;
        case GRALLOC1_ERROR_BAD_VALUE:
            return Error::BAD_VALUE;
        case GRALLOC1_ERROR_NOT_SHARED:
            return Error::NONE;  // this is fine
        case GRALLOC1_ERROR_NO_RESOURCES:
            return Error::NO_RESOURCES;
        case GRALLOC1_ERROR_UNDEFINED:
        case GRALLOC1_ERROR_UNSUPPORTED:
        default:
            return Error::UNSUPPORTED;
    }
}

uint64_t Gralloc1Hal::toProducerUsage(uint64_t usage) {
    // this is potentially broken as we have no idea which private flags
    // should be filtered out
    uint64_t producerUsage =
        usage & ~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
                                       BufferUsage::GPU_DATA_BUFFER);

    switch (usage & BufferUsage::CPU_WRITE_MASK) {
        case static_cast<uint64_t>(BufferUsage::CPU_WRITE_RARELY):
            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
            break;
        case static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN):
            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
            break;
        default:
            break;
    }

    switch (usage & BufferUsage::CPU_READ_MASK) {
        case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ;
            break;
        case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN;
            break;
        default:
            break;
    }

    // BufferUsage::GPU_DATA_BUFFER is always filtered out

    return producerUsage;
}

uint64_t Gralloc1Hal::toConsumerUsage(uint64_t usage) {
    // this is potentially broken as we have no idea which private flags
    // should be filtered out
    uint64_t consumerUsage =
        usage &
        ~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
                               BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::GPU_DATA_BUFFER);

    switch (usage & BufferUsage::CPU_READ_MASK) {
        case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
            consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
            break;
        case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
            consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
            break;
        default:
            break;
    }

    // BufferUsage::SENSOR_DIRECT_DATA is always filtered out

    if (usage & BufferUsage::GPU_DATA_BUFFER) {
        consumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER;
    }

    return consumerUsage;
}

Error Gralloc1Hal::createDescriptor(const mapper::V2_0::IMapper::BufferDescriptorInfo& info,
                                    gralloc1_buffer_descriptor_t* outDescriptor) {
    gralloc1_buffer_descriptor_t descriptor;

    int32_t error = mDispatch.createDescriptor(mDevice, &descriptor);

    if (error == GRALLOC1_ERROR_NONE) {
        error = mDispatch.setDimensions(mDevice, descriptor, info.width, info.height);
    }
    if (error == GRALLOC1_ERROR_NONE) {
        error = mDispatch.setFormat(mDevice, descriptor, static_cast<int32_t>(info.format));
    }
    if (error == GRALLOC1_ERROR_NONE) {
        if (mCapabilities.layeredBuffers) {
            error = mDispatch.setLayerCount(mDevice, descriptor, info.layerCount);
        } else if (info.layerCount > 1) {
            error = GRALLOC1_ERROR_UNSUPPORTED;
        }
    }
    if (error == GRALLOC1_ERROR_NONE) {
        error = mDispatch.setProducerUsage(mDevice, descriptor, toProducerUsage(info.usage));
    }
    if (error == GRALLOC1_ERROR_NONE) {
        error = mDispatch.setConsumerUsage(mDevice, descriptor, toConsumerUsage(info.usage));
    }

    if (error == GRALLOC1_ERROR_NONE) {
        *outDescriptor = descriptor;
    } else {
        mDispatch.destroyDescriptor(mDevice, descriptor);
    }

    return toError(error);
}

Error Gralloc1Hal::allocateOneBuffer(gralloc1_buffer_descriptor_t descriptor,
                                     const native_handle_t** outBuffer, uint32_t* outStride) {
    const native_handle_t* buffer = nullptr;
    int32_t error = mDispatch.allocate(mDevice, 1, &descriptor, &buffer);
    if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_NOT_SHARED) {
        return toError(error);
    }

    uint32_t stride = 0;
    error = mDispatch.getStride(mDevice, buffer, &stride);
    if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_UNDEFINED) {
        mDispatch.release(mDevice, buffer);
        return toError(error);
    }

    *outBuffer = buffer;
    *outStride = stride;

    return Error::NONE;
}

}  // namespace passthrough
}  // namespace V2_0
}  // namespace allocator
}  // namespace graphics
}  // namespace hardware
}  // namespace android
Loading