• 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>(),
51         mExtensions(Extensions::getInstance()), mInitialized(false) {
52     init();
53     initFont();
54     initConstraints();
55     initProperties();
56     initStaticProperties();
57     initExtensions();
58 
59     mDebugLevel = readDebugLevel();
60     ALOGD("Enabling debug mode %d", mDebugLevel);
61 }
62 
init()63 bool Caches::init() {
64     if (mInitialized) return false;
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     mCurrentPositionStride = 0;
74     mCurrentTexCoordsPointer = this;
75     mCurrentPixelBuffer = 0;
76 
77     mTexCoordsArrayEnabled = false;
78 
79     glDisable(GL_SCISSOR_TEST);
80     scissorEnabled = false;
81     mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
82 
83     glActiveTexture(gTextureUnits[0]);
84     mTextureUnit = 0;
85 
86     mRegionMesh = NULL;
87     mMeshIndices = 0;
88 
89     blend = false;
90     lastSrcMode = GL_ZERO;
91     lastDstMode = GL_ZERO;
92     currentProgram = NULL;
93 
94     mFunctorsCount = 0;
95 
96     debugLayersUpdates = false;
97     debugOverdraw = false;
98     debugStencilClip = kStencilHide;
99 
100     patchCache.init(*this);
101 
102     mInitialized = true;
103 
104     resetBoundTextures();
105 
106     return true;
107 }
108 
initFont()109 void Caches::initFont() {
110     fontRenderer = GammaFontRenderer::createRenderer();
111 }
112 
initExtensions()113 void Caches::initExtensions() {
114     if (mExtensions.hasDebugMarker()) {
115         eventMark = glInsertEventMarkerEXT;
116 
117         startMark = glPushGroupMarkerEXT;
118         endMark = glPopGroupMarkerEXT;
119     } else {
120         eventMark = eventMarkNull;
121         startMark = startMarkNull;
122         endMark = endMarkNull;
123     }
124 
125     if (mExtensions.hasDebugLabel() && (drawDeferDisabled || drawReorderDisabled)) {
126         setLabel = glLabelObjectEXT;
127         getLabel = glGetObjectLabelEXT;
128     } else {
129         setLabel = setLabelNull;
130         getLabel = getLabelNull;
131     }
132 }
133 
initConstraints()134 void Caches::initConstraints() {
135     GLint maxTextureUnits;
136     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
137     if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
138         ALOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
139     }
140 
141     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
142 }
143 
initStaticProperties()144 void Caches::initStaticProperties() {
145     gpuPixelBuffersEnabled = false;
146 
147     // OpenGL ES 3.0+ specific features
148     if (mExtensions.hasPixelBufferObjects()) {
149         char property[PROPERTY_VALUE_MAX];
150         if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "true") > 0) {
151             gpuPixelBuffersEnabled = !strcmp(property, "true");
152         }
153     }
154 }
155 
initProperties()156 bool Caches::initProperties() {
157     bool prevDebugLayersUpdates = debugLayersUpdates;
158     bool prevDebugOverdraw = debugOverdraw;
159     StencilClipDebug prevDebugStencilClip = debugStencilClip;
160 
161     char property[PROPERTY_VALUE_MAX];
162     if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, NULL) > 0) {
163         INIT_LOGD("  Layers updates debug enabled: %s", property);
164         debugLayersUpdates = !strcmp(property, "true");
165     } else {
166         debugLayersUpdates = false;
167     }
168 
169     debugOverdraw = false;
170     if (property_get(PROPERTY_DEBUG_OVERDRAW, property, NULL) > 0) {
171         INIT_LOGD("  Overdraw debug enabled: %s", property);
172         if (!strcmp(property, "show")) {
173             debugOverdraw = true;
174             mOverdrawDebugColorSet = kColorSet_Default;
175         } else if (!strcmp(property, "show_deuteranomaly")) {
176             debugOverdraw = true;
177             mOverdrawDebugColorSet = kColorSet_Deuteranomaly;
178         }
179     }
180 
181     // See Properties.h for valid values
182     if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, NULL) > 0) {
183         INIT_LOGD("  Stencil clip debug enabled: %s", property);
184         if (!strcmp(property, "hide")) {
185             debugStencilClip = kStencilHide;
186         } else if (!strcmp(property, "highlight")) {
187             debugStencilClip = kStencilShowHighlight;
188         } else if (!strcmp(property, "region")) {
189             debugStencilClip = kStencilShowRegion;
190         }
191     } else {
192         debugStencilClip = kStencilHide;
193     }
194 
195     if (property_get(PROPERTY_DISABLE_DRAW_DEFER, property, "false")) {
196         drawDeferDisabled = !strcasecmp(property, "true");
197         INIT_LOGD("  Draw defer %s", drawDeferDisabled ? "disabled" : "enabled");
198     } else {
199         INIT_LOGD("  Draw defer enabled");
200     }
201 
202     if (property_get(PROPERTY_DISABLE_DRAW_REORDER, property, "false")) {
203         drawReorderDisabled = !strcasecmp(property, "true");
204         INIT_LOGD("  Draw reorder %s", drawReorderDisabled ? "disabled" : "enabled");
205     } else {
206         INIT_LOGD("  Draw reorder enabled");
207     }
208 
209     return (prevDebugLayersUpdates != debugLayersUpdates) ||
210             (prevDebugOverdraw != debugOverdraw) ||
211             (prevDebugStencilClip != debugStencilClip);
212 }
213 
terminate()214 void Caches::terminate() {
215     if (!mInitialized) return;
216 
217     glDeleteBuffers(1, &meshBuffer);
218     mCurrentBuffer = 0;
219 
220     glDeleteBuffers(1, &mMeshIndices);
221     delete[] mRegionMesh;
222     mMeshIndices = 0;
223     mRegionMesh = NULL;
224 
225     fboCache.clear();
226 
227     programCache.clear();
228     currentProgram = NULL;
229 
230     assetAtlas.terminate();
231 
232     patchCache.clear();
233 
234     clearGarbage();
235 
236     mInitialized = false;
237 }
238 
239 ///////////////////////////////////////////////////////////////////////////////
240 // Debug
241 ///////////////////////////////////////////////////////////////////////////////
242 
getOverdrawColor(uint32_t amount) const243 uint32_t Caches::getOverdrawColor(uint32_t amount) const {
244     static uint32_t sOverdrawColors[2][4] = {
245             { 0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000 },
246             { 0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000 }
247     };
248     if (amount < 1) amount = 1;
249     if (amount > 4) amount = 4;
250     return sOverdrawColors[mOverdrawDebugColorSet][amount - 1];
251 }
252 
dumpMemoryUsage()253 void Caches::dumpMemoryUsage() {
254     String8 stringLog;
255     dumpMemoryUsage(stringLog);
256     ALOGD("%s", stringLog.string());
257 }
258 
dumpMemoryUsage(String8 & log)259 void Caches::dumpMemoryUsage(String8 &log) {
260     log.appendFormat("Current memory usage / total memory usage (bytes):\n");
261     log.appendFormat("  TextureCache         %8d / %8d\n",
262             textureCache.getSize(), textureCache.getMaxSize());
263     log.appendFormat("  LayerCache           %8d / %8d\n",
264             layerCache.getSize(), layerCache.getMaxSize());
265     log.appendFormat("  RenderBufferCache    %8d / %8d\n",
266             renderBufferCache.getSize(), renderBufferCache.getMaxSize());
267     log.appendFormat("  GradientCache        %8d / %8d\n",
268             gradientCache.getSize(), gradientCache.getMaxSize());
269     log.appendFormat("  PathCache            %8d / %8d\n",
270             pathCache.getSize(), pathCache.getMaxSize());
271     log.appendFormat("  TextDropShadowCache  %8d / %8d\n", dropShadowCache.getSize(),
272             dropShadowCache.getMaxSize());
273     log.appendFormat("  PatchCache           %8d / %8d\n",
274             patchCache.getSize(), patchCache.getMaxSize());
275     for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
276         const uint32_t sizeA8 = fontRenderer->getFontRendererSize(i, GL_ALPHA);
277         const uint32_t sizeRGBA = fontRenderer->getFontRendererSize(i, GL_RGBA);
278         log.appendFormat("  FontRenderer %d A8    %8d / %8d\n", i, sizeA8, sizeA8);
279         log.appendFormat("  FontRenderer %d RGBA  %8d / %8d\n", i, sizeRGBA, sizeRGBA);
280         log.appendFormat("  FontRenderer %d total %8d / %8d\n", i, sizeA8 + sizeRGBA,
281                 sizeA8 + sizeRGBA);
282     }
283     log.appendFormat("Other:\n");
284     log.appendFormat("  FboCache             %8d / %8d\n",
285             fboCache.getSize(), fboCache.getMaxSize());
286 
287     uint32_t total = 0;
288     total += textureCache.getSize();
289     total += layerCache.getSize();
290     total += renderBufferCache.getSize();
291     total += gradientCache.getSize();
292     total += pathCache.getSize();
293     total += dropShadowCache.getSize();
294     total += patchCache.getSize();
295     for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
296         total += fontRenderer->getFontRendererSize(i, GL_ALPHA);
297         total += fontRenderer->getFontRendererSize(i, GL_RGBA);
298     }
299 
300     log.appendFormat("Total memory usage:\n");
301     log.appendFormat("  %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
302 }
303 
304 ///////////////////////////////////////////////////////////////////////////////
305 // Memory management
306 ///////////////////////////////////////////////////////////////////////////////
307 
clearGarbage()308 void Caches::clearGarbage() {
309     textureCache.clearGarbage();
310     pathCache.clearGarbage();
311     patchCache.clearGarbage();
312 
313     Vector<DisplayList*> displayLists;
314     Vector<Layer*> layers;
315 
316     { // scope for the lock
317         Mutex::Autolock _l(mGarbageLock);
318         displayLists = mDisplayListGarbage;
319         layers = mLayerGarbage;
320         mDisplayListGarbage.clear();
321         mLayerGarbage.clear();
322     }
323 
324     size_t count = displayLists.size();
325     for (size_t i = 0; i < count; i++) {
326         DisplayList* displayList = displayLists.itemAt(i);
327         delete displayList;
328     }
329 
330     count = layers.size();
331     for (size_t i = 0; i < count; i++) {
332         Layer* layer = layers.itemAt(i);
333         delete layer;
334     }
335     layers.clear();
336 }
337 
deleteLayerDeferred(Layer * layer)338 void Caches::deleteLayerDeferred(Layer* layer) {
339     Mutex::Autolock _l(mGarbageLock);
340     mLayerGarbage.push(layer);
341 }
342 
deleteDisplayListDeferred(DisplayList * displayList)343 void Caches::deleteDisplayListDeferred(DisplayList* displayList) {
344     Mutex::Autolock _l(mGarbageLock);
345     mDisplayListGarbage.push(displayList);
346 }
347 
flush(FlushMode mode)348 void Caches::flush(FlushMode mode) {
349     FLUSH_LOGD("Flushing caches (mode %d)", mode);
350 
351     // We must stop tasks before clearing caches
352     if (mode > kFlushMode_Layers) {
353         tasks.stop();
354     }
355 
356     switch (mode) {
357         case kFlushMode_Full:
358             textureCache.clear();
359             patchCache.clear();
360             dropShadowCache.clear();
361             gradientCache.clear();
362             fontRenderer->clear();
363             fboCache.clear();
364             dither.clear();
365             // fall through
366         case kFlushMode_Moderate:
367             fontRenderer->flush();
368             textureCache.flush();
369             pathCache.clear();
370             // fall through
371         case kFlushMode_Layers:
372             layerCache.clear();
373             renderBufferCache.clear();
374             break;
375     }
376 
377     clearGarbage();
378 }
379 
380 ///////////////////////////////////////////////////////////////////////////////
381 // VBO
382 ///////////////////////////////////////////////////////////////////////////////
383 
bindMeshBuffer()384 bool Caches::bindMeshBuffer() {
385     return bindMeshBuffer(meshBuffer);
386 }
387 
bindMeshBuffer(const GLuint buffer)388 bool Caches::bindMeshBuffer(const GLuint buffer) {
389     if (mCurrentBuffer != buffer) {
390         glBindBuffer(GL_ARRAY_BUFFER, buffer);
391         mCurrentBuffer = buffer;
392         return true;
393     }
394     return false;
395 }
396 
unbindMeshBuffer()397 bool Caches::unbindMeshBuffer() {
398     if (mCurrentBuffer) {
399         glBindBuffer(GL_ARRAY_BUFFER, 0);
400         mCurrentBuffer = 0;
401         return true;
402     }
403     return false;
404 }
405 
bindIndicesBuffer(const GLuint buffer)406 bool Caches::bindIndicesBuffer(const GLuint buffer) {
407     if (mCurrentIndicesBuffer != buffer) {
408         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
409         mCurrentIndicesBuffer = buffer;
410         return true;
411     }
412     return false;
413 }
414 
bindIndicesBuffer()415 bool Caches::bindIndicesBuffer() {
416     if (!mMeshIndices) {
417         uint16_t* regionIndices = new uint16_t[gMaxNumberOfQuads * 6];
418         for (uint32_t i = 0; i < gMaxNumberOfQuads; i++) {
419             uint16_t quad = i * 4;
420             int index = i * 6;
421             regionIndices[index    ] = quad;       // top-left
422             regionIndices[index + 1] = quad + 1;   // top-right
423             regionIndices[index + 2] = quad + 2;   // bottom-left
424             regionIndices[index + 3] = quad + 2;   // bottom-left
425             regionIndices[index + 4] = quad + 1;   // top-right
426             regionIndices[index + 5] = quad + 3;   // bottom-right
427         }
428 
429         glGenBuffers(1, &mMeshIndices);
430         bool force = bindIndicesBuffer(mMeshIndices);
431         glBufferData(GL_ELEMENT_ARRAY_BUFFER, gMaxNumberOfQuads * 6 * sizeof(uint16_t),
432                 regionIndices, GL_STATIC_DRAW);
433 
434         delete[] regionIndices;
435         return force;
436     }
437 
438     return bindIndicesBuffer(mMeshIndices);
439 }
440 
unbindIndicesBuffer()441 bool Caches::unbindIndicesBuffer() {
442     if (mCurrentIndicesBuffer) {
443         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
444         mCurrentIndicesBuffer = 0;
445         return true;
446     }
447     return false;
448 }
449 
450 ///////////////////////////////////////////////////////////////////////////////
451 // PBO
452 ///////////////////////////////////////////////////////////////////////////////
453 
bindPixelBuffer(const GLuint buffer)454 bool Caches::bindPixelBuffer(const GLuint buffer) {
455     if (mCurrentPixelBuffer != buffer) {
456         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
457         mCurrentPixelBuffer = buffer;
458         return true;
459     }
460     return false;
461 }
462 
unbindPixelBuffer()463 bool Caches::unbindPixelBuffer() {
464     if (mCurrentPixelBuffer) {
465         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
466         mCurrentPixelBuffer = 0;
467         return true;
468     }
469     return false;
470 }
471 
472 ///////////////////////////////////////////////////////////////////////////////
473 // Meshes and textures
474 ///////////////////////////////////////////////////////////////////////////////
475 
bindPositionVertexPointer(bool force,GLvoid * vertices,GLsizei stride)476 void Caches::bindPositionVertexPointer(bool force, GLvoid* vertices, GLsizei stride) {
477     if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
478         GLuint slot = currentProgram->position;
479         glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
480         mCurrentPositionPointer = vertices;
481         mCurrentPositionStride = stride;
482     }
483 }
484 
bindTexCoordsVertexPointer(bool force,GLvoid * vertices,GLsizei stride)485 void Caches::bindTexCoordsVertexPointer(bool force, GLvoid* vertices, GLsizei stride) {
486     if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
487         GLuint slot = currentProgram->texCoords;
488         glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
489         mCurrentTexCoordsPointer = vertices;
490         mCurrentTexCoordsStride = stride;
491     }
492 }
493 
resetVertexPointers()494 void Caches::resetVertexPointers() {
495     mCurrentPositionPointer = this;
496     mCurrentTexCoordsPointer = this;
497 }
498 
resetTexCoordsVertexPointer()499 void Caches::resetTexCoordsVertexPointer() {
500     mCurrentTexCoordsPointer = this;
501 }
502 
enableTexCoordsVertexArray()503 void Caches::enableTexCoordsVertexArray() {
504     if (!mTexCoordsArrayEnabled) {
505         glEnableVertexAttribArray(Program::kBindingTexCoords);
506         mCurrentTexCoordsPointer = this;
507         mTexCoordsArrayEnabled = true;
508     }
509 }
510 
disableTexCoordsVertexArray()511 void Caches::disableTexCoordsVertexArray() {
512     if (mTexCoordsArrayEnabled) {
513         glDisableVertexAttribArray(Program::kBindingTexCoords);
514         mTexCoordsArrayEnabled = false;
515     }
516 }
517 
activeTexture(GLuint textureUnit)518 void Caches::activeTexture(GLuint textureUnit) {
519     if (mTextureUnit != textureUnit) {
520         glActiveTexture(gTextureUnits[textureUnit]);
521         mTextureUnit = textureUnit;
522     }
523 }
524 
resetActiveTexture()525 void Caches::resetActiveTexture() {
526     mTextureUnit = -1;
527 }
528 
bindTexture(GLuint texture)529 void Caches::bindTexture(GLuint texture) {
530     if (mBoundTextures[mTextureUnit] != texture) {
531         glBindTexture(GL_TEXTURE_2D, texture);
532         mBoundTextures[mTextureUnit] = texture;
533     }
534 }
535 
bindTexture(GLenum target,GLuint texture)536 void Caches::bindTexture(GLenum target, GLuint texture) {
537     if (mBoundTextures[mTextureUnit] != texture) {
538         glBindTexture(target, texture);
539         mBoundTextures[mTextureUnit] = texture;
540     }
541 }
542 
deleteTexture(GLuint texture)543 void Caches::deleteTexture(GLuint texture) {
544     // When glDeleteTextures() is called on a currently bound texture,
545     // OpenGL ES specifies that the texture is then considered unbound
546     // Consider the following series of calls:
547     //
548     // glGenTextures -> creates texture name 2
549     // glBindTexture(2)
550     // glDeleteTextures(2) -> 2 is now unbound
551     // glGenTextures -> can return 2 again
552     //
553     // If we don't call glBindTexture(2) after the second glGenTextures
554     // call, any texture operation will be performed on the default
555     // texture (name=0)
556 
557     for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
558         if (mBoundTextures[i] == texture) {
559             mBoundTextures[i] = 0;
560         }
561     }
562     glDeleteTextures(1, &texture);
563 }
564 
resetBoundTextures()565 void Caches::resetBoundTextures() {
566     memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint));
567 }
568 
569 ///////////////////////////////////////////////////////////////////////////////
570 // Scissor
571 ///////////////////////////////////////////////////////////////////////////////
572 
setScissor(GLint x,GLint y,GLint width,GLint height)573 bool Caches::setScissor(GLint x, GLint y, GLint width, GLint height) {
574     if (scissorEnabled && (x != mScissorX || y != mScissorY ||
575             width != mScissorWidth || height != mScissorHeight)) {
576 
577         if (x < 0) {
578             width += x;
579             x = 0;
580         }
581         if (y < 0) {
582             height += y;
583             y = 0;
584         }
585         if (width < 0) {
586             width = 0;
587         }
588         if (height < 0) {
589             height = 0;
590         }
591         glScissor(x, y, width, height);
592 
593         mScissorX = x;
594         mScissorY = y;
595         mScissorWidth = width;
596         mScissorHeight = height;
597 
598         return true;
599     }
600     return false;
601 }
602 
enableScissor()603 bool Caches::enableScissor() {
604     if (!scissorEnabled) {
605         glEnable(GL_SCISSOR_TEST);
606         scissorEnabled = true;
607         resetScissor();
608         return true;
609     }
610     return false;
611 }
612 
disableScissor()613 bool Caches::disableScissor() {
614     if (scissorEnabled) {
615         glDisable(GL_SCISSOR_TEST);
616         scissorEnabled = false;
617         return true;
618     }
619     return false;
620 }
621 
setScissorEnabled(bool enabled)622 void Caches::setScissorEnabled(bool enabled) {
623     if (scissorEnabled != enabled) {
624         if (enabled) glEnable(GL_SCISSOR_TEST);
625         else glDisable(GL_SCISSOR_TEST);
626         scissorEnabled = enabled;
627     }
628 }
629 
resetScissor()630 void Caches::resetScissor() {
631     mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
632 }
633 
634 ///////////////////////////////////////////////////////////////////////////////
635 // Tiling
636 ///////////////////////////////////////////////////////////////////////////////
637 
startTiling(GLuint x,GLuint y,GLuint width,GLuint height,bool discard)638 void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard) {
639     if (mExtensions.hasTiledRendering() && !debugOverdraw) {
640         glStartTilingQCOM(x, y, width, height, (discard ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM));
641     }
642 }
643 
endTiling()644 void Caches::endTiling() {
645     if (mExtensions.hasTiledRendering() && !debugOverdraw) {
646         glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM);
647     }
648 }
649 
hasRegisteredFunctors()650 bool Caches::hasRegisteredFunctors() {
651     return mFunctorsCount > 0;
652 }
653 
registerFunctors(uint32_t functorCount)654 void Caches::registerFunctors(uint32_t functorCount) {
655     mFunctorsCount += functorCount;
656 }
657 
unregisterFunctors(uint32_t functorCount)658 void Caches::unregisterFunctors(uint32_t functorCount) {
659     if (functorCount > mFunctorsCount) {
660         mFunctorsCount = 0;
661     } else {
662         mFunctorsCount -= functorCount;
663     }
664 }
665 
666 ///////////////////////////////////////////////////////////////////////////////
667 // Regions
668 ///////////////////////////////////////////////////////////////////////////////
669 
getRegionMesh()670 TextureVertex* Caches::getRegionMesh() {
671     // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
672     if (!mRegionMesh) {
673         mRegionMesh = new TextureVertex[gMaxNumberOfQuads * 4];
674     }
675 
676     return mRegionMesh;
677 }
678 
679 }; // namespace uirenderer
680 }; // namespace android
681