From ed6fcb034b44d9a6ac2fc72fee6030417811f234 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Mon, 21 Mar 2011 13:11:28 -0700 Subject: Add support for drawPoint() and drawPoints(). Change-Id: I01bef50c08ec3160f8d40dc060b2cf6c2e4d7639 --- core/java/android/view/GLES20Canvas.java | 15 ++++--- core/jni/android_view_GLES20Canvas.cpp | 10 ++++- libs/hwui/DisplayListRenderer.cpp | 14 ++++++ libs/hwui/DisplayListRenderer.h | 2 + libs/hwui/OpenGLRenderer.cpp | 52 ++++++++++++++++++++++ libs/hwui/OpenGLRenderer.h | 3 ++ libs/hwui/ProgramCache.cpp | 42 +++++++++++++++-- libs/hwui/ProgramCache.h | 13 +++++- .../src/com/android/test/hwui/LinesActivity.java | 32 ++++++++++++- 9 files changed, 168 insertions(+), 15 deletions(-) diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index d841419..8621de3 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -773,19 +773,24 @@ class GLES20Canvas extends HardwareCanvas { public void drawPoint(float x, float y, Paint paint) { mPoint[0] = x; mPoint[1] = y; - drawPoints(mPoint, 0, 1, paint); + drawPoints(mPoint, 0, 2, paint); } @Override - public void drawPoints(float[] pts, int offset, int count, Paint paint) { - // TODO: Implement + public void drawPoints(float[] pts, Paint paint) { + drawPoints(pts, 0, pts.length, paint); } @Override - public void drawPoints(float[] pts, Paint paint) { - drawPoints(pts, 0, pts.length / 2, paint); + public void drawPoints(float[] pts, int offset, int count, Paint paint) { + int modifiers = setupModifiers(paint); + nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } + private static native void nDrawPoints(int renderer, float[] points, + int offset, int count, int paint); + @Override public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) { // TODO: Implement diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index d6d3e4f..a4931ac 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -366,6 +366,13 @@ static void android_view_GLES20Canvas_drawRects(JNIEnv* env, jobject clazz, } } +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); + renderer->drawPoints(storage + offset, count, paint); + env->ReleaseFloatArrayElements(points, storage, 0); +} + static void android_view_GLES20Canvas_drawPath(JNIEnv* env, jobject clazz, OpenGLRenderer* renderer, SkPath* path, SkPaint* paint) { renderer->drawPath(path, paint); @@ -374,9 +381,7 @@ static void android_view_GLES20Canvas_drawPath(JNIEnv* env, jobject clazz, static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject clazz, OpenGLRenderer* renderer, jfloatArray points, jint offset, jint count, SkPaint* paint) { jfloat* storage = env->GetFloatArrayElements(points, NULL); - renderer->drawLines(storage + offset, count, paint); - env->ReleaseFloatArrayElements(points, storage, 0); } @@ -645,6 +650,7 @@ static JNINativeMethod gMethods[] = { { "nDrawCircle", "(IFFFI)V", (void*) android_view_GLES20Canvas_drawCircle }, { "nDrawOval", "(IFFFFI)V", (void*) android_view_GLES20Canvas_drawOval }, { "nDrawArc", "(IFFFFFFZI)V", (void*) android_view_GLES20Canvas_drawArc }, + { "nDrawPoints", "(I[FIII)V", (void*) android_view_GLES20Canvas_drawPoints }, { "nDrawPath", "(III)V", (void*) android_view_GLES20Canvas_drawPath }, { "nDrawLines", "(I[FIII)V", (void*) android_view_GLES20Canvas_drawLines }, diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index f2f983f..bf1182c 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -53,6 +53,7 @@ const char* DisplayList::OP_NAMES[] = { "DrawArc", "DrawPath", "DrawLines", + "DrawPoints", "DrawText", "ResetShader", "SetupShader", @@ -441,6 +442,13 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) renderer.drawLines(points, count, getPaint()); } break; + case DrawPoints: { + int count = 0; + float* points = getFloats(count); + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); + renderer.drawPoints(points, count, getPaint()); + } + break; case DrawText: { getText(&text); int count = getInt(); @@ -787,6 +795,12 @@ void DisplayListRenderer::drawLines(float* points, int count, SkPaint* paint) { addPaint(paint); } +void DisplayListRenderer::drawPoints(float* points, int count, SkPaint* paint) { + addOp(DisplayList::DrawPoints); + addFloats(points, count); + addPaint(paint); +} + void DisplayListRenderer::drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint) { addOp(DisplayList::DrawText); diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 8773cb5..da57e4a 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -89,6 +89,7 @@ public: DrawArc, DrawPath, DrawLines, + DrawPoints, DrawText, ResetShader, SetupShader, @@ -264,6 +265,7 @@ public: float startAngle, float sweepAngle, bool useCenter, SkPaint* paint); void drawPath(SkPath* path, SkPaint* paint); void drawLines(float* points, int count, SkPaint* paint); + void drawPoints(float* points, int count, SkPaint* paint); void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint); void resetShader(); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index a711289..6c454a4 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -879,6 +879,11 @@ void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) { mDescription.hasAlpha8Texture = isAlpha8; } +void OpenGLRenderer::setupDrawPoint(float pointSize) { + mDescription.isPoint = true; + mDescription.pointSize = pointSize; +} + void OpenGLRenderer::setupDrawColor(int color) { setupDrawColor(color, (color >> 24) & 0xFF); } @@ -987,6 +992,11 @@ void OpenGLRenderer::setupDrawModelView(float left, float top, float right, floa } } +void OpenGLRenderer::setupDrawPointUniforms() { + int slot = mCaches.currentProgram->getUniform("pointSize"); + glUniform1f(slot, mDescription.pointSize); +} + void OpenGLRenderer::setupDrawColorUniforms() { if (mColorSet || (mShader && mSetShaderColor)) { mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA); @@ -1446,6 +1456,48 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { } } +void OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { + if (mSnapshot->isIgnored()) return; + + // TODO: The paint's cap style defines whether the points are square or circular + // TODO: Handle AA for round points + + // A stroke width of 0 has a special meaningin Skia: + // it draws an unscaled 1px point + const bool isHairLine = paint->getStrokeWidth() == 0.0f; + + int alpha; + SkXfermode::Mode mode; + getAlphaAndMode(paint, &alpha, &mode); + + int verticesCount = count >> 1; + int generatedVerticesCount = 0; + + TextureVertex pointsData[verticesCount]; + TextureVertex* vertex = &pointsData[0]; + + setupDraw(); + setupDrawPoint(isHairLine ? 1.0f : paint->getStrokeWidth()); + setupDrawColor(paint->getColor(), alpha); + setupDrawColorFilter(); + setupDrawShader(); + setupDrawBlending(mode); + setupDrawProgram(); + setupDrawModelViewIdentity(); + setupDrawColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawPointUniforms(); + setupDrawShaderIdentityUniforms(); + setupDrawMesh(vertex); + + for (int i = 0; i < count; i += 2) { + TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); + generatedVerticesCount++; + } + + glDrawArrays(GL_POINTS, 0, generatedVerticesCount); +} + void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { // No need to check against the clip, we fill the clip region if (mSnapshot->isIgnored()) return; diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 402563c..4b93b80 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -119,6 +119,7 @@ public: float startAngle, float sweepAngle, bool useCenter, SkPaint* paint); virtual void drawPath(SkPath* path, SkPaint* paint); virtual void drawLines(float* points, int count, SkPaint* paint); + virtual void drawPoints(float* points, int count, SkPaint* paint); virtual void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint); @@ -424,6 +425,7 @@ private: * Various methods to setup OpenGL rendering. */ void setupDrawWithTexture(bool isAlpha8 = false); + void setupDrawPoint(float pointSize); void setupDrawColor(int color); void setupDrawColor(int color, int alpha); void setupDrawColor(float r, float g, float b, float a); @@ -442,6 +444,7 @@ private: bool ignoreTransform = false, bool ignoreModelView = false); void setupDrawModelViewTranslate(float left, float top, float right, float bottom, bool ignoreTransform = false); + void setupDrawPointUniforms(); void setupDrawColorUniforms(); void setupDrawPureColorUniforms(); void setupDrawShaderIdentityUniforms(); diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 0b6c7b5..2562306 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -41,6 +41,8 @@ const char* gVS_Header_Attributes_TexCoords = "attribute vec2 texCoords;\n"; const char* gVS_Header_Uniforms = "uniform mat4 transform;\n"; +const char* gVS_Header_Uniforms_IsPoint = + "uniform float pointSize;\n"; const char* gVS_Header_Uniforms_HasGradient[3] = { // Linear "uniform mat4 screenSpace;\n", @@ -56,6 +58,8 @@ const char* gVS_Header_Varyings_HasTexture = "varying vec2 outTexCoords;\n"; const char* gVS_Header_Varyings_HasBitmap = "varying vec2 outBitmapTexCoords;\n"; +const char* gVS_Header_Varyings_PointHasBitmap = + "varying vec2 outPointBitmapTexCoords;\n"; const char* gVS_Header_Varyings_HasGradient[3] = { // Linear "varying vec2 linear;\n", @@ -78,8 +82,12 @@ const char* gVS_Main_OutGradient[3] = { }; const char* gVS_Main_OutBitmapTexCoords = " outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n"; +const char* gVS_Main_OutPointBitmapTexCoords = + " outPointBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n"; const char* gVS_Main_Position = " gl_Position = transform * position;\n"; +const char* gVS_Main_PointSize = + " gl_PointSize = pointSize;\n"; const char* gVS_Footer = "}\n\n"; @@ -93,6 +101,9 @@ const char* gFS_Header = "precision mediump float;\n\n"; const char* gFS_Uniforms_Color = "uniform vec4 color;\n"; +const char* gFS_Header_Uniforms_PointHasBitmap = + "uniform vec2 textureDimension;\n" + "uniform float pointSize;\n"; const char* gFS_Uniforms_TextureSampler = "uniform sampler2D sampler;\n"; const char* gFS_Uniforms_GradientSampler[3] = { @@ -121,6 +132,10 @@ const char* gFS_Main = "\nvoid main(void) {\n" " lowp vec4 fragColor;\n"; +const char* gFS_Main_PointBitmapTexCoords = + " vec2 outBitmapTexCoords = outPointBitmapTexCoords + " + "((gl_PointCoord - vec2(0.5, 0.5)) * textureDimension * vec2(pointSize, pointSize));\n"; + // Fast cases const char* gFS_Fast_SingleColor = "\nvoid main(void) {\n" @@ -347,6 +362,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasBitmap) { shader.append(gVS_Header_Uniforms_HasBitmap); } + if (description.isPoint) { + shader.append(gVS_Header_Uniforms_IsPoint); + } // Varyings if (description.hasTexture) { shader.append(gVS_Header_Varyings_HasTexture); @@ -355,7 +373,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } if (description.hasBitmap) { - shader.append(gVS_Header_Varyings_HasBitmap); + shader.append(description.isPoint ? + gVS_Header_Varyings_PointHasBitmap : + gVS_Header_Varyings_HasBitmap); } // Begin the shader @@ -367,7 +387,12 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description shader.append(gVS_Main_OutGradient[description.gradientType]); } if (description.hasBitmap) { - shader.append(gVS_Main_OutBitmapTexCoords); + shader.append(description.isPoint ? + gVS_Main_OutPointBitmapTexCoords : + gVS_Main_OutBitmapTexCoords); + } + if (description.isPoint) { + shader.append(gVS_Main_PointSize); } // Output transformed position shader.append(gVS_Main_Position); @@ -399,7 +424,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } if (description.hasBitmap) { - shader.append(gVS_Header_Varyings_HasBitmap); + shader.append(description.isPoint ? + gVS_Header_Varyings_PointHasBitmap : + gVS_Header_Varyings_HasBitmap); } // Uniforms @@ -417,9 +444,13 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.hasGradient) { shader.append(gFS_Uniforms_GradientSampler[description.gradientType]); } + if (description.hasBitmap && description.isPoint) { + shader.append(gFS_Header_Uniforms_PointHasBitmap); + } // Optimization for common cases - if (!blendFramebuffer && description.colorOp == ProgramDescription::kColorNone) { + if (!blendFramebuffer && description.colorOp == ProgramDescription::kColorNone && + !description.isPoint) { bool fast = false; const bool noShader = !description.hasGradient && !description.hasBitmap; @@ -507,6 +538,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Main_FetchGradient[description.gradientType]); } if (description.hasBitmap) { + if (description.isPoint) { + shader.append(gFS_Main_PointBitmapTexCoords); + } if (!description.isBitmapNpot) { shader.append(gFS_Main_FetchBitmap); } else { diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h index ead5b92..737d91b 100644 --- a/libs/hwui/ProgramCache.h +++ b/libs/hwui/ProgramCache.h @@ -71,7 +71,9 @@ namespace uirenderer { #define PROGRAM_BITMAP_WRAPT_SHIFT 11 #define PROGRAM_GRADIENT_TYPE_SHIFT 33 -#define PROGRAM_MODULATE 35 +#define PROGRAM_MODULATE_SHIFT 35 + +#define PROGRAM_IS_POINT_SHIFT 36 /////////////////////////////////////////////////////////////////////////////// // Types @@ -135,6 +137,9 @@ struct ProgramDescription { SkXfermode::Mode framebufferMode; bool swapSrcDst; + bool isPoint; + float pointSize; + /** * Resets this description. All fields are reset back to the default * values they hold after building a new instance. @@ -162,6 +167,9 @@ struct ProgramDescription { framebufferMode = SkXfermode::kClear_Mode; swapSrcDst = false; + + isPoint = false; + pointSize = 0.0f; } /** @@ -223,7 +231,8 @@ struct ProgramDescription { } key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT; if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST; - if (modulate) key |= programid(0x1) << PROGRAM_MODULATE; + if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT; + if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT; return key; } diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java index 8ca842e..4233367 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java @@ -16,6 +16,7 @@ package com.android.test.hwui; +import android.animation.ObjectAnimator; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; @@ -29,13 +30,26 @@ import android.view.View; @SuppressWarnings({"UnusedDeclaration"}) public class LinesActivity extends Activity { + private ObjectAnimator mAnimator; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().setBackgroundDrawable(new ColorDrawable(0xffffffff)); final LinesView view = new LinesView(this); - //view.setAlpha(0.80f); setContentView(view); + + mAnimator = ObjectAnimator.ofFloat(view, "offset", 0.0f, 15.0f); + mAnimator.setDuration(1500); + mAnimator.setRepeatCount(ObjectAnimator.INFINITE); + mAnimator.setRepeatMode(ObjectAnimator.REVERSE); + mAnimator.start(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mAnimator.cancel(); } public static class LinesView extends View { @@ -50,6 +64,8 @@ public class LinesActivity extends Activity { private final Paint mAlphaPaint; private final Paint mHairLinePaint; + private float mOffset; + public LinesView(Context c) { super(c); @@ -89,11 +105,16 @@ public class LinesActivity extends Activity { 352.0f, 400.0f, 352.0f, 500.0f }; } + + public void setOffset(float offset) { + mOffset = offset; + invalidate(); + } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); - + canvas.save(); canvas.translate(100.0f, 20.0f); @@ -103,6 +124,12 @@ public class LinesActivity extends Activity { mLargePaint.setShader(mShader); canvas.drawLine(42.0f, 0.0f, 222.0f, 400.0f, mLargePaint); + for (int x = 0; x < 20; x++) { + for (int y = 0; y < 20; y++) { + canvas.drawPoint(500.0f + x * (15.0f + mOffset), + y * (15.0f + mOffset), mLargePaint); + } + } mLargePaint.setShader(null); canvas.drawLines(mPoints, mAlphaPaint); @@ -120,6 +147,7 @@ public class LinesActivity extends Activity { canvas.restore(); + canvas.save(); canvas.scale(10.0f, 10.0f); canvas.drawLine(50.0f, 40.0f, 10.0f, 40.0f, mSmallPaint); canvas.drawLine(10.0f, 50.0f, 50.0f, 50.0f, mSmallPaint); -- cgit v1.1