aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorAlan Jeffrey <ajeffrey@mozilla.com>2020-01-09 17:28:46 -0600
committerAlan Jeffrey <ajeffrey@mozilla.com>2020-04-17 23:44:53 -0500
commit8bb1732258c44e6850618a8f2fbb2927bc01b090 (patch)
treee4483e94fd5fbceb15fe9e35e3d5a085d3b2b814 /components
parent9dbc6554f087ca3675104fb1bac45b0c442a0158 (diff)
downloadservo-8bb1732258c44e6850618a8f2fbb2927bc01b090.tar.gz
servo-8bb1732258c44e6850618a8f2fbb2927bc01b090.zip
Update surfman to 0.2 and remove glutin
Diffstat (limited to 'components')
-rw-r--r--components/canvas/Cargo.toml3
-rw-r--r--components/canvas/webgl_mode/inprocess.rs46
-rw-r--r--components/canvas/webgl_thread.rs442
-rw-r--r--components/canvas_traits/webgl.rs2
-rw-r--r--components/compositing/Cargo.toml1
-rw-r--r--components/compositing/compositor.rs66
-rw-r--r--components/compositing/compositor_thread.rs4
-rw-r--r--components/compositing/lib.rs1
-rw-r--r--components/compositing/windowing.rs21
-rw-r--r--components/config/prefs.rs6
-rw-r--r--components/script/dom/webgl_extensions/extensions.rs22
-rw-r--r--components/script/dom/webglrenderbuffer.rs2
-rw-r--r--components/script/dom/webglshader.rs45
-rw-r--r--components/servo/Cargo.toml3
-rw-r--r--components/servo/lib.rs95
-rw-r--r--components/webrender_surfman/Cargo.toml17
-rw-r--r--components/webrender_surfman/lib.rs213
-rw-r--r--components/webrender_traits/Cargo.toml1
-rw-r--r--components/webrender_traits/lib.rs2
19 files changed, 738 insertions, 254 deletions
diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml
index 0917ad981a0..9dba07b7a15 100644
--- a/components/canvas/Cargo.toml
+++ b/components/canvas/Cargo.toml
@@ -38,9 +38,10 @@ servo_config = {path = "../config"}
sparkle = "0.1.22"
webrender = {git = "https://github.com/servo/webrender"}
webrender_api = {git = "https://github.com/servo/webrender"}
+webrender_surfman = {path = "../webrender_surfman"}
webrender_traits = {path = "../webrender_traits"}
webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]}
# NOTE: the sm-angle feature only enables angle on windows, not other platforms!
-surfman = { version = "0.1", features = ["sm-angle", "sm-osmesa"] }
+surfman = { version = "0.2", features = ["sm-angle","sm-angle-default"] }
surfman-chains = "0.3"
surfman-chains-api = "0.2"
diff --git a/components/canvas/webgl_mode/inprocess.rs b/components/canvas/webgl_mode/inprocess.rs
index a5707c29069..ff744481770 100644
--- a/components/canvas/webgl_mode/inprocess.rs
+++ b/components/canvas/webgl_mode/inprocess.rs
@@ -15,19 +15,19 @@ use std::collections::HashMap;
use std::default::Default;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
-use surfman::platform::generic::universal::context::Context;
-use surfman::platform::generic::universal::device::Device;
-use surfman::platform::generic::universal::surface::SurfaceTexture;
+use surfman::Device;
use surfman::SurfaceInfo;
+use surfman::SurfaceTexture;
use surfman_chains::SwapChains;
use surfman_chains_api::SwapChainAPI;
use surfman_chains_api::SwapChainsAPI;
+use webrender_surfman::WebrenderSurfman;
use webrender_traits::{WebrenderExternalImageApi, WebrenderExternalImageRegistry};
use webxr_api::SwapChainId as WebXRSwapChainId;
pub struct WebGLComm {
pub webgl_threads: WebGLThreads,
- pub webxr_swap_chains: SwapChains<WebXRSwapChainId>,
+ pub webxr_swap_chains: SwapChains<WebXRSwapChainId, Device>,
pub webxr_surface_providers: SurfaceProviders,
pub image_handler: Box<dyn WebrenderExternalImageApi>,
pub output_handler: Option<Box<dyn webrender_api::OutputImageHandler>>,
@@ -37,8 +37,7 @@ pub struct WebGLComm {
impl WebGLComm {
/// Creates a new `WebGLComm` object.
pub fn new(
- device: Device,
- context: Context,
+ surfman: WebrenderSurfman,
webrender_gl: Rc<dyn gleam::gl::Gl>,
webrender_api_sender: webrender_api::RenderApiSender,
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
@@ -60,8 +59,8 @@ impl WebGLComm {
webrender_swap_chains: webrender_swap_chains.clone(),
webxr_swap_chains: webxr_swap_chains.clone(),
webxr_surface_providers: webxr_surface_providers.clone(),
- connection: device.connection(),
- adapter: device.adapter(),
+ connection: surfman.connection(),
+ adapter: surfman.adapter(),
api_type,
runnable_receiver,
};
@@ -72,7 +71,7 @@ impl WebGLComm {
None
};
- let external = WebGLExternalImages::new(device, context, webrender_swap_chains);
+ let external = WebGLExternalImages::new(surfman, webrender_swap_chains);
WebGLThread::run_on_own_thread(init);
@@ -89,23 +88,15 @@ impl WebGLComm {
/// Bridge between the webrender::ExternalImage callbacks and the WebGLThreads.
struct WebGLExternalImages {
- device: Device,
- context: Context,
- swap_chains: SwapChains<WebGLContextId>,
+ surfman: WebrenderSurfman,
+ swap_chains: SwapChains<WebGLContextId, Device>,
locked_front_buffers: FnvHashMap<WebGLContextId, SurfaceTexture>,
}
-impl Drop for WebGLExternalImages {
- fn drop(&mut self) {
- let _ = self.device.destroy_context(&mut self.context);
- }
-}
-
impl WebGLExternalImages {
- fn new(device: Device, context: Context, swap_chains: SwapChains<WebGLContextId>) -> Self {
+ fn new(surfman: WebrenderSurfman, swap_chains: SwapChains<WebGLContextId, Device>) -> Self {
Self {
- device,
- context,
+ surfman,
swap_chains,
locked_front_buffers: FnvHashMap::default(),
}
@@ -119,13 +110,10 @@ impl WebGLExternalImages {
id: front_buffer_id,
size,
..
- } = self.device.surface_info(&front_buffer);
+ } = self.surfman.surface_info(&front_buffer);
debug!("... getting texture for surface {:?}", front_buffer_id);
- let front_buffer_texture = self
- .device
- .create_surface_texture(&mut self.context, front_buffer)
- .unwrap();
- let gl_texture = front_buffer_texture.gl_texture();
+ let front_buffer_texture = self.surfman.create_surface_texture(front_buffer).unwrap();
+ let gl_texture = self.surfman.surface_texture_object(&front_buffer_texture);
self.locked_front_buffers.insert(id, front_buffer_texture);
@@ -135,8 +123,8 @@ impl WebGLExternalImages {
fn unlock_swap_chain(&mut self, id: WebGLContextId) -> Option<()> {
let locked_front_buffer = self.locked_front_buffers.remove(&id)?;
let locked_front_buffer = self
- .device
- .destroy_surface_texture(&mut self.context, locked_front_buffer)
+ .surfman
+ .destroy_surface_texture(locked_front_buffer)
.unwrap();
debug!("... unlocked chain {:?}", id);
diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs
index bb643bf3192..a8736e39280 100644
--- a/components/canvas/webgl_thread.rs
+++ b/components/canvas/webgl_thread.rs
@@ -47,7 +47,6 @@ use euclid::default::Size2D;
use fnv::FnvHashMap;
use half::f16;
use pixels::{self, PixelFormat};
-use servo_config::opts;
use sparkle::gl;
use sparkle::gl::GLint;
use sparkle::gl::GLuint;
@@ -59,12 +58,12 @@ use std::slice;
use std::sync::{Arc, Mutex};
use std::thread;
use surfman;
-use surfman::platform::generic::universal::adapter::Adapter;
-use surfman::platform::generic::universal::connection::Connection;
-use surfman::platform::generic::universal::context::Context;
-use surfman::platform::generic::universal::device::Device;
+use surfman::Adapter;
+use surfman::Connection;
+use surfman::Context;
use surfman::ContextAttributeFlags;
use surfman::ContextAttributes;
+use surfman::Device;
use surfman::GLVersion;
use surfman::SurfaceAccess;
use surfman::SurfaceInfo;
@@ -87,30 +86,130 @@ struct GLContextData {
attributes: GLContextAttributes,
}
+#[derive(Debug)]
pub struct GLState {
webgl_version: WebGLVersion,
gl_version: GLVersion,
+ requested_flags: ContextAttributeFlags,
+ // This is the WebGL view of the color mask
+ // The GL view may be different: if the GL context supports alpha
+ // but the WebGL context doesn't, then color_write_mask.3 might be true
+ // but the GL color write mask is false.
+ color_write_mask: [bool; 4],
clear_color: (f32, f32, f32, f32),
scissor_test_enabled: bool,
+ // The WebGL view of the stencil write mask (see comment re `color_write_mask`)
stencil_write_mask: (u32, u32),
+ stencil_test_enabled: bool,
stencil_clear_value: i32,
+ // The WebGL view of the depth write mask (see comment re `color_write_mask`)
depth_write_mask: bool,
+ depth_test_enabled: bool,
depth_clear_value: f64,
+ // True when the default framebuffer is bound to DRAW_FRAMEBUFFER
+ drawing_to_default_framebuffer: bool,
default_vao: gl::GLuint,
}
+impl GLState {
+ // Are we faking having no alpha / depth / stencil?
+ fn fake_no_alpha(&self) -> bool {
+ self.drawing_to_default_framebuffer &
+ !self.requested_flags.contains(ContextAttributeFlags::ALPHA)
+ }
+
+ fn fake_no_depth(&self) -> bool {
+ self.drawing_to_default_framebuffer &
+ !self.requested_flags.contains(ContextAttributeFlags::DEPTH)
+ }
+
+ fn fake_no_stencil(&self) -> bool {
+ self.drawing_to_default_framebuffer &
+ !self
+ .requested_flags
+ .contains(ContextAttributeFlags::STENCIL)
+ }
+
+ // We maintain invariants between the GLState object and the GL state.
+ fn restore_invariant(&self, gl: &Gl) {
+ self.restore_clear_color_invariant(gl);
+ self.restore_scissor_invariant(gl);
+ self.restore_alpha_invariant(gl);
+ self.restore_depth_invariant(gl);
+ self.restore_stencil_invariant(gl);
+ }
+
+ fn restore_clear_color_invariant(&self, gl: &Gl) {
+ let (r, g, b, a) = self.clear_color;
+ gl.clear_color(r, g, b, a);
+ }
+
+ fn restore_scissor_invariant(&self, gl: &Gl) {
+ if self.scissor_test_enabled {
+ gl.enable(gl::SCISSOR_TEST);
+ } else {
+ gl.disable(gl::SCISSOR_TEST);
+ }
+ }
+
+ fn restore_alpha_invariant(&self, gl: &Gl) {
+ let [r, g, b, a] = self.color_write_mask;
+ if self.fake_no_alpha() {
+ gl.color_mask(r, g, b, false);
+ } else {
+ gl.color_mask(r, g, b, a);
+ }
+ }
+
+ fn restore_depth_invariant(&self, gl: &Gl) {
+ if self.fake_no_depth() {
+ gl.depth_mask(false);
+ gl.disable(gl::DEPTH_TEST);
+ } else {
+ gl.depth_mask(self.depth_write_mask);
+ if self.depth_test_enabled {
+ gl.enable(gl::DEPTH_TEST);
+ } else {
+ gl.disable(gl::DEPTH_TEST);
+ }
+ }
+ }
+
+ fn restore_stencil_invariant(&self, gl: &Gl) {
+ if self.fake_no_stencil() {
+ gl.stencil_mask(0);
+ gl.disable(gl::STENCIL_TEST);
+ } else {
+ let (f, b) = self.stencil_write_mask;
+ gl.stencil_mask_separate(gl::FRONT, f);
+ gl.stencil_mask_separate(gl::BACK, b);
+ if self.stencil_test_enabled {
+ gl.enable(gl::STENCIL_TEST);
+ } else {
+ gl.disable(gl::STENCIL_TEST);
+ }
+ }
+ }
+}
+
impl Default for GLState {
fn default() -> GLState {
GLState {
gl_version: GLVersion { major: 1, minor: 0 },
webgl_version: WebGLVersion::WebGL1,
+ requested_flags: ContextAttributeFlags::empty(),
+ color_write_mask: [true, true, true, true],
clear_color: (0., 0., 0., 0.),
scissor_test_enabled: false,
+ // Should these be 0xFFFF_FFFF?
stencil_write_mask: (0, 0),
+ stencil_test_enabled: false,
stencil_clear_value: 0,
depth_write_mask: true,
+ depth_test_enabled: false,
depth_clear_value: 1.,
default_vao: 0,
+ drawing_to_default_framebuffer: true,
}
}
}
@@ -138,9 +237,9 @@ pub(crate) struct WebGLThread {
/// The receiver that should be used to send WebGL messages for processing.
sender: WebGLSender<WebGLMsg>,
/// The swap chains used by webrender
- webrender_swap_chains: SwapChains<WebGLContextId>,
+ webrender_swap_chains: SwapChains<WebGLContextId, Device>,
/// The swap chains used by webxr
- webxr_swap_chains: SwapChains<WebXRSwapChainId>,
+ webxr_swap_chains: SwapChains<WebXRSwapChainId, Device>,
/// The set of all surface providers corresponding to WebXR sessions.
webxr_surface_providers: SurfaceProviders,
/// A channel to allow arbitrary threads to execute tasks that run in the WebGL thread.
@@ -150,9 +249,9 @@ pub(crate) struct WebGLThread {
}
pub type WebGlExecutor = crossbeam_channel::Sender<WebGlRunnable>;
-pub type WebGlRunnable = Box<dyn FnOnce() + Send>;
+pub type WebGlRunnable = Box<dyn FnOnce(&Device) + Send>;
pub type SurfaceProviders = Arc<Mutex<HashMap<SessionId, SurfaceProvider>>>;
-pub type SurfaceProvider = Box<dyn surfman_chains::SurfaceProvider + Send>;
+pub type SurfaceProvider = Box<dyn surfman_chains::SurfaceProvider<Device> + Send>;
/// The data required to initialize an instance of the WebGLThread type.
pub(crate) struct WebGLThreadInit {
@@ -161,8 +260,8 @@ pub(crate) struct WebGLThreadInit {
pub external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
pub sender: WebGLSender<WebGLMsg>,
pub receiver: WebGLReceiver<WebGLMsg>,
- pub webrender_swap_chains: SwapChains<WebGLContextId>,
- pub webxr_swap_chains: SwapChains<WebXRSwapChainId>,
+ pub webrender_swap_chains: SwapChains<WebGLContextId, Device>,
+ pub webxr_swap_chains: SwapChains<WebXRSwapChainId, Device>,
pub connection: Connection,
pub adapter: Adapter,
pub api_type: gl::GlType,
@@ -190,7 +289,9 @@ impl WebGLThread {
}: WebGLThreadInit,
) -> Self {
WebGLThread {
- device: Device::new(&connection, &adapter).expect("Couldn't open WebGL device!"),
+ device: connection
+ .create_device(&adapter)
+ .expect("Couldn't open WebGL device!"),
webrender_api: webrender_api_sender.create_api(),
contexts: Default::default(),
cached_context_info: Default::default(),
@@ -236,7 +337,7 @@ impl WebGLThread {
}
recv(self.runnable_receiver) -> msg => {
if let Ok(msg) = msg {
- msg();
+ msg(&self.device);
} else {
self.runnable_receiver = crossbeam_channel::never();
}
@@ -303,7 +404,7 @@ impl WebGLThread {
.unwrap();
},
WebGLMsg::ResizeContext(ctx_id, size, sender) => {
- self.resize_webgl_context(ctx_id, size, sender);
+ let _ = sender.send(self.resize_webgl_context(ctx_id, size));
},
WebGLMsg::RemoveContext(ctx_id) => {
self.remove_webgl_context(ctx_id);
@@ -394,21 +495,35 @@ impl WebGLThread {
requested_size: Size2D<u32>,
attributes: GLContextAttributes,
) -> Result<(WebGLContextId, webgl::GLLimits), String> {
- debug!("WebGLThread::create_webgl_context({:?})", requested_size);
+ debug!(
+ "WebGLThread::create_webgl_context({:?}, {:?}, {:?})",
+ webgl_version, requested_size, attributes
+ );
// Creating a new GLContext may make the current bound context_id dirty.
// Clear it to ensure that make_current() is called in subsequent commands.
self.bound_context_id = None;
+ let requested_flags =
+ attributes.to_surfman_context_attribute_flags(webgl_version, self.api_type);
+ // Some GL implementations seem to only allow famebuffers
+ // to have alpha, depth and stencil if their creating context does.
+ // WebGL requires all contexts to be able to create framebuffers with
+ // alpha, depth and stencil. So we always create a context with them,
+ // and fake not having them if requested.
+ let flags = requested_flags |
+ ContextAttributeFlags::ALPHA |
+ ContextAttributeFlags::DEPTH |
+ ContextAttributeFlags::STENCIL;
let context_attributes = &ContextAttributes {
- version: webgl_version.to_surfman_version(),
- flags: attributes.to_surfman_context_attribute_flags(webgl_version),
+ version: webgl_version.to_surfman_version(self.api_type),
+ flags: flags,
};
let context_descriptor = self
.device
.create_context_descriptor(&context_attributes)
- .unwrap();
+ .map_err(|err| format!("Failed to create context descriptor: {:?}", err))?;
let safe_size = Size2D::new(
requested_size.width.min(SAFE_VIEWPORT_DIMS[0]).max(1),
@@ -423,30 +538,30 @@ impl WebGLThread {
let mut ctx = self
.device
.create_context(&context_descriptor)
- .expect("Failed to create the GL context!");
+ .map_err(|err| format!("Failed to create the GL context: {:?}", err))?;
let surface = self
.device
- .create_surface(&ctx, surface_access, &surface_type)
- .expect("Failed to create the initial surface!");
+ .create_surface(&ctx, surface_access, surface_type)
+ .map_err(|err| format!("Failed to create the initial surface: {:?}", err))?;
self.device
.bind_surface_to_context(&mut ctx, surface)
- .unwrap();
+ .map_err(|err| format!("Failed to bind initial surface: {:?}", err))?;
// https://github.com/pcwalton/surfman/issues/7
self.device
.make_context_current(&ctx)
- .expect("failed to make new context current");
+ .map_err(|err| format!("Failed to make new context current: {:?}", err))?;
let id = WebGLContextId(
self.external_images
.lock()
- .unwrap()
+ .expect("Lock poisoned?")
.next_id(WebrenderImageHandlerType::WebGL)
.0,
);
self.webrender_swap_chains
.create_attached_swap_chain(id, &mut self.device, &mut ctx, surface_provider)
- .expect("Failed to create the swap chain");
+ .map_err(|err| format!("Failed to create swap chain: {:?}", err))?;
let swap_chain = self
.webrender_swap_chains
@@ -456,7 +571,7 @@ impl WebGLThread {
debug!(
"Created webgl context {:?}/{:?}",
id,
- self.device.context_id(&ctx)
+ self.device.context_id(&ctx),
);
let gl = match self.api_type {
@@ -475,34 +590,33 @@ impl WebGLThread {
debug!("Resizing swap chain from {} to {}", safe_size, size);
swap_chain
.resize(&mut self.device, &mut ctx, size.to_i32())
- .expect("Failed to resize swap chain");
+ .map_err(|err| format!("Failed to resize swap chain: {:?}", err))?;
}
+ let descriptor = self.device.context_descriptor(&ctx);
+ let descriptor_attributes = self.device.context_descriptor_attributes(&descriptor);
+ let gl_version = descriptor_attributes.version;
+ let has_alpha = requested_flags.contains(ContextAttributeFlags::ALPHA);
+ let texture_target = current_wr_texture_target(&self.device);
+
self.device.make_context_current(&ctx).unwrap();
let framebuffer = self
.device
.context_surface_info(&ctx)
- .unwrap()
- .unwrap()
+ .map_err(|err| format!("Failed to get context surface info: {:?}", err))?
+ .ok_or_else(|| format!("Failed to get context surface info"))?
.framebuffer_object;
+
gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer);
gl.viewport(0, 0, size.width as i32, size.height as i32);
gl.scissor(0, 0, size.width as i32, size.height as i32);
- gl.clear_color(0., 0., 0., 0.);
+ gl.clear_color(0., 0., 0., !has_alpha as u32 as f32);
gl.clear_depth(1.);
gl.clear_stencil(0);
gl.clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
+ gl.clear_color(0., 0., 0., 0.);
debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
- let descriptor = self.device.context_descriptor(&ctx);
- let descriptor_attributes = self.device.context_descriptor_attributes(&descriptor);
-
- let gl_version = descriptor_attributes.version;
- let has_alpha = descriptor_attributes
- .flags
- .contains(ContextAttributeFlags::ALPHA);
- let texture_target = current_wr_texture_target(&self.device);
-
let use_apple_vertex_array = WebGLImpl::needs_apple_vertex_arrays(gl_version);
let default_vao = if let Some(vao) =
WebGLImpl::create_vertex_array(&gl, use_apple_vertex_array, webgl_version)
@@ -517,9 +631,15 @@ impl WebGLThread {
let state = GLState {
gl_version,
webgl_version,
+ requested_flags,
default_vao,
..Default::default()
};
+ debug!("Created state {:?}", state);
+
+ state.restore_invariant(&*gl);
+ debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
+
self.contexts.insert(
id,
GLContextData {
@@ -549,8 +669,7 @@ impl WebGLThread {
&mut self,
context_id: WebGLContextId,
requested_size: Size2D<u32>,
- sender: WebGLSender<Result<(), String>>,
- ) {
+ ) -> Result<(), String> {
let data = Self::make_current_if_needed_mut(
&self.device,
context_id,
@@ -568,16 +687,17 @@ impl WebGLThread {
// Resize the swap chains
if let Some(swap_chain) = self.webrender_swap_chains.get(context_id) {
+ let alpha = data
+ .state
+ .requested_flags
+ .contains(ContextAttributeFlags::ALPHA);
+ let clear_color = [0.0, 0.0, 0.0, !alpha as i32 as f32];
swap_chain
.resize(&mut self.device, &mut data.ctx, size.to_i32())
- .expect("Failed to resize swap chain");
- // temporary, till https://github.com/pcwalton/surfman/issues/35 is fixed
- self.device
- .make_context_current(&data.ctx)
- .expect("Failed to make context current again");
+ .map_err(|err| format!("Failed to resize swap chain: {:?}", err))?;
swap_chain
- .clear_surface(&mut self.device, &mut data.ctx, &*data.gl)
- .expect("Failed to clear resized swap chain");
+ .clear_surface(&mut self.device, &mut data.ctx, &*data.gl, clear_color)
+ .map_err(|err| format!("Failed to clear resized swap chain: {:?}", err))?;
} else {
error!("Failed to find swap chain");
}
@@ -587,11 +707,9 @@ impl WebGLThread {
// Update WR image if needed.
let info = self.cached_context_info.get_mut(&context_id).unwrap();
- let context_descriptor = self.device.context_descriptor(&data.ctx);
- let has_alpha = self
- .device
- .context_descriptor_attributes(&context_descriptor)
- .flags
+ let has_alpha = data
+ .state
+ .requested_flags
.contains(ContextAttributeFlags::ALPHA);
let texture_target = current_wr_texture_target(&self.device);
Self::update_wr_external_image(
@@ -605,7 +723,7 @@ impl WebGLThread {
debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR);
- sender.send(Ok(())).unwrap();
+ Ok(())
}
/// Removes a WebGLContext and releases attached resources.
@@ -697,8 +815,13 @@ impl WebGLThread {
// TODO: if preserveDrawingBuffer is true, then blit the front buffer to the back buffer
// https://github.com/servo/servo/issues/24604
debug!("Clearing {:?}", swap_id);
+ let alpha = data
+ .state
+ .requested_flags
+ .contains(ContextAttributeFlags::ALPHA);
+ let clear_color = [0.0, 0.0, 0.0, !alpha as i32 as f32];
swap_chain
- .clear_surface(&mut self.device, &mut data.ctx, &*data.gl)
+ .clear_surface(&mut self.device, &mut data.ctx, &*data.gl, clear_color)
.unwrap();
debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR);
@@ -1084,7 +1207,10 @@ impl WebGLImpl {
state.stencil_clear_value = stencil;
gl.clear_stencil(stencil);
},
- WebGLCommand::ColorMask(r, g, b, a) => gl.color_mask(r, g, b, a),
+ WebGLCommand::ColorMask(r, g, b, a) => {
+ state.color_write_mask = [r, g, b, a];
+ state.restore_alpha_invariant(gl);
+ },
WebGLCommand::CopyTexImage2D(
target,
level,
@@ -1109,22 +1235,40 @@ impl WebGLImpl {
WebGLCommand::DepthFunc(func) => gl.depth_func(func),
WebGLCommand::DepthMask(flag) => {
state.depth_write_mask = flag;
- gl.depth_mask(flag);
+ state.restore_depth_invariant(gl);
},
WebGLCommand::DepthRange(near, far) => {
gl.depth_range(near.max(0.).min(1.) as f64, far.max(0.).min(1.) as f64)
},
- WebGLCommand::Disable(cap) => {
- if cap == gl::SCISSOR_TEST {
+ WebGLCommand::Disable(cap) => match cap {
+ gl::SCISSOR_TEST => {
state.scissor_test_enabled = false;
- }
- gl.disable(cap);
+ state.restore_scissor_invariant(gl);
+ },
+ gl::DEPTH_TEST => {
+ state.depth_test_enabled = false;
+ state.restore_depth_invariant(gl);
+ },
+ gl::STENCIL_TEST => {
+ state.stencil_test_enabled = false;
+ state.restore_stencil_invariant(gl);
+ },
+ _ => gl.disable(cap),
},
- WebGLCommand::Enable(cap) => {
- if cap == gl::SCISSOR_TEST {
+ WebGLCommand::Enable(cap) => match cap {
+ gl::SCISSOR_TEST => {
state.scissor_test_enabled = true;
- }
- gl.enable(cap);
+ state.restore_scissor_invariant(gl);
+ },
+ gl::DEPTH_TEST => {
+ state.depth_test_enabled = true;
+ state.restore_depth_invariant(gl);
+ },
+ gl::STENCIL_TEST => {
+ state.stencil_test_enabled = true;
+ state.restore_stencil_invariant(gl);
+ },
+ _ => gl.enable(cap),
},
WebGLCommand::FramebufferRenderbuffer(target, attachment, renderbuffertarget, rb) => {
let attach = |attachment| {
@@ -1221,7 +1365,7 @@ impl WebGLImpl {
},
WebGLCommand::StencilMask(mask) => {
state.stencil_write_mask = (mask, mask);
- gl.stencil_mask(mask);
+ state.restore_stencil_invariant(gl);
},
WebGLCommand::StencilMaskSeparate(face, mask) => {
if face == gl::FRONT {
@@ -1229,7 +1373,7 @@ impl WebGLImpl {
} else {
state.stencil_write_mask.1 = mask;
}
- gl.stencil_mask_separate(face, mask);
+ state.restore_stencil_invariant(gl);
},
WebGLCommand::StencilOp(fail, zfail, zpass) => gl.stencil_op(fail, zfail, zpass),
WebGLCommand::StencilOpSeparate(face, fail, zfail, zpass) => {
@@ -1321,7 +1465,7 @@ impl WebGLImpl {
gl.bind_buffer(target, id.map_or(0, WebGLBufferId::get))
},
WebGLCommand::BindFramebuffer(target, request) => {
- Self::bind_framebuffer(gl, target, request, ctx, device)
+ Self::bind_framebuffer(gl, target, request, ctx, device, state)
},
WebGLCommand::BindRenderbuffer(target, id) => {
gl.bind_renderbuffer(target, id.map_or(0, WebGLRenderbufferId::get))
@@ -1557,11 +1701,15 @@ impl WebGLImpl {
Self::bind_vertex_array(gl, id, use_apple_vertex_array, state.webgl_version);
},
WebGLCommand::GetParameterBool(param, ref sender) => {
- let mut value = [0];
- unsafe {
- gl.get_boolean_v(param as u32, &mut value);
- }
- sender.send(value[0] != 0).unwrap()
+ let value = match param {
+ webgl::ParameterBool::DepthWritemask => state.depth_write_mask,
+ _ => unsafe {
+ let mut value = [0];
+ gl.get_boolean_v(param as u32, &mut value);
+ value[0] != 0
+ },
+ };
+ sender.send(value).unwrap()
},
WebGLCommand::FenceSync(ref sender) => {
let value = gl.fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0);
@@ -1588,19 +1736,25 @@ impl WebGLImpl {
gl.delete_sync(sync_id.get() as *const _);
},
WebGLCommand::GetParameterBool4(param, ref sender) => {
- let mut value = [0; 4];
- unsafe {
- gl.get_boolean_v(param as u32, &mut value);
- }
- let value = [value[0] != 0, value[1] != 0, value[2] != 0, value[3] != 0];
+ let value = match param {
+ webgl::ParameterBool4::ColorWritemask => state.color_write_mask,
+ };
sender.send(value).unwrap()
},
WebGLCommand::GetParameterInt(param, ref sender) => {
- let mut value = [0];
- unsafe {
- gl.get_integer_v(param as u32, &mut value);
- }
- sender.send(value[0]).unwrap()
+ let value = match param {
+ webgl::ParameterInt::AlphaBits if state.fake_no_alpha() => 0,
+ webgl::ParameterInt::DepthBits if state.fake_no_depth() => 0,
+ webgl::ParameterInt::StencilBits if state.fake_no_stencil() => 0,
+ webgl::ParameterInt::StencilWritemask => state.stencil_write_mask.0 as i32,
+ webgl::ParameterInt::StencilBackWritemask => state.stencil_write_mask.1 as i32,
+ _ => unsafe {
+ let mut value = [0];
+ gl.get_integer_v(param as u32, &mut value);
+ value[0]
+ },
+ };
+ sender.send(value).unwrap()
},
WebGLCommand::GetParameterInt2(param, ref sender) => {
let mut value = [0; 2];
@@ -1978,15 +2132,25 @@ impl WebGLImpl {
sender.send(value).unwrap();
},
WebGLCommand::BindBufferBase(target, index, id) => {
- gl.bind_buffer_base(target, index, id.map_or(0, WebGLBufferId::get))
+ // https://searchfox.org/mozilla-central/rev/13b081a62d3f3e3e3120f95564529257b0bf451c/dom/canvas/WebGLContextBuffers.cpp#208-210
+ // BindBufferBase/Range will fail (on some drivers) if the buffer name has
+ // never been bound. (GenBuffers makes a name, but BindBuffer initializes
+ // that name as a real buffer object)
+ let id = id.map_or(0, WebGLBufferId::get);
+ gl.bind_buffer(target, id);
+ gl.bind_buffer(target, 0);
+ gl.bind_buffer_base(target, index, id);
+ },
+ WebGLCommand::BindBufferRange(target, index, id, offset, size) => {
+ // https://searchfox.org/mozilla-central/rev/13b081a62d3f3e3e3120f95564529257b0bf451c/dom/canvas/WebGLContextBuffers.cpp#208-210
+ // BindBufferBase/Range will fail (on some drivers) if the buffer name has
+ // never been bound. (GenBuffers makes a name, but BindBuffer initializes
+ // that name as a real buffer object)
+ let id = id.map_or(0, WebGLBufferId::get);
+ gl.bind_buffer(target, id);
+ gl.bind_buffer(target, 0);
+ gl.bind_buffer_range(target, index, id, offset as isize, size as isize);
},
- WebGLCommand::BindBufferRange(target, index, id, offset, size) => gl.bind_buffer_range(
- target,
- index,
- id.map_or(0, WebGLBufferId::get),
- offset as isize,
- size as isize,
- ),
WebGLCommand::ClearBufferfv(buffer, draw_buffer, ref value) => {
gl.clear_buffer_fv(buffer, draw_buffer, value)
},
@@ -2065,47 +2229,17 @@ impl WebGLImpl {
bits | if enabled { bit } else { 0 }
});
- if state.scissor_test_enabled {
- gl.disable(gl::SCISSOR_TEST);
- }
-
- if color {
- gl.clear_color(0., 0., 0., 0.);
- }
-
- if depth {
- gl.depth_mask(true);
- gl.clear_depth(1.);
- }
-
- if stencil {
- gl.stencil_mask_separate(gl::FRONT, 0xFFFFFFFF);
- gl.stencil_mask_separate(gl::BACK, 0xFFFFFFFF);
- gl.clear_stencil(0);
- }
-
+ gl.disable(gl::SCISSOR_TEST);
+ gl.color_mask(true, true, true, true);
+ gl.clear_color(0., 0., 0., 0.);
+ gl.depth_mask(true);
+ gl.clear_depth(1.);
+ gl.stencil_mask_separate(gl::FRONT, 0xFFFFFFFF);
+ gl.stencil_mask_separate(gl::BACK, 0xFFFFFFFF);
+ gl.clear_stencil(0);
gl.clear(bits);
- if state.scissor_test_enabled {
- gl.enable(gl::SCISSOR_TEST);
- }
-
- if color {
- let (r, g, b, a) = state.clear_color;
- gl.clear_color(r, g, b, a);
- }
-
- if depth {
- gl.depth_mask(state.depth_write_mask);
- gl.clear_depth(state.depth_clear_value);
- }
-
- if stencil {
- let (front, back) = state.stencil_write_mask;
- gl.stencil_mask_separate(gl::FRONT, front);
- gl.stencil_mask_separate(gl::BACK, back);
- gl.clear_stencil(state.stencil_clear_value);
- }
+ state.restore_invariant(gl);
}
#[allow(unsafe_code)]
@@ -2213,6 +2347,7 @@ impl WebGLImpl {
&mut transform_feedback_mode,
);
}
+
ProgramLinkInfo {
linked: true,
active_attribs,
@@ -2243,7 +2378,7 @@ impl WebGLImpl {
// array object functions, but support a set of APPLE extension functions that
// provide VAO support instead.
fn needs_apple_vertex_arrays(gl_version: GLVersion) -> bool {
- cfg!(target_os = "macos") && !opts::get().headless && gl_version.major < 3
+ cfg!(target_os = "macos") && gl_version.major < 3
}
#[allow(unsafe_code)]
@@ -2427,8 +2562,8 @@ impl WebGLImpl {
/// Updates the swap buffers if the context surface needs to be changed
fn attach_surface(
context_id: WebGLContextId,
- webrender_swap_chains: &SwapChains<WebGLContextId>,
- webxr_swap_chains: &SwapChains<WebXRSwapChainId>,
+ webrender_swap_chains: &SwapChains<WebGLContextId, Device>,
+ webxr_swap_chains: &SwapChains<WebXRSwapChainId, Device>,
request: WebGLFramebufferBindingRequest,
ctx: &mut Context,
device: &mut Device,
@@ -2479,6 +2614,7 @@ impl WebGLImpl {
request: WebGLFramebufferBindingRequest,
ctx: &Context,
device: &Device,
+ state: &mut GLState,
) {
let id = match request {
WebGLFramebufferBindingRequest::Explicit(WebGLFramebufferId::Transparent(id)) => {
@@ -2496,6 +2632,12 @@ impl WebGLImpl {
debug!("WebGLImpl::bind_framebuffer: {:?}", id);
gl.bind_framebuffer(target, id);
+
+ if (target == gl::FRAMEBUFFER) || (target == gl::DRAW_FRAMEBUFFER) {
+ state.drawing_to_default_framebuffer =
+ request == WebGLFramebufferBindingRequest::Default;
+ state.restore_invariant(gl);
+ }
}
#[inline]
@@ -2885,27 +3027,41 @@ fn flip_pixels_y(
// Clamp a size to the current GL context's max viewport
fn clamp_viewport(gl: &Gl, size: Size2D<u32>) -> Size2D<u32> {
- let mut max_size = [i32::max_value(), i32::max_value()];
+ let mut max_viewport = [i32::max_value(), i32::max_value()];
+ let mut max_renderbuffer = [i32::max_value()];
#[allow(unsafe_code)]
unsafe {
- gl.get_integer_v(gl::MAX_VIEWPORT_DIMS, &mut max_size);
+ gl.get_integer_v(gl::MAX_VIEWPORT_DIMS, &mut max_viewport);
+ gl.get_integer_v(gl::MAX_RENDERBUFFER_SIZE, &mut max_renderbuffer);
debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
}
Size2D::new(
- size.width.min(max_size[0] as u32).max(1),
- size.height.min(max_size[1] as u32).max(1),
+ size.width
+ .min(max_viewport[0] as u32)
+ .min(max_renderbuffer[0] as u32)
+ .max(1),
+ size.height
+ .min(max_viewport[1] as u32)
+ .min(max_renderbuffer[0] as u32)
+ .max(1),
)
}
trait ToSurfmanVersion {
- fn to_surfman_version(self) -> GLVersion;
+ fn to_surfman_version(self, api_type: gl::GlType) -> GLVersion;
}
impl ToSurfmanVersion for WebGLVersion {
- fn to_surfman_version(self) -> GLVersion {
+ fn to_surfman_version(self, api_type: gl::GlType) -> GLVersion {
+ if api_type == gl::GlType::Gles {
+ return GLVersion::new(3, 0);
+ }
match self {
- WebGLVersion::WebGL1 => GLVersion::new(2, 0),
- WebGLVersion::WebGL2 => GLVersion::new(3, 0),
+ // We make use of GL_PACK_PIXEL_BUFFER, which needs at least GL2.1
+ // We make use of compatibility mode, which needs at most GL3.0
+ WebGLVersion::WebGL1 => GLVersion::new(2, 1),
+ // The WebGL2 conformance tests use std140 layout, which needs at GL3.1
+ WebGLVersion::WebGL2 => GLVersion::new(3, 2),
}
}
}
@@ -2914,6 +3070,7 @@ trait SurfmanContextAttributeFlagsConvert {
fn to_surfman_context_attribute_flags(
&self,
webgl_version: WebGLVersion,
+ api_type: gl::GlType,
) -> ContextAttributeFlags;
}
@@ -2921,12 +3078,13 @@ impl SurfmanContextAttributeFlagsConvert for GLContextAttributes {
fn to_surfman_context_attribute_flags(
&self,
webgl_version: WebGLVersion,
+ api_type: gl::GlType,
) -> ContextAttributeFlags {
let mut flags = ContextAttributeFlags::empty();
flags.set(ContextAttributeFlags::ALPHA, self.alpha);
flags.set(ContextAttributeFlags::DEPTH, self.depth);
flags.set(ContextAttributeFlags::STENCIL, self.stencil);
- if webgl_version == WebGLVersion::WebGL1 {
+ if (webgl_version == WebGLVersion::WebGL1) && (api_type == gl::GlType::Gl) {
flags.set(ContextAttributeFlags::COMPATIBILITY_PROFILE, true);
}
flags
diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs
index e1537055280..510e20a590d 100644
--- a/components/canvas_traits/webgl.rs
+++ b/components/canvas_traits/webgl.rs
@@ -667,7 +667,7 @@ pub enum WebGLFramebufferId {
Opaque(WebGLOpaqueFramebufferId),
}
-#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum WebGLFramebufferBindingRequest {
Explicit(WebGLFramebufferId),
Default,
diff --git a/components/compositing/Cargo.toml b/components/compositing/Cargo.toml
index a6dcd9894d1..50f1d6f8456 100644
--- a/components/compositing/Cargo.toml
+++ b/components/compositing/Cargo.toml
@@ -40,6 +40,7 @@ style_traits = {path = "../style_traits"}
time = "0.1.17"
webrender = {git = "https://github.com/servo/webrender", features = ["capture"]}
webrender_api = {git = "https://github.com/servo/webrender"}
+webrender_surfman = {path = "../webrender_surfman"}
webxr = {git = "https://github.com/servo/webxr"}
[build-dependencies]
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs
index 19898928420..5a495ed1aa8 100644
--- a/components/compositing/compositor.rs
+++ b/components/compositing/compositor.rs
@@ -19,6 +19,7 @@ use gfx_traits::Epoch;
use image::{DynamicImage, ImageFormat};
use ipc_channel::ipc;
use libc::c_void;
+use log::warn;
use msg::constellation_msg::{PipelineId, PipelineIndex, PipelineNamespaceId};
use net_traits::image::base::Image;
use net_traits::image_cache::CorsStatus;
@@ -46,6 +47,7 @@ use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor};
use time::{now, precise_time_ns, precise_time_s};
use webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePoint, LayoutVector2D};
use webrender_api::{self, HitTestFlags, HitTestResult, ScrollLocation};
+use webrender_surfman::WebrenderSurfman;
#[derive(Debug, PartialEq)]
enum UnableToComposite {
@@ -178,6 +180,12 @@ pub struct IOCompositor<Window: WindowMethods + ?Sized> {
/// The webrender interface, if enabled.
webrender_api: webrender_api::RenderApi,
+ /// The surfman instance that webrender targets
+ webrender_surfman: WebrenderSurfman,
+
+ /// The GL bindings for webrender
+ webrender_gl: Rc<dyn gleam::gl::Gl>,
+
/// Some XR devices want to run on the main thread.
pub webxr_main_thread: webxr::MainThreadRegistry,
@@ -316,6 +324,8 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
webrender: state.webrender,
webrender_document: state.webrender_document,
webrender_api: state.webrender_api,
+ webrender_surfman: state.webrender_surfman,
+ webrender_gl: state.webrender_gl,
webxr_main_thread: state.webxr_main_thread,
pending_paint_metrics: HashMap::new(),
cursor: Cursor::None,
@@ -345,6 +355,9 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
convert_mouse_to_touch,
);
+ // Make sure the GL state is OK
+ compositor.assert_gl_framebuffer_complete();
+
// Set the size of the root layer.
compositor.update_zoom_transform();
@@ -352,7 +365,9 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
}
pub fn deinit(self) {
- self.window.make_gl_context_current();
+ if let Err(err) = self.webrender_surfman.make_gl_context_current() {
+ warn!("Failed to make GL context current: {:?}", err);
+ }
self.webrender.deinit();
}
@@ -1238,7 +1253,22 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
) -> Result<Option<Image>, UnableToComposite> {
let size = self.embedder_coordinates.framebuffer.to_u32();
- self.window.make_gl_context_current();
+ if let Err(err) = self.webrender_surfman.make_gl_context_current() {
+ warn!("Failed to make GL context current: {:?}", err);
+ }
+ self.assert_no_gl_error();
+
+ // Bind the webrender framebuffer
+ let framebuffer_object = self
+ .webrender_surfman
+ .context_surface_info()
+ .unwrap_or(None)
+ .map(|info| info.framebuffer_object)
+ .unwrap_or(0);
+ self.webrender_gl
+ .bind_framebuffer(gleam::gl::FRAMEBUFFER, framebuffer_object);
+ self.assert_gl_framebuffer_complete();
+
self.webrender.update();
let wait_for_stable_image = match target {
@@ -1266,7 +1296,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
CompositeTarget::Window => gl::RenderTargetInfo::default(),
#[cfg(feature = "gl")]
CompositeTarget::WindowAndPng | CompositeTarget::PngFile => gl::initialize_png(
- &*self.window.gl(),
+ &*self.webrender_gl,
FramebufferUintLength::new(size.width),
FramebufferUintLength::new(size.height),
),
@@ -1347,7 +1377,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
#[cfg(feature = "gl")]
CompositeTarget::WindowAndPng => {
let img = gl::draw_img(
- &*self.window.gl(),
+ &*self.webrender_gl,
rt_info,
x,
y,
@@ -1365,7 +1395,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
},
#[cfg(feature = "gl")]
CompositeTarget::PngFile => {
- let gl = &*self.window.gl();
+ let gl = &*self.webrender_gl;
profile(
ProfilerCategory::ImageSaving,
None,
@@ -1399,7 +1429,9 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
};
// Perform the page flip. This will likely block for a while.
- self.window.present();
+ if let Err(err) = self.webrender_surfman.present() {
+ warn!("Failed to present surface: {:?}", err);
+ }
self.last_composite_time = precise_time_ns();
@@ -1426,11 +1458,13 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
}
fn clear_background(&self) {
- let gl = self.window.gl();
+ let gl = &self.webrender_gl;
+ self.assert_gl_framebuffer_complete();
// Make framebuffer fully transparent.
gl.clear_color(0.0, 0.0, 0.0, 0.0);
gl.clear(gleam::gl::COLOR_BUFFER_BIT);
+ self.assert_gl_framebuffer_complete();
// Make the viewport white.
let viewport = self.embedder_coordinates.get_flipped_viewport();
@@ -1444,6 +1478,24 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
gl.enable(gleam::gl::SCISSOR_TEST);
gl.clear(gleam::gl::COLOR_BUFFER_BIT);
gl.disable(gleam::gl::SCISSOR_TEST);
+ self.assert_gl_framebuffer_complete();
+ }
+
+ #[track_caller]
+ fn assert_no_gl_error(&self) {
+ debug_assert_eq!(self.webrender_gl.get_error(), gleam::gl::NO_ERROR);
+ }
+
+ #[track_caller]
+ fn assert_gl_framebuffer_complete(&self) {
+ debug_assert_eq!(
+ (
+ self.webrender_gl.get_error(),
+ self.webrender_gl
+ .check_frame_buffer_status(gleam::gl::FRAMEBUFFER)
+ ),
+ (gleam::gl::NO_ERROR, gleam::gl::FRAMEBUFFER_COMPLETE)
+ );
}
fn get_root_pipeline_id(&self) -> Option<PipelineId> {
diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs
index 245ed1055ea..cbd715af0dd 100644
--- a/components/compositing/compositor_thread.rs
+++ b/components/compositing/compositor_thread.rs
@@ -17,12 +17,14 @@ use profile_traits::mem;
use profile_traits::time;
use script_traits::{AnimationState, EventResult, MouseButton, MouseEventType};
use std::fmt::{Debug, Error, Formatter};
+use std::rc::Rc;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use style_traits::viewport::ViewportConstraints;
use style_traits::CSSPixel;
use webrender_api;
use webrender_api::units::{DeviceIntPoint, DeviceIntSize};
+use webrender_surfman::WebrenderSurfman;
/// Sends messages to the compositor.
pub struct CompositorProxy {
@@ -166,6 +168,8 @@ pub struct InitialCompositorState {
pub webrender: webrender::Renderer,
pub webrender_document: webrender_api::DocumentId,
pub webrender_api: webrender_api::RenderApi,
+ pub webrender_surfman: WebrenderSurfman,
+ pub webrender_gl: Rc<dyn gleam::gl::Gl>,
pub webxr_main_thread: webxr::MainThreadRegistry,
pub pending_wr_frame: Arc<AtomicBool>,
}
diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs
index cc4f86922ff..da11e95fd55 100644
--- a/components/compositing/lib.rs
+++ b/components/compositing/lib.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#![deny(unsafe_code)]
+#![feature(track_caller)]
#[macro_use]
extern crate log;
diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs
index b3a48026e30..7a2784e08fd 100644
--- a/components/compositing/windowing.rs
+++ b/components/compositing/windowing.rs
@@ -7,8 +7,6 @@
use canvas::{SurfaceProviders, WebGlExecutor};
use embedder_traits::{EmbedderProxy, EventLoopWaker};
use euclid::Scale;
-#[cfg(feature = "gl")]
-use gleam::gl;
use keyboard_types::KeyboardEvent;
use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId, TraversalDirection};
use script_traits::{MediaSessionActionType, MouseButton, TouchEventType, TouchId, WheelDelta};
@@ -16,14 +14,13 @@ use servo_geometry::DeviceIndependentPixel;
use servo_media::player::context::{GlApi, GlContext, NativeDisplay};
use servo_url::ServoUrl;
use std::fmt::{Debug, Error, Formatter};
-#[cfg(feature = "gl")]
-use std::rc::Rc;
use std::time::Duration;
use style_traits::DevicePixel;
use webrender_api::units::DevicePoint;
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use webrender_api::ScrollLocation;
+use webrender_surfman::WebrenderSurfman;
#[derive(Clone)]
pub enum MouseWindowEvent {
@@ -148,14 +145,10 @@ pub enum AnimationState {
Animating,
}
+// TODO: this trait assumes that the window is responsible
+// for creating the GL context, making it current, buffer
+// swapping, etc. Really that should all be done by surfman.
pub trait WindowMethods {
- /// Presents the window to the screen (perhaps by page flipping).
- fn present(&self);
- /// Make the OpenGL context current.
- fn make_gl_context_current(&self);
- /// Return the GL function pointer trait.
- #[cfg(feature = "gl")]
- fn gl(&self) -> Rc<dyn gl::Gl>;
/// Get the coordinates of the native window, the screen and the framebuffer.
fn get_coordinates(&self) -> EmbedderCoordinates;
/// Set whether the application is currently animating.
@@ -163,12 +156,14 @@ pub trait WindowMethods {
/// will want to avoid blocking on UI events, and just
/// run the event loop at the vsync interval.
fn set_animation_state(&self, _state: AnimationState);
- /// Get the GL context
+ /// Get the media GL context
fn get_gl_context(&self) -> GlContext;
- /// Get the native display
+ /// Get the media native display
fn get_native_display(&self) -> NativeDisplay;
/// Get the GL api
fn get_gl_api(&self) -> GlApi;
+ /// Get the webrender surfman instance
+ fn webrender_surfman(&self) -> WebrenderSurfman;
}
pub trait EmbedderMethods {
diff --git a/components/config/prefs.rs b/components/config/prefs.rs
index 82f4d6a0057..2561ebf937f 100644
--- a/components/config/prefs.rs
+++ b/components/config/prefs.rs
@@ -321,7 +321,11 @@ mod gen {
subpixel_text_antialiasing: {
#[serde(rename = "gfx.subpixel-text-antialiasing.enabled")]
enabled: bool,
- }
+ },
+ texture_swizzling: {
+ #[serde(rename = "gfx.texture-swizzling.enabled")]
+ enabled: bool,
+ },
},
js: {
asmjs: {
diff --git a/components/script/dom/webgl_extensions/extensions.rs b/components/script/dom/webgl_extensions/extensions.rs
index 2dc3ef8f11f..04e110b7ed0 100644
--- a/components/script/dom/webgl_extensions/extensions.rs
+++ b/components/script/dom/webgl_extensions/extensions.rs
@@ -52,12 +52,24 @@ const DEFAULT_DISABLED_GET_PARAMETER_NAMES_WEBGL1: [GLenum; 3] = [
OESVertexArrayObjectConstants::VERTEX_ARRAY_BINDING_OES,
];
+// Param names that are implemented for glGetParameter in a WebGL 2.0 context
+// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
+// Example: https://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/
+const DEFAULT_DISABLED_GET_PARAMETER_NAMES_WEBGL2: [GLenum; 1] =
+ [EXTTextureFilterAnisotropicConstants::MAX_TEXTURE_MAX_ANISOTROPY_EXT];
+
// Param names that are implemented for glGetTexParameter in a WebGL 1.0 context
// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
// Example: https://www.khronos.org/registry/webgl/extensions/OES_standard_derivatives/
const DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL1: [GLenum; 1] =
[EXTTextureFilterAnisotropicConstants::TEXTURE_MAX_ANISOTROPY_EXT];
+// Param names that are implemented for glGetTexParameter in a WebGL 2.0 context
+// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
+// Example: https://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/
+const DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL2: [GLenum; 1] =
+ [EXTTextureFilterAnisotropicConstants::TEXTURE_MAX_ANISOTROPY_EXT];
+
// Param names that are implemented for glGetVertexAttrib in a WebGL 1.0 context
// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
// Example: https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
@@ -116,8 +128,14 @@ impl WebGLExtensionFeatures {
),
WebGLVersion::WebGL2 => (
Default::default(),
- Default::default(),
- Default::default(),
+ DEFAULT_DISABLED_GET_PARAMETER_NAMES_WEBGL2
+ .iter()
+ .cloned()
+ .collect(),
+ DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL2
+ .iter()
+ .cloned()
+ .collect(),
Default::default(),
true,
true,
diff --git a/components/script/dom/webglrenderbuffer.rs b/components/script/dom/webglrenderbuffer.rs
index 51f1bdbad4e..f1a3ba99c53 100644
--- a/components/script/dom/webglrenderbuffer.rs
+++ b/components/script/dom/webglrenderbuffer.rs
@@ -233,7 +233,7 @@ impl WebGLRenderbuffer {
),
);
let samples = receiver.recv().unwrap();
- if sample_count < 0 || sample_count as usize > samples.len() {
+ if sample_count < 0 || sample_count > samples.get(0).cloned().unwrap_or(0) {
return Err(WebGLError::InvalidOperation);
}
}
diff --git a/components/script/dom/webglshader.rs b/components/script/dom/webglshader.rs
index 5302c6c78ad..9be334f6595 100644
--- a/components/script/dom/webglshader.rs
+++ b/components/script/dom/webglshader.rs
@@ -277,8 +277,49 @@ impl WebGLShader {
},
};
- match validator.compile_and_translate(&[&source]) {
- Ok(translated_source) => {
+ // Replicating
+ // https://searchfox.org/mozilla-central/rev/c621276fbdd9591f52009042d959b9e19b66d49f/dom/canvas/WebGLShaderValidator.cpp#32
+ let options = mozangle::shaders::ffi::SH_VARIABLES |
+ mozangle::shaders::ffi::SH_ENFORCE_PACKING_RESTRICTIONS |
+ mozangle::shaders::ffi::SH_OBJECT_CODE |
+ mozangle::shaders::ffi::SH_INIT_GL_POSITION |
+ mozangle::shaders::ffi::SH_INITIALIZE_UNINITIALIZED_LOCALS |
+ mozangle::shaders::ffi::SH_INIT_OUTPUT_VARIABLES |
+ mozangle::shaders::ffi::SH_LIMIT_EXPRESSION_COMPLEXITY |
+ mozangle::shaders::ffi::SH_LIMIT_CALL_STACK_DEPTH |
+ if cfg!(target_os = "macos") {
+ // Work around https://bugs.webkit.org/show_bug.cgi?id=124684,
+ // https://chromium.googlesource.com/angle/angle/+/5e70cf9d0b1bb
+ mozangle::shaders::ffi::SH_UNFOLD_SHORT_CIRCUIT |
+ // Work around that Mac drivers handle struct scopes incorrectly.
+ mozangle::shaders::ffi::SH_REGENERATE_STRUCT_NAMES |
+ // Work around that Intel drivers on Mac OSX handle for-loop incorrectly.
+ mozangle::shaders::ffi::SH_ADD_AND_TRUE_TO_LOOP_CONDITION
+ } else {
+ // We want to do this everywhere, but to do this on Mac, we need
+ // to do it only on Mac OSX > 10.6 as this causes the shader
+ // compiler in 10.6 to crash
+ mozangle::shaders::ffi::SH_CLAMP_INDIRECT_ARRAY_BOUNDS
+ };
+
+ // Replicating
+ // https://github.com/servo/mozangle/blob/706a9baaf8026c1a3cb6c67ba63aa5f4734264d0/src/shaders/mod.rs#L226
+ let options = options |
+ mozangle::shaders::ffi::SH_VALIDATE |
+ mozangle::shaders::ffi::SH_OBJECT_CODE |
+ mozangle::shaders::ffi::SH_VARIABLES | // For uniform_name_map()
+ mozangle::shaders::ffi::SH_EMULATE_ABS_INT_FUNCTION | // To workaround drivers
+ mozangle::shaders::ffi::SH_EMULATE_ISNAN_FLOAT_FUNCTION | // To workaround drivers
+ mozangle::shaders::ffi::SH_EMULATE_ATAN2_FLOAT_FUNCTION | // To workaround drivers
+ mozangle::shaders::ffi::SH_CLAMP_INDIRECT_ARRAY_BOUNDS |
+ mozangle::shaders::ffi::SH_INIT_GL_POSITION |
+ mozangle::shaders::ffi::SH_ENFORCE_PACKING_RESTRICTIONS |
+ mozangle::shaders::ffi::SH_LIMIT_EXPRESSION_COMPLEXITY |
+ mozangle::shaders::ffi::SH_LIMIT_CALL_STACK_DEPTH;
+
+ match validator.compile(&[&source], options) {
+ Ok(()) => {
+ let translated_source = validator.object_code();
debug!("Shader translated: {}", translated_source);
// NOTE: At this point we should be pretty sure that the compilation in the paint thread
// will succeed.
diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml
index 68d3fa2cd6a..ca933bb848c 100644
--- a/components/servo/Cargo.toml
+++ b/components/servo/Cargo.toml
@@ -81,11 +81,12 @@ style_traits = {path = "../style_traits", features = ["servo"]}
webgpu = {path = "../webgpu"}
webrender = {git = "https://github.com/servo/webrender"}
webrender_api = {git = "https://github.com/servo/webrender"}
+webrender_surfman = {path = "../webrender_surfman"}
webrender_traits = {path = "../webrender_traits"}
webdriver_server = {path = "../webdriver_server", optional = true}
webxr-api = {git = "https://github.com/servo/webxr"}
webxr = {git = "https://github.com/servo/webxr"}
-surfman = { version = "0.1", features = ["sm-osmesa"] }
+surfman = "0.2"
gstreamer = { version = "0.15", optional = true }
[target.'cfg(all(not(target_os = "windows"), not(target_os = "ios"), not(target_os="android"), not(target_arch="arm"), not(target_arch="aarch64")))'.dependencies]
diff --git a/components/servo/lib.rs b/components/servo/lib.rs
index 1bd9ace8035..82ac035fc4c 100644
--- a/components/servo/lib.rs
+++ b/components/servo/lib.rs
@@ -51,6 +51,7 @@ pub use style;
pub use style_traits;
pub use webgpu;
pub use webrender_api;
+pub use webrender_surfman;
pub use webrender_traits;
#[cfg(feature = "webdriver")]
@@ -116,14 +117,9 @@ use std::path::PathBuf;
use std::rc::Rc;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex};
-#[cfg(not(target_os = "windows"))]
-use surfman::platform::default::device::Device as HWDevice;
-#[cfg(not(target_os = "windows"))]
-use surfman::platform::generic::osmesa::device::Device as SWDevice;
-#[cfg(not(target_os = "windows"))]
-use surfman::platform::generic::universal::context::Context;
-use surfman::platform::generic::universal::device::Device;
+use surfman::GLApi;
use webrender::{RendererKind, ShaderPrecacheFlags};
+use webrender_surfman::WebrenderSurfman;
use webrender_traits::WebrenderImageHandlerType;
use webrender_traits::{WebrenderExternalImageHandlers, WebrenderExternalImageRegistry};
@@ -353,8 +349,28 @@ where
.unwrap_or(default_user_agent_string_for(DEFAULT_USER_AGENT).into()),
};
+ // Initialize surfman
+ let webrender_surfman = window.webrender_surfman();
+
+ // Get GL bindings
+ let webrender_gl = match webrender_surfman.connection().gl_api() {
+ GLApi::GL => unsafe { gl::GlFns::load_with(|s| webrender_surfman.get_proc_address(s)) },
+ GLApi::GLES => unsafe {
+ gl::GlesFns::load_with(|s| webrender_surfman.get_proc_address(s))
+ },
+ };
+
// Make sure the gl context is made current.
- window.make_gl_context_current();
+ webrender_surfman.make_gl_context_current().unwrap();
+ debug_assert_eq!(webrender_gl.get_error(), gleam::gl::NO_ERROR,);
+
+ // Bind the webrender framebuffer
+ let framebuffer_object = webrender_surfman
+ .context_surface_info()
+ .unwrap_or(None)
+ .map(|info| info.framebuffer_object)
+ .unwrap_or(0);
+ webrender_gl.bind_framebuffer(gleam::gl::FRAMEBUFFER, framebuffer_object);
// Reserving a namespace to create TopLevelBrowserContextId.
PipelineNamespace::install(PipelineNamespaceId(0));
@@ -407,7 +423,7 @@ where
let window_size = Size2D::from_untyped(viewport_size.to_i32().to_untyped());
webrender::Renderer::new(
- window.gl(),
+ webrender_gl.clone(),
render_notifier,
webrender::RendererOptions {
device_pixel_ratio,
@@ -422,6 +438,7 @@ where
},
renderer_kind: renderer_kind,
enable_subpixel_aa: opts.enable_subpixel_text_antialiasing,
+ allow_texture_swizzling: pref!(gfx.texture_swizzling.enabled),
clear_color: None,
..Default::default()
},
@@ -451,7 +468,8 @@ where
.expect("Failed to create WebXR device registry");
let (webgl_threads, webgl_extras) = create_webgl_threads(
- &*window,
+ webrender_surfman.clone(),
+ webrender_gl.clone(),
&mut webrender,
webrender_api_sender.clone(),
&mut webxr_main_thread,
@@ -542,6 +560,8 @@ where
webrender,
webrender_document,
webrender_api,
+ webrender_surfman,
+ webrender_gl,
webxr_main_thread,
pending_wr_frame,
},
@@ -806,6 +826,10 @@ where
log::set_max_level(filter);
}
+ pub fn window(&self) -> &Window {
+ &self.compositor.window
+ }
+
pub fn deinit(self) {
self.compositor.deinit();
}
@@ -1030,8 +1054,9 @@ fn create_sandbox() {
}
// Initializes the WebGL thread.
-fn create_webgl_threads<W>(
- window: &W,
+fn create_webgl_threads(
+ webrender_surfman: WebrenderSurfman,
+ webrender_gl: Rc<dyn gl::Gl>,
webrender: &mut webrender::Renderer,
webrender_api_sender: webrender_api::RenderApiSender,
webxr_main_thread: &mut webxr::MainThreadRegistry,
@@ -1040,45 +1065,8 @@ fn create_webgl_threads<W>(
) -> (
Option<WebGLThreads>,
Option<(SurfaceProviders, WebGlExecutor)>,
-)
-where
- W: WindowMethods + 'static + ?Sized,
-{
- // Create a `surfman` device and context.
- window.make_gl_context_current();
-
- #[cfg(not(target_os = "windows"))]
- let (device, context) = unsafe {
- if opts::get().headless {
- let (device, context) = match SWDevice::from_current_context() {
- Ok(a) => a,
- Err(e) => {
- warn!("Failed to create software graphics context: {:?}", e);
- return (None, None);
- },
- };
- (Device::Software(device), Context::Software(context))
- } else {
- let (device, context) = match HWDevice::from_current_context() {
- Ok(a) => a,
- Err(e) => {
- warn!("Failed to create hardware graphics context: {:?}", e);
- return (None, None);
- },
- };
- (Device::Hardware(device), Context::Hardware(context))
- }
- };
- #[cfg(target_os = "windows")]
- let (device, context) = match unsafe { Device::from_current_context() } {
- Ok(a) => a,
- Err(e) => {
- warn!("Failed to create graphics context: {:?}", e);
- return (None, None);
- },
- };
-
- let gl_type = match window.gl().get_type() {
+) {
+ let gl_type = match webrender_gl.get_type() {
gleam::gl::GlType::Gl => sparkle::gl::GlType::Gl,
gleam::gl::GlType::Gles => sparkle::gl::GlType::Gles,
};
@@ -1091,9 +1079,8 @@ where
output_handler,
webgl_executor,
} = WebGLComm::new(
- device,
- context,
- window.gl(),
+ webrender_surfman,
+ webrender_gl,
webrender_api_sender,
external_images,
gl_type,
diff --git a/components/webrender_surfman/Cargo.toml b/components/webrender_surfman/Cargo.toml
new file mode 100644
index 00000000000..e82f553d2cc
--- /dev/null
+++ b/components/webrender_surfman/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "webrender_surfman"
+version = "0.0.1"
+authors = ["The Servo Project Developers"]
+license = "MPL-2.0"
+edition = "2018"
+publish = false
+
+[lib]
+name = "webrender_surfman"
+path = "lib.rs"
+
+[dependencies]
+euclid = "0.20"
+surfman = "0.2"
+surfman-chains = "0.3"
+
diff --git a/components/webrender_surfman/lib.rs b/components/webrender_surfman/lib.rs
new file mode 100644
index 00000000000..193298808bc
--- /dev/null
+++ b/components/webrender_surfman/lib.rs
@@ -0,0 +1,213 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#![deny(unsafe_code)]
+
+use euclid::default::Size2D;
+
+use std::cell::RefCell;
+use std::ffi::c_void;
+use std::rc::Rc;
+use surfman::Adapter;
+use surfman::Connection;
+use surfman::Context;
+use surfman::ContextAttributeFlags;
+use surfman::ContextAttributes;
+use surfman::Device;
+use surfman::Error;
+use surfman::GLApi;
+use surfman::GLVersion;
+use surfman::NativeContext;
+use surfman::NativeDevice;
+use surfman::NativeWidget;
+use surfman::Surface;
+use surfman::SurfaceAccess;
+use surfman::SurfaceInfo;
+use surfman::SurfaceTexture;
+use surfman::SurfaceType;
+use surfman_chains::SurfmanProvider;
+use surfman_chains::SwapChain;
+
+/// A bridge between webrender and surfman
+// TODO: move this into a different crate so that script doesn't depend on surfman
+#[derive(Clone)]
+pub struct WebrenderSurfman(Rc<WebrenderSurfmanData>);
+
+struct WebrenderSurfmanData {
+ device: RefCell<Device>,
+ context: RefCell<Context>,
+ // We either render to a swap buffer or to a native widget
+ swap_chain: Option<SwapChain<Device>>,
+}
+
+impl Drop for WebrenderSurfmanData {
+ fn drop(&mut self) {
+ let ref mut device = self.device.borrow_mut();
+ let ref mut context = self.context.borrow_mut();
+ if let Some(ref swap_chain) = self.swap_chain {
+ let _ = swap_chain.destroy(device, context);
+ }
+ let _ = device.destroy_context(context);
+ }
+}
+
+impl WebrenderSurfman {
+ pub fn create(
+ connection: &Connection,
+ adapter: &Adapter,
+ surface_type: SurfaceType<NativeWidget>,
+ ) -> Result<Self, Error> {
+ let mut device = connection.create_device(&adapter)?;
+ let flags = ContextAttributeFlags::ALPHA |
+ ContextAttributeFlags::DEPTH |
+ ContextAttributeFlags::STENCIL;
+ let version = match connection.gl_api() {
+ GLApi::GLES => GLVersion { major: 3, minor: 0 },
+ GLApi::GL => GLVersion { major: 3, minor: 2 },
+ };
+ let context_attributes = ContextAttributes { flags, version };
+ let context_descriptor = device.create_context_descriptor(&context_attributes)?;
+ let mut context = device.create_context(&context_descriptor)?;
+ let surface_access = SurfaceAccess::GPUOnly;
+ let headless = match surface_type {
+ SurfaceType::Widget { .. } => false,
+ SurfaceType::Generic { .. } => true,
+ };
+ let surface = device.create_surface(&context, surface_access, surface_type)?;
+ device
+ .bind_surface_to_context(&mut context, surface)
+ .map_err(|(err, mut surface)| {
+ let _ = device.destroy_surface(&mut context, &mut surface);
+ err
+ })?;
+ let swap_chain = if headless {
+ let surface_provider = Box::new(SurfmanProvider::new(surface_access));
+ Some(SwapChain::create_attached(
+ &mut device,
+ &mut context,
+ surface_provider,
+ )?)
+ } else {
+ None
+ };
+ let device = RefCell::new(device);
+ let context = RefCell::new(context);
+ let data = WebrenderSurfmanData {
+ device,
+ context,
+ swap_chain,
+ };
+ Ok(WebrenderSurfman(Rc::new(data)))
+ }
+
+ pub fn create_surface_texture(
+ &self,
+ surface: Surface,
+ ) -> Result<SurfaceTexture, (Error, Surface)> {
+ let ref device = self.0.device.borrow();
+ let ref mut context = self.0.context.borrow_mut();
+ device.create_surface_texture(context, surface)
+ }
+
+ pub fn destroy_surface_texture(
+ &self,
+ surface_texture: SurfaceTexture,
+ ) -> Result<Surface, (Error, SurfaceTexture)> {
+ let ref device = self.0.device.borrow();
+ let ref mut context = self.0.context.borrow_mut();
+ device.destroy_surface_texture(context, surface_texture)
+ }
+
+ pub fn make_gl_context_current(&self) -> Result<(), Error> {
+ let ref device = self.0.device.borrow();
+ let ref context = self.0.context.borrow();
+ device.make_context_current(context)
+ }
+
+ pub fn swap_chain(&self) -> Result<&SwapChain<Device>, Error> {
+ self.0.swap_chain.as_ref().ok_or(Error::WidgetAttached)
+ }
+
+ pub fn resize(&self, size: Size2D<i32>) -> Result<(), Error> {
+ let ref mut device = self.0.device.borrow_mut();
+ let ref mut context = self.0.context.borrow_mut();
+ if let Some(swap_chain) = self.0.swap_chain.as_ref() {
+ return swap_chain.resize(device, context, size);
+ }
+ let mut surface = device.unbind_surface_from_context(context)?.unwrap();
+ device.resize_surface(context, &mut surface, size)?;
+ device
+ .bind_surface_to_context(context, surface)
+ .map_err(|(err, mut surface)| {
+ let _ = device.destroy_surface(context, &mut surface);
+ err
+ })
+ }
+
+ pub fn present(&self) -> Result<(), Error> {
+ let ref mut device = self.0.device.borrow_mut();
+ let ref mut context = self.0.context.borrow_mut();
+ if let Some(ref swap_chain) = self.0.swap_chain {
+ return swap_chain.swap_buffers(device, context);
+ }
+ let mut surface = device.unbind_surface_from_context(context)?.unwrap();
+ device.present_surface(context, &mut surface)?;
+ device
+ .bind_surface_to_context(context, surface)
+ .map_err(|(err, mut surface)| {
+ let _ = device.destroy_surface(context, &mut surface);
+ err
+ })
+ }
+
+ pub fn connection(&self) -> Connection {
+ let ref device = self.0.device.borrow();
+ device.connection()
+ }
+
+ pub fn adapter(&self) -> Adapter {
+ let ref device = self.0.device.borrow();
+ device.adapter()
+ }
+
+ pub fn native_context(&self) -> NativeContext {
+ let ref device = self.0.device.borrow();
+ let ref context = self.0.context.borrow();
+ device.native_context(context)
+ }
+
+ pub fn native_device(&self) -> NativeDevice {
+ let ref device = self.0.device.borrow();
+ device.native_device()
+ }
+
+ pub fn context_attributes(&self) -> ContextAttributes {
+ let ref device = self.0.device.borrow();
+ let ref context = self.0.context.borrow();
+ let ref descriptor = device.context_descriptor(context);
+ device.context_descriptor_attributes(descriptor)
+ }
+
+ pub fn context_surface_info(&self) -> Result<Option<SurfaceInfo>, Error> {
+ let ref device = self.0.device.borrow();
+ let ref context = self.0.context.borrow();
+ device.context_surface_info(context)
+ }
+
+ pub fn surface_info(&self, surface: &Surface) -> SurfaceInfo {
+ let ref device = self.0.device.borrow();
+ device.surface_info(surface)
+ }
+
+ pub fn surface_texture_object(&self, surface: &SurfaceTexture) -> u32 {
+ let ref device = self.0.device.borrow();
+ device.surface_texture_object(surface)
+ }
+
+ pub fn get_proc_address(&self, name: &str) -> *const c_void {
+ let ref device = self.0.device.borrow();
+ let ref context = self.0.context.borrow();
+ device.get_proc_address(context, name)
+ }
+}
diff --git a/components/webrender_traits/Cargo.toml b/components/webrender_traits/Cargo.toml
index 29d2bf8aa9f..bf4720038c5 100644
--- a/components/webrender_traits/Cargo.toml
+++ b/components/webrender_traits/Cargo.toml
@@ -12,5 +12,6 @@ path = "lib.rs"
[dependencies]
euclid = "0.20"
+servo_geometry = {path = "../geometry"}
webrender_api = {git = "https://github.com/servo/webrender"}
diff --git a/components/webrender_traits/lib.rs b/components/webrender_traits/lib.rs
index 75c5f60272e..b6dfea27169 100644
--- a/components/webrender_traits/lib.rs
+++ b/components/webrender_traits/lib.rs
@@ -5,8 +5,10 @@
#![deny(unsafe_code)]
use euclid::default::Size2D;
+
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
+
use webrender_api::units::TexelRect;
/// This trait is used as a bridge between the different GL clients