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