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 <utils/Log.h>
20 #include <utils/String8.h>
21
22 #include "Caches.h"
23 #include "DisplayListRenderer.h"
24 #include "Properties.h"
25 #include "LayerRenderer.h"
26
27 namespace android {
28
29 #ifdef USE_OPENGL_RENDERER
30 using namespace uirenderer;
31 ANDROID_SINGLETON_STATIC_INSTANCE(Caches);
32 #endif
33
34 namespace uirenderer {
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()50 Caches::Caches(): Singleton<Caches>(), mInitialized(false) {
51 init();
52 initFont();
53 initExtensions();
54 initConstraints();
55 initProperties();
56
57 mDebugLevel = readDebugLevel();
58 ALOGD("Enabling debug mode %d", mDebugLevel);
59 }
60
init()61 void Caches::init() {
62 if (mInitialized) return;
63
64 glGenBuffers(1, &meshBuffer);
65 glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
66 glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
67
68 mCurrentBuffer = meshBuffer;
69 mCurrentIndicesBuffer = 0;
70 mCurrentPositionPointer = this;
71 mCurrentPositionStride = 0;
72 mCurrentTexCoordsPointer = this;
73
74 mTexCoordsArrayEnabled = false;
75
76 glDisable(GL_SCISSOR_TEST);
77 scissorEnabled = false;
78 mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
79
80 glActiveTexture(gTextureUnits[0]);
81 mTextureUnit = 0;
82
83 mRegionMesh = NULL;
84
85 blend = false;
86 lastSrcMode = GL_ZERO;
87 lastDstMode = GL_ZERO;
88 currentProgram = NULL;
89
90 mFunctorsCount = 0;
91
92 mInitialized = true;
93 }
94
initFont()95 void Caches::initFont() {
96 fontRenderer = GammaFontRenderer::createRenderer();
97 }
98
initExtensions()99 void Caches::initExtensions() {
100 if (extensions.hasDebugMarker()) {
101 eventMark = glInsertEventMarkerEXT;
102 startMark = glPushGroupMarkerEXT;
103 endMark = glPopGroupMarkerEXT;
104 } else {
105 eventMark = eventMarkNull;
106 startMark = startMarkNull;
107 endMark = endMarkNull;
108 }
109
110 if (extensions.hasDebugLabel()) {
111 setLabel = glLabelObjectEXT;
112 getLabel = glGetObjectLabelEXT;
113 } else {
114 setLabel = setLabelNull;
115 getLabel = getLabelNull;
116 }
117 }
118
initConstraints()119 void Caches::initConstraints() {
120 GLint maxTextureUnits;
121 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
122 if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
123 ALOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
124 }
125
126 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
127 }
128
initProperties()129 void Caches::initProperties() {
130 char property[PROPERTY_VALUE_MAX];
131 if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, NULL) > 0) {
132 INIT_LOGD(" Layers updates debug enabled: %s", property);
133 debugLayersUpdates = !strcmp(property, "true");
134 } else {
135 debugLayersUpdates = false;
136 }
137
138 if (property_get(PROPERTY_DEBUG_OVERDRAW, property, NULL) > 0) {
139 INIT_LOGD(" Overdraw debug enabled: %s", property);
140 debugOverdraw = !strcmp(property, "true");
141 } else {
142 debugOverdraw = false;
143 }
144 }
145
terminate()146 void Caches::terminate() {
147 if (!mInitialized) return;
148
149 glDeleteBuffers(1, &meshBuffer);
150 mCurrentBuffer = 0;
151
152 glDeleteBuffers(1, &mRegionMeshIndices);
153 delete[] mRegionMesh;
154 mRegionMesh = NULL;
155
156 fboCache.clear();
157
158 programCache.clear();
159 currentProgram = NULL;
160
161 mInitialized = false;
162 }
163
164 ///////////////////////////////////////////////////////////////////////////////
165 // Debug
166 ///////////////////////////////////////////////////////////////////////////////
167
dumpMemoryUsage()168 void Caches::dumpMemoryUsage() {
169 String8 stringLog;
170 dumpMemoryUsage(stringLog);
171 ALOGD("%s", stringLog.string());
172 }
173
dumpMemoryUsage(String8 & log)174 void Caches::dumpMemoryUsage(String8 &log) {
175 log.appendFormat("Current memory usage / total memory usage (bytes):\n");
176 log.appendFormat(" TextureCache %8d / %8d\n",
177 textureCache.getSize(), textureCache.getMaxSize());
178 log.appendFormat(" LayerCache %8d / %8d\n",
179 layerCache.getSize(), layerCache.getMaxSize());
180 log.appendFormat(" GradientCache %8d / %8d\n",
181 gradientCache.getSize(), gradientCache.getMaxSize());
182 log.appendFormat(" PathCache %8d / %8d\n",
183 pathCache.getSize(), pathCache.getMaxSize());
184 log.appendFormat(" CircleShapeCache %8d / %8d\n",
185 circleShapeCache.getSize(), circleShapeCache.getMaxSize());
186 log.appendFormat(" OvalShapeCache %8d / %8d\n",
187 ovalShapeCache.getSize(), ovalShapeCache.getMaxSize());
188 log.appendFormat(" RoundRectShapeCache %8d / %8d\n",
189 roundRectShapeCache.getSize(), roundRectShapeCache.getMaxSize());
190 log.appendFormat(" RectShapeCache %8d / %8d\n",
191 rectShapeCache.getSize(), rectShapeCache.getMaxSize());
192 log.appendFormat(" ArcShapeCache %8d / %8d\n",
193 arcShapeCache.getSize(), arcShapeCache.getMaxSize());
194 log.appendFormat(" TextDropShadowCache %8d / %8d\n", dropShadowCache.getSize(),
195 dropShadowCache.getMaxSize());
196 for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
197 const uint32_t size = fontRenderer->getFontRendererSize(i);
198 log.appendFormat(" FontRenderer %d %8d / %8d\n", i, size, size);
199 }
200 log.appendFormat("Other:\n");
201 log.appendFormat(" FboCache %8d / %8d\n",
202 fboCache.getSize(), fboCache.getMaxSize());
203 log.appendFormat(" PatchCache %8d / %8d\n",
204 patchCache.getSize(), patchCache.getMaxSize());
205
206 uint32_t total = 0;
207 total += textureCache.getSize();
208 total += layerCache.getSize();
209 total += gradientCache.getSize();
210 total += pathCache.getSize();
211 total += dropShadowCache.getSize();
212 total += roundRectShapeCache.getSize();
213 total += circleShapeCache.getSize();
214 total += ovalShapeCache.getSize();
215 total += rectShapeCache.getSize();
216 total += arcShapeCache.getSize();
217 for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
218 total += fontRenderer->getFontRendererSize(i);
219 }
220
221 log.appendFormat("Total memory usage:\n");
222 log.appendFormat(" %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
223 }
224
225 ///////////////////////////////////////////////////////////////////////////////
226 // Memory management
227 ///////////////////////////////////////////////////////////////////////////////
228
clearGarbage()229 void Caches::clearGarbage() {
230 textureCache.clearGarbage();
231 pathCache.clearGarbage();
232
233 Vector<DisplayList*> displayLists;
234 Vector<Layer*> layers;
235
236 { // scope for the lock
237 Mutex::Autolock _l(mGarbageLock);
238 displayLists = mDisplayListGarbage;
239 layers = mLayerGarbage;
240 mDisplayListGarbage.clear();
241 mLayerGarbage.clear();
242 }
243
244 size_t count = displayLists.size();
245 for (size_t i = 0; i < count; i++) {
246 DisplayList* displayList = displayLists.itemAt(i);
247 delete displayList;
248 }
249
250 count = layers.size();
251 for (size_t i = 0; i < count; i++) {
252 Layer* layer = layers.itemAt(i);
253 delete layer;
254 }
255 layers.clear();
256 }
257
deleteLayerDeferred(Layer * layer)258 void Caches::deleteLayerDeferred(Layer* layer) {
259 Mutex::Autolock _l(mGarbageLock);
260 mLayerGarbage.push(layer);
261 }
262
deleteDisplayListDeferred(DisplayList * displayList)263 void Caches::deleteDisplayListDeferred(DisplayList* displayList) {
264 Mutex::Autolock _l(mGarbageLock);
265 mDisplayListGarbage.push(displayList);
266 }
267
flush(FlushMode mode)268 void Caches::flush(FlushMode mode) {
269 FLUSH_LOGD("Flushing caches (mode %d)", mode);
270
271 switch (mode) {
272 case kFlushMode_Full:
273 textureCache.clear();
274 patchCache.clear();
275 dropShadowCache.clear();
276 gradientCache.clear();
277 fontRenderer->clear();
278 dither.clear();
279 // fall through
280 case kFlushMode_Moderate:
281 fontRenderer->flush();
282 textureCache.flush();
283 pathCache.clear();
284 roundRectShapeCache.clear();
285 circleShapeCache.clear();
286 ovalShapeCache.clear();
287 rectShapeCache.clear();
288 arcShapeCache.clear();
289 // fall through
290 case kFlushMode_Layers:
291 layerCache.clear();
292 break;
293 }
294
295 clearGarbage();
296 }
297
298 ///////////////////////////////////////////////////////////////////////////////
299 // VBO
300 ///////////////////////////////////////////////////////////////////////////////
301
bindMeshBuffer()302 bool Caches::bindMeshBuffer() {
303 return bindMeshBuffer(meshBuffer);
304 }
305
bindMeshBuffer(const GLuint buffer)306 bool Caches::bindMeshBuffer(const GLuint buffer) {
307 if (mCurrentBuffer != buffer) {
308 glBindBuffer(GL_ARRAY_BUFFER, buffer);
309 mCurrentBuffer = buffer;
310 return true;
311 }
312 return false;
313 }
314
unbindMeshBuffer()315 bool Caches::unbindMeshBuffer() {
316 if (mCurrentBuffer) {
317 glBindBuffer(GL_ARRAY_BUFFER, 0);
318 mCurrentBuffer = 0;
319 return true;
320 }
321 return false;
322 }
323
bindIndicesBuffer(const GLuint buffer)324 bool Caches::bindIndicesBuffer(const GLuint buffer) {
325 if (mCurrentIndicesBuffer != buffer) {
326 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
327 mCurrentIndicesBuffer = buffer;
328 return true;
329 }
330 return false;
331 }
332
unbindIndicesBuffer()333 bool Caches::unbindIndicesBuffer() {
334 if (mCurrentIndicesBuffer) {
335 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
336 mCurrentIndicesBuffer = 0;
337 return true;
338 }
339 return false;
340 }
341
342 ///////////////////////////////////////////////////////////////////////////////
343 // Meshes and textures
344 ///////////////////////////////////////////////////////////////////////////////
345
bindPositionVertexPointer(bool force,GLvoid * vertices,GLsizei stride)346 void Caches::bindPositionVertexPointer(bool force, GLvoid* vertices, GLsizei stride) {
347 if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
348 GLuint slot = currentProgram->position;
349 glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
350 mCurrentPositionPointer = vertices;
351 mCurrentPositionStride = stride;
352 }
353 }
354
bindTexCoordsVertexPointer(bool force,GLvoid * vertices)355 void Caches::bindTexCoordsVertexPointer(bool force, GLvoid* vertices) {
356 if (force || vertices != mCurrentTexCoordsPointer) {
357 GLuint slot = currentProgram->texCoords;
358 glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, gMeshStride, vertices);
359 mCurrentTexCoordsPointer = vertices;
360 }
361 }
362
resetVertexPointers()363 void Caches::resetVertexPointers() {
364 mCurrentPositionPointer = this;
365 mCurrentTexCoordsPointer = this;
366 }
367
resetTexCoordsVertexPointer()368 void Caches::resetTexCoordsVertexPointer() {
369 mCurrentTexCoordsPointer = this;
370 }
371
enableTexCoordsVertexArray()372 void Caches::enableTexCoordsVertexArray() {
373 if (!mTexCoordsArrayEnabled) {
374 glEnableVertexAttribArray(Program::kBindingTexCoords);
375 mCurrentTexCoordsPointer = this;
376 mTexCoordsArrayEnabled = true;
377 }
378 }
379
disbaleTexCoordsVertexArray()380 void Caches::disbaleTexCoordsVertexArray() {
381 if (mTexCoordsArrayEnabled) {
382 glDisableVertexAttribArray(Program::kBindingTexCoords);
383 mTexCoordsArrayEnabled = false;
384 }
385 }
386
activeTexture(GLuint textureUnit)387 void Caches::activeTexture(GLuint textureUnit) {
388 if (mTextureUnit != textureUnit) {
389 glActiveTexture(gTextureUnits[textureUnit]);
390 mTextureUnit = textureUnit;
391 }
392 }
393
394 ///////////////////////////////////////////////////////////////////////////////
395 // Scissor
396 ///////////////////////////////////////////////////////////////////////////////
397
setScissor(GLint x,GLint y,GLint width,GLint height)398 bool Caches::setScissor(GLint x, GLint y, GLint width, GLint height) {
399 if (scissorEnabled && (x != mScissorX || y != mScissorY ||
400 width != mScissorWidth || height != mScissorHeight)) {
401
402 if (x < 0) {
403 width += x;
404 x = 0;
405 }
406 if (y < 0) {
407 height += y;
408 y = 0;
409 }
410 if (width < 0) {
411 width = 0;
412 }
413 if (height < 0) {
414 height = 0;
415 }
416 glScissor(x, y, width, height);
417
418 mScissorX = x;
419 mScissorY = y;
420 mScissorWidth = width;
421 mScissorHeight = height;
422
423 return true;
424 }
425 return false;
426 }
427
enableScissor()428 bool Caches::enableScissor() {
429 if (!scissorEnabled) {
430 glEnable(GL_SCISSOR_TEST);
431 scissorEnabled = true;
432 resetScissor();
433 return true;
434 }
435 return false;
436 }
437
disableScissor()438 bool Caches::disableScissor() {
439 if (scissorEnabled) {
440 glDisable(GL_SCISSOR_TEST);
441 scissorEnabled = false;
442 return true;
443 }
444 return false;
445 }
446
setScissorEnabled(bool enabled)447 void Caches::setScissorEnabled(bool enabled) {
448 if (scissorEnabled != enabled) {
449 if (enabled) glEnable(GL_SCISSOR_TEST);
450 else glDisable(GL_SCISSOR_TEST);
451 scissorEnabled = enabled;
452 }
453 }
454
resetScissor()455 void Caches::resetScissor() {
456 mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
457 }
458
459 ///////////////////////////////////////////////////////////////////////////////
460 // Tiling
461 ///////////////////////////////////////////////////////////////////////////////
462
startTiling(GLuint x,GLuint y,GLuint width,GLuint height,bool opaque)463 void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool opaque) {
464 if (extensions.hasTiledRendering() && !debugOverdraw) {
465 glStartTilingQCOM(x, y, width, height, (opaque ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM));
466 }
467 }
468
endTiling()469 void Caches::endTiling() {
470 if (extensions.hasTiledRendering() && !debugOverdraw) {
471 glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM);
472 }
473 }
474
hasRegisteredFunctors()475 bool Caches::hasRegisteredFunctors() {
476 return mFunctorsCount > 0;
477 }
478
registerFunctors(uint32_t functorCount)479 void Caches::registerFunctors(uint32_t functorCount) {
480 mFunctorsCount += functorCount;
481 }
482
unregisterFunctors(uint32_t functorCount)483 void Caches::unregisterFunctors(uint32_t functorCount) {
484 if (functorCount > mFunctorsCount) {
485 mFunctorsCount = 0;
486 } else {
487 mFunctorsCount -= functorCount;
488 }
489 }
490
491 ///////////////////////////////////////////////////////////////////////////////
492 // Regions
493 ///////////////////////////////////////////////////////////////////////////////
494
getRegionMesh()495 TextureVertex* Caches::getRegionMesh() {
496 // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
497 if (!mRegionMesh) {
498 mRegionMesh = new TextureVertex[REGION_MESH_QUAD_COUNT * 4];
499
500 uint16_t* regionIndices = new uint16_t[REGION_MESH_QUAD_COUNT * 6];
501 for (int i = 0; i < REGION_MESH_QUAD_COUNT; i++) {
502 uint16_t quad = i * 4;
503 int index = i * 6;
504 regionIndices[index ] = quad; // top-left
505 regionIndices[index + 1] = quad + 1; // top-right
506 regionIndices[index + 2] = quad + 2; // bottom-left
507 regionIndices[index + 3] = quad + 2; // bottom-left
508 regionIndices[index + 4] = quad + 1; // top-right
509 regionIndices[index + 5] = quad + 3; // bottom-right
510 }
511
512 glGenBuffers(1, &mRegionMeshIndices);
513 bindIndicesBuffer(mRegionMeshIndices);
514 glBufferData(GL_ELEMENT_ARRAY_BUFFER, REGION_MESH_QUAD_COUNT * 6 * sizeof(uint16_t),
515 regionIndices, GL_STATIC_DRAW);
516
517 delete[] regionIndices;
518 } else {
519 bindIndicesBuffer(mRegionMeshIndices);
520 }
521
522 return mRegionMesh;
523 }
524
525 }; // namespace uirenderer
526 }; // namespace android
527