Update surfman to 0.2 and remove glutin

This commit is contained in:
Alan Jeffrey 2020-01-09 17:28:46 -06:00
parent 9dbc6554f0
commit 8bb1732258
94 changed files with 2265 additions and 1513 deletions

View file

@ -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"

View file

@ -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);

View file

@ -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

View file

@ -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,

View file

@ -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]

View file

@ -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> {

View file

@ -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>,
}

View file

@ -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;

View file

@ -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 {

View file

@ -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: {

View file

@ -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,

View file

@ -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);
}
}

View file

@ -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.

View file

@ -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]

View file

@ -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,

View file

@ -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"

View file

@ -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)
}
}

View file

@ -12,5 +12,6 @@ path = "lib.rs"
[dependencies]
euclid = "0.20"
servo_geometry = {path = "../geometry"}
webrender_api = {git = "https://github.com/servo/webrender"}

View file

@ -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