diff options
| -rw-r--r-- | libs/hwui/DisplayListOp.h | 4 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 31 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.h | 2 | ||||
| -rw-r--r-- | libs/hwui/PathTessellator.cpp | 38 | ||||
| -rw-r--r-- | libs/hwui/PathTessellator.h | 52 | ||||
| -rw-r--r-- | libs/hwui/ShadowTessellator.cpp | 55 | ||||
| -rw-r--r-- | libs/hwui/ShadowTessellator.h | 14 |
7 files changed, 110 insertions, 86 deletions
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index e3d4e2d21bd5..5024880889de 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -1589,7 +1589,9 @@ public: mWidth(width), mHeight(height) {} virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { - return renderer.drawShadow(mCasterTransform, mCasterAlpha, mWidth, mHeight); + SkPath casterOutline; // TODO: drive with path from view + casterOutline.addRect(0, 0, mWidth, mHeight); + return renderer.drawShadow(mCasterTransform, mCasterAlpha, &casterOutline); } virtual void output(int level, uint32_t logFlags) const { diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 741e953e3eba..41f34e5e4eb8 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -3185,28 +3185,43 @@ status_t OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* } status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlpha, - float width, float height) { + const SkPath* casterOutline) { if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone; - // For now, always and scissor - // TODO: use quickReject + // TODO: use quickRejectWithScissor. For now, always force enable scissor. mCaches.enableScissor(); SkPaint paint; - paint.setColor(mCaches.propertyShadowStrength << 24); + paint.setARGB(mCaches.propertyShadowStrength, 0, 0, 0); paint.setAntiAlias(true); // want to use AlphaVertex + // tessellate caster outline into a 2d polygon + Vector<Vertex> casterVertices2d; + const float casterRefinementThresholdSquared = 20.0f; // TODO: experiment with this value + PathTessellator::approximatePathOutlineVertices(*casterOutline, + casterRefinementThresholdSquared, casterVertices2d); + + // map 2d caster poly into 3d + const int casterVertexCount = casterVertices2d.size(); + Vector3 casterPolygon[casterVertexCount]; + for (int i = 0; i < casterVertexCount; i++) { + const Vertex& point2d = casterVertices2d[i]; + casterPolygon[i] = Vector3(point2d.x, point2d.y, 0); + casterTransform.mapPoint3d(casterPolygon[i]); + } + + // draw caster's shadows VertexBuffer ambientShadowVertexBuffer; - ShadowTessellator::tessellateAmbientShadow(width, height, casterTransform, + ShadowTessellator::tessellateAmbientShadow(casterPolygon, casterVertexCount, ambientShadowVertexBuffer); drawVertexBuffer(ambientShadowVertexBuffer, &paint); VertexBuffer spotShadowVertexBuffer; Vector3 lightPosScale(mCaches.propertyLightPosXScale, mCaches.propertyLightPosYScale, mCaches.propertyLightPosZScale); - ShadowTessellator::tessellateSpotShadow(width, height, lightPosScale, - *currentTransform(), getWidth(), getHeight(), - casterTransform, spotShadowVertexBuffer); + ShadowTessellator::tessellateSpotShadow(casterPolygon, casterVertexCount, + lightPosScale, *currentTransform(), getWidth(), getHeight(), + spotShadowVertexBuffer); drawVertexBuffer(spotShadowVertexBuffer, &paint); diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index fb780ce72dbd..806e80573e47 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -214,7 +214,7 @@ public: virtual status_t drawRects(const float* rects, int count, const SkPaint* paint); status_t drawShadow(const mat4& casterTransform, float casterAlpha, - float width, float height); + const SkPath* casterOutline); virtual void resetShader(); virtual void setupShader(SkiaShader* shader); diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp index c6ce67cd1c9b..cc56333f3081 100644 --- a/libs/hwui/PathTessellator.cpp +++ b/libs/hwui/PathTessellator.cpp @@ -53,7 +53,7 @@ namespace android { namespace uirenderer { -#define THRESHOLD 0.5f +#define OUTLINE_REFINE_THRESHOLD_SQUARED (0.5f * 0.5f) #define ROUND_CAP_THRESH 0.25f #define PI 3.1415926535897932f @@ -739,7 +739,8 @@ void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint, // force close if we're filling the path, since fill path expects closed perimeter. bool forceClose = paintInfo.style != SkPaint::kStroke_Style; bool wasClosed = approximatePathOutlineVertices(path, forceClose, - threshInvScaleX * threshInvScaleX, threshInvScaleY * threshInvScaleY, tempVertices); + threshInvScaleX * threshInvScaleX, threshInvScaleY * threshInvScaleY, + OUTLINE_REFINE_THRESHOLD_SQUARED, tempVertices); if (!tempVertices.size()) { // path was empty, return without allocating vertex buffer @@ -824,7 +825,8 @@ void PathTessellator::tessellatePoints(const float* points, int count, const SkP Vector<Vertex> outlineVertices; approximatePathOutlineVertices(path, true, paintInfo.inverseScaleX * paintInfo.inverseScaleX, - paintInfo.inverseScaleY * paintInfo.inverseScaleY, outlineVertices); + paintInfo.inverseScaleY * paintInfo.inverseScaleY, + OUTLINE_REFINE_THRESHOLD_SQUARED, outlineVertices); if (!outlineVertices.size()) return; @@ -897,6 +899,11 @@ void PathTessellator::tessellateLines(const float* points, int count, const SkPa // Simple path line approximation /////////////////////////////////////////////////////////////////////////////// +bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, float thresholdSquared, + Vector<Vertex>& outputVertices) { + return approximatePathOutlineVertices(path, true, 1.0f, 1.0f, thresholdSquared, outputVertices); +} + void pushToVector(Vector<Vertex>& vertices, float x, float y) { // TODO: make this not yuck vertices.push(); @@ -905,7 +912,8 @@ void pushToVector(Vector<Vertex>& vertices, float x, float y) { } bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool forceClose, - float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex>& outputVertices) { + float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared, + Vector<Vertex>& outputVertices) { ATRACE_CALL(); // TODO: to support joins other than sharp miter, join vertices should be labelled in the @@ -932,7 +940,7 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo pts[0].x(), pts[0].y(), pts[2].x(), pts[2].y(), pts[1].x(), pts[1].y(), - sqrInvScaleX, sqrInvScaleY, outputVertices); + sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices); break; case SkPath::kCubic_Verb: ALOGV("kCubic_Verb"); @@ -941,7 +949,7 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo pts[1].x(), pts[1].y(), pts[3].x(), pts[3].y(), pts[2].x(), pts[2].y(), - sqrInvScaleX, sqrInvScaleY, outputVertices); + sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices); break; default: break; @@ -964,7 +972,8 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo void PathTessellator::recursiveCubicBezierVertices( float p1x, float p1y, float c1x, float c1y, float p2x, float p2y, float c2x, float c2y, - float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex>& outputVertices) { + float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared, + Vector<Vertex>& outputVertices) { float dx = p2x - p1x; float dy = p2y - p1y; float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx); @@ -973,7 +982,7 @@ void PathTessellator::recursiveCubicBezierVertices( // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors - if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) { + if (d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) { // below thresh, draw line by adding endpoint pushToVector(outputVertices, p2x, p2y); } else { @@ -997,11 +1006,11 @@ void PathTessellator::recursiveCubicBezierVertices( recursiveCubicBezierVertices( p1x, p1y, p1c1x, p1c1y, mx, my, p1c1c2x, p1c1c2y, - sqrInvScaleX, sqrInvScaleY, outputVertices); + sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices); recursiveCubicBezierVertices( mx, my, p2c1c2x, p2c1c2y, p2x, p2y, p2c2x, p2c2y, - sqrInvScaleX, sqrInvScaleY, outputVertices); + sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices); } } @@ -1009,12 +1018,13 @@ void PathTessellator::recursiveQuadraticBezierVertices( float ax, float ay, float bx, float by, float cx, float cy, - float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex>& outputVertices) { + float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared, + Vector<Vertex>& outputVertices) { float dx = bx - ax; float dy = by - ay; float d = (cx - bx) * dy - (cy - by) * dx; - if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) { + if (d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) { // below thresh, draw line by adding endpoint pushToVector(outputVertices, bx, by); } else { @@ -1028,9 +1038,9 @@ void PathTessellator::recursiveQuadraticBezierVertices( float my = (acy + bcy) * 0.5f; recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy, - sqrInvScaleX, sqrInvScaleY, outputVertices); + sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices); recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy, - sqrInvScaleX, sqrInvScaleY, outputVertices); + sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices); } } diff --git a/libs/hwui/PathTessellator.h b/libs/hwui/PathTessellator.h index e43b10133b99..a215b7a85d12 100644 --- a/libs/hwui/PathTessellator.h +++ b/libs/hwui/PathTessellator.h @@ -31,18 +31,64 @@ class PathTessellator { public: static void expandBoundsForStroke(SkRect& bounds, const SkPaint* paint); + /** + * Populates a VertexBuffer with a tessellated approximation of the input convex path, as a single + * triangle strip. Note: joins are not currently supported. + * + * @param path The path to be approximated + * @param paint The paint the path will be drawn with, indicating AA, painting style + * (stroke vs fill), stroke width, stroke cap & join style, etc. + * @param transform The transform the path is to be drawn with, used to drive stretch-aware path + * vertex approximation, and correct AA ramp offsetting. + * @param vertexBuffer The output buffer + */ static void tessellatePath(const SkPath& path, const SkPaint* paint, const mat4& transform, VertexBuffer& vertexBuffer); + /** + * Populates a VertexBuffer with a tessellated approximation of points as a single triangle + * strip (with degenerate tris separating), respecting the shape defined by the paint cap. + * + * @param points The center vertices of the points to be drawn + * @param count The number of floats making up the point vertices + * @param paint The paint the points will be drawn with indicating AA, stroke width & cap + * @param transform The transform the points will be drawn with, used to drive stretch-aware path + * vertex approximation, and correct AA ramp offsetting + * @param bounds An output rectangle, which returns the total area covered by the output buffer + * @param vertexBuffer The output buffer + */ static void tessellatePoints(const float* points, int count, const SkPaint* paint, const mat4& transform, SkRect& bounds, VertexBuffer& vertexBuffer); + /** + * Populates a VertexBuffer with a tessellated approximation of lines as a single triangle + * strip (with degenerate tris separating). + * + * @param points Pairs of endpoints defining the lines to be drawn + * @param count The number of floats making up the line vertices + * @param paint The paint the lines will be drawn with indicating AA, stroke width & cap + * @param transform The transform the points will be drawn with, used to drive stretch-aware path + * vertex approximation, and correct AA ramp offsetting + * @param bounds An output rectangle, which returns the total area covered by the output buffer + * @param vertexBuffer The output buffer + */ static void tessellateLines(const float* points, int count, const SkPaint* paint, const mat4& transform, SkRect& bounds, VertexBuffer& vertexBuffer); + /** + * Approximates a convex, CW outline into a Vector of 2d vertices. + * + * @param path The outline to be approximated + * @param thresholdSquared The threshold of acceptable error (in pixels) when approximating + * @param outputVertices An empty Vector which will be populated with the output + */ + static bool approximatePathOutlineVertices(const SkPath &path, float thresholdSquared, + Vector<Vertex> &outputVertices); + private: static bool approximatePathOutlineVertices(const SkPath &path, bool forceClose, - float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex> &outputVertices); + float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared, + Vector<Vertex> &outputVertices); /* endpoints a & b, @@ -52,7 +98,7 @@ private: float ax, float ay, float bx, float by, float cx, float cy, - float sqrInvScaleX, float sqrInvScaleY, + float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared, Vector<Vertex> &outputVertices); /* @@ -64,7 +110,7 @@ private: float c1x, float c1y, float p2x, float p2y, float c2x, float c2y, - float sqrInvScaleX, float sqrInvScaleY, + float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared, Vector<Vertex> &outputVertices); }; diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp index 6dfd9255b612..7700ea0c6ad5 100644 --- a/libs/hwui/ShadowTessellator.cpp +++ b/libs/hwui/ShadowTessellator.cpp @@ -31,46 +31,8 @@ static inline T max(T a, T b) { return a > b ? a : b; } -// TODO: Support path as the input of the polygon instead of the rect's width -// and height. And the z values need to be computed according to the -// transformation for each vertex. -/** - * Generate the polygon for the caster. - * - * @param width the width of the caster - * @param height the height of the caster - * @param casterTransform transformation info of the caster - * @param polygon return the caster's polygon - * - */ -void ShadowTessellator::generateCasterPolygon(float width, float height, - const mat4& casterTransform, int vertexCount, Vector3* polygon) { - Rect blockRect(0, 0, width, height); - polygon[0].x = blockRect.left; - polygon[0].y = blockRect.top; - polygon[0].z = 0; - polygon[1].x = blockRect.right; - polygon[1].y = blockRect.top; - polygon[1].z = 0; - polygon[2].x = blockRect.right; - polygon[2].y = blockRect.bottom; - polygon[2].z = 0; - polygon[3].x = blockRect.left; - polygon[3].y = blockRect.bottom; - polygon[3].z = 0; - casterTransform.mapPoint3d(polygon[0]); - casterTransform.mapPoint3d(polygon[1]); - casterTransform.mapPoint3d(polygon[2]); - casterTransform.mapPoint3d(polygon[3]); -} - -void ShadowTessellator::tessellateAmbientShadow(float width, float height, - const mat4& casterTransform, VertexBuffer& shadowVertexBuffer) { - - const int vertexCount = 4; - Vector3 polygon[vertexCount]; - generateCasterPolygon(width, height, casterTransform, vertexCount, polygon); - +void ShadowTessellator::tessellateAmbientShadow(const Vector3* casterPolygon, int casterVertexCount, + VertexBuffer& shadowVertexBuffer) { // A bunch of parameters to tweak the shadow. // TODO: Allow some of these changable by debug settings or APIs. const int rays = 128; @@ -79,19 +41,14 @@ void ShadowTessellator::tessellateAmbientShadow(float width, float height, const float heightFactor = 128; const float geomFactor = 64; - AmbientShadow::createAmbientShadow(polygon, vertexCount, rays, layers, strength, + AmbientShadow::createAmbientShadow(casterPolygon, casterVertexCount, rays, layers, strength, heightFactor, geomFactor, shadowVertexBuffer); } -void ShadowTessellator::tessellateSpotShadow(float width, float height, +void ShadowTessellator::tessellateSpotShadow(const Vector3* casterPolygon, int casterVertexCount, const Vector3& lightPosScale, const mat4& receiverTransform, - int screenWidth, int screenHeight, const mat4& casterTransform, - VertexBuffer& shadowVertexBuffer) { - const int vertexCount = 4; - Vector3 polygon[vertexCount]; - generateCasterPolygon(width, height, casterTransform, vertexCount, polygon); - + int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer) { // A bunch of parameters to tweak the shadow. // TODO: Allow some of these changable by debug settings or APIs. const int rays = 256; @@ -113,7 +70,7 @@ void ShadowTessellator::tessellateSpotShadow(float width, float height, const float lightSize = maximal / 4; const int lightVertexCount = 16; - SpotShadow::createSpotShadow(polygon, vertexCount, lightCenter, lightSize, + SpotShadow::createSpotShadow(casterPolygon, casterVertexCount, lightCenter, lightSize, lightVertexCount, rays, layers, strength, shadowVertexBuffer); } diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h index 2399f8fe503c..ef9560939f18 100644 --- a/libs/hwui/ShadowTessellator.h +++ b/libs/hwui/ShadowTessellator.h @@ -26,18 +26,12 @@ namespace uirenderer { class ShadowTessellator { public: - static void tessellateAmbientShadow(float width, float height, - const mat4& casterTransform, VertexBuffer& shadowVertexBuffer); - - static void tessellateSpotShadow(float width, float height, - const Vector3& lightPosScale, const mat4& receiverTransform, - int screenWidth, int screenHeight, const mat4& casterTransform, + static void tessellateAmbientShadow(const Vector3* casterPolygon, int casterVertexCount, VertexBuffer& shadowVertexBuffer); -private: - static void generateCasterPolygon(float width, float height, - const mat4& casterTransform, int vertexCount, Vector3* polygon); - + static void tessellateSpotShadow(const Vector3* casterPolygon, int casterVertexCount, + const Vector3& lightPosScale, const mat4& receiverTransform, + int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer); }; // ShadowTessellator }; // namespace uirenderer |