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