diff options
-rw-r--r-- | core/java/android/view/GLES20Canvas.java | 23 | ||||
-rw-r--r-- | core/java/android/view/HardwareRenderer.java | 148 | ||||
-rw-r--r-- | core/java/android/view/ViewRoot.java | 34 | ||||
-rw-r--r-- | core/jni/android_view_GLES20Canvas.cpp | 3 | ||||
-rw-r--r-- | libs/hwui/Caches.h | 75 | ||||
-rw-r--r-- | libs/hwui/GenerationCache.h | 10 | ||||
-rw-r--r-- | libs/hwui/GradientCache.cpp | 15 | ||||
-rw-r--r-- | libs/hwui/GradientCache.h | 1 | ||||
-rw-r--r-- | libs/hwui/LayerCache.cpp | 13 | ||||
-rw-r--r-- | libs/hwui/LayerCache.h | 1 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 164 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 26 | ||||
-rw-r--r-- | libs/hwui/PatchCache.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/PatchCache.h | 1 | ||||
-rw-r--r-- | libs/hwui/PathCache.cpp | 26 | ||||
-rw-r--r-- | libs/hwui/PathCache.h | 3 | ||||
-rw-r--r-- | libs/hwui/ProgramCache.h | 1 | ||||
-rw-r--r-- | libs/hwui/Properties.h | 12 | ||||
-rw-r--r-- | libs/hwui/TextDropShadowCache.cpp | 14 | ||||
-rw-r--r-- | libs/hwui/TextDropShadowCache.h | 21 | ||||
-rw-r--r-- | libs/hwui/TextureCache.cpp | 27 | ||||
-rw-r--r-- | libs/hwui/TextureCache.h | 3 | ||||
-rw-r--r-- | tests/HwAccelerationTest/src/com/google/android/test/hwui/ListActivity.java | 12 |
23 files changed, 392 insertions, 245 deletions
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 4c72e95..b058685 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -44,7 +44,7 @@ class GLES20Canvas extends Canvas { @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) private final GL mGl; private final boolean mOpaque; - private final int mRenderer; + private int mRenderer; private int mWidth; private int mHeight; @@ -76,16 +76,25 @@ class GLES20Canvas extends Canvas { mOpaque = !translucent; mRenderer = nCreateRenderer(); + if (mRenderer == 0) { + throw new IllegalStateException("Could not create GLES20Canvas renderer"); + } } - + private native int nCreateRenderer(); - @Override - protected void finalize() throws Throwable { - try { - super.finalize(); - } finally { + /** + * This method <strong>must</strong> be called before releasing a + * reference to a GLES20Canvas. This method is responsible for freeing + * native resources associated with the hardware. Not invoking this + * method properly can result in memory leaks. + * + * @hide + */ + public synchronized void destroy() { + if (mRenderer != 0) { nDestroyRenderer(mRenderer); + mRenderer = 0; } } diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index ca60a89..32d8123 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -35,9 +35,10 @@ import javax.microedition.khronos.opengles.GL; * @hide */ public abstract class HardwareRenderer { + private static final String LOG_TAG = "HardwareRenderer"; + private boolean mEnabled; private boolean mRequested = true; - private static final String LOG_TAG = "HardwareRenderer"; /** * Indicates whether hardware acceleration is available under any form for @@ -70,9 +71,8 @@ public abstract class HardwareRenderer { * * @param width Width of the drawing surface. * @param height Height of the drawing surface. - * @param attachInfo The AttachInfo used to render the ViewRoot. */ - abstract void setup(int width, int height, View.AttachInfo attachInfo); + abstract void setup(int width, int height); /** * Draws the specified view. @@ -96,12 +96,11 @@ public abstract class HardwareRenderer { */ void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, SurfaceHolder holder) { - if (isRequested()) { // We lost the gl context, so recreate it. if (!isEnabled()) { if (initialize(holder)) { - setup(width, height, attachInfo); + setup(width, height); } } } @@ -165,18 +164,23 @@ public abstract class HardwareRenderer { static abstract class GlRenderer extends HardwareRenderer { private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; - EGL10 mEgl; - EGLDisplay mEglDisplay; - EGLContext mEglContext; - EGLSurface mEglSurface; - EGLConfig mEglConfig; + static EGLContext sEglContext; + static EGL10 sEgl; + static EGLDisplay sEglDisplay; + static EGLConfig sEglConfig; + private static Thread sEglThread; + + EGLSurface mEglSurface; + GL mGl; - Canvas mCanvas; + GLES20Canvas mCanvas; final int mGlVersion; final boolean mTranslucent; + private boolean mDestroyed; + GlRenderer(int glVersion, boolean translucent) { mGlVersion = glVersion; mTranslucent = translucent; @@ -189,7 +193,7 @@ public abstract class HardwareRenderer { */ void checkErrors() { if (isEnabled()) { - int error = mEgl.eglGetError(); + int error = sEgl.eglGetError(); if (error != EGL10.EGL_SUCCESS) { // something bad has happened revert to // normal rendering. @@ -208,13 +212,17 @@ public abstract class HardwareRenderer { if (isRequested() && !isEnabled()) { initializeEgl(); mGl = createEglSurface(holder); + mDestroyed = false; if (mGl != null) { - int err = mEgl.eglGetError(); + int err = sEgl.eglGetError(); if (err != EGL10.EGL_SUCCESS) { destroy(); setRequested(false); } else { + if (mCanvas != null) { + destroyCanvas(); + } mCanvas = createCanvas(); if (mCanvas != null) { setEnabled(true); @@ -229,64 +237,75 @@ public abstract class HardwareRenderer { return false; } - abstract Canvas createCanvas(); + private void destroyCanvas() { + mCanvas.destroy(); + mCanvas = null; + } + + abstract GLES20Canvas createCanvas(); void initializeEgl() { - mEgl = (EGL10) EGLContext.getEGL(); + if (sEglContext != null) return; + + sEglThread = Thread.currentThread(); + sEgl = (EGL10) EGLContext.getEGL(); // Get to the default display. - mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + sEglDisplay = sEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - if (mEglDisplay == EGL10.EGL_NO_DISPLAY) { + if (sEglDisplay == EGL10.EGL_NO_DISPLAY) { throw new RuntimeException("eglGetDisplay failed"); } // We can now initialize EGL for that display int[] version = new int[2]; - if (!mEgl.eglInitialize(mEglDisplay, version)) { + if (!sEgl.eglInitialize(sEglDisplay, version)) { throw new RuntimeException("eglInitialize failed"); } - mEglConfig = getConfigChooser(mGlVersion).chooseConfig(mEgl, mEglDisplay); + sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay); /* * Create an EGL context. We want to do this as rarely as we can, because an * EGL context is a somewhat heavy object. */ - mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); + sEglContext = createContext(sEgl, sEglDisplay, sEglConfig); } GL createEglSurface(SurfaceHolder holder) { // Check preconditions. - if (mEgl == null) { + if (sEgl == null) { throw new RuntimeException("egl not initialized"); } - if (mEglDisplay == null) { + if (sEglDisplay == null) { throw new RuntimeException("eglDisplay not initialized"); } - if (mEglConfig == null) { + if (sEglConfig == null) { throw new RuntimeException("mEglConfig not initialized"); } + if (Thread.currentThread() != sEglThread) { + throw new IllegalStateException("HardwareRenderer cannot be used " + + "from multiple threads"); + } /* * The window size has changed, so we need to create a new * surface. */ if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) { - /* * Unbind and destroy the old EGL surface, if * there is one. */ - mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, + sEgl.eglMakeCurrent(sEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); - mEgl.eglDestroySurface(mEglDisplay, mEglSurface); + sEgl.eglDestroySurface(sEglDisplay, mEglSurface); } // Create an EGL surface we can render into. - mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, holder, null); + mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null); if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) { - int error = mEgl.eglGetError(); + int error = sEgl.eglGetError(); if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); return null; @@ -298,11 +317,11 @@ public abstract class HardwareRenderer { * Before we can issue GL commands, we need to make sure * the context is current and bound to a surface. */ - if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) { throw new RuntimeException("eglMakeCurrent failed"); } - return mEglContext.getGL(); + return sEglContext.getGL(); } EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { @@ -315,7 +334,6 @@ public abstract class HardwareRenderer { @Override void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, SurfaceHolder holder) { - if (isRequested()) { checkErrors(); super.initializeIfNeeded(width, height, attachInfo, holder); @@ -324,28 +342,34 @@ public abstract class HardwareRenderer { @Override void destroy() { - if (!isEnabled()) return; + if (!isEnabled() || mDestroyed) return; + + mDestroyed = true; - mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, + checkCurrent(); + // Destroy the Canvas first in case it needs to use a GL context + // to perform its cleanup. + destroyCanvas(); + + sEgl.eglMakeCurrent(sEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); - mEgl.eglDestroyContext(mEglDisplay, mEglContext); - mEgl.eglDestroySurface(mEglDisplay, mEglSurface); - mEgl.eglTerminate(mEglDisplay); + sEgl.eglDestroySurface(sEglDisplay, mEglSurface); - mEglContext = null; mEglSurface = null; - mEglDisplay = null; - mEgl = null; mGl = null; - mCanvas = null; + + // mEgl.eglDestroyContext(mEglDisplay, mEglContext); + // mEglContext = null; + // mEgl.eglTerminate(mEglDisplay); + // mEgl = null; + // mEglDisplay = null; setEnabled(false); - } - + } + @Override - void setup(int width, int height, View.AttachInfo attachInfo) { - final float scale = attachInfo.mApplicationScale; - mCanvas.setViewport((int) (width * scale + 0.5f), (int) (height * scale + 0.5f)); + void setup(int width, int height) { + mCanvas.setViewport(width, height); } boolean canDraw() { @@ -363,7 +387,8 @@ public abstract class HardwareRenderer { * @param glVersion */ EglConfigChooser getConfigChooser(int glVersion) { - return new ComponentSizeChooser(glVersion, 8, 8, 8, mTranslucent ? 8 : 0, 0, 0); + // TODO: Check for mTranslucent here, which means at least 2 EGL contexts + return new ComponentSizeChooser(glVersion, 8, 8, 8, 8, 0, 0); } @Override @@ -373,14 +398,7 @@ public abstract class HardwareRenderer { attachInfo.mIgnoreDirtyState = true; view.mPrivateFlags |= View.DRAWN; - // TODO: Don't check the current context when we have one per UI thread - // TODO: Use a threadlocal flag to know whether the surface has changed - if (mEgl.eglGetCurrentContext() != mEglContext || - mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW) != mEglSurface) { - if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { - throw new RuntimeException("eglMakeCurrent failed"); - } - } + checkCurrent(); onPreDraw(); @@ -396,11 +414,22 @@ public abstract class HardwareRenderer { attachInfo.mIgnoreDirtyState = false; - mEgl.eglSwapBuffers(mEglDisplay, mEglSurface); + sEgl.eglSwapBuffers(sEglDisplay, mEglSurface); checkErrors(); } } + private void checkCurrent() { + // TODO: Don't check the current context when we have one per UI thread + // TODO: Use a threadlocal flag to know whether the surface has changed + if (sEgl.eglGetCurrentContext() != sEglContext || + sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW) != mEglSurface) { + if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) { + throw new RuntimeException("eglMakeCurrent failed"); + } + } + } + static abstract class EglConfigChooser { final int[] mConfigSpec; private final int mGlVersion; @@ -496,7 +525,7 @@ public abstract class HardwareRenderer { int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0); int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0); int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0); - if (r == mRedSize && g == mGreenSize && b == mBlueSize && a >= mAlphaSize) { + if (r >= mRedSize && g >= mGreenSize && b >= mBlueSize && a >= mAlphaSize) { return config; } } @@ -514,7 +543,7 @@ public abstract class HardwareRenderer { } } } - + /** * Hardware renderer using OpenGL ES 2.0. */ @@ -526,8 +555,9 @@ public abstract class HardwareRenderer { } @Override - Canvas createCanvas() { - return mGlCanvas = new GLES20Canvas(mGl, mTranslucent); + GLES20Canvas createCanvas() { + // TODO: Pass mTranslucent instead of true + return mGlCanvas = new GLES20Canvas(mGl, true); } @Override diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index d32ccb1..5999aba 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -251,7 +251,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn mTempRect = new Rect(); mVisRect = new Rect(); mWinFrame = new Rect(); - mWindow = new W(this, context); + mWindow = new W(this); mInputMethodCallback = new InputMethodCallback(this); mViewVisibility = View.GONE; mTransparentRegion = new Region(); @@ -469,6 +469,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn if (attrs != null && (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0) { final boolean translucent = attrs.format != PixelFormat.OPAQUE; + destroyHardwareRenderer(); mHwRenderer = HardwareRenderer.createGlRenderer(2, translucent); } } @@ -677,9 +678,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn attachInfo.mWindowVisibility = viewVisibility; host.dispatchWindowVisibilityChanged(viewVisibility); if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) { - if (mHwRenderer != null) { - mHwRenderer.destroy(); - } + destroyHardwareRenderer(); } if (viewVisibility == View.GONE) { // After making a window gone, we will count it as being @@ -963,7 +962,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn } if (hwIntialized) { - mHwRenderer.setup(mWidth, mHeight, mAttachInfo); + mHwRenderer.setup(mWidth, mHeight); } boolean focusChangedDueToTouchMode = ensureTouchModeLocally( @@ -1598,9 +1597,9 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn mAttachInfo.mRootView = null; mAttachInfo.mSurface = null; - if (mHwRenderer != null) { - mHwRenderer.destroy(); - } + destroyHardwareRenderer(); + mHwRenderer = null; + mSurface.release(); if (mInputChannel != null) { @@ -1625,6 +1624,12 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn } } + private void destroyHardwareRenderer() { + if (mHwRenderer != null) { + mHwRenderer.destroy(); + } + } + void updateConfiguration(Configuration config, boolean force) { if (DEBUG_CONFIGURATION) Log.v(TAG, "Applying new config to window " @@ -2734,10 +2739,6 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn public void childDrawableStateChanged(View child) { } - protected Rect getWindowFrame() { - return mWinFrame; - } - void checkThread() { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( @@ -2816,16 +2817,15 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn static class W extends IWindow.Stub { private final WeakReference<ViewRoot> mViewRoot; - public W(ViewRoot viewRoot, Context context) { + W(ViewRoot viewRoot) { mViewRoot = new WeakReference<ViewRoot>(viewRoot); } - public void resized(int w, int h, Rect coveredInsets, - Rect visibleInsets, boolean reportDraw, Configuration newConfig) { + public void resized(int w, int h, Rect coveredInsets, Rect visibleInsets, + boolean reportDraw, Configuration newConfig) { final ViewRoot viewRoot = mViewRoot.get(); if (viewRoot != null) { - viewRoot.dispatchResized(w, h, coveredInsets, - visibleInsets, reportDraw, newConfig); + viewRoot.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw, newConfig); } } diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 4c6eced..98c03a6 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -34,7 +34,6 @@ #include <SkiaShader.h> #include <SkiaColorFilter.h> #include <Rect.h> -#include <ui/Rect.h> #include "TextLayout.h" @@ -418,7 +417,7 @@ static JNINativeMethod gMethods[] = { { "nDrawTextRun", "(ILjava/lang/String;IIIIFFII)V", (void*) android_view_GLES20Canvas_drawTextRun }, - { "nGetClipBounds", "(ILandroid/graphics/Rect;)Z", + { "nGetClipBounds", "(ILandroid/graphics/Rect;)Z", (void*) android_view_GLES20Canvas_getClipBounds }, #endif }; diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h new file mode 100644 index 0000000..0789d89 --- /dev/null +++ b/libs/hwui/Caches.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_UI_CACHES_H +#define ANDROID_UI_CACHES_H + +#define LOG_TAG "OpenGLRenderer" + +#include <utils/Singleton.h> + +#include "TextureCache.h" +#include "LayerCache.h" +#include "GradientCache.h" +#include "PatchCache.h" +#include "FontRenderer.h" +#include "ProgramCache.h" +#include "PathCache.h" +#include "TextDropShadowCache.h" + +namespace android { +namespace uirenderer { + +struct CacheLogger { + CacheLogger() { + LOGD("Creating caches"); + } +}; // struct CacheLogger + +class Caches: public Singleton<Caches> { + Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO), + lastDstMode(GL_ZERO), currentProgram(NULL) { + dropShadowCache.setFontRenderer(fontRenderer); + } + + friend class Singleton<Caches>; + + CacheLogger logger; + +public: + bool blend; + GLenum lastSrcMode; + GLenum lastDstMode; + Program* currentProgram; + + TextureCache textureCache; + LayerCache layerCache; + GradientCache gradientCache; + ProgramCache programCache; + PathCache pathCache; + PatchCache patchCache; + TextDropShadowCache dropShadowCache; + FontRenderer fontRenderer; +}; // class Caches + +}; // namespace uirenderer + +using namespace uirenderer; +ANDROID_SINGLETON_STATIC_INSTANCE(Caches); + +}; // namespace android + +#endif // ANDROID_UI_CACHES_H diff --git a/libs/hwui/GenerationCache.h b/libs/hwui/GenerationCache.h index 45b3ffa..c358c80 100644 --- a/libs/hwui/GenerationCache.h +++ b/libs/hwui/GenerationCache.h @@ -104,12 +104,14 @@ void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* list template<typename K, typename V> void GenerationCache<K, V>::clear() { if (mListener) { - while (mCache.size() > 0) { - removeOldest(); + for (uint32_t i = 0; i < mCache.size(); i++) { + sp<Entry<K, V> > entry = mCache.valueAt(i); + if (mListener) { + (*mListener)(entry->key, entry->value); + } } - } else { - mCache.clear(); } + mCache.clear(); mYoungest.clear(); mOldest.clear(); } diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 59fa0a7..58920bd 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -22,6 +22,7 @@ #include <SkGradientShader.h> #include "GradientCache.h" +#include "Properties.h" namespace android { namespace uirenderer { @@ -30,6 +31,20 @@ namespace uirenderer { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// +GradientCache::GradientCache(): + mCache(GenerationCache<SkShader*, Texture*>::kUnlimitedCapacity), + mSize(0), mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) { + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) { + LOGD(" Setting gradient cache size to %sMB", property); + setMaxSize(MB(atof(property))); + } else { + LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE); + } + + mCache.setOnEntryRemovedListener(this); +} + GradientCache::GradientCache(uint32_t maxByteSize): mCache(GenerationCache<SkShader*, Texture*>::kUnlimitedCapacity), mSize(0), mMaxSize(maxByteSize) { diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h index 12c8a23..8795920 100644 --- a/libs/hwui/GradientCache.h +++ b/libs/hwui/GradientCache.h @@ -32,6 +32,7 @@ namespace uirenderer { */ class GradientCache: public OnEntryRemoved<SkShader*, Texture*> { public: + GradientCache(); GradientCache(uint32_t maxByteSize); ~GradientCache(); diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp index 3d263a3..a204778 100644 --- a/libs/hwui/LayerCache.cpp +++ b/libs/hwui/LayerCache.cpp @@ -21,6 +21,7 @@ #include <utils/Log.h> #include "LayerCache.h" +#include "Properties.h" namespace android { namespace uirenderer { @@ -29,6 +30,18 @@ namespace uirenderer { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// +LayerCache::LayerCache(): + mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity), + mIdGenerator(1), mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) { + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) { + LOGD(" Setting layer cache size to %sMB", property); + setMaxSize(MB(atof(property))); + } else { + LOGD(" Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE); + } +} + LayerCache::LayerCache(uint32_t maxByteSize): mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity), mIdGenerator(1), mSize(0), mMaxSize(maxByteSize) { diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h index 2580551..9860994 100644 --- a/libs/hwui/LayerCache.h +++ b/libs/hwui/LayerCache.h @@ -43,6 +43,7 @@ namespace uirenderer { class LayerCache: public OnEntryRemoved<LayerSize, Layer*> { public: + LayerCache(); LayerCache(uint32_t maxByteSize); ~LayerCache(); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 49d49da..033d8e2 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -23,11 +23,9 @@ #include <SkCanvas.h> #include <SkTypeface.h> -#include <cutils/properties.h> #include <utils/Log.h> #include "OpenGLRenderer.h" -#include "Properties.h" namespace android { namespace uirenderer { @@ -36,18 +34,8 @@ namespace uirenderer { // Defines /////////////////////////////////////////////////////////////////////////////// -#define DEFAULT_TEXTURE_CACHE_SIZE 20.0f -#define DEFAULT_LAYER_CACHE_SIZE 6.0f -#define DEFAULT_PATH_CACHE_SIZE 6.0f -#define DEFAULT_PATCH_CACHE_SIZE 100 -#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f -#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f - #define REQUIRED_TEXTURE_UNITS_COUNT 3 -// Converts a number of mega-bytes into bytes -#define MB(s) s * 1024 * 1024 - // Generates simple and textured vertices #define FV(x, y, u, v) { { x, y }, { u, v } } @@ -102,54 +90,9 @@ static const GLenum gTextureUnits[] = { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// -OpenGLRenderer::OpenGLRenderer(): - mBlend(false), mLastSrcMode(GL_ZERO), mLastDstMode(GL_ZERO), - mTextureCache(MB(DEFAULT_TEXTURE_CACHE_SIZE)), - mLayerCache(MB(DEFAULT_LAYER_CACHE_SIZE)), - mGradientCache(MB(DEFAULT_GRADIENT_CACHE_SIZE)), - mPathCache(MB(DEFAULT_PATH_CACHE_SIZE)), - mPatchCache(DEFAULT_PATCH_CACHE_SIZE), - mDropShadowCache(MB(DEFAULT_DROP_SHADOW_CACHE_SIZE)) { +OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) { LOGD("Create OpenGLRenderer"); - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) { - LOGD(" Setting texture cache size to %sMB", property); - mTextureCache.setMaxSize(MB(atof(property))); - } else { - LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE); - } - - if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) { - LOGD(" Setting layer cache size to %sMB", property); - mLayerCache.setMaxSize(MB(atof(property))); - } else { - LOGD(" Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE); - } - - if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) { - LOGD(" Setting gradient cache size to %sMB", property); - mGradientCache.setMaxSize(MB(atof(property))); - } else { - LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE); - } - - if (property_get(PROPERTY_PATH_CACHE_SIZE, property, NULL) > 0) { - LOGD(" Setting path cache size to %sMB", property); - mPathCache.setMaxSize(MB(atof(property))); - } else { - LOGD(" Using default path cache size of %.2fMB", DEFAULT_PATH_CACHE_SIZE); - } - - if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, NULL) > 0) { - LOGD(" Setting drop shadow cache size to %sMB", property); - mDropShadowCache.setMaxSize(MB(atof(property))); - } else { - LOGD(" Using default drop shadow cache size of %.2fMB", DEFAULT_DROP_SHADOW_CACHE_SIZE); - } - mDropShadowCache.setFontRenderer(mFontRenderer); - - mCurrentProgram = NULL; mShader = NULL; mColorFilter = NULL; mHasShadow = false; @@ -167,14 +110,6 @@ OpenGLRenderer::OpenGLRenderer(): OpenGLRenderer::~OpenGLRenderer() { LOGD("Destroy OpenGLRenderer"); - - mTextureCache.clear(); - mLayerCache.clear(); - mGradientCache.clear(); - mPathCache.clear(); - mPatchCache.clear(); - mProgramCache.clear(); - mDropShadowCache.clear(); } /////////////////////////////////////////////////////////////////////////////// @@ -195,6 +130,8 @@ void OpenGLRenderer::prepare() { mSnapshot = new Snapshot(mFirstSnapshot); mSaveCount = 1; + glViewport(0, 0, mWidth, mHeight); + glDisable(GL_SCISSOR_TEST); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); @@ -310,12 +247,12 @@ int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bot bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) { LAYER_LOGD("Requesting layer %fx%f", right - left, bottom - top); - LAYER_LOGD("Layer cache size = %d", mLayerCache.getSize()); + LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize()); GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0; LayerSize size(right - left, bottom - top); - Layer* layer = mLayerCache.get(size, previousFbo); + Layer* layer = mCaches.layerCache.get(size, previousFbo); if (!layer) { return false; } @@ -380,7 +317,7 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { LayerSize size(rect.getWidth(), rect.getHeight()); // Failing to add the layer to the cache should happen only if the // layer is too large - if (!mLayerCache.put(size, layer)) { + if (!mCaches.layerCache.put(size, layer)) { LAYER_LOGD("Deleting layer"); glDeleteFramebuffers(1, &layer->fbo); @@ -461,7 +398,7 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const S } glActiveTexture(GL_TEXTURE0); - const Texture* texture = mTextureCache.get(bitmap); + const Texture* texture = mCaches.textureCache.get(bitmap); if (!texture) return; const AutoTexture autoCleanup(texture); @@ -478,7 +415,7 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const } glActiveTexture(GL_TEXTURE0); - const Texture* texture = mTextureCache.get(bitmap); + const Texture* texture = mCaches.textureCache.get(bitmap); if (!texture) return; const AutoTexture autoCleanup(texture); @@ -494,7 +431,7 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, } glActiveTexture(GL_TEXTURE0); - const Texture* texture = mTextureCache.get(bitmap); + const Texture* texture = mCaches.textureCache.get(bitmap); if (!texture) return; const AutoTexture autoCleanup(texture); @@ -520,7 +457,7 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, } glActiveTexture(GL_TEXTURE0); - const Texture* texture = mTextureCache.get(bitmap); + const Texture* texture = mCaches.textureCache.get(bitmap); if (!texture) return; const AutoTexture autoCleanup(texture); @@ -528,7 +465,7 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); - Patch* mesh = mPatchCache.get(patch); + Patch* mesh = mCaches.patchCache.get(patch); mesh->updateVertices(bitmap, left, top, right, bottom, &patch->xDivs[0], &patch->yDivs[0], patch->numXDivs, patch->numYDivs); @@ -607,10 +544,11 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; const GLfloat b = a * ((color ) & 0xFF) / 255.0f; - mFontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), paint->getTextSize()); + mCaches.fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), + paint->getTextSize()); if (mHasShadow) { glActiveTexture(gTextureUnits[0]); - const ShadowTexture* shadow = mDropShadowCache.get(paint, text, bytesCount, + const ShadowTexture* shadow = mCaches.dropShadowCache.get(paint, text, bytesCount, count, mShadowRadius); const AutoTexture autoCleanup(shadow); @@ -618,20 +556,20 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, // Draw the mesh glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); - glDisableVertexAttribArray(mCurrentProgram->getAttrib("texCoords")); + glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); } GLuint textureUnit = 0; glActiveTexture(gTextureUnits[textureUnit]); - setupTextureAlpha8(mFontRenderer.getTexture(), 0, 0, textureUnit, x, y, r, g, b, a, + setupTextureAlpha8(mCaches.fontRenderer.getTexture(), 0, 0, textureUnit, x, y, r, g, b, a, mode, false, true); const Rect& clip = mSnapshot->getLocalClip(); - mFontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y); + mCaches.fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glDisableVertexAttribArray(mCurrentProgram->getAttrib("texCoords")); + glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); drawTextDecorations(text, bytesCount, length, x, y, paint); @@ -646,7 +584,7 @@ void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) { GLuint textureUnit = 0; glActiveTexture(gTextureUnits[textureUnit]); - const PathTexture* texture = mPathCache.get(path, paint); + const PathTexture* texture = mCaches.pathCache.get(path, paint); if (!texture) return; const AutoTexture autoCleanup(texture); @@ -671,7 +609,7 @@ void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) { // Draw the mesh glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); - glDisableVertexAttribArray(mCurrentProgram->getAttrib("texCoords")); + glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); } /////////////////////////////////////////////////////////////////////////////// @@ -685,7 +623,7 @@ void OpenGLRenderer::resetShader() { void OpenGLRenderer::setupShader(SkiaShader* shader) { mShader = shader; if (mShader) { - mShader->set(&mTextureCache, &mGradientCache); + mShader->set(&mCaches.textureCache, &mCaches.gradientCache); } } @@ -761,18 +699,18 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t } // Build and use the appropriate shader - useProgram(mProgramCache.get(description)); + useProgram(mCaches.programCache.get(description)); // Setup the blending mode chooseBlending(true, mode); bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, textureUnit); - glUniform1i(mCurrentProgram->getUniform("sampler"), textureUnit); + glUniform1i(mCaches.currentProgram->getUniform("sampler"), textureUnit); - int texCoordsSlot = mCurrentProgram->getAttrib("texCoords"); + int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); glEnableVertexAttribArray(texCoordsSlot); // Setup attributes - glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE, + glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, gMeshStride, &mMeshVertices[0].position[0]); glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, &mMeshVertices[0].texture[0]); @@ -784,17 +722,17 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t } else { mModelView.loadIdentity(); } - mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); - glUniform4f(mCurrentProgram->color, r, g, b, a); + mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); + glUniform4f(mCaches.currentProgram->color, r, g, b, a); textureUnit++; if (applyFilters) { // Setup attributes and uniforms required by the shaders if (mShader) { - mShader->setupProgram(mCurrentProgram, mModelView, *mSnapshot, &textureUnit); + mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); } if (mColorFilter) { - mColorFilter->setupProgram(mCurrentProgram); + mColorFilter->setupProgram(mCaches.currentProgram); } } } @@ -879,29 +817,29 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot } // Build and use the appropriate shader - useProgram(mProgramCache.get(description)); + useProgram(mCaches.programCache.get(description)); // Setup attributes - glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE, + glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, gMeshStride, &mMeshVertices[0].position[0]); // Setup uniforms mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); if (!ignoreTransform) { - mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); + mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); } else { mat4 identity; - mCurrentProgram->set(mOrthoMatrix, mModelView, identity); + mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity); } - glUniform4f(mCurrentProgram->color, r, g, b, a); + glUniform4f(mCaches.currentProgram->color, r, g, b, a); // Setup attributes and uniforms required by the shaders if (mShader) { - mShader->setupProgram(mCurrentProgram, mModelView, *mSnapshot, &textureUnit); + mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); } if (mColorFilter) { - mColorFilter->setupProgram(mCurrentProgram); + mColorFilter->setupProgram(mCaches.currentProgram); } // Draw the mesh @@ -936,28 +874,28 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); - useProgram(mProgramCache.get(description)); - mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); + useProgram(mCaches.programCache.get(description)); + mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); chooseBlending(blend || alpha < 1.0f, mode); // Texture bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0); - glUniform1i(mCurrentProgram->getUniform("sampler"), 0); + glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0); // Always premultiplied - glUniform4f(mCurrentProgram->color, alpha, alpha, alpha, alpha); + glUniform4f(mCaches.currentProgram->color, alpha, alpha, alpha, alpha); // Mesh - int texCoordsSlot = mCurrentProgram->getAttrib("texCoords"); + int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); glEnableVertexAttribArray(texCoordsSlot); - glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE, + glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, gMeshStride, vertices); glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); // Color filter if (mColorFilter) { - mColorFilter->setupProgram(mCurrentProgram); + mColorFilter->setupProgram(mCaches.currentProgram); } if (!indices) { @@ -971,7 +909,7 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied) { blend = blend || mode != SkXfermode::kSrcOver_Mode; if (blend) { - if (!mBlend) { + if (!mCaches.blend) { glEnable(GL_BLEND); } @@ -981,22 +919,22 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPr sourceMode = GL_SRC_ALPHA; } - if (sourceMode != mLastSrcMode || destMode != mLastDstMode) { + if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) { glBlendFunc(sourceMode, destMode); - mLastSrcMode = sourceMode; - mLastDstMode = destMode; + mCaches.lastSrcMode = sourceMode; + mCaches.lastDstMode = destMode; } - } else if (mBlend) { + } else if (mCaches.blend) { glDisable(GL_BLEND); } - mBlend = blend; + mCaches.blend = blend; } bool OpenGLRenderer::useProgram(Program* program) { if (!program->isInUse()) { - if (mCurrentProgram != NULL) mCurrentProgram->remove(); + if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove(); program->use(); - mCurrentProgram = program; + mCaches.currentProgram = program; return false; } return true; diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 5c0089f..5748d57 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -35,17 +35,10 @@ #include "Program.h" #include "Rect.h" #include "Snapshot.h" -#include "TextureCache.h" -#include "LayerCache.h" -#include "GradientCache.h" -#include "PatchCache.h" #include "Vertex.h" -#include "FontRenderer.h" -#include "ProgramCache.h" #include "SkiaShader.h" #include "SkiaColorFilter.h" -#include "PathCache.h" -#include "TextDropShadowCache.h" +#include "Caches.h" namespace android { namespace uirenderer { @@ -356,7 +349,6 @@ private: sp<Snapshot> mSnapshot; // Shaders - Program* mCurrentProgram; SkiaShader* mShader; // Color filters @@ -365,17 +357,9 @@ private: // Used to draw textured quads TextureVertex mMeshVertices[4]; - // Last known blend state - bool mBlend; - GLenum mLastSrcMode; - GLenum mLastDstMode; - // GL extensions Extensions mExtensions; - // Font renderer - FontRenderer mFontRenderer; - // Drop shadow bool mHasShadow; float mShadowRadius; @@ -384,13 +368,7 @@ private: int mShadowColor; // Various caches - TextureCache mTextureCache; - LayerCache mLayerCache; - GradientCache mGradientCache; - ProgramCache mProgramCache; - PathCache mPathCache; - PatchCache mPatchCache; - TextDropShadowCache mDropShadowCache; + Caches& mCaches; }; // class OpenGLRenderer }; // namespace uirenderer diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp index 694e3fd..a7c0cce 100644 --- a/libs/hwui/PatchCache.cpp +++ b/libs/hwui/PatchCache.cpp @@ -20,6 +20,7 @@ #include <utils/ResourceTypes.h> #include "PatchCache.h" +#include "Properties.h" namespace android { namespace uirenderer { @@ -28,6 +29,9 @@ namespace uirenderer { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// +PatchCache::PatchCache(): mCache(DEFAULT_PATCH_CACHE_SIZE) { +} + PatchCache::PatchCache(uint32_t maxEntries): mCache(maxEntries) { } diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h index de95087..e874a16 100644 --- a/libs/hwui/PatchCache.h +++ b/libs/hwui/PatchCache.h @@ -43,6 +43,7 @@ namespace uirenderer { class PatchCache: public OnEntryRemoved<PatchDescription, Patch*> { public: + PatchCache(); PatchCache(uint32_t maxCapacity); ~PatchCache(); diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index 10440ea..158c0cc 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -22,6 +22,7 @@ #include <SkRect.h> #include "PathCache.h" +#include "Properties.h" namespace android { namespace uirenderer { @@ -30,9 +31,30 @@ namespace uirenderer { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// +PathCache::PathCache(): + mCache(GenerationCache<PathCacheEntry, PathTexture*>::kUnlimitedCapacity), + mSize(0), mMaxSize(MB(DEFAULT_PATH_CACHE_SIZE)) { + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_PATH_CACHE_SIZE, property, NULL) > 0) { + LOGD(" Setting path cache size to %sMB", property); + setMaxSize(MB(atof(property))); + } else { + LOGD(" Using default path cache size of %.2fMB", DEFAULT_PATH_CACHE_SIZE); + } + init(); +} + PathCache::PathCache(uint32_t maxByteSize): mCache(GenerationCache<PathCacheEntry, PathTexture*>::kUnlimitedCapacity), mSize(0), mMaxSize(maxByteSize) { + init(); +} + +PathCache::~PathCache() { + mCache.clear(); +} + +void PathCache::init() { mCache.setOnEntryRemovedListener(this); GLint maxTextureSize; @@ -40,10 +62,6 @@ PathCache::PathCache(uint32_t maxByteSize): mMaxTextureSize = maxTextureSize; } -PathCache::~PathCache() { - mCache.clear(); -} - /////////////////////////////////////////////////////////////////////////////// // Size management /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index d09789f..522e5e0 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -95,6 +95,7 @@ struct PathTexture: public Texture { */ class PathCache: public OnEntryRemoved<PathCacheEntry, PathTexture*> { public: + PathCache(); PathCache(uint32_t maxByteSize); ~PathCache(); @@ -135,6 +136,8 @@ private: PathTexture* addTexture(const PathCacheEntry& entry, const SkPath *path, const SkPaint* paint); + void init(); + GenerationCache<PathCacheEntry, PathTexture*> mCache; uint32_t mSize; diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h index fa4b8c4..f211ab6 100644 --- a/libs/hwui/ProgramCache.h +++ b/libs/hwui/ProgramCache.h @@ -183,7 +183,6 @@ private: void printLongString(const String8& shader) const; KeyedVector<programid, Program*> mCache; - }; // class ProgramCache }; // namespace uirenderer diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 7514b6f..dfe022a 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -17,6 +17,8 @@ #ifndef ANDROID_UI_PROPERTIES_H #define ANDROID_UI_PROPERTIES_H +#include <cutils/properties.h> + /** * This file contains the list of system properties used to configure * the OpenGLRenderer. @@ -33,4 +35,14 @@ #define PROPERTY_TEXT_CACHE_WIDTH "ro.hwui.text_cache_width" #define PROPERTY_TEXT_CACHE_HEIGHT "ro.hwui.text_cache_height" +// Converts a number of mega-bytes into bytes +#define MB(s) s * 1024 * 1024 + +#define DEFAULT_TEXTURE_CACHE_SIZE 20.0f +#define DEFAULT_LAYER_CACHE_SIZE 6.0f +#define DEFAULT_PATH_CACHE_SIZE 6.0f +#define DEFAULT_PATCH_CACHE_SIZE 100 +#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f +#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f + #endif // ANDROID_UI_PROPERTIES_H diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp index aab5bd4..f95d2be 100644 --- a/libs/hwui/TextDropShadowCache.cpp +++ b/libs/hwui/TextDropShadowCache.cpp @@ -25,6 +25,20 @@ namespace uirenderer { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// +TextDropShadowCache::TextDropShadowCache(): + mCache(GenerationCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity), + mSize(0), mMaxSize(MB(DEFAULT_DROP_SHADOW_CACHE_SIZE)) { + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, NULL) > 0) { + LOGD(" Setting drop shadow cache size to %sMB", property); + setMaxSize(MB(atof(property))); + } else { + LOGD(" Using default drop shadow cache size of %.2fMB", DEFAULT_DROP_SHADOW_CACHE_SIZE); + } + + mCache.setOnEntryRemovedListener(this); +} + TextDropShadowCache::TextDropShadowCache(uint32_t maxByteSize): mCache(GenerationCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity), mSize(0), mMaxSize(maxByteSize) { diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h index c3be483..b65d62a 100644 --- a/libs/hwui/TextDropShadowCache.h +++ b/libs/hwui/TextDropShadowCache.h @@ -69,16 +69,16 @@ struct ShadowText { char *text; bool operator<(const ShadowText& rhs) const { - if (len < rhs.len) return true; - else if (len == rhs.len) { - if (radius < rhs.radius) return true; - else if (radius == rhs.radius) { - if (textSize < rhs.textSize) return true; - else if (textSize == rhs.textSize) { - if (typeface < rhs.typeface) return true; - else if (typeface == rhs.typeface) { - if (hash < rhs.hash) return true; - if (hash == rhs.hash) { + if (hash < rhs.hash) return true; + else if (hash == rhs.hash) { + if (len < rhs.len) return true; + else if (len == rhs.len) { + if (radius < rhs.radius) return true; + else if (radius == rhs.radius) { + if (textSize < rhs.textSize) return true; + else if (textSize == rhs.textSize) { + if (typeface < rhs.typeface) return true; + else if (typeface == rhs.typeface) { return strncmp(text, rhs.text, len) < 0; } } @@ -102,6 +102,7 @@ struct ShadowTexture: public Texture { class TextDropShadowCache: public OnEntryRemoved<ShadowText, ShadowTexture*> { public: + TextDropShadowCache(); TextDropShadowCache(uint32_t maxByteSize); ~TextDropShadowCache(); diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 2e8a8be..753c544 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -19,6 +19,7 @@ #include <GLES2/gl2.h> #include "TextureCache.h" +#include "Properties.h" namespace android { namespace uirenderer { @@ -27,19 +28,37 @@ namespace uirenderer { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// +TextureCache::TextureCache(): + mCache(GenerationCache<SkBitmap*, Texture*>::kUnlimitedCapacity), + mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)) { + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) { + LOGD(" Setting texture cache size to %sMB", property); + setMaxSize(MB(atof(property))); + } else { + LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE); + } + + init(); +} + TextureCache::TextureCache(uint32_t maxByteSize): mCache(GenerationCache<SkBitmap*, Texture*>::kUnlimitedCapacity), mSize(0), mMaxSize(maxByteSize) { - mCache.setOnEntryRemovedListener(this); - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); - LOGD("Maximum texture dimension is %d pixels", mMaxTextureSize); + init(); } TextureCache::~TextureCache() { mCache.clear(); } +void TextureCache::init() { + mCache.setOnEntryRemovedListener(this); + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); + LOGD(" Maximum texture dimension is %d pixels", mMaxTextureSize); +} + /////////////////////////////////////////////////////////////////////////////// // Size management /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h index 452716c..b5e4c7c 100644 --- a/libs/hwui/TextureCache.h +++ b/libs/hwui/TextureCache.h @@ -32,6 +32,7 @@ namespace uirenderer { */ class TextureCache: public OnEntryRemoved<SkBitmap*, Texture*> { public: + TextureCache(); TextureCache(uint32_t maxByteSize); ~TextureCache(); @@ -78,6 +79,8 @@ private: */ void generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate = false); + void init(); + GenerationCache<SkBitmap*, Texture*> mCache; uint32_t mSize; diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/ListActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ListActivity.java index c638958..94b936b 100644 --- a/tests/HwAccelerationTest/src/com/google/android/test/hwui/ListActivity.java +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ListActivity.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.res.Resources; import android.os.Bundle; import android.util.DisplayMetrics; +import android.view.ContextMenu; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; @@ -83,6 +84,17 @@ public class ListActivity extends Activity { ListView list = (ListView) findViewById(R.id.list); list.setAdapter(adapter); + + registerForContextMenu(list); + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + menu.setHeaderTitle("Context menu"); + menu.add("List item 1"); + menu.add("List item 2"); + menu.add("List item 3"); } private static class SimpleListAdapter extends ArrayAdapter<String> { |