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

Commit b82cf27c authored by Wale Ogunwale's avatar Wale Ogunwale Committed by Android (Google) Code Review
Browse files

Merge "Revert "Caching between SF and HWC for BufferStateLayers""

parents 84b50b86 5723fbda
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -366,7 +366,7 @@ void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display)
    uint32_t hwcSlot = 0;
    sp<GraphicBuffer> hwcBuffer;
    (*outputLayer->editState().hwc)
            .hwcBufferCache.getHwcBuffer(mActiveBuffer, &hwcSlot, &hwcBuffer);
            .hwcBufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot, &hwcBuffer);

    auto acquireFence = mConsumer->getCurrentFence();
    auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
+3 −6
Original line number Diff line number Diff line
@@ -565,17 +565,14 @@ status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) {
void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
    const auto outputLayer = findOutputLayerForDisplay(display);
    LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
    auto& hwcInfo = *outputLayer->editState().hwc;
    auto& hwcLayer = hwcInfo.hwcLayer;
    auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;

    const State& s(getDrawingState());

    // obtain slot
    // TODO(marissaw): support more than one slot
    uint32_t hwcSlot = 0;
    sp<GraphicBuffer> buffer;
    hwcInfo.hwcBufferCache.getHwcBuffer(s.buffer, &hwcSlot, &buffer);

    auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence);
    auto error = hwcLayer->setBuffer(hwcSlot, s.buffer, s.acquireFence);
    if (error != HWC2::Error::None) {
        ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
              s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
+6 −16
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@
#include <cstdint>
#include <vector>

#include <gui/BufferQueue.h>
#include <utils/StrongPointer.h>

namespace android {
@@ -40,28 +39,19 @@ namespace compositionengine::impl {
class HwcBufferCache {
public:
    HwcBufferCache();
    // Given a buffer, return the HWC cache slot and

    // Given a buffer queue slot and buffer, return the HWC cache slot and
    // buffer to be sent to HWC.
    //
    // outBuffer is set to buffer when buffer is not in the HWC cache;
    // otherwise, outBuffer is set to nullptr.
    void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
    void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                      sp<GraphicBuffer>* outBuffer);

protected:
    int getSlot(const sp<GraphicBuffer>& buffer);
    int getLeastRecentlyUsedSlot();
    uint64_t getCounter();

private:
    // an array where the index corresponds to a slot and the value corresponds to a (counter,
    // buffer) pair. "counter" is a unique value that indicates the last time this slot was updated
    // or used and allows us to keep track of the least-recently used buffer.
    std::pair<uint64_t, wp<GraphicBuffer>> mBuffers[BufferQueue::NUM_BUFFER_SLOTS];

    // The cache increments this counter value when a slot is updated or used.
    // Used to track the least recently-used buffer
    uint64_t mCounter = 1;
    // a vector as we expect "slot" to be in the range of [0, 63] (that is,
    // less than BufferQueue::NUM_BUFFER_SLOTS).
    std::vector<sp<GraphicBuffer>> mBuffers;
};

} // namespace compositionengine::impl
+13 −27
Original line number Diff line number Diff line
@@ -21,45 +21,31 @@
namespace android::compositionengine::impl {

HwcBufferCache::HwcBufferCache() {
    std::fill(std::begin(mBuffers), std::end(mBuffers),
              std::pair<uint64_t, wp<GraphicBuffer>>(0, nullptr));
}
int HwcBufferCache::getSlot(const sp<GraphicBuffer>& buffer) {
    // search for cached buffer first
    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
        if (mBuffers[i].second == buffer) {
            return i;
        }
    mBuffers.reserve(BufferQueue::NUM_BUFFER_SLOTS);
}

    // use the least-recently used slot
    return getLeastRecentlyUsedSlot();
void HwcBufferCache::getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                                  sp<GraphicBuffer>* outBuffer) {
    if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0) {
        // default to slot 0
        slot = 0;
    }

int HwcBufferCache::getLeastRecentlyUsedSlot() {
    auto iter = std::min_element(std::begin(mBuffers), std::end(mBuffers));
    return std::distance(std::begin(mBuffers), iter);
    if (static_cast<size_t>(slot) >= mBuffers.size()) {
        mBuffers.resize(slot + 1);
    }

void HwcBufferCache::getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                                  sp<GraphicBuffer>* outBuffer) {
    *outSlot = getSlot(buffer);
    *outSlot = slot;

    auto& [currentCounter, currentBuffer] = mBuffers[*outSlot];
    if (currentBuffer == buffer) {
    if (mBuffers[slot] == buffer) {
        // already cached in HWC, skip sending the buffer
        *outBuffer = nullptr;
        currentCounter = getCounter();
    } else {
        *outBuffer = buffer;

        // update cache
        currentBuffer = buffer;
        currentCounter = getCounter();
        mBuffers[slot] = buffer;
    }
}

uint64_t HwcBufferCache::getCounter() {
    return mCounter++;
}
} // namespace android::compositionengine::impl
+42 −60
Original line number Diff line number Diff line
@@ -22,78 +22,60 @@
namespace android::compositionengine {
namespace {

class TestableHwcBufferCache : public impl::HwcBufferCache {
public:
    void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                      sp<GraphicBuffer>* outBuffer) {
        HwcBufferCache::getHwcBuffer(buffer, outSlot, outBuffer);
    }
    int getSlot(const sp<GraphicBuffer>& buffer) { return HwcBufferCache::getSlot(buffer); }
    int getLeastRecentlyUsedSlot() { return HwcBufferCache::getLeastRecentlyUsedSlot(); }
};

class HwcBufferCacheTest : public testing::Test {
public:
    ~HwcBufferCacheTest() override = default;

    TestableHwcBufferCache mCache;
    sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
    sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
};

TEST_F(HwcBufferCacheTest, testSlot) {
    void testSlot(const int inSlot, const uint32_t expectedSlot) {
        uint32_t outSlot;
        sp<GraphicBuffer> outBuffer;

        // The first time, the output  is the same as the input
    mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
    EXPECT_EQ(0, outSlot);
        mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer);
        EXPECT_EQ(expectedSlot, outSlot);
        EXPECT_EQ(mBuffer1, outBuffer);

        // The second time with the same buffer, the outBuffer is nullptr.
    mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
    EXPECT_EQ(0, outSlot);
        mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer);
        EXPECT_EQ(expectedSlot, outSlot);
        EXPECT_EQ(nullptr, outBuffer.get());

        // With a new buffer, the outBuffer is the input.
    mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer);
    EXPECT_EQ(1, outSlot);
        mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer);
        EXPECT_EQ(expectedSlot, outSlot);
        EXPECT_EQ(mBuffer2, outBuffer);

        // Again, the second request with the same buffer sets outBuffer to nullptr.
    mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer);
    EXPECT_EQ(1, outSlot);
        mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer);
        EXPECT_EQ(expectedSlot, outSlot);
        EXPECT_EQ(nullptr, outBuffer.get());

        // Setting a slot to use nullptr lookslike works, but note that
        // the output values make it look like no new buffer is being set....
    mCache.getHwcBuffer(sp<GraphicBuffer>(), &outSlot, &outBuffer);
    EXPECT_EQ(2, outSlot);
        mCache.getHwcBuffer(inSlot, sp<GraphicBuffer>(), &outSlot, &outBuffer);
        EXPECT_EQ(expectedSlot, outSlot);
        EXPECT_EQ(nullptr, outBuffer.get());
    }

TEST_F(HwcBufferCacheTest, testGetLeastRecentlyUsedSlot) {
    int slot;
    uint32_t outSlot;
    sp<GraphicBuffer> outBuffer;
    impl::HwcBufferCache mCache;
    sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
    sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
};

    // fill up cache
    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
        sp<GraphicBuffer> buf{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
        mCache.getHwcBuffer(buf, &outSlot, &outBuffer);
        EXPECT_EQ(buf, outBuffer);
        EXPECT_EQ(i, outSlot);
TEST_F(HwcBufferCacheTest, cacheWorksForSlotZero) {
    testSlot(0, 0);
}

    slot = mCache.getLeastRecentlyUsedSlot();
    EXPECT_EQ(0, slot);
TEST_F(HwcBufferCacheTest, cacheWorksForMaxSlot) {
    testSlot(BufferQueue::NUM_BUFFER_SLOTS - 1, BufferQueue::NUM_BUFFER_SLOTS - 1);
}

    mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
    EXPECT_EQ(0, outSlot);
    EXPECT_EQ(mBuffer1, outBuffer);
TEST_F(HwcBufferCacheTest, cacheMapsNegativeSlotToZero) {
    testSlot(-123, 0);
}

    slot = mCache.getLeastRecentlyUsedSlot();
    EXPECT_EQ(1, slot);
TEST_F(HwcBufferCacheTest, cacheMapsInvalidBufferSlotToZero) {
    testSlot(BufferQueue::INVALID_BUFFER_SLOT, 0);
}

} // namespace
Loading