1 /* 2 * Copyright (C) 2015 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 <Rect.h> 18 #include <gtest/gtest.h> 19 #include <renderstate/OffscreenBufferPool.h> 20 21 #include <tests/common/TestUtils.h> 22 23 using namespace android::uirenderer; 24 25 TEST(OffscreenBuffer, computeIdealDimension) { 26 EXPECT_EQ(64u, OffscreenBuffer::computeIdealDimension(1)); 27 EXPECT_EQ(64u, OffscreenBuffer::computeIdealDimension(31)); 28 EXPECT_EQ(64u, OffscreenBuffer::computeIdealDimension(33)); 29 EXPECT_EQ(64u, OffscreenBuffer::computeIdealDimension(64)); 30 EXPECT_EQ(1024u, OffscreenBuffer::computeIdealDimension(1000)); 31 } 32 33 RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, construct) { 34 OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 49u, 149u); 35 EXPECT_EQ(49u, layer.viewportWidth); 36 EXPECT_EQ(149u, layer.viewportHeight); 37 38 EXPECT_EQ(64u, layer.texture.width()); 39 EXPECT_EQ(192u, layer.texture.height()); 40 41 EXPECT_EQ(64u * 192u * 4u, layer.getSizeInBytes()); 42 } 43 44 RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, constructWideColorGamut) { 45 OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 49u, 149u, true); 46 EXPECT_EQ(49u, layer.viewportWidth); 47 EXPECT_EQ(149u, layer.viewportHeight); 48 49 EXPECT_EQ(64u, layer.texture.width()); 50 EXPECT_EQ(192u, layer.texture.height()); 51 52 EXPECT_TRUE(layer.wideColorGamut); 53 54 EXPECT_EQ(64u * 192u * 8u, layer.getSizeInBytes()); 55 } 56 57 RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, getTextureCoordinates) { 58 OffscreenBuffer layerAligned(renderThread.renderState(), Caches::getInstance(), 256u, 256u); 59 EXPECT_EQ(Rect(0, 1, 1, 0), layerAligned.getTextureCoordinates()); 60 61 OffscreenBuffer layerUnaligned(renderThread.renderState(), Caches::getInstance(), 200u, 225u); 62 EXPECT_EQ(Rect(0, 225.0f / 256.0f, 200.0f / 256.0f, 0), layerUnaligned.getTextureCoordinates()); 63 } 64 65 RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, dirty) { 66 OffscreenBuffer buffer(renderThread.renderState(), Caches::getInstance(), 256u, 256u); 67 buffer.dirty(Rect(-100, -100, 100, 100)); 68 EXPECT_EQ(android::Rect(100, 100), buffer.region.getBounds()); 69 } 70 71 RENDERTHREAD_TEST(OffscreenBufferPool, construct) { 72 OffscreenBufferPool pool; 73 EXPECT_EQ(0u, pool.getCount()) << "pool must be created empty"; 74 EXPECT_EQ(0u, pool.getSize()) << "pool must be created empty"; 75 // TODO: Does this really make sense as a test? 76 EXPECT_EQ(DeviceInfo::multiplyByResolution(4 * 4), pool.getMaxSize()); 77 } 78 79 RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, getPutClear) { 80 OffscreenBufferPool pool; 81 82 auto layer = pool.get(renderThread.renderState(), 100u, 200u); 83 EXPECT_EQ(100u, layer->viewportWidth); 84 EXPECT_EQ(200u, layer->viewportHeight); 85 86 ASSERT_LT(layer->getSizeInBytes(), pool.getMaxSize()); 87 88 pool.putOrDelete(layer); 89 ASSERT_EQ(layer->getSizeInBytes(), pool.getSize()); 90 91 auto layer2 = pool.get(renderThread.renderState(), 102u, 202u); 92 EXPECT_EQ(layer, layer2) << "layer should be recycled"; 93 ASSERT_EQ(0u, pool.getSize()) << "pool should have been emptied by removing only layer"; 94 95 pool.putOrDelete(layer); 96 EXPECT_EQ(1u, pool.getCount()); 97 pool.clear(); 98 EXPECT_EQ(0u, pool.getSize()); 99 EXPECT_EQ(0u, pool.getCount()); 100 } 101 102 RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, getPutClearWideColorGamut) { 103 OffscreenBufferPool pool; 104 105 auto layer = pool.get(renderThread.renderState(), 100u, 200u, true); 106 EXPECT_EQ(100u, layer->viewportWidth); 107 EXPECT_EQ(200u, layer->viewportHeight); 108 EXPECT_TRUE(layer->wideColorGamut); 109 110 ASSERT_LT(layer->getSizeInBytes(), pool.getMaxSize()); 111 112 pool.putOrDelete(layer); 113 ASSERT_EQ(layer->getSizeInBytes(), pool.getSize()); 114 115 auto layer2 = pool.get(renderThread.renderState(), 102u, 202u, true); 116 EXPECT_EQ(layer, layer2) << "layer should be recycled"; 117 ASSERT_EQ(0u, pool.getSize()) << "pool should have been emptied by removing only layer"; 118 119 pool.putOrDelete(layer2); 120 EXPECT_EQ(1u, pool.getCount()); 121 pool.clear(); 122 EXPECT_EQ(0u, pool.getSize()); 123 EXPECT_EQ(0u, pool.getCount()); 124 125 // add non wide gamut layer 126 auto layer3 = pool.get(renderThread.renderState(), 100u, 200u); 127 EXPECT_FALSE(layer3->wideColorGamut); 128 pool.putOrDelete(layer3); 129 EXPECT_EQ(1u, pool.getCount()); 130 131 auto layer4 = pool.get(renderThread.renderState(), 100u, 200u, true); 132 EXPECT_TRUE(layer4->wideColorGamut); 133 EXPECT_EQ(1u, pool.getCount()); 134 ASSERT_NE(layer3, layer4); 135 136 pool.putOrDelete(layer4); 137 138 pool.clear(); 139 EXPECT_EQ(0u, pool.getSize()); 140 EXPECT_EQ(0u, pool.getCount()); 141 } 142 143 RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, resize) { 144 OffscreenBufferPool pool; 145 146 auto layer = pool.get(renderThread.renderState(), 64u, 64u); 147 layer->dirty(Rect(64, 64)); 148 149 // resize in place 150 ASSERT_EQ(layer, pool.resize(layer, 60u, 55u)); 151 EXPECT_TRUE(layer->region.isEmpty()) << "In place resize should clear usage region"; 152 EXPECT_EQ(60u, layer->viewportWidth); 153 EXPECT_EQ(55u, layer->viewportHeight); 154 EXPECT_EQ(64u, layer->texture.width()); 155 EXPECT_EQ(64u, layer->texture.height()); 156 157 // resized to use different object in pool 158 auto layer2 = pool.get(renderThread.renderState(), 128u, 128u); 159 layer2->dirty(Rect(128, 128)); 160 EXPECT_FALSE(layer2->region.isEmpty()); 161 pool.putOrDelete(layer2); 162 ASSERT_EQ(1u, pool.getCount()); 163 164 ASSERT_EQ(layer2, pool.resize(layer, 120u, 125u)); 165 EXPECT_TRUE(layer2->region.isEmpty()) << "Swap resize should clear usage region"; 166 EXPECT_EQ(120u, layer2->viewportWidth); 167 EXPECT_EQ(125u, layer2->viewportHeight); 168 EXPECT_EQ(128u, layer2->texture.width()); 169 EXPECT_EQ(128u, layer2->texture.height()); 170 171 // original allocation now only thing in pool 172 EXPECT_EQ(1u, pool.getCount()); 173 EXPECT_EQ(layer->getSizeInBytes(), pool.getSize()); 174 175 pool.putOrDelete(layer2); 176 } 177 178 RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, resizeWideColorGamut) { 179 OffscreenBufferPool pool; 180 181 auto layer = pool.get(renderThread.renderState(), 64u, 64u, true); 182 183 // resize in place 184 ASSERT_EQ(layer, pool.resize(layer, 60u, 55u)); 185 EXPECT_EQ(60u, layer->viewportWidth); 186 EXPECT_EQ(55u, layer->viewportHeight); 187 EXPECT_EQ(64u, layer->texture.width()); 188 EXPECT_EQ(64u, layer->texture.height()); 189 190 EXPECT_TRUE(layer->wideColorGamut); 191 EXPECT_EQ(64u * 64u * 8u, layer->getSizeInBytes()); 192 193 // resized to use different object in pool 194 auto layer2 = pool.get(renderThread.renderState(), 128u, 128u, true); 195 pool.putOrDelete(layer2); 196 ASSERT_EQ(1u, pool.getCount()); 197 198 // add a non-wide gamut layer 199 auto layer3 = pool.get(renderThread.renderState(), 128u, 128u); 200 pool.putOrDelete(layer3); 201 ASSERT_EQ(2u, pool.getCount()); 202 203 ASSERT_EQ(layer2, pool.resize(layer, 120u, 125u)); 204 EXPECT_EQ(120u, layer2->viewportWidth); 205 EXPECT_EQ(125u, layer2->viewportHeight); 206 EXPECT_EQ(128u, layer2->texture.width()); 207 EXPECT_EQ(128u, layer2->texture.height()); 208 209 EXPECT_TRUE(layer2->wideColorGamut); 210 EXPECT_EQ(128u * 128u * 8u, layer2->getSizeInBytes()); 211 212 pool.putOrDelete(layer2); 213 } 214 215 RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, putAndDestroy) { 216 OffscreenBufferPool pool; 217 // layer too big to return to the pool 218 // Note: this relies on the fact that the pool won't reject based on max texture size 219 auto hugeLayer = pool.get(renderThread.renderState(), pool.getMaxSize() / 64, 64); 220 EXPECT_GT(hugeLayer->getSizeInBytes(), pool.getMaxSize()); 221 pool.putOrDelete(hugeLayer); 222 EXPECT_EQ(0u, pool.getCount()); // failed to put (so was destroyed instead) 223 } 224 225 RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, clear) { 226 EXPECT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer)); 227 OffscreenBufferPool pool; 228 229 // Create many buffers, with several at each size 230 std::vector<OffscreenBuffer*> buffers; 231 for (int size = 32; size <= 128; size += 32) { 232 for (int i = 0; i < 10; i++) { 233 buffers.push_back(pool.get(renderThread.renderState(), size, size)); 234 } 235 } 236 EXPECT_EQ(0u, pool.getCount()) << "Expect nothing inside"; 237 for (auto& buffer : buffers) pool.putOrDelete(buffer); 238 EXPECT_EQ(40u, pool.getCount()) << "Expect all items added"; 239 EXPECT_EQ(40, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer)); 240 pool.clear(); 241 EXPECT_EQ(0u, pool.getCount()) << "Expect all items cleared"; 242 243 EXPECT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer)); 244 } 245