--- a/servo/components/canvas/webgl_thread.rs
+++ b/servo/components/canvas/webgl_thread.rs
@@ -3,17 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use canvas_traits::canvas::byte_swap;
use canvas_traits::webgl::*;
use euclid::Size2D;
use fnv::FnvHashMap;
use gleam::gl;
use offscreen_gl_context::{GLContext, GLContextAttributes, GLLimits, NativeGLContextMethods};
-use std::mem;
use std::thread;
use super::gl_context::{GLContextFactory, GLContextWrapper};
use webrender;
use webrender_api;
/// WebGL Threading API entry point that lives in the constellation.
/// It allows to get a WebGLThread handle for each script pipeline.
pub use ::webgl_mode::WebGLThreads;
@@ -197,18 +196,16 @@ impl<VR: WebVRRenderHandler + 'static, O
self.contexts.insert(id, ctx);
self.cached_context_info.insert(id, WebGLContextInfo {
texture_id,
size,
alpha: attributes.alpha,
image_key: None,
share_mode,
gl_sync: None,
- old_image_key: None,
- very_old_image_key: None,
});
self.observer.on_context_create(id, texture_id, size);
Ok((id, limits, share_mode))
},
Err(msg) => {
Err(msg.to_owned())
@@ -226,23 +223,28 @@ impl<VR: WebVRRenderHandler + 'static, O
Ok(_) => {
let (real_size, texture_id, _) = ctx.get_info();
self.observer.on_context_resize(context_id, texture_id, real_size);
let info = self.cached_context_info.get_mut(&context_id).unwrap();
// Update webgl texture size. Texture id may change too.
info.texture_id = texture_id;
info.size = real_size;
- // WR doesn't support resizing and requires to create a new `ImageKey`.
- // Mark the current image_key to be deleted later in the next epoch.
- if let Some(image_key) = info.image_key.take() {
- // If this executes, then we are in a new epoch since we last recreated the canvas,
- // so `old_image_key` must be `None`.
- debug_assert!(info.old_image_key.is_none());
- info.old_image_key = Some(image_key);
+ // Update WR image if needed. Resize image updates are only required for SharedTexture mode.
+ // 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) => {
+ Self::update_wr_external_image(&self.webrender_api,
+ info.size,
+ info.alpha,
+ context_id,
+ image_key);
+ },
+ _ => {}
}
sender.send(Ok(())).unwrap();
},
Err(msg) => {
sender.send(Err(msg.into())).unwrap();
}
}
@@ -252,50 +254,44 @@ impl<VR: WebVRRenderHandler + 'static, O
fn remove_webgl_context(&mut self, context_id: WebGLContextId) {
// Release webrender image keys.
if let Some(info) = self.cached_context_info.remove(&context_id) {
let mut updates = webrender_api::ResourceUpdates::new();
if let Some(image_key) = info.image_key {
updates.delete_image(image_key);
}
- if let Some(image_key) = info.old_image_key {
- updates.delete_image(image_key);
- }
- if let Some(image_key) = info.very_old_image_key {
- updates.delete_image(image_key);
- }
self.webrender_api.update_resources(updates)
}
// Release GL context.
if self.contexts.remove(&context_id).is_some() {
self.observer.on_context_delete(context_id);
}
// Removing a GLContext may make the current bound context_id dirty.
self.bound_context_id = None;
}
- /// Handles the creation/update of webrender_api::ImageKeys fpr a specific WebGLContext.
+ /// 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 or resize.
+ /// 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(&mut self, context_id: WebGLContextId, sender: WebGLSender<webrender_api::ImageKey>) {
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 or resize.
+ // 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], info.size);
match info.image_key.clone() {
Some(image_key) => {
@@ -317,23 +313,16 @@ impl<VR: WebVRRenderHandler + 'static, O
pixels);
info.image_key = Some(image_key);
image_key
}
}
}
};
- // Delete old image
- if let Some(image_key) = mem::replace(&mut info.very_old_image_key, info.old_image_key.take()) {
- let mut updates = webrender_api::ResourceUpdates::new();
- updates.delete_image(image_key);
- self.webrender_api.update_resources(updates);
- }
-
// Send the ImageKey to the Layout thread.
sender.send(image_key).unwrap();
}
/// Gets a reference to a GLContextWrapper for a given WebGLContextId and makes it current if required.
fn make_current_if_needed<'a>(context_id: WebGLContextId,
contexts: &'a FnvHashMap<WebGLContextId, GLContextWrapper>,
bound_id: &mut Option<WebGLContextId>) -> Option<&'a GLContextWrapper> {
@@ -360,35 +349,46 @@ impl<VR: WebVRRenderHandler + 'static, O
}
/// Creates a `webrender_api::ImageKey` that uses shared textures.
fn create_wr_external_image(webrender_api: &webrender_api::RenderApi,
size: Size2D<i32>,
alpha: bool,
context_id: WebGLContextId) -> webrender_api::ImageKey {
let descriptor = Self::image_descriptor(size, alpha);
-
- let data = webrender_api::ExternalImageData {
- id: webrender_api::ExternalImageId(context_id.0 as u64),
- channel_index: 0,
- image_type: webrender_api::ExternalImageType::Texture2DHandle,
- };
- let data = webrender_api::ImageData::External(data);
+ let data = Self::external_image_data(context_id);
let image_key = webrender_api.generate_image_key();
let mut updates = webrender_api::ResourceUpdates::new();
updates.add_image(image_key,
descriptor,
data,
None);
webrender_api.update_resources(updates);
image_key
}
+ /// Updates a `webrender_api::ImageKey` that uses shared textures.
+ fn update_wr_external_image(webrender_api: &webrender_api::RenderApi,
+ size: Size2D<i32>,
+ alpha: bool,
+ context_id: WebGLContextId,
+ image_key: webrender_api::ImageKey) {
+ let descriptor = Self::image_descriptor(size, alpha);
+ let data = Self::external_image_data(context_id);
+
+ let mut updates = webrender_api::ResourceUpdates::new();
+ updates.update_image(image_key,
+ descriptor,
+ data,
+ None);
+ webrender_api.update_resources(updates);
+ }
+
/// Creates a `webrender_api::ImageKey` that uses raw pixels.
fn create_wr_readback_image(webrender_api: &webrender_api::RenderApi,
size: Size2D<i32>,
alpha: bool,
data: Vec<u8>) -> webrender_api::ImageKey {
let descriptor = Self::image_descriptor(size, alpha);
let data = webrender_api::ImageData::new(data);
@@ -427,16 +427,26 @@ impl<VR: WebVRRenderHandler + 'static, O
height: size.height as u32,
stride: None,
format: if alpha { webrender_api::ImageFormat::BGRA8 } else { webrender_api::ImageFormat::RGB8 },
offset: 0,
is_opaque: !alpha,
}
}
+ /// Helper function to create a `webrender_api::ImageData::External` instance.
+ fn external_image_data(context_id: WebGLContextId) -> webrender_api::ImageData {
+ let data = webrender_api::ExternalImageData {
+ id: webrender_api::ExternalImageId(context_id.0 as u64),
+ channel_index: 0,
+ image_type: webrender_api::ExternalImageType::Texture2DHandle,
+ };
+ webrender_api::ImageData::External(data)
+ }
+
/// Helper function to fetch the raw pixels used in readback mode.
fn raw_pixels(context: &GLContextWrapper, size: Size2D<i32>) -> Vec<u8> {
let width = size.width as usize;
let height = size.height as usize;
let mut pixels = context.gl().read_pixels(0, 0,
size.width as gl::GLsizei,
size.height as gl::GLsizei,
@@ -474,20 +484,16 @@ struct WebGLContextInfo {
/// True if the WebGLContext uses an alpha channel.
alpha: bool,
/// Currently used WebRender image key.
image_key: Option<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.
gl_sync: Option<gl::GLsync>,
- /// An old WebRender image key that can be deleted when the next epoch ends.
- old_image_key: Option<webrender_api::ImageKey>,
- /// An old WebRender image key that can be deleted when the current epoch ends.
- very_old_image_key: Option<webrender_api::ImageKey>,
}
/// Trait used to observe events in a WebGL Thread.
/// Used in webrender::ExternalImageHandler when multiple WebGL threads are used.
pub trait WebGLThreadObserver: Send + 'static {
fn on_context_create(&mut self, ctx_id: WebGLContextId, texture_id: u32, size: Size2D<i32>);
fn on_context_resize(&mut self, ctx_id: WebGLContextId, texture_id: u32, size: Size2D<i32>);
fn on_context_delete(&mut self, ctx_id: WebGLContextId);