OSDN Git Service

Fix memory leak in HWUI
[android-x86/frameworks-base.git] / libs / hwui / Caches.cpp
index cdf8150..2763e89 100644 (file)
 
 #define LOG_TAG "OpenGLRenderer"
 
-#include <utils/Log.h>
-#include <utils/String8.h>
-
 #include "Caches.h"
-#include "DisplayListRenderer.h"
-#include "Properties.h"
+
+#include "GammaFontRenderer.h"
 #include "LayerRenderer.h"
+#include "Properties.h"
+#include "renderstate/RenderState.h"
 #include "ShadowTessellator.h"
-#include "RenderState.h"
+#include "utils/GLUtils.h"
 
-namespace android {
-
-#ifdef USE_OPENGL_RENDERER
-using namespace uirenderer;
-ANDROID_SINGLETON_STATIC_INSTANCE(Caches);
-#endif
+#include <utils/Log.h>
+#include <utils/String8.h>
 
+namespace android {
 namespace uirenderer {
 
+Caches* Caches::sInstance = nullptr;
+
 ///////////////////////////////////////////////////////////////////////////////
 // Macros
 ///////////////////////////////////////////////////////////////////////////////
@@ -49,18 +47,19 @@ namespace uirenderer {
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-Caches::Caches(): Singleton<Caches>(),
-        mExtensions(Extensions::getInstance()), mInitialized(false), mRenderState(NULL) {
+Caches::Caches(RenderState& renderState)
+        : gradientCache(mExtensions)
+        , patchCache(renderState)
+        , programCache(mExtensions)
+        , dither(*this)
+        , mRenderState(&renderState)
+        , mInitialized(false) {
+    INIT_LOGD("Creating OpenGL renderer caches");
     init();
     initFont();
     initConstraints();
-    initProperties();
     initStaticProperties();
     initExtensions();
-    initTempProperties();
-
-    mDebugLevel = readDebugLevel();
-    ALOGD("Enabling debug mode %d", mDebugLevel);
 }
 
 bool Caches::init() {
@@ -68,45 +67,17 @@ bool Caches::init() {
 
     ATRACE_NAME("Caches::init");
 
-    glGenBuffers(1, &meshBuffer);
-    glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
-
-    mCurrentBuffer = meshBuffer;
-    mCurrentIndicesBuffer = 0;
-    mCurrentPositionPointer = this;
-    mCurrentPositionStride = 0;
-    mCurrentTexCoordsPointer = this;
-    mCurrentPixelBuffer = 0;
-
-    mTexCoordsArrayEnabled = false;
-
-    glDisable(GL_SCISSOR_TEST);
-    scissorEnabled = false;
-    mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
-
-    glActiveTexture(gTextureUnits[0]);
-    mTextureUnit = 0;
-
-    mRegionMesh = NULL;
-    mMeshIndices = 0;
-    mShadowStripsIndices = 0;
-    blend = false;
-    lastSrcMode = GL_ZERO;
-    lastDstMode = GL_ZERO;
-    currentProgram = NULL;
+    mRegionMesh = nullptr;
+    mProgram = nullptr;
 
     mFunctorsCount = 0;
 
-    debugLayersUpdates = false;
-    debugOverdraw = false;
-    debugStencilClip = kStencilHide;
-
-    patchCache.init(*this);
+    patchCache.init();
 
     mInitialized = true;
 
-    resetBoundTextures();
+    mPixelBufferState = new PixelBufferState();
+    mTextureState = new TextureState();
 
     return true;
 }
@@ -126,23 +97,9 @@ void Caches::initExtensions() {
         startMark = startMarkNull;
         endMark = endMarkNull;
     }
-
-    if (mExtensions.hasDebugLabel() && (drawDeferDisabled || drawReorderDisabled)) {
-        setLabel = glLabelObjectEXT;
-        getLabel = glGetObjectLabelEXT;
-    } else {
-        setLabel = setLabelNull;
-        getLabel = getLabelNull;
-    }
 }
 
 void Caches::initConstraints() {
-    GLint maxTextureUnits;
-    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
-    if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
-        ALOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
-    }
-
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
 }
 
@@ -158,92 +115,42 @@ void Caches::initStaticProperties() {
     }
 }
 
-bool Caches::initProperties() {
-    bool prevDebugLayersUpdates = debugLayersUpdates;
-    bool prevDebugOverdraw = debugOverdraw;
-    StencilClipDebug prevDebugStencilClip = debugStencilClip;
-
-    char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, NULL) > 0) {
-        INIT_LOGD("  Layers updates debug enabled: %s", property);
-        debugLayersUpdates = !strcmp(property, "true");
-    } else {
-        debugLayersUpdates = false;
-    }
-
-    debugOverdraw = false;
-    if (property_get(PROPERTY_DEBUG_OVERDRAW, property, NULL) > 0) {
-        INIT_LOGD("  Overdraw debug enabled: %s", property);
-        if (!strcmp(property, "show")) {
-            debugOverdraw = true;
-            mOverdrawDebugColorSet = kColorSet_Default;
-        } else if (!strcmp(property, "show_deuteranomaly")) {
-            debugOverdraw = true;
-            mOverdrawDebugColorSet = kColorSet_Deuteranomaly;
-        }
-    }
-
-    // See Properties.h for valid values
-    if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, NULL) > 0) {
-        INIT_LOGD("  Stencil clip debug enabled: %s", property);
-        if (!strcmp(property, "hide")) {
-            debugStencilClip = kStencilHide;
-        } else if (!strcmp(property, "highlight")) {
-            debugStencilClip = kStencilShowHighlight;
-        } else if (!strcmp(property, "region")) {
-            debugStencilClip = kStencilShowRegion;
-        }
-    } else {
-        debugStencilClip = kStencilHide;
-    }
-
-    if (property_get(PROPERTY_DISABLE_DRAW_DEFER, property, "false")) {
-        drawDeferDisabled = !strcasecmp(property, "true");
-        INIT_LOGD("  Draw defer %s", drawDeferDisabled ? "disabled" : "enabled");
-    } else {
-        drawDeferDisabled = false;
-        INIT_LOGD("  Draw defer enabled");
-    }
-
-    if (property_get(PROPERTY_DISABLE_DRAW_REORDER, property, "false")) {
-        drawReorderDisabled = !strcasecmp(property, "true");
-        INIT_LOGD("  Draw reorder %s", drawReorderDisabled ? "disabled" : "enabled");
-    } else {
-        drawReorderDisabled = false;
-        INIT_LOGD("  Draw reorder enabled");
-    }
-
-    return (prevDebugLayersUpdates != debugLayersUpdates) ||
-            (prevDebugOverdraw != debugOverdraw) ||
-            (prevDebugStencilClip != debugStencilClip);
-}
-
 void Caches::terminate() {
     if (!mInitialized) return;
-
-    glDeleteBuffers(1, &meshBuffer);
-    mCurrentBuffer = 0;
-
-    glDeleteBuffers(1, &mMeshIndices);
-    delete[] mRegionMesh;
-    mMeshIndices = 0;
-    mRegionMesh = NULL;
-
-    glDeleteBuffers(1, &mShadowStripsIndices);
-    mShadowStripsIndices = 0;
+    mRegionMesh.reset(nullptr);
 
     fboCache.clear();
 
     programCache.clear();
-    currentProgram = NULL;
+    mProgram = nullptr;
 
     patchCache.clear();
 
     clearGarbage();
 
+    delete mPixelBufferState;
+    mPixelBufferState = nullptr;
+    delete mTextureState;
+    mTextureState = nullptr;
     mInitialized = false;
 }
 
+void Caches::setProgram(const ProgramDescription& description) {
+    setProgram(programCache.get(description));
+}
+
+void Caches::setProgram(Program* program) {
+    if (!program || !program->isInUse()) {
+        if (mProgram) {
+            mProgram->remove();
+        }
+        if (program) {
+            program->use();
+        }
+        mProgram = program;
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Debug
 ///////////////////////////////////////////////////////////////////////////////
@@ -255,7 +162,9 @@ uint32_t Caches::getOverdrawColor(uint32_t amount) const {
     };
     if (amount < 1) amount = 1;
     if (amount > 4) amount = 4;
-    return sOverdrawColors[mOverdrawDebugColorSet][amount - 1];
+
+    int overdrawColorIndex = static_cast<int>(Properties::overdrawColorSet);
+    return sOverdrawColors[overdrawColorIndex][amount - 1];
 }
 
 void Caches::dumpMemoryUsage() {
@@ -278,7 +187,7 @@ void Caches::dumpMemoryUsage(String8 &log) {
             const Layer* layer = *it;
             log.appendFormat("    Layer size %dx%d; isTextureLayer()=%d; texid=%u fbo=%u; refs=%d\n",
                     layer->getWidth(), layer->getHeight(),
-                    layer->isTextureLayer(), layer->getTexture(),
+                    layer->isTextureLayer(), layer->getTextureId(),
                     layer->getFbo(), layer->getStrongCount());
             memused += layer->getWidth() * layer->getHeight() * 4;
         }
@@ -339,11 +248,6 @@ void Caches::clearGarbage() {
 void Caches::flush(FlushMode mode) {
     FLUSH_LOGD("Flushing caches (mode %d)", mode);
 
-    // We must stop tasks before clearing caches
-    if (mode > kFlushMode_Layers) {
-        tasks.stop();
-    }
-
     switch (mode) {
         case kFlushMode_Full:
             textureCache.clear();
@@ -368,285 +272,9 @@ void Caches::flush(FlushMode mode) {
 
     clearGarbage();
     glFinish();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// VBO
-///////////////////////////////////////////////////////////////////////////////
-
-bool Caches::bindMeshBuffer() {
-    return bindMeshBuffer(meshBuffer);
-}
-
-bool Caches::bindMeshBuffer(const GLuint buffer) {
-    if (mCurrentBuffer != buffer) {
-        glBindBuffer(GL_ARRAY_BUFFER, buffer);
-        mCurrentBuffer = buffer;
-        return true;
-    }
-    return false;
-}
-
-bool Caches::unbindMeshBuffer() {
-    if (mCurrentBuffer) {
-        glBindBuffer(GL_ARRAY_BUFFER, 0);
-        mCurrentBuffer = 0;
-        return true;
-    }
-    return false;
-}
-
-bool Caches::bindIndicesBufferInternal(const GLuint buffer) {
-    if (mCurrentIndicesBuffer != buffer) {
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
-        mCurrentIndicesBuffer = buffer;
-        return true;
-    }
-    return false;
-}
-
-bool Caches::bindQuadIndicesBuffer() {
-    if (!mMeshIndices) {
-        uint16_t* regionIndices = new uint16_t[gMaxNumberOfQuads * 6];
-        for (uint32_t i = 0; i < gMaxNumberOfQuads; i++) {
-            uint16_t quad = i * 4;
-            int index = i * 6;
-            regionIndices[index    ] = quad;       // top-left
-            regionIndices[index + 1] = quad + 1;   // top-right
-            regionIndices[index + 2] = quad + 2;   // bottom-left
-            regionIndices[index + 3] = quad + 2;   // bottom-left
-            regionIndices[index + 4] = quad + 1;   // top-right
-            regionIndices[index + 5] = quad + 3;   // bottom-right
-        }
-
-        glGenBuffers(1, &mMeshIndices);
-        bool force = bindIndicesBufferInternal(mMeshIndices);
-        glBufferData(GL_ELEMENT_ARRAY_BUFFER, gMaxNumberOfQuads * 6 * sizeof(uint16_t),
-                regionIndices, GL_STATIC_DRAW);
-
-        delete[] regionIndices;
-        return force;
-    }
-
-    return bindIndicesBufferInternal(mMeshIndices);
-}
-
-bool Caches::bindShadowIndicesBuffer() {
-    if (!mShadowStripsIndices) {
-        uint16_t* shadowIndices = new uint16_t[MAX_SHADOW_INDEX_COUNT];
-        ShadowTessellator::generateShadowIndices(shadowIndices);
-        glGenBuffers(1, &mShadowStripsIndices);
-        bool force = bindIndicesBufferInternal(mShadowStripsIndices);
-        glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_SHADOW_INDEX_COUNT * sizeof(uint16_t),
-            shadowIndices, GL_STATIC_DRAW);
-
-        delete[] shadowIndices;
-        return force;
-    }
-
-    return bindIndicesBufferInternal(mShadowStripsIndices);
-}
-
-bool Caches::unbindIndicesBuffer() {
-    if (mCurrentIndicesBuffer) {
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-        mCurrentIndicesBuffer = 0;
-        return true;
-    }
-    return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// PBO
-///////////////////////////////////////////////////////////////////////////////
-
-bool Caches::bindPixelBuffer(const GLuint buffer) {
-    if (mCurrentPixelBuffer != buffer) {
-        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
-        mCurrentPixelBuffer = buffer;
-        return true;
-    }
-    return false;
-}
-
-bool Caches::unbindPixelBuffer() {
-    if (mCurrentPixelBuffer) {
-        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
-        mCurrentPixelBuffer = 0;
-        return true;
-    }
-    return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Meshes and textures
-///////////////////////////////////////////////////////////////////////////////
-
-void Caches::bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
-    if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
-        GLuint slot = currentProgram->position;
-        glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
-        mCurrentPositionPointer = vertices;
-        mCurrentPositionStride = stride;
-    }
-}
-
-void Caches::bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
-    if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
-        GLuint slot = currentProgram->texCoords;
-        glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
-        mCurrentTexCoordsPointer = vertices;
-        mCurrentTexCoordsStride = stride;
-    }
-}
-
-void Caches::resetVertexPointers() {
-    mCurrentPositionPointer = this;
-    mCurrentTexCoordsPointer = this;
-}
-
-void Caches::resetTexCoordsVertexPointer() {
-    mCurrentTexCoordsPointer = this;
-}
-
-void Caches::enableTexCoordsVertexArray() {
-    if (!mTexCoordsArrayEnabled) {
-        glEnableVertexAttribArray(Program::kBindingTexCoords);
-        mCurrentTexCoordsPointer = this;
-        mTexCoordsArrayEnabled = true;
-    }
-}
-
-void Caches::disableTexCoordsVertexArray() {
-    if (mTexCoordsArrayEnabled) {
-        glDisableVertexAttribArray(Program::kBindingTexCoords);
-        mTexCoordsArrayEnabled = false;
-    }
-}
-
-void Caches::activeTexture(GLuint textureUnit) {
-    if (mTextureUnit != textureUnit) {
-        glActiveTexture(gTextureUnits[textureUnit]);
-        mTextureUnit = textureUnit;
-    }
-}
-
-void Caches::resetActiveTexture() {
-    mTextureUnit = -1;
-}
-
-void Caches::bindTexture(GLuint texture) {
-    if (mBoundTextures[mTextureUnit] != texture) {
-        glBindTexture(GL_TEXTURE_2D, texture);
-        mBoundTextures[mTextureUnit] = texture;
-    }
-}
-
-void Caches::bindTexture(GLenum target, GLuint texture) {
-    if (target == GL_TEXTURE_2D) {
-        bindTexture(texture);
-    } else {
-        // GLConsumer directly calls glBindTexture() with
-        // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target
-        // since the cached state could be stale
-        glBindTexture(target, texture);
-    }
-}
-
-void Caches::deleteTexture(GLuint texture) {
-    // When glDeleteTextures() is called on a currently bound texture,
-    // OpenGL ES specifies that the texture is then considered unbound
-    // Consider the following series of calls:
-    //
-    // glGenTextures -> creates texture name 2
-    // glBindTexture(2)
-    // glDeleteTextures(2) -> 2 is now unbound
-    // glGenTextures -> can return 2 again
-    //
-    // If we don't call glBindTexture(2) after the second glGenTextures
-    // call, any texture operation will be performed on the default
-    // texture (name=0)
-
-    unbindTexture(texture);
-
-    glDeleteTextures(1, &texture);
-}
-
-void Caches::resetBoundTextures() {
-    memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint));
-}
-
-void Caches::unbindTexture(GLuint texture) {
-    for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
-        if (mBoundTextures[i] == texture) {
-            mBoundTextures[i] = 0;
-        }
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Scissor
-///////////////////////////////////////////////////////////////////////////////
-
-bool Caches::setScissor(GLint x, GLint y, GLint width, GLint height) {
-    if (scissorEnabled && (x != mScissorX || y != mScissorY ||
-            width != mScissorWidth || height != mScissorHeight)) {
-
-        if (x < 0) {
-            width += x;
-            x = 0;
-        }
-        if (y < 0) {
-            height += y;
-            y = 0;
-        }
-        if (width < 0) {
-            width = 0;
-        }
-        if (height < 0) {
-            height = 0;
-        }
-        glScissor(x, y, width, height);
-
-        mScissorX = x;
-        mScissorY = y;
-        mScissorWidth = width;
-        mScissorHeight = height;
-
-        return true;
-    }
-    return false;
-}
-
-bool Caches::enableScissor() {
-    if (!scissorEnabled) {
-        glEnable(GL_SCISSOR_TEST);
-        scissorEnabled = true;
-        resetScissor();
-        return true;
-    }
-    return false;
-}
-
-bool Caches::disableScissor() {
-    if (scissorEnabled) {
-        glDisable(GL_SCISSOR_TEST);
-        scissorEnabled = false;
-        return true;
-    }
-    return false;
-}
-
-void Caches::setScissorEnabled(bool enabled) {
-    if (scissorEnabled != enabled) {
-        if (enabled) glEnable(GL_SCISSOR_TEST);
-        else glDisable(GL_SCISSOR_TEST);
-        scissorEnabled = enabled;
-    }
-}
-
-void Caches::resetScissor() {
-    mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
+    // Errors during cleanup should be considered non-fatal, dump them and
+    // and move on. TODO: All errors or just errors like bad surface?
+    GLUtils::dumpGLErrors();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -654,13 +282,13 @@ void Caches::resetScissor() {
 ///////////////////////////////////////////////////////////////////////////////
 
 void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard) {
-    if (mExtensions.hasTiledRendering() && !debugOverdraw) {
+    if (mExtensions.hasTiledRendering() && !Properties::debugOverdraw) {
         glStartTilingQCOM(x, y, width, height, (discard ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM));
     }
 }
 
 void Caches::endTiling() {
-    if (mExtensions.hasTiledRendering() && !debugOverdraw) {
+    if (mExtensions.hasTiledRendering() && !Properties::debugOverdraw) {
         glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM);
     }
 }
@@ -688,54 +316,15 @@ void Caches::unregisterFunctors(uint32_t functorCount) {
 TextureVertex* Caches::getRegionMesh() {
     // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
     if (!mRegionMesh) {
-        mRegionMesh = new TextureVertex[gMaxNumberOfQuads * 4];
+        mRegionMesh.reset(new TextureVertex[kMaxNumberOfQuads * 4]);
     }
 
-    return mRegionMesh;
+    return mRegionMesh.get();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Temporary Properties
 ///////////////////////////////////////////////////////////////////////////////
 
-void Caches::initTempProperties() {
-    propertyLightDiameter = -1.0f;
-    propertyLightPosY = -1.0f;
-    propertyLightPosZ = -1.0f;
-    propertyAmbientRatio = -1.0f;
-    propertyAmbientShadowStrength = -1;
-    propertySpotShadowStrength = -1;
-}
-
-void Caches::setTempProperty(const char* name, const char* value) {
-    ALOGD("setting property %s to %s", name, value);
-    if (!strcmp(name, "ambientRatio")) {
-        propertyAmbientRatio = fmin(fmax(atof(value), 0.0), 10.0);
-        ALOGD("ambientRatio = %.2f", propertyAmbientRatio);
-        return;
-    } else if (!strcmp(name, "lightDiameter")) {
-        propertyLightDiameter = fmin(fmax(atof(value), 0.0), 3000.0);
-        ALOGD("lightDiameter = %.2f", propertyLightDiameter);
-        return;
-    } else if (!strcmp(name, "lightPosY")) {
-        propertyLightPosY = fmin(fmax(atof(value), 0.0), 3000.0);
-        ALOGD("lightPos Y = %.2f", propertyLightPosY);
-        return;
-    } else if (!strcmp(name, "lightPosZ")) {
-        propertyLightPosZ = fmin(fmax(atof(value), 0.0), 3000.0);
-        ALOGD("lightPos Z = %.2f", propertyLightPosZ);
-        return;
-    } else if (!strcmp(name, "ambientShadowStrength")) {
-        propertyAmbientShadowStrength = atoi(value);
-        ALOGD("ambient shadow strength = 0x%x out of 0xff", propertyAmbientShadowStrength);
-        return;
-    } else if (!strcmp(name, "spotShadowStrength")) {
-        propertySpotShadowStrength = atoi(value);
-        ALOGD("spot shadow strength = 0x%x out of 0xff", propertySpotShadowStrength);
-        return;
-    }
-    ALOGD("    failed");
-}
-
 }; // namespace uirenderer
 }; // namespace android