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

Commit 8b448819 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "media.c2 aidl: Add AHardwareBuffer based C2Allocator" into main

parents 74cc2a07 1a67c9dc
Loading
Loading
Loading
Loading
+443 −1
Original line number Diff line number Diff line
@@ -238,6 +238,130 @@ public:
    }
};

class C2HandleAhwb : public C2Handle {
private:
    // TODO: remove extradata and use AHardwareBuffer directly.
    struct ExtraData {
        uint32_t width;
        uint32_t height;
        uint32_t format;
        uint32_t usage_lo;
        uint32_t usage_hi;
        uint32_t stride;
        uint32_t origId_lo;
        uint32_t origId_hi;
        uint32_t magic;
    };

    enum {
        NUM_INTS = sizeof(ExtraData) / sizeof(int),
    };
    const static uint32_t MAGIC = '\xc2hw\x00';

    static
    const ExtraData* GetExtraData(const C2Handle *const handle) {
        if (handle == nullptr
                || native_handle_is_invalid(handle)
                || handle->numInts < NUM_INTS) {
            return nullptr;
        }
        return reinterpret_cast<const ExtraData*>(
                &handle->data[handle->numFds + handle->numInts - NUM_INTS]);
    }

    static
    ExtraData *GetExtraData(C2Handle *const handle) {
        return const_cast<ExtraData *>(GetExtraData(const_cast<const C2Handle *const>(handle)));
    }

public:
    void getOrigId(uint64_t *origId) const {
        const ExtraData *ed = GetExtraData(this);
        *origId = unsigned(ed->origId_lo) | uint64_t(unsigned(ed->origId_hi)) << 32;
    }

    static bool IsValid(const C2Handle *const o) {
        if (o == nullptr) { // null handle is always valid
            return true;
        }
        const ExtraData *xd = GetExtraData(o);
        // we cannot validate width/height/format/usage without accessing gralloc driver
        return xd != nullptr && xd->magic == MAGIC;
    }

    static C2HandleAhwb* WrapAndMoveNativeHandle(
            const native_handle_t *const handle,
            uint32_t width, uint32_t height, uint32_t format, uint64_t usage,
            uint32_t stride, uint64_t origId) {
        //CHECK(handle != nullptr);
        if (native_handle_is_invalid(handle) || handle->numInts >
                int((INT_MAX - handle->version) / sizeof(int)) - NUM_INTS - handle->numFds) {
            return nullptr;
        }
        ExtraData xd = {
            width, height, format, uint32_t(usage & 0xFFFFFFFF), uint32_t(usage >> 32),
            stride,  uint32_t(origId & 0xFFFFFFFF), uint32_t(origId >> 32), MAGIC
        };
        native_handle_t *res = native_handle_create(handle->numFds, handle->numInts + NUM_INTS);
        if (res != nullptr) {
            memcpy(&res->data, &handle->data, sizeof(int) * (handle->numFds + handle->numInts));
            *GetExtraData(res) = xd;
        }
        return reinterpret_cast<C2HandleAhwb *>(res);
    }

    static C2HandleAhwb* WrapNativeHandle(
            const native_handle_t *const handle,
            uint32_t width, uint32_t height, uint32_t format, uint64_t usage,
            uint32_t stride, uint64_t origId) {
        if (handle == nullptr) {
            return nullptr;
        }
        native_handle_t *clone = native_handle_clone(handle);
        if (clone == nullptr) {
            return nullptr;
        }
        C2HandleAhwb *res = WrapAndMoveNativeHandle(
                clone, width, height, format, usage, stride, origId);
        if (res == nullptr) {
            native_handle_close(clone);
        }
        native_handle_delete(clone);
        return res;
    }

    static native_handle_t* UnwrapNativeHandle(
            const C2Handle *const handle) {
        const ExtraData *xd = GetExtraData(handle);
        if (xd == nullptr || xd->magic != MAGIC) {
            return nullptr;
        }
        native_handle_t *res = native_handle_create(handle->numFds, handle->numInts - NUM_INTS);
        if (res != nullptr) {
            memcpy(&res->data, &handle->data, sizeof(int) * (res->numFds + res->numInts));
        }
        return res;
    }

    static const C2HandleAhwb* Import(
            const C2Handle *const handle,
            uint32_t *width, uint32_t *height, uint32_t *format,
            uint64_t *usage, uint32_t *stride,
            uint64_t *origId) {
        const ExtraData *xd = GetExtraData(handle);
        if (xd == nullptr) {
            return nullptr;
        }
        *width = xd->width;
        *height = xd->height;
        *format = xd->format;
        *usage = xd->usage_lo | (uint64_t(xd->usage_hi) << 32);
        *stride = xd->stride;
        *origId = xd->origId_lo | (uint64_t(xd->origId_hi) << 32);
        return reinterpret_cast<const C2HandleAhwb *>(handle);
    }
};

static
c2_status_t Gralloc4Mapper_lock(native_handle_t *handle, uint64_t usage, const Rect& bounds,
        C2PlanarLayout *layout, uint8_t **addr) {
@@ -785,6 +909,7 @@ bool MigrateNativeCodec2GrallocHandle(
}



class C2AllocationGralloc : public C2GraphicAllocation {
public:
    virtual ~C2AllocationGralloc() override;
@@ -851,7 +976,7 @@ C2AllocationGralloc::C2AllocationGralloc(

C2AllocationGralloc::~C2AllocationGralloc() {
    if (mBuffer && mLocked) {
        // implementation ignores addresss and rect
        // implementation ignores address and rect
        uint8_t* addr[C2PlanarLayout::MAX_NUM_PLANES] = {};
        unmap(addr, C2Rect(), nullptr);
    }
@@ -1112,4 +1237,321 @@ bool C2AllocatorGralloc::CheckHandle(const C2Handle* const o) {
    return C2HandleGralloc::IsValid(o);
}


native_handle_t *UnwrapNativeCodec2AhwbHandle(const C2Handle *const handle) {
    return C2HandleAhwb::UnwrapNativeHandle(handle);
}

C2Handle *WrapNativeCodec2AhwbHandle(
        const native_handle_t *const handle,
        uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride,
        uint64_t origId) {
    return C2HandleAhwb::WrapNativeHandle(handle, width, height, format, usage, stride,
                                          origId);
}

class C2AllocationAhwb : public C2GraphicAllocation {
public:
    virtual ~C2AllocationAhwb() override;

    virtual c2_status_t map(
            C2Rect c2Rect, C2MemoryUsage usage, C2Fence *fence,
            C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
    virtual c2_status_t unmap(
            uint8_t **addr /* nonnull */, C2Rect rect, C2Fence *fence /* nullable */) override;
    virtual C2Allocator::id_t getAllocatorId() const override { return mAllocatorId; }
    virtual const C2Handle *handle() const override { return mLockedHandle ? : mHandle; }
    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override;

    // internal methods
    // |handle| will be moved.

    C2AllocationAhwb(
              uint32_t width, uint32_t height,
              uint32_t format, uint32_t layerCount,
              uint64_t grallocUsage, uint32_t stride,
              const C2HandleAhwb *const handle,
              C2Allocator::id_t allocatorId);
    int dup() const;
    c2_status_t status() const;

private:
    const uint32_t mWidth;
    const uint32_t mHeight;
    const uint32_t mFormat;
    const uint32_t mLayerCount;
    const uint64_t mGrallocUsage;
    const uint32_t mStride;
    const native_handle_t *mRawHandle;
    const C2HandleAhwb *mHandle;
    buffer_handle_t mBuffer;
    const C2HandleAhwb *mLockedHandle;
    bool mLocked;
    C2Allocator::id_t mAllocatorId;
    std::mutex mMappedLock;
};

C2AllocationAhwb::C2AllocationAhwb(
          uint32_t width, uint32_t height,
          uint32_t format, uint32_t layerCount,
          uint64_t grallocUsage, uint32_t stride,
          const C2HandleAhwb *const handle,
          C2Allocator::id_t allocatorId)
    : C2GraphicAllocation(width, height),
      mWidth(width),
      mHeight(height),
      mFormat(format),
      mLayerCount(layerCount),
      mGrallocUsage(grallocUsage),
      mStride(stride),
      mRawHandle(C2HandleAhwb::UnwrapNativeHandle(handle)),
      mHandle(handle),
      mBuffer(nullptr),
      mLockedHandle(nullptr),
      mLocked(false),
      mAllocatorId(allocatorId) {
}

C2AllocationAhwb::~C2AllocationAhwb() {
    if (mBuffer && mLocked) {
        // implementation ignores address and rect
        uint8_t* addr[C2PlanarLayout::MAX_NUM_PLANES] = {};
        unmap(addr, C2Rect(), nullptr);
    }
    if (mBuffer) {
        status_t err = GraphicBufferMapper::get().freeBuffer(mBuffer);
        if (err) {
            ALOGE("failed transaction: freeBuffer");
        }
    }
    if (mRawHandle) {
        native_handle_close(
                const_cast<native_handle_t *>(
                        reinterpret_cast<const native_handle_t *>(mRawHandle)));
        native_handle_delete(
                const_cast<native_handle_t *>(
                        reinterpret_cast<const native_handle_t *>(mRawHandle)));
    }
    if (mHandle) {
        native_handle_delete(
                const_cast<native_handle_t *>(reinterpret_cast<const native_handle_t *>(mHandle)));
    }
    if (mLockedHandle) {
        native_handle_delete(
                const_cast<native_handle_t *>(
                        reinterpret_cast<const native_handle_t *>(mLockedHandle)));
    }
}

c2_status_t C2AllocationAhwb::map(
        C2Rect c2Rect, C2MemoryUsage usage, C2Fence *fence,
        C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
    const Rect rect{(int32_t)c2Rect.left, (int32_t)c2Rect.top,
                    (int32_t)(c2Rect.left + c2Rect.width) /* right */,
                    (int32_t)(c2Rect.top + c2Rect.height) /* bottom */};

    uint64_t grallocUsage = static_cast<C2AndroidMemoryUsage>(usage).asGrallocUsage();
    ALOGV("mapping buffer with usage %#llx => %#llx",
          (long long)usage.expected, (long long)grallocUsage);

    // TODO
    (void)fence;

    std::lock_guard<std::mutex> lock(mMappedLock);
    if (mBuffer && mLocked) {
        ALOGD("already mapped");
        return C2_DUPLICATE;
    }
    if (!layout || !addr) {
        ALOGD("wrong param");
        return C2_BAD_VALUE;
    }

    if (!mBuffer) {
        // TODO: libui/libgui dependency removal (b/214400477)
        status_t err = GraphicBufferMapper::get().importBuffer(
                            mRawHandle, mWidth, mHeight, mLayerCount,
                            mFormat, mGrallocUsage, mStride, &mBuffer);
        if (err) {
            ALOGE("failed transaction: importBuffer");
            return C2_CORRUPTED;
        }
        if (mBuffer == nullptr) {
            ALOGD("importBuffer returned null buffer");
            return C2_CORRUPTED;
        }
        uint64_t origId = 0;
        if (mHandle) {
            mHandle->getOrigId(&origId);
        }

        mLockedHandle = C2HandleAhwb::WrapAndMoveNativeHandle(
                mBuffer, mWidth, mHeight, mFormat, mGrallocUsage,
                mStride, origId);
    }

    c2_status_t ret = PopulatePlaneLayout(
            mBuffer, rect, mFormat, grallocUsage, mStride, layout, addr);
    if (ret != C2_OK) {
        return ret;
    }
    mLocked = true;

    HandleInterleavedPlanes(layout, addr);

    ALOGV("C2AllocationGralloc::map: layout: type=%d numPlanes=%d rootPlanes=%d",
          layout->type, layout->numPlanes, layout->rootPlanes);
    for (int i = 0; i < layout->numPlanes; ++i) {
        const C2PlaneInfo &plane = layout->planes[i];
        ALOGV("C2AllocationGralloc::map: plane[%d]: colInc=%d rowInc=%d rootIx=%u offset=%u",
              i, plane.colInc, plane.rowInc, plane.rootIx, plane.offset);
    }

    return C2_OK;
}

c2_status_t C2AllocationAhwb::unmap(
        uint8_t **addr, C2Rect rect, C2Fence *fence /* nullable */) {
    // TODO: check addr and size, use fence
    (void)addr;
    (void)rect;
    (void)fence;

    std::lock_guard<std::mutex> lock(mMappedLock);
    // TODO: fence
    status_t err = GraphicBufferMapper::get().unlock(mBuffer);
    if (err) {
        ALOGE("failed transaction: unlock");
        return C2_CORRUPTED;
    }

    mLocked = false;
    return C2_OK;
}

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

/* ===================================== AHARDWAREBUFFER ALLOCATOR ============================= */
class C2AllocatorAhwb::Impl {
public:
    Impl(id_t id);

    id_t getId() const {
        return mTraits->id;
    }

    C2String getName() const {
        return mTraits->name;
    }

    std::shared_ptr<const C2Allocator::Traits> getTraits() const {
        return mTraits;
    }

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

    c2_status_t priorGraphicAllocation(
            const C2Handle *handle,
            std::shared_ptr<C2GraphicAllocation> *allocation);

    c2_status_t status() const { return mInit; }

private:
    std::shared_ptr<C2Allocator::Traits> mTraits;
    c2_status_t mInit;
};

void _UnwrapNativeCodec2AhwbMetadata(
        const C2Handle *const handle,
        uint32_t *width, uint32_t *height, uint32_t *format,uint64_t *usage, uint32_t *stride,
        uint64_t *origId) {
    (void)C2HandleAhwb::Import(handle, width, height, format, usage, stride, origId);
}

C2AllocatorAhwb::Impl::Impl(id_t id)
    : mInit(C2_OK) {
    // TODO: get this from allocator
    C2MemoryUsage minUsage = { 0, 0 }, maxUsage = { ~(uint64_t)0, ~(uint64_t)0 };
    Traits traits = { "android.allocator.ahwb", id, C2Allocator::GRAPHIC, minUsage, maxUsage };
    mTraits = std::make_shared<C2Allocator::Traits>(traits);
}

c2_status_t C2AllocatorAhwb::Impl::newGraphicAllocation(
        uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
        std::shared_ptr<C2GraphicAllocation> *allocation) {
    // TODO: for client side usage
    // HAL side Ahwb allocation should be done via IGBA currently.
    (void) width;
    (void) height;
    (void) format;
    (void) usage;
    (void) allocation;
    return C2_OMITTED;
}

c2_status_t C2AllocatorAhwb::Impl::priorGraphicAllocation(
        const C2Handle *handle,
        std::shared_ptr<C2GraphicAllocation> *allocation) {

    uint32_t width;
    uint32_t height;
    uint32_t format;
    uint32_t layerCount = 1;
    uint64_t grallocUsage;
    uint32_t stride;
    uint64_t origId;

    const C2HandleAhwb *ahwbHandle = C2HandleAhwb::Import(
            handle, &width, &height, &format, &grallocUsage, &stride, &origId);
    if (ahwbHandle == nullptr) {
        return C2_BAD_VALUE;
    }

    allocation->reset(new C2AllocationAhwb(
            width, height, format, layerCount,
            grallocUsage, stride, ahwbHandle, mTraits->id));
    return C2_OK;
}

C2AllocatorAhwb::C2AllocatorAhwb(id_t id)
        : mImpl(new Impl(id)) {}

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

C2Allocator::id_t C2AllocatorAhwb::getId() const {
    return mImpl->getId();
}

C2String C2AllocatorAhwb::getName() const {
    return mImpl->getName();
}

std::shared_ptr<const C2Allocator::Traits> C2AllocatorAhwb::getTraits() const {
    return mImpl->getTraits();
}

c2_status_t C2AllocatorAhwb::newGraphicAllocation(
        uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
        std::shared_ptr<C2GraphicAllocation> *allocation) {
    return mImpl->newGraphicAllocation(width, height, format, usage, allocation);
}

c2_status_t C2AllocatorAhwb::priorGraphicAllocation(
        const C2Handle *handle,
        std::shared_ptr<C2GraphicAllocation> *allocation) {
    return mImpl->priorGraphicAllocation(handle, allocation);
}

c2_status_t C2AllocatorAhwb::status() const {
    return mImpl->status();
}

// static
bool C2AllocatorAhwb::CheckHandle(const C2Handle* const o) {
    return C2HandleAhwb::IsValid(o);
}
} // namespace android
+77 −0
Original line number Diff line number Diff line
@@ -63,6 +63,36 @@ void _UnwrapNativeCodec2GrallocMetadata(
        uint32_t *width, uint32_t *height, uint32_t *format, uint64_t *usage, uint32_t *stride,
        uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot);

/**
 * Unwrap the native handle from a Codec2 handle allocated by C2AllocatorAhwb.
 *
 * @param handle a handle allocated by C2AllocatorAhwb. This includes handles returned for a
 * graphic block allocation handle based on an AHardwareBuffer.
 *
 * @return a new NON-OWNING native handle that must be deleted using native_handle_delete.
 */
native_handle_t *UnwrapNativeCodec2AhwbHandle(const C2Handle *const handle);

/**
 * Wrap the gralloc handle and metadata based on AHardwareBuffer into Codec2 handle
 * recognized by C2AllocatorAhwb.
 *
 * @return a new NON-OWNING C2Handle that must be closed and deleted using native_handle_close and
 * native_handle_delete.
 */
C2Handle *WrapNativeCodec2AhwbHandle(
        const native_handle_t *const handle,
        uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride,
        uint64_t origId);

/**
 * \todo Get this from the buffer
 */
void _UnwrapNativeCodec2AhwbMetadata(
        const C2Handle *const handle,
        uint32_t *width, uint32_t *height, uint32_t *format, uint64_t *usage, uint32_t *stride,
        uint64_t *origId);

class C2AllocatorGralloc : public C2Allocator {
public:
    virtual id_t getId() const override;
@@ -97,6 +127,53 @@ private:
    Impl *mImpl;
};

/**
 * C2Allocator for AHardwareBuffer based allocation.
 *
 * C2Allocator interface is based on C2Handle, which is actually wrapped
 * native_handle_t. This is based on extracted handle from AHardwareBuffer.
 * Trying to recover an AHardwareBuffer from C2GraphicAllocation created by the
 * allocator will creates a new AHardwareBuffer with a different unique Id, but
 * it is identical and will use same memory by the handle.
 *
 * C2GraphicAllocation does not have the original AHardwareBuffer. But
 * C2GraphicBlock and C2ConstGraphicBlock has the original AHardwareBuffer,
 * which can be sent to the other processes.
 *
 * TODO: Bundle AHardwareBuffer for C2GraphicAllocation.
 * TODO: Add support for C2AllocatorBlob.
 */
class C2AllocatorAhwb : public C2Allocator {
public:
    virtual id_t getId() const override;

    virtual C2String getName() const override;

    virtual std::shared_ptr<const Traits> getTraits() const override;

    virtual c2_status_t newGraphicAllocation(
            uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
            std::shared_ptr<C2GraphicAllocation> *allocation) override;

    virtual c2_status_t priorGraphicAllocation(
            const C2Handle *handle,
            std::shared_ptr<C2GraphicAllocation> *allocation) override;

    C2AllocatorAhwb(id_t id);

    c2_status_t status() const;

    virtual ~C2AllocatorAhwb() override;

    virtual bool checkHandle(const C2Handle* const o) const override { return CheckHandle(o); }

    static bool CheckHandle(const C2Handle* const o);

private:
    class Impl;
    Impl *mImpl;
};

} // namespace android

#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_