Caches.cpp revision f9f0016b1ff816eb2c7561eed482c056189005f8
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    initStaticProperties();
56    initExtensions();
57
58    mDebugLevel = readDebugLevel();
59    ALOGD("Enabling debug mode %d", mDebugLevel);
60}
61
62bool Caches::init() {
63    if (mInitialized) return false;
64
65    glGenBuffers(1, &meshBuffer);
66    glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
67    glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
68
69    mCurrentBuffer = meshBuffer;
70    mCurrentIndicesBuffer = 0;
71    mCurrentPositionPointer = this;
72    mCurrentPositionStride = 0;
73    mCurrentTexCoordsPointer = this;
74    mCurrentPixelBuffer = 0;
75
76    mTexCoordsArrayEnabled = false;
77
78    glDisable(GL_SCISSOR_TEST);
79    scissorEnabled = false;
80    mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
81
82    glActiveTexture(gTextureUnits[0]);
83    mTextureUnit = 0;
84
85    mRegionMesh = NULL;
86    mMeshIndices = 0;
87
88    blend = false;
89    lastSrcMode = GL_ZERO;
90    lastDstMode = GL_ZERO;
91    currentProgram = NULL;
92
93    mFunctorsCount = 0;
94
95    debugLayersUpdates = false;
96    debugOverdraw = false;
97    debugStencilClip = kStencilHide;
98
99    patchCache.init(*this);
100
101    mInitialized = true;
102
103    return true;
104}
105
106void Caches::initFont() {
107    fontRenderer = GammaFontRenderer::createRenderer();
108}
109
110void Caches::initExtensions() {
111    if (mExtensions.hasDebugMarker()) {
112        eventMark = glInsertEventMarkerEXT;
113
114        startMark = glPushGroupMarkerEXT;
115        endMark = glPopGroupMarkerEXT;
116    } else {
117        eventMark = eventMarkNull;
118        startMark = startMarkNull;
119        endMark = endMarkNull;
120    }
121
122    if (mExtensions.hasDebugLabel() && (drawDeferDisabled || drawReorderDisabled)) {
123        setLabel = glLabelObjectEXT;
124        getLabel = glGetObjectLabelEXT;
125    } else {
126        setLabel = setLabelNull;
127        getLabel = getLabelNull;
128    }
129}
130
131void Caches::initConstraints() {
132    GLint maxTextureUnits;
133    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
134    if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
135        ALOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
136    }
137
138    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
139}
140
141void Caches::initStaticProperties() {
142    gpuPixelBuffersEnabled = false;
143
144    // OpenGL ES 3.0+ specific features
145    if (mExtensions.getMajorGlVersion() >= 3) {
146        char property[PROPERTY_VALUE_MAX];
147        if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "true") > 0) {
148            gpuPixelBuffersEnabled = !strcmp(property, "true");
149        }
150    }
151}
152
153bool Caches::initProperties() {
154    bool prevDebugLayersUpdates = debugLayersUpdates;
155    bool prevDebugOverdraw = debugOverdraw;
156    StencilClipDebug prevDebugStencilClip = debugStencilClip;
157
158    char property[PROPERTY_VALUE_MAX];
159    if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, NULL) > 0) {
160        INIT_LOGD("  Layers updates debug enabled: %s", property);
161        debugLayersUpdates = !strcmp(property, "true");
162    } else {
163        debugLayersUpdates = false;
164    }
165
166    if (property_get(PROPERTY_DEBUG_OVERDRAW, property, NULL) > 0) {
167        INIT_LOGD("  Overdraw debug enabled: %s", property);
168        debugOverdraw = !strcmp(property, "show");
169    } else {
170        debugOverdraw = false;
171    }
172
173    // See Properties.h for valid values
174    if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, NULL) > 0) {
175        INIT_LOGD("  Stencil clip debug enabled: %s", property);
176        if (!strcmp(property, "hide")) {
177            debugStencilClip = kStencilHide;
178        } else if (!strcmp(property, "highlight")) {
179            debugStencilClip = kStencilShowHighlight;
180        } else if (!strcmp(property, "region")) {
181            debugStencilClip = kStencilShowRegion;
182        }
183    } else {
184        debugStencilClip = kStencilHide;
185    }
186
187    if (property_get(PROPERTY_DISABLE_DRAW_DEFER, property, "false")) {
188        drawDeferDisabled = !strcasecmp(property, "true");
189        INIT_LOGD("  Draw defer %s", drawDeferDisabled ? "disabled" : "enabled");
190    } else {
191        INIT_LOGD("  Draw defer enabled");
192    }
193
194    if (property_get(PROPERTY_DISABLE_DRAW_REORDER, property, "false")) {
195        drawReorderDisabled = !strcasecmp(property, "true");
196        INIT_LOGD("  Draw reorder %s", drawReorderDisabled ? "disabled" : "enabled");
197    } else {
198        INIT_LOGD("  Draw reorder enabled");
199    }
200
201    return (prevDebugLayersUpdates != debugLayersUpdates) ||
202            (prevDebugOverdraw != debugOverdraw) ||
203            (prevDebugStencilClip != debugStencilClip);
204}
205
206void Caches::terminate() {
207    if (!mInitialized) return;
208
209    glDeleteBuffers(1, &meshBuffer);
210    mCurrentBuffer = 0;
211
212    glDeleteBuffers(1, &mMeshIndices);
213    delete[] mRegionMesh;
214    mMeshIndices = 0;
215    mRegionMesh = NULL;
216
217    fboCache.clear();
218
219    programCache.clear();
220    currentProgram = NULL;
221
222    assetAtlas.terminate();
223
224    patchCache.clear();
225
226    mInitialized = false;
227}
228
229///////////////////////////////////////////////////////////////////////////////
230// Debug
231///////////////////////////////////////////////////////////////////////////////
232
233void Caches::dumpMemoryUsage() {
234    String8 stringLog;
235    dumpMemoryUsage(stringLog);
236    ALOGD("%s", stringLog.string());
237}
238
239void Caches::dumpMemoryUsage(String8 &log) {
240    log.appendFormat("Current memory usage / total memory usage (bytes):\n");
241    log.appendFormat("  TextureCache         %8d / %8d\n",
242            textureCache.getSize(), textureCache.getMaxSize());
243    log.appendFormat("  LayerCache           %8d / %8d\n",
244            layerCache.getSize(), layerCache.getMaxSize());
245    log.appendFormat("  RenderBufferCache    %8d / %8d\n",
246            renderBufferCache.getSize(), renderBufferCache.getMaxSize());
247    log.appendFormat("  GradientCache        %8d / %8d\n",
248            gradientCache.getSize(), gradientCache.getMaxSize());
249    log.appendFormat("  PathCache            %8d / %8d\n",
250            pathCache.getSize(), pathCache.getMaxSize());
251    log.appendFormat("  TextDropShadowCache  %8d / %8d\n", dropShadowCache.getSize(),
252            dropShadowCache.getMaxSize());
253    log.appendFormat("  PatchCache           %8d / %8d\n",
254            patchCache.getSize(), patchCache.getMaxSize());
255    for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
256        const uint32_t size = fontRenderer->getFontRendererSize(i);
257        log.appendFormat("  FontRenderer %d       %8d / %8d\n", i, size, size);
258    }
259    log.appendFormat("Other:\n");
260    log.appendFormat("  FboCache             %8d / %8d\n",
261            fboCache.getSize(), fboCache.getMaxSize());
262
263    uint32_t total = 0;
264    total += textureCache.getSize();
265    total += layerCache.getSize();
266    total += renderBufferCache.getSize();
267    total += gradientCache.getSize();
268    total += pathCache.getSize();
269    total += dropShadowCache.getSize();
270    total += patchCache.getSize();
271    for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
272        total += fontRenderer->getFontRendererSize(i);
273    }
274
275    log.appendFormat("Total memory usage:\n");
276    log.appendFormat("  %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
277}
278
279///////////////////////////////////////////////////////////////////////////////
280// Memory management
281///////////////////////////////////////////////////////////////////////////////
282
283void Caches::clearGarbage() {
284    textureCache.clearGarbage();
285    pathCache.clearGarbage();
286
287    Vector<DisplayList*> displayLists;
288    Vector<Layer*> layers;
289
290    { // scope for the lock
291        Mutex::Autolock _l(mGarbageLock);
292        displayLists = mDisplayListGarbage;
293        layers = mLayerGarbage;
294        mDisplayListGarbage.clear();
295        mLayerGarbage.clear();
296    }
297
298    size_t count = displayLists.size();
299    for (size_t i = 0; i < count; i++) {
300        DisplayList* displayList = displayLists.itemAt(i);
301        delete displayList;
302    }
303
304    count = layers.size();
305    for (size_t i = 0; i < count; i++) {
306        Layer* layer = layers.itemAt(i);
307        delete layer;
308    }
309    layers.clear();
310}
311
312void Caches::deleteLayerDeferred(Layer* layer) {
313    Mutex::Autolock _l(mGarbageLock);
314    mLayerGarbage.push(layer);
315}
316
317void Caches::deleteDisplayListDeferred(DisplayList* displayList) {
318    Mutex::Autolock _l(mGarbageLock);
319    mDisplayListGarbage.push(displayList);
320}
321
322void Caches::flush(FlushMode mode) {
323    FLUSH_LOGD("Flushing caches (mode %d)", mode);
324
325    switch (mode) {
326        case kFlushMode_Full:
327            textureCache.clear();
328            patchCache.clear();
329            dropShadowCache.clear();
330            gradientCache.clear();
331            fontRenderer->clear();
332            dither.clear();
333            // fall through
334        case kFlushMode_Moderate:
335            fontRenderer->flush();
336            textureCache.flush();
337            pathCache.clear();
338            tasks.stop();
339            // fall through
340        case kFlushMode_Layers:
341            layerCache.clear();
342            renderBufferCache.clear();
343            break;
344    }
345
346    clearGarbage();
347}
348
349///////////////////////////////////////////////////////////////////////////////
350// VBO
351///////////////////////////////////////////////////////////////////////////////
352
353bool Caches::bindMeshBuffer() {
354    return bindMeshBuffer(meshBuffer);
355}
356
357bool Caches::bindMeshBuffer(const GLuint buffer) {
358    if (mCurrentBuffer != buffer) {
359        glBindBuffer(GL_ARRAY_BUFFER, buffer);
360        mCurrentBuffer = buffer;
361        return true;
362    }
363    return false;
364}
365
366bool Caches::unbindMeshBuffer() {
367    if (mCurrentBuffer) {
368        glBindBuffer(GL_ARRAY_BUFFER, 0);
369        mCurrentBuffer = 0;
370        return true;
371    }
372    return false;
373}
374
375bool Caches::bindIndicesBuffer(const GLuint buffer) {
376    if (mCurrentIndicesBuffer != buffer) {
377        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
378        mCurrentIndicesBuffer = buffer;
379        return true;
380    }
381    return false;
382}
383
384bool Caches::bindIndicesBuffer() {
385    if (!mMeshIndices) {
386        uint16_t* regionIndices = new uint16_t[REGION_MESH_QUAD_COUNT * 6];
387        for (int i = 0; i < REGION_MESH_QUAD_COUNT; i++) {
388            uint16_t quad = i * 4;
389            int index = i * 6;
390            regionIndices[index    ] = quad;       // top-left
391            regionIndices[index + 1] = quad + 1;   // top-right
392            regionIndices[index + 2] = quad + 2;   // bottom-left
393            regionIndices[index + 3] = quad + 2;   // bottom-left
394            regionIndices[index + 4] = quad + 1;   // top-right
395            regionIndices[index + 5] = quad + 3;   // bottom-right
396        }
397
398        glGenBuffers(1, &mMeshIndices);
399        bool force = bindIndicesBuffer(mMeshIndices);
400        glBufferData(GL_ELEMENT_ARRAY_BUFFER, REGION_MESH_QUAD_COUNT * 6 * sizeof(uint16_t),
401                regionIndices, GL_STATIC_DRAW);
402
403        delete[] regionIndices;
404        return force;
405    }
406
407    return bindIndicesBuffer(mMeshIndices);
408}
409
410bool Caches::unbindIndicesBuffer() {
411    if (mCurrentIndicesBuffer) {
412        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
413        mCurrentIndicesBuffer = 0;
414        return true;
415    }
416    return false;
417}
418
419///////////////////////////////////////////////////////////////////////////////
420// PBO
421///////////////////////////////////////////////////////////////////////////////
422
423bool Caches::bindPixelBuffer(const GLuint buffer) {
424    if (mCurrentPixelBuffer != buffer) {
425        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
426        mCurrentPixelBuffer = buffer;
427        return true;
428    }
429    return false;
430}
431
432bool Caches::unbindPixelBuffer() {
433    if (mCurrentPixelBuffer) {
434        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
435        mCurrentPixelBuffer = 0;
436        return true;
437    }
438    return false;
439}
440
441///////////////////////////////////////////////////////////////////////////////
442// Meshes and textures
443///////////////////////////////////////////////////////////////////////////////
444
445void Caches::bindPositionVertexPointer(bool force, GLvoid* vertices, GLsizei stride) {
446    if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
447        GLuint slot = currentProgram->position;
448        glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
449        mCurrentPositionPointer = vertices;
450        mCurrentPositionStride = stride;
451    }
452}
453
454void Caches::bindTexCoordsVertexPointer(bool force, GLvoid* vertices, GLsizei stride) {
455    if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
456        GLuint slot = currentProgram->texCoords;
457        glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
458        mCurrentTexCoordsPointer = vertices;
459        mCurrentTexCoordsStride = stride;
460    }
461}
462
463void Caches::resetVertexPointers() {
464    mCurrentPositionPointer = this;
465    mCurrentTexCoordsPointer = this;
466}
467
468void Caches::resetTexCoordsVertexPointer() {
469    mCurrentTexCoordsPointer = this;
470}
471
472void Caches::enableTexCoordsVertexArray() {
473    if (!mTexCoordsArrayEnabled) {
474        glEnableVertexAttribArray(Program::kBindingTexCoords);
475        mCurrentTexCoordsPointer = this;
476        mTexCoordsArrayEnabled = true;
477    }
478}
479
480void Caches::disableTexCoordsVertexArray() {
481    if (mTexCoordsArrayEnabled) {
482        glDisableVertexAttribArray(Program::kBindingTexCoords);
483        mTexCoordsArrayEnabled = false;
484    }
485}
486
487void Caches::activeTexture(GLuint textureUnit) {
488    if (mTextureUnit != textureUnit) {
489        glActiveTexture(gTextureUnits[textureUnit]);
490        mTextureUnit = textureUnit;
491    }
492}
493
494///////////////////////////////////////////////////////////////////////////////
495// Scissor
496///////////////////////////////////////////////////////////////////////////////
497
498bool Caches::setScissor(GLint x, GLint y, GLint width, GLint height) {
499    if (scissorEnabled && (x != mScissorX || y != mScissorY ||
500            width != mScissorWidth || height != mScissorHeight)) {
501
502        if (x < 0) {
503            width += x;
504            x = 0;
505        }
506        if (y < 0) {
507            height += y;
508            y = 0;
509        }
510        if (width < 0) {
511            width = 0;
512        }
513        if (height < 0) {
514            height = 0;
515        }
516        glScissor(x, y, width, height);
517
518        mScissorX = x;
519        mScissorY = y;
520        mScissorWidth = width;
521        mScissorHeight = height;
522
523        return true;
524    }
525    return false;
526}
527
528bool Caches::enableScissor() {
529    if (!scissorEnabled) {
530        glEnable(GL_SCISSOR_TEST);
531        scissorEnabled = true;
532        resetScissor();
533        return true;
534    }
535    return false;
536}
537
538bool Caches::disableScissor() {
539    if (scissorEnabled) {
540        glDisable(GL_SCISSOR_TEST);
541        scissorEnabled = false;
542        return true;
543    }
544    return false;
545}
546
547void Caches::setScissorEnabled(bool enabled) {
548    if (scissorEnabled != enabled) {
549        if (enabled) glEnable(GL_SCISSOR_TEST);
550        else glDisable(GL_SCISSOR_TEST);
551        scissorEnabled = enabled;
552    }
553}
554
555void Caches::resetScissor() {
556    mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
557}
558
559///////////////////////////////////////////////////////////////////////////////
560// Tiling
561///////////////////////////////////////////////////////////////////////////////
562
563void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard) {
564    if (mExtensions.hasTiledRendering() && !debugOverdraw) {
565        glStartTilingQCOM(x, y, width, height, (discard ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM));
566    }
567}
568
569void Caches::endTiling() {
570    if (mExtensions.hasTiledRendering() && !debugOverdraw) {
571        glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM);
572    }
573}
574
575bool Caches::hasRegisteredFunctors() {
576    return mFunctorsCount > 0;
577}
578
579void Caches::registerFunctors(uint32_t functorCount) {
580    mFunctorsCount += functorCount;
581}
582
583void Caches::unregisterFunctors(uint32_t functorCount) {
584    if (functorCount > mFunctorsCount) {
585        mFunctorsCount = 0;
586    } else {
587        mFunctorsCount -= functorCount;
588    }
589}
590
591///////////////////////////////////////////////////////////////////////////////
592// Regions
593///////////////////////////////////////////////////////////////////////////////
594
595TextureVertex* Caches::getRegionMesh() {
596    // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
597    if (!mRegionMesh) {
598        mRegionMesh = new TextureVertex[REGION_MESH_QUAD_COUNT * 4];
599    }
600
601    return mRegionMesh;
602}
603
604}; // namespace uirenderer
605}; // namespace android
606