1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <compositionengine/impl/HwcBufferCache.h>
18 #include <gtest/gtest.h>
19 #include <gui/BufferQueue.h>
20 #include <ui/GraphicBuffer.h>
21 
22 namespace android::compositionengine {
23 namespace {
24 
25 using impl::HwcBufferCache;
26 using impl::HwcSlotAndBuffer;
27 
28 class HwcBufferCacheTest : public testing::Test {
29 public:
30     ~HwcBufferCacheTest() override = default;
31 
32     sp<GraphicBuffer> mBuffer1 =
33             sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
34     sp<GraphicBuffer> mBuffer2 =
35             sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
36 };
37 
TEST_F(HwcBufferCacheTest,getHwcSlotAndBuffer_returnsUniqueSlotNumberForEachBuffer)38 TEST_F(HwcBufferCacheTest, getHwcSlotAndBuffer_returnsUniqueSlotNumberForEachBuffer) {
39     HwcBufferCache cache;
40     sp<GraphicBuffer> outBuffer;
41 
42     HwcSlotAndBuffer slotAndBufferFor1 = cache.getHwcSlotAndBuffer(mBuffer1);
43     EXPECT_NE(slotAndBufferFor1.slot, UINT32_MAX);
44     EXPECT_EQ(slotAndBufferFor1.buffer, mBuffer1);
45 
46     HwcSlotAndBuffer slotAndBufferFor2 = cache.getHwcSlotAndBuffer(mBuffer2);
47     EXPECT_NE(slotAndBufferFor2.slot, slotAndBufferFor1.slot);
48     EXPECT_NE(slotAndBufferFor2.slot, UINT32_MAX);
49     EXPECT_EQ(slotAndBufferFor2.buffer, mBuffer2);
50 }
51 
TEST_F(HwcBufferCacheTest,getHwcSlotAndBuffer_whenCached_returnsSameSlotNumberAndNullBuffer)52 TEST_F(HwcBufferCacheTest, getHwcSlotAndBuffer_whenCached_returnsSameSlotNumberAndNullBuffer) {
53     HwcBufferCache cache;
54     sp<GraphicBuffer> outBuffer;
55 
56     HwcSlotAndBuffer originalSlotAndBuffer = cache.getHwcSlotAndBuffer(mBuffer1);
57     EXPECT_NE(originalSlotAndBuffer.slot, UINT32_MAX);
58     EXPECT_EQ(originalSlotAndBuffer.buffer, mBuffer1);
59 
60     HwcSlotAndBuffer finalSlotAndBuffer = cache.getHwcSlotAndBuffer(mBuffer1);
61     EXPECT_EQ(finalSlotAndBuffer.slot, originalSlotAndBuffer.slot);
62     EXPECT_EQ(finalSlotAndBuffer.buffer, nullptr);
63 }
64 
TEST_F(HwcBufferCacheTest,getHwcSlotAndBuffer_whenSlotsFull_evictsOldestCachedBuffer)65 TEST_F(HwcBufferCacheTest, getHwcSlotAndBuffer_whenSlotsFull_evictsOldestCachedBuffer) {
66     HwcBufferCache cache;
67     sp<GraphicBuffer> outBuffer;
68 
69     sp<GraphicBuffer> graphicBuffers[100];
70     HwcSlotAndBuffer slotsAndBuffers[100];
71     int finalCachedBufferIndex = 0;
72     for (int i = 0; i < 100; ++i) {
73         graphicBuffers[i] = sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
74         slotsAndBuffers[i] = cache.getHwcSlotAndBuffer(graphicBuffers[i]);
75         // we fill up the cache when the slot number for the first buffer is reused
76         if (i > 0 && slotsAndBuffers[i].slot == slotsAndBuffers[0].slot) {
77             finalCachedBufferIndex = i;
78             break;
79         }
80     }
81     ASSERT_GT(finalCachedBufferIndex, 1);
82     // the final cached buffer has the same slot value as the oldest buffer
83     EXPECT_EQ(slotsAndBuffers[finalCachedBufferIndex].slot, slotsAndBuffers[0].slot);
84     // the oldest buffer is no longer in the cache because it was evicted
85     EXPECT_EQ(cache.uncache(graphicBuffers[0]->getId()), UINT32_MAX);
86 }
87 
TEST_F(HwcBufferCacheTest,uncache_whenCached_returnsSlotNumber)88 TEST_F(HwcBufferCacheTest, uncache_whenCached_returnsSlotNumber) {
89     HwcBufferCache cache;
90     sp<GraphicBuffer> outBuffer;
91 
92     HwcSlotAndBuffer slotAndBufferFor1 = cache.getHwcSlotAndBuffer(mBuffer1);
93     ASSERT_NE(slotAndBufferFor1.slot, UINT32_MAX);
94 
95     HwcSlotAndBuffer slotAndBufferFor2 = cache.getHwcSlotAndBuffer(mBuffer2);
96     ASSERT_NE(slotAndBufferFor2.slot, UINT32_MAX);
97 
98     // the 1st buffer should be found in the cache with a slot number
99     EXPECT_EQ(cache.uncache(mBuffer1->getId()), slotAndBufferFor1.slot);
100     // since the 1st buffer has been previously uncached, we should no longer receive a slot number
101     EXPECT_EQ(cache.uncache(mBuffer1->getId()), UINT32_MAX);
102     // the 2nd buffer should be still found in the cache with a slot number
103     EXPECT_EQ(cache.uncache(mBuffer2->getId()), slotAndBufferFor2.slot);
104     // since the 2nd buffer has been previously uncached, we should no longer receive a slot number
105     EXPECT_EQ(cache.uncache(mBuffer2->getId()), UINT32_MAX);
106 }
107 
TEST_F(HwcBufferCacheTest,uncache_whenUncached_returnsInvalidSlotNumber)108 TEST_F(HwcBufferCacheTest, uncache_whenUncached_returnsInvalidSlotNumber) {
109     HwcBufferCache cache;
110     sp<GraphicBuffer> outBuffer;
111 
112     HwcSlotAndBuffer slotAndBufferFor1 = cache.getHwcSlotAndBuffer(mBuffer1);
113     ASSERT_NE(slotAndBufferFor1.slot, UINT32_MAX);
114 
115     EXPECT_EQ(cache.uncache(mBuffer2->getId()), UINT32_MAX);
116 }
117 
TEST_F(HwcBufferCacheTest,getOverrideHwcSlotAndBuffer_whenCached_returnsSameSlotAndNullBuffer)118 TEST_F(HwcBufferCacheTest, getOverrideHwcSlotAndBuffer_whenCached_returnsSameSlotAndNullBuffer) {
119     HwcBufferCache cache;
120     sp<GraphicBuffer> outBuffer;
121 
122     HwcSlotAndBuffer originalSlotAndBuffer = cache.getOverrideHwcSlotAndBuffer(mBuffer1);
123     EXPECT_NE(originalSlotAndBuffer.slot, UINT32_MAX);
124     EXPECT_EQ(originalSlotAndBuffer.buffer, mBuffer1);
125 
126     HwcSlotAndBuffer finalSlotAndBuffer = cache.getOverrideHwcSlotAndBuffer(mBuffer1);
127     EXPECT_EQ(finalSlotAndBuffer.slot, originalSlotAndBuffer.slot);
128     EXPECT_EQ(finalSlotAndBuffer.buffer, nullptr);
129 }
130 
TEST_F(HwcBufferCacheTest,getOverrideHwcSlotAndBuffer_whenSlotsFull_returnsIndependentSlot)131 TEST_F(HwcBufferCacheTest, getOverrideHwcSlotAndBuffer_whenSlotsFull_returnsIndependentSlot) {
132     HwcBufferCache cache;
133     sp<GraphicBuffer> outBuffer;
134 
135     sp<GraphicBuffer> graphicBuffers[100];
136     HwcSlotAndBuffer slotsAndBuffers[100];
137     int finalCachedBufferIndex = -1;
138     for (int i = 0; i < 100; ++i) {
139         graphicBuffers[i] = sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
140         slotsAndBuffers[i] = cache.getHwcSlotAndBuffer(graphicBuffers[i]);
141         // we fill up the cache when the slot number for the first buffer is reused
142         if (i > 0 && slotsAndBuffers[i].slot == slotsAndBuffers[0].slot) {
143             finalCachedBufferIndex = i;
144             break;
145         }
146     }
147     // expect to have cached at least a few buffers before evicting
148     ASSERT_GT(finalCachedBufferIndex, 1);
149 
150     sp<GraphicBuffer> overrideBuffer =
151             sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
152     HwcSlotAndBuffer overrideSlotAndBuffer = cache.getOverrideHwcSlotAndBuffer(overrideBuffer);
153     // expect us to have a slot number
154     EXPECT_NE(overrideSlotAndBuffer.slot, UINT32_MAX);
155     // expect this to be the first time we cached the buffer
156     EXPECT_NE(overrideSlotAndBuffer.buffer, nullptr);
157 
158     // expect the slot number to not equal any other slot number, even after the slots have been
159     // exhausted, indicating that the override buffer slot is independent from the slots for
160     // non-override buffers
161     for (int i = 0; i < finalCachedBufferIndex; ++i) {
162         EXPECT_NE(overrideSlotAndBuffer.slot, slotsAndBuffers[i].slot);
163     }
164     // the override buffer is independently uncached from the oldest cached buffer
165     // expect to find the override buffer still in the override buffer slot
166     EXPECT_EQ(cache.uncache(overrideBuffer->getId()), overrideSlotAndBuffer.slot);
167     // expect that the first buffer was not evicted from the cache when the override buffer was
168     // cached
169     EXPECT_EQ(cache.uncache(graphicBuffers[1]->getId()), slotsAndBuffers[1].slot);
170 }
171 
TEST_F(HwcBufferCacheTest,uncache_whenOverrideCached_returnsSlotNumber)172 TEST_F(HwcBufferCacheTest, uncache_whenOverrideCached_returnsSlotNumber) {
173     HwcBufferCache cache;
174     sp<GraphicBuffer> outBuffer;
175 
176     HwcSlotAndBuffer hwcSlotAndBuffer = cache.getOverrideHwcSlotAndBuffer(mBuffer1);
177     ASSERT_NE(hwcSlotAndBuffer.slot, UINT32_MAX);
178 
179     EXPECT_EQ(cache.uncache(mBuffer1->getId()), hwcSlotAndBuffer.slot);
180     EXPECT_EQ(cache.uncache(mBuffer1->getId()), UINT32_MAX);
181 }
182 
TEST_F(HwcBufferCacheTest,uncache_whenOverrideUncached_returnsInvalidSlotNumber)183 TEST_F(HwcBufferCacheTest, uncache_whenOverrideUncached_returnsInvalidSlotNumber) {
184     HwcBufferCache cache;
185     sp<GraphicBuffer> outBuffer;
186 
187     HwcSlotAndBuffer hwcSlotAndBuffer = cache.getOverrideHwcSlotAndBuffer(mBuffer1);
188     ASSERT_NE(hwcSlotAndBuffer.slot, UINT32_MAX);
189 
190     EXPECT_EQ(cache.uncache(mBuffer2->getId()), UINT32_MAX);
191 }
192 
193 } // namespace
194 } // namespace android::compositionengine
195