Caches.cpp revision 56ad6ec42f814e9e61030ff819cac4e5d31def8b
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 "Layer.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    mInitialized = true;
72
73    mPixelBufferState = new PixelBufferState();
74    mTextureState = new TextureState();
75    mTextureState->constructTexture(*this);
76
77    return true;
78}
79
80void Caches::initExtensions() {
81    if (mExtensions.hasDebugMarker()) {
82        eventMark = glInsertEventMarkerEXT;
83
84        startMark = glPushGroupMarkerEXT;
85        endMark = glPopGroupMarkerEXT;
86    } else {
87        eventMark = eventMarkNull;
88        startMark = startMarkNull;
89        endMark = endMarkNull;
90    }
91}
92
93void Caches::initConstraints() {
94    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
95}
96
97void Caches::initStaticProperties() {
98    // OpenGL ES 3.0+ specific features
99    gpuPixelBuffersEnabled = mExtensions.hasPixelBufferObjects()
100            && property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true);
101}
102
103void Caches::terminate() {
104    if (!mInitialized) return;
105    mRegionMesh.reset(nullptr);
106
107    fboCache.clear();
108
109    programCache.clear();
110    mProgram = nullptr;
111
112    patchCache.clear();
113
114    clearGarbage();
115
116    delete mPixelBufferState;
117    mPixelBufferState = nullptr;
118    delete mTextureState;
119    mTextureState = nullptr;
120    mInitialized = false;
121}
122
123void Caches::setProgram(const ProgramDescription& description) {
124    setProgram(programCache.get(description));
125}
126
127void Caches::setProgram(Program* program) {
128    if (!program || !program->isInUse()) {
129        if (mProgram) {
130            mProgram->remove();
131        }
132        if (program) {
133            program->use();
134        }
135        mProgram = program;
136    }
137}
138
139///////////////////////////////////////////////////////////////////////////////
140// Debug
141///////////////////////////////////////////////////////////////////////////////
142
143uint32_t Caches::getOverdrawColor(uint32_t amount) const {
144    static uint32_t sOverdrawColors[2][4] = {
145            { 0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000 },
146            { 0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000 }
147    };
148    if (amount < 1) amount = 1;
149    if (amount > 4) amount = 4;
150
151    int overdrawColorIndex = static_cast<int>(Properties::overdrawColorSet);
152    return sOverdrawColors[overdrawColorIndex][amount - 1];
153}
154
155void Caches::dumpMemoryUsage() {
156    String8 stringLog;
157    dumpMemoryUsage(stringLog);
158    ALOGD("%s", stringLog.string());
159}
160
161void Caches::dumpMemoryUsage(String8 &log) {
162    uint32_t total = 0;
163    log.appendFormat("Current memory usage / total memory usage (bytes):\n");
164    log.appendFormat("  TextureCache         %8d / %8d\n",
165            textureCache.getSize(), textureCache.getMaxSize());
166    if (mRenderState) {
167        int memused = 0;
168        for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin();
169                it != mRenderState->mActiveLayers.end(); it++) {
170            const Layer* layer = *it;
171            log.appendFormat("    Layer size %dx%d; texid=%u refs=%d\n",
172                    layer->getWidth(), layer->getHeight(),
173                    layer->getTextureId(),
174                    layer->getStrongCount());
175            memused += layer->getWidth() * layer->getHeight() * 4;
176        }
177        log.appendFormat("  Layers total   %8d (numLayers = %zu)\n",
178                memused, mRenderState->mActiveLayers.size());
179        total += memused;
180    }
181    log.appendFormat("  RenderBufferCache    %8d / %8d\n",
182            renderBufferCache.getSize(), renderBufferCache.getMaxSize());
183    log.appendFormat("  GradientCache        %8d / %8d\n",
184            gradientCache.getSize(), gradientCache.getMaxSize());
185    log.appendFormat("  PathCache            %8d / %8d\n",
186            pathCache.getSize(), pathCache.getMaxSize());
187    log.appendFormat("  TessellationCache    %8d / %8d\n",
188            tessellationCache.getSize(), tessellationCache.getMaxSize());
189    log.appendFormat("  TextDropShadowCache  %8d / %8d\n", dropShadowCache.getSize(),
190            dropShadowCache.getMaxSize());
191    log.appendFormat("  PatchCache           %8d / %8d\n",
192            patchCache.getSize(), patchCache.getMaxSize());
193
194    const uint32_t sizeA8 = fontRenderer.getFontRendererSize(GL_ALPHA);
195    const uint32_t sizeRGBA = fontRenderer.getFontRendererSize(GL_RGBA);
196    log.appendFormat("  FontRenderer A8    %8d / %8d\n", sizeA8, sizeA8);
197    log.appendFormat("  FontRenderer RGBA  %8d / %8d\n", sizeRGBA, sizeRGBA);
198    log.appendFormat("  FontRenderer total %8d / %8d\n", sizeA8 + sizeRGBA,
199            sizeA8 + sizeRGBA);
200
201    log.appendFormat("Other:\n");
202    log.appendFormat("  FboCache             %8d / %8d\n",
203            fboCache.getSize(), fboCache.getMaxSize());
204
205    total += textureCache.getSize();
206    total += renderBufferCache.getSize();
207    total += gradientCache.getSize();
208    total += pathCache.getSize();
209    total += tessellationCache.getSize();
210    total += dropShadowCache.getSize();
211    total += patchCache.getSize();
212    total += fontRenderer.getFontRendererSize(GL_ALPHA);
213    total += fontRenderer.getFontRendererSize(GL_RGBA);
214
215    log.appendFormat("Total memory usage:\n");
216    log.appendFormat("  %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
217}
218
219///////////////////////////////////////////////////////////////////////////////
220// Memory management
221///////////////////////////////////////////////////////////////////////////////
222
223void Caches::clearGarbage() {
224    textureCache.clearGarbage();
225    pathCache.clearGarbage();
226    patchCache.clearGarbage();
227}
228
229void Caches::flush(FlushMode mode) {
230    FLUSH_LOGD("Flushing caches (mode %d)", mode);
231
232    switch (mode) {
233        case FlushMode::Full:
234            textureCache.clear();
235            patchCache.clear();
236            dropShadowCache.clear();
237            gradientCache.clear();
238            fontRenderer.clear();
239            fboCache.clear();
240            dither.clear();
241            // fall through
242        case FlushMode::Moderate:
243            fontRenderer.flush();
244            textureCache.flush();
245            pathCache.clear();
246            tessellationCache.clear();
247            // fall through
248        case FlushMode::Layers:
249            renderBufferCache.clear();
250            break;
251    }
252
253    clearGarbage();
254    glFinish();
255    // Errors during cleanup should be considered non-fatal, dump them and
256    // and move on. TODO: All errors or just errors like bad surface?
257    GLUtils::dumpGLErrors();
258}
259
260///////////////////////////////////////////////////////////////////////////////
261// Regions
262///////////////////////////////////////////////////////////////////////////////
263
264TextureVertex* Caches::getRegionMesh() {
265    // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
266    if (!mRegionMesh) {
267        mRegionMesh.reset(new TextureVertex[kMaxNumberOfQuads * 4]);
268    }
269
270    return mRegionMesh.get();
271}
272
273///////////////////////////////////////////////////////////////////////////////
274// Temporary Properties
275///////////////////////////////////////////////////////////////////////////////
276
277}; // namespace uirenderer
278}; // namespace android
279