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 #pragma once 18 19 #include <SkSurface.h> 20 #include <utils/FatVector.h> 21 #include <utils/RefBase.h> 22 #include <utils/Thread.h> 23 #include <list> 24 #include <map> 25 26 class GrRectanizer; 27 28 namespace android { 29 namespace uirenderer { 30 namespace skiapipeline { 31 32 typedef uintptr_t AtlasKey; 33 34 #define INVALID_ATLAS_KEY 0 35 36 struct AtlasEntry { 37 sk_sp<SkSurface> surface; 38 SkRect rect; 39 AtlasKey key = INVALID_ATLAS_KEY; 40 }; 41 42 /** 43 * VectorDrawableAtlas provides offscreen buffers used to draw VD and AnimatedVD. 44 * VectorDrawableAtlas can allocate a standalone surface or provide a subrect from a shared surface. 45 * VectorDrawableAtlas is owned by the CacheManager and weak pointers are kept by each 46 * VectorDrawable that is using it. VectorDrawableAtlas and its surface can be deleted at any time, 47 * except during a renderFrame call. VectorDrawable does not contain a pointer to atlas SkSurface 48 * nor any coordinates into the atlas, but instead holds a rectangle "id", which is resolved only 49 * when drawing. This design makes VectorDrawableAtlas free to move the data internally. 50 * At draw time a VectorDrawable may find, that its atlas has been deleted, which will make it 51 * draw in a standalone cache surface not part of an atlas. In this case VD won't use 52 * VectorDrawableAtlas until the next frame. 53 * VectorDrawableAtlas tries to fit VDs in the atlas SkSurface. If there is not enough space in 54 * the atlas, VectorDrawableAtlas creates a standalone surface for each VD. 55 * When a VectorDrawable is deleted, it invokes VectorDrawableAtlas::releaseEntry, which is keeping 56 * track of free spaces and allow to reuse the surface for another VD. 57 */ 58 // TODO: Check if not using atlas for AnimatedVD is more efficient. 59 // TODO: For low memory situations, when there are no paint effects in VD, we may render without an 60 // TODO: offscreen surface. 61 class VectorDrawableAtlas : public virtual RefBase { 62 public: 63 enum class StorageMode { allowSharedSurface, disallowSharedSurface }; 64 65 explicit VectorDrawableAtlas(size_t surfaceArea, 66 StorageMode storageMode = StorageMode::allowSharedSurface); 67 68 /** 69 * "prepareForDraw" may allocate a new surface if needed. It may schedule to repack the 70 * atlas at a later time. 71 */ 72 void prepareForDraw(GrContext* context); 73 74 /** 75 * Repack the atlas if needed, by moving used rectangles into a new atlas surface. 76 * The goal of repacking is to fix a fragmented atlas. 77 */ 78 void repackIfNeeded(GrContext* context); 79 80 /** 81 * Returns true if atlas is fragmented and repack is needed. 82 */ 83 bool isFragmented(); 84 85 /** 86 * "requestNewEntry" is called by VectorDrawable to allocate a new rectangle area from the atlas 87 * or create a standalone surface if atlas is full. 88 * On success it returns a non-negative unique id, which can be used later with "getEntry" and 89 * "releaseEntry". 90 */ 91 AtlasEntry requestNewEntry(int width, int height, GrContext* context); 92 93 /** 94 * "getEntry" extracts coordinates and surface of a previously created rectangle. 95 * "atlasKey" is an unique id created by "requestNewEntry". Passing a non-existing "atlasKey" is 96 * causing an undefined behaviour. 97 * On success it returns a rectangle Id -> may be same or different from "atlasKey" if 98 * implementation decides to move the record internally. 99 */ 100 AtlasEntry getEntry(AtlasKey atlasKey); 101 102 /** 103 * "releaseEntry" is invoked when a VectorDrawable is deleted. Passing a non-existing "atlasKey" 104 * is causing an undefined behaviour. This is the only function in the class that can be 105 * invoked from any thread. It will marshal internally to render thread if needed. 106 */ 107 void releaseEntry(AtlasKey atlasKey); 108 109 void setStorageMode(StorageMode mode); 110 111 /** 112 * "delayedReleaseEntries" is indirectly invoked by "releaseEntry", when "releaseEntry" is 113 * invoked from a non render thread. 114 */ 115 void delayedReleaseEntries(); 116 117 private: 118 struct CacheEntry { CacheEntryCacheEntry119 CacheEntry(const SkRect& newVDrect, const SkRect& newRect, 120 const sk_sp<SkSurface>& newSurface) 121 : VDrect(newVDrect), rect(newRect), surface(newSurface) {} 122 123 /** 124 * size and position of VectorDrawable into the atlas or in "this.surface" 125 */ 126 SkRect VDrect; 127 128 /** 129 * rect allocated in atlas surface or "this.surface". It may be bigger than "VDrect" 130 */ 131 SkRect rect; 132 133 /** 134 * this surface is used if atlas is full or VD is too big 135 */ 136 sk_sp<SkSurface> surface; 137 138 /** 139 * iterator is used to delete self with a constant complexity (without traversing the list) 140 */ 141 std::list<CacheEntry>::iterator eraseIt; 142 }; 143 144 /** 145 * atlas surface shared by all VDs 146 */ 147 sk_sp<SkSurface> mSurface; 148 149 std::unique_ptr<GrRectanizer> mRectanizer; 150 const int mWidth; 151 const int mHeight; 152 153 /** 154 * "mRects" keeps records only for rectangles used by VDs. List has nice properties: constant 155 * complexity to insert and erase and references are not invalidated by insert/erase. 156 */ 157 std::list<CacheEntry> mRects; 158 159 /** 160 * Rectangles freed by "releaseEntry" are removed from "mRects" and added to "mFreeRects". 161 * "mFreeRects" is using for an index the rectangle area. There could be more than one free 162 * rectangle with the same area, which is the reason to use "multimap" instead of "map". 163 */ 164 std::multimap<size_t, SkRect> mFreeRects; 165 166 /** 167 * area in atlas used by VectorDrawables (area in standalone surface not counted) 168 */ 169 int mPixelUsedByVDs = 0; 170 171 /** 172 * area allocated in mRectanizer 173 */ 174 int mPixelAllocated = 0; 175 176 /** 177 * Consecutive times we had to allocate standalone surfaces, because atlas was full. 178 */ 179 int mConsecutiveFailures = 0; 180 181 /** 182 * mStorageMode allows using a shared surface to store small vector drawables. 183 * Using a shared surface can boost the performance by allowing GL ops to be batched, but may 184 * consume more memory. 185 */ 186 StorageMode mStorageMode; 187 188 /** 189 * mKeysForRelease is used by releaseEntry implementation to pass atlas keys from an arbitrary 190 * calling thread to the render thread. 191 */ 192 std::vector<AtlasKey> mKeysForRelease; 193 194 /** 195 * A lock used to protect access to mKeysForRelease. 196 */ 197 Mutex mReleaseKeyLock; 198 199 sk_sp<SkSurface> createSurface(int width, int height, GrContext* context); 200 fitInAtlas(int width,int height)201 inline bool fitInAtlas(int width, int height) { 202 return 2 * width < mWidth && 2 * height < mHeight; 203 } 204 205 void repack(GrContext* context); 206 207 static bool compareCacheEntry(const CacheEntry& first, const CacheEntry& second); 208 }; 209 210 } /* namespace skiapipeline */ 211 } /* namespace uirenderer */ 212 } /* namespace android */ 213