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