summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2010-12-08 19:10:51 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2010-12-08 19:10:51 -0800
commit279d34f4b26caf77e5dde2f7cbe3d286ac54dda6 (patch)
tree6c3877ca5d0e383fa0aa601eea4395741a9dae04
parent324c31622b3f0c0d94cfece32df3261c5f2cb20e (diff)
parenta957eea78557cb47a91d44d9e6ee641c58cf1c07 (diff)
downloadframeworks_base-279d34f4b26caf77e5dde2f7cbe3d286ac54dda6.zip
frameworks_base-279d34f4b26caf77e5dde2f7cbe3d286ac54dda6.tar.gz
frameworks_base-279d34f4b26caf77e5dde2f7cbe3d286ac54dda6.tar.bz2
Merge "New, better line drawing implementation. Bug #3207544 Bug #3225875"
-rw-r--r--libs/hwui/Caches.h3
-rw-r--r--libs/hwui/Line.h127
-rw-r--r--libs/hwui/OpenGLRenderer.cpp139
-rw-r--r--libs/hwui/Vector.h119
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml3
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java24
6 files changed, 235 insertions, 180 deletions
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index e8ced9c..318c120 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -34,7 +34,6 @@
#include "PathCache.h"
#include "TextDropShadowCache.h"
#include "FboCache.h"
-#include "Line.h"
#include "ResourceCache.h"
namespace android {
@@ -158,8 +157,6 @@ public:
GammaFontRenderer fontRenderer;
ResourceCache resourceCache;
- Line line;
-
private:
DebugLevel mDebugLevel;
}; // class Caches
diff --git a/libs/hwui/Line.h b/libs/hwui/Line.h
deleted file mode 100644
index 264fd19..0000000
--- a/libs/hwui/Line.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_LINE_H
-#define ANDROID_HWUI_LINE_H
-
-#include <GLES2/gl2.h>
-
-#include <cmath>
-
-#include <sys/types.h>
-
-#include "Patch.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Globals
-///////////////////////////////////////////////////////////////////////////////
-
-// Alpha8 texture used to perform texture anti-aliasing
-static const uint8_t gLineTexture[] = {
- 0, 0, 0, 0, 0,
- 0, 255, 255, 255, 0,
- 0, 255, 255, 255, 0,
- 0, 255, 255, 255, 0,
- 0, 0, 0, 0, 0
-};
-static const GLsizei gLineTextureWidth = 5;
-static const GLsizei gLineTextureHeight = 5;
-static const float gLineAABias = 1.0f;
-
-///////////////////////////////////////////////////////////////////////////////
-// Line
-///////////////////////////////////////////////////////////////////////////////
-
-class Line {
-public:
- Line(): mXDivsCount(2), mYDivsCount(2) {
- mPatch = new Patch(mXDivsCount, mYDivsCount);
- mXDivs = new int32_t[mXDivsCount];
- mYDivs = new int32_t[mYDivsCount];
-
- mXDivs[0] = mYDivs[0] = 2;
- mXDivs[1] = mYDivs[1] = 3;
-
- mPatch->copy(mXDivs, mYDivs);
-
- glGenTextures(1, &mTexture);
- glBindTexture(GL_TEXTURE_2D, mTexture);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, gLineTextureWidth, gLineTextureHeight, 0,
- GL_ALPHA, GL_UNSIGNED_BYTE, gLineTexture);
- }
-
- ~Line() {
- delete mPatch;
- delete[] mXDivs;
- delete[] mYDivs;
-
- glDeleteTextures(1, &mTexture);
- }
-
- inline float getLength(float x1, float y1, float x2, float y2) {
- return sqrtf((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
- }
-
- void update(float x1, float y1, float x2, float y2, float lineWidth, float& tx, float& ty) {
- const float length = getLength(x1, y1, x2, y2);
- const float half = lineWidth * 0.5f;
-
- mPatch->updateVertices(gLineTextureWidth, gLineTextureHeight,
- -gLineAABias, -half - gLineAABias, length + gLineAABias, half + gLineAABias);
-
- tx = -gLineAABias;
- ty = lineWidth <= 1.0f ? -gLineAABias : -half - gLineAABias;
- }
-
- inline GLuint getMeshBuffer() const {
- return mPatch->meshBuffer;
- }
-
- inline GLsizei getElementsCount() const {
- return mPatch->verticesCount;
- }
-
- inline GLuint getTexture() const {
- return mTexture;
- }
-
-private:
- uint32_t mXDivsCount;
- uint32_t mYDivsCount;
-
- int32_t* mXDivs;
- int32_t* mYDivs;
-
- Patch* mPatch;
-
- GLuint mTexture;
-}; // class Line
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_LINE_H
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 1a89ca0..b357973 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -30,6 +30,7 @@
#include "OpenGLRenderer.h"
#include "DisplayListRenderer.h"
+#include "Vector.h"
namespace android {
namespace uirenderer {
@@ -989,6 +990,12 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
// TODO: Should do quickReject for each line
if (mSnapshot->invisible) return;
+ const bool isAA = paint->isAntiAlias();
+ const float strokeWidth = paint->getStrokeWidth() * 0.5f;
+ // A stroke width of 0 has a special meaningin Skia:
+ // it draws an unscaled 1px wide line
+ const bool isHairLine = paint->getStrokeWidth() == 0.0f;
+
setupDraw();
int alpha;
@@ -1001,59 +1008,105 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f;
const GLfloat b = a * ((color ) & 0xFF) / 255.0f;
- const bool isAA = paint->isAntiAlias();
- if (isAA) {
- GLuint textureUnit = 0;
- glActiveTexture(gTextureUnits[textureUnit]);
- setupTextureAlpha8(mCaches.line.getTexture(), 0, 0, textureUnit, 0.0f, 0.0f, r, g, b, a,
- mode, false, true, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
- mCaches.line.getMeshBuffer());
- } else {
- setupColorRect(0.0f, 0.0f, 1.0f, 1.0f, r, g, b, a, mode, false, true);
+ // Used only with AA lines
+ GLuint textureUnit = 0;
+
+ // Describe the required shaders
+ ProgramDescription description;
+ const bool setColor = description.setColor(r, g, b, a);
+
+ if (mShader) {
+ mShader->describe(description, mCaches.extensions);
+ }
+ if (mColorFilter) {
+ mColorFilter->describe(description, mCaches.extensions);
}
- const float strokeWidth = paint->getStrokeWidth();
- const GLsizei elementsCount = isAA ? mCaches.line.getElementsCount() : gMeshCount;
- const GLenum drawMode = isAA ? GL_TRIANGLES : GL_TRIANGLE_STRIP;
+ // Setup the blending mode
+ chooseBlending(a < 1.0f || (mShader && mShader->blend()), mode, description);
- for (int i = 0; i < count; i += 4) {
- float tx = 0.0f;
- float ty = 0.0f;
+ // We're not drawing with VBOs here
+ mCaches.unbindMeshBuffer();
- if (isAA) {
- mCaches.line.update(points[i], points[i + 1], points[i + 2], points[i + 3],
- strokeWidth, tx, ty);
- } else {
- ty = strokeWidth <= 1.0f ? 0.0f : -strokeWidth * 0.5f;
- }
+ int verticesCount = count >> 2;
+ if (!isHairLine) {
+ // TODO: AA needs more vertices
+ verticesCount *= 6;
+ } else {
+ // TODO: AA will be different
+ verticesCount *= 2;
+ }
- const float dx = points[i + 2] - points[i];
- const float dy = points[i + 3] - points[i + 1];
- const float mag = sqrtf(dx * dx + dy * dy);
- const float angle = acos(dx / mag);
+ TextureVertex lines[verticesCount];
+ TextureVertex* vertex = &lines[0];
- mModelView.loadTranslate(points[i], points[i + 1], 0.0f);
- if (angle > MIN_ANGLE || angle < -MIN_ANGLE) {
- mModelView.rotate(angle * RAD_TO_DEG, 0.0f, 0.0f, 1.0f);
- }
- mModelView.translate(tx, ty, 0.0f);
- if (!isAA) {
- float length = mCaches.line.getLength(points[i], points[i + 1],
- points[i + 2], points[i + 3]);
- mModelView.scale(length, strokeWidth, 1.0f);
- }
- mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
- // TODO: Add bounds to the layer's region
+ glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
+ gMeshStride, vertex);
- if (mShader) {
- mShader->updateTransforms(mCaches.currentProgram, mModelView, *mSnapshot);
- }
+ mModelView.loadIdentity();
- glDrawArrays(drawMode, 0, elementsCount);
+ // Build and use the appropriate shader
+ useProgram(mCaches.programCache.get(description));
+ mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
+
+ if (!mShader || (mShader && setColor)) {
+ mCaches.currentProgram->setColor(r, g, b, a);
}
- if (isAA) {
- glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
+ if (mShader) {
+ mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit);
+ }
+ if (mColorFilter) {
+ mColorFilter->setupProgram(mCaches.currentProgram);
+ }
+
+ if (!isHairLine) {
+ // TODO: Handle the AA case
+ for (int i = 0; i < count; i += 4) {
+ // a = start point, b = end point
+ vec2 a(points[i], points[i + 1]);
+ vec2 b(points[i + 2], points[i + 3]);
+
+ // Bias to snap to the same pixels as Skia
+ a += 0.375;
+ b += 0.375;
+
+ // Find the normal to the line
+ vec2 n = (b - a).copyNormalized() * strokeWidth;
+ float x = n.x;
+ n.x = -n.y;
+ n.y = x;
+
+ // Four corners of the rectangle defining a thick line
+ vec2 p1 = a - n;
+ vec2 p2 = a + n;
+ vec2 p3 = b + n;
+ vec2 p4 = b - n;
+
+ // Draw the line as 2 triangles, could be optimized
+ // by using only 4 vertices and the correct indices
+ // Also we should probably used non textured vertices
+ // when line AA is disabled to save on bandwidth
+ TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f);
+ TextureVertex::set(vertex++, p2.x, p2.y, 0.0f, 0.0f);
+ TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f);
+ TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f);
+ TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f);
+ TextureVertex::set(vertex++, p4.x, p4.y, 0.0f, 0.0f);
+
+ // TODO: Mark the dirty regions when RENDER_LAYERS_AS_REGIONS is set
+ }
+
+ // GL_LINE does not give the result we want to match Skia
+ glDrawArrays(GL_TRIANGLES, 0, verticesCount);
+ } else {
+ // TODO: Handle the AA case
+ for (int i = 0; i < count; i += 4) {
+ TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f);
+ TextureVertex::set(vertex++, points[i + 2], points[i + 3], 0.0f, 0.0f);
+ }
+ glLineWidth(1.0f);
+ glDrawArrays(GL_LINES, 0, verticesCount);
}
}
diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h
new file mode 100644
index 0000000..46dded5
--- /dev/null
+++ b/libs/hwui/Vector.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_VECTOR_H
+#define ANDROID_HWUI_VECTOR_H
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes
+///////////////////////////////////////////////////////////////////////////////
+
+struct Vector2 {
+ float x;
+ float y;
+
+ Vector2() :
+ x(0.0f), y(0.0f) {
+ }
+
+ Vector2(float px, float py) :
+ x(px), y(py) {
+ }
+
+ float length() const {
+ return sqrt(x * x + y * y);
+ }
+
+ void operator+=(const Vector2& v) {
+ x += v.x;
+ y += v.y;
+ }
+
+ void operator-=(const Vector2& v) {
+ x -= v.x;
+ y -= v.y;
+ }
+
+ void operator+=(const float v) {
+ x += v;
+ y += v;
+ }
+
+ void operator-=(const float v) {
+ x -= v;
+ y -= v;
+ }
+
+ void operator/=(float s) {
+ x /= s;
+ y /= s;
+ }
+
+ void operator*=(float s) {
+ x *= s;
+ y *= s;
+ }
+
+ Vector2 operator+(const Vector2& v) const {
+ return Vector2(x + v.x, y + v.y);
+ }
+
+ Vector2 operator-(const Vector2& v) const {
+ return Vector2(x - v.x, y - v.y);
+ }
+
+ Vector2 operator/(float s) const {
+ return Vector2(x / s, y / s);
+ }
+
+ Vector2 operator*(float s) const {
+ return Vector2(x * s, y * s);
+ }
+
+ void normalize() {
+ float s = 1.0f / length();
+ x *= s;
+ y *= s;
+ }
+
+ Vector2 copyNormalized() const {
+ Vector2 v(x, y);
+ v.normalize();
+ return v;
+ }
+
+ float dot(const Vector2& v) const {
+ return x * v.x + y * v.y;
+ }
+
+ void dump() {
+ LOGD("Vector2[%.2f, %.2f]", x, y);
+ }
+}; // class Vector2
+
+///////////////////////////////////////////////////////////////////////////////
+// Types
+///////////////////////////////////////////////////////////////////////////////
+
+typedef Vector2 vec2;
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_VECTOR_H
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 7f3a968..7fa71a9 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -261,8 +261,7 @@
<activity
android:name="LinesActivity"
- android:label="_Lines"
- android:hardwareAccelerated="true">
+ android:label="_Lines">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
index 0dc836d..6afbb01 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
@@ -36,6 +36,8 @@ public class LinesActivity extends Activity {
}
static class LinesView extends View {
+ private static final boolean LINE_AA = false;
+
private final Bitmap mBitmap1;
private final Paint mSmallPaint;
private final Paint mMediumPaint;
@@ -43,6 +45,7 @@ public class LinesActivity extends Activity {
private final BitmapShader mShader;
private final float[] mPoints;
private final Paint mAlphaPaint;
+ private final Paint mHairLinePaint;
LinesView(Context c) {
super(c);
@@ -50,25 +53,30 @@ public class LinesActivity extends Activity {
mBitmap1 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
mSmallPaint = new Paint();
- mSmallPaint.setAntiAlias(true);
+ mSmallPaint.setAntiAlias(LINE_AA);
mSmallPaint.setColor(0xffff0000);
mSmallPaint.setStrokeWidth(1.0f);
mMediumPaint = new Paint();
- mMediumPaint.setAntiAlias(true);
+ mMediumPaint.setAntiAlias(LINE_AA);
mMediumPaint.setColor(0xff0000ff);
mMediumPaint.setStrokeWidth(4.0f);
mLargePaint = new Paint();
- mLargePaint.setAntiAlias(true);
+ mLargePaint.setAntiAlias(LINE_AA);
mLargePaint.setColor(0xff00ff00);
mLargePaint.setStrokeWidth(15.0f);
mAlphaPaint = new Paint();
- mAlphaPaint.setAntiAlias(true);
+ mAlphaPaint.setAntiAlias(LINE_AA);
mAlphaPaint.setColor(0x7fff0050);
mAlphaPaint.setStrokeWidth(10.0f);
+ mHairLinePaint = new Paint();
+ mHairLinePaint.setAntiAlias(LINE_AA);
+ mHairLinePaint.setColor(0xff0000ff);
+ mHairLinePaint.setStrokeWidth(0.0f);
+
mShader = new BitmapShader(mBitmap1, BitmapShader.TileMode.MIRROR,
BitmapShader.TileMode.MIRROR);
@@ -100,7 +108,7 @@ public class LinesActivity extends Activity {
mSmallPaint.setAntiAlias(false);
canvas.drawLine(0.0f, 0.0f, 400.0f, 0.0f, mSmallPaint);
- mSmallPaint.setAntiAlias(true);
+ mSmallPaint.setAntiAlias(LINE_AA);
canvas.drawLine(0.0f, 0.0f, 0.0f, 400.0f, mSmallPaint);
canvas.drawLine(0.0f, 400.0f, 400.0f, 400.0f, mSmallPaint);
@@ -110,6 +118,12 @@ public class LinesActivity extends Activity {
mAlphaPaint.setShader(null);
canvas.restore();
+
+ 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);
+ canvas.drawLine(10.0f, 60.0f, 50.0f, 60.0f, mHairLinePaint);
+ canvas.restore();
}
}
}