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