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