Tessellate on worker threads
Tessellate and cache (where possible) shadow and round rect
tessellation tasks.
Change-Id: I2cfda8e11d83d51ea74af871235cf26e8f831d40
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 4ef2158..c9921ba3 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -57,15 +57,17 @@
#define ROUND_CAP_THRESH 0.25f
#define PI 3.1415926535897932f
-/**
- * Note: this function doesn't account for the AA case with sub-pixel line thickness (not just 0 <
- * width < 1.0, canvas scale factors in as well) so this can't be used for points/lines
- */
-void PathTessellator::expandBoundsForStroke(SkRect& bounds, const SkPaint* paint) {
- if (paint->getStyle() != SkPaint::kFill_Style) {
- float outset = paint->getStrokeWidth() * 0.5f;
- if (outset == 0) outset = 0.5f; // account for hairline
- bounds.outset(outset, outset);
+void PathTessellator::extractTessellationScales(const Matrix4& transform,
+ float* scaleX, float* scaleY) {
+ *scaleX = 1.0f;
+ *scaleY = 1.0f;
+ if (CC_UNLIKELY(!transform.isPureTranslate())) {
+ float m00 = transform.data[Matrix4::kScaleX];
+ float m01 = transform.data[Matrix4::kSkewY];
+ float m10 = transform.data[Matrix4::kSkewX];
+ float m11 = transform.data[Matrix4::kScaleY];
+ *scaleX = sqrt(m00 * m00 + m01 * m01);
+ *scaleY = sqrt(m10 * m10 + m11 * m11);
}
}
@@ -94,18 +96,15 @@
halfStrokeWidth(paint->getStrokeWidth() * 0.5f), maxAlpha(1.0f) {
// compute inverse scales
if (CC_UNLIKELY(!transform.isPureTranslate())) {
- float m00 = transform.data[Matrix4::kScaleX];
- float m01 = transform.data[Matrix4::kSkewY];
- float m10 = transform.data[Matrix4::kSkewX];
- float m11 = transform.data[Matrix4::kScaleY];
- float scaleX = sqrt(m00 * m00 + m01 * m01);
- float scaleY = sqrt(m10 * m10 + m11 * m11);
+ float scaleX, scaleY;
+ PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY);
inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 1.0f;
inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 1.0f;
}
if (isAA && halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
2 * halfStrokeWidth < inverseScaleX) {
+ // AA, with non-hairline stroke, width < 1 pixel. Scale alpha and treat as hairline.
maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
halfStrokeWidth = 0.0f;
}
@@ -159,10 +158,10 @@
* Outset the bounds of point data (for line endpoints or points) to account for AA stroke
* geometry.
*/
- void expandBoundsForStrokeAA(SkRect& bounds) const {
+ void expandBoundsForStroke(Rect* bounds) const {
float outset = halfStrokeWidth;
if (outset == 0) outset = 0.5f;
- bounds.outset(outset * inverseScaleX + Vertex::GeometryFudgeFactor(),
+ bounds->outset(outset * inverseScaleX + Vertex::GeometryFudgeFactor(),
outset * inverseScaleY + Vertex::GeometryFudgeFactor());
}
};
@@ -778,21 +777,25 @@
getFillVerticesFromPerimeterAA(paintInfo, tempVertices, vertexBuffer);
}
}
+
+ Rect bounds(path.getBounds());
+ paintInfo.expandBoundsForStroke(&bounds);
+ vertexBuffer.setBounds(bounds);
}
-static void expandRectToCoverVertex(SkRect& rect, float x, float y) {
- rect.fLeft = fminf(rect.fLeft, x);
- rect.fTop = fminf(rect.fTop, y);
- rect.fRight = fmaxf(rect.fRight, x);
- rect.fBottom = fmaxf(rect.fBottom, y);
+static void expandRectToCoverVertex(Rect& rect, float x, float y) {
+ rect.left = fminf(rect.left, x);
+ rect.top = fminf(rect.top, y);
+ rect.right = fmaxf(rect.right, x);
+ rect.bottom = fmaxf(rect.bottom, y);
}
-static void expandRectToCoverVertex(SkRect& rect, const Vertex& vertex) {
+static void expandRectToCoverVertex(Rect& rect, const Vertex& vertex) {
expandRectToCoverVertex(rect, vertex.x, vertex.y);
}
template <class TYPE>
static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer,
- const float* points, int count, SkRect& bounds) {
+ const float* points, int count, Rect& bounds) {
bounds.set(points[0], points[1], points[0], points[1]);
int numPoints = count / 2;
@@ -807,7 +810,7 @@
}
void PathTessellator::tessellatePoints(const float* points, int count, const SkPaint* paint,
- const mat4& transform, SkRect& bounds, VertexBuffer& vertexBuffer) {
+ const mat4& transform, VertexBuffer& vertexBuffer) {
const PaintInfo paintInfo(paint, transform);
// determine point shape
@@ -830,6 +833,7 @@
if (!outlineVertices.size()) return;
+ Rect bounds;
// tessellate, then duplicate outline across points
int numPoints = count / 2;
VertexBuffer tempBuffer;
@@ -843,12 +847,12 @@
}
// expand bounds from vertex coords to pixel data
- paintInfo.expandBoundsForStrokeAA(bounds);
-
+ paintInfo.expandBoundsForStroke(&bounds);
+ vertexBuffer.setBounds(bounds);
}
void PathTessellator::tessellateLines(const float* points, int count, const SkPaint* paint,
- const mat4& transform, SkRect& bounds, VertexBuffer& vertexBuffer) {
+ const mat4& transform, VertexBuffer& vertexBuffer) {
ATRACE_CALL();
const PaintInfo paintInfo(paint, transform);
@@ -868,6 +872,7 @@
tempVertices.push();
tempVertices.push();
Vertex* tempVerticesData = tempVertices.editArray();
+ Rect bounds;
bounds.set(points[0], points[1], points[0], points[1]);
for (int i = 0; i < count; i += 4) {
Vertex::set(&(tempVerticesData[0]), points[i + 0], points[i + 1]);
@@ -892,7 +897,8 @@
}
// expand bounds from vertex coords to pixel data
- paintInfo.expandBoundsForStrokeAA(bounds);
+ paintInfo.expandBoundsForStroke(&bounds);
+ vertexBuffer.setBounds(bounds);
}
///////////////////////////////////////////////////////////////////////////////