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