Caches.cpp revision 1540153198fc59e5f344b363c198acf5b65251aa
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#include "Caches.h"
18
19#include "GammaFontRenderer.h"
20#include "LayerRenderer.h"
21#include "Properties.h"
22#include "renderstate/RenderState.h"
23#include "ShadowTessellator.h"
24#include "utils/GLUtils.h"
25
26#include <cutils/properties.h>
27#include <utils/Log.h>
28#include <utils/String8.h>
29
30namespace android {
31namespace uirenderer {
32
33Caches* Caches::sInstance = nullptr;
34
35///////////////////////////////////////////////////////////////////////////////
36// Macros
37///////////////////////////////////////////////////////////////////////////////
38
39#if DEBUG_CACHE_FLUSH
40    #define FLUSH_LOGD(...) ALOGD(__VA_ARGS__)
41#else
42    #define FLUSH_LOGD(...)
43#endif
44
45///////////////////////////////////////////////////////////////////////////////
46// Constructors/destructor
47///////////////////////////////////////////////////////////////////////////////
48
49Caches::Caches(RenderState& renderState)
50        : gradientCache(mExtensions)
51        , patchCache(renderState)
52        , programCache(mExtensions)
53        , dither(*this)
54        , mRenderState(&renderState)
55        , mInitialized(false) {
56    INIT_LOGD("Creating OpenGL renderer caches");
57    init();
58    initConstraints();
59    initStaticProperties();
60    initExtensions();
61}
62
63bool Caches::init() {
64    if (mInitialized) return false;
65
66    ATRACE_NAME("Caches::init");
67
68    mRegionMesh = nullptr;
69    mProgram = nullptr;
70
71    patchCache.init();
72
73    mInitialized = true;
74
75    mPixelBufferState = new PixelBufferState();
76    mTextureState = new TextureState();
77
78    return true;
79}
80
81void Caches::initExtensions() {
82    if (mExtensions.hasDebugMarker()) {
83        eventMark = glInsertEventMarkerEXT;
84
85        startMark = glPushGroupMarkerEXT;
86        endMark = glPopGroupMarkerEXT;
87    } else {
88        eventMark = eventMarkNull;
89        startMark = startMarkNull;
90        endMark = endMarkNull;
91    }
92}
93
94void Caches::initConstraints() {
95    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
96}
97
98void Caches::initStaticProperties() {
99    // OpenGL ES 3.0+ specific features
100    gpuPixelBuffersEnabled = mExtensions.hasPixelBufferObjects()
101            && property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true);
102}
103
104void Caches::terminate() {
105    if (!mInitialized) return;
106    mRegionMesh.release();
107
108    fboCache.clear();
109
110    programCache.clear();
111    mProgram = nullptr;
112
113    patchCache.clear();
114
115    clearGarbage();
116
117    delete mPixelBufferState;
118    mPixelBufferState = nullptr;
119    delete mTextureState;
120    mTextureState = nullptr;
121    mInitialized = false;
122}
123
124void Caches::setProgram(const ProgramDescription& description) {
125    setProgram(programCache.get(description));
126}
127
128void Caches::setProgram(Program* program) {
129    if (!program || !program->isInUse()) {
130        if (mProgram) {
131            mProgram->remove();
132        }
133        if (program) {
134            program->use();
135        }
136        mProgram = program;
137    }
138}
139
140///////////////////////////////////////////////////////////////////////////////
141// Debug
142///////////////////////////////////////////////////////////////////////////////
143
144uint32_t Caches::getOverdrawColor(uint32_t amount) const {
145    static uint32_t sOverdrawColors[2][4] = {
146            { 0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000 },
147            { 0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000 }
148    };
149    if (amount < 1) amount = 1;
150    if (amount > 4) amount = 4;
151
152    int overdrawColorIndex = static_cast<int>(Properties::overdrawColorSet);
153    return sOverdrawColors[overdrawColorIndex][amount - 1];
154}
155
156void Caches::dumpMemoryUsage() {
157    String8 stringLog;
158    dumpMemoryUsage(stringLog);
159    ALOGD("%s", stringLog.string());
160}
161
162void Caches::dumpMemoryUsage(String8 &log) {
163    uint32_t total = 0;
164    log.appendFormat("Current memory usage / total memory usage (bytes):\n");
165    log.appendFormat("  TextureCache         %8d / %8d\n",
166            textureCache.getSize(), textureCache.getMaxSize());
167    log.appendFormat("  LayerCache           %8d / %8d (numLayers = %zu)\n",
168            layerCache.getSize(), layerCache.getMaxSize(), layerCache.getCount());
169    if (mRenderState) {
170        int memused = 0;
171        for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin();
172                it != mRenderState->mActiveLayers.end(); it++) {
173            const Layer* layer = *it;
174            log.appendFormat("    Layer size %dx%d; isTextureLayer()=%d; texid=%u fbo=%u; refs=%d\n",
175                    layer->getWidth(), layer->getHeight(),
176                    layer->isTextureLayer(), layer->getTextureId(),
177                    layer->getFbo(), layer->getStrongCount());
178            memused += layer->getWidth() * layer->getHeight() * 4;
179        }
180        log.appendFormat("  Layers total   %8d (numLayers = %zu)\n",
181                memused, mRenderState->mActiveLayers.size());
182        total += memused;
183    }
184    log.appendFormat("  RenderBufferCache    %8d / %8d\n",
185            renderBufferCache.getSize(), renderBufferCache.getMaxSize());
186    log.appendFormat("  GradientCache        %8d / %8d\n",
187            gradientCache.getSize(), gradientCache.getMaxSize());
188    log.appendFormat("  PathCache            %8d / %8d\n",
189            pathCache.getSize(), pathCache.getMaxSize());
190    log.appendFormat("  TessellationCache    %8d / %8d\n",
191            tessellationCache.getSize(), tessellationCache.getMaxSize());
192    log.appendFormat("  TextDropShadowCache  %8d / %8d\n", dropShadowCache.getSize(),
193            dropShadowCache.getMaxSize());
194    log.appendFormat("  PatchCache           %8d / %8d\n",
195            patchCache.getSize(), patchCache.getMaxSize());
196
197    const uint32_t sizeA8 = fontRenderer.getFontRendererSize(GL_ALPHA);
198    const uint32_t sizeRGBA = fontRenderer.getFontRendererSize(GL_RGBA);
199    log.appendFormat("  FontRenderer A8    %8d / %8d\n", sizeA8, sizeA8);
200    log.appendFormat("  FontRenderer RGBA  %8d / %8d\n", sizeRGBA, sizeRGBA);
201    log.appendFormat("  FontRenderer total %8d / %8d\n", sizeA8 + sizeRGBA,
202            sizeA8 + sizeRGBA);
203
204    log.appendFormat("Other:\n");
205    log.appendFormat("  FboCache             %8d / %8d\n",
206            fboCache.getSize(), fboCache.getMaxSize());
207
208    total += textureCache.getSize();
209    total += renderBufferCache.getSize();
210    total += gradientCache.getSize();
211    total += pathCache.getSize();
212    total += tessellationCache.getSize();
213    total += dropShadowCache.getSize();
214    total += patchCache.getSize();
215    total += fontRenderer.getFontRendererSize(GL_ALPHA);
216    total += fontRenderer.getFontRendererSize(GL_RGBA);
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    patchCache.clearGarbage();
230}
231
232void Caches::flush(FlushMode mode) {
233    FLUSH_LOGD("Flushing caches (mode %d)", mode);
234
235    switch (mode) {
236        case FlushMode::Full:
237            textureCache.clear();
238            patchCache.clear();
239            dropShadowCache.clear();
240            gradientCache.clear();
241            fontRenderer.clear();
242            fboCache.clear();
243            dither.clear();
244            // fall through
245        case FlushMode::Moderate:
246            fontRenderer.flush();
247            textureCache.flush();
248            pathCache.clear();
249            tessellationCache.clear();
250            // fall through
251        case FlushMode::Layers:
252            layerCache.clear();
253            renderBufferCache.clear();
254            break;
255    }
256
257    clearGarbage();
258    glFinish();
259    // Errors during cleanup should be considered non-fatal, dump them and
260    // and move on. TODO: All errors or just errors like bad surface?
261    GLUtils::dumpGLErrors();
262}
263
264///////////////////////////////////////////////////////////////////////////////
265// Regions
266///////////////////////////////////////////////////////////////////////////////
267
268TextureVertex* Caches::getRegionMesh() {
269    // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
270    if (!mRegionMesh) {
271        mRegionMesh.reset(new TextureVertex[kMaxNumberOfQuads * 4]);
272    }
273
274    return mRegionMesh.get();
275}
276
277///////////////////////////////////////////////////////////////////////////////
278// Temporary Properties
279///////////////////////////////////////////////////////////////////////////////
280
281}; // namespace uirenderer
282}; // namespace android
283