diff options
| -rw-r--r-- | core/java/android/view/GLES20Canvas.java | 12 | ||||
| -rw-r--r-- | core/java/android/view/GLES20RenderLayer.java | 7 | ||||
| -rw-r--r-- | core/java/android/view/GLES20TextureLayer.java | 5 | ||||
| -rw-r--r-- | core/java/android/view/HardwareLayer.java | 12 | ||||
| -rw-r--r-- | core/java/android/view/HardwareRenderer.java | 137 | ||||
| -rw-r--r-- | core/jni/android_view_GLES20Canvas.cpp | 13 | ||||
| -rw-r--r-- | libs/hwui/Caches.cpp | 2 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 39 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.h | 15 | ||||
| -rw-r--r-- | libs/hwui/Program.h | 3 | ||||
| -rw-r--r-- | libs/hwui/ProgramCache.cpp | 15 | ||||
| -rw-r--r-- | libs/hwui/Properties.h | 4 | ||||
| -rw-r--r-- | libs/hwui/thread/TaskManager.h | 2 |
13 files changed, 241 insertions, 25 deletions
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 21a03d8..cc7d948 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -274,6 +274,18 @@ class GLES20Canvas extends HardwareCanvas { private static native int nGetStencilSize(); + void setCountOverdrawEnabled(boolean enabled) { + nSetCountOverdrawEnabled(mRenderer, enabled); + } + + static native void nSetCountOverdrawEnabled(int renderer, boolean enabled); + + float getOverdraw() { + return nGetOverdraw(mRenderer); + } + + static native float nGetOverdraw(int renderer); + /////////////////////////////////////////////////////////////////////////// // Functor /////////////////////////////////////////////////////////////////////////// diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java index 685dc70..68ba77c 100644 --- a/core/java/android/view/GLES20RenderLayer.java +++ b/core/java/android/view/GLES20RenderLayer.java @@ -100,12 +100,17 @@ class GLES20RenderLayer extends GLES20Layer { @Override HardwareCanvas start(Canvas currentCanvas) { + return start(currentCanvas, null); + } + + @Override + HardwareCanvas start(Canvas currentCanvas, Rect dirty) { if (currentCanvas instanceof GLES20Canvas) { ((GLES20Canvas) currentCanvas).interrupt(); } HardwareCanvas canvas = getCanvas(); canvas.setViewport(mWidth, mHeight); - canvas.onPreDraw(null); + canvas.onPreDraw(dirty); return canvas; } diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java index e863e49..a4cc630 100644 --- a/core/java/android/view/GLES20TextureLayer.java +++ b/core/java/android/view/GLES20TextureLayer.java @@ -63,6 +63,11 @@ class GLES20TextureLayer extends GLES20Layer { } @Override + HardwareCanvas start(Canvas currentCanvas, Rect dirty) { + return null; + } + + @Override void end(Canvas currentCanvas) { } diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java index 18b838b..23383d9 100644 --- a/core/java/android/view/HardwareLayer.java +++ b/core/java/android/view/HardwareLayer.java @@ -158,14 +158,22 @@ abstract class HardwareLayer { /** * This must be invoked before drawing onto this layer. * - * @param currentCanvas + * @param currentCanvas The canvas whose rendering needs to be interrupted */ abstract HardwareCanvas start(Canvas currentCanvas); /** + * This must be invoked before drawing onto this layer. + * + * @param dirty The dirty area to repaint + * @param currentCanvas The canvas whose rendering needs to be interrupted + */ + abstract HardwareCanvas start(Canvas currentCanvas, Rect dirty); + + /** * This must be invoked after drawing onto this layer. * - * @param currentCanvas + * @param currentCanvas The canvas whose rendering needs to be resumed */ abstract void end(Canvas currentCanvas); diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index c7b1253..e8c1653 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -17,6 +17,7 @@ package android.view; import android.content.ComponentCallbacks2; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.SurfaceTexture; @@ -45,7 +46,6 @@ import javax.microedition.khronos.opengles.GL; import java.io.File; import java.io.PrintWriter; -import java.util.Arrays; import java.util.concurrent.locks.ReentrantLock; import static javax.microedition.khronos.egl.EGL10.*; @@ -165,15 +165,32 @@ public abstract class HardwareRenderer { "debug.hwui.show_layers_updates"; /** - * Turn on to show overdraw level. + * Controls overdraw debugging. * * Possible values: - * "true", to enable overdraw debugging * "false", to disable overdraw debugging + * "show", to show overdraw areas on screen + * "count", to display an overdraw counter * * @hide */ - public static final String DEBUG_SHOW_OVERDRAW_PROPERTY = "debug.hwui.show_overdraw"; + public static final String DEBUG_OVERDRAW_PROPERTY = "debug.hwui.overdraw"; + + /** + * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this + * value, overdraw will be shown on screen by coloring pixels. + * + * @hide + */ + public static final String OVERDRAW_PROPERTY_SHOW = "show"; + + /** + * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this + * value, an overdraw counter will be shown on screen. + * + * @hide + */ + public static final String OVERDRAW_PROPERTY_COUNT = "count"; /** * Turn on to debug non-rectangular clip operations. @@ -765,6 +782,17 @@ public abstract class HardwareRenderer { private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2; private static final int PROFILE_DRAW_DP_PER_MS = 7; + private static final String[] VISUALIZERS = { + PROFILE_PROPERTY_VISUALIZE_BARS, + PROFILE_PROPERTY_VISUALIZE_LINES + }; + + private static final String[] OVERDRAW = { + OVERDRAW_PROPERTY_SHOW, + OVERDRAW_PROPERTY_COUNT + }; + private static final int OVERDRAW_TYPE_COUNT = 1; + static EGL10 sEgl; static EGLDisplay sEglDisplay; static EGLConfig sEglConfig; @@ -810,7 +838,9 @@ public abstract class HardwareRenderer { Paint mProfilePaint; boolean mDebugDirtyRegions; - boolean mShowOverdraw; + int mDebugOverdraw = -1; + HardwareLayer mDebugOverdrawLayer; + Paint mDebugOverdrawPaint; final int mGlVersion; final boolean mTranslucent; @@ -829,18 +859,13 @@ public abstract class HardwareRenderer { loadSystemProperties(null); } - private static final String[] VISUALIZERS = { - PROFILE_PROPERTY_VISUALIZE_BARS, - PROFILE_PROPERTY_VISUALIZE_LINES - }; - @Override boolean loadSystemProperties(Surface surface) { boolean value; boolean changed = false; String profiling = SystemProperties.get(PROFILE_PROPERTY); - int graphType = Arrays.binarySearch(VISUALIZERS, profiling); + int graphType = search(VISUALIZERS, profiling); value = graphType >= 0; if (graphType != mProfileVisualizerType) { @@ -897,11 +922,19 @@ public abstract class HardwareRenderer { } } - value = SystemProperties.getBoolean( - HardwareRenderer.DEBUG_SHOW_OVERDRAW_PROPERTY, false); - if (value != mShowOverdraw) { + String overdraw = SystemProperties.get(HardwareRenderer.DEBUG_OVERDRAW_PROPERTY); + int debugOverdraw = search(OVERDRAW, overdraw); + if (debugOverdraw != mDebugOverdraw) { changed = true; - mShowOverdraw = value; + mDebugOverdraw = debugOverdraw; + + if (mDebugOverdraw != OVERDRAW_TYPE_COUNT) { + if (mDebugOverdrawLayer != null) { + mDebugOverdrawLayer.destroy(); + mDebugOverdrawLayer = null; + mDebugOverdrawPaint = null; + } + } } if (nLoadProperties()) { @@ -911,6 +944,13 @@ public abstract class HardwareRenderer { return changed; } + private static int search(String[] values, String value) { + for (int i = 0; i < values.length; i++) { + if (values[i].equals(value)) return i; + } + return -1; + } + @Override void dumpGfxInfo(PrintWriter pw) { if (mProfileEnabled) { @@ -1392,6 +1432,8 @@ public abstract class HardwareRenderer { canvas.restoreToCount(saveCount); view.mRecreateDisplayList = false; + debugOverdraw(attachInfo, dirty, canvas, displayList); + mFrameCount++; debugDirtyRegions(dirty, canvas); @@ -1411,6 +1453,61 @@ public abstract class HardwareRenderer { } } + abstract void countOverdraw(HardwareCanvas canvas); + abstract float getOverdraw(HardwareCanvas canvas); + + private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty, + HardwareCanvas canvas, DisplayList displayList) { + + if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) { + // TODO: Use an alpha layer allocated from a GraphicBuffer + // The alpha format will help with rendering performance and + // the GraphicBuffer will let us skip the read pixels step + if (mDebugOverdrawLayer == null) { + mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true); + } else if (mDebugOverdrawLayer.getWidth() != mWidth || + mDebugOverdrawLayer.getHeight() != mHeight) { + mDebugOverdrawLayer.resize(mWidth, mHeight); + } + + if (!mDebugOverdrawLayer.isValid()) { + mDebugOverdraw = -1; + return; + } + + HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty); + countOverdraw(layerCanvas); + final int restoreCount = layerCanvas.save(); + layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN); + layerCanvas.restoreToCount(restoreCount); + mDebugOverdrawLayer.end(canvas); + + float overdraw = getOverdraw(layerCanvas); + DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics(); + + drawOverdrawCounter(canvas, overdraw, metrics.density); + } + } + + private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) { + final String text = String.format("%.2fx", overdraw); + final Paint paint = setupPaint(density); + // HSBtoColor will clamp the values in the 0..1 range + paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f)); + + canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint); + } + + private Paint setupPaint(float density) { + if (mDebugOverdrawPaint == null) { + mDebugOverdrawPaint = new Paint(); + mDebugOverdrawPaint.setAntiAlias(true); + mDebugOverdrawPaint.setShadowLayer(density * 3.0f, 0.0f, 0.0f, 0xff000000); + mDebugOverdrawPaint.setTextSize(density * 20.0f); + } + return mDebugOverdrawPaint; + } + private DisplayList buildDisplayList(View view, HardwareCanvas canvas) { view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) == View.PFLAG_INVALIDATED; @@ -2019,6 +2116,16 @@ public abstract class HardwareRenderer { } @Override + void countOverdraw(HardwareCanvas canvas) { + ((GLES20Canvas) canvas).setCountOverdrawEnabled(true); + } + + @Override + float getOverdraw(HardwareCanvas canvas) { + return ((GLES20Canvas) canvas).getOverdraw(); + } + + @Override public SurfaceTexture createSurfaceTexture(HardwareLayer layer) { return ((GLES20TextureLayer) layer).getSurfaceTexture(); } diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index c8fa290..cd7a032 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -185,6 +185,16 @@ static void android_view_GLES20Canvas_setName(JNIEnv* env, } } +static void android_view_GLES20Canvas_setCountOverdrawEnabled(JNIEnv* env, jobject clazz, + OpenGLRenderer* renderer, jboolean enabled) { + renderer->setCountOverdrawEnabled(enabled); +} + +static jfloat android_view_GLES20Canvas_getOverdraw(JNIEnv* env, jobject clazz, + OpenGLRenderer* renderer) { + return renderer->getOverdraw(); +} + // ---------------------------------------------------------------------------- // Functor // ---------------------------------------------------------------------------- @@ -944,6 +954,9 @@ static JNINativeMethod gMethods[] = { { "nSetName", "(ILjava/lang/String;)V", (void*) android_view_GLES20Canvas_setName }, + { "nSetCountOverdrawEnabled", "(IZ)V", (void*) android_view_GLES20Canvas_setCountOverdrawEnabled }, + { "nGetOverdraw", "(I)F", (void*) android_view_GLES20Canvas_getOverdraw }, + { "nGetStencilSize", "()I", (void*) android_view_GLES20Canvas_getStencilSize }, { "nCallDrawGLFunction", "(II)I", (void*) android_view_GLES20Canvas_callDrawGLFunction }, diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index c60848c..f08b5ca 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -152,7 +152,7 @@ bool Caches::initProperties() { if (property_get(PROPERTY_DEBUG_OVERDRAW, property, NULL) > 0) { INIT_LOGD(" Overdraw debug enabled: %s", property); - debugOverdraw = !strcmp(property, "true"); + debugOverdraw = !strcmp(property, "show"); } else { debugOverdraw = false; } diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 025e9f8..1447eb7 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -21,7 +21,6 @@ #include <sys/types.h> #include <SkCanvas.h> -#include <SkPathMeasure.h> #include <SkTypeface.h> #include <utils/Log.h> @@ -120,6 +119,7 @@ OpenGLRenderer::OpenGLRenderer(): mFirstSnapshot = new Snapshot; mFrameStarted = false; + mCountOverdraw = false; mScissorOptimizationDisabled = false; } @@ -222,6 +222,7 @@ status_t OpenGLRenderer::prepare(bool opaque) { status_t OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) { + setupFrameState(left, top, right, bottom, opaque); // Layer renderers will start the frame immediately @@ -253,7 +254,7 @@ void OpenGLRenderer::discardFramebuffer(float left, float top, float right, floa } status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) { - if (!opaque) { + if (!opaque || mCountOverdraw) { mCaches.enableScissor(); mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top); glClear(GL_COLOR_BUFFER_BIT); @@ -335,6 +336,10 @@ void OpenGLRenderer::finish() { #endif } + if (mCountOverdraw) { + countOverdraw(); + } + mFrameStarted = false; } @@ -524,6 +529,21 @@ void OpenGLRenderer::renderOverdraw() { } } +void OpenGLRenderer::countOverdraw() { + size_t count = mWidth * mHeight; + uint32_t* buffer = new uint32_t[count]; + glReadPixels(0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]); + + size_t total = 0; + for (size_t i = 0; i < count; i++) { + total += buffer[i] & 0xff; + } + + mOverdraw = total / float(count); + + delete[] buffer; +} + /////////////////////////////////////////////////////////////////////////////// // Layers /////////////////////////////////////////////////////////////////////////////// @@ -1656,6 +1676,8 @@ void OpenGLRenderer::setupDraw(bool clear) { mDescription.hasDebugHighlight = !mCaches.debugOverdraw && mCaches.debugStencilClip == Caches::kStencilShowHighlight && mCaches.stencil.isTestEnabled(); + + mDescription.emulateStencil = mCountOverdraw; } void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) { @@ -3546,6 +3568,19 @@ void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, f void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, ProgramDescription& description, bool swapSrcDst) { + if (mCountOverdraw) { + if (!mCaches.blend) glEnable(GL_BLEND); + if (mCaches.lastSrcMode != GL_ONE || mCaches.lastDstMode != GL_ONE) { + glBlendFunc(GL_ONE, GL_ONE); + } + + mCaches.blend = true; + mCaches.lastSrcMode = GL_ONE; + mCaches.lastDstMode = GL_ONE; + + return; + } + blend = blend || mode != SkXfermode::kSrcOver_Mode; if (blend) { diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 640c7db..df275d7 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -192,6 +192,14 @@ public: */ virtual void resume(); + ANDROID_API void setCountOverdrawEnabled(bool enabled) { + mCountOverdraw = enabled; + } + + ANDROID_API float getOverdraw() { + return mCountOverdraw ? mOverdraw : 0.0f; + } + ANDROID_API status_t invokeFunctors(Rect& dirty); ANDROID_API void detachFunctor(Functor* functor); ANDROID_API void attachFunctor(Functor* functor); @@ -981,6 +989,7 @@ private: void debugOverdraw(bool enable, bool clear); void renderOverdraw(); + void countOverdraw(); /** * Should be invoked every time the glScissor is modified. @@ -1072,6 +1081,12 @@ private: // No-ops start/endTiling when set bool mSuppressTiling; + + // If true, this renderer will setup drawing to emulate + // an increment stencil buffer in the color buffer + bool mCountOverdraw; + float mOverdraw; + // Optional name of the renderer String8 mName; diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index a252209..dd1aaa2 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -85,6 +85,7 @@ namespace uirenderer { #define PROGRAM_HAS_COLORS 42 #define PROGRAM_HAS_DEBUG_HIGHLIGHT 43 +#define PROGRAM_EMULATE_STENCIL 44 /////////////////////////////////////////////////////////////////////////////// // Types @@ -163,6 +164,7 @@ struct ProgramDescription { float gamma; bool hasDebugHighlight; + bool emulateStencil; /** * Resets this description. All fields are reset back to the default @@ -275,6 +277,7 @@ struct ProgramDescription { if (isSimpleGradient) key |= programid(0x1) << PROGRAM_IS_SIMPLE_GRADIENT; if (hasColors) key |= programid(0x1) << PROGRAM_HAS_COLORS; if (hasDebugHighlight) key |= programid(0x1) << PROGRAM_HAS_DEBUG_HIGHLIGHT; + if (emulateStencil) key |= programid(0x1) << PROGRAM_EMULATE_STENCIL; return key; } diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 8eb85e5..367294c 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -342,6 +342,12 @@ const char* gFS_Main_ApplyColorOp[4] = { }; const char* gFS_Main_DebugHighlight = " gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n"; +const char* gFS_Main_EmulateStencil = + " gl_FragColor.rgba = vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 1.0);\n" + " return;\n" + " /*\n"; +const char* gFS_Footer_EmulateStencil = + " */\n"; const char* gFS_Footer = "}\n\n"; @@ -603,7 +609,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti // Optimization for common cases if (!description.isAA && !blendFramebuffer && !description.hasColors && description.colorOp == ProgramDescription::kColorNone && - !description.isPoint && !description.hasDebugHighlight) { + !description.isPoint && !description.hasDebugHighlight && + !description.emulateStencil) { bool fast = false; const bool noShader = !description.hasGradient && !description.hasBitmap; @@ -683,6 +690,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti // Begin the shader shader.append(gFS_Main); { + if (description.emulateStencil) { + shader.append(gFS_Main_EmulateStencil); + } // Stores the result in fragColor directly if (description.hasTexture || description.hasExternalTexture) { if (description.hasAlpha8Texture) { @@ -757,6 +767,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Main_DebugHighlight); } } + if (description.emulateStencil) { + shader.append(gFS_Footer_EmulateStencil); + } // End the shader shader.append(gFS_Footer); diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 87ac845..7c68b5b 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -71,9 +71,9 @@ enum DebugLevel { /** * Used to enable/disable overdraw debugging. The accepted values are - * "true" and "false". The default value is "false". + * "show", "count" and "false". The default value is "false". */ -#define PROPERTY_DEBUG_OVERDRAW "debug.hwui.show_overdraw" +#define PROPERTY_DEBUG_OVERDRAW "debug.hwui.overdraw" /** * Used to enable/disable non-rectangular clipping debugging. diff --git a/libs/hwui/thread/TaskManager.h b/libs/hwui/thread/TaskManager.h index 477314b..f2a216f 100644 --- a/libs/hwui/thread/TaskManager.h +++ b/libs/hwui/thread/TaskManager.h @@ -43,7 +43,7 @@ public: /** * Returns true if this task manager can run tasks, * false otherwise. This method will typically return - * true on a single CPU core device. + * false on a single CPU core device. */ bool canRunTasks() const; |
