Auto merge of #18332 - MortimerGoro:webgl_reuse_image, r=glennw

Reuse WebGL ImageKeys after a resize.

<!-- Please describe your changes on the following line: -->

WebRender does now support resizing with the same image key

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

<!-- Either: -->
- [x] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- 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/18332)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-09-01 01:22:38 -05:00 committed by GitHub
commit 3dceb11158
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();