Codec2: make C2Allocation API independent from android limitations

- use C2Fence everywhere
- use crop region and address in unmap

Bug: 64121714
Test: unit tests
Change-Id: Ifd0cadfa347194ea390edd204cfc243bdfcbb950
diff --git a/media/libstagefright/codec2/include/C2Buffer.h b/media/libstagefright/codec2/include/C2Buffer.h
index 0095800..4bdd20f 100644
--- a/media/libstagefright/codec2/include/C2Buffer.h
+++ b/media/libstagefright/codec2/include/C2Buffer.h
@@ -746,19 +746,19 @@
     /**
      * Maps a portion of an allocation starting from |offset| with |size| into local process memory.
      * Stores the starting address into |addr|, or NULL if the operation was unsuccessful.
-     * |fenceFd| is a file descriptor referring to an acquire sync fence object. If it is already
-     * safe to access the buffer contents, then -1.
+     * |fence| will contain an acquire sync fence object. If it is already
+     * safe to access the buffer contents, then it will contain an empty (already fired) fence.
      *
-     * \param offset          starting position of the portion to be mapped (this does not have to
+     * \param offset        starting position of the portion to be mapped (this does not have to
      *                      be page aligned)
-     * \param size            size of the portion to be mapped (this does not have to be page
+     * \param size          size of the portion to be mapped (this does not have to be page
      *                      aligned)
-     * \param usage           the desired usage. \todo this must be kSoftwareRead and/or
+     * \param usage         the desired usage. \todo this must be kSoftwareRead and/or
      *                      kSoftwareWrite.
-     * \param fenceFd         a pointer to a file descriptor if an async mapping is requested. If
-     *                      not-null, and acquire fence FD will be stored here on success, or -1
-     *                      on failure. If null, the mapping will be synchronous.
-     * \param addr            a pointer to where the starting address of the mapped portion will be
+     * \param fence         a pointer to a fence object if an async mapping is requested. If
+     *                      not-null, and acquire fence will be stored here on success, or empty
+     *                      fence on failure. If null, the mapping will be synchronous.
+     * \param addr          a pointer to where the starting address of the mapped portion will be
      *                      stored. On failure, nullptr will be stored here.
      *
      * \todo Only one portion can be mapped at the same time - this is true for gralloc, but there
@@ -775,19 +775,19 @@
      * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
      */
     virtual c2_status_t map(
-            size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd /* nullable */,
+            size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence /* nullable */,
             void **addr /* nonnull */) = 0;
 
     /**
      * Unmaps a portion of an allocation at |addr| with |size|. These must be parameters previously
-     * passed to |map|; otherwise, this operation is a no-op.
+     * passed to and returned by |map|; otherwise, this operation is a no-op.
      *
-     * \param addr            starting address of the mapped region
-     * \param size            size of the mapped region
-     * \param fenceFd         a pointer to a file descriptor if an async unmapping is requested. If
-     *                      not-null, a release fence FD will be stored here on success, or -1
+     * \param addr          starting address of the mapped region
+     * \param size          size of the mapped region
+     * \param fence         a pointer to a fence object if an async unmapping is requested. If
+     *                      not-null, a release fence will be stored here on success, or empty fence
      *                      on failure. This fence signals when the original allocation contains
-     *                      any changes that happened to the mapped region. If null, the unmapping
+     *                      all changes that happened to the mapped region. If null, the unmapping
      *                      will be synchronous.
      *
      * \retval C2_OK        the operation was successful
@@ -798,7 +798,7 @@
      * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
      * \retval C2_REFUSED   no permission to unmap the portion (unexpected - system)
      */
-    virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd /* nullable */) = 0;
+    virtual c2_status_t unmap(void *addr, size_t size, C2Fence *fence /* nullable */) = 0;
 
     /**
      * Returns the allocator ID for this allocation. This is useful to put the handle into context.
@@ -1510,6 +1510,15 @@
         BIG_END,    // BIG_ENDIAN is a reserved macro
     } endianness; ///< endianness of the samples
 
+    /**
+     * The following two fields define the relation between multiple planes. If multiple planes are
+     * interleaved, they share a root plane (whichever plane's start address is the lowest), and
+     * |offset| is the offset of this plane inside the root plane (in bytes). |rootIx| is the index
+     * of the root plane. If a plane is independent, rootIx is its index and offset is 0.
+     */
+    uint32_t rootIx; ///< index of the root plane
+    uint32_t offset; ///< offset of this plane inside of the root plane
+
     inline constexpr ssize_t minOffset(uint32_t width, uint32_t height) const {
         ssize_t offs = 0;
         if (width > 0 && colInc < 0) {
@@ -1544,7 +1553,8 @@
     };
 
     type_t type;                    // image type
-    uint32_t numPlanes;             // number of planes
+    uint32_t numPlanes;             // number of component planes
+    uint32_t rootPlanes;            // number of layout planes (root planes)
 
     enum plane_index_t : uint32_t {
         PLANE_Y = 0,
@@ -1696,22 +1706,19 @@
      * Maps a rectangular section (as defined by |rect|) of a 2D allocation into local process
      * memory for flexible access. On success, it fills out |layout| with the plane specifications
      * and fills the |addr| array with pointers to the first byte of the top-left pixel of each
-     * plane used. Otherwise, it leaves |layout| and |addr| untouched. |fenceFd| is a file
-     * descriptor referring to an acquire sync fence object. If it is already safe to access the
-     * buffer contents, then -1.
+     * plane used. Otherwise, it leaves |layout| and |addr| untouched. |fence| will contain
+     * an acquire sync fence object. If it is already safe to access the
+     * buffer contents, then it will be an empty (already fired) fence.
      *
-     * Safe regions for the pointer addresses returned can be gotten via C2LayoutInfo.minOffse()/
+     * Safe regions for the pointer addresses returned can be gotten via C2LayoutInfo.minOffset()/
      * maxOffset().
      *
-     * \note Only one portion of the graphic allocation can be mapped at the same time. (This is
-     * from gralloc1 limitation.)
-     *
      * \param rect          section to be mapped (this does not have to be aligned)
      * \param usage         the desired usage. \todo this must be kSoftwareRead and/or
      *                      kSoftwareWrite.
-     * \param fenceFd       a pointer to a file descriptor if an async mapping is requested. If
-     *                      not-null, and acquire fence FD will be stored here on success, or -1
-     *                      on failure. If null, the mapping will be synchronous.
+     * \param fence         a pointer to a fence object if an async mapping is requested. If
+     *                      not-null, and acquire fence will be stored here on success, or empty
+     *                      fence on failure. If null, the mapping will be synchronous.
      * \param layout        a pointer to where the mapped planes' descriptors will be
      *                      stored. On failure, nullptr will be stored here.
      * \param addr          pointer to an array with at least C2PlanarLayout::MAX_NUM_PLANES
@@ -1719,7 +1726,8 @@
      *
      * \retval C2_OK        the operation was successful
      * \retval C2_REFUSED   no permission to map the section
-     * \retval C2_DUPLICATE there is already a mapped region (caller error)
+     * \retval C2_DUPLICATE there is already a mapped region and this allocation cannot support
+     *                      multi-mapping (caller error)
      * \retval C2_TIMED_OUT the operation timed out
      * \retval C2_NO_MEMORY not enough memory to complete the operation
      * \retval C2_BAD_VALUE the parameters (rect) are invalid or outside the allocation, or the
@@ -1728,25 +1736,30 @@
 
      */
     virtual c2_status_t map(
-            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+            C2Rect rect, C2MemoryUsage usage, C2Fence *fence,
             C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) = 0;
 
     /**
-     * Unmaps the last mapped rectangular section.
+     * Unmaps a section of an allocation at |addr| with |rect|. These must be parameters previously
+     * passed to and returned by |map|; otherwise, this operation is a no-op.
      *
-     * \param fenceFd         a pointer to a file descriptor if an async unmapping is requested. If
-     *                      not-null, a release fence FD will be stored here on success, or -1
+     * \param addr          pointer to an array with at least C2PlanarLayout::MAX_NUM_PLANES
+     *                      elements containing the starting addresses of the mapped layers
+     * \param rect          boundaries of the mapped section
+     * \param fence         a pointer to a fence object if an async unmapping is requested. If
+     *                      not-null, a release fence will be stored here on success, or empty fence
      *                      on failure. This fence signals when the original allocation contains
-     *                      any changes that happened to the mapped section. If null, the unmapping
+     *                      all changes that happened to the mapped section. If null, the unmapping
      *                      will be synchronous.
      *
      * \retval C2_OK        the operation was successful
      * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_NOT_FOUND there is no mapped region (caller error)
+     * \retval C2_NOT_FOUND there is no such mapped region (caller error)
      * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
      * \retval C2_REFUSED   no permission to unmap the section (unexpected - system)
      */
-    virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) = 0;
+    virtual c2_status_t unmap(
+            uint8_t **addr /* nonnull */, C2Rect rect, C2Fence *fence /* nullable */) = 0;
 
     /**
      * Returns the allocator ID for this allocation. This is useful to put the handle into context.
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
index f0e57e2..038be48 100644
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -312,13 +312,15 @@
             addr[C2PlanarLayout::PLANE_V] = nullptr;
             FAIL() << "C2GraphicAllocation::map() failed: " << err;
         }
+        mMappedRect = rect;
+        memcpy(mAddrGraphic, addr, sizeof(uint8_t*) * C2PlanarLayout::MAX_NUM_PLANES);
     }
 
     void unmapGraphic() {
         ASSERT_TRUE(mGraphicAllocation);
 
         // TODO: fence
-        ASSERT_EQ(C2_OK, mGraphicAllocation->unmap(nullptr));
+        ASSERT_EQ(C2_OK, mGraphicAllocation->unmap(mAddrGraphic, mMappedRect, nullptr));
     }
 
     std::shared_ptr<C2BlockPool> makeGraphicBlockPool() {
@@ -330,6 +332,8 @@
     std::shared_ptr<C2LinearAllocation> mLinearAllocation;
     size_t mSize;
     void *mAddr;
+    C2Rect mMappedRect;
+    uint8_t* mAddrGraphic[C2PlanarLayout::MAX_NUM_PLANES];
 
     std::shared_ptr<C2Allocator> mGraphicAllocator;
     std::shared_ptr<C2GraphicAllocation> mGraphicAllocation;
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
index b255eec..3d7fc8d 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
@@ -213,9 +213,10 @@
     virtual ~C2AllocationGralloc() override;
 
     virtual c2_status_t map(
-            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+            C2Rect rect, C2MemoryUsage usage, C2Fence *fence,
             C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
-    virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) 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;
@@ -263,16 +264,18 @@
         return;
     }
     if (mLocked) {
-        unmap(nullptr);
+        // implementation ignores addresss and rect
+        uint8_t* addr[C2PlanarLayout::MAX_NUM_PLANES] = {};
+        unmap(addr, C2Rect(), nullptr);
     }
     mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer));
 }
 
 c2_status_t C2AllocationGralloc::map(
-        C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+        C2Rect rect, C2MemoryUsage usage, C2Fence *fence,
         C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
     // TODO
-    (void) fenceFd;
+    (void) fence;
     (void) usage;
 
     if (mBuffer && mLocked) {
@@ -326,6 +329,7 @@
             addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
             layout->type = C2PlanarLayout::TYPE_YUV;
             layout->numPlanes = 3;
+            layout->rootPlanes = 3;
             layout->planes[C2PlanarLayout::PLANE_Y] = {
                 C2PlaneInfo::CHANNEL_Y,         // channel
                 1,                              // colInc
@@ -336,6 +340,8 @@
                 8,                              // bitDepth
                 0,                              // rightShift
                 C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
             };
             layout->planes[C2PlanarLayout::PLANE_U] = {
                 C2PlaneInfo::CHANNEL_CB,          // channel
@@ -347,6 +353,8 @@
                 8,                                // bitDepth
                 0,                                // rightShift
                 C2PlaneInfo::NATIVE,              // endianness
+                C2PlanarLayout::PLANE_U,          // rootIx
+                0,                                // offset
             };
             layout->planes[C2PlanarLayout::PLANE_V] = {
                 C2PlaneInfo::CHANNEL_CR,          // channel
@@ -358,7 +366,20 @@
                 8,                                // bitDepth
                 0,                                // rightShift
                 C2PlaneInfo::NATIVE,              // endianness
+                C2PlanarLayout::PLANE_V,          // rootIx
+                0,                                // offset
             };
+            // handle interleaved formats
+            intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
+            if (uvOffset > 0 && uvOffset < (intptr_t)ycbcrLayout.chromaStep) {
+                layout->rootPlanes = 2;
+                layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
+                layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
+            } else if (uvOffset < 0 && uvOffset > -(intptr_t)ycbcrLayout.chromaStep) {
+                layout->rootPlanes = 2;
+                layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
+                layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
+            }
             break;
         }
 
@@ -387,6 +408,7 @@
             addr[C2PlanarLayout::PLANE_B] = (uint8_t *)pointer + 2;
             layout->type = C2PlanarLayout::TYPE_RGB;
             layout->numPlanes = 3;
+            layout->rootPlanes = 1;
             layout->planes[C2PlanarLayout::PLANE_R] = {
                 C2PlaneInfo::CHANNEL_R,         // channel
                 4,                              // colInc
@@ -397,6 +419,8 @@
                 8,                              // bitDepth
                 0,                              // rightShift
                 C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_R,        // rootIx
+                0,                              // offset
             };
             layout->planes[C2PlanarLayout::PLANE_G] = {
                 C2PlaneInfo::CHANNEL_G,         // channel
@@ -408,6 +432,8 @@
                 8,                              // bitDepth
                 0,                              // rightShift
                 C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_R,        // rootIx
+                1,                              // offset
             };
             layout->planes[C2PlanarLayout::PLANE_B] = {
                 C2PlaneInfo::CHANNEL_B,         // channel
@@ -419,6 +445,8 @@
                 8,                              // bitDepth
                 0,                              // rightShift
                 C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_R,        // rootIx
+                2,                              // offset
             };
             break;
         }
@@ -431,14 +459,17 @@
     return C2_OK;
 }
 
-c2_status_t C2AllocationGralloc::unmap(C2Fence *fenceFd /* nullable */) {
-    // TODO: fence
+c2_status_t C2AllocationGralloc::unmap(
+        uint8_t **addr, C2Rect rect, C2Fence *fence /* nullable */) {
+    // TODO: check addr and size, use fence
+    (void)addr;
+    (void)rect;
     c2_status_t err = C2_OK;
     mMapper->unlock(
             const_cast<native_handle_t *>(mBuffer),
-            [&err, &fenceFd](const auto &maperr, const auto &releaseFence) {
+            [&err, &fence](const auto &maperr, const auto &releaseFence) {
                 // TODO
-                (void) fenceFd;
+                (void) fence;
                 (void) releaseFence;
                 err = maperr2error(maperr);
                 if (err == C2_OK) {
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
index a9613e4..6b0cffb 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
@@ -117,9 +117,9 @@
 public:
     /* Interface methods */
     virtual c2_status_t map(
-        size_t offset, size_t size, C2MemoryUsage usage, int *fence,
+        size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence,
         void **addr /* nonnull */) override;
-    virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd) override;
+    virtual c2_status_t unmap(void *addr, size_t size, C2Fence *fenceFd) override;
     virtual ~C2AllocationIon() override;
     virtual const C2Handle *handle() const override;
     virtual id_t getAllocatorId() const override;
@@ -218,8 +218,8 @@
         return new Impl(ionFd, size, bufferFd, buffer, id, ret);
     }
 
-    c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
-        (void)fenceFd; // TODO: wait for fence
+    c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
+        (void)fence; // TODO: wait for fence
         *addr = nullptr;
         if (mMapSize > 0) {
             // TODO: technically we should return DUPLICATE here, but our block views don't
@@ -272,7 +272,7 @@
         return err;
     }
 
-    c2_status_t unmap(void *addr, size_t size, int *fenceFd) {
+    c2_status_t unmap(void *addr, size_t size, C2Fence *fence) {
         if (mMapFd < 0 || mMapSize == 0) {
             return C2_NOT_FOUND;
         }
@@ -284,8 +284,8 @@
         if (err != 0) {
             return c2_map_errno<EINVAL>(errno);
         }
-        if (fenceFd) {
-            *fenceFd = -1; // not using fences
+        if (fence) {
+            *fence = C2Fence(); // not using fences
         }
         mMapSize = 0;
         return C2_OK;
@@ -334,12 +334,12 @@
 };
 
 c2_status_t C2AllocationIon::map(
-    size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
-    return mImpl->map(offset, size, usage, fenceFd, addr);
+    size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
+    return mImpl->map(offset, size, usage, fence, addr);
 }
 
-c2_status_t C2AllocationIon::unmap(void *addr, size_t size, int *fenceFd) {
-    return mImpl->unmap(addr, size, fenceFd);
+c2_status_t C2AllocationIon::unmap(void *addr, size_t size, C2Fence *fence) {
+    return mImpl->unmap(addr, size, fence);
 }
 
 c2_status_t C2AllocationIon::status() const {
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index 47fdca1..dc765f5 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -414,6 +414,7 @@
             if (mError != C2_OK) {
                 memset(&mLayout, 0, sizeof(mLayout));
                 memset(mData, 0, sizeof(mData));
+                memset(mOffsetData, 0, sizeof(mData));
             } else {
                 // TODO: validate plane layout and
                 // adjust data pointers to the crop region's top left corner.
@@ -424,14 +425,16 @@
                     if (crop.left % colSampling || crop.right() % colSampling
                             || crop.top % rowSampling || crop.bottom() % rowSampling) {
                         // cannot calculate data pointer
-                        mImpl->getAllocation()->unmap(nullptr);
+                        mImpl->getAllocation()->unmap(mData, crop, nullptr);
                         memset(&mLayout, 0, sizeof(mLayout));
                         memset(mData, 0, sizeof(mData));
+                        memset(mOffsetData, 0, sizeof(mData));
                         mError = C2_BAD_VALUE;
                         return;
                     }
-                    mData[planeIx] += (ssize_t)crop.left * mLayout.planes[planeIx].colInc
-                            + (ssize_t)crop.top * mLayout.planes[planeIx].rowInc;
+                    mOffsetData[planeIx] =
+                        mData[planeIx] + (ssize_t)crop.left * mLayout.planes[planeIx].colInc
+                                + (ssize_t)crop.top * mLayout.planes[planeIx].rowInc;
                 }
             }
         }
@@ -441,12 +444,13 @@
             // CHECK(error != C2_OK);
             memset(&mLayout, 0, sizeof(mLayout));
             memset(mData, 0, sizeof(mData));
+            memset(mOffsetData, 0, sizeof(mData));
         }
 
     public:
         ~Mapped() {
             if (mData[0] != nullptr) {
-                mImpl->getAllocation()->unmap(nullptr);
+                mImpl->getAllocation()->unmap(mData, mImpl->crop(), nullptr);
             }
         }
 
@@ -454,7 +458,7 @@
         c2_status_t error() const { return mError; }
 
         /** returns data pointer */
-        uint8_t *const *data() const { return mData; }
+        uint8_t *const *data() const { return mOffsetData; }
 
         /** returns the plane layout */
         C2PlanarLayout layout() const { return mLayout; }
@@ -467,6 +471,7 @@
         bool mWritable;
         c2_status_t mError;
         uint8_t *mData[C2PlanarLayout::MAX_NUM_PLANES];
+        uint8_t *mOffsetData[C2PlanarLayout::MAX_NUM_PLANES];
         C2PlanarLayout mLayout;
     };