Caches.cpp revision cf51a4199835e9604aa4c8b3854306f8fbabbf33
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>(), 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
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    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
100void Caches::initFont() {
101    fontRenderer = GammaFontRenderer::createRenderer();
102}
103
104void 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
125void 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
135bool 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
188void 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
210void Caches::dumpMemoryUsage() {
211    String8 stringLog;
212    dumpMemoryUsage(stringLog);
213    ALOGD("%s", stringLog.string());
214}
215
216void 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
259void 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
288void Caches::deleteLayerDeferred(Layer* layer) {
289    Mutex::Autolock _l(mGarbageLock);
290    mLayerGarbage.push(layer);
291}
292
293void Caches::deleteDisplayListDeferred(DisplayList* displayList) {
294    Mutex::Autolock _l(mGarbageLock);
295    mDisplayListGarbage.push(displayList);
296}
297
298void 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
329bool Caches::bindMeshBuffer() {
330    return bindMeshBuffer(meshBuffer);
331}
332
333bool 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
342bool Caches::unbindMeshBuffer() {
343    if (mCurrentBuffer) {
344        glBindBuffer(GL_ARRAY_BUFFER, 0);
345        mCurrentBuffer = 0;
346        return true;
347    }
348    return false;
349}
350
351bool 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
360bool 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
373bool 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
382bool 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
395void 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
404void 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
413void Caches::resetVertexPointers() {
414    mCurrentPositionPointer = this;
415    mCurrentTexCoordsPointer = this;
416}
417
418void Caches::resetTexCoordsVertexPointer() {
419    mCurrentTexCoordsPointer = this;
420}
421
422void Caches::enableTexCoordsVertexArray() {
423    if (!mTexCoordsArrayEnabled) {
424        glEnableVertexAttribArray(Program::kBindingTexCoords);
425        mCurrentTexCoordsPointer = this;
426        mTexCoordsArrayEnabled = true;
427    }
428}
429
430void Caches::disableTexCoordsVertexArray() {
431    if (mTexCoordsArrayEnabled) {
432        glDisableVertexAttribArray(Program::kBindingTexCoords);
433        mTexCoordsArrayEnabled = false;
434    }
435}
436
437void Caches::activeTexture(GLuint textureUnit) {
438    if (mTextureUnit != textureUnit) {
439        glActiveTexture(gTextureUnits[textureUnit]);
440        mTextureUnit = textureUnit;
441    }
442}
443
444///////////////////////////////////////////////////////////////////////////////
445// Scissor
446///////////////////////////////////////////////////////////////////////////////
447
448bool 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
478bool Caches::enableScissor() {
479    if (!scissorEnabled) {
480        glEnable(GL_SCISSOR_TEST);
481        scissorEnabled = true;
482        resetScissor();
483        return true;
484    }
485    return false;
486}
487
488bool Caches::disableScissor() {
489    if (scissorEnabled) {
490        glDisable(GL_SCISSOR_TEST);
491        scissorEnabled = false;
492        return true;
493    }
494    return false;
495}
496
497void 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
505void Caches::resetScissor() {
506    mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
507}
508
509///////////////////////////////////////////////////////////////////////////////
510// Tiling
511///////////////////////////////////////////////////////////////////////////////
512
513void 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
519void Caches::endTiling() {
520    if (mExtensions.hasTiledRendering() && !debugOverdraw) {
521        glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM);
522    }
523}
524
525bool Caches::hasRegisteredFunctors() {
526    return mFunctorsCount > 0;
527}
528
529void Caches::registerFunctors(uint32_t functorCount) {
530    mFunctorsCount += functorCount;
531}
532
533void 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
545TextureVertex* 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