Loading libs/hwui/DisplayListOp.h +2 −2 Original line number Diff line number Diff line Loading @@ -1118,8 +1118,8 @@ public: const DeferredDisplayState& state) { DrawStrokableOp::onDefer(renderer, deferInfo, state); if (!mPaint->getPathEffect()) { renderer.getCaches().tessellationCache.precacheRoundRect(state.mMatrix, mLocalBounds.getWidth(), mLocalBounds.getHeight(), mRx, mRy, mPaint); renderer.getCaches().tessellationCache.precacheRoundRect(state.mMatrix, *mPaint, mLocalBounds.getWidth(), mLocalBounds.getHeight(), mRx, mRy); } } Loading libs/hwui/DisplayListRenderer.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -308,6 +308,10 @@ status_t DisplayListRenderer::drawOval(float left, float top, float right, float status_t DisplayListRenderer::drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) { if (fabs(sweepAngle) > 360.0f) { return drawOval(left, top, right, bottom, paint); } paint = refPaint(paint); addDrawOp(new (alloc()) DrawArcOp(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint)); Loading libs/hwui/OpenGLRenderer.cpp +2 −6 Original line number Diff line number Diff line Loading @@ -2556,8 +2556,8 @@ status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float return drawShape(left, top, texture, p); } const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(*currentTransform(), right - left, bottom - top, rx, ry, p); const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect( *currentTransform(), *p, right - left, bottom - top, rx, ry); return drawVertexBuffer(left, top, *vertexBuffer, p); } Loading Loading @@ -2611,10 +2611,6 @@ status_t OpenGLRenderer::drawArc(float left, float top, float right, float botto return DrawGlInfo::kStatusDone; } if (fabs(sweepAngle) >= 360.0f) { return drawOval(left, top, right, bottom, p); } // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180) if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || useCenter) { mCaches.activeTexture(0); Loading libs/hwui/TessellationCache.cpp +54 −58 Original line number Diff line number Diff line Loading @@ -39,6 +39,8 @@ namespace uirenderer { TessellationCache::Description::Description() : type(kNone) , scaleX(1.0f) , scaleY(1.0f) , aa(false) , cap(SkPaint::kDefault_Cap) , style(SkPaint::kFill_Style) Loading @@ -46,21 +48,13 @@ TessellationCache::Description::Description() memset(&shape, 0, sizeof(Shape)); } TessellationCache::Description::Description(Type type) TessellationCache::Description::Description(Type type, const Matrix4& transform, const SkPaint& paint) : type(type) , aa(false) , cap(SkPaint::kDefault_Cap) , style(SkPaint::kFill_Style) , strokeWidth(1.0f) { memset(&shape, 0, sizeof(Shape)); } TessellationCache::Description::Description(Type type, const SkPaint* paint) : type(type) , aa(paint->isAntiAlias()) , cap(paint->getStrokeCap()) , style(paint->getStyle()) , strokeWidth(paint->getStrokeWidth()) { , aa(paint.isAntiAlias()) , cap(paint.getStrokeCap()) , style(paint.getStyle()) , strokeWidth(paint.getStrokeWidth()) { PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY); memset(&shape, 0, sizeof(Shape)); } Loading @@ -70,10 +64,20 @@ hash_t TessellationCache::Description::hash() const { hash = JenkinsHashMix(hash, cap); hash = JenkinsHashMix(hash, style); hash = JenkinsHashMix(hash, android::hash_type(strokeWidth)); hash = JenkinsHashMix(hash, android::hash_type(scaleX)); hash = JenkinsHashMix(hash, android::hash_type(scaleY)); hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape)); return JenkinsHashWhiten(hash); } void TessellationCache::Description::setupMatrixAndPaint(Matrix4* matrix, SkPaint* paint) const { matrix->loadScale(scaleX, scaleY, 1.0f); paint->setAntiAlias(aa); paint->setStrokeCap(cap); paint->setStyle(style); paint->setStrokeWidth(strokeWidth); } TessellationCache::ShadowDescription::ShadowDescription() : nodeKey(NULL) { memset(&matrixData, 0, 16 * sizeof(float)); Loading @@ -96,20 +100,15 @@ hash_t TessellationCache::ShadowDescription::hash() const { class TessellationCache::TessellationTask : public Task<VertexBuffer*> { public: TessellationTask(Tessellator tessellator, const Description& description, const SkPaint* paint) TessellationTask(Tessellator tessellator, const Description& description) : tessellator(tessellator) , description(description) , paint(*paint) { , description(description) { } ~TessellationTask() {} Tessellator tessellator; Description description; //copied, since input paint may not be immutable const SkPaint paint; }; class TessellationCache::TessellationProcessor : public TaskProcessor<VertexBuffer*> { Loading @@ -121,7 +120,7 @@ public: virtual void onProcess(const sp<Task<VertexBuffer*> >& task) { TessellationTask* t = static_cast<TessellationTask*>(task.get()); ATRACE_NAME("shape tessellation"); VertexBuffer* buffer = t->tessellator(t->description, t->paint); VertexBuffer* buffer = t->tessellator(t->description); t->setResult(buffer); } }; Loading Loading @@ -416,21 +415,12 @@ void TessellationCache::getShadowBuffers(const Matrix4* drawTransform, const Rec // Tessellation precaching /////////////////////////////////////////////////////////////////////////////// static VertexBuffer* tessellatePath(const SkPath& path, const SkPaint* paint, float scaleX, float scaleY) { VertexBuffer* buffer = new VertexBuffer(); Matrix4 matrix; matrix.loadScale(scaleX, scaleY, 1); PathTessellator::tessellatePath(path, paint, matrix, *buffer); return buffer; } TessellationCache::Buffer* TessellationCache::getOrCreateBuffer( const Description& entry, Tessellator tessellator, const SkPaint* paint) { const Description& entry, Tessellator tessellator) { Buffer* buffer = mCache.get(entry); if (!buffer) { // not cached, enqueue a task to fill the buffer sp<TessellationTask> task = new TessellationTask(tessellator, entry, paint); sp<TessellationTask> task = new TessellationTask(tessellator, entry); buffer = new Buffer(task); if (mProcessor == NULL) { Loading @@ -442,43 +432,49 @@ TessellationCache::Buffer* TessellationCache::getOrCreateBuffer( return buffer; } static VertexBuffer* tessellatePath(const TessellationCache::Description& description, const SkPath& path) { Matrix4 matrix; SkPaint paint; description.setupMatrixAndPaint(&matrix, &paint); VertexBuffer* buffer = new VertexBuffer(); PathTessellator::tessellatePath(path, &paint, matrix, *buffer); return buffer; } /////////////////////////////////////////////////////////////////////////////// // Rounded rects // RoundRect /////////////////////////////////////////////////////////////////////////////// static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& description, const SkPaint& paint) { SkRect rect = SkRect::MakeWH(description.shape.roundRect.mWidth, description.shape.roundRect.mHeight); float rx = description.shape.roundRect.mRx; float ry = description.shape.roundRect.mRy; if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) { float outset = paint.getStrokeWidth() / 2; static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& description) { SkRect rect = SkRect::MakeWH(description.shape.roundRect.width, description.shape.roundRect.height); float rx = description.shape.roundRect.rx; float ry = description.shape.roundRect.ry; if (description.style == SkPaint::kStrokeAndFill_Style) { float outset = description.strokeWidth / 2; rect.outset(outset, outset); rx += outset; ry += outset; } SkPath path; path.addRoundRect(rect, rx, ry); return tessellatePath(path, &paint, description.shape.roundRect.mScaleX, description.shape.roundRect.mScaleY); } TessellationCache::Buffer* TessellationCache::getRoundRectBuffer(const Matrix4& transform, float width, float height, float rx, float ry, const SkPaint* paint) { Description entry(Description::kRoundRect, paint); entry.shape.roundRect.mWidth = width; entry.shape.roundRect.mHeight = height; entry.shape.roundRect.mRx = rx; entry.shape.roundRect.mRy = ry; PathTessellator::extractTessellationScales(transform, &entry.shape.roundRect.mScaleX, &entry.shape.roundRect.mScaleY); return getOrCreateBuffer(entry, &tessellateRoundRect, paint); } const VertexBuffer* TessellationCache::getRoundRect(const Matrix4& transform, float width, float height, float rx, float ry, const SkPaint* paint) { return getRoundRectBuffer(transform, width, height, rx, ry, paint)->getVertexBuffer(); return tessellatePath(description, path); } TessellationCache::Buffer* TessellationCache::getRoundRectBuffer( const Matrix4& transform, const SkPaint& paint, float width, float height, float rx, float ry) { Description entry(Description::kRoundRect, transform, paint); entry.shape.roundRect.width = width; entry.shape.roundRect.height = height; entry.shape.roundRect.rx = rx; entry.shape.roundRect.ry = ry; return getOrCreateBuffer(entry, &tessellateRoundRect); } const VertexBuffer* TessellationCache::getRoundRect(const Matrix4& transform, const SkPaint& paint, float width, float height, float rx, float ry) { return getRoundRectBuffer(transform, paint, width, height, rx, ry)->getVertexBuffer(); } }; // namespace uirenderer Loading libs/hwui/TessellationCache.h +19 −21 Original line number Diff line number Diff line Loading @@ -50,30 +50,28 @@ public: enum Type { kNone, kRoundRect, kAmbientShadow, kSpotShadow }; Type type; float scaleX; float scaleY; bool aa; SkPaint::Cap cap; SkPaint::Style style; float strokeWidth; union Shape { struct RoundRect { float mScaleX; float mScaleY; float mWidth; float mHeight; float mRx; float mRy; float width; float height; float rx; float ry; } roundRect; } shape; Description(); Description(Type type); Description(Type type, const SkPaint* paint); Description(Type type, const Matrix4& transform, const SkPaint& paint); hash_t hash() const; void setupMatrixAndPaint(Matrix4* matrix, SkPaint* paint) const; }; struct ShadowDescription { Loading Loading @@ -123,12 +121,12 @@ public: // TODO: precache/get for Oval, Lines, Points, etc. void precacheRoundRect(const Matrix4& transform, float width, float height, float rx, float ry, const SkPaint* paint) { getRoundRectBuffer(transform, width, height, rx, ry, paint); void precacheRoundRect(const Matrix4& transform, const SkPaint& paint, float width, float height, float rx, float ry) { getRoundRectBuffer(transform, paint, width, height, rx, ry); } const VertexBuffer* getRoundRect(const Matrix4& transform, float width, float height, float rx, float ry, const SkPaint* paint); const VertexBuffer* getRoundRect(const Matrix4& transform, const SkPaint& paint, float width, float height, float rx, float ry); void precacheShadows(const Matrix4* drawTransform, const Rect& localClip, bool opaque, const SkPath* casterPerimeter, Loading @@ -146,14 +144,14 @@ private: class TessellationTask; class TessellationProcessor; typedef VertexBuffer* (*Tessellator)(const Description&); typedef VertexBuffer* (*Tessellator)(const Description&, const SkPaint&); Buffer* getRectBuffer(const Matrix4& transform, const SkPaint& paint, float width, float height); Buffer* getRoundRectBuffer(const Matrix4& transform, const SkPaint& paint, float width, float height, float rx, float ry); Buffer* getRoundRectBuffer(const Matrix4& transform, float width, float height, float rx, float ry, const SkPaint* paint); Buffer* getOrCreateBuffer(const Description& entry, Tessellator tessellator, const SkPaint* paint); Buffer* getOrCreateBuffer(const Description& entry, Tessellator tessellator); uint32_t mSize; uint32_t mMaxSize; Loading Loading
libs/hwui/DisplayListOp.h +2 −2 Original line number Diff line number Diff line Loading @@ -1118,8 +1118,8 @@ public: const DeferredDisplayState& state) { DrawStrokableOp::onDefer(renderer, deferInfo, state); if (!mPaint->getPathEffect()) { renderer.getCaches().tessellationCache.precacheRoundRect(state.mMatrix, mLocalBounds.getWidth(), mLocalBounds.getHeight(), mRx, mRy, mPaint); renderer.getCaches().tessellationCache.precacheRoundRect(state.mMatrix, *mPaint, mLocalBounds.getWidth(), mLocalBounds.getHeight(), mRx, mRy); } } Loading
libs/hwui/DisplayListRenderer.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -308,6 +308,10 @@ status_t DisplayListRenderer::drawOval(float left, float top, float right, float status_t DisplayListRenderer::drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) { if (fabs(sweepAngle) > 360.0f) { return drawOval(left, top, right, bottom, paint); } paint = refPaint(paint); addDrawOp(new (alloc()) DrawArcOp(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint)); Loading
libs/hwui/OpenGLRenderer.cpp +2 −6 Original line number Diff line number Diff line Loading @@ -2556,8 +2556,8 @@ status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float return drawShape(left, top, texture, p); } const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(*currentTransform(), right - left, bottom - top, rx, ry, p); const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect( *currentTransform(), *p, right - left, bottom - top, rx, ry); return drawVertexBuffer(left, top, *vertexBuffer, p); } Loading Loading @@ -2611,10 +2611,6 @@ status_t OpenGLRenderer::drawArc(float left, float top, float right, float botto return DrawGlInfo::kStatusDone; } if (fabs(sweepAngle) >= 360.0f) { return drawOval(left, top, right, bottom, p); } // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180) if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || useCenter) { mCaches.activeTexture(0); Loading
libs/hwui/TessellationCache.cpp +54 −58 Original line number Diff line number Diff line Loading @@ -39,6 +39,8 @@ namespace uirenderer { TessellationCache::Description::Description() : type(kNone) , scaleX(1.0f) , scaleY(1.0f) , aa(false) , cap(SkPaint::kDefault_Cap) , style(SkPaint::kFill_Style) Loading @@ -46,21 +48,13 @@ TessellationCache::Description::Description() memset(&shape, 0, sizeof(Shape)); } TessellationCache::Description::Description(Type type) TessellationCache::Description::Description(Type type, const Matrix4& transform, const SkPaint& paint) : type(type) , aa(false) , cap(SkPaint::kDefault_Cap) , style(SkPaint::kFill_Style) , strokeWidth(1.0f) { memset(&shape, 0, sizeof(Shape)); } TessellationCache::Description::Description(Type type, const SkPaint* paint) : type(type) , aa(paint->isAntiAlias()) , cap(paint->getStrokeCap()) , style(paint->getStyle()) , strokeWidth(paint->getStrokeWidth()) { , aa(paint.isAntiAlias()) , cap(paint.getStrokeCap()) , style(paint.getStyle()) , strokeWidth(paint.getStrokeWidth()) { PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY); memset(&shape, 0, sizeof(Shape)); } Loading @@ -70,10 +64,20 @@ hash_t TessellationCache::Description::hash() const { hash = JenkinsHashMix(hash, cap); hash = JenkinsHashMix(hash, style); hash = JenkinsHashMix(hash, android::hash_type(strokeWidth)); hash = JenkinsHashMix(hash, android::hash_type(scaleX)); hash = JenkinsHashMix(hash, android::hash_type(scaleY)); hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape)); return JenkinsHashWhiten(hash); } void TessellationCache::Description::setupMatrixAndPaint(Matrix4* matrix, SkPaint* paint) const { matrix->loadScale(scaleX, scaleY, 1.0f); paint->setAntiAlias(aa); paint->setStrokeCap(cap); paint->setStyle(style); paint->setStrokeWidth(strokeWidth); } TessellationCache::ShadowDescription::ShadowDescription() : nodeKey(NULL) { memset(&matrixData, 0, 16 * sizeof(float)); Loading @@ -96,20 +100,15 @@ hash_t TessellationCache::ShadowDescription::hash() const { class TessellationCache::TessellationTask : public Task<VertexBuffer*> { public: TessellationTask(Tessellator tessellator, const Description& description, const SkPaint* paint) TessellationTask(Tessellator tessellator, const Description& description) : tessellator(tessellator) , description(description) , paint(*paint) { , description(description) { } ~TessellationTask() {} Tessellator tessellator; Description description; //copied, since input paint may not be immutable const SkPaint paint; }; class TessellationCache::TessellationProcessor : public TaskProcessor<VertexBuffer*> { Loading @@ -121,7 +120,7 @@ public: virtual void onProcess(const sp<Task<VertexBuffer*> >& task) { TessellationTask* t = static_cast<TessellationTask*>(task.get()); ATRACE_NAME("shape tessellation"); VertexBuffer* buffer = t->tessellator(t->description, t->paint); VertexBuffer* buffer = t->tessellator(t->description); t->setResult(buffer); } }; Loading Loading @@ -416,21 +415,12 @@ void TessellationCache::getShadowBuffers(const Matrix4* drawTransform, const Rec // Tessellation precaching /////////////////////////////////////////////////////////////////////////////// static VertexBuffer* tessellatePath(const SkPath& path, const SkPaint* paint, float scaleX, float scaleY) { VertexBuffer* buffer = new VertexBuffer(); Matrix4 matrix; matrix.loadScale(scaleX, scaleY, 1); PathTessellator::tessellatePath(path, paint, matrix, *buffer); return buffer; } TessellationCache::Buffer* TessellationCache::getOrCreateBuffer( const Description& entry, Tessellator tessellator, const SkPaint* paint) { const Description& entry, Tessellator tessellator) { Buffer* buffer = mCache.get(entry); if (!buffer) { // not cached, enqueue a task to fill the buffer sp<TessellationTask> task = new TessellationTask(tessellator, entry, paint); sp<TessellationTask> task = new TessellationTask(tessellator, entry); buffer = new Buffer(task); if (mProcessor == NULL) { Loading @@ -442,43 +432,49 @@ TessellationCache::Buffer* TessellationCache::getOrCreateBuffer( return buffer; } static VertexBuffer* tessellatePath(const TessellationCache::Description& description, const SkPath& path) { Matrix4 matrix; SkPaint paint; description.setupMatrixAndPaint(&matrix, &paint); VertexBuffer* buffer = new VertexBuffer(); PathTessellator::tessellatePath(path, &paint, matrix, *buffer); return buffer; } /////////////////////////////////////////////////////////////////////////////// // Rounded rects // RoundRect /////////////////////////////////////////////////////////////////////////////// static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& description, const SkPaint& paint) { SkRect rect = SkRect::MakeWH(description.shape.roundRect.mWidth, description.shape.roundRect.mHeight); float rx = description.shape.roundRect.mRx; float ry = description.shape.roundRect.mRy; if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) { float outset = paint.getStrokeWidth() / 2; static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& description) { SkRect rect = SkRect::MakeWH(description.shape.roundRect.width, description.shape.roundRect.height); float rx = description.shape.roundRect.rx; float ry = description.shape.roundRect.ry; if (description.style == SkPaint::kStrokeAndFill_Style) { float outset = description.strokeWidth / 2; rect.outset(outset, outset); rx += outset; ry += outset; } SkPath path; path.addRoundRect(rect, rx, ry); return tessellatePath(path, &paint, description.shape.roundRect.mScaleX, description.shape.roundRect.mScaleY); } TessellationCache::Buffer* TessellationCache::getRoundRectBuffer(const Matrix4& transform, float width, float height, float rx, float ry, const SkPaint* paint) { Description entry(Description::kRoundRect, paint); entry.shape.roundRect.mWidth = width; entry.shape.roundRect.mHeight = height; entry.shape.roundRect.mRx = rx; entry.shape.roundRect.mRy = ry; PathTessellator::extractTessellationScales(transform, &entry.shape.roundRect.mScaleX, &entry.shape.roundRect.mScaleY); return getOrCreateBuffer(entry, &tessellateRoundRect, paint); } const VertexBuffer* TessellationCache::getRoundRect(const Matrix4& transform, float width, float height, float rx, float ry, const SkPaint* paint) { return getRoundRectBuffer(transform, width, height, rx, ry, paint)->getVertexBuffer(); return tessellatePath(description, path); } TessellationCache::Buffer* TessellationCache::getRoundRectBuffer( const Matrix4& transform, const SkPaint& paint, float width, float height, float rx, float ry) { Description entry(Description::kRoundRect, transform, paint); entry.shape.roundRect.width = width; entry.shape.roundRect.height = height; entry.shape.roundRect.rx = rx; entry.shape.roundRect.ry = ry; return getOrCreateBuffer(entry, &tessellateRoundRect); } const VertexBuffer* TessellationCache::getRoundRect(const Matrix4& transform, const SkPaint& paint, float width, float height, float rx, float ry) { return getRoundRectBuffer(transform, paint, width, height, rx, ry)->getVertexBuffer(); } }; // namespace uirenderer Loading
libs/hwui/TessellationCache.h +19 −21 Original line number Diff line number Diff line Loading @@ -50,30 +50,28 @@ public: enum Type { kNone, kRoundRect, kAmbientShadow, kSpotShadow }; Type type; float scaleX; float scaleY; bool aa; SkPaint::Cap cap; SkPaint::Style style; float strokeWidth; union Shape { struct RoundRect { float mScaleX; float mScaleY; float mWidth; float mHeight; float mRx; float mRy; float width; float height; float rx; float ry; } roundRect; } shape; Description(); Description(Type type); Description(Type type, const SkPaint* paint); Description(Type type, const Matrix4& transform, const SkPaint& paint); hash_t hash() const; void setupMatrixAndPaint(Matrix4* matrix, SkPaint* paint) const; }; struct ShadowDescription { Loading Loading @@ -123,12 +121,12 @@ public: // TODO: precache/get for Oval, Lines, Points, etc. void precacheRoundRect(const Matrix4& transform, float width, float height, float rx, float ry, const SkPaint* paint) { getRoundRectBuffer(transform, width, height, rx, ry, paint); void precacheRoundRect(const Matrix4& transform, const SkPaint& paint, float width, float height, float rx, float ry) { getRoundRectBuffer(transform, paint, width, height, rx, ry); } const VertexBuffer* getRoundRect(const Matrix4& transform, float width, float height, float rx, float ry, const SkPaint* paint); const VertexBuffer* getRoundRect(const Matrix4& transform, const SkPaint& paint, float width, float height, float rx, float ry); void precacheShadows(const Matrix4* drawTransform, const Rect& localClip, bool opaque, const SkPath* casterPerimeter, Loading @@ -146,14 +144,14 @@ private: class TessellationTask; class TessellationProcessor; typedef VertexBuffer* (*Tessellator)(const Description&); typedef VertexBuffer* (*Tessellator)(const Description&, const SkPaint&); Buffer* getRectBuffer(const Matrix4& transform, const SkPaint& paint, float width, float height); Buffer* getRoundRectBuffer(const Matrix4& transform, const SkPaint& paint, float width, float height, float rx, float ry); Buffer* getRoundRectBuffer(const Matrix4& transform, float width, float height, float rx, float ry, const SkPaint* paint); Buffer* getOrCreateBuffer(const Description& entry, Tessellator tessellator, const SkPaint* paint); Buffer* getOrCreateBuffer(const Description& entry, Tessellator tessellator); uint32_t mSize; uint32_t mMaxSize; Loading