blob: 5e892aa7e92cc653fb947092a6c0dcb65ebc6421 [file] [log] [blame]
Stan Iliev3310fb12017-03-23 16:56:51 -04001/*
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
Stan Iliev3310fb12017-03-23 16:56:51 -040019#include <SkSurface.h>
20#include <utils/FatVector.h>
21#include <utils/RefBase.h>
Stan Iliev6b894d72017-08-23 12:41:41 -040022#include <utils/Thread.h>
Stan Iliev3310fb12017-03-23 16:56:51 -040023#include <list>
John Reck1bcacfd2017-11-03 10:12:19 -070024#include <map>
Stan Iliev3310fb12017-03-23 16:56:51 -040025
26class GrRectanizer;
27
28namespace android {
29namespace uirenderer {
30namespace skiapipeline {
31
32typedef uintptr_t AtlasKey;
33
34#define INVALID_ATLAS_KEY 0
35
36struct 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 */
John Reck1bcacfd2017-11-03 10:12:19 -070058// 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.
Stan Iliev3310fb12017-03-23 16:56:51 -040061class VectorDrawableAtlas : public virtual RefBase {
62public:
John Reck1bcacfd2017-11-03 10:12:19 -070063 enum class StorageMode { allowSharedSurface, disallowSharedSurface };
Stan Iliev3310fb12017-03-23 16:56:51 -040064
Chih-Hung Hsiehf9336412018-12-20 13:48:57 -080065 explicit VectorDrawableAtlas(size_t surfaceArea,
66 StorageMode storageMode = StorageMode::allowSharedSurface);
Stan Iliev3310fb12017-03-23 16:56:51 -040067
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"
Stan Iliev6b894d72017-08-23 12:41:41 -0400104 * 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.
Stan Iliev3310fb12017-03-23 16:56:51 -0400106 */
107 void releaseEntry(AtlasKey atlasKey);
108
109 void setStorageMode(StorageMode mode);
110
Stan Iliev6b894d72017-08-23 12:41:41 -0400111 /**
112 * "delayedReleaseEntries" is indirectly invoked by "releaseEntry", when "releaseEntry" is
113 * invoked from a non render thread.
114 */
115 void delayedReleaseEntries();
116
Stan Iliev3310fb12017-03-23 16:56:51 -0400117private:
118 struct CacheEntry {
119 CacheEntry(const SkRect& newVDrect, const SkRect& newRect,
John Reck1bcacfd2017-11-03 10:12:19 -0700120 const sk_sp<SkSurface>& newSurface)
121 : VDrect(newVDrect), rect(newRect), surface(newSurface) {}
Stan Iliev3310fb12017-03-23 16:56:51 -0400122
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
Stan Iliev6b894d72017-08-23 12:41:41 -0400188 /**
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
Stan Iliev3310fb12017-03-23 16:56:51 -0400199 sk_sp<SkSurface> createSurface(int width, int height, GrContext* context);
200
201 inline bool fitInAtlas(int width, int height) {
John Reck1bcacfd2017-11-03 10:12:19 -0700202 return 2 * width < mWidth && 2 * height < mHeight;
Stan Iliev3310fb12017-03-23 16:56:51 -0400203 }
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 */