Caches.cpp revision 31e08e953fe7bdb1b1cbc247156cb6a19917a2f1
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
290    Vector<DisplayList*> displayLists;
291    Vector<Layer*> layers;
292
293    { // scope for the lock
294        Mutex::Autolock _l(mGarbageLock);
295        displayLists = mDisplayListGarbage;
296        layers = mLayerGarbage;
297        mDisplayListGarbage.clear();
298        mLayerGarbage.clear();
299    }
300
301    size_t count = displayLists.size();
302    for (size_t i = 0; i < count; i++) {
303        DisplayList* displayList = displayLists.itemAt(i);
304        delete displayList;
305    }
306
307    count = layers.size();
308    for (size_t i = 0; i < count; i++) {
309        Layer* layer = layers.itemAt(i);
310        delete layer;
311    }
312    layers.clear();
313}
314
315void Caches::deleteLayerDeferred(Layer* layer) {
316    Mutex::Autolock _l(mGarbageLock);
317    mLayerGarbage.push(layer);
318}
319
320void Caches::deleteDisplayListDeferred(DisplayList* displayList) {
321    Mutex::Autolock _l(mGarbageLock);
322    mDisplayListGarbage.push(displayList);
323}
324
325void Caches::flush(FlushMode mode) {
326    FLUSH_LOGD("Flushing caches (mode %d)", mode);
327
328    switch (mode) {
329        case kFlushMode_Full:
330            textureCache.clear();
331            patchCache.clear();
332            dropShadowCache.clear();
333            gradientCache.clear();
334            fontRenderer->clear();
335            dither.clear();
336            // fall through
337        case kFlushMode_Moderate:
338            fontRenderer->flush();
339            textureCache.flush();
340            pathCache.clear();
341            tasks.stop();
342            // fall through
343        case kFlushMode_Layers:
344            layerCache.clear();
345            renderBufferCache.clear();
346            break;
347    }
348
349    clearGarbage();
350}
351
352///////////////////////////////////////////////////////////////////////////////
353// VBO
354///////////////////////////////////////////////////////////////////////////////
355
356bool Caches::bindMeshBuffer() {
357    return bindMeshBuffer(meshBuffer);
358}
359
360bool Caches::bindMeshBuffer(const GLuint buffer) {
361    if (mCurrentBuffer != buffer) {
362        glBindBuffer(GL_ARRAY_BUFFER, buffer);
363        mCurrentBuffer = buffer;
364        return true;
365    }
366    return false;
367}
368
369bool Caches::unbindMeshBuffer() {
370    if (mCurrentBuffer) {
371        glBindBuffer(GL_ARRAY_BUFFER, 0);
372        mCurrentBuffer = 0;
373        return true;
374    }
375    return false;
376}
377
378bool Caches::bindIndicesBuffer(const GLuint buffer) {
379    if (mCurrentIndicesBuffer != buffer) {
380        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
381        mCurrentIndicesBuffer = buffer;
382        return true;
383    }
384    return false;
385}
386
387bool Caches::bindIndicesBuffer() {
388    if (!mMeshIndices) {
389        uint16_t* regionIndices = new uint16_t[gMaxNumberOfQuads * 6];
390        for (uint32_t i = 0; i < gMaxNumberOfQuads; i++) {
391            uint16_t quad = i * 4;
392            int index = i * 6;
393            regionIndices[index    ] = quad;       // top-left
394            regionIndices[index + 1] = quad + 1;   // top-right
395            regionIndices[index + 2] = quad + 2;   // bottom-left
396            regionIndices[index + 3] = quad + 2;   // bottom-left
397            regionIndices[index + 4] = quad + 1;   // top-right
398            regionIndices[index + 5] = quad + 3;   // bottom-right
399        }
400
401        glGenBuffers(1, &mMeshIndices);
402        bool force = bindIndicesBuffer(mMeshIndices);
403        glBufferData(GL_ELEMENT_ARRAY_BUFFER, gMaxNumberOfQuads * 6 * sizeof(uint16_t),
404                regionIndices, GL_STATIC_DRAW);
405
406        delete[] regionIndices;
407        return force;
408    }
409
410    return bindIndicesBuffer(mMeshIndices);
411}
412
413bool Caches::unbindIndicesBuffer() {
414    if (mCurrentIndicesBuffer) {
415        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
416        mCurrentIndicesBuffer = 0;
417        return true;
418    }
419    return false;
420}
421
422///////////////////////////////////////////////////////////////////////////////
423// PBO
424///////////////////////////////////////////////////////////////////////////////
425
426bool Caches::bindPixelBuffer(const GLuint buffer) {
427    if (mCurrentPixelBuffer != buffer) {
428        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
429        mCurrentPixelBuffer = buffer;
430        return true;
431    }
432    return false;
433}
434
435bool Caches::unbindPixelBuffer() {
436    if (mCurrentPixelBuffer) {
437        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
438        mCurrentPixelBuffer = 0;
439        return true;
440    }
441    return false;
442}
443
444///////////////////////////////////////////////////////////////////////////////
445// Meshes and textures
446///////////////////////////////////////////////////////////////////////////////
447
448void Caches::bindPositionVertexPointer(bool force, GLvoid* vertices, GLsizei stride) {
449    if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
450        GLuint slot = currentProgram->position;
451        glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
452        mCurrentPositionPointer = vertices;
453        mCurrentPositionStride = stride;
454    }
455}
456
457void Caches::bindTexCoordsVertexPointer(bool force, GLvoid* vertices, GLsizei stride) {
458    if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
459        GLuint slot = currentProgram->texCoords;
460        glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
461        mCurrentTexCoordsPointer = vertices;
462        mCurrentTexCoordsStride = stride;
463    }
464}
465
466void Caches::resetVertexPointers() {
467    mCurrentPositionPointer = this;
468    mCurrentTexCoordsPointer = this;
469}
470
471void Caches::resetTexCoordsVertexPointer() {
472    mCurrentTexCoordsPointer = this;
473}
474
475void Caches::enableTexCoordsVertexArray() {
476    if (!mTexCoordsArrayEnabled) {
477        glEnableVertexAttribArray(Program::kBindingTexCoords);
478        mCurrentTexCoordsPointer = this;
479        mTexCoordsArrayEnabled = true;
480    }
481}
482
483void Caches::disableTexCoordsVertexArray() {
484    if (mTexCoordsArrayEnabled) {
485        glDisableVertexAttribArray(Program::kBindingTexCoords);
486        mTexCoordsArrayEnabled = false;
487    }
488}
489
490void Caches::activeTexture(GLuint textureUnit) {
491    if (mTextureUnit != textureUnit) {
492        glActiveTexture(gTextureUnits[textureUnit]);
493        mTextureUnit = textureUnit;
494    }
495}
496
497void Caches::bindTexture(GLuint texture) {
498    if (mBoundTextures[mTextureUnit] != texture) {
499        glBindTexture(GL_TEXTURE_2D, texture);
500        mBoundTextures[mTextureUnit] = texture;
501    }
502}
503
504void Caches::bindTexture(GLenum target, GLuint texture) {
505    if (mBoundTextures[mTextureUnit] != texture) {
506        glBindTexture(target, texture);
507        mBoundTextures[mTextureUnit] = texture;
508    }
509}
510
511void Caches::deleteTexture(GLuint texture) {
512    // When glDeleteTextures() is called on a currently bound texture,
513    // OpenGL ES specifies that the texture is then considered unbound
514    // Consider the following series of calls:
515    //
516    // glGenTextures -> creates texture name 2
517    // glBindTexture(2)
518    // glDeleteTextures(2) -> 2 is now unbound
519    // glGenTextures -> can return 2 again
520    //
521    // If we don't call glBindTexture(2) after the second glGenTextures
522    // call, any texture operation will be performed on the default
523    // texture (name=0)
524
525    for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
526        if (mBoundTextures[i] == texture) {
527            mBoundTextures[i] = 0;
528        }
529    }
530    glDeleteTextures(1, &texture);
531}
532
533void Caches::resetBoundTextures() {
534    memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint));
535}
536
537///////////////////////////////////////////////////////////////////////////////
538// Scissor
539///////////////////////////////////////////////////////////////////////////////
540
541bool Caches::setScissor(GLint x, GLint y, GLint width, GLint height) {
542    if (scissorEnabled && (x != mScissorX || y != mScissorY ||
543            width != mScissorWidth || height != mScissorHeight)) {
544
545        if (x < 0) {
546            width += x;
547            x = 0;
548        }
549        if (y < 0) {
550            height += y;
551            y = 0;
552        }
553        if (width < 0) {
554            width = 0;
555        }
556        if (height < 0) {
557            height = 0;
558        }
559        glScissor(x, y, width, height);
560
561        mScissorX = x;
562        mScissorY = y;
563        mScissorWidth = width;
564        mScissorHeight = height;
565
566        return true;
567    }
568    return false;
569}
570
571bool Caches::enableScissor() {
572    if (!scissorEnabled) {
573        glEnable(GL_SCISSOR_TEST);
574        scissorEnabled = true;
575        resetScissor();
576        return true;
577    }
578    return false;
579}
580
581bool Caches::disableScissor() {
582    if (scissorEnabled) {
583        glDisable(GL_SCISSOR_TEST);
584        scissorEnabled = false;
585        return true;
586    }
587    return false;
588}
589
590void Caches::setScissorEnabled(bool enabled) {
591    if (scissorEnabled != enabled) {
592        if (enabled) glEnable(GL_SCISSOR_TEST);
593        else glDisable(GL_SCISSOR_TEST);
594        scissorEnabled = enabled;
595    }
596}
597
598void Caches::resetScissor() {
599    mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
600}
601
602///////////////////////////////////////////////////////////////////////////////
603// Tiling
604///////////////////////////////////////////////////////////////////////////////
605
606void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard) {
607    if (mExtensions.hasTiledRendering() && !debugOverdraw) {
608        glStartTilingQCOM(x, y, width, height, (discard ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM));
609    }
610}
611
612void Caches::endTiling() {
613    if (mExtensions.hasTiledRendering() && !debugOverdraw) {
614        glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM);
615    }
616}
617
618bool Caches::hasRegisteredFunctors() {
619    return mFunctorsCount > 0;
620}
621
622void Caches::registerFunctors(uint32_t functorCount) {
623    mFunctorsCount += functorCount;
624}
625
626void Caches::unregisterFunctors(uint32_t functorCount) {
627    if (functorCount > mFunctorsCount) {
628        mFunctorsCount = 0;
629    } else {
630        mFunctorsCount -= functorCount;
631    }
632}
633
634///////////////////////////////////////////////////////////////////////////////
635// Regions
636///////////////////////////////////////////////////////////////////////////////
637
638TextureVertex* Caches::getRegionMesh() {
639    // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
640    if (!mRegionMesh) {
641        mRegionMesh = new TextureVertex[gMaxNumberOfQuads * 4];
642    }
643
644    return mRegionMesh;
645}
646
647}; // namespace uirenderer
648}; // namespace android
649