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