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