Caches.cpp revision 34725687748cc2b4ace2bdb49becfdcd569e9a5d
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 "Caches.h"
20
21#include "DisplayListRenderer.h"
22#include "GammaFontRenderer.h"
23#include "LayerRenderer.h"
24#include "Properties.h"
25#include "renderstate/RenderState.h"
26#include "ShadowTessellator.h"
27
28#include <utils/Log.h>
29#include <utils/String8.h>
30
31namespace android {
32namespace uirenderer {
33
34Caches* Caches::sInstance = nullptr;
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(RenderState& renderState)
51        : patchCache(renderState)
52        , dither(*this)
53        , mRenderState(&renderState)
54        , mExtensions(Extensions::getInstance())
55        , mInitialized(false) {
56    INIT_LOGD("Creating OpenGL renderer caches");
57    init();
58    initFont();
59    initConstraints();
60    initProperties();
61    initStaticProperties();
62    initExtensions();
63    initTempProperties();
64
65    mDebugLevel = readDebugLevel();
66    ALOGD_IF(mDebugLevel != kDebugDisabled,
67            "Enabling debug mode %d", mDebugLevel);
68}
69
70bool Caches::init() {
71    if (mInitialized) return false;
72
73    ATRACE_NAME("Caches::init");
74
75    mRegionMesh = nullptr;
76    mProgram = nullptr;
77
78    mFunctorsCount = 0;
79
80    debugLayersUpdates = false;
81    debugOverdraw = false;
82    debugStencilClip = kStencilHide;
83
84    patchCache.init();
85
86    mInitialized = true;
87
88    mPixelBufferState = new PixelBufferState();
89    mTextureState = new TextureState();
90
91    return true;
92}
93
94void Caches::initFont() {
95    fontRenderer = GammaFontRenderer::createRenderer();
96}
97
98void Caches::initExtensions() {
99    if (mExtensions.hasDebugMarker()) {
100        eventMark = glInsertEventMarkerEXT;
101
102        startMark = glPushGroupMarkerEXT;
103        endMark = glPopGroupMarkerEXT;
104    } else {
105        eventMark = eventMarkNull;
106        startMark = startMarkNull;
107        endMark = endMarkNull;
108    }
109
110    if (mExtensions.hasDebugLabel() && (drawDeferDisabled || drawReorderDisabled)) {
111        setLabel = glLabelObjectEXT;
112        getLabel = glGetObjectLabelEXT;
113    } else {
114        setLabel = setLabelNull;
115        getLabel = getLabelNull;
116    }
117}
118
119void Caches::initConstraints() {
120    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
121}
122
123void Caches::initStaticProperties() {
124    gpuPixelBuffersEnabled = false;
125
126    // OpenGL ES 3.0+ specific features
127    if (mExtensions.hasPixelBufferObjects()) {
128        char property[PROPERTY_VALUE_MAX];
129        if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "true") > 0) {
130            gpuPixelBuffersEnabled = !strcmp(property, "true");
131        }
132    }
133}
134
135bool Caches::initProperties() {
136    bool prevDebugLayersUpdates = debugLayersUpdates;
137    bool prevDebugOverdraw = debugOverdraw;
138    StencilClipDebug prevDebugStencilClip = debugStencilClip;
139
140    char property[PROPERTY_VALUE_MAX];
141    if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, nullptr) > 0) {
142        INIT_LOGD("  Layers updates debug enabled: %s", property);
143        debugLayersUpdates = !strcmp(property, "true");
144    } else {
145        debugLayersUpdates = false;
146    }
147
148    debugOverdraw = false;
149    if (property_get(PROPERTY_DEBUG_OVERDRAW, property, nullptr) > 0) {
150        INIT_LOGD("  Overdraw debug enabled: %s", property);
151        if (!strcmp(property, "show")) {
152            debugOverdraw = true;
153            mOverdrawDebugColorSet = kColorSet_Default;
154        } else if (!strcmp(property, "show_deuteranomaly")) {
155            debugOverdraw = true;
156            mOverdrawDebugColorSet = kColorSet_Deuteranomaly;
157        }
158    }
159
160    // See Properties.h for valid values
161    if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, nullptr) > 0) {
162        INIT_LOGD("  Stencil clip debug enabled: %s", property);
163        if (!strcmp(property, "hide")) {
164            debugStencilClip = kStencilHide;
165        } else if (!strcmp(property, "highlight")) {
166            debugStencilClip = kStencilShowHighlight;
167        } else if (!strcmp(property, "region")) {
168            debugStencilClip = kStencilShowRegion;
169        }
170    } else {
171        debugStencilClip = kStencilHide;
172    }
173
174    if (property_get(PROPERTY_DISABLE_DRAW_DEFER, property, "false")) {
175        drawDeferDisabled = !strcasecmp(property, "true");
176        INIT_LOGD("  Draw defer %s", drawDeferDisabled ? "disabled" : "enabled");
177    } else {
178        drawDeferDisabled = false;
179        INIT_LOGD("  Draw defer enabled");
180    }
181
182    if (property_get(PROPERTY_DISABLE_DRAW_REORDER, property, "false")) {
183        drawReorderDisabled = !strcasecmp(property, "true");
184        INIT_LOGD("  Draw reorder %s", drawReorderDisabled ? "disabled" : "enabled");
185    } else {
186        drawReorderDisabled = false;
187        INIT_LOGD("  Draw reorder enabled");
188    }
189
190    return (prevDebugLayersUpdates != debugLayersUpdates) ||
191            (prevDebugOverdraw != debugOverdraw) ||
192            (prevDebugStencilClip != debugStencilClip);
193}
194
195void Caches::terminate() {
196    if (!mInitialized) return;
197    mRegionMesh.release();
198
199    fboCache.clear();
200
201    programCache.clear();
202    mProgram = nullptr;
203
204    patchCache.clear();
205
206    clearGarbage();
207
208    delete mPixelBufferState;
209    mPixelBufferState = nullptr;
210    delete mTextureState;
211    mTextureState = nullptr;
212    mInitialized = false;
213}
214
215void Caches::setProgram(const ProgramDescription& description) {
216    setProgram(programCache.get(description));
217}
218
219void Caches::setProgram(Program* program) {
220    if (!program || !program->isInUse()) {
221        if (mProgram) {
222            mProgram->remove();
223        }
224        if (program) {
225            program->use();
226        }
227        mProgram = program;
228    }
229}
230
231///////////////////////////////////////////////////////////////////////////////
232// Debug
233///////////////////////////////////////////////////////////////////////////////
234
235uint32_t Caches::getOverdrawColor(uint32_t amount) const {
236    static uint32_t sOverdrawColors[2][4] = {
237            { 0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000 },
238            { 0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000 }
239    };
240    if (amount < 1) amount = 1;
241    if (amount > 4) amount = 4;
242    return sOverdrawColors[mOverdrawDebugColorSet][amount - 1];
243}
244
245void Caches::dumpMemoryUsage() {
246    String8 stringLog;
247    dumpMemoryUsage(stringLog);
248    ALOGD("%s", stringLog.string());
249}
250
251void Caches::dumpMemoryUsage(String8 &log) {
252    uint32_t total = 0;
253    log.appendFormat("Current memory usage / total memory usage (bytes):\n");
254    log.appendFormat("  TextureCache         %8d / %8d\n",
255            textureCache.getSize(), textureCache.getMaxSize());
256    log.appendFormat("  LayerCache           %8d / %8d (numLayers = %zu)\n",
257            layerCache.getSize(), layerCache.getMaxSize(), layerCache.getCount());
258    if (mRenderState) {
259        int memused = 0;
260        for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin();
261                it != mRenderState->mActiveLayers.end(); it++) {
262            const Layer* layer = *it;
263            log.appendFormat("    Layer size %dx%d; isTextureLayer()=%d; texid=%u fbo=%u; refs=%d\n",
264                    layer->getWidth(), layer->getHeight(),
265                    layer->isTextureLayer(), layer->getTexture(),
266                    layer->getFbo(), layer->getStrongCount());
267            memused += layer->getWidth() * layer->getHeight() * 4;
268        }
269        log.appendFormat("  Layers total   %8d (numLayers = %zu)\n",
270                memused, mRenderState->mActiveLayers.size());
271        total += memused;
272    }
273    log.appendFormat("  RenderBufferCache    %8d / %8d\n",
274            renderBufferCache.getSize(), renderBufferCache.getMaxSize());
275    log.appendFormat("  GradientCache        %8d / %8d\n",
276            gradientCache.getSize(), gradientCache.getMaxSize());
277    log.appendFormat("  PathCache            %8d / %8d\n",
278            pathCache.getSize(), pathCache.getMaxSize());
279    log.appendFormat("  TessellationCache    %8d / %8d\n",
280            tessellationCache.getSize(), tessellationCache.getMaxSize());
281    log.appendFormat("  TextDropShadowCache  %8d / %8d\n", dropShadowCache.getSize(),
282            dropShadowCache.getMaxSize());
283    log.appendFormat("  PatchCache           %8d / %8d\n",
284            patchCache.getSize(), patchCache.getMaxSize());
285    for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
286        const uint32_t sizeA8 = fontRenderer->getFontRendererSize(i, GL_ALPHA);
287        const uint32_t sizeRGBA = fontRenderer->getFontRendererSize(i, GL_RGBA);
288        log.appendFormat("  FontRenderer %d A8    %8d / %8d\n", i, sizeA8, sizeA8);
289        log.appendFormat("  FontRenderer %d RGBA  %8d / %8d\n", i, sizeRGBA, sizeRGBA);
290        log.appendFormat("  FontRenderer %d total %8d / %8d\n", i, sizeA8 + sizeRGBA,
291                sizeA8 + sizeRGBA);
292    }
293    log.appendFormat("Other:\n");
294    log.appendFormat("  FboCache             %8d / %8d\n",
295            fboCache.getSize(), fboCache.getMaxSize());
296
297    total += textureCache.getSize();
298    total += renderBufferCache.getSize();
299    total += gradientCache.getSize();
300    total += pathCache.getSize();
301    total += tessellationCache.getSize();
302    total += dropShadowCache.getSize();
303    total += patchCache.getSize();
304    for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
305        total += fontRenderer->getFontRendererSize(i, GL_ALPHA);
306        total += fontRenderer->getFontRendererSize(i, GL_RGBA);
307    }
308
309    log.appendFormat("Total memory usage:\n");
310    log.appendFormat("  %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
311}
312
313///////////////////////////////////////////////////////////////////////////////
314// Memory management
315///////////////////////////////////////////////////////////////////////////////
316
317void Caches::clearGarbage() {
318    textureCache.clearGarbage();
319    pathCache.clearGarbage();
320    patchCache.clearGarbage();
321}
322
323void Caches::flush(FlushMode mode) {
324    FLUSH_LOGD("Flushing caches (mode %d)", mode);
325
326    // We must stop tasks before clearing caches
327    if (mode > kFlushMode_Layers) {
328        tasks.stop();
329    }
330
331    switch (mode) {
332        case kFlushMode_Full:
333            textureCache.clear();
334            patchCache.clear();
335            dropShadowCache.clear();
336            gradientCache.clear();
337            fontRenderer->clear();
338            fboCache.clear();
339            dither.clear();
340            // fall through
341        case kFlushMode_Moderate:
342            fontRenderer->flush();
343            textureCache.flush();
344            pathCache.clear();
345            tessellationCache.clear();
346            // fall through
347        case kFlushMode_Layers:
348            layerCache.clear();
349            renderBufferCache.clear();
350            break;
351    }
352
353    clearGarbage();
354    glFinish();
355}
356
357///////////////////////////////////////////////////////////////////////////////
358// Tiling
359///////////////////////////////////////////////////////////////////////////////
360
361void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard) {
362    if (mExtensions.hasTiledRendering() && !debugOverdraw) {
363        glStartTilingQCOM(x, y, width, height, (discard ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM));
364    }
365}
366
367void Caches::endTiling() {
368    if (mExtensions.hasTiledRendering() && !debugOverdraw) {
369        glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM);
370    }
371}
372
373bool Caches::hasRegisteredFunctors() {
374    return mFunctorsCount > 0;
375}
376
377void Caches::registerFunctors(uint32_t functorCount) {
378    mFunctorsCount += functorCount;
379}
380
381void Caches::unregisterFunctors(uint32_t functorCount) {
382    if (functorCount > mFunctorsCount) {
383        mFunctorsCount = 0;
384    } else {
385        mFunctorsCount -= functorCount;
386    }
387}
388
389///////////////////////////////////////////////////////////////////////////////
390// Regions
391///////////////////////////////////////////////////////////////////////////////
392
393TextureVertex* Caches::getRegionMesh() {
394    // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
395    if (!mRegionMesh) {
396        mRegionMesh.reset(new TextureVertex[kMaxNumberOfQuads * 4]);
397    }
398
399    return mRegionMesh.get();
400}
401
402///////////////////////////////////////////////////////////////////////////////
403// Temporary Properties
404///////////////////////////////////////////////////////////////////////////////
405
406void Caches::initTempProperties() {
407    propertyLightDiameter = -1.0f;
408    propertyLightPosY = -1.0f;
409    propertyLightPosZ = -1.0f;
410    propertyAmbientRatio = -1.0f;
411    propertyAmbientShadowStrength = -1;
412    propertySpotShadowStrength = -1;
413}
414
415void Caches::setTempProperty(const char* name, const char* value) {
416    ALOGD("setting property %s to %s", name, value);
417    if (!strcmp(name, "ambientRatio")) {
418        propertyAmbientRatio = fmin(fmax(atof(value), 0.0), 10.0);
419        ALOGD("ambientRatio = %.2f", propertyAmbientRatio);
420        return;
421    } else if (!strcmp(name, "lightDiameter")) {
422        propertyLightDiameter = fmin(fmax(atof(value), 0.0), 3000.0);
423        ALOGD("lightDiameter = %.2f", propertyLightDiameter);
424        return;
425    } else if (!strcmp(name, "lightPosY")) {
426        propertyLightPosY = fmin(fmax(atof(value), 0.0), 3000.0);
427        ALOGD("lightPos Y = %.2f", propertyLightPosY);
428        return;
429    } else if (!strcmp(name, "lightPosZ")) {
430        propertyLightPosZ = fmin(fmax(atof(value), 0.0), 3000.0);
431        ALOGD("lightPos Z = %.2f", propertyLightPosZ);
432        return;
433    } else if (!strcmp(name, "ambientShadowStrength")) {
434        propertyAmbientShadowStrength = atoi(value);
435        ALOGD("ambient shadow strength = 0x%x out of 0xff", propertyAmbientShadowStrength);
436        return;
437    } else if (!strcmp(name, "spotShadowStrength")) {
438        propertySpotShadowStrength = atoi(value);
439        ALOGD("spot shadow strength = 0x%x out of 0xff", propertySpotShadowStrength);
440        return;
441    }
442    ALOGD("    failed");
443}
444
445}; // namespace uirenderer
446}; // namespace android
447