Merge "gralloc: add flush and reread for locked buffers"
diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal
index 89d4128..03dfef1 100644
--- a/graphics/mapper/4.0/IMapper.hal
+++ b/graphics/mapper/4.0/IMapper.hal
@@ -266,6 +266,50 @@
unlock(pointer buffer) generates (Error error, handle releaseFence);
/**
+ * Flushes the contents of a locked buffer.
+ *
+ * This function flushes the CPUs caches for the range of all the buffer's
+ * planes and metadata. This should behave similarly to unlock() except the
+ * buffer should remain mapped to the CPU.
+ *
+ * The client is still responsible for calling unlock() when it is done
+ * with all CPU accesses to the buffer.
+ *
+ * If non-CPU blocks are simultaneously writing the buffer, the locked
+ * copy should still be flushed but what happens is undefined except that
+ * it should not cause any crashes.
+ *
+ * @param buffer Buffer to flush.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or not locked.
+ * @return releaseFence Handle containing a file descriptor referring to a
+ * sync fence object. The sync fence object will be signaled when the
+ * mapper has completed any pending work. @p releaseFence may be an
+ * empty fence.
+ */
+ flushLockedBuffer(pointer buffer) generates (Error error, handle releaseFence);
+
+ /**
+ * Rereads the contents of a locked buffer.
+ *
+ * This should fetch the most recent copy of the locked buffer.
+ *
+ * It may reread locked copies of the buffer in other processes.
+ *
+ * The client is still responsible for calling unlock() when it is done
+ * with all CPU accesses to the buffer.
+ *
+ * @param buffer Buffer to reread.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or not locked.
+ * - `NO_RESOURCES` if the buffer cannot be reread at this time. Note
+ * that rereading may succeed at a later time.
+ */
+ rereadLockedBuffer(pointer buffer) generates(Error error);
+
+ /**
* Test whether the given BufferDescriptorInfo is allocatable.
*
* If this function returns true, it means that a buffer with the given
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
index 1dafd4a..c317ed2 100644
--- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -246,6 +246,34 @@
return releaseFence;
}
+int Gralloc::flushLockedBuffer(const native_handle_t* bufferHandle) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ int releaseFence = -1;
+ mMapper->flushLockedBuffer(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to flush locked buffer " << buffer;
+
+ auto fenceHandle = tmpReleaseFence.getNativeHandle();
+ if (fenceHandle) {
+ ASSERT_EQ(0, fenceHandle->numInts) << "invalid fence handle " << fenceHandle;
+ if (fenceHandle->numFds == 1) {
+ releaseFence = dup(fenceHandle->data[0]);
+ ASSERT_LT(0, releaseFence) << "failed to dup fence fd";
+ } else {
+ ASSERT_EQ(0, fenceHandle->numFds) << " invalid fence handle " << fenceHandle;
+ }
+ }
+ });
+
+ return releaseFence;
+}
+
+void Gralloc::rereadLockedBuffer(const native_handle_t* bufferHandle) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ ASSERT_EQ(Error::NONE, mMapper->rereadLockedBuffer(buffer));
+}
+
bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle,
const IMapper::BufferDescriptorInfo& descriptorInfo,
uint32_t stride) {
diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
index de77e1f..eed043f 100644
--- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -73,6 +73,9 @@
const IMapper::Rect& accessRegion, int acquireFence);
int unlock(const native_handle_t* bufferHandle);
+ int flushLockedBuffer(const native_handle_t* bufferHandle);
+ void rereadLockedBuffer(const native_handle_t* bufferHandle);
+
bool validateBufferSize(const native_handle_t* bufferHandle,
const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride);
void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp
index a8030ab..506026d 100644
--- a/graphics/mapper/4.0/vts/functional/Android.bp
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -20,6 +20,7 @@
srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"],
static_libs: [
"android.hardware.graphics.mapper@4.0-vts",
+ "libsync",
],
shared_libs: [
"android.hardware.graphics.allocator@4.0",
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index f5c0617..347eca6 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -25,6 +25,7 @@
#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
+#include <android/sync.h>
#include <gralloctypes/Gralloc4.h>
#include <mapper-vts/4.0/MapperVts.h>
#include <system/graphics.h>
@@ -275,6 +276,24 @@
ASSERT_NE(nullptr, outYCbCr->cr);
}
+ void fillRGBA8888(uint8_t* data, uint32_t height, size_t strideInBytes, size_t widthInBytes,
+ uint32_t seed = 0) {
+ for (uint32_t y = 0; y < height; y++) {
+ memset(data, y + seed, widthInBytes);
+ data += strideInBytes;
+ }
+ }
+
+ void verifyRGBA8888(uint8_t* data, uint32_t height, size_t strideInBytes, size_t widthInBytes,
+ uint32_t seed = 0) {
+ for (uint32_t y = 0; y < height; y++) {
+ for (size_t i = 0; i < widthInBytes; i++) {
+ EXPECT_EQ(static_cast<uint8_t>(y + seed), data[i]);
+ }
+ data += strideInBytes;
+ }
+ }
+
std::unique_ptr<Gralloc> mGralloc;
IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
static const std::set<StandardMetadataType> sRequiredMetadataTypes;
@@ -531,25 +550,14 @@
data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
// RGBA_8888
- size_t strideInBytes = stride * 4;
- size_t writeInBytes = info.width * 4;
-
- for (uint32_t y = 0; y < info.height; y++) {
- memset(data, y, writeInBytes);
- data += strideInBytes;
- }
+ fillRGBA8888(data, info.height, stride * 4, info.width * 4);
ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
// lock again for reading
ASSERT_NO_FATAL_FAILURE(
data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
- for (uint32_t y = 0; y < info.height; y++) {
- for (size_t i = 0; i < writeInBytes; i++) {
- EXPECT_EQ(static_cast<uint8_t>(y), data[i]);
- }
- data += strideInBytes;
- }
+ ASSERT_NO_FATAL_FAILURE(verifyRGBA8888(data, info.height, stride * 4, info.width * 4));
ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
if (fence >= 0) {
@@ -708,6 +716,75 @@
}
/**
+ * Test IMapper::flush and IMapper::reread.
+ */
+TEST_F(GraphicsMapperHidlTest, FlushRereadBasic) {
+ const auto& info = mDummyDescriptorInfo;
+
+ const native_handle_t* rawHandle;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(
+ rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false, false, &stride));
+
+ const native_handle_t* writeBufferHandle;
+ const native_handle_t* readBufferHandle;
+ ASSERT_NO_FATAL_FAILURE(writeBufferHandle = mGralloc->importBuffer(rawHandle));
+ ASSERT_NO_FATAL_FAILURE(readBufferHandle = mGralloc->importBuffer(rawHandle));
+
+ // lock buffer for writing
+ const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+ static_cast<int32_t>(info.height)};
+ uint8_t* writeData;
+ ASSERT_NO_FATAL_FAILURE(
+ writeData = static_cast<uint8_t*>(mGralloc->lock(
+ writeBufferHandle, static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN), region,
+ -1)));
+
+ uint8_t* readData;
+ ASSERT_NO_FATAL_FAILURE(
+ readData = static_cast<uint8_t*>(mGralloc->lock(
+ readBufferHandle, static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN), region,
+ -1)));
+
+ fillRGBA8888(writeData, info.height, stride * 4, info.width * 4);
+
+ int fence;
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->flushLockedBuffer(writeBufferHandle));
+ ASSERT_EQ(0, sync_wait(fence, 3500));
+ close(fence);
+
+ ASSERT_NO_FATAL_FAILURE(mGralloc->rereadLockedBuffer(readBufferHandle));
+
+ ASSERT_NO_FATAL_FAILURE(verifyRGBA8888(readData, info.height, stride * 4, info.width * 4));
+
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(readBufferHandle));
+ if (fence >= 0) {
+ close(fence);
+ }
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(writeBufferHandle));
+ if (fence >= 0) {
+ close(fence);
+ }
+}
+
+/**
+ * Test IMapper::flushLockedBuffer with bad buffer
+ */
+TEST_F(GraphicsMapperHidlTest, FlushLockedBufferBadBuffer) {
+ ASSERT_NO_FATAL_FAILURE(mGralloc->getMapper()->flushLockedBuffer(
+ nullptr, [&](const auto& tmpError, const auto& /*tmpReleaseFence*/) {
+ ASSERT_EQ(Error::BAD_BUFFER, tmpError);
+ }));
+}
+
+/**
+ * Test IMapper::rereadLockedBuffer with bad buffer
+ */
+TEST_F(GraphicsMapperHidlTest, RereadLockedBufferBadBuffer) {
+ ASSERT_EQ(Error::BAD_BUFFER, mGralloc->getMapper()->rereadLockedBuffer(nullptr));
+}
+
+/**
* Test IMapper::isSupported with required format RGBA_8888
*/
TEST_F(GraphicsMapperHidlTest, IsSupportedRGBA8888) {