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