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