Merge "Use only one GL context per process, share chaches."
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
|
||||
mDestroyed = true;
|
||||
|
||||
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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
75
libs/hwui/Caches.h
Normal file
75
libs/hwui/Caches.h
Normal file
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace uirenderer {
|
||||
*/
|
||||
class GradientCache: public OnEntryRemoved<SkShader*, Texture*> {
|
||||
public:
|
||||
GradientCache();
|
||||
GradientCache(uint32_t maxByteSize);
|
||||
~GradientCache();
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace uirenderer {
|
||||
|
||||
class LayerCache: public OnEntryRemoved<LayerSize, Layer*> {
|
||||
public:
|
||||
LayerCache();
|
||||
LayerCache(uint32_t maxByteSize);
|
||||
~LayerCache();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace uirenderer {
|
||||
|
||||
class PatchCache: public OnEntryRemoved<PatchDescription, Patch*> {
|
||||
public:
|
||||
PatchCache();
|
||||
PatchCache(uint32_t maxCapacity);
|
||||
~PatchCache();
|
||||
|
||||
|
||||
@@ -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
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -183,7 +183,6 @@ private:
|
||||
void printLongString(const String8& shader) const;
|
||||
|
||||
KeyedVector<programid, Program*> mCache;
|
||||
|
||||
}; // class ProgramCache
|
||||
|
||||
}; // namespace uirenderer
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user