/* * 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 #include #include #include namespace android::compositionengine { namespace { using impl::HwcBufferCache; using impl::HwcSlotAndBuffer; class HwcBufferCacheTest : public testing::Test { public: ~HwcBufferCacheTest() override = default; sp mBuffer1 = sp::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u); sp mBuffer2 = sp::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u); }; TEST_F(HwcBufferCacheTest, getHwcSlotAndBuffer_returnsUniqueSlotNumberForEachBuffer) { HwcBufferCache cache; sp 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 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 outBuffer; sp graphicBuffers[100]; HwcSlotAndBuffer slotsAndBuffers[100]; int finalCachedBufferIndex = 0; for (int i = 0; i < 100; ++i) { graphicBuffers[i] = sp::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 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 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 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 outBuffer; sp graphicBuffers[100]; HwcSlotAndBuffer slotsAndBuffers[100]; int finalCachedBufferIndex = -1; for (int i = 0; i < 100; ++i) { graphicBuffers[i] = sp::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 overrideBuffer = sp::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 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 outBuffer; HwcSlotAndBuffer hwcSlotAndBuffer = cache.getOverrideHwcSlotAndBuffer(mBuffer1); ASSERT_NE(hwcSlotAndBuffer.slot, UINT32_MAX); EXPECT_EQ(cache.uncache(mBuffer2->getId()), UINT32_MAX); } } // namespace } // namespace android::compositionengine