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