Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't send empty canvases to WebRender #26065

Merged
merged 1 commit into from Apr 3, 2020
Merged

Conversation

@dralley
Copy link
Contributor

dralley commented Mar 31, 2020

If any dimension of a canvas is 0, don't try to display it as it causes
problems inside webrender.

Minimal test case available here: #21411 (comment)


  • ./mach build -d does not report any errors
  • ./mach test-tidy does not report any errors
  • These changes fix #___ (GitHub issue number if applicable)
  • There are tests for these changes OR
  • These changes do not require tests because ___
@highfive
Copy link

highfive commented Mar 31, 2020

Thanks for the pull request, and welcome! The Servo team is excited to review your changes, and you should hear from @jdm (or someone else) soon.

@highfive
Copy link

highfive commented Mar 31, 2020

Heads up! This PR modifies the following files:

  • @emilio: components/layout/display_list/builder.rs
@highfive
Copy link

highfive commented Mar 31, 2020

warning Warning warning

  • These commits modify layout code, but no tests are modified. Please consider adding a test!
@dralley
Copy link
Contributor Author

dralley commented Mar 31, 2020

Cannot run test-tidy locally because Fedora 31 is Python 3 only

@dralley dralley force-pushed the dralley:fix-motionmark branch 3 times, most recently from 7d7fb79 to f049a3b Mar 31, 2020
@cbrewster
Copy link
Member

cbrewster commented Mar 31, 2020

Since we have a minimal test case, it would be nice to add a test that makes sure we don't regress on this panic.

Since this will be a servo-specific test, I would put it here: tests/wpt/mozilla/tests/mozilla/canvas

@dralley
Copy link
Contributor Author

dralley commented Mar 31, 2020

There's no issue specifically relating to zero-sized-canvas panic -- should I create one specifically to reference in a comment, or just reference the motionmark issue?

@cbrewster
Copy link
Member

cbrewster commented Mar 31, 2020

Referencing the motionmark issue would be fine since that's where most the discussion is at regarding this fix.

@dralley dralley force-pushed the dralley:fix-motionmark branch from f049a3b to c674ce2 Mar 31, 2020
@cbrewster
Copy link
Member

cbrewster commented Mar 31, 2020

Can you run ./mach update-manifest and push, that will update the test manifest file.

Once that is done, this looks good to me. Thanks again!

@dralley dralley force-pushed the dralley:fix-motionmark branch from c674ce2 to 468814a Mar 31, 2020
@cbrewster
Copy link
Member

cbrewster commented Mar 31, 2020

@bors-servo
Copy link
Contributor

bors-servo commented Mar 31, 2020

📌 Commit 468814a has been approved by cbrewster

@highfive highfive assigned cbrewster and unassigned jdm Mar 31, 2020
@gterzian
Copy link
Member

gterzian commented Mar 31, 2020

I'm pretty sure you want to apply the fix also to layout_2020. cc @SimonSapin

@cbrewster
Copy link
Member

cbrewster commented Mar 31, 2020

@gterzian ah good catch!
@bors-servo r-

@dralley dralley force-pushed the dralley:fix-motionmark branch from 468814a to 9b6aa90 Mar 31, 2020
@dralley dralley force-pushed the dralley:fix-motionmark branch from 9b6aa90 to 26273fb Mar 31, 2020
@dralley
Copy link
Contributor Author

dralley commented Mar 31, 2020

No idea if that is the correct fix for layout 2020, but it seems like a decent guess.

@cbrewster
Copy link
Member

cbrewster commented Mar 31, 2020

Maybe it would make more sense here?

ReplacedContentKind::Canvas(canvas_info) => {
let image_key = match canvas_info.source {
CanvasSource::WebGL(image_key) => image_key,
CanvasSource::Image(ref ipc_renderer) => match *ipc_renderer {
Some(ref ipc_renderer) => {
let ipc_renderer = ipc_renderer.lock().unwrap();
let (sender, receiver) = ipc::channel().unwrap();
ipc_renderer
.send(CanvasMsg::FromLayout(
FromLayoutMsg::SendData(sender),
canvas_info.canvas_id,
))
.unwrap();
receiver.recv().unwrap().image_key
},
None => return vec![],
},
};
vec![Fragment::Image(ImageFragment {
debug_id: DebugId::new(),
style: style.clone(),
rect: Rect {
start_corner: Vec2::zero(),
size,
},
image_key,
})]
},

It might be good to check with someone familiar with layout 2020 canvas.

cc @SimonSapin @ferjm

@@ -411,6 +411,9 @@ where
fn as_canvas(self) -> Option<(CanvasInfo, PhysicalSize<f64>)> {
let node = self.to_threadsafe();
let canvas_data = node.canvas_data()?;
if canvas_data.width == 0 || canvas_data.height == 0 {
return None;

This comment has been minimized.

Copy link
@SimonSapin

SimonSapin Apr 1, 2020

Member

This doesn’t look right: it’ll generate a non-replaced box (as for <div></div>), but we want to generate a replaced box, which might have different layout behavior (even if zero-size). Somewhere under layout_2020/display_list/ would be the right place for this change.

@dralley dralley force-pushed the dralley:fix-motionmark branch from 26273fb to f44050a Apr 2, 2020
@servo-wpt-sync
Copy link
Collaborator

servo-wpt-sync commented Apr 2, 2020

Error syncing changes upstream. Logs saved in error-snapshot-1585841672750.

@dralley dralley force-pushed the dralley:fix-motionmark branch 2 times, most recently from 67eb348 to cfa7092 Apr 2, 2020
@dralley
Copy link
Contributor Author

dralley commented Apr 2, 2020

Alright, I've tested this patch for layout 2020 and it seems to work... If there is somewhere better, let me know. I couldn't find anywhere that looked more appropriate.

Comparing float equality makes me cringe a little bit but that is the only size available at this location.

@SimonSapin
Copy link
Member

SimonSapin commented Apr 2, 2020

Sorry, but this still doesn’t look right. Returning None from the constructor of ReplacedContent still cause the box to be non-replaced, instead of a zero-size replaced box. Somewhere under layout_2020/display_list/ would be the right place for this change.

@dralley
Copy link
Contributor Author

dralley commented Apr 2, 2020

@SimonSapin Apologies, but I simply do not know where this is supposed to go. The only usages of the word "replace" under the layout2020/display_list/ directory is:

  • one occurance of mem::replace
  • two occurances of use crate::replaced::IntrinsicSizes;

And the one place under layout2020/display_list/ where I thought it looked possibly reasonable for this to go -- did not fix the problem. I'm stumped.

Would it be better to just merge the fix for layout 2013 and file an issue for layout 2020? Or is there any chance you could narrow it down a bit more?

@SimonSapin
Copy link
Member

SimonSapin commented Apr 3, 2020

Would it be better to just merge the fix for layout 2013 and file an issue for layout 2020?

That’s fine with me too.


This code generates a fragment for the replaced box for a <canvas> element:

ReplacedContentKind::Canvas(canvas_info) => {
let image_key = match canvas_info.source {
CanvasSource::WebGL(image_key) => image_key,
CanvasSource::Image(ref ipc_renderer) => match *ipc_renderer {
Some(ref ipc_renderer) => {
let ipc_renderer = ipc_renderer.lock().unwrap();
let (sender, receiver) = ipc::channel().unwrap();
ipc_renderer
.send(CanvasMsg::FromLayout(
FromLayoutMsg::SendData(sender),
canvas_info.canvas_id,
))
.unwrap();
receiver.recv().unwrap().image_key
},
None => return vec![],
},
};
vec![Fragment::Image(ImageFragment {
debug_id: DebugId::new(),
style: style.clone(),
rect: Rect {
start_corner: Vec2::zero(),
size,
},
image_key,
})]
},

It generates a Fragment::Image, because at that point the canvas has already been rendered to a pixel buffer within WebRender). This image is then added to the display list here:

Fragment::Image(i) => {
builder.is_contentful = true;
let rect = i
.rect
.to_physical(i.style.writing_mode, containing_block)
.translate(containing_block.origin.to_vector());
let common = builder.common_properties(rect.clone().to_webrender());
builder.wr.push_image(
&common,
rect.to_webrender(),
image_rendering(i.style.get_inherited_box().image_rendering),
wr::AlphaType::PremultipliedAlpha,
i.image_key,
wr::ColorF::WHITE,
);
},

In that second location, it should be possible to check for i.rect.size == Vec2::zero() (with use crate::geom::Vec2; at the top of the file) to skip generating a display item for zero-size images (including rendered <canvas>). But if the problem this is attempting to fix is with rendering canvas to pixels in the first place, then in the first location we could check for (self.intrinsic.width, self.intrinsic.height) == (Some(Length::zero()), Some(Length::zero())) (with use style::Zero; at the top of the file) and return an empty Vec of zero fragments.

@dralley dralley force-pushed the dralley:fix-motionmark branch from cfa7092 to 9b1c781 Apr 3, 2020
@dralley
Copy link
Contributor Author

dralley commented Apr 3, 2020

@SimonSapin Thanks! I think the more accurate description of this issue is probably the latter one, that Webrender shouldn't be rendering 0-size canvases. The latter patch you suggested works (slightly modified), the others did not.

@dralley dralley force-pushed the dralley:fix-motionmark branch from 9b1c781 to 632daf8 Apr 3, 2020
@dralley dralley changed the title Don't add empty canvas' to the display list Don't send empty canvas' to WebRender Apr 3, 2020
@dralley dralley changed the title Don't send empty canvas' to WebRender Don't send empty canvases to WebRender Apr 3, 2020
If any dimension of a canvas is 0, don't try to render it as it causes
problems inside webrender.
@dralley dralley force-pushed the dralley:fix-motionmark branch from 632daf8 to 61fb84d Apr 3, 2020
@SimonSapin
Copy link
Member

SimonSapin commented Apr 3, 2020

Looks good, thanks!

@bors-servo r=cbrewster,SimonSapin

@bors-servo
Copy link
Contributor

bors-servo commented Apr 3, 2020

📌 Commit 61fb84d has been approved by cbrewster,SimonSapin

@bors-servo
Copy link
Contributor

bors-servo commented Apr 3, 2020

Testing commit 61fb84d with merge f7d3d4a...

@bors-servo
Copy link
Contributor

bors-servo commented Apr 3, 2020

☀️ Test successful - status-taskcluster
Approved by: cbrewster,SimonSapin
Pushing f7d3d4a to master...

@bors-servo bors-servo merged commit f7d3d4a into servo:master Apr 3, 2020
2 checks passed
2 checks passed
Community-TC (pull_request) TaskGroup: success
Details
homu Test successful
Details
@dralley dralley deleted the dralley:fix-motionmark branch Apr 3, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

8 participants
You can’t perform that action at this time.