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