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