Bug 1828137 - Support accelerating large clearRects if they encompass entire viewport. r=aosmond

Differential Revision: https://phabricator.services.mozilla.com/D175727
This commit is contained in:
Lee Salzman
2023-04-18 15:08:27 +00:00
parent c5c8aee75c
commit 3a27b37e62
2 changed files with 67 additions and 22 deletions

View File

@@ -1383,20 +1383,53 @@ 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()));
}
// 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));
}
void DrawTargetWebgl::ClearRect(const Rect& aRect) {
if (mIsClear) {
// No need to clear anything if the entire framebuffer is already clear.
return;
}
DrawRect(aRect, GetClearPattern(),
DrawOptions(1.0f, CompositionOp::OP_CLEAR));
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(),
DrawOptions(1.0f, CompositionOp::OP_CLEAR), Nothing(), nullptr,
false);
} else if (RectInsidePrecisionLimits(aRect, mTransform)) {
// If the rect transform won't stress precision, then just use it.
DrawRect(aRect, GetClearPattern(),
DrawOptions(1.0f, CompositionOp::OP_CLEAR));
} else {
// Otherwise, using the transform in the shader may lead to inaccuracies, so
// just fall back.
MarkSkiaChanged();
mSkia->ClearRect(aRect);
}
// If the clear rectangle encompasses the entire viewport and is not clipped,
// then mark the target as entirely clear.
if (mTransform.PreservesAxisAlignedRectangles() &&
mTransform.TransformBounds(aRect).Contains(Rect(GetRect())) &&
mSharedContext->IsCurrentTarget(this) && !mSharedContext->HasClipMask() &&
if (containsViewport && mSharedContext->IsCurrentTarget(this) &&
!mSharedContext->HasClipMask() &&
mSharedContext->mClipAARect.Contains(Rect(GetRect()))) {
mIsClear = true;
}
@@ -2456,22 +2489,23 @@ bool DrawTargetWebgl::SharedContext::PruneTextureMemory(size_t aMargin,
return mNumTextureHandles < oldItems;
}
// 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));
}
void DrawTargetWebgl::FillRect(const Rect& aRect, const Pattern& aPattern,
const DrawOptions& aOptions) {
if (SupportsPattern(aPattern) &&
RectInsidePrecisionLimits(aRect, GetTransform())) {
DrawRect(aRect, aPattern, aOptions);
} else if (!mWebglValid) {
if (SupportsPattern(aPattern)) {
if (RectInsidePrecisionLimits(aRect, mTransform)) {
DrawRect(aRect, aPattern, aOptions);
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);
return;
}
}
if (!mWebglValid) {
MarkSkiaChanged(aOptions);
mSkia->FillRect(aRect, aPattern, aOptions);
} else {
@@ -2621,10 +2655,18 @@ void DrawTargetWebgl::Fill(const Path* aPath, const Pattern& aPattern,
// 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, GetTransform())) {
if (RectInsidePrecisionLimits(rect, mTransform)) {
DrawRect(rect, aPattern, aOptions);
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);
return;
}
}
DrawPath(aPath, aPattern, aOptions);

View File

@@ -513,8 +513,9 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
void DrawRectFallback(const Rect& aRect, const Pattern& aPattern,
const DrawOptions& aOptions,
Maybe<DeviceColor> aMaskColor, bool aTransform,
bool aClipped, const StrokeOptions* aStrokeOptions);
Maybe<DeviceColor> aMaskColor = Nothing(),
bool aTransform = true, bool aClipped = true,
const StrokeOptions* aStrokeOptions = nullptr);
bool DrawRect(const Rect& aRect, const Pattern& aPattern,
const DrawOptions& aOptions,
Maybe<DeviceColor> aMaskColor = Nothing(),
@@ -525,6 +526,8 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
ColorPattern GetClearPattern() const;
bool RectContainsViewport(const Rect& aRect) const;
bool ShouldAccelPath(const DrawOptions& aOptions,
const StrokeOptions* aStrokeOptions);
void DrawPath(const Path* aPath, const Pattern& aPattern,