Open Bug 1452829 Opened 6 years ago Updated 1 year ago

Canvas is not optimized for clipping to rectangles

Categories

(Core :: Graphics, enhancement, P3)

enhancement

Tracking

()

Performance Impact low

People

(Reporter: mconley, Unassigned)

References

(Blocks 1 open bug)

Details

(Whiteboard: [gfx-noted])

Attachments

(1 file, 2 obsolete files)

jrmuizel and I discovered this during Episode 23 of The Joy of Profiling[1].

According to jrmuizel, this is where we should check to see if the mPath is a rect, and then use PushClipRect instead of PushClip, which should be cheaper:

https://searchfox.org/mozilla-central/rev/d0413b711da4dac72b237d0895daba2537f1514c/dom/canvas/CanvasRenderingContext2D.cpp#3401-3407

[1]: https://air.mozilla.org/the-joy-of-profiling-episode-23/
Blocks: 1448895
Hi Maire!  If we've got any layout engineers looking for things to work on, this might be a good optimization to point them at.  (Technically in DOM, but on the fringes of layout/graphics.)
Flags: needinfo?(mreavy)
Whiteboard: [qf] → [qf:p3][qf:f64]
Plus this is super easy.
Priority: -- → P3
Whiteboard: [qf:p3][qf:f64] → [qf:p3][qf:f64][gfx-noted]
Flags: needinfo?(mreavy)
Hello! I'd like to work on this, can I get this assigned to me?
Sorry, did I miss anything simple? I don't actually see a method that returns whether or not a gfx::Path is a rectangle :/
There's no method like that. It should be possible to track this similar to how gfxContext does it in: https://searchfox.org/mozilla-central/source/gfx/thebes/gfxContext.cpp#272

i.e. add mPathIsRect and mRect members to CanvasRenderingContext2D and track the state in a similar way.
Assignee: nobody → dwlsalmeida
Attachment #8970558 - Flags: review?(jmuizelaar)
Attachment #8970558 - Attachment is obsolete: true
Attachment #8970558 - Flags: review?(jmuizelaar)
Attachment #8970562 - Flags: review?(jmuizelaar)
Comment on attachment 8970562 [details] [diff] [review]
0001-bug-1452829-optimize-for-clipping-to-rectangles.patch

Review of attachment 8970562 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/canvas/CanvasRenderingContext2D.cpp
@@ +3542,5 @@
>      mDSPathBuilder->LineTo(mTarget->GetTransform().TransformPoint(Point(aX, aY + aH)));
>      mDSPathBuilder->Close();
>    }
> +
> +  mPathIsRect = true;

mPathIsRect never gets set to false. You'll need to do that when the path isn't a rect anymore.

::: dom/canvas/CanvasRenderingContext2D.h
@@ +848,4 @@
>    RefPtr<mozilla::gfx::PathBuilder> mDSPathBuilder;
>    RefPtr<mozilla::gfx::PathBuilder> mPathBuilder;
>    bool mPathTransformWillUpdate;
> +  bool mPathIsRect;

You'll need to initialize mPathIsRect to false in the constructor of CanvasRenderingContext2D.
Attachment #8970562 - Flags: review?(jmuizelaar) → review-
(In reply to Jeff Muizelaar [:jrmuizel] from comment #8)
> Comment on attachment 8970562 [details] [diff] [review]
> 0001-bug-1452829-optimize-for-clipping-to-rectangles.patch
> 
> Review of attachment 8970562 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> ::: dom/canvas/CanvasRenderingContext2D.cpp
> @@ +3542,5 @@
> >      mDSPathBuilder->LineTo(mTarget->GetTransform().TransformPoint(Point(aX, aY + aH)));
> >      mDSPathBuilder->Close();
> >    }
> > +
> > +  mPathIsRect = true;
> 
> mPathIsRect never gets set to false. You'll need to do that when the path
> isn't a rect anymore.
> 

Most of the methods in which mPathIsRect was set to false in gfxContext aren't present in CanvasRenderingContext2D. Should I assume the path isn't a rect if there was a call to either Arc, ArcTo or Ellipse?

By the way, where can I educate myself some more about this topic?
So in the gfxContext the main function that clears mPathIsRect is EnsurePathBuilder().

We can use EnsureWritablePath() for the same mechanism. i.e. Rect() will look something like:

  if (!mPathBuilder && !mPathIsRect) {
    mPathIsRect = true;
    mRect = rec;
    return;
  }

  EnsureWritablePath();

  if (mPathBuilder) {
    mPathBuilder->MoveTo(Point(aX, aY));
    mPathBuilder->LineTo(Point(aX + aW, aY));
    mPathBuilder->LineTo(Point(aX + aW, aY + aH));
    mPathBuilder->LineTo(Point(aX, aY + aH));
    mPathBuilder->Close();
  } else {
    mDSPathBuilder->MoveTo(mTarget->GetTransform().TransformPoint(Point(aX, aY)));
    mDSPathBuilder->LineTo(mTarget->GetTransform().TransformPoint(Point(aX + aW, aY)));
    mDSPathBuilder->LineTo(mTarget->GetTransform().TransformPoint(Point(aX + aW, aY + aH)));
    mDSPathBuilder->LineTo(mTarget->GetTransform().TransformPoint(Point(aX, aY + aH)));
    mDSPathBuilder->Close();
  }


And EnsureWritablePath() will need an additional piece like the following to make sure we end up with the rectangle in the path:

if (mPathIsRect) {
  if (mPathBuilder) {
    mPathBuilder->MoveTo(Point(aX, aY));
    mPathBuilder->LineTo(Point(aX + aW, aY));
    mPathBuilder->LineTo(Point(aX + aW, aY + aH));
    mPathBuilder->LineTo(Point(aX, aY + aH));
    mPathBuilder->Close();
  } else {
    mDSPathBuilder->MoveTo(mTarget->GetTransform().TransformPoint(Point(aX, aY)));
    mDSPathBuilder->LineTo(mTarget->GetTransform().TransformPoint(Point(aX + aW, aY)));
    mDSPathBuilder->LineTo(mTarget->GetTransform().TransformPoint(Point(aX + aW, aY + aH)));
    mDSPathBuilder->LineTo(mTarget->GetTransform().TransformPoint(Point(aX, aY + aH)));
    mDSPathBuilder->Close();
  }
}

If this doesn't make sense I can elaborate further. Just ask/need info me. Hopefully, it won't take so long to respond.
Jeff,

See if that's what you're asking.


I did not get this part:

>>And EnsureWritablePath() will need an additional piece like the following to make sure we end up with the rectangle in the path:

Why would this method ever need to make sure we end up with a rectangle? mPathIsRect is already set on CanvasRenderingContext2D::Rect
Attachment #8970562 - Attachment is obsolete: true
Flags: needinfo?(jmuizelaar)
Also, should I assign mRect to something else when mPathIsRect gets set to false?
(In reply to Daniel  Almeida from comment #11
> 
> Why would this method ever need to make sure we end up with a rectangle?
> mPathIsRect is already set on CanvasRenderingContext2D::Rect

You're current code will break something that does this:

ctx.rect(0, 0, 5, 5);
ctx.rect(10, 10, 10, 10);
ctx.fill();

This should fill both rectangles. With your code the first rectangle will not be included in the path.
Flags: needinfo?(jmuizelaar)
(In reply to Daniel  Almeida from comment #12)
> Also, should I assign mRect to something else when mPathIsRect gets set to
> false?

I don't think that will be necessary.
Whiteboard: [qf:p3][qf:f64][gfx-noted] → [qf:p3:f64][gfx-noted]
Whiteboard: [qf:p3:f64][gfx-noted] → [qf:p3][gfx-noted]
Performance Impact: --- → P3
Whiteboard: [qf:p3][gfx-noted] → [gfx-noted]

The bug assignee didn't login in Bugzilla in the last 7 months.
:bhood, could you have a look please?
For more information, please visit auto_nag documentation.

Assignee: dwlsalmeida → nobody
Flags: needinfo?(bhood)
Flags: needinfo?(bhood)
Severity: normal → S3
Severity: S3 → N/A
See Also: → 1804952
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: