Merge "Add visual profiling feature"
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -88,11 +88,26 @@ 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.
|
||||
@@ -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;
|
||||
@@ -1493,6 +1576,94 @@ public abstract class HardwareRenderer {
|
||||
mGlCanvas.onPostDraw();
|
||||
}
|
||||
|
||||
@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 {
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
@@ -3045,6 +3046,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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user