diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index d948ec28cbd2e..ac06d2d9501c3 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -154,6 +154,7 @@ class GLES20Canvas extends HardwareCanvas { static native void nSetTextureLayerTransform(int layerId, int matrix); static native void nDestroyLayer(int layerId); static native void nDestroyLayerDeferred(int layerId); + static native void nFlushLayer(int layerId); static native boolean nCopyLayer(int layerId, int bitmap); /////////////////////////////////////////////////////////////////////////// diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java index fd3b9e55b111b..4f25792d6317e 100644 --- a/core/java/android/view/GLES20Layer.java +++ b/core/java/android/view/GLES20Layer.java @@ -60,6 +60,13 @@ abstract class GLES20Layer extends HardwareLayer { } mLayer = 0; } + + @Override + void flush() { + if (mLayer != 0) { + GLES20Canvas.nFlushLayer(mLayer); + } + } static class Finalizer { private int mLayerId; diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java index 28389abc3421e..d5666f37d7ab5 100644 --- a/core/java/android/view/HardwareLayer.java +++ b/core/java/android/view/HardwareLayer.java @@ -115,6 +115,11 @@ abstract class HardwareLayer { */ abstract void destroy(); + /** + * Flush the render queue associated with this layer. + */ + abstract void flush(); + /** * This must be invoked before drawing onto this layer. * @param currentCanvas diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index dc46d424450f6..3bddeef1d4f76 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -10146,6 +10146,12 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal break; } } + + void flushLayer() { + if (mLayerType == LAYER_TYPE_HARDWARE && mHardwareLayer != null) { + mHardwareLayer.flush(); + } + } /** *
Returns a hardware layer that can be used to draw this view again
@@ -10158,6 +10164,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
!mAttachInfo.mHardwareRenderer.isEnabled()) {
return null;
}
+
+ if (!mAttachInfo.mHardwareRenderer.validate()) return null;
+
final int width = mRight - mLeft;
final int height = mBottom - mTop;
@@ -10232,8 +10241,14 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*/
boolean destroyLayer() {
if (mHardwareLayer != null) {
- mHardwareLayer.destroy();
- mHardwareLayer = null;
+ AttachInfo info = mAttachInfo;
+ if (info != null && info.mHardwareRenderer != null &&
+ info.mHardwareRenderer.isEnabled()) {
+ if (!info.mHardwareRenderer.validate()) {
+ mHardwareLayer.destroy();
+ mHardwareLayer = null;
+ }
+ }
return true;
}
return false;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index e366e72976c0b..50b34b016a983 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2957,6 +2957,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (enabled != mDrawLayers) {
mDrawLayers = enabled;
invalidate(true);
+
+ AttachInfo info = mAttachInfo;
+ if (info != null && info.mHardwareRenderer != null &&
+ info.mHardwareRenderer.isEnabled()) {
+ if (!info.mHardwareRenderer.validate()) {
+ enabled = false;
+ }
+ } else {
+ enabled = false;
+ }
// We need to invalidate any child with a layer. For instance,
// if a child is backed by a hardware layer and we disable layers
@@ -2968,6 +2978,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
for (int i = 0; i < mChildrenCount; i++) {
View child = mChildren[i];
if (child.mLayerType != LAYER_TYPE_NONE) {
+ if (!enabled) child.flushLayer();
child.invalidate(true);
}
}
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 4f75fad684f31..78b8e8ede38a1 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -718,6 +718,10 @@ static void android_view_GLES20Canvas_destroyLayerDeferred(JNIEnv* env,
LayerRenderer::destroyLayerDeferred(layer);
}
+static void android_view_GLES20Canvas_flushLayer(JNIEnv* env, jobject clazz, Layer* layer) {
+ LayerRenderer::flushLayer(layer);
+}
+
static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
OpenGLRenderer* renderer, Layer* layer, jfloat x, jfloat y, SkPaint* paint) {
renderer->drawLayer(layer, x, y, paint);
@@ -860,6 +864,7 @@ static JNINativeMethod gMethods[] = {
{ "nSetTextureLayerTransform", "(II)V", (void*) android_view_GLES20Canvas_setTextureLayerTransform },
{ "nDestroyLayer", "(I)V", (void*) android_view_GLES20Canvas_destroyLayer },
{ "nDestroyLayerDeferred", "(I)V", (void*) android_view_GLES20Canvas_destroyLayerDeferred },
+ { "nFlushLayer", "(I)V", (void*) android_view_GLES20Canvas_flushLayer },
{ "nDrawLayer", "(IIFFI)V", (void*) android_view_GLES20Canvas_drawLayer },
{ "nCopyLayer", "(II)Z", (void*) android_view_GLES20Canvas_copyLayer },
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 9bfc94cb11fda..95e0a181333eb 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -38,7 +38,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
external/skia/src/ports \
external/skia/include/utils
- LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER
+ LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DGL_GLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 38d1130004801..48e42471aa65b 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -66,6 +66,7 @@ public:
mHasNPot = hasExtension("GL_OES_texture_npot");
mHasFramebufferFetch = hasExtension("GL_NV_shader_framebuffer_fetch");
+ mHasDiscardFramebuffer = hasExtension("GL_EXT_discard_framebuffer");
const char* vendor = (const char*) glGetString(GL_VENDOR);
EXT_LOGD("Vendor: %s", vendor);
@@ -80,6 +81,7 @@ public:
inline bool hasNPot() const { return mHasNPot; }
inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
inline bool needsHighpTexCoords() const { return mNeedsHighpTexCoords; }
+ inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
bool hasExtension(const char* extension) const {
const String8 s(extension);
@@ -98,6 +100,7 @@ private:
bool mHasNPot;
bool mNeedsHighpTexCoords;
bool mHasFramebufferFetch;
+ bool mHasDiscardFramebuffer;
}; // class Extensions
}; // namespace uirenderer
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e38b4794bcae2..b7c079b585a34 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -305,8 +305,10 @@ void LayerRenderer::destroyLayer(Layer* layer) {
LAYER_RENDERER_LOGD("Recycling layer, %dx%d fbo = %d",
layer->getWidth(), layer->getHeight(), layer->getFbo());
- if (layer->getFbo()) {
- Caches::getInstance().fboCache.put(layer->getFbo());
+ GLuint fbo = layer->getFbo();
+ if (fbo) {
+ flushLayer(layer);
+ Caches::getInstance().fboCache.put(fbo);
}
if (!Caches::getInstance().layerCache.put(layer)) {
@@ -331,6 +333,26 @@ void LayerRenderer::destroyLayerDeferred(Layer* layer) {
}
}
+void LayerRenderer::flushLayer(Layer* layer) {
+#ifdef GL_EXT_discard_framebuffer
+ GLuint fbo = layer->getFbo();
+ if (layer && fbo) {
+ // If possible, discard any enqued operations on deferred
+ // rendering architectures
+ if (Caches::getInstance().extensions.hasDiscardFramebuffer()) {
+ GLuint previousFbo;
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
+
+ GLenum attachments = GL_COLOR_ATTACHMENT0;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, &attachments);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
+ }
+ }
+#endif
+}
+
bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
Caches& caches = Caches::getInstance();
if (layer && layer->isTextureLayer() && bitmap->width() <= caches.maxTextureSize &&
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 61043015f768b..72d8d81aa130c 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -61,6 +61,7 @@ public:
bool isOpaque, GLenum renderTarget, float* transform);
ANDROID_API static void destroyLayer(Layer* layer);
ANDROID_API static void destroyLayerDeferred(Layer* layer);
+ ANDROID_API static void flushLayer(Layer* layer);
ANDROID_API static bool copyLayer(Layer* layer, SkBitmap* bitmap);
private:
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 32595e4a55aeb..1a8c19977ca61 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -611,6 +611,11 @@ void OpenGLRenderer::composeLayer(sp