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