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