Skip to content

Commit 359cadb

Browse files
author
Alan Jeffrey
committed
Allow webGL swap chains to exist without being attached to their context
1 parent 156e3d8 commit 359cadb

File tree

1 file changed

+33
-11
lines changed

1 file changed

+33
-11
lines changed

components/canvas/webgl_thread.rs

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,26 @@ use pixels::{self, PixelFormat};
2323
use std::borrow::Cow;
2424
use std::cell::{Cell, RefCell};
2525
use std::collections::hash_map::Entry;
26+
use std::iter;
2627
use std::mem;
2728
use std::rc::Rc;
2829
use std::sync::{Arc, Mutex};
2930
use std::thread;
3031
use surfman::{self, Adapter, Context, ContextAttributeFlags, ContextAttributes, Device};
3132
use surfman::GLVersion;
33+
use surfman::Surface;
3234
use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType};
3335

3436
struct GLContextData {
3537
ctx: Context,
3638
gl: Rc<dyn Gl>,
3739
state: GLState,
3840
attributes: GLContextAttributes,
41+
// Each WebGL context has a collection of swap chains, one of which is attached
42+
// (that is, its surface is the current surface of the context).
43+
attached: SwapChainId,
44+
// The other swap chains are unattached, and their surfaces are not the current surface of the context.
45+
unattached: FnvHashMap<SwapChainId, Surface>,
3946
}
4047

4148
pub struct GLState {
@@ -364,7 +371,9 @@ impl WebGLThread {
364371
gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer);
365372

366373
let state = Default::default();
367-
self.contexts.insert(id, GLContextData { ctx, gl, state, attributes });
374+
let attached = SwapChainId::Context(id);
375+
let unattached = Default::default();
376+
self.contexts.insert(id, GLContextData { ctx, gl, state, attributes, attached, unattached });
368377

369378
self.cached_context_info.insert(
370379
id,
@@ -388,9 +397,13 @@ impl WebGLThread {
388397
&mut self.bound_context_id).expect("Missing WebGL context!");
389398

390399
// Throw out all buffers.
400+
let swap_id = SwapChainId::Context(context_id);
391401
let context_descriptor = self.device.context_descriptor(&data.ctx);
392402
let new_surface = self.device.create_surface(&data.ctx, &size.to_i32()).unwrap();
393-
let old_surface = self.device.replace_context_surface(&mut data.ctx, new_surface).unwrap();
403+
let old_surface = match data.unattached.get_mut(&swap_id) {
404+
Some(surface) => mem::replace(surface, new_surface),
405+
None => self.device.replace_context_surface(&mut data.ctx, new_surface).unwrap(),
406+
};
394407
self.device.destroy_surface(&mut data.ctx, old_surface).unwrap();
395408

396409
// Update WR image if needed. Resize image updates are only required for SharedTexture mode.
@@ -439,15 +452,21 @@ impl WebGLThread {
439452
};
440453

441454
// Destroy all the surfaces
442-
let swap_id = SwapChainId::Context(context_id);
443-
if let Some(swap_chain) = self.swap_chains.lock().remove(&swap_id) {
444-
for surface in swap_chain.pending_surface {
445-
self.device.destroy_surface(&mut data.ctx, surface).unwrap();
446-
}
447-
for surface in swap_chain.presented_surfaces {
448-
self.device.destroy_surface(&mut data.ctx, surface).unwrap();
455+
let swap_ids = iter::once(data.attached)
456+
.chain(data.unattached.keys().cloned());
457+
for swap_id in swap_ids {
458+
if let Some(swap_chain) = self.swap_chains.lock().remove(&swap_id) {
459+
for surface in swap_chain.pending_surface {
460+
self.device.destroy_surface(&mut data.ctx, surface).unwrap();
461+
}
462+
for surface in swap_chain.presented_surfaces {
463+
self.device.destroy_surface(&mut data.ctx, surface).unwrap();
464+
}
449465
}
450466
}
467+
for (_, surface) in data.unattached {
468+
self.device.destroy_surface(&mut data.ctx, surface).unwrap();
469+
}
451470

452471
// Destroy the context
453472
self.device.destroy_context(&mut data.ctx).unwrap();
@@ -541,8 +560,11 @@ impl WebGLThread {
541560
println!("... new back buffer will become {:?}", new_back_buffer.id());
542561

543562
// Swap the buffers.
544-
let new_front_buffer = self.device.replace_context_surface(&mut data.ctx, new_back_buffer)
545-
.expect("Where's the new front buffer?");
563+
let new_front_buffer = match data.unattached.get_mut(&swap_id) {
564+
Some(surface) => mem::replace(surface, new_back_buffer),
565+
None => self.device.replace_context_surface(&mut data.ctx, new_back_buffer)
566+
.expect("Where's the new front buffer?"),
567+
};
546568
println!("... front buffer is now {:?}", new_front_buffer.id());
547569

548570
// Hand the new front buffer to the compositor.

0 commit comments

Comments
 (0)