Reuse WebGL ImageKeys after a resize.

This commit is contained in:
Imanol Fernandez 2017-08-31 22:54:33 +02:00
parent 174c37fddd
commit 21f8b519c3
2 changed files with 43 additions and 41 deletions

View file

@ -8,7 +8,6 @@ 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;
@ -202,8 +201,6 @@ impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR,
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);
@ -231,13 +228,18 @@ impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR,
// 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();
@ -257,12 +259,6 @@ impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR,
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)
}
@ -276,9 +272,9 @@ impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR,
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>) {
@ -290,7 +286,7 @@ impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR,
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)
})
@ -322,13 +318,6 @@ impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR,
}
};
// 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();
}
@ -365,13 +354,7 @@ impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR,
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();
@ -384,6 +367,23 @@ impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR,
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>,
@ -432,6 +432,16 @@ impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR,
}
}
/// 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;
@ -479,10 +489,6 @@ struct WebGLContextInfo {
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.

View file

@ -264,10 +264,6 @@ impl WebGLRenderingContext {
return;
};
// Reset webrender_image because resize creates a new image_key.
// The new image key is set in the next handle_layout() method.
self.webrender_image.set(None);
// ClearColor needs to be restored because after a resize the GLContext is recreated
// and the framebuffer is cleared using the default black transparent color.
let color = self.current_clear_color.get();