• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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