Merge "Simplify paint filtering" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
3d4061ac9d
@@ -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); });
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user