1 /* 2 * Copyright (C) 2017 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 <gtest/gtest.h> 18 19 #include <GrRectanizer.h> 20 #include "pipeline/skia/VectorDrawableAtlas.h" 21 #include "tests/common/TestUtils.h" 22 23 using namespace android; 24 using namespace android::uirenderer; 25 using namespace android::uirenderer::renderthread; 26 using namespace android::uirenderer::skiapipeline; 27 28 RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, addGetRemove) { 29 VectorDrawableAtlas atlas(100 * 100); 30 atlas.prepareForDraw(renderThread.getGrContext()); 31 // create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects) 32 const int MAX_RECTS = 150; 33 AtlasEntry VDRects[MAX_RECTS]; 34 35 sk_sp<SkSurface> atlasSurface; 36 37 // check we are able to allocate new rects 38 // check that rects in the atlas do not intersect 39 for (uint32_t i = 0; i < MAX_RECTS; i++) { 40 VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext()); 41 if (0 == i) { 42 atlasSurface = VDRects[0].surface; 43 } 44 ASSERT_TRUE(VDRects[i].key != INVALID_ATLAS_KEY); 45 ASSERT_TRUE(VDRects[i].surface.get() != nullptr); 46 ASSERT_TRUE(VDRects[i].rect.width() == 10 && VDRects[i].rect.height() == 10); 47 48 // nothing in the atlas should intersect 49 if (atlasSurface.get() == VDRects[i].surface.get()) { 50 for (uint32_t j = 0; j < i; j++) { 51 if (atlasSurface.get() == VDRects[j].surface.get()) { 52 ASSERT_FALSE(VDRects[i].rect.intersect(VDRects[j].rect)); 53 } 54 } 55 } 56 } 57 58 // first 1/3 rects should all be in the same surface 59 for (uint32_t i = 1; i < MAX_RECTS / 3; i++) { 60 ASSERT_NE(VDRects[i].key, VDRects[0].key); 61 ASSERT_EQ(VDRects[i].surface.get(), atlasSurface.get()); 62 } 63 64 // first rect is using atlas and last is a standalone surface 65 ASSERT_NE(VDRects[0].surface.get(), VDRects[MAX_RECTS - 1].surface.get()); 66 67 // check getEntry returns the same surfaces that we had created 68 for (uint32_t i = 0; i < MAX_RECTS; i++) { 69 auto VDRect = atlas.getEntry(VDRects[i].key); 70 ASSERT_TRUE(VDRect.key != INVALID_ATLAS_KEY); 71 ASSERT_EQ(VDRects[i].key, VDRect.key); 72 ASSERT_EQ(VDRects[i].surface.get(), VDRect.surface.get()); 73 ASSERT_EQ(VDRects[i].rect, VDRect.rect); 74 atlas.releaseEntry(VDRect.key); 75 } 76 77 // check that any new rects will be allocated in the atlas, even that rectanizer is full. 78 // rects in the atlas should not intersect. 79 for (uint32_t i = 0; i < MAX_RECTS / 3; i++) { 80 VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext()); 81 ASSERT_TRUE(VDRects[i].key != INVALID_ATLAS_KEY); 82 ASSERT_EQ(VDRects[i].surface.get(), atlasSurface.get()); 83 ASSERT_TRUE(VDRects[i].rect.width() == 10 && VDRects[i].rect.height() == 10); 84 for (uint32_t j = 0; j < i; j++) { 85 ASSERT_FALSE(VDRects[i].rect.intersect(VDRects[j].rect)); 86 } 87 } 88 } 89 90 RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, disallowSharedSurface) { 91 VectorDrawableAtlas atlas(100 * 100); 92 // don't allow to use a shared surface 93 atlas.setStorageMode(VectorDrawableAtlas::StorageMode::disallowSharedSurface); 94 atlas.prepareForDraw(renderThread.getGrContext()); 95 // create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects) 96 const int MAX_RECTS = 150; 97 AtlasEntry VDRects[MAX_RECTS]; 98 99 // check we are able to allocate new rects 100 // check that rects in the atlas use unique surfaces 101 for (uint32_t i = 0; i < MAX_RECTS; i++) { 102 VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext()); 103 ASSERT_TRUE(VDRects[i].key != INVALID_ATLAS_KEY); 104 ASSERT_TRUE(VDRects[i].surface.get() != nullptr); 105 ASSERT_TRUE(VDRects[i].rect.width() == 10 && VDRects[i].rect.height() == 10); 106 107 // nothing in the atlas should use the same surface 108 for (uint32_t j = 0; j < i; j++) { 109 ASSERT_NE(VDRects[i].surface.get(), VDRects[j].surface.get()); 110 } 111 } 112 } 113 114 RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, repack) { 115 VectorDrawableAtlas atlas(100 * 100); 116 ASSERT_FALSE(atlas.isFragmented()); 117 atlas.prepareForDraw(renderThread.getGrContext()); 118 ASSERT_FALSE(atlas.isFragmented()); 119 // create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects) 120 const int MAX_RECTS = 150; 121 AtlasEntry VDRects[MAX_RECTS]; 122 123 sk_sp<SkSurface> atlasSurface; 124 125 // fill the atlas with check we are able to allocate new rects 126 for (uint32_t i = 0; i < MAX_RECTS; i++) { 127 VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext()); 128 if (0 == i) { 129 atlasSurface = VDRects[0].surface; 130 } 131 ASSERT_TRUE(VDRects[i].key != INVALID_ATLAS_KEY); 132 } 133 134 ASSERT_FALSE(atlas.isFragmented()); 135 136 // first 1/3 rects should all be in the same surface 137 for (uint32_t i = 1; i < MAX_RECTS / 3; i++) { 138 ASSERT_NE(VDRects[i].key, VDRects[0].key); 139 ASSERT_EQ(VDRects[i].surface.get(), atlasSurface.get()); 140 } 141 142 // release all entries 143 for (uint32_t i = 0; i < MAX_RECTS; i++) { 144 auto VDRect = atlas.getEntry(VDRects[i].key); 145 ASSERT_TRUE(VDRect.key != INVALID_ATLAS_KEY); 146 atlas.releaseEntry(VDRect.key); 147 } 148 149 ASSERT_FALSE(atlas.isFragmented()); 150 151 // allocate 4x4 rects, which will fragment the atlas badly, because each entry occupies a 10x10 152 // area 153 for (uint32_t i = 0; i < 4 * MAX_RECTS; i++) { 154 AtlasEntry entry = atlas.requestNewEntry(4, 4, renderThread.getGrContext()); 155 ASSERT_TRUE(entry.key != INVALID_ATLAS_KEY); 156 } 157 158 ASSERT_TRUE(atlas.isFragmented()); 159 160 atlas.repackIfNeeded(renderThread.getGrContext()); 161 162 ASSERT_FALSE(atlas.isFragmented()); 163 }