summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2013-01-04 19:05:13 -0800
committerRomain Guy <romainguy@google.com>2013-01-04 19:21:54 -0800
commit672433d90fab7383cd28beac9d4485b566a90940 (patch)
tree8e5088ba91b9a33aeffccd3b2c6f03b0c8e2b144
parent5913148104f0b233d861fab2873befc865bf57c0 (diff)
downloadframeworks_base-672433d90fab7383cd28beac9d4485b566a90940.zip
frameworks_base-672433d90fab7383cd28beac9d4485b566a90940.tar.gz
frameworks_base-672433d90fab7383cd28beac9d4485b566a90940.tar.bz2
Add visual profiling feature
When profiling is enabled with debug.hwui.profile set to true, setting debug.hwui.profile_visualizer to true will display the profiling data directly on screen. Change-Id: I3d5fe3f0347090815087b1cbfce66b8e76d9347b
-rw-r--r--core/java/android/view/GLES20Canvas.java11
-rw-r--r--core/java/android/view/HardwareRenderer.java365
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp39
-rw-r--r--libs/hwui/DisplayListRenderer.cpp25
-rw-r--r--libs/hwui/DisplayListRenderer.h2
-rw-r--r--libs/hwui/OpenGLRenderer.cpp73
-rw-r--r--libs/hwui/OpenGLRenderer.h5
7 files changed, 415 insertions, 105 deletions
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index b64a06e..7739ff7 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -1013,6 +1013,17 @@ class GLES20Canvas extends HardwareCanvas {
private static native void nDrawPath(int renderer, int path, int paint);
private static native void nDrawRects(int renderer, int region, int paint);
+ void drawRects(float[] rects, int count, Paint paint) {
+ int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+ try {
+ nDrawRects(mRenderer, rects, count, paint.mNativePaint);
+ } finally {
+ if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ }
+ }
+
+ private static native void nDrawRects(int renderer, float[] rects, int count, int paint);
+
@Override
public void drawPicture(Picture picture) {
if (picture.createdFromStream) {
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 157c321..e50b36d 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -88,12 +88,27 @@ public abstract class HardwareRenderer {
* Possible values:
* "true", to enable profiling
* "false", to disable profiling
- *
+ *
* @hide
*/
public static final String PROFILE_PROPERTY = "debug.hwui.profile";
/**
+ * System property used to enable or disable hardware rendering profiling
+ * visualization. The default value of this property is assumed to be false.
+ *
+ * This property is only taken into account when {@link #PROFILE_PROPERTY} is
+ * turned on.
+ *
+ * Possible values:
+ * "true", to enable on screen profiling
+ * "false", to disable on screen profiling
+ *
+ * @hide
+ */
+ public static final String PROFILE_VISUALIZER_PROPERTY = "debug.hwui.profile_visualizer";
+
+ /**
* System property used to specify the number of frames to be used
* when doing hardware rendering profiling.
* The default value of this property is #PROFILE_MAX_FRAMES.
@@ -342,7 +357,7 @@ public abstract class HardwareRenderer {
* Notifies EGL that the frame is about to be rendered.
* @param size
*/
- private static void beginFrame(int[] size) {
+ static void beginFrame(int[] size) {
nBeginFrame(size);
}
@@ -648,10 +663,14 @@ public abstract class HardwareRenderer {
boolean mUpdateDirtyRegions;
boolean mProfileEnabled;
+ boolean mProfileVisualizerEnabled;
float[] mProfileData;
ReentrantLock mProfileLock;
int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
-
+
+ float[][] mProfileRects;
+ Paint mProfilePaint;
+
boolean mDebugDirtyRegions;
boolean mShowOverdraw;
@@ -698,6 +717,18 @@ public abstract class HardwareRenderer {
mProfileData = null;
mProfileLock = null;
}
+
+ mProfileRects = null;
+ mProfilePaint = null;
+ }
+
+ value = SystemProperties.getBoolean(PROFILE_VISUALIZER_PROPERTY, false);
+ if (value != mProfileVisualizerEnabled) {
+ changed = true;
+ mProfileVisualizerEnabled = value;
+
+ mProfileRects = null;
+ mProfilePaint = null;
}
value = SystemProperties.getBoolean(DEBUG_DIRTY_REGIONS_PROPERTY, false);
@@ -1175,23 +1206,7 @@ public abstract class HardwareRenderer {
mProfileLock.lock();
}
- // We had to change the current surface and/or context, redraw everything
- if (surfaceState == SURFACE_STATE_UPDATED) {
- dirty = null;
- beginFrame(null);
- } else {
- int[] size = mSurfaceSize;
- beginFrame(size);
-
- if (size[1] != mHeight || size[0] != mWidth) {
- mWidth = size[0];
- mHeight = size[1];
-
- canvas.setViewport(mWidth, mHeight);
-
- dirty = null;
- }
- }
+ dirty = beginFrame(canvas, dirty, surfaceState);
int saveCount = 0;
int status = DisplayList.STATUS_DONE;
@@ -1201,63 +1216,19 @@ public abstract class HardwareRenderer {
== View.PFLAG_INVALIDATED;
view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
- long getDisplayListStartTime = 0;
- if (mProfileEnabled) {
- mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
- if (mProfileCurrentFrame >= mProfileData.length) {
- mProfileCurrentFrame = 0;
- }
-
- getDisplayListStartTime = System.nanoTime();
- }
-
+ long buildDisplayListStartTime = startBuildDisplayListProfiling();
canvas.clearLayerUpdates();
- DisplayList displayList;
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
- try {
- displayList = view.getDisplayList();
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
+ DisplayList displayList = buildDisplayList(view);
+ status = prepareFrame(dirty);
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
- try {
- status = onPreDraw(dirty);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
saveCount = canvas.save();
callbacks.onHardwarePreDraw(canvas);
- if (mProfileEnabled) {
- long now = System.nanoTime();
- float total = (now - getDisplayListStartTime) * 0.000001f;
- //noinspection PointlessArithmeticExpression
- mProfileData[mProfileCurrentFrame] = total;
- }
+ endBuildDisplayListProfiling(buildDisplayListStartTime);
if (displayList != null) {
- long drawDisplayListStartTime = 0;
- if (mProfileEnabled) {
- drawDisplayListStartTime = System.nanoTime();
- }
-
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
- try {
- status |= canvas.drawDisplayList(displayList, mRedrawClip,
- DisplayList.FLAG_CLIP_CHILDREN);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
-
- if (mProfileEnabled) {
- long now = System.nanoTime();
- float total = (now - drawDisplayListStartTime) * 0.000001f;
- mProfileData[mProfileCurrentFrame + 1] = total;
- }
-
- handleFunctorStatus(attachInfo, status);
+ status = drawDisplayList(attachInfo, canvas, displayList, status);
} else {
// Shouldn't reach here
view.draw(canvas);
@@ -1269,43 +1240,19 @@ public abstract class HardwareRenderer {
mFrameCount++;
- if (mDebugDirtyRegions) {
- if (mDebugPaint == null) {
- mDebugPaint = new Paint();
- mDebugPaint.setColor(0x7fff0000);
- }
-
- if (dirty != null && (mFrameCount & 1) == 0) {
- canvas.drawRect(dirty, mDebugPaint);
- }
- }
+ debugDirtyRegions(dirty, canvas);
+ drawProfileData();
}
onPostDraw();
- attachInfo.mIgnoreDirtyState = false;
-
- if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
- long eglSwapBuffersStartTime = 0;
- if (mProfileEnabled) {
- eglSwapBuffersStartTime = System.nanoTime();
- }
-
- sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
-
- if (mProfileEnabled) {
- long now = System.nanoTime();
- float total = (now - eglSwapBuffersStartTime) * 0.000001f;
- mProfileData[mProfileCurrentFrame + 2] = total;
- }
-
- checkEglErrors();
- }
+ swapBuffers(status);
if (mProfileEnabled) {
mProfileLock.unlock();
}
+ attachInfo.mIgnoreDirtyState = false;
return dirty == null;
}
}
@@ -1313,6 +1260,133 @@ public abstract class HardwareRenderer {
return false;
}
+ abstract void drawProfileData();
+
+ private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
+ // We had to change the current surface and/or context, redraw everything
+ if (surfaceState == SURFACE_STATE_UPDATED) {
+ dirty = null;
+ beginFrame(null);
+ } else {
+ int[] size = mSurfaceSize;
+ beginFrame(size);
+
+ if (size[1] != mHeight || size[0] != mWidth) {
+ mWidth = size[0];
+ mHeight = size[1];
+
+ canvas.setViewport(mWidth, mHeight);
+
+ dirty = null;
+ }
+ }
+
+ if (mProfileEnabled && mProfileVisualizerEnabled) dirty = null;
+
+ return dirty;
+ }
+
+ private long startBuildDisplayListProfiling() {
+ if (mProfileEnabled) {
+ mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
+ if (mProfileCurrentFrame >= mProfileData.length) {
+ mProfileCurrentFrame = 0;
+ }
+
+ return System.nanoTime();
+ }
+ return 0;
+ }
+
+ private void endBuildDisplayListProfiling(long getDisplayListStartTime) {
+ if (mProfileEnabled) {
+ long now = System.nanoTime();
+ float total = (now - getDisplayListStartTime) * 0.000001f;
+ //noinspection PointlessArithmeticExpression
+ mProfileData[mProfileCurrentFrame] = total;
+ }
+ }
+
+ private static DisplayList buildDisplayList(View view) {
+ DisplayList displayList;
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
+ try {
+ displayList = view.getDisplayList();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ return displayList;
+ }
+
+ private int prepareFrame(Rect dirty) {
+ int status;
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
+ try {
+ status = onPreDraw(dirty);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ return status;
+ }
+
+ private int drawDisplayList(View.AttachInfo attachInfo, HardwareCanvas canvas,
+ DisplayList displayList, int status) {
+
+ long drawDisplayListStartTime = 0;
+ if (mProfileEnabled) {
+ drawDisplayListStartTime = System.nanoTime();
+ }
+
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
+ try {
+ status |= canvas.drawDisplayList(displayList, mRedrawClip,
+ DisplayList.FLAG_CLIP_CHILDREN);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+
+ if (mProfileEnabled) {
+ long now = System.nanoTime();
+ float total = (now - drawDisplayListStartTime) * 0.000001f;
+ mProfileData[mProfileCurrentFrame + 1] = total;
+ }
+
+ handleFunctorStatus(attachInfo, status);
+ return status;
+ }
+
+ private void swapBuffers(int status) {
+ if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
+ long eglSwapBuffersStartTime = 0;
+ if (mProfileEnabled) {
+ eglSwapBuffersStartTime = System.nanoTime();
+ }
+
+ sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
+
+ if (mProfileEnabled) {
+ long now = System.nanoTime();
+ float total = (now - eglSwapBuffersStartTime) * 0.000001f;
+ mProfileData[mProfileCurrentFrame + 2] = total;
+ }
+
+ checkEglErrors();
+ }
+ }
+
+ private void debugDirtyRegions(Rect dirty, HardwareCanvas canvas) {
+ if (mDebugDirtyRegions) {
+ if (mDebugPaint == null) {
+ mDebugPaint = new Paint();
+ mDebugPaint.setColor(0x7fff0000);
+ }
+
+ if (dirty != null && (mFrameCount & 1) == 0) {
+ canvas.drawRect(dirty, mDebugPaint);
+ }
+ }
+ }
+
private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
// If the draw flag is set, functors will be invoked while executing
// the tree of display lists
@@ -1389,6 +1463,15 @@ public abstract class HardwareRenderer {
* Hardware renderer using OpenGL ES 2.0.
*/
static class Gl20Renderer extends GlRenderer {
+ // TODO: Convert dimensions to dp instead of px
+ private static final int PROFILE_DRAW_MARGIN = 1;
+ private static final int PROFILE_DRAW_WIDTH = 3;
+ private static final int[] PROFILE_DRAW_COLORS = { 0xff3e66cc, 0xffdc3912, 0xffe69800 };
+ private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d;
+ private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
+ private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xff5faa4d;
+ private static final int PROFILE_DRAW_PX_PER_MS = 10;
+
private GLES20Canvas mGlCanvas;
private static EGLSurface sPbuffer;
@@ -1494,6 +1577,94 @@ public abstract class HardwareRenderer {
}
@Override
+ void drawProfileData() {
+ if (mProfileEnabled && mProfileVisualizerEnabled) {
+ initProfileDrawData();
+
+ int x = 0;
+ int count = 0;
+ int current = 0;
+
+ for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
+ if (mProfileData[i] < 0.0f) break;
+
+ int index = count * 4;
+ if (i == mProfileCurrentFrame) current = index;
+
+ x += PROFILE_DRAW_MARGIN;
+ int x2 = x + PROFILE_DRAW_WIDTH;
+
+ int y2 = mHeight;
+ int y1 = (int) (y2 - mProfileData[i] * PROFILE_DRAW_PX_PER_MS);
+
+ float[] r = mProfileRects[0];
+ r[index] = x;
+ r[index + 1] = y1;
+ r[index + 2] = x2;
+ r[index + 3] = y2;
+
+ y2 = y1;
+ y1 = (int) (y2 - mProfileData[i + 1] * PROFILE_DRAW_PX_PER_MS);
+
+ r = mProfileRects[1];
+ r[index] = x;
+ r[index + 1] = y1;
+ r[index + 2] = x2;
+ r[index + 3] = y2;
+
+ y2 = y1;
+ y1 = (int) (y2 - mProfileData[i + 2] * PROFILE_DRAW_PX_PER_MS);
+
+ r = mProfileRects[2];
+ r[index] = x;
+ r[index + 1] = y1;
+ r[index + 2] = x2;
+ r[index + 3] = y2;
+
+ x += PROFILE_DRAW_WIDTH;
+
+ count++;
+ }
+
+ drawGraph(count);
+ drawCurrentFrame(current);
+ drawThreshold(x + PROFILE_DRAW_MARGIN);
+ }
+ }
+
+ private void drawGraph(int count) {
+ for (int i = 0; i < mProfileRects.length; i++) {
+ mProfilePaint.setColor(PROFILE_DRAW_COLORS[i]);
+ mGlCanvas.drawRects(mProfileRects[i], count, mProfilePaint);
+ }
+ }
+
+ private void drawCurrentFrame(int index) {
+ mProfilePaint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
+ mGlCanvas.drawRect(mProfileRects[2][index], mProfileRects[2][index + 1],
+ mProfileRects[2][index + 2], mProfileRects[0][index + 3], mProfilePaint);
+ }
+
+ private void drawThreshold(int x) {
+ mProfilePaint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
+ mProfilePaint.setStrokeWidth(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH);
+ int y = mHeight - 16 * 10;
+ mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint);
+ mProfilePaint.setStrokeWidth(1.0f);
+ }
+
+ private void initProfileDrawData() {
+ if (mProfileRects == null) {
+ mProfileRects = new float[PROFILE_FRAME_DATA_COUNT][];
+ for (int i = 0; i < mProfileRects.length; i++) {
+ int count = mProfileData.length / PROFILE_FRAME_DATA_COUNT;
+ mProfileRects[i] = new float[count * 4];
+ }
+ mProfilePaint = new Paint();
+ }
+ }
+
+ @Override
void destroy(boolean full) {
try {
super.destroy(full);
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index d8d55b2..7d886da 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -449,16 +449,40 @@ static void android_view_GLES20Canvas_drawArc(JNIEnv* env, jobject clazz,
renderer->drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint);
}
-static void android_view_GLES20Canvas_drawRects(JNIEnv* env, jobject clazz,
+static void android_view_GLES20Canvas_drawRegionAsRects(JNIEnv* env, jobject clazz,
OpenGLRenderer* renderer, SkRegion* region, SkPaint* paint) {
- SkRegion::Iterator it(*region);
- while (!it.done()) {
- const SkIRect& r = it.rect();
- renderer->drawRect(r.fLeft, r.fTop, r.fRight, r.fBottom, paint);
- it.next();
+ if (paint->getStyle() != SkPaint::kFill_Style ||
+ (paint->isAntiAlias() && !renderer->isCurrentTransformSimple())) {
+ SkRegion::Iterator it(*region);
+ while (!it.done()) {
+ const SkIRect& r = it.rect();
+ renderer->drawRect(r.fLeft, r.fTop, r.fRight, r.fBottom, paint);
+ it.next();
+ }
+ } else {
+ int count = 0;
+ Vector<float> rects;
+ SkRegion::Iterator it(*region);
+ while (!it.done()) {
+ const SkIRect& r = it.rect();
+ rects.push(r.fLeft);
+ rects.push(r.fTop);
+ rects.push(r.fRight);
+ rects.push(r.fBottom);
+ count++;
+ it.next();
+ }
+ renderer->drawRects(rects.array(), count, paint);
}
}
+static void android_view_GLES20Canvas_drawRects(JNIEnv* env, jobject clazz,
+ OpenGLRenderer* renderer, jfloatArray rects, jint count, SkPaint* paint) {
+ jfloat* storage = env->GetFloatArrayElements(rects, NULL);
+ renderer->drawRects(storage, count, paint);
+ env->ReleaseFloatArrayElements(rects, storage, 0);
+}
+
static void android_view_GLES20Canvas_drawPoints(JNIEnv* env, jobject clazz,
OpenGLRenderer* renderer, jfloatArray points, jint offset, jint count, SkPaint* paint) {
jfloat* storage = env->GetFloatArrayElements(points, NULL);
@@ -958,7 +982,8 @@ static JNINativeMethod gMethods[] = {
{ "nDrawColor", "(III)V", (void*) android_view_GLES20Canvas_drawColor },
{ "nDrawRect", "(IFFFFI)V", (void*) android_view_GLES20Canvas_drawRect },
- { "nDrawRects", "(III)V", (void*) android_view_GLES20Canvas_drawRects },
+ { "nDrawRects", "(III)V", (void*) android_view_GLES20Canvas_drawRegionAsRects },
+ { "nDrawRects", "(I[FII)V", (void*) android_view_GLES20Canvas_drawRects },
{ "nDrawRoundRect", "(IFFFFFFI)V", (void*) android_view_GLES20Canvas_drawRoundRect },
{ "nDrawCircle", "(IFFFI)V", (void*) android_view_GLES20Canvas_drawCircle },
{ "nDrawOval", "(IFFFFI)V", (void*) android_view_GLES20Canvas_drawOval },
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 7a38b40..747856c 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -64,6 +64,7 @@ const char* DisplayList::OP_NAMES[] = {
"DrawTextOnPath",
"DrawPosText",
"DrawText",
+ "DrawRects",
"ResetShader",
"SetupShader",
"ResetColorFilter",
@@ -633,6 +634,13 @@ void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) {
text.text(), text.length(), count, paint);
}
break;
+ case DrawRects: {
+ int32_t count = 0;
+ float* rects = getFloats(count);
+ SkPaint* paint = getPaint(renderer);
+ ALOGD("%s%s %d, %p", (char*) indent, OP_NAMES[op], count / 4, paint);
+ }
+ break;
case ResetShader: {
ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
}
@@ -1277,6 +1285,14 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag
x, y, positions, paint, length);
}
break;
+ case DrawRects: {
+ int32_t count = 0;
+ float* rects = getFloats(count);
+ SkPaint* paint = getPaint(renderer);
+ DISPLAY_LIST_LOGD("%s%s %d, %p", (char*) indent, OP_NAMES[op], count, paint);
+ drawGlStatus |= renderer.drawRects(rects, count / 4, paint);
+ }
+ break;
case ResetShader: {
DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
renderer.resetShader();
@@ -1814,6 +1830,15 @@ status_t DisplayListRenderer::drawText(const char* text, int bytesCount, int cou
return DrawGlInfo::kStatusDone;
}
+status_t DisplayListRenderer::drawRects(const float* rects, int count, SkPaint* paint) {
+ if (count <= 0) return DrawGlInfo::kStatusDone;
+
+ addOp(DisplayList::DrawRects);
+ addFloats(rects, count * 4);
+ addPaint(paint);
+ return DrawGlInfo::kStatusDone;
+}
+
void DisplayListRenderer::resetShader() {
addOp(DisplayList::ResetShader);
}
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index e42def5..fb01753 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -106,6 +106,7 @@ public:
DrawTextOnPath,
DrawPosText,
DrawText,
+ DrawRects,
ResetShader,
SetupShader,
ResetColorFilter,
@@ -608,6 +609,7 @@ public:
const float* positions, SkPaint* paint);
virtual status_t drawText(const char* text, int bytesCount, int count,
float x, float y, const float* positions, SkPaint* paint, float length);
+ virtual status_t drawRects(const float* rects, int count, SkPaint* paint);
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index ca9a38e..4b1d8ec 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1254,7 +1254,8 @@ bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, fl
return !clip.intersects(transformed);
}
-bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint) {
+bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom,
+ SkPaint* paint) {
if (paint->getStyle() != SkPaint::kFill_Style) {
float outset = paint->getStrokeWidth() * 0.5f;
return quickReject(left - outset, top - outset, right + outset, bottom + outset);
@@ -3030,6 +3031,76 @@ void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float
}
}
+status_t OpenGLRenderer::drawRects(const float* rects, int count, SkPaint* paint) {
+ if (mSnapshot->isIgnored()) {
+ return DrawGlInfo::kStatusDone;
+ }
+
+ float left = FLT_MAX;
+ float top = FLT_MAX;
+ float right = FLT_MIN;
+ float bottom = FLT_MIN;
+
+ int vertexCount = 0;
+ Vertex mesh[count * 6];
+ Vertex* vertex = mesh;
+
+ for (int i = 0; i < count; i++) {
+ int index = i * 4;
+ float l = rects[index + 0];
+ float t = rects[index + 1];
+ float r = rects[index + 2];
+ float b = rects[index + 3];
+
+ if (!quickRejectNoScissor(left, top, right, bottom)) {
+ Vertex::set(vertex++, l, b);
+ Vertex::set(vertex++, l, t);
+ Vertex::set(vertex++, r, t);
+ Vertex::set(vertex++, l, b);
+ Vertex::set(vertex++, r, t);
+ Vertex::set(vertex++, r, b);
+
+ vertexCount += 6;
+
+ left = fminf(left, l);
+ top = fminf(top, t);
+ right = fmaxf(right, r);
+ bottom = fmaxf(bottom, b);
+ }
+ }
+
+ if (count == 0) return DrawGlInfo::kStatusDone;
+
+ int color = paint->getColor();
+ // If a shader is set, preserve only the alpha
+ if (mShader) {
+ color |= 0x00ffffff;
+ }
+ SkXfermode::Mode mode = getXfermode(paint->getXfermode());
+
+ setupDraw();
+ setupDrawNoTexture();
+ setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
+ setupDrawShader();
+ setupDrawColorFilter();
+ setupDrawBlending(mode);
+ setupDrawProgram();
+ setupDrawDirtyRegionsDisabled();
+ setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f);
+ setupDrawColorUniforms();
+ setupDrawShaderUniforms();
+ setupDrawColorFilterUniforms();
+ setupDrawVertices((GLvoid*) &mesh[0].position[0]);
+
+ if (hasLayer()) {
+ dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
+ }
+
+ glDrawArrays(GL_TRIANGLES, 0, vertexCount);
+
+ return DrawGlInfo::kStatusDrew;
+}
+
void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
int color, SkXfermode::Mode mode, bool ignoreTransform) {
// If a shader is set, preserve only the alpha
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index f165581..b1d3cc3 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -201,6 +201,7 @@ public:
const float* positions, SkPaint* paint);
virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
const float* positions, SkPaint* paint, float length = -1.0f);
+ virtual status_t drawRects(const float* rects, int count, SkPaint* paint);
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
@@ -216,6 +217,10 @@ public:
SkPaint* filterPaint(SkPaint* paint);
+ ANDROID_API bool isCurrentTransformSimple() {
+ return mSnapshot->transform->isSimple();
+ }
+
/**
* Sets the alpha on the current snapshot. This alpha value will be modulated
* with other alpha values when drawing primitives.