Loading libs/hwui/PathCache.cpp +31 −53 Original line number Diff line number Diff line Loading @@ -121,29 +121,19 @@ bool PathDescription::operator==(const PathDescription& rhs) const { // Utilities /////////////////////////////////////////////////////////////////////////////// bool PathCache::canDrawAsConvexPath(SkPath* path, const SkPaint* paint) { // NOTE: This should only be used after PathTessellator handles joins properly return paint->getPathEffect() == nullptr && path->getConvexity() == SkPath::kConvex_Convexity; } void PathCache::computePathBounds(const SkPath* path, const SkPaint* paint, float& left, float& top, float& offset, uint32_t& width, uint32_t& height) { static void computePathBounds(const SkPath* path, const SkPaint* paint, PathTexture* texture, uint32_t& width, uint32_t& height) { const SkRect& bounds = path->getBounds(); PathCache::computeBounds(bounds, paint, left, top, offset, width, height); } void PathCache::computeBounds(const SkRect& bounds, const SkPaint* paint, float& left, float& top, float& offset, uint32_t& width, uint32_t& height) { const float pathWidth = std::max(bounds.width(), 1.0f); const float pathHeight = std::max(bounds.height(), 1.0f); left = bounds.fLeft; top = bounds.fTop; texture->left = floorf(bounds.fLeft); texture->top = floorf(bounds.fTop); offset = (int) floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f); texture->offset = (int) floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f); width = uint32_t(pathWidth + offset * 2.0 + 0.5); height = uint32_t(pathHeight + offset * 2.0 + 0.5); width = uint32_t(pathWidth + texture->offset * 2.0 + 0.5); height = uint32_t(pathHeight + texture->offset * 2.0 + 0.5); } static void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) { Loading @@ -163,16 +153,26 @@ static void initPaint(SkPaint& paint) { SkSafeUnref(paint.setXfermode(mode)); } static void drawPath(const SkPath *path, const SkPaint* paint, SkBitmap& bitmap, float left, float top, float offset, uint32_t width, uint32_t height) { initBitmap(bitmap, width, height); static SkBitmap* drawPath(const SkPath* path, const SkPaint* paint, PathTexture* texture, uint32_t maxTextureSize) { uint32_t width, height; computePathBounds(path, paint, texture, width, height); if (width > maxTextureSize || height > maxTextureSize) { ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)", width, height, maxTextureSize, maxTextureSize); return nullptr; } SkBitmap* bitmap = new SkBitmap(); initBitmap(*bitmap, width, height); SkPaint pathPaint(*paint); initPaint(pathPaint); SkCanvas canvas(bitmap); canvas.translate(-left + offset, -top + offset); SkCanvas canvas(*bitmap); canvas.translate(-texture->left + texture->offset, -texture->top + texture->offset); canvas.drawPath(*path, pathPaint); return bitmap; } /////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -271,21 +271,15 @@ PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *p const SkPaint* paint) { ATRACE_NAME("Generate Path Texture"); float left, top, offset; uint32_t width, height; computePathBounds(path, paint, left, top, offset, width, height); if (!checkTextureSize(width, height)) return nullptr; purgeCache(width, height); SkBitmap bitmap; drawPath(path, paint, bitmap, left, top, offset, width, height); PathTexture* texture = new PathTexture(Caches::getInstance(), left, top, offset, path->getGenerationID()); generateTexture(entry, &bitmap, texture); PathTexture* texture = new PathTexture(Caches::getInstance(), path->getGenerationID()); std::unique_ptr<SkBitmap> bitmap(drawPath(path, paint, texture, mMaxTextureSize)); if (!bitmap.get()) { delete texture; return nullptr; } purgeCache(bitmap->width(), bitmap->height()); generateTexture(entry, bitmap.get(), texture); return texture; } Loading Loading @@ -330,22 +324,7 @@ void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) { PathTask* t = static_cast<PathTask*>(task.get()); ATRACE_NAME("pathPrecache"); float left, top, offset; uint32_t width, height; PathCache::computePathBounds(&t->path, &t->paint, left, top, offset, width, height); PathTexture* texture = t->texture; texture->left = left; texture->top = top; texture->offset = offset; if (width <= mMaxTextureSize && height <= mMaxTextureSize) { SkBitmap* bitmap = new SkBitmap(); drawPath(&t->path, &t->paint, *bitmap, left, top, offset, width, height); t->setResult(bitmap); } else { t->setResult(nullptr); } t->setResult(drawPath(&t->path, &t->paint, t->texture, mMaxTextureSize)); } /////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -399,7 +378,6 @@ PathTexture* PathCache::get(const SkPath* path, const SkPaint* paint) { generateTexture(entry, bitmap, texture, false); texture->clearTask(); } else { ALOGW("Path too large to be rendered into a texture"); texture->clearTask(); texture = nullptr; mCache.remove(entry); Loading libs/hwui/PathCache.h +0 −23 Original line number Diff line number Diff line Loading @@ -61,14 +61,6 @@ class Caches; * Alpha texture used to represent a path. */ struct PathTexture: public Texture { PathTexture(Caches& caches, float left, float top, float offset, int generation) : Texture(caches) , left(left) , top(top) , offset(offset) { this->generation = generation; } PathTexture(Caches& caches, int generation) : Texture(caches) { this->generation = generation; Loading Loading @@ -227,12 +219,6 @@ public: */ void precache(const SkPath* path, const SkPaint* paint); static bool canDrawAsConvexPath(SkPath* path, const SkPaint* paint); static void computePathBounds(const SkPath* path, const SkPaint* paint, float& left, float& top, float& offset, uint32_t& width, uint32_t& height); static void computeBounds(const SkRect& bounds, const SkPaint* paint, float& left, float& top, float& offset, uint32_t& width, uint32_t& height); private: PathTexture* addTexture(const PathDescription& entry, const SkPath *path, const SkPaint* paint); Loading @@ -257,15 +243,6 @@ private: void removeTexture(PathTexture* texture); bool checkTextureSize(uint32_t width, uint32_t height) { if (width > mMaxTextureSize || height > mMaxTextureSize) { ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)", width, height, mMaxTextureSize, mMaxTextureSize); return false; } return true; } void init(); class PathTask: public Task<SkBitmap*> { Loading libs/hwui/tests/unit/BakedOpDispatcherTests.cpp +15 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <SkBlurDrawLooper.h> #include <SkDashPathEffect.h> #include <SkPath.h> using namespace android::uirenderer; Loading Loading @@ -273,3 +274,17 @@ RENDERTHREAD_TEST(BakedOpDispatcher, layerUpdateProperties) { } } } RENDERTHREAD_TEST(BakedOpDispatcher, pathTextureSnapping) { Rect bounds(10, 15, 20, 25); SkPaint paint; SkPath path; path.addRect(SkRect::MakeXYWH(1.5, 3.8, 100, 90)); PathOp op(bounds, Matrix4::identity(), nullptr, &paint, &path); testUnmergedGlopDispatch(renderThread, &op, [] (const Glop& glop) { auto texture = glop.fill.texture.texture; ASSERT_NE(nullptr, texture); EXPECT_EQ(1, reinterpret_cast<PathTexture*>(texture)->left); EXPECT_EQ(3, reinterpret_cast<PathTexture*>(texture)->top); }); } No newline at end of file Loading
libs/hwui/PathCache.cpp +31 −53 Original line number Diff line number Diff line Loading @@ -121,29 +121,19 @@ bool PathDescription::operator==(const PathDescription& rhs) const { // Utilities /////////////////////////////////////////////////////////////////////////////// bool PathCache::canDrawAsConvexPath(SkPath* path, const SkPaint* paint) { // NOTE: This should only be used after PathTessellator handles joins properly return paint->getPathEffect() == nullptr && path->getConvexity() == SkPath::kConvex_Convexity; } void PathCache::computePathBounds(const SkPath* path, const SkPaint* paint, float& left, float& top, float& offset, uint32_t& width, uint32_t& height) { static void computePathBounds(const SkPath* path, const SkPaint* paint, PathTexture* texture, uint32_t& width, uint32_t& height) { const SkRect& bounds = path->getBounds(); PathCache::computeBounds(bounds, paint, left, top, offset, width, height); } void PathCache::computeBounds(const SkRect& bounds, const SkPaint* paint, float& left, float& top, float& offset, uint32_t& width, uint32_t& height) { const float pathWidth = std::max(bounds.width(), 1.0f); const float pathHeight = std::max(bounds.height(), 1.0f); left = bounds.fLeft; top = bounds.fTop; texture->left = floorf(bounds.fLeft); texture->top = floorf(bounds.fTop); offset = (int) floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f); texture->offset = (int) floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f); width = uint32_t(pathWidth + offset * 2.0 + 0.5); height = uint32_t(pathHeight + offset * 2.0 + 0.5); width = uint32_t(pathWidth + texture->offset * 2.0 + 0.5); height = uint32_t(pathHeight + texture->offset * 2.0 + 0.5); } static void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) { Loading @@ -163,16 +153,26 @@ static void initPaint(SkPaint& paint) { SkSafeUnref(paint.setXfermode(mode)); } static void drawPath(const SkPath *path, const SkPaint* paint, SkBitmap& bitmap, float left, float top, float offset, uint32_t width, uint32_t height) { initBitmap(bitmap, width, height); static SkBitmap* drawPath(const SkPath* path, const SkPaint* paint, PathTexture* texture, uint32_t maxTextureSize) { uint32_t width, height; computePathBounds(path, paint, texture, width, height); if (width > maxTextureSize || height > maxTextureSize) { ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)", width, height, maxTextureSize, maxTextureSize); return nullptr; } SkBitmap* bitmap = new SkBitmap(); initBitmap(*bitmap, width, height); SkPaint pathPaint(*paint); initPaint(pathPaint); SkCanvas canvas(bitmap); canvas.translate(-left + offset, -top + offset); SkCanvas canvas(*bitmap); canvas.translate(-texture->left + texture->offset, -texture->top + texture->offset); canvas.drawPath(*path, pathPaint); return bitmap; } /////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -271,21 +271,15 @@ PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *p const SkPaint* paint) { ATRACE_NAME("Generate Path Texture"); float left, top, offset; uint32_t width, height; computePathBounds(path, paint, left, top, offset, width, height); if (!checkTextureSize(width, height)) return nullptr; purgeCache(width, height); SkBitmap bitmap; drawPath(path, paint, bitmap, left, top, offset, width, height); PathTexture* texture = new PathTexture(Caches::getInstance(), left, top, offset, path->getGenerationID()); generateTexture(entry, &bitmap, texture); PathTexture* texture = new PathTexture(Caches::getInstance(), path->getGenerationID()); std::unique_ptr<SkBitmap> bitmap(drawPath(path, paint, texture, mMaxTextureSize)); if (!bitmap.get()) { delete texture; return nullptr; } purgeCache(bitmap->width(), bitmap->height()); generateTexture(entry, bitmap.get(), texture); return texture; } Loading Loading @@ -330,22 +324,7 @@ void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) { PathTask* t = static_cast<PathTask*>(task.get()); ATRACE_NAME("pathPrecache"); float left, top, offset; uint32_t width, height; PathCache::computePathBounds(&t->path, &t->paint, left, top, offset, width, height); PathTexture* texture = t->texture; texture->left = left; texture->top = top; texture->offset = offset; if (width <= mMaxTextureSize && height <= mMaxTextureSize) { SkBitmap* bitmap = new SkBitmap(); drawPath(&t->path, &t->paint, *bitmap, left, top, offset, width, height); t->setResult(bitmap); } else { t->setResult(nullptr); } t->setResult(drawPath(&t->path, &t->paint, t->texture, mMaxTextureSize)); } /////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -399,7 +378,6 @@ PathTexture* PathCache::get(const SkPath* path, const SkPaint* paint) { generateTexture(entry, bitmap, texture, false); texture->clearTask(); } else { ALOGW("Path too large to be rendered into a texture"); texture->clearTask(); texture = nullptr; mCache.remove(entry); Loading
libs/hwui/PathCache.h +0 −23 Original line number Diff line number Diff line Loading @@ -61,14 +61,6 @@ class Caches; * Alpha texture used to represent a path. */ struct PathTexture: public Texture { PathTexture(Caches& caches, float left, float top, float offset, int generation) : Texture(caches) , left(left) , top(top) , offset(offset) { this->generation = generation; } PathTexture(Caches& caches, int generation) : Texture(caches) { this->generation = generation; Loading Loading @@ -227,12 +219,6 @@ public: */ void precache(const SkPath* path, const SkPaint* paint); static bool canDrawAsConvexPath(SkPath* path, const SkPaint* paint); static void computePathBounds(const SkPath* path, const SkPaint* paint, float& left, float& top, float& offset, uint32_t& width, uint32_t& height); static void computeBounds(const SkRect& bounds, const SkPaint* paint, float& left, float& top, float& offset, uint32_t& width, uint32_t& height); private: PathTexture* addTexture(const PathDescription& entry, const SkPath *path, const SkPaint* paint); Loading @@ -257,15 +243,6 @@ private: void removeTexture(PathTexture* texture); bool checkTextureSize(uint32_t width, uint32_t height) { if (width > mMaxTextureSize || height > mMaxTextureSize) { ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)", width, height, mMaxTextureSize, mMaxTextureSize); return false; } return true; } void init(); class PathTask: public Task<SkBitmap*> { Loading
libs/hwui/tests/unit/BakedOpDispatcherTests.cpp +15 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <SkBlurDrawLooper.h> #include <SkDashPathEffect.h> #include <SkPath.h> using namespace android::uirenderer; Loading Loading @@ -273,3 +274,17 @@ RENDERTHREAD_TEST(BakedOpDispatcher, layerUpdateProperties) { } } } RENDERTHREAD_TEST(BakedOpDispatcher, pathTextureSnapping) { Rect bounds(10, 15, 20, 25); SkPaint paint; SkPath path; path.addRect(SkRect::MakeXYWH(1.5, 3.8, 100, 90)); PathOp op(bounds, Matrix4::identity(), nullptr, &paint, &path); testUnmergedGlopDispatch(renderThread, &op, [] (const Glop& glop) { auto texture = glop.fill.texture.texture; ASSERT_NE(nullptr, texture); EXPECT_EQ(1, reinterpret_cast<PathTexture*>(texture)->left); EXPECT_EQ(3, reinterpret_cast<PathTexture*>(texture)->top); }); } No newline at end of file