blob: c5fb5944fb3f9ec7c6e6291a8e04de3abe17eb39 [file] [log] [blame]
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <compositionengine/impl/HwcBufferCache.h>
#include <gtest/gtest.h>
#include <gui/BufferQueue.h>
#include <ui/GraphicBuffer.h>
namespace android::compositionengine {
namespace {
using impl::HwcBufferCache;
using impl::HwcSlotAndBuffer;
class HwcBufferCacheTest : public testing::Test {
public:
~HwcBufferCacheTest() override = default;
sp<GraphicBuffer> mBuffer1 =
sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
sp<GraphicBuffer> mBuffer2 =
sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
};
TEST_F(HwcBufferCacheTest, getHwcSlotAndBuffer_returnsUniqueSlotNumberForEachBuffer) {
HwcBufferCache cache;
sp<GraphicBuffer> outBuffer;
HwcSlotAndBuffer slotAndBufferFor1 = cache.getHwcSlotAndBuffer(mBuffer1);
EXPECT_NE(slotAndBufferFor1.slot, UINT32_MAX);
EXPECT_EQ(slotAndBufferFor1.buffer, mBuffer1);
HwcSlotAndBuffer slotAndBufferFor2 = cache.getHwcSlotAndBuffer(mBuffer2);
EXPECT_NE(slotAndBufferFor2.slot, slotAndBufferFor1.slot);
EXPECT_NE(slotAndBufferFor2.slot, UINT32_MAX);
EXPECT_EQ(slotAndBufferFor2.buffer, mBuffer2);
}
TEST_F(HwcBufferCacheTest, getHwcSlotAndBuffer_whenCached_returnsSameSlotNumberAndNullBuffer) {
HwcBufferCache cache;
sp<GraphicBuffer> outBuffer;
HwcSlotAndBuffer originalSlotAndBuffer = cache.getHwcSlotAndBuffer(mBuffer1);
EXPECT_NE(originalSlotAndBuffer.slot, UINT32_MAX);
EXPECT_EQ(originalSlotAndBuffer.buffer, mBuffer1);
HwcSlotAndBuffer finalSlotAndBuffer = cache.getHwcSlotAndBuffer(mBuffer1);
EXPECT_EQ(finalSlotAndBuffer.slot, originalSlotAndBuffer.slot);
EXPECT_EQ(finalSlotAndBuffer.buffer, nullptr);
}
TEST_F(HwcBufferCacheTest, getHwcSlotAndBuffer_whenSlotsFull_evictsOldestCachedBuffer) {
HwcBufferCache cache;
sp<GraphicBuffer> outBuffer;
sp<GraphicBuffer> graphicBuffers[100];
HwcSlotAndBuffer slotsAndBuffers[100];
int finalCachedBufferIndex = 0;
for (int i = 0; i < 100; ++i) {
graphicBuffers[i] = sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
slotsAndBuffers[i] = cache.getHwcSlotAndBuffer(graphicBuffers[i]);
// we fill up the cache when the slot number for the first buffer is reused
if (i > 0 && slotsAndBuffers[i].slot == slotsAndBuffers[0].slot) {
finalCachedBufferIndex = i;
break;
}
}
ASSERT_GT(finalCachedBufferIndex, 1);
// the final cached buffer has the same slot value as the oldest buffer
EXPECT_EQ(slotsAndBuffers[finalCachedBufferIndex].slot, slotsAndBuffers[0].slot);
// the oldest buffer is no longer in the cache because it was evicted
EXPECT_EQ(cache.uncache(graphicBuffers[0]->getId()), UINT32_MAX);
}
TEST_F(HwcBufferCacheTest, uncache_whenCached_returnsSlotNumber) {
HwcBufferCache cache;
sp<GraphicBuffer> outBuffer;
HwcSlotAndBuffer slotAndBufferFor1 = cache.getHwcSlotAndBuffer(mBuffer1);
ASSERT_NE(slotAndBufferFor1.slot, UINT32_MAX);
HwcSlotAndBuffer slotAndBufferFor2 = cache.getHwcSlotAndBuffer(mBuffer2);
ASSERT_NE(slotAndBufferFor2.slot, UINT32_MAX);
// the 1st buffer should be found in the cache with a slot number
EXPECT_EQ(cache.uncache(mBuffer1->getId()), slotAndBufferFor1.slot);
// since the 1st buffer has been previously uncached, we should no longer receive a slot number
EXPECT_EQ(cache.uncache(mBuffer1->getId()), UINT32_MAX);
// the 2nd buffer should be still found in the cache with a slot number
EXPECT_EQ(cache.uncache(mBuffer2->getId()), slotAndBufferFor2.slot);
// since the 2nd buffer has been previously uncached, we should no longer receive a slot number
EXPECT_EQ(cache.uncache(mBuffer2->getId()), UINT32_MAX);
}
TEST_F(HwcBufferCacheTest, uncache_whenUncached_returnsInvalidSlotNumber) {
HwcBufferCache cache;
sp<GraphicBuffer> outBuffer;
HwcSlotAndBuffer slotAndBufferFor1 = cache.getHwcSlotAndBuffer(mBuffer1);
ASSERT_NE(slotAndBufferFor1.slot, UINT32_MAX);
EXPECT_EQ(cache.uncache(mBuffer2->getId()), UINT32_MAX);
}
TEST_F(HwcBufferCacheTest, getOverrideHwcSlotAndBuffer_whenCached_returnsSameSlotAndNullBuffer) {
HwcBufferCache cache;
sp<GraphicBuffer> outBuffer;
HwcSlotAndBuffer originalSlotAndBuffer = cache.getOverrideHwcSlotAndBuffer(mBuffer1);
EXPECT_NE(originalSlotAndBuffer.slot, UINT32_MAX);
EXPECT_EQ(originalSlotAndBuffer.buffer, mBuffer1);
HwcSlotAndBuffer finalSlotAndBuffer = cache.getOverrideHwcSlotAndBuffer(mBuffer1);
EXPECT_EQ(finalSlotAndBuffer.slot, originalSlotAndBuffer.slot);
EXPECT_EQ(finalSlotAndBuffer.buffer, nullptr);
}
TEST_F(HwcBufferCacheTest, getOverrideHwcSlotAndBuffer_whenSlotsFull_returnsIndependentSlot) {
HwcBufferCache cache;
sp<GraphicBuffer> outBuffer;
sp<GraphicBuffer> graphicBuffers[100];
HwcSlotAndBuffer slotsAndBuffers[100];
int finalCachedBufferIndex = -1;
for (int i = 0; i < 100; ++i) {
graphicBuffers[i] = sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
slotsAndBuffers[i] = cache.getHwcSlotAndBuffer(graphicBuffers[i]);
// we fill up the cache when the slot number for the first buffer is reused
if (i > 0 && slotsAndBuffers[i].slot == slotsAndBuffers[0].slot) {
finalCachedBufferIndex = i;
break;
}
}
// expect to have cached at least a few buffers before evicting
ASSERT_GT(finalCachedBufferIndex, 1);
sp<GraphicBuffer> overrideBuffer =
sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
HwcSlotAndBuffer overrideSlotAndBuffer = cache.getOverrideHwcSlotAndBuffer(overrideBuffer);
// expect us to have a slot number
EXPECT_NE(overrideSlotAndBuffer.slot, UINT32_MAX);
// expect this to be the first time we cached the buffer
EXPECT_NE(overrideSlotAndBuffer.buffer, nullptr);
// expect the slot number to not equal any other slot number, even after the slots have been
// exhausted, indicating that the override buffer slot is independent from the slots for
// non-override buffers
for (int i = 0; i < finalCachedBufferIndex; ++i) {
EXPECT_NE(overrideSlotAndBuffer.slot, slotsAndBuffers[i].slot);
}
// the override buffer is independently uncached from the oldest cached buffer
// expect to find the override buffer still in the override buffer slot
EXPECT_EQ(cache.uncache(overrideBuffer->getId()), overrideSlotAndBuffer.slot);
// expect that the first buffer was not evicted from the cache when the override buffer was
// cached
EXPECT_EQ(cache.uncache(graphicBuffers[1]->getId()), slotsAndBuffers[1].slot);
}
TEST_F(HwcBufferCacheTest, uncache_whenOverrideCached_returnsSlotNumber) {
HwcBufferCache cache;
sp<GraphicBuffer> outBuffer;
HwcSlotAndBuffer hwcSlotAndBuffer = cache.getOverrideHwcSlotAndBuffer(mBuffer1);
ASSERT_NE(hwcSlotAndBuffer.slot, UINT32_MAX);
EXPECT_EQ(cache.uncache(mBuffer1->getId()), hwcSlotAndBuffer.slot);
EXPECT_EQ(cache.uncache(mBuffer1->getId()), UINT32_MAX);
}
TEST_F(HwcBufferCacheTest, uncache_whenOverrideUncached_returnsInvalidSlotNumber) {
HwcBufferCache cache;
sp<GraphicBuffer> outBuffer;
HwcSlotAndBuffer hwcSlotAndBuffer = cache.getOverrideHwcSlotAndBuffer(mBuffer1);
ASSERT_NE(hwcSlotAndBuffer.slot, UINT32_MAX);
EXPECT_EQ(cache.uncache(mBuffer2->getId()), UINT32_MAX);
}
} // namespace
} // namespace android::compositionengine