• 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>(), 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