Merge "Simplify paint filtering" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-02-23 19:52:20 +00:00
committed by Android (Google) Code Review
4 changed files with 77 additions and 136 deletions

View File

@@ -188,7 +188,7 @@ void SkiaCanvas::restoreUnclippedLayer(int restoreCount, const SkPaint& paint) {
}
if (mCanvas->getSaveCount() == restoreCount + 1) {
SkCanvasPriv::DrawBehind(mCanvas, *filterPaint(paint));
SkCanvasPriv::DrawBehind(mCanvas, filterPaint(paint));
this->restore();
}
}
@@ -431,15 +431,14 @@ void SkiaCanvas::drawColor(int color, SkBlendMode mode) {
mCanvas->drawColor(color, mode);
}
SkiaCanvas::PaintCoW&& SkiaCanvas::filterPaint(PaintCoW&& paint) const {
void SkiaCanvas::onFilterPaint(SkPaint& paint) {
if (mPaintFilter) {
mPaintFilter->filter(&paint.writeable());
mPaintFilter->filter(&paint);
}
return std::move(paint);
}
void SkiaCanvas::drawPaint(const SkPaint& paint) {
mCanvas->drawPaint(*filterPaint(paint));
mCanvas->drawPaint(filterPaint(paint));
}
// ----------------------------------------------------------------------------
@@ -457,13 +456,11 @@ void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint,
points += 2;
}
apply_looper(&paint, [&](const SkPaint& p) {
mCanvas->drawPoints(mode, count, pts.get(), p);
});
applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPoints(mode, count, pts.get(), p); });
}
void SkiaCanvas::drawPoint(float x, float y, const Paint& paint) {
apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawPoint(x, y, p); });
applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPoint(x, y, p); });
}
void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint) {
@@ -472,9 +469,8 @@ void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint)
void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
const Paint& paint) {
apply_looper(&paint, [&](const SkPaint& p) {
mCanvas->drawLine(startX, startY, stopX, stopY, p);
});
applyLooper(&paint,
[&](const SkPaint& p) { mCanvas->drawLine(startX, startY, stopX, stopY, p); });
}
void SkiaCanvas::drawLines(const float* points, int count, const Paint& paint) {
@@ -484,46 +480,44 @@ void SkiaCanvas::drawLines(const float* points, int count, const Paint& paint) {
void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
apply_looper(&paint, [&](const SkPaint& p) {
applyLooper(&paint, [&](const SkPaint& p) {
mCanvas->drawRect({left, top, right, bottom}, p);
});
}
void SkiaCanvas::drawRegion(const SkRegion& region, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawRegion(region, p); });
applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawRegion(region, p); });
}
void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
apply_looper(&paint, [&](const SkPaint& p) {
mCanvas->drawRoundRect(rect, rx, ry, p);
});
applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawRoundRect(rect, rx, ry, p); });
}
void SkiaCanvas::drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
const Paint& paint) {
apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawDRRect(outer, inner, p); });
applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawDRRect(outer, inner, p); });
}
void SkiaCanvas::drawCircle(float x, float y, float radius, const Paint& paint) {
if (CC_UNLIKELY(radius <= 0 || paint.nothingToDraw())) return;
apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawCircle(x, y, radius, p); });
applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawCircle(x, y, radius, p); });
}
void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawOval(oval, p); });
applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawOval(oval, p); });
}
void SkiaCanvas::drawArc(float left, float top, float right, float bottom, float startAngle,
float sweepAngle, bool useCenter, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
apply_looper(&paint, [&](const SkPaint& p) {
applyLooper(&paint, [&](const SkPaint& p) {
if (fabs(sweepAngle) >= 360.0f) {
mCanvas->drawOval(arc, p);
} else {
@@ -537,13 +531,11 @@ void SkiaCanvas::drawPath(const SkPath& path, const Paint& paint) {
if (CC_UNLIKELY(path.isEmpty() && (!path.isInverseFillType()))) {
return;
}
apply_looper(&paint, [&](const SkPaint& p) { mCanvas->drawPath(path, p); });
applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawPath(path, p); });
}
void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const Paint& paint) {
apply_looper(&paint, [&](const SkPaint& p) {
mCanvas->drawVertices(vertices, mode, p);
});
applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawVertices(vertices, mode, p); });
}
// ----------------------------------------------------------------------------
@@ -552,7 +544,7 @@ void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, cons
void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
auto image = bitmap.makeImage();
apply_looper(paint, [&](const SkPaint& p) {
applyLooper(paint, [&](const SkPaint& p) {
auto sampling = SkSamplingOptions(p.getFilterQuality());
mCanvas->drawImage(image, left, top, sampling, &p);
});
@@ -562,7 +554,7 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint*
auto image = bitmap.makeImage();
SkAutoCanvasRestore acr(mCanvas, true);
mCanvas->concat(matrix);
apply_looper(paint, [&](const SkPaint& p) {
applyLooper(paint, [&](const SkPaint& p) {
auto sampling = SkSamplingOptions(p.getFilterQuality());
mCanvas->drawImage(image, 0, 0, sampling, &p);
});
@@ -575,7 +567,7 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float s
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
apply_looper(paint, [&](const SkPaint& p) {
applyLooper(paint, [&](const SkPaint& p) {
auto sampling = SkSamplingOptions(p.getFilterQuality());
mCanvas->drawImageRect(image, srcRect, dstRect, sampling, &p,
SkCanvas::kFast_SrcRectConstraint);
@@ -672,11 +664,11 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
pnt.setShader(image->makeShader(sampling));
auto v = builder.detach();
apply_looper(&pnt, [&](const SkPaint& p) {
applyLooper(&pnt, [&](const SkPaint& p) {
SkPaint copy(p);
auto s = SkSamplingOptions(p.getFilterQuality());
if (s != sampling) {
// apply_looper changed the quality?
// applyLooper changed the quality?
copy.setShader(image->makeShader(s));
}
mCanvas->drawVertices(v, SkBlendMode::kModulate, copy);
@@ -707,7 +699,7 @@ void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, floa
lattice.fBounds = nullptr;
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
auto image = bitmap.makeImage();
apply_looper(paint, [&](const SkPaint& p) {
applyLooper(paint, [&](const SkPaint& p) {
auto filter = SkSamplingOptions(p.getFilterQuality()).filter;
mCanvas->drawImageLattice(image.get(), lattice, dst, filter, &p);
});
@@ -746,9 +738,7 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& pai
sk_sp<SkTextBlob> textBlob(builder.make());
apply_looper(&paintCopy, [&](const SkPaint& p) {
mCanvas->drawTextBlob(textBlob, 0, 0, p);
});
applyLooper(&paintCopy, [&](const SkPaint& p) { mCanvas->drawTextBlob(textBlob, 0, 0, p); });
drawTextDecorations(x, y, totalAdvance, paintCopy);
}
@@ -788,9 +778,7 @@ void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset,
sk_sp<SkTextBlob> textBlob(builder.make());
apply_looper(&paintCopy, [&](const SkPaint& p) {
mCanvas->drawTextBlob(textBlob, 0, 0, p);
});
applyLooper(&paintCopy, [&](const SkPaint& p) { mCanvas->drawTextBlob(textBlob, 0, 0, p); });
}
// ----------------------------------------------------------------------------

View File

@@ -169,53 +169,24 @@ protected:
const Paint& paint, const SkPath& path, size_t start,
size_t end) override;
/** This class acts as a copy on write SkPaint.
*
* Initially this will be the SkPaint passed to the contructor.
* The first time writable() is called this will become a copy of the
* initial SkPaint (or a default SkPaint if nullptr).
*/
struct PaintCoW {
PaintCoW(const SkPaint& that) : mPtr(&that) {}
PaintCoW(const SkPaint* ptr) : mPtr(ptr) {}
PaintCoW(const PaintCoW&) = delete;
PaintCoW(PaintCoW&&) = delete;
PaintCoW& operator=(const PaintCoW&) = delete;
PaintCoW& operator=(PaintCoW&&) = delete;
SkPaint& writeable() {
if (!mStorage) {
if (!mPtr) {
mStorage.emplace();
} else {
mStorage.emplace(*mPtr);
}
mPtr = &*mStorage;
}
return *mStorage;
}
operator const SkPaint*() const { return mPtr; }
const SkPaint* operator->() const { assert(mPtr); return mPtr; }
explicit operator bool() { return mPtr != nullptr; }
private:
const SkPaint* mPtr;
std::optional<SkPaint> mStorage;
};
void onFilterPaint(SkPaint& paint);
/** Filters the paint using the current paint filter.
*
* @param paint the paint to filter. Will be initialized with the default
* SkPaint before filtering if filtering is required.
*/
PaintCoW&& filterPaint(PaintCoW&& paint) const;
SkPaint filterPaint(const SkPaint& src) {
SkPaint dst(src);
this->onFilterPaint(dst);
return dst;
}
// proc(const SkPaint& modifiedPaint)
template <typename Proc> void apply_looper(const Paint* paint, Proc proc) {
SkPaint skp;
BlurDrawLooper* looper = nullptr;
if (paint) {
skp = *filterPaint(paint);
looper = paint->getLooper();
template <typename Proc>
void applyLooper(const Paint* paint, Proc proc, void (*preFilter)(SkPaint&) = nullptr) {
BlurDrawLooper* looper = paint ? paint->getLooper() : nullptr;
const SkPaint* skpPtr = paint;
SkPaint skp = skpPtr ? *skpPtr : SkPaint();
if (preFilter) {
preFilter(skp);
}
this->onFilterPaint(skp);
if (looper) {
looper->apply(skp, [&](SkPoint offset, const SkPaint& modifiedPaint) {
mCanvas->save();
@@ -228,7 +199,6 @@ protected:
}
}
private:
struct SaveRec {
int saveCount;

View File

@@ -170,36 +170,23 @@ void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
// Recording Canvas draw operations: Bitmaps
// ----------------------------------------------------------------------------
SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint) {
bool fixBlending = false;
bool fixAA = false;
if (paint) {
// kClear blend mode is drawn as kDstOut on HW for compatibility with Android O and
// older.
fixBlending = sApiLevel <= 27 && paint->getBlendMode() == SkBlendMode::kClear;
fixAA = paint->isAntiAlias();
void SkiaRecordingCanvas::FilterForImage(SkPaint& paint) {
// kClear blend mode is drawn as kDstOut on HW for compatibility with Android O and
// older.
if (sApiLevel <= 27 && paint.getBlendMode() == SkBlendMode::kClear) {
paint.setBlendMode(SkBlendMode::kDstOut);
}
if (fixBlending || fixAA) {
SkPaint& tmpPaint = paint.writeable();
if (fixBlending) {
tmpPaint.setBlendMode(SkBlendMode::kDstOut);
}
// disabling AA on bitmap draws matches legacy HWUI behavior
tmpPaint.setAntiAlias(false);
}
return filterPaint(std::move(paint));
// disabling AA on bitmap draws matches legacy HWUI behavior
paint.setAntiAlias(false);
}
static SkFilterMode Paint_to_filter(const SkPaint* paint) {
return paint && paint->getFilterQuality() != kNone_SkFilterQuality ? SkFilterMode::kLinear
: SkFilterMode::kNearest;
static SkFilterMode Paint_to_filter(const SkPaint& paint) {
return paint.getFilterQuality() != kNone_SkFilterQuality ? SkFilterMode::kLinear
: SkFilterMode::kNearest;
}
static SkSamplingOptions Paint_to_sampling(const SkPaint* paint) {
static SkSamplingOptions Paint_to_sampling(const SkPaint& paint) {
// Android only has 1-bit for "filter", so we don't try to cons-up mipmaps or cubics
return SkSamplingOptions(Paint_to_filter(paint), SkMipmapMode::kNone);
}
@@ -207,9 +194,12 @@ static SkSamplingOptions Paint_to_sampling(const SkPaint* paint) {
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
sk_sp<SkImage> image = bitmap.makeImage();
applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
mRecorder.drawImage(image, left + x, top + y, Paint_to_sampling(p), p, bitmap.palette());
});
applyLooper(
paint,
[&](const SkPaint& p) {
mRecorder.drawImage(image, left, top, Paint_to_sampling(p), &p, bitmap.palette());
},
FilterForImage);
// if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
// it is not safe to store a raw SkImage pointer, because the image object will be destroyed
@@ -225,9 +215,12 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, con
sk_sp<SkImage> image = bitmap.makeImage();
applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
mRecorder.drawImage(image, x, y, Paint_to_sampling(p), p, bitmap.palette());
});
applyLooper(
paint,
[&](const SkPaint& p) {
mRecorder.drawImage(image, 0, 0, Paint_to_sampling(p), &p, bitmap.palette());
},
FilterForImage);
if (!bitmap.isImmutable() && image.get() && !image->unique()) {
mDisplayList->mMutableImages.push_back(image.get());
@@ -242,10 +235,13 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop
sk_sp<SkImage> image = bitmap.makeImage();
applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
mRecorder.drawImageRect(image, srcRect, dstRect.makeOffset(x, y), Paint_to_sampling(p),
p, SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
});
applyLooper(
paint,
[&](const SkPaint& p) {
mRecorder.drawImageRect(image, srcRect, dstRect, Paint_to_sampling(p), &p,
SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
},
FilterForImage);
if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
!dstRect.isEmpty()) {
@@ -281,10 +277,12 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch
// HWUI always draws 9-patches with linear filtering, regardless of the Paint.
const SkFilterMode filter = SkFilterMode::kLinear;
applyLooper(paint, [&](SkScalar x, SkScalar y, const SkPaint* p) {
mRecorder.drawImageLattice(image, lattice, dst.makeOffset(x, y), filter, p,
bitmap.palette());
});
applyLooper(
paint,
[&](const SkPaint& p) {
mRecorder.drawImageLattice(image, lattice, dst, filter, &p, bitmap.palette());
},
FilterForImage);
if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());

View File

@@ -87,22 +87,7 @@ private:
std::unique_ptr<SkiaDisplayList> mDisplayList;
StartReorderBarrierDrawable* mCurrentBarrier;
template <typename Proc>
void applyLooper(const Paint* paint, Proc proc) {
SkPaint skp;
BlurDrawLooper* looper = nullptr;
if (paint) {
skp = *filterBitmap(paint);
looper = paint->getLooper();
}
if (looper) {
looper->apply(skp, [&](SkPoint offset, const SkPaint& modifiedPaint) {
proc(offset.fX, offset.fY, &modifiedPaint);
});
} else {
proc(0, 0, &skp);
}
}
static void FilterForImage(SkPaint&);
/**
* A new SkiaDisplayList is created or recycled if available.
@@ -113,7 +98,7 @@ private:
*/
void initDisplayList(uirenderer::RenderNode* renderNode, int width, int height);
PaintCoW&& filterBitmap(PaintCoW&& paint);
using INHERITED = SkiaCanvas;
};
} // namespace skiapipeline