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

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

Merge "gralloc: add flush and reread for locked buffers"

parents fb1d7a77 2c45bb16
Loading
Loading
Loading
Loading
+44 −0
Original line number Diff line number Diff line
@@ -265,6 +265,50 @@ interface IMapper {
     */
    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.
     *
+28 −0
Original line number Diff line number Diff line
@@ -246,6 +246,34 @@ int Gralloc::unlock(const native_handle_t* bufferHandle) {
    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) {
+3 −0
Original line number Diff line number Diff line
@@ -73,6 +73,9 @@ class Gralloc {
               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,
+1 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ cc_test {
    srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"],
    static_libs: [
        "android.hardware.graphics.mapper@4.0-vts",
        "libsync",
    ],
    shared_libs: [
        "android.hardware.graphics.allocator@4.0",
+90 −13
Original line number Diff line number Diff line
@@ -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 @@ class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
        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 @@ TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) {
            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) {
@@ -707,6 +715,75 @@ TEST_F(GraphicsMapperHidlTest, UnlockNegative) {
#endif
}

/**
 * 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
 */