Open Bug 1490123 Opened 6 years ago Updated 2 years ago

Consider adding PushFilterLayer/PopFilterLayer

Categories

(Core :: Graphics, enhancement, P3)

63 Branch
enhancement

Tracking

()

People

(Reporter: jrmuizel, Unassigned)

References

Details

(Whiteboard: [gfx-noted])

This would help us with tiled content because we could only draw the pieces we need.
Blocks: 1454810
Priority: -- → P3
Whiteboard: [gfx-noted]
mstange, I thought you wrote an elaborated comment about our plans here?
Flags: needinfo?(mstange)

I don't remember writing a comment, so I'll write one here.

At the moment, if you have some content that you want to apply a filter to, you have to do the following:

  1. Allocate an intermediate DrawTarget of an appropriate size. Draw the contents to that DrawTarget.
  2. Get a snapshot of that DrawTarget.
  3. Create Moz2D FilterNodes for your filter and hook them into each other.
  4. Set the snapshot from step 2 as the input of the first filter in your filter chain. (In some SVG filter graphs it is possible that multiple FilterNodes need to take that snapshot as their input.)
  5. Draw the final FilterNode of the graph into the destination DrawTarget. This processes the entire graph.

This means drawing filtered content works very differently from drawing transformed or blended content. With transforms, it goes like this:

  1. Set the transform for your content on the destination draw target.
  2. Draw your content to the destination draw target.
  3. Unset the transform again.

With opacity or blending, it goes like this:

  1. Call PushLayer on the destination draw target.
  2. Draw your content to the destination draw target.
  3. Call PopLayer.

The transform / PushLayer approach has a couple of advantages:

  • The caller does not need to reason about the size of the intermediate surface.
  • When recording, the recording is independent of the size of the intermediate surface. This means the recording can be played back on differently-sized destination DrawTargets which may require differently-sized intermediate surfaces. (This helps tiled blobs.)
  • The drawing of the content happens on the destination DrawTarget. This allows the blob invalidation code to record and merge "items" within the content separately, and to reuse parts of the recording if only some of the content items changed.
  • The "surrounding" calls, e.g. PushLayer/PopLayer, are separate calls on the destination DrawTarget. This means that it's easy for the blob invalidation code to put the recordings for these calls into separate "items" that can be merged independently.

It would be great if we could have these advantages for filter drawing, too.

I'm envisioning a solution that could be used as follows:

  1. Create the FilterNodes for your filter.
  2. Give the FilterNode at the start of the chain a special marker input.
  3. Call PushFilterLayer with the final filter node of the graph.
  4. Draw the content on the destination DrawTarget.
  5. Call PopFilterLayer.

I'm not entirely sure what form the "special marker input" should take. Another thing we need to think about is coordinate spaces: filter nodes currently assume a "filter space" which is different from the DrawTarget's user space.

Flags: needinfo?(mstange)

For reference Skia works something like this:

  • SkImageFilter is the base class for all filters.
  • It has a virtual onFilterImage() method that takes src image as parameter.
  • If the filter has a connected input, it should recurse on that input and use that in place of src.

You can set a SkImageFilter as part of the SkPaint and so filter painting looks something like
saveLayer(imagefilter)
drawStuff
restore()

Blocks: 1494924
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.