Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upSynchronize WebGL contexts with page rendering #21841
Conversation
highfive
commented
Sep 29, 2018
|
Heads up! This PR modifies the following files:
|
highfive
commented
Sep 29, 2018
|
@bors-servo try=wpt |
Synchronize WebGL contexts with page rendering The code that deals with a integrating a shared GL context with the display list that Webrender receives doesn't work right now. Webrender has an API that allows locking the context, but the period between the end of layout (when script starts running again) and when WR actually processes the display list means that the GL context can be modified so that what WR sees is not what was supposed to be composited. This change marks GL contexts for WebGL canvases as locked as soon as they are processed by layout, causing any future WebGL commands that affect the to context to be buffered and replayed once WebRender unlocks the GL context. --- - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #21838 - [x] These changes do not require tests because it's nondeterministic behaviour. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21841) <!-- Reviewable:end -->
|
r? @emilio |
|
|
|
np, I think I can review this :) Some comment below, I think it looks reasonable, though I think I need to re-page the locking / unlocking scheme is supposed to work to see if this is sound. We can probably take advantage that we're going to see us in person on Monday to double-check this :) Thanks! |
| @@ -183,6 +212,13 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> { | |||
| self.webvr_compositor.as_mut().unwrap().handle(command, texture.map(|t| (t.texture_id, t.size))); | |||
| } | |||
|
|
|||
| /// Handles a request to prevent a GL context from being modified until further notice. | |||
| fn handle_prevent_modification(&mut self, context_id: WebGLContextId) { | |||
| if !self.buffered_contexts.contains_key(&context_id) { | |||
This comment has been minimized.
This comment has been minimized.
| let target_id = match msg { | ||
| WebGLMsg::CreateContext(..) | | ||
| WebGLMsg::Lock(..) | | ||
| WebGLMsg::Unlock(..) | |
This comment has been minimized.
This comment has been minimized.
emilio
Sep 29, 2018
Member
We should probably assert that we don't receive lock messages while it's unlocked, or similar. Otherwise the code below in handle_unlock won't work. Though I think this is a pre-existing issue.
| { | ||
| let data = Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id) | ||
| .expect("WebGLContext not found in a WebGLMsg::Unlock message"); | ||
| let info = self.cached_context_info.get_mut(&context_id).unwrap(); |
This comment has been minimized.
This comment has been minimized.
emilio
Sep 29, 2018
Member
nit: while you're touching this, using the indexing operator may give a nicer error message if it fails.
| @@ -64,6 +65,9 @@ pub struct WebGLThread<VR: WebVRRenderHandler + 'static> { | |||
| webvr_compositor: Option<VR>, | |||
| /// Texture ids and sizes used in DOM to texture outputs. | |||
| dom_outputs: FnvHashMap<webrender_api::PipelineId, DOMToTextureData>, | |||
| /// Tracking GL contexts that must not be modified but can still be | |||
| /// targeted by WebGL commands. | |||
This comment has been minimized.
This comment has been minimized.
emilio
Sep 29, 2018
Member
This should document that this map only has keys for contexts that are currently locked, and for which a PreventModification message has been sent.
| guards.clone(), | ||
| true, | ||
| data.reflow_goal.needs_display(), | ||
| &map); |
This comment has been minimized.
This comment has been minimized.
| guards, | ||
| false, | ||
| goal.needs_display(), | ||
| &snapshots |
This comment has been minimized.
This comment has been minimized.
| @@ -183,6 +212,13 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> { | |||
| self.webvr_compositor.as_mut().unwrap().handle(command, texture.map(|t| (t.texture_id, t.size))); | |||
| } | |||
|
|
|||
| /// Handles a request to prevent a GL context from being modified until further notice. | |||
| fn handle_prevent_modification(&mut self, context_id: WebGLContextId) { | |||
This comment has been minimized.
This comment has been minimized.
emilio
Sep 29, 2018
Member
Should this assert that the context is locked? Otherwise there's no guarantee that the context would be unlocked, right?
|
Another thing to check is whether WebRender is guaranteed to give us an unlock() message. I'd expect it to not do so if the image is culled (because the element is off-screen for example). |
|
As an optimization we could start the msg buffering only when a Draw operation arrives (e.g. glDrawElements, glDrawArrays or glClear). It should be safe to run other methods. |
|
|
|
The concern about webrender only calling lock/unlock when the canvas is rendered onscreen is real. Firefox uses a queue of shared textures (instead of one shared context) to ensure that it can continue performing webgl operations while webrender will always see consistent texture contents. To avoid completely rewriting our webgl setup, I'm going to try delaying all webgl command execution until the webrender image handler lock is called; the webgl thread can buffer all commands and group them by frames. For a canvas with |
|
This runs into problems where JS will block on compositing. I'm going to try using textures like Gecko instead of a single offscreen framebuffer so we can just tell webrender "this is the frame; draw it" and keep working on a separate texture. |
|
That's a good idea. We are also going to need render to texture (SurfaceTexture) for WebVR integration with FxR. |
|
Huh. In a release build on my pixel 2, there is way more flickering with these changes than without them. That's... unexpected. |
|
This is definitely a huge improvement in debug builds, at least. |
|
@bors-servo try=wpt |
Synchronize WebGL contexts with page rendering The code that deals with a integrating a shared GL context with the display list that Webrender receives doesn't work right now. Webrender has an API that allows locking the context, but the period between the end of layout (when script starts running again) and when WR actually processes the display list means that the GL context can be modified so that what WR sees is not what was supposed to be composited. This change marks GL contexts for WebGL canvases as locked as soon as they are processed by layout, causing any future WebGL commands that affect the to context to be buffered and replayed once WebRender unlocks the GL context. --- - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #21838 - [x] These changes do not require tests because it's nondeterministic behaviour. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21841) <!-- Reviewable:end -->
|
|
|
Current theory about the pixel 2 brokenness:
More specifically, the locking mechanism currently implemented is broken by the switch to use multiple textures. The swapping code should only run when the texture is unlocked; otherwise we should just reset the current frame and skip displaying it, I suppose. |
|
The flickering is not helped by dealing with the issue described in the previous comment. It is helped by commenting out the call to reset_draw_buffer_contents in servo/surfman#131. |
|
|
|
No longer necessary with the introduction of #24482! |
jdm commentedSep 29, 2018
•
edited by SimonSapin
The code that deals with a integrating a shared GL context with the display list that Webrender receives doesn't work right now. Webrender has an API that allows locking the context, but the period between the end of layout (when script starts running again) and when WR actually processes the display list means that the GL context can be modified so that what WR sees is not what was supposed to be composited. This change marks GL contexts for WebGL canvases as locked as soon as they are processed by layout, causing any future WebGL commands that affect the to context to be buffered and replayed once WebRender unlocks the GL context.
./mach build -ddoes not report any errors./mach test-tidydoes not report any errorsThis change is