• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <utils/Log.h>
20 #include <utils/String8.h>
21 
22 #include "Caches.h"
23 #include "DisplayListRenderer.h"
24 #include "Properties.h"
25 #include "LayerRenderer.h"
26 
27 namespace android {
28 
29 #ifdef USE_OPENGL_RENDERER
30 using namespace uirenderer;
31 ANDROID_SINGLETON_STATIC_INSTANCE(Caches);
32 #endif
33 
34 namespace uirenderer {
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 
Caches()50 Caches::Caches(): Singleton<Caches>(), mInitialized(false) {
51     init();
52     initExtensions();
53     initConstraints();
54 
55     mDebugLevel = readDebugLevel();
56     ALOGD("Enabling debug mode %d", mDebugLevel);
57 
58 #if RENDER_LAYERS_AS_REGIONS
59     INIT_LOGD("Layers will be composited as regions");
60 #endif
61 }
62 
init()63 void Caches::init() {
64     if (mInitialized) return;
65 
66     glGenBuffers(1, &meshBuffer);
67     glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
68     glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
69 
70     mCurrentBuffer = meshBuffer;
71     mCurrentIndicesBuffer = 0;
72     mCurrentPositionPointer = this;
73     mCurrentTexCoordsPointer = this;
74 
75     mTexCoordsArrayEnabled = false;
76 
77     mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
78 
79     glActiveTexture(gTextureUnits[0]);
80     mTextureUnit = 0;
81 
82     mRegionMesh = NULL;
83 
84     blend = false;
85     lastSrcMode = GL_ZERO;
86     lastDstMode = GL_ZERO;
87     currentProgram = NULL;
88 
89     mInitialized = true;
90 }
91 
initExtensions()92 void Caches::initExtensions() {
93     if (extensions.hasDebugMarker()) {
94         eventMark = glInsertEventMarkerEXT;
95         startMark = glPushGroupMarkerEXT;
96         endMark = glPopGroupMarkerEXT;
97     } else {
98         eventMark = eventMarkNull;
99         startMark = startMarkNull;
100         endMark = endMarkNull;
101     }
102 
103     if (extensions.hasDebugLabel()) {
104         setLabel = glLabelObjectEXT;
105         getLabel = glGetObjectLabelEXT;
106     } else {
107         setLabel = setLabelNull;
108         getLabel = getLabelNull;
109     }
110 }
111 
initConstraints()112 void Caches::initConstraints() {
113     GLint maxTextureUnits;
114     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
115     if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
116         ALOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
117     }
118 
119     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
120 }
121 
terminate()122 void Caches::terminate() {
123     if (!mInitialized) return;
124 
125     glDeleteBuffers(1, &meshBuffer);
126     mCurrentBuffer = 0;
127 
128     glDeleteBuffers(1, &mRegionMeshIndices);
129     delete[] mRegionMesh;
130     mRegionMesh = NULL;
131 
132     fboCache.clear();
133 
134     programCache.clear();
135     currentProgram = NULL;
136 
137     mInitialized = false;
138 }
139 
140 ///////////////////////////////////////////////////////////////////////////////
141 // Debug
142 ///////////////////////////////////////////////////////////////////////////////
143 
dumpMemoryUsage()144 void Caches::dumpMemoryUsage() {
145     String8 stringLog;
146     dumpMemoryUsage(stringLog);
147     ALOGD("%s", stringLog.string());
148 }
149 
dumpMemoryUsage(String8 & log)150 void Caches::dumpMemoryUsage(String8 &log) {
151     log.appendFormat("Current memory usage / total memory usage (bytes):\n");
152     log.appendFormat("  TextureCache         %8d / %8d\n",
153             textureCache.getSize(), textureCache.getMaxSize());
154     log.appendFormat("  LayerCache           %8d / %8d\n",
155             layerCache.getSize(), layerCache.getMaxSize());
156     log.appendFormat("  GradientCache        %8d / %8d\n",
157             gradientCache.getSize(), gradientCache.getMaxSize());
158     log.appendFormat("  PathCache            %8d / %8d\n",
159             pathCache.getSize(), pathCache.getMaxSize());
160     log.appendFormat("  CircleShapeCache     %8d / %8d\n",
161             circleShapeCache.getSize(), circleShapeCache.getMaxSize());
162     log.appendFormat("  OvalShapeCache       %8d / %8d\n",
163             ovalShapeCache.getSize(), ovalShapeCache.getMaxSize());
164     log.appendFormat("  RoundRectShapeCache  %8d / %8d\n",
165             roundRectShapeCache.getSize(), roundRectShapeCache.getMaxSize());
166     log.appendFormat("  RectShapeCache       %8d / %8d\n",
167             rectShapeCache.getSize(), rectShapeCache.getMaxSize());
168     log.appendFormat("  ArcShapeCache        %8d / %8d\n",
169             arcShapeCache.getSize(), arcShapeCache.getMaxSize());
170     log.appendFormat("  TextDropShadowCache  %8d / %8d\n", dropShadowCache.getSize(),
171             dropShadowCache.getMaxSize());
172     for (uint32_t i = 0; i < fontRenderer.getFontRendererCount(); i++) {
173         const uint32_t size = fontRenderer.getFontRendererSize(i);
174         log.appendFormat("  FontRenderer %d       %8d / %8d\n", i, size, size);
175     }
176     log.appendFormat("Other:\n");
177     log.appendFormat("  FboCache             %8d / %8d\n",
178             fboCache.getSize(), fboCache.getMaxSize());
179     log.appendFormat("  PatchCache           %8d / %8d\n",
180             patchCache.getSize(), patchCache.getMaxSize());
181 
182     uint32_t total = 0;
183     total += textureCache.getSize();
184     total += layerCache.getSize();
185     total += gradientCache.getSize();
186     total += pathCache.getSize();
187     total += dropShadowCache.getSize();
188     total += roundRectShapeCache.getSize();
189     total += circleShapeCache.getSize();
190     total += ovalShapeCache.getSize();
191     total += rectShapeCache.getSize();
192     total += arcShapeCache.getSize();
193     for (uint32_t i = 0; i < fontRenderer.getFontRendererCount(); i++) {
194         total += fontRenderer.getFontRendererSize(i);
195     }
196 
197     log.appendFormat("Total memory usage:\n");
198     log.appendFormat("  %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
199 }
200 
201 ///////////////////////////////////////////////////////////////////////////////
202 // Memory management
203 ///////////////////////////////////////////////////////////////////////////////
204 
clearGarbage()205 void Caches::clearGarbage() {
206     textureCache.clearGarbage();
207     pathCache.clearGarbage();
208 
209     Mutex::Autolock _l(mGarbageLock);
210 
211     size_t count = mLayerGarbage.size();
212     for (size_t i = 0; i < count; i++) {
213         Layer* layer = mLayerGarbage.itemAt(i);
214         LayerRenderer::destroyLayer(layer);
215     }
216     mLayerGarbage.clear();
217 
218     count = mDisplayListGarbage.size();
219     for (size_t i = 0; i < count; i++) {
220         DisplayList* displayList = mDisplayListGarbage.itemAt(i);
221         delete displayList;
222     }
223     mDisplayListGarbage.clear();
224 }
225 
deleteLayerDeferred(Layer * layer)226 void Caches::deleteLayerDeferred(Layer* layer) {
227     Mutex::Autolock _l(mGarbageLock);
228     mLayerGarbage.push(layer);
229 }
230 
deleteDisplayListDeferred(DisplayList * displayList)231 void Caches::deleteDisplayListDeferred(DisplayList* displayList) {
232     Mutex::Autolock _l(mGarbageLock);
233     mDisplayListGarbage.push(displayList);
234 }
235 
flush(FlushMode mode)236 void Caches::flush(FlushMode mode) {
237     FLUSH_LOGD("Flushing caches (mode %d)", mode);
238 
239     clearGarbage();
240 
241     switch (mode) {
242         case kFlushMode_Full:
243             textureCache.clear();
244             patchCache.clear();
245             dropShadowCache.clear();
246             gradientCache.clear();
247             fontRenderer.clear();
248             // fall through
249         case kFlushMode_Moderate:
250             fontRenderer.flush();
251             textureCache.flush();
252             pathCache.clear();
253             roundRectShapeCache.clear();
254             circleShapeCache.clear();
255             ovalShapeCache.clear();
256             rectShapeCache.clear();
257             arcShapeCache.clear();
258             // fall through
259         case kFlushMode_Layers:
260             layerCache.clear();
261             break;
262     }
263 }
264 
265 ///////////////////////////////////////////////////////////////////////////////
266 // VBO
267 ///////////////////////////////////////////////////////////////////////////////
268 
bindMeshBuffer()269 bool Caches::bindMeshBuffer() {
270     return bindMeshBuffer(meshBuffer);
271 }
272 
bindMeshBuffer(const GLuint buffer)273 bool Caches::bindMeshBuffer(const GLuint buffer) {
274     if (mCurrentBuffer != buffer) {
275         glBindBuffer(GL_ARRAY_BUFFER, buffer);
276         mCurrentBuffer = buffer;
277         return true;
278     }
279     return false;
280 }
281 
unbindMeshBuffer()282 bool Caches::unbindMeshBuffer() {
283     if (mCurrentBuffer) {
284         glBindBuffer(GL_ARRAY_BUFFER, 0);
285         mCurrentBuffer = 0;
286         return true;
287     }
288     return false;
289 }
290 
bindIndicesBuffer(const GLuint buffer)291 bool Caches::bindIndicesBuffer(const GLuint buffer) {
292     if (mCurrentIndicesBuffer != buffer) {
293         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
294         mCurrentIndicesBuffer = buffer;
295         return true;
296     }
297     return false;
298 }
299 
unbindIndicesBuffer()300 bool Caches::unbindIndicesBuffer() {
301     if (mCurrentIndicesBuffer) {
302         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
303         mCurrentIndicesBuffer = 0;
304         return true;
305     }
306     return false;
307 }
308 
bindPositionVertexPointer(bool force,GLuint slot,GLvoid * vertices,GLsizei stride)309 void Caches::bindPositionVertexPointer(bool force, GLuint slot, GLvoid* vertices, GLsizei stride) {
310     if (force || vertices != mCurrentPositionPointer) {
311         glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
312         mCurrentPositionPointer = vertices;
313     }
314 }
315 
bindTexCoordsVertexPointer(bool force,GLuint slot,GLvoid * vertices)316 void Caches::bindTexCoordsVertexPointer(bool force, GLuint slot, GLvoid* vertices) {
317     if (force || vertices != mCurrentTexCoordsPointer) {
318         glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, gMeshStride, vertices);
319         mCurrentTexCoordsPointer = vertices;
320     }
321 }
322 
resetVertexPointers()323 void Caches::resetVertexPointers() {
324     mCurrentPositionPointer = this;
325     mCurrentTexCoordsPointer = this;
326 }
327 
resetTexCoordsVertexPointer()328 void Caches::resetTexCoordsVertexPointer() {
329     mCurrentTexCoordsPointer = this;
330 }
331 
enableTexCoordsVertexArray()332 void Caches::enableTexCoordsVertexArray() {
333     if (!mTexCoordsArrayEnabled) {
334         glEnableVertexAttribArray(Program::kBindingTexCoords);
335         mCurrentTexCoordsPointer = this;
336         mTexCoordsArrayEnabled = true;
337     }
338 }
339 
disbaleTexCoordsVertexArray()340 void Caches::disbaleTexCoordsVertexArray() {
341     if (mTexCoordsArrayEnabled) {
342         glDisableVertexAttribArray(Program::kBindingTexCoords);
343         mTexCoordsArrayEnabled = false;
344     }
345 }
346 
activeTexture(GLuint textureUnit)347 void Caches::activeTexture(GLuint textureUnit) {
348     if (mTextureUnit != textureUnit) {
349         glActiveTexture(gTextureUnits[textureUnit]);
350         mTextureUnit = textureUnit;
351     }
352 }
353 
setScissor(GLint x,GLint y,GLint width,GLint height)354 void Caches::setScissor(GLint x, GLint y, GLint width, GLint height) {
355     if (x != mScissorX || y != mScissorY || width != mScissorWidth || height != mScissorHeight) {
356         glScissor(x, y, width, height);
357 
358         mScissorX = x;
359         mScissorY = y;
360         mScissorWidth = width;
361         mScissorHeight = height;
362     }
363 }
364 
resetScissor()365 void Caches::resetScissor() {
366     mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
367 }
368 
getRegionMesh()369 TextureVertex* Caches::getRegionMesh() {
370     // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
371     if (!mRegionMesh) {
372         mRegionMesh = new TextureVertex[REGION_MESH_QUAD_COUNT * 4];
373 
374         uint16_t* regionIndices = new uint16_t[REGION_MESH_QUAD_COUNT * 6];
375         for (int i = 0; i < REGION_MESH_QUAD_COUNT; i++) {
376             uint16_t quad = i * 4;
377             int index = i * 6;
378             regionIndices[index    ] = quad;       // top-left
379             regionIndices[index + 1] = quad + 1;   // top-right
380             regionIndices[index + 2] = quad + 2;   // bottom-left
381             regionIndices[index + 3] = quad + 2;   // bottom-left
382             regionIndices[index + 4] = quad + 1;   // top-right
383             regionIndices[index + 5] = quad + 3;   // bottom-right
384         }
385 
386         glGenBuffers(1, &mRegionMeshIndices);
387         bindIndicesBuffer(mRegionMeshIndices);
388         glBufferData(GL_ELEMENT_ARRAY_BUFFER, REGION_MESH_QUAD_COUNT * 6 * sizeof(uint16_t),
389                 regionIndices, GL_STATIC_DRAW);
390 
391         delete[] regionIndices;
392     } else {
393         bindIndicesBuffer(mRegionMeshIndices);
394     }
395 
396     return mRegionMesh;
397 }
398 
399 }; // namespace uirenderer
400 }; // namespace android
401