1 /*
2 * Copyright (C) 2010 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 "Caches.h"
18
19 #include "GammaFontRenderer.h"
20 #include "LayerRenderer.h"
21 #include "Properties.h"
22 #include "renderstate/RenderState.h"
23 #include "ShadowTessellator.h"
24 #ifdef BUGREPORT_FONT_CACHE_USAGE
25 #include "font/FontCacheHistoryTracker.h"
26 #endif
27 #include "utils/GLUtils.h"
28
29 #include <cutils/properties.h>
30 #include <utils/Log.h>
31 #include <utils/String8.h>
32
33 namespace android {
34 namespace uirenderer {
35
36 Caches* Caches::sInstance = nullptr;
37
38 ///////////////////////////////////////////////////////////////////////////////
39 // Macros
40 ///////////////////////////////////////////////////////////////////////////////
41
42 #if DEBUG_CACHE_FLUSH
43 #define FLUSH_LOGD(...) ALOGD(__VA_ARGS__)
44 #else
45 #define FLUSH_LOGD(...)
46 #endif
47
48 ///////////////////////////////////////////////////////////////////////////////
49 // Constructors/destructor
50 ///////////////////////////////////////////////////////////////////////////////
51
Caches(RenderState & renderState)52 Caches::Caches(RenderState& renderState)
53 : gradientCache(mExtensions)
54 , patchCache(renderState)
55 , programCache(mExtensions)
56 , dither(*this)
57 , mRenderState(&renderState)
58 , mInitialized(false) {
59 INIT_LOGD("Creating OpenGL renderer caches");
60 init();
61 initConstraints();
62 initStaticProperties();
63 initExtensions();
64 }
65
init()66 bool Caches::init() {
67 if (mInitialized) return false;
68
69 ATRACE_NAME("Caches::init");
70
71 mRegionMesh = nullptr;
72 mProgram = nullptr;
73
74 patchCache.init();
75
76 mInitialized = true;
77
78 mPixelBufferState = new PixelBufferState();
79 mTextureState = new TextureState();
80 mTextureState->constructTexture(*this);
81
82 return true;
83 }
84
initExtensions()85 void Caches::initExtensions() {
86 if (mExtensions.hasDebugMarker()) {
87 eventMark = glInsertEventMarkerEXT;
88
89 startMark = glPushGroupMarkerEXT;
90 endMark = glPopGroupMarkerEXT;
91 } else {
92 eventMark = eventMarkNull;
93 startMark = startMarkNull;
94 endMark = endMarkNull;
95 }
96 }
97
initConstraints()98 void Caches::initConstraints() {
99 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
100 }
101
initStaticProperties()102 void Caches::initStaticProperties() {
103 // OpenGL ES 3.0+ specific features
104 gpuPixelBuffersEnabled = mExtensions.hasPixelBufferObjects()
105 && property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true);
106 }
107
terminate()108 void Caches::terminate() {
109 if (!mInitialized) return;
110 mRegionMesh.reset(nullptr);
111
112 fboCache.clear();
113
114 programCache.clear();
115 mProgram = nullptr;
116
117 patchCache.clear();
118
119 clearGarbage();
120
121 delete mPixelBufferState;
122 mPixelBufferState = nullptr;
123 delete mTextureState;
124 mTextureState = nullptr;
125 mInitialized = false;
126 }
127
setProgram(const ProgramDescription & description)128 void Caches::setProgram(const ProgramDescription& description) {
129 setProgram(programCache.get(description));
130 }
131
setProgram(Program * program)132 void Caches::setProgram(Program* program) {
133 if (!program || !program->isInUse()) {
134 if (mProgram) {
135 mProgram->remove();
136 }
137 if (program) {
138 program->use();
139 }
140 mProgram = program;
141 }
142 }
143
144 ///////////////////////////////////////////////////////////////////////////////
145 // Debug
146 ///////////////////////////////////////////////////////////////////////////////
147
getOverdrawColor(uint32_t amount) const148 uint32_t Caches::getOverdrawColor(uint32_t amount) const {
149 static uint32_t sOverdrawColors[2][4] = {
150 { 0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000 },
151 { 0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000 }
152 };
153 if (amount < 1) amount = 1;
154 if (amount > 4) amount = 4;
155
156 int overdrawColorIndex = static_cast<int>(Properties::overdrawColorSet);
157 return sOverdrawColors[overdrawColorIndex][amount - 1];
158 }
159
dumpMemoryUsage()160 void Caches::dumpMemoryUsage() {
161 String8 stringLog;
162 dumpMemoryUsage(stringLog);
163 ALOGD("%s", stringLog.string());
164 }
165
dumpMemoryUsage(String8 & log)166 void Caches::dumpMemoryUsage(String8 &log) {
167 uint32_t total = 0;
168 log.appendFormat("Current memory usage / total memory usage (bytes):\n");
169 log.appendFormat(" TextureCache %8d / %8d\n",
170 textureCache.getSize(), textureCache.getMaxSize());
171 log.appendFormat(" LayerCache %8d / %8d (numLayers = %zu)\n",
172 layerCache.getSize(), layerCache.getMaxSize(), layerCache.getCount());
173 if (mRenderState) {
174 int memused = 0;
175 for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin();
176 it != mRenderState->mActiveLayers.end(); it++) {
177 const Layer* layer = *it;
178 log.appendFormat(" Layer size %dx%d; isTextureLayer()=%d; texid=%u fbo=%u; refs=%d\n",
179 layer->getWidth(), layer->getHeight(),
180 layer->isTextureLayer(), layer->getTextureId(),
181 layer->getFbo(), layer->getStrongCount());
182 memused += layer->getWidth() * layer->getHeight() * 4;
183 }
184 log.appendFormat(" Layers total %8d (numLayers = %zu)\n",
185 memused, mRenderState->mActiveLayers.size());
186 total += memused;
187 }
188 log.appendFormat(" RenderBufferCache %8d / %8d\n",
189 renderBufferCache.getSize(), renderBufferCache.getMaxSize());
190 log.appendFormat(" GradientCache %8d / %8d\n",
191 gradientCache.getSize(), gradientCache.getMaxSize());
192 log.appendFormat(" PathCache %8d / %8d\n",
193 pathCache.getSize(), pathCache.getMaxSize());
194 log.appendFormat(" TessellationCache %8d / %8d\n",
195 tessellationCache.getSize(), tessellationCache.getMaxSize());
196 log.appendFormat(" TextDropShadowCache %8d / %8d\n", dropShadowCache.getSize(),
197 dropShadowCache.getMaxSize());
198 log.appendFormat(" PatchCache %8d / %8d\n",
199 patchCache.getSize(), patchCache.getMaxSize());
200
201 fontRenderer.dumpMemoryUsage(log);
202
203 log.appendFormat("Other:\n");
204 log.appendFormat(" FboCache %8d / %8d\n",
205 fboCache.getSize(), fboCache.getMaxSize());
206
207 total += textureCache.getSize();
208 total += renderBufferCache.getSize();
209 total += gradientCache.getSize();
210 total += pathCache.getSize();
211 total += tessellationCache.getSize();
212 total += dropShadowCache.getSize();
213 total += patchCache.getSize();
214 total += fontRenderer.getSize();
215
216 log.appendFormat("Total memory usage:\n");
217 log.appendFormat(" %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
218
219 #ifdef BUGREPORT_FONT_CACHE_USAGE
220 fontRenderer.getFontRenderer().historyTracker().dump(log);
221 #endif
222 }
223
224 ///////////////////////////////////////////////////////////////////////////////
225 // Memory management
226 ///////////////////////////////////////////////////////////////////////////////
227
clearGarbage()228 void Caches::clearGarbage() {
229 textureCache.clearGarbage();
230 pathCache.clearGarbage();
231 patchCache.clearGarbage();
232 }
233
flush(FlushMode mode)234 void Caches::flush(FlushMode mode) {
235 FLUSH_LOGD("Flushing caches (mode %d)", mode);
236
237 switch (mode) {
238 case FlushMode::Full:
239 textureCache.clear();
240 patchCache.clear();
241 dropShadowCache.clear();
242 gradientCache.clear();
243 fontRenderer.clear();
244 fboCache.clear();
245 dither.clear();
246 // fall through
247 case FlushMode::Moderate:
248 fontRenderer.flush();
249 textureCache.flush();
250 pathCache.clear();
251 tessellationCache.clear();
252 // fall through
253 case FlushMode::Layers:
254 layerCache.clear();
255 renderBufferCache.clear();
256 break;
257 }
258
259 clearGarbage();
260 glFinish();
261 // Errors during cleanup should be considered non-fatal, dump them and
262 // and move on. TODO: All errors or just errors like bad surface?
263 GLUtils::dumpGLErrors();
264 }
265
266 ///////////////////////////////////////////////////////////////////////////////
267 // Regions
268 ///////////////////////////////////////////////////////////////////////////////
269
getRegionMesh()270 TextureVertex* Caches::getRegionMesh() {
271 // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
272 if (!mRegionMesh) {
273 mRegionMesh.reset(new TextureVertex[kMaxNumberOfQuads * 4]);
274 }
275
276 return mRegionMesh.get();
277 }
278
279 ///////////////////////////////////////////////////////////////////////////////
280 // Temporary Properties
281 ///////////////////////////////////////////////////////////////////////////////
282
283 }; // namespace uirenderer
284 }; // namespace android
285