diff --git a/dom/canvas/DrawTargetWebgl.cpp b/dom/canvas/DrawTargetWebgl.cpp index 3da73d006d1c..6055fa72e17f 100644 --- a/dom/canvas/DrawTargetWebgl.cpp +++ b/dom/canvas/DrawTargetWebgl.cpp @@ -3406,9 +3406,26 @@ bool SharedContextWebgl::DrawPathAccel( Maybe wgrVB; Maybe strokeVB; if (!aStrokeOptions) { - wgrVB = GeneratePathVertexBuffer( - entry->GetPath(), IntRect(-intBounds.TopLeft(), mViewportSize), - mRasterizationTruncates, outputBuffer, outputBufferCapacity); + if (aPath == mUnitCirclePath) { + auto scaleFactors = pathXform.ScaleFactors(); + if (scaleFactors.AreScalesSame()) { + Point center = pathXform.GetTranslation() - quantBounds.TopLeft(); + float radius = scaleFactors.xScale; + AAStroke::VertexBuffer vb = AAStroke::aa_stroke_filled_circle( + center.x, center.y, radius, (AAStroke::OutputVertex*)outputBuffer, + outputBufferCapacity); + if (!vb.len || (outputBuffer && vb.len > outputBufferCapacity)) { + AAStroke::aa_stroke_vertex_buffer_release(vb); + } else { + strokeVB = Some(vb); + } + } + } + if (!strokeVB) { + wgrVB = GeneratePathVertexBuffer( + entry->GetPath(), IntRect(-intBounds.TopLeft(), mViewportSize), + mRasterizationTruncates, outputBuffer, outputBufferCapacity); + } } else { if (mPathAAStroke && SupportsAAStroke(aPattern, aOptions, *aStrokeOptions, @@ -3490,7 +3507,7 @@ bool SharedContextWebgl::DrawPathAccel( } else { AAStroke::aa_stroke_vertex_buffer_release(strokeVB.ref()); } - if (strokeVB && + if (strokeVB && aStrokeOptions && SupportsAAStroke(aPattern, aOptions, *aStrokeOptions, aAllowStrokeAlpha) == AAStrokeMode::Mask) { // Attempt to generate a stroke mask for path. @@ -3651,24 +3668,30 @@ void DrawTargetWebgl::DrawPath(const Path* aPath, const Pattern& aPattern, } } -// DrawCircle is a more specialized version of DrawPath that attempts to cache -// a unit circle. +// DrawCircleAccel is a more specialized version of DrawPathAccel that attempts +// to cache a unit circle. +bool SharedContextWebgl::DrawCircleAccel(const Point& aCenter, float aRadius, + const Pattern& aPattern, + const DrawOptions& aOptions, + const StrokeOptions* aStrokeOptions) { + // Cache a unit circle and transform it to avoid creating a path repeatedly. + if (!mUnitCirclePath) { + mUnitCirclePath = MakePathForCircle(*mCurrentTarget, Point(0, 0), 1); + } + // Scale and translate the circle to the desired shape. + Matrix circleXform(aRadius, 0, 0, aRadius, aCenter.x, aCenter.y); + return DrawPathAccel(mUnitCirclePath, aPattern, aOptions, aStrokeOptions, + true, nullptr, true, &circleXform); +} + void DrawTargetWebgl::DrawCircle(const Point& aOrigin, float aRadius, const Pattern& aPattern, const DrawOptions& aOptions, const StrokeOptions* aStrokeOptions) { - if (ShouldAccelPath(aOptions, aStrokeOptions)) { - // Cache a unit circle and transform it to avoid creating a path repeatedly. - if (!mUnitCirclePath) { - mUnitCirclePath = MakePathForCircle(*this, Point(0, 0), 1); - } - // Scale and translate the circle to the desired shape. - Matrix circleXform(aRadius, 0, 0, aRadius, aOrigin.x, aOrigin.y); - if (mSharedContext->DrawPathAccel(mUnitCirclePath, aPattern, aOptions, - aStrokeOptions, true, nullptr, true, - &circleXform)) { - return; - } + if (ShouldAccelPath(aOptions, aStrokeOptions) && + mSharedContext->DrawCircleAccel(aOrigin, aRadius, aPattern, aOptions, + aStrokeOptions)) { + return; } MarkSkiaChanged(aOptions); diff --git a/dom/canvas/DrawTargetWebgl.h b/dom/canvas/DrawTargetWebgl.h index f8225e4f9be5..7bc1a83abb59 100644 --- a/dom/canvas/DrawTargetWebgl.h +++ b/dom/canvas/DrawTargetWebgl.h @@ -219,6 +219,9 @@ class SharedContextWebgl : public mozilla::RefCounted, // value to restore it to when exiting the scope. Maybe mTlsScope; + // Cached unit circle path + RefPtr mUnitCirclePath; + bool Initialize(); bool CreateShaders(); void ResetPathVertexBuffer(bool aChanged = true); @@ -308,6 +311,10 @@ class SharedContextWebgl : public mozilla::RefCounted, bool aCacheable = true, const Matrix* aPathXform = nullptr); + bool DrawCircleAccel(const Point& aCenter, float aRadius, + const Pattern& aPattern, const DrawOptions& aOptions, + const StrokeOptions* aStrokeOptions = nullptr); + bool DrawGlyphsAccel(ScaledFont* aFont, const GlyphBuffer& aBuffer, const Pattern& aPattern, const DrawOptions& aOptions, const StrokeOptions* aStrokeOptions, @@ -386,9 +393,6 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr { RefPtr mSnapshotTexture; - // Cached unit circle path - RefPtr mUnitCirclePath; - // Store a log of clips currently pushed so that they can be used to init // the clip state of temporary DTs. struct ClipStack { diff --git a/gfx/src/AAStroke.h b/gfx/src/AAStroke.h index 685cf6064748..be6d0e7e4cd6 100644 --- a/gfx/src/AAStroke.h +++ b/gfx/src/AAStroke.h @@ -40,6 +40,9 @@ void aa_stroke_curve_to(Stroker* s, float c1x, float c1y, float c2x, float c2y, float x, float y, bool end); void aa_stroke_close(Stroker* s); VertexBuffer aa_stroke_finish(Stroker* s); +VertexBuffer aa_stroke_filled_circle(float cx, float cy, float radius, + OutputVertex* output_ptr = nullptr, + size_t output_capacity = 0); void aa_stroke_vertex_buffer_release(VertexBuffer vb); void aa_stroke_release(Stroker* s); };