Bug 1937751 - Remember AAStroke mode when caching stroked path. r=jrmuizel

Differential Revision: https://phabricator.services.mozilla.com/D232781
This commit is contained in:
Lee Salzman
2024-12-21 10:42:28 +00:00
parent cb6f41dbef
commit f389de744d
5 changed files with 122 additions and 34 deletions

View File

@@ -2822,13 +2822,11 @@ static inline bool HasMatchingScale(const Matrix& aTransform1,
// Determines if an existing path cache entry matches an incoming path and
// pattern.
inline bool PathCacheEntry::MatchesPath(const QuantizedPath& aPath,
const Pattern* aPattern,
const StrokeOptions* aStrokeOptions,
const Matrix& aTransform,
const IntRect& aBounds,
const Point& aOrigin, HashNumber aHash,
float aSigma) {
inline bool PathCacheEntry::MatchesPath(
const QuantizedPath& aPath, const Pattern* aPattern,
const StrokeOptions* aStrokeOptions, AAStrokeMode aStrokeMode,
const Matrix& aTransform, const IntRect& aBounds, const Point& aOrigin,
HashNumber aHash, float aSigma) {
return aHash == mHash && HasMatchingScale(aTransform, mTransform) &&
// Ensure the clipped relative bounds fit inside those of the entry
aBounds.x - aOrigin.x >= mBounds.x - mOrigin.x &&
@@ -2841,12 +2839,14 @@ inline bool PathCacheEntry::MatchesPath(const QuantizedPath& aPath,
(!aPattern ? !mPattern : mPattern && *aPattern == *mPattern) &&
(!aStrokeOptions
? !mStrokeOptions
: mStrokeOptions && *aStrokeOptions == *mStrokeOptions) &&
: mStrokeOptions && *aStrokeOptions == *mStrokeOptions &&
mAAStrokeMode == aStrokeMode) &&
aSigma == mSigma;
}
PathCacheEntry::PathCacheEntry(QuantizedPath&& aPath, Pattern* aPattern,
StoredStrokeOptions* aStrokeOptions,
AAStrokeMode aStrokeMode,
const Matrix& aTransform, const IntRect& aBounds,
const Point& aOrigin, HashNumber aHash,
float aSigma)
@@ -2855,6 +2855,7 @@ PathCacheEntry::PathCacheEntry(QuantizedPath&& aPath, Pattern* aPattern,
mOrigin(aOrigin),
mPattern(aPattern),
mStrokeOptions(aStrokeOptions),
mAAStrokeMode(aStrokeMode),
mSigma(aSigma) {}
// Attempt to find a matching entry in the path cache. If one isn't found,
@@ -2863,13 +2864,14 @@ PathCacheEntry::PathCacheEntry(QuantizedPath&& aPath, Pattern* aPattern,
// or just reuse the cached texture.
already_AddRefed<PathCacheEntry> PathCache::FindOrInsertEntry(
QuantizedPath aPath, const Pattern* aPattern,
const StrokeOptions* aStrokeOptions, const Matrix& aTransform,
const IntRect& aBounds, const Point& aOrigin, float aSigma) {
const StrokeOptions* aStrokeOptions, AAStrokeMode aStrokeMode,
const Matrix& aTransform, const IntRect& aBounds, const Point& aOrigin,
float aSigma) {
HashNumber hash =
PathCacheEntry::HashPath(aPath, aPattern, aTransform, aBounds, aOrigin);
for (const RefPtr<PathCacheEntry>& entry : GetChain(hash)) {
if (entry->MatchesPath(aPath, aPattern, aStrokeOptions, aTransform, aBounds,
aOrigin, hash, aSigma)) {
if (entry->MatchesPath(aPath, aPattern, aStrokeOptions, aStrokeMode,
aTransform, aBounds, aOrigin, hash, aSigma)) {
return do_AddRef(entry);
}
}
@@ -2888,8 +2890,8 @@ already_AddRefed<PathCacheEntry> PathCache::FindOrInsertEntry(
}
}
RefPtr<PathCacheEntry> entry =
new PathCacheEntry(std::move(aPath), pattern, strokeOptions, aTransform,
aBounds, aOrigin, hash, aSigma);
new PathCacheEntry(std::move(aPath), pattern, strokeOptions, aStrokeMode,
aTransform, aBounds, aOrigin, hash, aSigma);
Insert(entry);
return entry.forget();
}
@@ -3224,12 +3226,6 @@ inline bool DrawTargetWebgl::ShouldAccelPath(
return mWebglValid && SupportsDrawOptions(aOptions) && PrepareContext();
}
enum class AAStrokeMode {
Unsupported,
Geometry,
Mask,
};
// For now, we only directly support stroking solid color patterns to limit
// artifacts from blending of overlapping geometry generated by AAStroke. Other
// types of patterns may be partially supported by rendering to a temporary
@@ -3403,6 +3399,11 @@ bool SharedContextWebgl::DrawPathAccel(
: (aPattern.GetType() == PatternType::COLOR
? Some(static_cast<const ColorPattern&>(aPattern).mColor)
: Nothing());
AAStrokeMode aaStrokeMode =
aStrokeOptions && mPathAAStroke
? SupportsAAStroke(aPattern, aOptions, *aStrokeOptions,
aAllowStrokeAlpha)
: AAStrokeMode::Unsupported;
// Look for an existing path cache entry, if possible, or otherwise create
// one. If the draw request is not cacheable, then don't create an entry.
RefPtr<PathCacheEntry> entry;
@@ -3420,7 +3421,7 @@ bool SharedContextWebgl::DrawPathAccel(
}
entry = mPathCache->FindOrInsertEntry(
std::move(*qp), color ? nullptr : &aPattern, aStrokeOptions,
currentTransform, intBounds, quantizedOrigin,
aaStrokeMode, currentTransform, intBounds, quantizedOrigin,
aShadow ? aShadow->mSigma : -1.0f);
if (!entry) {
return false;
@@ -3502,9 +3503,7 @@ bool SharedContextWebgl::DrawPathAccel(
mRasterizationTruncates, outputBuffer, outputBufferCapacity);
}
} else {
if (mPathAAStroke &&
SupportsAAStroke(aPattern, aOptions, *aStrokeOptions,
aAllowStrokeAlpha) != AAStrokeMode::Unsupported) {
if (aaStrokeMode != AAStrokeMode::Unsupported) {
auto scaleFactors = currentTransform.ScaleFactors();
if (scaleFactors.AreScalesSame()) {
strokeVB = GenerateStrokeVertexBuffer(
@@ -3582,9 +3581,7 @@ bool SharedContextWebgl::DrawPathAccel(
} else {
AAStroke::aa_stroke_vertex_buffer_release(strokeVB.ref());
}
if (strokeVB && aStrokeOptions &&
SupportsAAStroke(aPattern, aOptions, *aStrokeOptions,
aAllowStrokeAlpha) == AAStrokeMode::Mask) {
if (strokeVB && aaStrokeMode == AAStrokeMode::Mask) {
// Attempt to generate a stroke mask for path.
if (RefPtr<TextureHandle> handle =
DrawStrokeMask(vertexRange, intBounds.Size())) {

View File

@@ -389,6 +389,12 @@ struct PathVertexRange {
bool IsValid() const { return mLength > 0; }
};
enum class AAStrokeMode {
Unsupported,
Geometry,
Mask,
};
// PathCacheEntry stores a rasterized version of a supplied path with a given
// pattern.
class PathCacheEntry : public CacheEntryImpl<PathCacheEntry> {
@@ -396,14 +402,15 @@ class PathCacheEntry : public CacheEntryImpl<PathCacheEntry> {
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathCacheEntry, override)
PathCacheEntry(QuantizedPath&& aPath, Pattern* aPattern,
StoredStrokeOptions* aStrokeOptions, const Matrix& aTransform,
const IntRect& aBounds, const Point& aOrigin, HashNumber aHash,
float aSigma = -1.0f);
StoredStrokeOptions* aStrokeOptions, AAStrokeMode aStrokeMode,
const Matrix& aTransform, const IntRect& aBounds,
const Point& aOrigin, HashNumber aHash, float aSigma = -1.0f);
bool MatchesPath(const QuantizedPath& aPath, const Pattern* aPattern,
const StrokeOptions* aStrokeOptions,
const Matrix& aTransform, const IntRect& aBounds,
const Point& aOrigin, HashNumber aHash, float aSigma);
AAStrokeMode aStrokeMode, const Matrix& aTransform,
const IntRect& aBounds, const Point& aOrigin,
HashNumber aHash, float aSigma);
static HashNumber HashPath(const QuantizedPath& aPath,
const Pattern* aPattern, const Matrix& aTransform,
@@ -428,6 +435,8 @@ class PathCacheEntry : public CacheEntryImpl<PathCacheEntry> {
UniquePtr<Pattern> mPattern;
// The StrokeOptions used for stroked paths, if applicable
UniquePtr<StoredStrokeOptions> mStrokeOptions;
// The AAStroke mode used for rendering a stroked path.
AAStrokeMode mAAStrokeMode = AAStrokeMode::Unsupported;
// The shadow blur sigma
float mSigma;
// If the path has cached geometry in the vertex buffer.
@@ -440,8 +449,9 @@ class PathCache : public CacheImpl<PathCacheEntry, true> {
already_AddRefed<PathCacheEntry> FindOrInsertEntry(
QuantizedPath aPath, const Pattern* aPattern,
const StrokeOptions* aStrokeOptions, const Matrix& aTransform,
const IntRect& aBounds, const Point& aOrigin, float aSigma = -1.0f);
const StrokeOptions* aStrokeOptions, AAStrokeMode aStrokeMode,
const Matrix& aTransform, const IntRect& aBounds, const Point& aOrigin,
float aSigma = -1.0f);
void ClearVertexRanges();
};

View File

@@ -0,0 +1,28 @@
<canvas id=dest height="768" width="1024"></canvas>
<script>
var c=document.getElementById("dest");
var ctx=c.getContext("2d");
ctx.setTransform(1,0,0,1,0,0);
ctx.transform(1,0,0,1,512,384);
ctx.globalAlpha=0.5;
ctx.beginPath();
ctx.moveTo(0,324);
ctx.lineTo(239.66624210637872,84.6706564587356);
ctx.lineTo(78.17543855489896,-213.5804865149861);
ctx.lineTo(-136.36617853185373,-262.93052317185794);
ctx.lineTo(-195.91764235680165,51.60583806061618);
ctx.lineTo(0,324);
ctx.closePath();
ctx.fillStyle="rgba(0,0,0,0)";
ctx.fill();
ctx.lineWidth=40;
ctx.lineCap="butt";
ctx.lineJoin="miter";
ctx.miterLimit="10";
ctx.strokeStyle="#555555";
ctx.stroke();
</script>

View File

@@ -0,0 +1,52 @@
<canvas id=dest height="768" width="1024"></canvas>
<script>
var c=document.getElementById("dest");
var ctx=c.getContext("2d");
ctx.setTransform(1,0,0,1,0,0);
ctx.transform(1,0,0,1,512,384);
ctx.globalAlpha=1;
ctx.beginPath();
ctx.moveTo(0,324);
ctx.lineTo(239.66624210637872,84.6706564587356);
ctx.lineTo(78.17543855489896,-213.5804865149861);
ctx.lineTo(-136.36617853185373,-262.93052317185794);
ctx.lineTo(-195.91764235680165,51.60583806061618);
ctx.lineTo(0,324);
ctx.closePath();
ctx.fillStyle="rgba(0,0,0,0)";
ctx.fill();
ctx.lineWidth=40;
ctx.lineCap="butt";
ctx.lineJoin="miter";
ctx.miterLimit="10";
ctx.strokeStyle="#555555";
ctx.stroke();
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,1024,768);
ctx.transform(1,0,0,1,512,384);
ctx.globalAlpha=0.5;
ctx.beginPath();
ctx.moveTo(0,324);
ctx.lineTo(239.66624210637872,84.6706564587356);
ctx.lineTo(78.17543855489896,-213.5804865149861);
ctx.lineTo(-136.36617853185373,-262.93052317185794);
ctx.lineTo(-195.91764235680165,51.60583806061618);
ctx.lineTo(0,324);
ctx.closePath();
ctx.fillStyle="rgba(0,0,0,0)";
ctx.fill();
ctx.lineWidth=40;
ctx.lineCap="butt";
ctx.lineJoin="miter";
ctx.miterLimit="10";
ctx.strokeStyle="#555555";
ctx.stroke();
</script>

View File

@@ -246,3 +246,4 @@ skip-if(isDebugBuild) == draw-large-image.html draw-large-image-ref.html
== 1758968-1.html 1758968-1-ref.html
== 1768521-1.html 1768521-1-ref.html
== 1851943.html 1851943-ref.html
== 1937751-cached-stroked-paths-1.html 1937751-cached-stroked-paths-1-ref.html