canvas: Add vello backend (#36821)

Add vello backend by implementing Backend traits in canvas crate (so
this lives in canvas_paint_thread - embedded process). Current
implementation uses normal wgpu, so we block on GPU work. Vello backend
is gated behind `vello` feature and `dom_canvas_vello_enabled` pref.

Feature-wise this backend is on on par with raqote (sometimes better
sometimes worse), but performance wise it's worse.

## Known vello problems:

- image roundtrip does not work (fixed in
https://github.com/linebender/vello/pull/974)
- https://github.com/linebender/vello/issues/1066 (fixed)
- clip layers are not working properly:
https://github.com/linebender/vello/issues/1061
  - `/html/canvas/element/pixel-manipulation/2d.imageData.put.*`
  - `/html/canvas/element/path-objects/2d.path.clip.intersect.html`
- https://github.com/linebender/vello/issues/1056
-
`/html/canvas/element/fill-and-stroke-styles/2d.gradient.interpolate.coloralpha.html`
- `kurbo::Cap::Butt` is defect (only visible with big lineWidth)
https://github.com/linebender/vello/issues/1063
  - `/html/canvas/element/line-styles/2d.line.cross.html`
  - `/html/canvas/element/line-styles/2d.line.miter.acute.html`
- other lack of strong correct problems
(https://github.com/linebender/vello/issues/1063#issuecomment-2998084736):
  - `/html/canvas/element/path-objects/2d.path.rect.selfintersect.html`
- There is currently no way to do put image properly in vello as we
would need to ignore all clips and other stuff (we try to work around
this on best effort basis)
https://github.com/linebender/vello/issues/1088
  - `/html/canvas/element/pixel-manipulation/2d.imageData.put.*`
- precision problems
  - `/html/canvas/element/path-objects/2d.path.stroke.scale2.html`
  - `/html/canvas/element/path-objects/2d.path.arc.scale.1.html`

## Known servo problems

- bad performance due to blocking on GPU work
  - some get/put intensive tests `TIMEOUT`
- proper shadow support (non-blocker as we already are living without it
now)
- support for rect shadow is there but unimplemented currently as that's
the state in raqote

Testing: `mach try vello` will run normal WPT (with raqote) +
vello_canvas subsuite that runs only on `/html/canvas/element`. All
subsuite expectations are stored separately.
Fixes: #36823
Fixes: #35230

---------

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
sagudev 2025-07-26 06:53:10 +02:00 committed by GitHub
parent c2ed599eb1
commit d678901122
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
49 changed files with 1779 additions and 165 deletions

View file

@ -1,2 +1,3 @@
[2d.composite.grid.no_filter.no_shadow.drawImage.html]
expected: FAIL
expected:
if subsuite == "": FAIL

View file

@ -1,2 +1,3 @@
[2d.composite.grid.no_filter.no_shadow.fillRect.html]
expected: FAIL
expected:
if subsuite == "": FAIL

View file

@ -1,2 +1,3 @@
[2d.composite.grid.no_filter.no_shadow.pattern.html]
expected: FAIL
expected:
if subsuite == "": FAIL

View file

@ -0,0 +1,5 @@
[2d.gradient.interpolate.coloralpha.html]
[Canvas test: 2d.gradient.interpolate.coloralpha]
bug: https://github.com/linebender/vello/issues/1056
expected:
if subsuite == "vello_canvas": FAIL

View file

@ -1,4 +1,4 @@
[2d.gradient.radial.cone.behind.html]
[Canvas test: 2d.gradient.radial.cone.behind]
expected: FAIL
expected:
if subsuite == "": FAIL

View file

@ -1,4 +1,4 @@
[2d.gradient.radial.cone.shape2.html]
[Canvas test: 2d.gradient.radial.cone.shape2]
expected: FAIL
expected:
if subsuite == "": FAIL

View file

@ -1,4 +1,4 @@
[2d.gradient.radial.outside2.html]
[Canvas test: 2d.gradient.radial.outside2]
expected: FAIL
expected:
if subsuite == "": FAIL

View file

@ -1,4 +1,4 @@
[2d.gradient.radial.outside3.html]
[Canvas test: 2d.gradient.radial.outside3]
expected: FAIL
expected:
if subsuite == "": FAIL

View file

@ -0,0 +1,4 @@
[2d.layer.globalCompositeOperation.html]
expected:
if subsuite == "vello_canvas": TIMEOUT
PASS

View file

@ -0,0 +1,5 @@
[2d.line.cross.html]
[Canvas test: 2d.line.cross]
bug: https://github.com/linebender/vello/issues/1063
expected:
if subsuite == "vello_canvas": FAIL

View file

@ -0,0 +1,5 @@
[2d.line.miter.acute.html]
[Miter joins are drawn correctly with acute angles]
bug: https://github.com/linebender/vello/issues/1063
expected:
if subsuite == "vello_canvas": FAIL

View file

@ -1,3 +1,15 @@
[canvas-createImageBitmap-resize.html]
expected:
if subsuite == "vello_canvas": TIMEOUT
[createImageBitmap from a HTMLImageElement of svg with no specified size with resize option.]
expected: FAIL
expected:
if subsuite == "vello_canvas": TIMEOUT
FAIL
[createImageBitmap from an ImageBitmap with resize option.]
expected:
if subsuite == "vello_canvas": NOTRUN
[createImageBitmap from an ImageData with resize option.]
expected:
if subsuite == "vello_canvas": NOTRUN

View file

@ -1,4 +1,6 @@
[createImageBitmap-drawImage.html]
expected:
if subsuite == "vello_canvas": TIMEOUT
[createImageBitmap from a vector HTMLImageElement resized, and drawImage on the created ImageBitmap]
expected: FAIL
@ -73,3 +75,39 @@
[createImageBitmap from a vector HTMLImageElement scaled up, and drawImage on the created ImageBitmap]
expected: FAIL
[createImageBitmap from an ImageBitmap scaled down, and drawImage on the created ImageBitmap]
expected:
if subsuite == "vello_canvas": [PASS, TIMEOUT]
[createImageBitmap from an ImageBitmap scaled up, and drawImage on the created ImageBitmap]
expected:
if subsuite == "vello_canvas": [TIMEOUT, NOTRUN]
[createImageBitmap from an ImageBitmap resized, and drawImage on the created ImageBitmap]
expected:
if subsuite == "vello_canvas": NOTRUN
[createImageBitmap from an ImageBitmap with negative sw/sh, and drawImage on the created ImageBitmap]
expected:
if subsuite == "vello_canvas": NOTRUN
[createImageBitmap from a Blob, and drawImage on the created ImageBitmap]
expected:
if subsuite == "vello_canvas": NOTRUN
[createImageBitmap from a Blob scaled down, and drawImage on the created ImageBitmap]
expected:
if subsuite == "vello_canvas": NOTRUN
[createImageBitmap from a Blob scaled up, and drawImage on the created ImageBitmap]
expected:
if subsuite == "vello_canvas": NOTRUN
[createImageBitmap from a Blob resized, and drawImage on the created ImageBitmap]
expected:
if subsuite == "vello_canvas": NOTRUN
[createImageBitmap from a Blob with negative sw/sh, and drawImage on the created ImageBitmap]
expected:
if subsuite == "vello_canvas": NOTRUN

View file

@ -0,0 +1,3 @@
[canvas.2d.lang.dynamic.html]
expected:
if subsuite == "vello_canvas": [PASS, FAIL]

View file

@ -1,4 +1,6 @@
[canvas-display-p3-drawImage-ImageBitmap-Blob.html]
expected:
if subsuite == "vello_canvas": TIMEOUT
[sRGB-FF0000FF.png, Context srgb, ImageData display-p3, cropSource=false]
expected: FAIL

View file

@ -0,0 +1,3 @@
[canvas-display-p3-drawImage-ImageBitmap-ImageBitmap.html]
expected:
if subsuite == "vello_canvas": TIMEOUT

View file

@ -1,4 +1,6 @@
[canvas-display-p3-drawImage-ImageBitmap-cloned.html]
expected:
if subsuite == "vello_canvas": TIMEOUT
[sRGB-FF0000FF.png, Context srgb, ImageData display-p3, cropSource=false]
expected: FAIL

View file

@ -1,4 +1,6 @@
[canvas-display-p3-drawImage-ImageBitmap-image.html]
expected:
if subsuite == "vello_canvas": TIMEOUT
[sRGB-FF0000FF.png, Context srgb, ImageData display-p3, cropSource=false]
expected: FAIL

View file

@ -1,4 +1,6 @@
[canvas-display-p3-pattern-image.html]
expected:
if subsuite == "vello_canvas": TIMEOUT
[sRGB-FF0000FF.png, Context srgb, ImageData display-p3]
expected: FAIL

View file

@ -0,0 +1,4 @@
[2d.path.arc.scale.1.html]
[Non-uniformly scaled arcs are the right shape]
expected:
if subsuite == "vello_canvas": FAIL

View file

@ -1,4 +1,4 @@
[2d.path.arc.scale.2.html]
[Highly scaled arcs are the right shape]
expected: FAIL
expected:
if subsuite == "": FAIL

View file

@ -1,4 +1,4 @@
[2d.path.arc.selfintersect.1.html]
[arc() with lineWidth > 2*radius is drawn sensibly]
expected: FAIL
expected:
if subsuite == "": FAIL

View file

@ -1,4 +1,4 @@
[2d.path.arc.selfintersect.2.html]
[arc() with lineWidth > 2*radius is drawn sensibly]
expected: FAIL
expected:
if subsuite == "": FAIL

View file

@ -1,4 +1,4 @@
[2d.path.arc.shape.3.html]
[arc() from 0 to -pi/2 does not draw anything in the wrong quadrant]
expected: FAIL
expected:
if subsuite == "": FAIL

View file

@ -1,4 +1,4 @@
[2d.path.arc.shape.4.html]
[arc() from 0 to -pi/2 draws stuff in the right quadrant]
expected: FAIL
expected:
if subsuite == "": FAIL

View file

@ -0,0 +1,5 @@
[2d.path.clip.intersect.html]
[Canvas test: 2d.path.clip.intersect]
bug: https://github.com/linebender/vello/issues/1061
expected:
if subsuite == "vello_canvas": FAIL

View file

@ -0,0 +1,5 @@
[2d.path.rect.selfintersect.html]
[Canvas test: 2d.path.rect.selfintersect]
bug: https://github.com/linebender/vello/issues/1063#issuecomment-2998084736
expected:
if subsuite == "vello_canvas": FAIL

View file

@ -0,0 +1,4 @@
[2d.path.stroke.scale2.html]
[Stroke line widths are scaled by the current transformation matrix]
expected:
if subsuite == "vello_canvas": FAIL

View file

@ -0,0 +1,5 @@
[2d.imageData.put.clip.html]
[putImageData() is not affected by clipping regions]
bug: https://github.com/linebender/vello/issues/1088
expected:
if subsuite == "vello_canvas": FAIL

View file

@ -0,0 +1,5 @@
[2d.imageData.put.dirty.negative.html]
[putImageData() handles negative-sized dirty rectangles correctly]
bug: https://github.com/linebender/vello/issues/1061
expected:
if subsuite == "vello_canvas": FAIL

View file

@ -0,0 +1,5 @@
[2d.imageData.put.dirty.rect1.html]
[putImageData() only modifies areas inside the dirty rectangle, using width and height]
bug: https://github.com/linebender/vello/issues/1061
expected:
if subsuite == "vello_canvas": FAIL

View file

@ -0,0 +1,5 @@
[2d.imageData.put.dirty.rect2.html]
[putImageData() only modifies areas inside the dirty rectangle, using x and y]
bug: https://github.com/linebender/vello/issues/1061
expected:
if subsuite == "vello_canvas": FAIL

View file

@ -1,4 +1,4 @@
[2d.imageData.put.unchanged.html]
[putImageData(getImageData(...), ...) has no effect]
expected: FAIL
expected:
if subsuite == "": FAIL

View file

@ -1,4 +1,4 @@
[2d.transformation.scale.large.html]
[scale() with large scale factors works]
expected: FAIL
expected:
if subsuite == "": FAIL

View file

@ -1,2 +1,3 @@
[2d.layer.globalCompositeOperation.html]
expected: FAIL
expected:
FAIL

8
tests/wpt/vello_canvas_subsuite.json vendored Normal file
View file

@ -0,0 +1,8 @@
{
"vello_canvas": {
"config": {
"binary_args": ["--pref", "dom_canvas_vello_enabled"]
},
"include": ["/html/canvas/element"]
}
}