Ensure that resized GL contexts do not destroy their resources while in use by WR.

This commit is contained in:
Josh Matthews 2019-01-10 23:47:58 -05:00
parent 85c1c5ad13
commit 878f020013
8 changed files with 43 additions and 23 deletions

View file

@ -9,7 +9,9 @@ use euclid::Size2D;
use fnv::FnvHashMap;
use gleam::gl;
use half::f16;
use offscreen_gl_context::{GLContext, GLContextAttributes, GLLimits, NativeGLContextMethods};
use offscreen_gl_context::{
DrawBuffer, GLContext, GLContextAttributes, GLLimits, NativeGLContextMethods,
};
use pixels::{self, PixelFormat};
use std::borrow::Cow;
use std::thread;
@ -228,6 +230,7 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id)
.expect("WebGLContext not found in a WebGLMsg::Lock message");
let info = self.cached_context_info.get_mut(&context_id).unwrap();
info.render_state = ContextRenderState::Locked(None);
// Insert a OpenGL Fence sync object that sends a signal when all the WebGL commands are finished.
// The related gl().wait_sync call is performed in the WR thread. See WebGLExternalImageApi for mor details.
let gl_sync = data.ctx.gl().fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0);
@ -247,6 +250,7 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
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();
info.render_state = ContextRenderState::Unlocked;
if let Some(gl_sync) = info.gl_sync.take() {
// Release the GLSync object.
data.ctx.gl().delete_sync(gl_sync);
@ -299,6 +303,7 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
image_key: None,
share_mode,
gl_sync: None,
render_state: ContextRenderState::Unlocked,
},
);
@ -319,9 +324,19 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
)
.expect("Missing WebGL context!");
match data.ctx.resize(size) {
Ok(_) => {
Ok(old_draw_buffer) => {
let (real_size, texture_id, _) = data.ctx.get_info();
let info = self.cached_context_info.get_mut(&context_id).unwrap();
if let ContextRenderState::Locked(ref mut in_use) = info.render_state {
// If there's already an outdated draw buffer present, we can ignore
// the newly resized one since it's not in use by the renderer.
if in_use.is_none() {
// We're resizing the context while WR is actively rendering
// it, so we need to retain the GL resources until WR is
// finished with them.
*in_use = Some(old_draw_buffer);
}
}
// Update webgl texture size. Texture id may change too.
info.texture_id = texture_id;
info.size = real_size;
@ -682,6 +697,14 @@ impl<VR: WebVRRenderHandler + 'static> Drop for WebGLThread<VR> {
}
}
enum ContextRenderState {
/// The context is not being actively rendered.
Unlocked,
/// The context is actively being rendered. If a DrawBuffer value is present,
/// it is outdated but in use as long as the context is locked.
Locked(Option<DrawBuffer>),
}
/// Helper struct to store cached WebGLContext information.
struct WebGLContextInfo {
/// Render to texture identifier used by the WebGLContext.
@ -696,6 +719,8 @@ struct WebGLContextInfo {
share_mode: WebGLContextShareMode,
/// GLSync Object used for a correct synchronization with Webrender external image callbacks.
gl_sync: Option<gl::GLsync>,
/// The status of this context with respect to external consumers.
render_state: ContextRenderState,
}
/// This trait is used as a bridge between the `WebGLThreads` implementation and