aboutsummaryrefslogtreecommitdiffstats
path: root/components/canvas/webgl_thread.rs
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2019-10-08 13:19:21 -0400
committerJosh Matthews <josh@joshmatthews.net>2019-10-10 09:57:20 -0400
commitc53680b282aa5bf77ca15b8a4f9ae84afb8b9361 (patch)
treec41be0a3275b0ef09751a0c85517d4030545ec8a /components/canvas/webgl_thread.rs
parent4d7110aca53f54c5a9ee2bbbfbe800627c9af249 (diff)
downloadservo-c53680b282aa5bf77ca15b8a4f9ae84afb8b9361.tar.gz
servo-c53680b282aa5bf77ca15b8a4f9ae84afb8b9361.zip
webgl: Lazily clear the canvas right before the first webgl command of the next frame.
Diffstat (limited to 'components/canvas/webgl_thread.rs')
-rw-r--r--components/canvas/webgl_thread.rs157
1 files changed, 77 insertions, 80 deletions
diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs
index 0e930b1f947..a2e95955753 100644
--- a/components/canvas/webgl_thread.rs
+++ b/components/canvas/webgl_thread.rs
@@ -239,6 +239,12 @@ impl WebGLThread {
let result = self.create_webgl_context(version, size, attributes);
result_sender
.send(result.map(|(id, limits, share_mode, framebuffer_format)| {
+ let image_key = self
+ .cached_context_info
+ .get_mut(&id)
+ .expect("Where's the cached context info?")
+ .image_key;
+
let data = Self::make_current_if_needed(
id,
&self.contexts,
@@ -277,6 +283,7 @@ impl WebGLThread {
glsl_version,
api_type,
framebuffer_format,
+ image_key,
}
}))
.unwrap();
@@ -299,12 +306,12 @@ impl WebGLThread {
WebGLMsg::Unlock(ctx_id) => {
self.handle_unlock(ctx_id);
},
- WebGLMsg::UpdateWebRenderImage(ctx_id, sender) => {
- self.handle_update_wr_image(ctx_id, sender);
- },
WebGLMsg::DOMToTextureCommand(command) => {
self.handle_dom_to_texture(command);
},
+ WebGLMsg::SwapBuffers(context_ids, sender) => {
+ self.handle_swap_buffers(context_ids, sender);
+ },
WebGLMsg::Exit => {
return true;
},
@@ -326,6 +333,11 @@ impl WebGLThread {
&mut self.bound_context_id,
);
if let Some(data) = data {
+ let info = self.cached_context_info.get_mut(&context_id).unwrap();
+ if info.clear_required {
+ info.clear_required = false;
+ Self::clear_drawing_buffer(data);
+ }
data.ctx.apply_command(
command,
data.use_apple_vertex_arrays,
@@ -400,32 +412,36 @@ impl WebGLThread {
data.ctx.gl().delete_sync(gl_sync);
debug_assert!(data.ctx.gl().get_error() == gl::NO_ERROR);
}
-
- self.clear_drawing_buffer(context_id);
}
- fn clear_drawing_buffer(&mut self, context_id: WebGLContextId) {
- let info = self.cached_context_info.get_mut(&context_id).unwrap();
- if info.preserve_drawing_buffer {
- return;
+ #[allow(unsafe_code)]
+ fn clear_drawing_buffer(data: &mut GLContextData) {
+ trace!("clearing GL framebuffer");
+
+ // Ensure we're clearing the default framebuffer.
+ let mut fb = [0];
+ unsafe {
+ data.ctx
+ .gl()
+ .get_integer_v(gl::FRAMEBUFFER_BINDING, &mut fb);
}
+ data.ctx
+ .gl()
+ .bind_framebuffer(gl::FRAMEBUFFER, data.ctx.framebuffer());
- let data = Self::make_current_if_needed(
- context_id,
- &self.contexts,
- &mut self.bound_context_id,
- )
- .expect("WebGLContext not found when clearing drawing buffer");
- trace!("clearing GL framebuffer");
data.ctx.gl().clear_color(0., 0., 0., 0.);
data.ctx.gl().clear_depth(1.0);
data.ctx.gl().clear_stencil(0);
- data.ctx.gl().clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
+ data.ctx
+ .gl()
+ .clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
let (r, g, b, a) = data.state.clear_color;
data.ctx.gl().clear_color(r, g, b, a);
data.ctx.gl().clear_depth(data.state.depth_clear_value);
data.ctx.gl().clear_stencil(data.state.stencil_clear_value);
+
+ data.ctx.gl().bind_framebuffer(gl::FRAMEBUFFER, fb[0] as _);
}
/// Creates a new WebGLContext
@@ -475,17 +491,33 @@ impl WebGLThread {
},
);
+ let image_key = match share_mode {
+ WebGLContextShareMode::Readback => Self::create_wr_readback_image(
+ &self.webrender_api,
+ size,
+ attributes.alpha,
+ vec![0; 4 * size.width as usize * size.height as usize],
+ ),
+ WebGLContextShareMode::SharedTexture => Self::create_wr_external_image(
+ &self.webrender_api,
+ size.to_i32(),
+ attributes.alpha,
+ id,
+ ),
+ };
+
self.cached_context_info.insert(
id,
WebGLContextInfo {
texture_id,
size,
alpha: attributes.alpha,
- image_key: None,
+ image_key: image_key,
share_mode,
gl_sync: None,
render_state: ContextRenderState::Unlocked,
preserve_drawing_buffer,
+ clear_required: false,
},
);
@@ -527,7 +559,7 @@ impl WebGLThread {
// Readback mode already updates the image every frame to send the raw pixels.
// See `handle_update_wr_image`.
match (info.image_key, info.share_mode) {
- (Some(image_key), WebGLContextShareMode::SharedTexture) => {
+ (image_key, WebGLContextShareMode::SharedTexture) => {
Self::update_wr_external_image(
&self.webrender_api,
info.size,
@@ -553,9 +585,7 @@ impl WebGLThread {
if let Some(info) = self.cached_context_info.remove(&context_id) {
let mut txn = webrender_api::Transaction::new();
- if let Some(image_key) = info.image_key {
- txn.delete_image(image_key);
- }
+ txn.delete_image(info.image_key);
self.webrender_api.update_resources(txn.resource_updates)
}
@@ -571,68 +601,33 @@ impl WebGLThread {
self.bound_context_id = None;
}
- /// Handles the creation/update of webrender_api::ImageKeys for a specific WebGLContext.
- /// This method is invoked from a UpdateWebRenderImage message sent by the layout thread.
- /// If SharedTexture is used the UpdateWebRenderImage message is sent only after a WebGLContext creation.
- /// If Readback is used UpdateWebRenderImage message is sent always on each layout iteration in order to
- /// submit the updated raw pixels.
- fn handle_update_wr_image(
+ fn handle_swap_buffers(
&mut self,
- context_id: WebGLContextId,
- sender: WebGLSender<webrender_api::ImageKey>,
+ context_ids: Vec<WebGLContextId>,
+ completed_sender: WebGLSender<()>,
) {
- let info = self.cached_context_info.get_mut(&context_id).unwrap();
- let webrender_api = &self.webrender_api;
-
- let image_key = match info.share_mode {
- WebGLContextShareMode::SharedTexture => {
- let size = info.size;
- let alpha = info.alpha;
- // Reuse existing ImageKey or generate a new one.
- // When using a shared texture ImageKeys are only generated after a WebGLContext creation.
- *info.image_key.get_or_insert_with(|| {
- Self::create_wr_external_image(webrender_api, size, alpha, context_id)
- })
- },
- WebGLContextShareMode::Readback => {
- let pixels = Self::raw_pixels(&self.contexts[&context_id].ctx, info.size);
- match info.image_key.clone() {
- Some(image_key) => {
- // ImageKey was already created, but WR Images must
- // be updated every frame in readback mode to send the new raw pixels.
- Self::update_wr_readback_image(
- webrender_api,
- info.size,
- info.alpha,
- image_key,
- pixels,
- );
-
- image_key
- },
- None => {
- // Generate a new ImageKey for Readback mode.
- let image_key = Self::create_wr_readback_image(
- webrender_api,
- info.size,
- info.alpha,
- pixels,
- );
- info.image_key = Some(image_key);
- image_key
- },
- }
- },
- };
+ for context_id in context_ids {
+ let info = self.cached_context_info.get_mut(&context_id).unwrap();
+ let webrender_api = &self.webrender_api;
- // Send the ImageKey to the Layout thread.
- sender.send(image_key).unwrap();
+ if let WebGLContextShareMode::Readback = info.share_mode {
+ let pixels = Self::raw_pixels(&self.contexts[&context_id].ctx, info.size);
+ // WR Images must be updated every frame in readback mode to send the new raw pixels.
+ Self::update_wr_readback_image(
+ webrender_api,
+ info.size,
+ info.alpha,
+ info.image_key,
+ pixels,
+ );
+ }
- if let WebGLContextShareMode::Readback = info.share_mode {
- // Ensure that the drawing buffer is cleared when webrender isn't involved
- // in drawing the GL texture.
- self.clear_drawing_buffer(context_id);
+ if !info.preserve_drawing_buffer {
+ info.clear_required = true;
+ }
}
+
+ let _ = completed_sender.send(());
}
fn handle_dom_to_texture(&mut self, command: DOMToTextureCommand) {
@@ -911,7 +906,7 @@ struct WebGLContextInfo {
/// True if the WebGLContext uses an alpha channel.
alpha: bool,
/// Currently used WebRender image key.
- image_key: Option<webrender_api::ImageKey>,
+ image_key: webrender_api::ImageKey,
/// The sharing mode used to send the image to WebRender.
share_mode: WebGLContextShareMode,
/// GLSync Object used for a correct synchronization with Webrender external image callbacks.
@@ -920,6 +915,8 @@ struct WebGLContextInfo {
render_state: ContextRenderState,
/// Should the drawing buffer be preserved between frames?
preserve_drawing_buffer: bool,
+ /// Does the canvas need to be cleared before executing further WebGL commands?
+ clear_required: bool,
}
/// Data about the linked DOM<->WebGLTexture elements.