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

Commit bb0a61a8 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Codec2: move allocators into their own files"

parents 8f8932c4 c04c1234
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

#include <gtest/gtest.h>

#include <C2AllocatorIon.h>
#include <C2AllocatorGralloc.h>
#include <C2Buffer.h>
#include <C2BufferPriv.h>
#include <C2ParamDef.h>
+2 −0
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@ cc_library_static {
    name: "libstagefright_codec2_vndk",

    srcs: [
        "C2AllocatorIon.cpp",
        "C2AllocatorGralloc.cpp",
        "C2Buffer.cpp",
        "C2Config.cpp",
    ],
+340 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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
#define LOG_TAG "C2AllocatorIon"
#include <utils/Log.h>

#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <hardware/gralloc.h>

#include <C2AllocatorGralloc.h>
#include <C2Buffer.h>

namespace android {

using ::android::hardware::graphics::allocator::V2_0::IAllocator;
using ::android::hardware::graphics::common::V1_0::BufferUsage;
using ::android::hardware::graphics::common::V1_0::PixelFormat;
using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
using ::android::hardware::graphics::mapper::V2_0::Error;
using ::android::hardware::graphics::mapper::V2_0::IMapper;
using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_vec;

/* ===================================== GRALLOC ALLOCATION ==================================== */
static C2Error maperr2error(Error maperr) {
    switch (maperr) {
        case Error::NONE:           return C2_OK;
        case Error::BAD_DESCRIPTOR: return C2_BAD_VALUE;
        case Error::BAD_BUFFER:     return C2_BAD_VALUE;
        case Error::BAD_VALUE:      return C2_BAD_VALUE;
        case Error::NO_RESOURCES:   return C2_NO_MEMORY;
        case Error::UNSUPPORTED:    return C2_UNSUPPORTED;
    }
    return C2_CORRUPTED;
}

class C2AllocationGralloc : public C2GraphicAllocation {
public:
    virtual ~C2AllocationGralloc();

    virtual C2Error map(
            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
            C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
    virtual C2Error unmap(C2Fence *fenceFd /* nullable */) override;
    virtual bool isValid() const override { return true; }
    virtual const C2Handle *handle() const override { return mHandle; }
    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override;

    // internal methods
    // |handle| will be moved.
    C2AllocationGralloc(
              const IMapper::BufferDescriptorInfo &info,
              const sp<IMapper> &mapper,
              hidl_handle &handle);
    int dup() const;
    C2Error status() const;

private:
    const IMapper::BufferDescriptorInfo mInfo;
    const sp<IMapper> mMapper;
    const hidl_handle mHandle;
    buffer_handle_t mBuffer;
    bool mLocked;
};

C2AllocationGralloc::C2AllocationGralloc(
          const IMapper::BufferDescriptorInfo &info,
          const sp<IMapper> &mapper,
          hidl_handle &handle)
    : C2GraphicAllocation(info.width, info.height),
      mInfo(info),
      mMapper(mapper),
      mHandle(std::move(handle)),
      mBuffer(nullptr),
      mLocked(false) {}

C2AllocationGralloc::~C2AllocationGralloc() {
    if (!mBuffer) {
        return;
    }
    if (mLocked) {
        unmap(nullptr);
    }
    mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer));
}

C2Error C2AllocationGralloc::map(
        C2Rect rect, C2MemoryUsage usage, int *fenceFd,
        C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
    // TODO
    (void) fenceFd;
    (void) usage;

    if (mBuffer && mLocked) {
        return C2_DUPLICATE;
    }
    if (!layout || !addr) {
        return C2_BAD_VALUE;
    }

    C2Error err = C2_OK;
    if (!mBuffer) {
        mMapper->importBuffer(
                mHandle, [&err, this](const auto &maperr, const auto &buffer) {
                    err = maperr2error(maperr);
                    if (err == C2_OK) {
                        mBuffer = static_cast<buffer_handle_t>(buffer);
                    }
                });
        if (err != C2_OK) {
            return err;
        }
    }

    if (mInfo.format == PixelFormat::YCBCR_420_888 || mInfo.format == PixelFormat::YV12) {
        YCbCrLayout ycbcrLayout;
        mMapper->lockYCbCr(
                const_cast<native_handle_t *>(mBuffer),
                BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
                { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
                // TODO: fence
                hidl_handle(),
                [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
                    err = maperr2error(maperr);
                    if (err == C2_OK) {
                        ycbcrLayout = mapLayout;
                    }
                });
        if (err != C2_OK) {
            return err;
        }
        addr[C2PlaneLayout::Y] = (uint8_t *)ycbcrLayout.y;
        addr[C2PlaneLayout::U] = (uint8_t *)ycbcrLayout.cb;
        addr[C2PlaneLayout::V] = (uint8_t *)ycbcrLayout.cr;
        layout->mType = C2PlaneLayout::MEDIA_IMAGE_TYPE_YUV;
        layout->mNumPlanes = 3;
        layout->mPlanes[C2PlaneLayout::Y] = {
            C2PlaneInfo::Y,                 // mChannel
            1,                              // mColInc
            (int32_t)ycbcrLayout.yStride,   // mRowInc
            1,                              // mHorizSubsampling
            1,                              // mVertSubsampling
            8,                              // mBitDepth
            8,                              // mAllocatedDepth
        };
        layout->mPlanes[C2PlaneLayout::U] = {
            C2PlaneInfo::Cb,                  // mChannel
            (int32_t)ycbcrLayout.chromaStep,  // mColInc
            (int32_t)ycbcrLayout.cStride,     // mRowInc
            2,                                // mHorizSubsampling
            2,                                // mVertSubsampling
            8,                                // mBitDepth
            8,                                // mAllocatedDepth
        };
        layout->mPlanes[C2PlaneLayout::V] = {
            C2PlaneInfo::Cr,                  // mChannel
            (int32_t)ycbcrLayout.chromaStep,  // mColInc
            (int32_t)ycbcrLayout.cStride,     // mRowInc
            2,                                // mHorizSubsampling
            2,                                // mVertSubsampling
            8,                                // mBitDepth
            8,                                // mAllocatedDepth
        };
    } else {
        void *pointer = nullptr;
        mMapper->lock(
                const_cast<native_handle_t *>(mBuffer),
                BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
                { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
                // TODO: fence
                hidl_handle(),
                [&err, &pointer](const auto &maperr, const auto &mapPointer) {
                    err = maperr2error(maperr);
                    if (err == C2_OK) {
                        pointer = mapPointer;
                    }
                });
        if (err != C2_OK) {
            return err;
        }
        // TODO
        return C2_UNSUPPORTED;
    }
    mLocked = true;

    return C2_OK;
}

C2Error C2AllocationGralloc::unmap(C2Fence *fenceFd /* nullable */) {
    // TODO: fence
    C2Error err = C2_OK;
    mMapper->unlock(
            const_cast<native_handle_t *>(mBuffer),
            [&err, &fenceFd](const auto &maperr, const auto &releaseFence) {
                // TODO
                (void) fenceFd;
                (void) releaseFence;
                err = maperr2error(maperr);
                if (err == C2_OK) {
                    // TODO: fence
                }
            });
    if (err == C2_OK) {
        mLocked = false;
    }
    return err;
}

bool C2AllocationGralloc::equals(const std::shared_ptr<const C2GraphicAllocation> &other) const {
    return other && other->handle() == handle();
}

/* ===================================== GRALLOC ALLOCATOR ==================================== */
class C2AllocatorGralloc::Impl {
public:
    Impl();

    C2Error allocateGraphicBuffer(
            uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
            std::shared_ptr<C2GraphicAllocation> *allocation);

    C2Error recreateGraphicBuffer(
            const C2Handle *handle,
            std::shared_ptr<C2GraphicAllocation> *allocation);

    C2Error status() const { return mInit; }

private:
    C2Error mInit;
    sp<IAllocator> mAllocator;
    sp<IMapper> mMapper;
};

C2AllocatorGralloc::Impl::Impl() : mInit(C2_OK) {
    // TODO: share a global service
    mAllocator = IAllocator::getService();
    mMapper = IMapper::getService();
    if (mAllocator == nullptr || mMapper == nullptr) {
        mInit = C2_CORRUPTED;
    }
}

C2Error C2AllocatorGralloc::Impl::allocateGraphicBuffer(
        uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
        std::shared_ptr<C2GraphicAllocation> *allocation) {
    // TODO: buffer usage should be determined according to |usage|
    (void) usage;

    IMapper::BufferDescriptorInfo info = {
        width,
        height,
        1u,  // layerCount
        (PixelFormat)format,
        BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
    };
    C2Error err = C2_OK;
    BufferDescriptor desc;
    mMapper->createDescriptor(
            info, [&err, &desc](const auto &maperr, const auto &descriptor) {
                err = maperr2error(maperr);
                if (err == C2_OK) {
                    desc = descriptor;
                }
            });
    if (err != C2_OK) {
        return err;
    }

    // IAllocator shares IMapper error codes.
    hidl_handle buffer;
    mAllocator->allocate(
            desc,
            1u,
            [&err, &buffer](const auto &maperr, const auto &stride, auto &buffers) {
                (void) stride;
                err = maperr2error(maperr);
                if (err != C2_OK) {
                    return;
                }
                if (buffers.size() != 1u) {
                    err = C2_CORRUPTED;
                    return;
                }
                buffer = std::move(buffers[0]);
            });
    if (err != C2_OK) {
        return err;
    }

    allocation->reset(new C2AllocationGralloc(info, mMapper, buffer));
    return C2_OK;
}

C2Error C2AllocatorGralloc::Impl::recreateGraphicBuffer(
        const C2Handle *handle,
        std::shared_ptr<C2GraphicAllocation> *allocation) {
    (void) handle;

    // TODO: need to figure out BufferDescriptorInfo from the handle.
    allocation->reset();
    return C2_UNSUPPORTED;
}

C2AllocatorGralloc::C2AllocatorGralloc() : mImpl(new Impl) {}

C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }

C2Error C2AllocatorGralloc::allocateGraphicBuffer(
        uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
        std::shared_ptr<C2GraphicAllocation> *allocation) {
    return mImpl->allocateGraphicBuffer(width, height, format, usage, allocation);
}

C2Error C2AllocatorGralloc::recreateGraphicBuffer(
        const C2Handle *handle,
        std::shared_ptr<C2GraphicAllocation> *allocation) {
    return mImpl->recreateGraphicBuffer(handle, allocation);
}

C2Error C2AllocatorGralloc::status() const {
    return mImpl->status();
}

} // namespace android
+344 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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
#define LOG_TAG "C2AllocatorIon"
#include <utils/Log.h>

#include <ion/ion.h>
#include <sys/mman.h>

#include <C2AllocatorIon.h>
#include <C2Buffer.h>
#include <C2ErrnoUtils.h>

namespace android {

/* ========================================= ION HANDLE ======================================== */
struct C2HandleIon : public C2Handle {
    C2HandleIon(int ionFd, ion_user_handle_t buffer) : C2Handle(cHeader),
          mFds{ ionFd, buffer },
          mInts{ kMagic } { }

    static bool isValid(const C2Handle * const o);

    int ionFd() const { return mFds.mIon; }
    ion_user_handle_t buffer() const { return mFds.mBuffer; }

    void setBuffer(ion_user_handle_t bufferFd) { mFds.mBuffer = bufferFd; }

protected:
    struct {
        int mIon;
        int mBuffer; // ion_user_handle_t
    } mFds;
    struct {
        int mMagic;
    } mInts;

private:
    typedef C2HandleIon _type;
    enum {
        kMagic = 'ion1',
        numFds = sizeof(mFds) / sizeof(int),
        numInts = sizeof(mInts) / sizeof(int),
        version = sizeof(C2Handle) + sizeof(mFds) + sizeof(mInts)
    };
    //constexpr static C2Handle cHeader = { version, numFds, numInts, {} };
    const static C2Handle cHeader;
};

const C2Handle C2HandleIon::cHeader = {
    C2HandleIon::version,
    C2HandleIon::numFds,
    C2HandleIon::numInts,
    {}
};

// static
bool C2HandleIon::isValid(const C2Handle * const o) {
    if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
        return false;
    }
    const C2HandleIon *other = static_cast<const C2HandleIon*>(o);
    return other->mInts.mMagic == kMagic;
}

// TODO: is the dup of an ion fd identical to ion_share?

/* ======================================= ION ALLOCATION ====================================== */
class C2AllocationIon : public C2LinearAllocation {
public:
    virtual C2Error map(
        size_t offset, size_t size, C2MemoryUsage usage, int *fence,
        void **addr /* nonnull */);
    virtual C2Error unmap(void *addr, size_t size, int *fenceFd);
    virtual bool isValid() const;
    virtual ~C2AllocationIon();
    virtual const C2Handle *handle() const;
    virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const;

    // internal methods
    C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags);
    C2AllocationIon(int ionFd, size_t size, int shareFd);
    int dup() const;
    C2Error status() const;

protected:
    class Impl;
    Impl *mImpl;
};

class C2AllocationIon::Impl {
public:
    // NOTE: using constructor here instead of a factory method as we will need the
    // error value and this simplifies the error handling by the wrapper.
    Impl(int ionFd, size_t capacity, size_t align, unsigned heapMask, unsigned flags)
        : mInit(C2_OK),
          mHandle(ionFd, -1),
          mMapFd(-1),
          mCapacity(capacity) {
        ion_user_handle_t buffer = -1;
        int ret = ion_alloc(mHandle.ionFd(), mCapacity, align, heapMask, flags, &buffer);
        if (ret == 0) {
            mHandle.setBuffer(buffer);
        } else {
            mInit = c2_map_errno<ENOMEM, EACCES, EINVAL>(-ret);
        }
    }

    Impl(int ionFd, size_t capacity, int shareFd)
        : mHandle(ionFd, -1),
          mMapFd(-1),
          mCapacity(capacity) {
        ion_user_handle_t buffer;
        mInit = ion_import(mHandle.ionFd(), shareFd, &buffer);
        if (mInit == 0) {
            mHandle.setBuffer(buffer);
        }
        (void)mCapacity; // TODO
    }

    C2Error map(size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
        (void)fenceFd; // TODO: wait for fence
        *addr = nullptr;
        int prot = PROT_NONE;
        int flags = MAP_PRIVATE;
        if (usage.mConsumer & GRALLOC_USAGE_SW_READ_MASK) {
            prot |= PROT_READ;
        }
        if (usage.mProducer & GRALLOC_USAGE_SW_WRITE_MASK) {
            prot |= PROT_WRITE;
            flags = MAP_SHARED;
        }

        size_t alignmentBytes = offset % PAGE_SIZE;
        size_t mapOffset = offset - alignmentBytes;
        size_t mapSize = size + alignmentBytes;

        C2Error err = C2_OK;
        if (mMapFd == -1) {
            int ret = ion_map(mHandle.ionFd(), mHandle.buffer(), mapSize, prot,
                              flags, mapOffset, (unsigned char**)&mMapAddr, &mMapFd);
            if (ret) {
                mMapFd = -1;
                *addr = nullptr;
                err = c2_map_errno<EINVAL>(-ret);
            } else {
                *addr = (uint8_t *)mMapAddr + alignmentBytes;
                mMapAlignmentBytes = alignmentBytes;
                mMapSize = mapSize;
            }
        } else {
            mMapAddr = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
            if (mMapAddr == MAP_FAILED) {
                mMapAddr = *addr = nullptr;
                err = c2_map_errno<EINVAL>(errno);
            } else {
                *addr = (uint8_t *)mMapAddr + alignmentBytes;
                mMapAlignmentBytes = alignmentBytes;
                mMapSize = mapSize;
            }
        }
        return err;
    }

    C2Error unmap(void *addr, size_t size, int *fenceFd) {
        if (addr != (uint8_t *)mMapAddr + mMapAlignmentBytes ||
                size + mMapAlignmentBytes != mMapSize) {
            return C2_BAD_VALUE;
        }
        int err = munmap(mMapAddr, mMapSize);
        if (err != 0) {
            return c2_map_errno<EINVAL>(errno);
        }
        if (fenceFd) {
            *fenceFd = -1;
        }
        return C2_OK;
    }

    ~Impl() {
        if (mMapFd != -1) {
            close(mMapFd);
            mMapFd = -1;
        }

        (void)ion_free(mHandle.ionFd(), mHandle.buffer());
    }

    C2Error status() const {
        return mInit;
    }

    const C2Handle * handle() const {
        return &mHandle;
    }

    int dup() const {
        int fd = -1;
        if (mInit != 0 || ion_share(mHandle.ionFd(), mHandle.buffer(), &fd) != 0) {
            fd = -1;
        }
        return fd;
    }

private:
    C2Error mInit;
    C2HandleIon mHandle;
    int mMapFd; // only one for now
    void *mMapAddr;
    size_t mMapAlignmentBytes;
    size_t mMapSize;
    size_t mCapacity;
};

C2Error C2AllocationIon::map(
    size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
    return mImpl->map(offset, size, usage, fenceFd, addr);
}

C2Error C2AllocationIon::unmap(void *addr, size_t size, int *fenceFd) {
    return mImpl->unmap(addr, size, fenceFd);
}

bool C2AllocationIon::isValid() const {
    return mImpl->status() == C2_OK;
}

C2Error C2AllocationIon::status() const {
    return mImpl->status();
}

bool C2AllocationIon::equals(const std::shared_ptr<C2LinearAllocation> &other) const {
    return other != nullptr &&
        other->handle(); // TODO
}

const C2Handle *C2AllocationIon::handle() const {
    return mImpl->handle();
}

C2AllocationIon::~C2AllocationIon() {
    delete mImpl;
}

C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags)
    : C2LinearAllocation(size),
      mImpl(new Impl(ionFd, size, align, heapMask, flags)) { }

C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd)
    : C2LinearAllocation(size),
      mImpl(new Impl(ionFd, size, shareFd)) { }

int C2AllocationIon::dup() const {
    return mImpl->dup();
}

/* ======================================= ION ALLOCATOR ====================================== */
C2AllocatorIon::C2AllocatorIon() : mInit(C2_OK), mIonFd(ion_open()) {
    if (mIonFd < 0) {
        switch (errno) {
        case ENOENT:    mInit = C2_UNSUPPORTED; break;
        default:        mInit = c2_map_errno<EACCES>(errno); break;
        }
    }
}

C2AllocatorIon::~C2AllocatorIon() {
    if (mInit == C2_OK) {
        ion_close(mIonFd);
    }
}

C2Error C2AllocatorIon::allocateLinearBuffer(
        uint32_t capacity, C2MemoryUsage usage, std::shared_ptr<C2LinearAllocation> *allocation) {
    if (allocation == nullptr) {
        return C2_BAD_VALUE;
    }

    allocation->reset();
    if (mInit != C2_OK) {
        return C2_UNSUPPORTED;
    }

    // get align, heapMask and flags
    //size_t align = 1;
    size_t align = 0;
    unsigned heapMask = ~0;
    unsigned flags = 0;
    //TODO
    (void) usage;
#if 0
    int err = mUsageMapper(usage, capacity, &align, &heapMask, &flags);
    if (err < 0) {
        return c2_map_errno<EINVAL, ENOMEM, EACCES>(-err);
    }
#endif

    std::shared_ptr<C2AllocationIon> alloc
        = std::make_shared<C2AllocationIon>(mIonFd, capacity, align, heapMask, flags);
    C2Error ret = alloc->status();
    if (ret == C2_OK) {
        *allocation = alloc;
    }
    return ret;
}

C2Error C2AllocatorIon::recreateLinearBuffer(
        const C2Handle *handle, std::shared_ptr<C2LinearAllocation> *allocation) {
    *allocation = nullptr;
    if (mInit != C2_OK) {
        return C2_UNSUPPORTED;
    }

    if (!C2HandleIon::isValid(handle)) {
        return C2_BAD_VALUE;
    }

    // TODO: get capacity and validate it
    const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
    std::shared_ptr<C2AllocationIon> alloc
        = std::make_shared<C2AllocationIon>(mIonFd, 0 /* capacity */, h->buffer());
    C2Error ret = alloc->status();
    if (ret == C2_OK) {
        *allocation = alloc;
    }
    return ret;
}

} // namespace android
+2 −696

File changed.

Preview size limit exceeded, changes collapsed.

Loading