mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
Bug 1911231 - Clip fill/clear ops to viewport when possible. r=aosmond
We can avoid falling back to Skia on certain fill/clear ops so long as the transform produces axis-aligned rectangles. In that case, we can do a precise clip of the transformed rect to the viewport, which can then be accelerated without any risk of fallback. Differential Revision: https://phabricator.services.mozilla.com/D218472
This commit is contained in:
parent
61ef38e43f
commit
def60a14fa
@ -1408,23 +1408,27 @@ inline ColorPattern DrawTargetWebgl::GetClearPattern() const {
|
||||
DeviceColor(0.0f, 0.0f, 0.0f, IsOpaque(mFormat) ? 1.0f : 0.0f));
|
||||
}
|
||||
|
||||
// Check if the transformed rect would contain the entire viewport.
|
||||
inline bool DrawTargetWebgl::RectContainsViewport(const Rect& aRect) const {
|
||||
return mTransform.PreservesAxisAlignedRectangles() &&
|
||||
MatrixDouble(mTransform)
|
||||
.TransformBounds(
|
||||
RectDouble(aRect.x, aRect.y, aRect.width, aRect.height))
|
||||
.Contains(RectDouble(GetRect()));
|
||||
template <typename R>
|
||||
inline RectDouble DrawTargetWebgl::TransformDouble(const R& aRect) const {
|
||||
return MatrixDouble(mTransform).TransformBounds(WidenToDouble(aRect));
|
||||
}
|
||||
|
||||
// Check if the transformed rect clips to the viewport.
|
||||
inline Maybe<Rect> DrawTargetWebgl::RectClippedToViewport(
|
||||
const RectDouble& aRect) const {
|
||||
if (!mTransform.PreservesAxisAlignedRectangles()) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(NarrowToFloat(aRect.SafeIntersect(RectDouble(GetRect()))));
|
||||
}
|
||||
|
||||
// Ensure that the rect, after transform, is within reasonable precision limits
|
||||
// such that when transformed and clipped in the shader it will not round bits
|
||||
// from the mantissa in a way that will diverge in a noticeable way from path
|
||||
// geometry calculated by the path fallback.
|
||||
static inline bool RectInsidePrecisionLimits(const Rect& aRect,
|
||||
const Matrix& aTransform) {
|
||||
return Rect(-(1 << 20), -(1 << 20), 2 << 20, 2 << 20)
|
||||
.Contains(aTransform.TransformBounds(aRect));
|
||||
static inline bool RectInsidePrecisionLimits(const RectDouble& aRect) {
|
||||
return RectDouble(-(1 << 20), -(1 << 20), 2 << 20, 2 << 20).Contains(aRect);
|
||||
}
|
||||
|
||||
void DrawTargetWebgl::ClearRect(const Rect& aRect) {
|
||||
@ -1433,14 +1437,16 @@ void DrawTargetWebgl::ClearRect(const Rect& aRect) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool containsViewport = RectContainsViewport(aRect);
|
||||
if (containsViewport) {
|
||||
// If the rect encompasses the entire viewport, just clear the viewport
|
||||
// instead to avoid transform issues.
|
||||
DrawRect(Rect(GetRect()), GetClearPattern(),
|
||||
RectDouble xformRect = TransformDouble(aRect);
|
||||
bool containsViewport = false;
|
||||
if (Maybe<Rect> clipped = RectClippedToViewport(xformRect)) {
|
||||
// If the rect clips to viewport, just clear the clipped rect
|
||||
// to avoid transform issues.
|
||||
containsViewport = clipped->Size() == Size(GetSize());
|
||||
DrawRect(*clipped, GetClearPattern(),
|
||||
DrawOptions(1.0f, CompositionOp::OP_CLEAR), Nothing(), nullptr,
|
||||
false);
|
||||
} else if (RectInsidePrecisionLimits(aRect, mTransform)) {
|
||||
} else if (RectInsidePrecisionLimits(xformRect)) {
|
||||
// If the rect transform won't stress precision, then just use it.
|
||||
DrawRect(aRect, GetClearPattern(),
|
||||
DrawOptions(1.0f, CompositionOp::OP_CLEAR));
|
||||
@ -2592,16 +2598,18 @@ bool SharedContextWebgl::PruneTextureMemory(size_t aMargin, bool aPruneUnused) {
|
||||
void DrawTargetWebgl::FillRect(const Rect& aRect, const Pattern& aPattern,
|
||||
const DrawOptions& aOptions) {
|
||||
if (SupportsPattern(aPattern)) {
|
||||
if (RectInsidePrecisionLimits(aRect, mTransform)) {
|
||||
DrawRect(aRect, aPattern, aOptions);
|
||||
return;
|
||||
RectDouble xformRect = TransformDouble(aRect);
|
||||
if (aPattern.GetType() == PatternType::COLOR) {
|
||||
if (Maybe<Rect> clipped = RectClippedToViewport(xformRect)) {
|
||||
// If the pattern is transform-invariant and the rect clips to the
|
||||
// viewport, just clip drawing to the viewport to avoid transform
|
||||
// issues.
|
||||
DrawRect(*clipped, aPattern, aOptions, Nothing(), nullptr, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (aPattern.GetType() == PatternType::COLOR &&
|
||||
RectContainsViewport(aRect)) {
|
||||
// If the pattern is transform-invariant and the rect encompasses the
|
||||
// entire viewport, just clip drawing to the viewport to avoid transform
|
||||
// issues.
|
||||
DrawRect(Rect(GetRect()), aPattern, aOptions, Nothing(), nullptr, false);
|
||||
if (RectInsidePrecisionLimits(xformRect)) {
|
||||
DrawRect(aRect, aPattern, aOptions);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2762,17 +2770,19 @@ void DrawTargetWebgl::Fill(const Path* aPath, const Pattern& aPattern,
|
||||
SkRect skiaRect = SkRect::MakeEmpty();
|
||||
// Draw the path as a simple rectangle with a supported pattern when possible.
|
||||
if (skiaPath.isRect(&skiaRect) && SupportsPattern(aPattern)) {
|
||||
Rect rect = SkRectToRect(skiaRect);
|
||||
if (RectInsidePrecisionLimits(rect, mTransform)) {
|
||||
DrawRect(rect, aPattern, aOptions);
|
||||
return;
|
||||
RectDouble rect = SkRectToRectDouble(skiaRect);
|
||||
RectDouble xformRect = TransformDouble(rect);
|
||||
if (aPattern.GetType() == PatternType::COLOR) {
|
||||
if (Maybe<Rect> clipped = RectClippedToViewport(xformRect)) {
|
||||
// If the pattern is transform-invariant and the rect clips to the
|
||||
// viewport, just clip drawing to the viewport to avoid transform
|
||||
// issues.
|
||||
DrawRect(*clipped, aPattern, aOptions, Nothing(), nullptr, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (aPattern.GetType() == PatternType::COLOR &&
|
||||
RectContainsViewport(rect)) {
|
||||
// If the pattern is transform-invariant and the rect encompasses the
|
||||
// entire viewport, just clip drawing to the viewport to avoid transform
|
||||
// issues.
|
||||
DrawRect(Rect(GetRect()), aPattern, aOptions, Nothing(), nullptr, false);
|
||||
if (RectInsidePrecisionLimits(xformRect)) {
|
||||
DrawRect(NarrowToFloat(rect), aPattern, aOptions);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -622,7 +622,10 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
|
||||
|
||||
ColorPattern GetClearPattern() const;
|
||||
|
||||
bool RectContainsViewport(const Rect& aRect) const;
|
||||
template <typename R>
|
||||
RectDouble TransformDouble(const R& aRect) const;
|
||||
|
||||
Maybe<Rect> RectClippedToViewport(const RectDouble& aRect) const;
|
||||
|
||||
bool ShouldAccelPath(const DrawOptions& aOptions,
|
||||
const StrokeOptions* aStrokeOptions);
|
||||
|
@ -275,6 +275,13 @@ static inline Rect SkRectToRect(const SkRect& aRect) {
|
||||
SkScalarToFloat(aRect.width()), SkScalarToFloat(aRect.height()));
|
||||
}
|
||||
|
||||
static inline RectDouble SkRectToRectDouble(const SkRect& aRect) {
|
||||
double x = SkScalarToDouble(aRect.x());
|
||||
double y = SkScalarToDouble(aRect.y());
|
||||
return RectDouble(x, y, SkScalarToDouble(aRect.right()) - x,
|
||||
SkScalarToDouble(aRect.bottom()) - y);
|
||||
}
|
||||
|
||||
static inline SkTileMode ExtendModeToTileMode(ExtendMode aMode, Axis aAxis) {
|
||||
switch (aMode) {
|
||||
case ExtendMode::CLAMP:
|
||||
|
@ -318,6 +318,18 @@ struct MOZ_EMPTY_BASES RectTyped
|
||||
typedef RectTyped<UnknownUnits> Rect;
|
||||
typedef RectTyped<UnknownUnits, double> RectDouble;
|
||||
|
||||
template <class Units, class D>
|
||||
RectTyped<Units> NarrowToFloat(const RectTyped<Units, D>& aRect) {
|
||||
return RectTyped<Units>(float(aRect.x), float(aRect.y), float(aRect.width),
|
||||
float(aRect.height));
|
||||
}
|
||||
|
||||
template <class Units, class F>
|
||||
RectTyped<Units, double> WidenToDouble(const RectTyped<Units, F>& aRect) {
|
||||
return RectTyped<Units, double>(double(aRect.x), double(aRect.y),
|
||||
double(aRect.width), double(aRect.height));
|
||||
}
|
||||
|
||||
template <class Units>
|
||||
IntRectTyped<Units> RoundedToInt(const RectTyped<Units>& aRect) {
|
||||
RectTyped<Units> copy(aRect);
|
||||
|
Loading…
Reference in New Issue
Block a user