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

100
Cargo.lock generated
View file

@ -502,12 +502,13 @@ dependencies = [
"raqote", "raqote",
"servo_config", "servo_config",
"sparkle", "sparkle",
"surfman 0.1.4", "surfman",
"surfman-chains 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "surfman-chains",
"surfman-chains-api", "surfman-chains-api",
"time", "time",
"webrender", "webrender",
"webrender_api", "webrender_api",
"webrender_surfman",
"webrender_traits", "webrender_traits",
"webxr-api", "webxr-api",
] ]
@ -591,6 +592,12 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg_aliases"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6da2b592f5a2e590c3d94c44313bab369f2286cfe1e4134c830bf3317814866"
[[package]] [[package]]
name = "cgl" name = "cgl"
version = "0.2.3" version = "0.2.3"
@ -772,6 +779,7 @@ dependencies = [
"toml", "toml",
"webrender", "webrender",
"webrender_api", "webrender_api",
"webrender_surfman",
"webxr", "webxr",
] ]
@ -3203,11 +3211,12 @@ dependencies = [
"sparkle", "sparkle",
"style", "style",
"style_traits", "style_traits",
"surfman 0.1.4", "surfman",
"webdriver_server", "webdriver_server",
"webgpu", "webgpu",
"webrender", "webrender",
"webrender_api", "webrender_api",
"webrender_surfman",
"webrender_traits", "webrender_traits",
"webxr", "webxr",
"webxr-api", "webxr-api",
@ -3976,11 +3985,6 @@ version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
[[package]]
name = "osmesa-src"
version = "0.1.1"
source = "git+https://github.com/servo/osmesa-src#1a9519c3675ebc1117cbb18ed6db420b5941cb8b"
[[package]] [[package]]
name = "osmesa-sys" name = "osmesa-sys"
version = "0.1.2" version = "0.1.2"
@ -4946,22 +4950,21 @@ dependencies = [
"euclid", "euclid",
"getopts", "getopts",
"gleam 0.9.2", "gleam 0.9.2",
"glutin",
"image", "image",
"keyboard-types", "keyboard-types",
"lazy_static", "lazy_static",
"libc", "libc",
"libservo", "libservo",
"log", "log",
"osmesa-src",
"osmesa-sys",
"servo-media", "servo-media",
"shellwords", "shellwords",
"sig", "sig",
"surfman",
"tinyfiledialogs", "tinyfiledialogs",
"webxr", "webxr",
"webxr-api", "webxr-api",
"winapi", "winapi",
"winit",
"winres", "winres",
] ]
@ -5025,8 +5028,8 @@ dependencies = [
"log", "log",
"servo-media", "servo-media",
"sparkle", "sparkle",
"surfman 0.2.0", "surfman",
"surfman-chains 0.3.0 (git+https://github.com/asajeffrey/surfman-chains?branch=multi)", "surfman-chains",
"surfman-chains-api", "surfman-chains-api",
] ]
@ -5370,6 +5373,7 @@ dependencies = [
"libservo", "libservo",
"log", "log",
"servo-media", "servo-media",
"surfman",
"webxr", "webxr",
"webxr-api", "webxr-api",
"winapi", "winapi",
@ -5386,6 +5390,7 @@ dependencies = [
"libc", "libc",
"log", "log",
"simpleservo", "simpleservo",
"surfman",
"winapi", "winapi",
] ]
@ -5676,47 +5681,20 @@ dependencies = [
"webrender_api", "webrender_api",
] ]
[[package]]
name = "surfman"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43bf043642ad98aaa51956091c4f829a400bad5f023b5f0095ecda61f925c63d"
dependencies = [
"bitflags",
"cgl 0.3.2",
"cocoa 0.19.1",
"core-foundation 0.6.4",
"core-graphics 0.17.3",
"display-link",
"euclid",
"gl_generator 0.11.0",
"io-surface",
"lazy_static",
"libc",
"log",
"mach",
"objc",
"osmesa-sys",
"wayland-sys 0.24.0",
"winapi",
"winit",
"wio",
"x11",
]
[[package]] [[package]]
name = "surfman" name = "surfman"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/pcwalton/surfman?branch=multi#fb782262617e7ca839a4e487b116a5199afaf963" source = "git+https://github.com/servo/surfman#41ac1ee64bc2d1978aeed0f8bf549c57f20ec7c8"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg_aliases",
"cgl 0.3.2", "cgl 0.3.2",
"cocoa 0.19.1", "cocoa 0.19.1",
"core-foundation 0.6.4", "core-foundation 0.6.4",
"core-graphics 0.17.3", "core-graphics 0.17.3",
"display-link", "display-link",
"euclid", "euclid",
"gl_generator 0.11.0", "gl_generator 0.13.1",
"io-surface", "io-surface",
"lazy_static", "lazy_static",
"libc", "libc",
@ -5734,27 +5712,13 @@ dependencies = [
[[package]] [[package]]
name = "surfman-chains" name = "surfman-chains"
version = "0.3.0" version = "0.3.0"
source = "git+https://github.com/asajeffrey/surfman-chains?branch=multi#e775b8c7807659958a4f20cf8e6eca4290f35124" source = "git+https://github.com/asajeffrey/surfman-chains#b949a240d73ef86d3c4bd22bc3d93933fac21ee9"
dependencies = [ dependencies = [
"euclid", "euclid",
"fnv", "fnv",
"log", "log",
"sparkle", "sparkle",
"surfman 0.2.0", "surfman",
"surfman-chains-api",
]
[[package]]
name = "surfman-chains"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2a679f5be9644bbf93662f3b1a704cc6b81c147d4b7d6d5c8d8b6f453176f01"
dependencies = [
"euclid",
"fnv",
"log",
"sparkle",
"surfman 0.1.4",
"surfman-chains-api", "surfman-chains-api",
] ]
@ -6591,18 +6555,28 @@ dependencies = [
"sha2", "sha2",
] ]
[[package]]
name = "webrender_surfman"
version = "0.0.1"
dependencies = [
"euclid",
"surfman",
"surfman-chains",
]
[[package]] [[package]]
name = "webrender_traits" name = "webrender_traits"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"euclid", "euclid",
"servo_geometry",
"webrender_api", "webrender_api",
] ]
[[package]] [[package]]
name = "webxr" name = "webxr"
version = "0.0.1" version = "0.0.1"
source = "git+https://github.com/servo/webxr#373a2fa762a859054070dad921ace05bea9fa712" source = "git+https://github.com/servo/webxr#0d9c83f333920b98d95adf9666b0a365258990a3"
dependencies = [ dependencies = [
"android_injected_glue", "android_injected_glue",
"bindgen", "bindgen",
@ -6615,8 +6589,8 @@ dependencies = [
"log", "log",
"openxr", "openxr",
"serde", "serde",
"surfman 0.1.4", "surfman",
"surfman-chains 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "surfman-chains",
"time", "time",
"webxr-api", "webxr-api",
"winapi", "winapi",
@ -6626,7 +6600,7 @@ dependencies = [
[[package]] [[package]]
name = "webxr-api" name = "webxr-api"
version = "0.0.1" version = "0.0.1"
source = "git+https://github.com/servo/webxr#373a2fa762a859054070dad921ace05bea9fa712" source = "git+https://github.com/servo/webxr#0d9c83f333920b98d95adf9666b0a365258990a3"
dependencies = [ dependencies = [
"euclid", "euclid",
"ipc-channel", "ipc-channel",

View file

@ -32,3 +32,5 @@ mio = { git = "https://github.com/servo/mio.git", branch = "servo" }
winapi = { git = "https://github.com/servo/winapi-rs", branch = "patch-1" } winapi = { git = "https://github.com/servo/winapi-rs", branch = "patch-1" }
spirv_cross = { git = "https://github.com/servo/spirv_cross", branch = "wgpu-servo" } spirv_cross = { git = "https://github.com/servo/spirv_cross", branch = "wgpu-servo" }
backtrace = { git = "https://github.com/MeFisto94/backtrace-rs", branch = "fix-strtab-freeing-crash" } backtrace = { git = "https://github.com/MeFisto94/backtrace-rs", branch = "fix-strtab-freeing-crash" }
surfman-chains = { git = "https://github.com/asajeffrey/surfman-chains" }
surfman = { git = "https://github.com/servo/surfman" }

View file

@ -38,9 +38,10 @@ servo_config = {path = "../config"}
sparkle = "0.1.22" sparkle = "0.1.22"
webrender = {git = "https://github.com/servo/webrender"} webrender = {git = "https://github.com/servo/webrender"}
webrender_api = {git = "https://github.com/servo/webrender"} webrender_api = {git = "https://github.com/servo/webrender"}
webrender_surfman = {path = "../webrender_surfman"}
webrender_traits = {path = "../webrender_traits"} webrender_traits = {path = "../webrender_traits"}
webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]} webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]}
# NOTE: the sm-angle feature only enables angle on windows, not other platforms! # 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 = "0.3"
surfman-chains-api = "0.2" surfman-chains-api = "0.2"

View file

@ -15,19 +15,19 @@ use std::collections::HashMap;
use std::default::Default; use std::default::Default;
use std::rc::Rc; use std::rc::Rc;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use surfman::platform::generic::universal::context::Context; use surfman::Device;
use surfman::platform::generic::universal::device::Device;
use surfman::platform::generic::universal::surface::SurfaceTexture;
use surfman::SurfaceInfo; use surfman::SurfaceInfo;
use surfman::SurfaceTexture;
use surfman_chains::SwapChains; use surfman_chains::SwapChains;
use surfman_chains_api::SwapChainAPI; use surfman_chains_api::SwapChainAPI;
use surfman_chains_api::SwapChainsAPI; use surfman_chains_api::SwapChainsAPI;
use webrender_surfman::WebrenderSurfman;
use webrender_traits::{WebrenderExternalImageApi, WebrenderExternalImageRegistry}; use webrender_traits::{WebrenderExternalImageApi, WebrenderExternalImageRegistry};
use webxr_api::SwapChainId as WebXRSwapChainId; use webxr_api::SwapChainId as WebXRSwapChainId;
pub struct WebGLComm { pub struct WebGLComm {
pub webgl_threads: WebGLThreads, pub webgl_threads: WebGLThreads,
pub webxr_swap_chains: SwapChains<WebXRSwapChainId>, pub webxr_swap_chains: SwapChains<WebXRSwapChainId, Device>,
pub webxr_surface_providers: SurfaceProviders, pub webxr_surface_providers: SurfaceProviders,
pub image_handler: Box<dyn WebrenderExternalImageApi>, pub image_handler: Box<dyn WebrenderExternalImageApi>,
pub output_handler: Option<Box<dyn webrender_api::OutputImageHandler>>, pub output_handler: Option<Box<dyn webrender_api::OutputImageHandler>>,
@ -37,8 +37,7 @@ pub struct WebGLComm {
impl WebGLComm { impl WebGLComm {
/// Creates a new `WebGLComm` object. /// Creates a new `WebGLComm` object.
pub fn new( pub fn new(
device: Device, surfman: WebrenderSurfman,
context: Context,
webrender_gl: Rc<dyn gleam::gl::Gl>, webrender_gl: Rc<dyn gleam::gl::Gl>,
webrender_api_sender: webrender_api::RenderApiSender, webrender_api_sender: webrender_api::RenderApiSender,
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>, external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
@ -60,8 +59,8 @@ impl WebGLComm {
webrender_swap_chains: webrender_swap_chains.clone(), webrender_swap_chains: webrender_swap_chains.clone(),
webxr_swap_chains: webxr_swap_chains.clone(), webxr_swap_chains: webxr_swap_chains.clone(),
webxr_surface_providers: webxr_surface_providers.clone(), webxr_surface_providers: webxr_surface_providers.clone(),
connection: device.connection(), connection: surfman.connection(),
adapter: device.adapter(), adapter: surfman.adapter(),
api_type, api_type,
runnable_receiver, runnable_receiver,
}; };
@ -72,7 +71,7 @@ impl WebGLComm {
None None
}; };
let external = WebGLExternalImages::new(device, context, webrender_swap_chains); let external = WebGLExternalImages::new(surfman, webrender_swap_chains);
WebGLThread::run_on_own_thread(init); WebGLThread::run_on_own_thread(init);
@ -89,23 +88,15 @@ impl WebGLComm {
/// Bridge between the webrender::ExternalImage callbacks and the WebGLThreads. /// Bridge between the webrender::ExternalImage callbacks and the WebGLThreads.
struct WebGLExternalImages { struct WebGLExternalImages {
device: Device, surfman: WebrenderSurfman,
context: Context, swap_chains: SwapChains<WebGLContextId, Device>,
swap_chains: SwapChains<WebGLContextId>,
locked_front_buffers: FnvHashMap<WebGLContextId, SurfaceTexture>, locked_front_buffers: FnvHashMap<WebGLContextId, SurfaceTexture>,
} }
impl Drop for WebGLExternalImages {
fn drop(&mut self) {
let _ = self.device.destroy_context(&mut self.context);
}
}
impl WebGLExternalImages { impl WebGLExternalImages {
fn new(device: Device, context: Context, swap_chains: SwapChains<WebGLContextId>) -> Self { fn new(surfman: WebrenderSurfman, swap_chains: SwapChains<WebGLContextId, Device>) -> Self {
Self { Self {
device, surfman,
context,
swap_chains, swap_chains,
locked_front_buffers: FnvHashMap::default(), locked_front_buffers: FnvHashMap::default(),
} }
@ -119,13 +110,10 @@ impl WebGLExternalImages {
id: front_buffer_id, id: front_buffer_id,
size, size,
.. ..
} = self.device.surface_info(&front_buffer); } = self.surfman.surface_info(&front_buffer);
debug!("... getting texture for surface {:?}", front_buffer_id); debug!("... getting texture for surface {:?}", front_buffer_id);
let front_buffer_texture = self let front_buffer_texture = self.surfman.create_surface_texture(front_buffer).unwrap();
.device let gl_texture = self.surfman.surface_texture_object(&front_buffer_texture);
.create_surface_texture(&mut self.context, front_buffer)
.unwrap();
let gl_texture = front_buffer_texture.gl_texture();
self.locked_front_buffers.insert(id, 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<()> { fn unlock_swap_chain(&mut self, id: WebGLContextId) -> Option<()> {
let locked_front_buffer = self.locked_front_buffers.remove(&id)?; let locked_front_buffer = self.locked_front_buffers.remove(&id)?;
let locked_front_buffer = self let locked_front_buffer = self
.device .surfman
.destroy_surface_texture(&mut self.context, locked_front_buffer) .destroy_surface_texture(locked_front_buffer)
.unwrap(); .unwrap();
debug!("... unlocked chain {:?}", id); debug!("... unlocked chain {:?}", id);

View file

@ -47,7 +47,6 @@ use euclid::default::Size2D;
use fnv::FnvHashMap; use fnv::FnvHashMap;
use half::f16; use half::f16;
use pixels::{self, PixelFormat}; use pixels::{self, PixelFormat};
use servo_config::opts;
use sparkle::gl; use sparkle::gl;
use sparkle::gl::GLint; use sparkle::gl::GLint;
use sparkle::gl::GLuint; use sparkle::gl::GLuint;
@ -59,12 +58,12 @@ use std::slice;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use surfman; use surfman;
use surfman::platform::generic::universal::adapter::Adapter; use surfman::Adapter;
use surfman::platform::generic::universal::connection::Connection; use surfman::Connection;
use surfman::platform::generic::universal::context::Context; use surfman::Context;
use surfman::platform::generic::universal::device::Device;
use surfman::ContextAttributeFlags; use surfman::ContextAttributeFlags;
use surfman::ContextAttributes; use surfman::ContextAttributes;
use surfman::Device;
use surfman::GLVersion; use surfman::GLVersion;
use surfman::SurfaceAccess; use surfman::SurfaceAccess;
use surfman::SurfaceInfo; use surfman::SurfaceInfo;
@ -87,30 +86,130 @@ struct GLContextData {
attributes: GLContextAttributes, attributes: GLContextAttributes,
} }
#[derive(Debug)]
pub struct GLState { pub struct GLState {
webgl_version: WebGLVersion, webgl_version: WebGLVersion,
gl_version: GLVersion, 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), clear_color: (f32, f32, f32, f32),
scissor_test_enabled: bool, scissor_test_enabled: bool,
// The WebGL view of the stencil write mask (see comment re `color_write_mask`)
stencil_write_mask: (u32, u32), stencil_write_mask: (u32, u32),
stencil_test_enabled: bool,
stencil_clear_value: i32, stencil_clear_value: i32,
// The WebGL view of the depth write mask (see comment re `color_write_mask`)
depth_write_mask: bool, depth_write_mask: bool,
depth_test_enabled: bool,
depth_clear_value: f64, depth_clear_value: f64,
// True when the default framebuffer is bound to DRAW_FRAMEBUFFER
drawing_to_default_framebuffer: bool,
default_vao: gl::GLuint, 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 { impl Default for GLState {
fn default() -> GLState { fn default() -> GLState {
GLState { GLState {
gl_version: GLVersion { major: 1, minor: 0 }, gl_version: GLVersion { major: 1, minor: 0 },
webgl_version: WebGLVersion::WebGL1, webgl_version: WebGLVersion::WebGL1,
requested_flags: ContextAttributeFlags::empty(),
color_write_mask: [true, true, true, true],
clear_color: (0., 0., 0., 0.), clear_color: (0., 0., 0., 0.),
scissor_test_enabled: false, scissor_test_enabled: false,
// Should these be 0xFFFF_FFFF?
stencil_write_mask: (0, 0), stencil_write_mask: (0, 0),
stencil_test_enabled: false,
stencil_clear_value: 0, stencil_clear_value: 0,
depth_write_mask: true, depth_write_mask: true,
depth_test_enabled: false,
depth_clear_value: 1., depth_clear_value: 1.,
default_vao: 0, 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. /// The receiver that should be used to send WebGL messages for processing.
sender: WebGLSender<WebGLMsg>, sender: WebGLSender<WebGLMsg>,
/// The swap chains used by webrender /// The swap chains used by webrender
webrender_swap_chains: SwapChains<WebGLContextId>, webrender_swap_chains: SwapChains<WebGLContextId, Device>,
/// The swap chains used by webxr /// 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. /// The set of all surface providers corresponding to WebXR sessions.
webxr_surface_providers: SurfaceProviders, webxr_surface_providers: SurfaceProviders,
/// A channel to allow arbitrary threads to execute tasks that run in the WebGL thread. /// 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 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 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. /// The data required to initialize an instance of the WebGLThread type.
pub(crate) struct WebGLThreadInit { pub(crate) struct WebGLThreadInit {
@ -161,8 +260,8 @@ pub(crate) struct WebGLThreadInit {
pub external_images: Arc<Mutex<WebrenderExternalImageRegistry>>, pub external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
pub sender: WebGLSender<WebGLMsg>, pub sender: WebGLSender<WebGLMsg>,
pub receiver: WebGLReceiver<WebGLMsg>, pub receiver: WebGLReceiver<WebGLMsg>,
pub webrender_swap_chains: SwapChains<WebGLContextId>, pub webrender_swap_chains: SwapChains<WebGLContextId, Device>,
pub webxr_swap_chains: SwapChains<WebXRSwapChainId>, pub webxr_swap_chains: SwapChains<WebXRSwapChainId, Device>,
pub connection: Connection, pub connection: Connection,
pub adapter: Adapter, pub adapter: Adapter,
pub api_type: gl::GlType, pub api_type: gl::GlType,
@ -190,7 +289,9 @@ impl WebGLThread {
}: WebGLThreadInit, }: WebGLThreadInit,
) -> Self { ) -> Self {
WebGLThread { 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(), webrender_api: webrender_api_sender.create_api(),
contexts: Default::default(), contexts: Default::default(),
cached_context_info: Default::default(), cached_context_info: Default::default(),
@ -236,7 +337,7 @@ impl WebGLThread {
} }
recv(self.runnable_receiver) -> msg => { recv(self.runnable_receiver) -> msg => {
if let Ok(msg) = msg { if let Ok(msg) = msg {
msg(); msg(&self.device);
} else { } else {
self.runnable_receiver = crossbeam_channel::never(); self.runnable_receiver = crossbeam_channel::never();
} }
@ -303,7 +404,7 @@ impl WebGLThread {
.unwrap(); .unwrap();
}, },
WebGLMsg::ResizeContext(ctx_id, size, sender) => { 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) => { WebGLMsg::RemoveContext(ctx_id) => {
self.remove_webgl_context(ctx_id); self.remove_webgl_context(ctx_id);
@ -394,21 +495,35 @@ impl WebGLThread {
requested_size: Size2D<u32>, requested_size: Size2D<u32>,
attributes: GLContextAttributes, attributes: GLContextAttributes,
) -> Result<(WebGLContextId, webgl::GLLimits), String> { ) -> 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. // Creating a new GLContext may make the current bound context_id dirty.
// Clear it to ensure that make_current() is called in subsequent commands. // Clear it to ensure that make_current() is called in subsequent commands.
self.bound_context_id = None; 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 { let context_attributes = &ContextAttributes {
version: webgl_version.to_surfman_version(), version: webgl_version.to_surfman_version(self.api_type),
flags: attributes.to_surfman_context_attribute_flags(webgl_version), flags: flags,
}; };
let context_descriptor = self let context_descriptor = self
.device .device
.create_context_descriptor(&context_attributes) .create_context_descriptor(&context_attributes)
.unwrap(); .map_err(|err| format!("Failed to create context descriptor: {:?}", err))?;
let safe_size = Size2D::new( let safe_size = Size2D::new(
requested_size.width.min(SAFE_VIEWPORT_DIMS[0]).max(1), requested_size.width.min(SAFE_VIEWPORT_DIMS[0]).max(1),
@ -423,30 +538,30 @@ impl WebGLThread {
let mut ctx = self let mut ctx = self
.device .device
.create_context(&context_descriptor) .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 let surface = self
.device .device
.create_surface(&ctx, surface_access, &surface_type) .create_surface(&ctx, surface_access, surface_type)
.expect("Failed to create the initial surface!"); .map_err(|err| format!("Failed to create the initial surface: {:?}", err))?;
self.device self.device
.bind_surface_to_context(&mut ctx, surface) .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 // https://github.com/pcwalton/surfman/issues/7
self.device self.device
.make_context_current(&ctx) .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( let id = WebGLContextId(
self.external_images self.external_images
.lock() .lock()
.unwrap() .expect("Lock poisoned?")
.next_id(WebrenderImageHandlerType::WebGL) .next_id(WebrenderImageHandlerType::WebGL)
.0, .0,
); );
self.webrender_swap_chains self.webrender_swap_chains
.create_attached_swap_chain(id, &mut self.device, &mut ctx, surface_provider) .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 let swap_chain = self
.webrender_swap_chains .webrender_swap_chains
@ -456,7 +571,7 @@ impl WebGLThread {
debug!( debug!(
"Created webgl context {:?}/{:?}", "Created webgl context {:?}/{:?}",
id, id,
self.device.context_id(&ctx) self.device.context_id(&ctx),
); );
let gl = match self.api_type { let gl = match self.api_type {
@ -475,34 +590,33 @@ impl WebGLThread {
debug!("Resizing swap chain from {} to {}", safe_size, size); debug!("Resizing swap chain from {} to {}", safe_size, size);
swap_chain swap_chain
.resize(&mut self.device, &mut ctx, size.to_i32()) .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(); self.device.make_context_current(&ctx).unwrap();
let framebuffer = self let framebuffer = self
.device .device
.context_surface_info(&ctx) .context_surface_info(&ctx)
.unwrap() .map_err(|err| format!("Failed to get context surface info: {:?}", err))?
.unwrap() .ok_or_else(|| format!("Failed to get context surface info"))?
.framebuffer_object; .framebuffer_object;
gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer); gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer);
gl.viewport(0, 0, size.width as i32, size.height as i32); 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.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_depth(1.);
gl.clear_stencil(0); gl.clear_stencil(0);
gl.clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT); 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); 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 use_apple_vertex_array = WebGLImpl::needs_apple_vertex_arrays(gl_version);
let default_vao = if let Some(vao) = let default_vao = if let Some(vao) =
WebGLImpl::create_vertex_array(&gl, use_apple_vertex_array, webgl_version) WebGLImpl::create_vertex_array(&gl, use_apple_vertex_array, webgl_version)
@ -517,9 +631,15 @@ impl WebGLThread {
let state = GLState { let state = GLState {
gl_version, gl_version,
webgl_version, webgl_version,
requested_flags,
default_vao, default_vao,
..Default::default() ..Default::default()
}; };
debug!("Created state {:?}", state);
state.restore_invariant(&*gl);
debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
self.contexts.insert( self.contexts.insert(
id, id,
GLContextData { GLContextData {
@ -549,8 +669,7 @@ impl WebGLThread {
&mut self, &mut self,
context_id: WebGLContextId, context_id: WebGLContextId,
requested_size: Size2D<u32>, requested_size: Size2D<u32>,
sender: WebGLSender<Result<(), String>>, ) -> Result<(), String> {
) {
let data = Self::make_current_if_needed_mut( let data = Self::make_current_if_needed_mut(
&self.device, &self.device,
context_id, context_id,
@ -568,16 +687,17 @@ impl WebGLThread {
// Resize the swap chains // Resize the swap chains
if let Some(swap_chain) = self.webrender_swap_chains.get(context_id) { 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 swap_chain
.resize(&mut self.device, &mut data.ctx, size.to_i32()) .resize(&mut self.device, &mut data.ctx, size.to_i32())
.expect("Failed to resize swap chain"); .map_err(|err| format!("Failed to resize swap chain: {:?}", err))?;
// 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");
swap_chain swap_chain
.clear_surface(&mut self.device, &mut data.ctx, &*data.gl) .clear_surface(&mut self.device, &mut data.ctx, &*data.gl, clear_color)
.expect("Failed to clear resized swap chain"); .map_err(|err| format!("Failed to clear resized swap chain: {:?}", err))?;
} else { } else {
error!("Failed to find swap chain"); error!("Failed to find swap chain");
} }
@ -587,11 +707,9 @@ impl WebGLThread {
// Update WR image if needed. // Update WR image if needed.
let info = self.cached_context_info.get_mut(&context_id).unwrap(); let info = self.cached_context_info.get_mut(&context_id).unwrap();
let context_descriptor = self.device.context_descriptor(&data.ctx); let has_alpha = data
let has_alpha = self .state
.device .requested_flags
.context_descriptor_attributes(&context_descriptor)
.flags
.contains(ContextAttributeFlags::ALPHA); .contains(ContextAttributeFlags::ALPHA);
let texture_target = current_wr_texture_target(&self.device); let texture_target = current_wr_texture_target(&self.device);
Self::update_wr_external_image( Self::update_wr_external_image(
@ -605,7 +723,7 @@ impl WebGLThread {
debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR); debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR);
sender.send(Ok(())).unwrap(); Ok(())
} }
/// Removes a WebGLContext and releases attached resources. /// 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 // TODO: if preserveDrawingBuffer is true, then blit the front buffer to the back buffer
// https://github.com/servo/servo/issues/24604 // https://github.com/servo/servo/issues/24604
debug!("Clearing {:?}", swap_id); 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 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(); .unwrap();
debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR); debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR);
@ -1084,7 +1207,10 @@ impl WebGLImpl {
state.stencil_clear_value = stencil; state.stencil_clear_value = stencil;
gl.clear_stencil(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( WebGLCommand::CopyTexImage2D(
target, target,
level, level,
@ -1109,22 +1235,40 @@ impl WebGLImpl {
WebGLCommand::DepthFunc(func) => gl.depth_func(func), WebGLCommand::DepthFunc(func) => gl.depth_func(func),
WebGLCommand::DepthMask(flag) => { WebGLCommand::DepthMask(flag) => {
state.depth_write_mask = flag; state.depth_write_mask = flag;
gl.depth_mask(flag); state.restore_depth_invariant(gl);
}, },
WebGLCommand::DepthRange(near, far) => { WebGLCommand::DepthRange(near, far) => {
gl.depth_range(near.max(0.).min(1.) as f64, far.max(0.).min(1.) as f64) gl.depth_range(near.max(0.).min(1.) as f64, far.max(0.).min(1.) as f64)
}, },
WebGLCommand::Disable(cap) => { WebGLCommand::Disable(cap) => match cap {
if cap == gl::SCISSOR_TEST { gl::SCISSOR_TEST => {
state.scissor_test_enabled = false; state.scissor_test_enabled = false;
} state.restore_scissor_invariant(gl);
gl.disable(cap); },
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) => { WebGLCommand::Enable(cap) => match cap {
if cap == gl::SCISSOR_TEST { gl::SCISSOR_TEST => {
state.scissor_test_enabled = true; state.scissor_test_enabled = true;
} state.restore_scissor_invariant(gl);
gl.enable(cap); },
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) => { WebGLCommand::FramebufferRenderbuffer(target, attachment, renderbuffertarget, rb) => {
let attach = |attachment| { let attach = |attachment| {
@ -1221,7 +1365,7 @@ impl WebGLImpl {
}, },
WebGLCommand::StencilMask(mask) => { WebGLCommand::StencilMask(mask) => {
state.stencil_write_mask = (mask, mask); state.stencil_write_mask = (mask, mask);
gl.stencil_mask(mask); state.restore_stencil_invariant(gl);
}, },
WebGLCommand::StencilMaskSeparate(face, mask) => { WebGLCommand::StencilMaskSeparate(face, mask) => {
if face == gl::FRONT { if face == gl::FRONT {
@ -1229,7 +1373,7 @@ impl WebGLImpl {
} else { } else {
state.stencil_write_mask.1 = mask; 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::StencilOp(fail, zfail, zpass) => gl.stencil_op(fail, zfail, zpass),
WebGLCommand::StencilOpSeparate(face, 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)) gl.bind_buffer(target, id.map_or(0, WebGLBufferId::get))
}, },
WebGLCommand::BindFramebuffer(target, request) => { 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) => { WebGLCommand::BindRenderbuffer(target, id) => {
gl.bind_renderbuffer(target, id.map_or(0, WebGLRenderbufferId::get)) 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); Self::bind_vertex_array(gl, id, use_apple_vertex_array, state.webgl_version);
}, },
WebGLCommand::GetParameterBool(param, ref sender) => { WebGLCommand::GetParameterBool(param, ref sender) => {
let mut value = [0]; let value = match param {
unsafe { webgl::ParameterBool::DepthWritemask => state.depth_write_mask,
gl.get_boolean_v(param as u32, &mut value); _ => unsafe {
} let mut value = [0];
sender.send(value[0] != 0).unwrap() gl.get_boolean_v(param as u32, &mut value);
value[0] != 0
},
};
sender.send(value).unwrap()
}, },
WebGLCommand::FenceSync(ref sender) => { WebGLCommand::FenceSync(ref sender) => {
let value = gl.fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0); 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 _); gl.delete_sync(sync_id.get() as *const _);
}, },
WebGLCommand::GetParameterBool4(param, ref sender) => { WebGLCommand::GetParameterBool4(param, ref sender) => {
let mut value = [0; 4]; let value = match param {
unsafe { webgl::ParameterBool4::ColorWritemask => state.color_write_mask,
gl.get_boolean_v(param as u32, &mut value); };
}
let value = [value[0] != 0, value[1] != 0, value[2] != 0, value[3] != 0];
sender.send(value).unwrap() sender.send(value).unwrap()
}, },
WebGLCommand::GetParameterInt(param, ref sender) => { WebGLCommand::GetParameterInt(param, ref sender) => {
let mut value = [0]; let value = match param {
unsafe { webgl::ParameterInt::AlphaBits if state.fake_no_alpha() => 0,
gl.get_integer_v(param as u32, &mut value); webgl::ParameterInt::DepthBits if state.fake_no_depth() => 0,
} webgl::ParameterInt::StencilBits if state.fake_no_stencil() => 0,
sender.send(value[0]).unwrap() 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) => { WebGLCommand::GetParameterInt2(param, ref sender) => {
let mut value = [0; 2]; let mut value = [0; 2];
@ -1978,15 +2132,25 @@ impl WebGLImpl {
sender.send(value).unwrap(); sender.send(value).unwrap();
}, },
WebGLCommand::BindBufferBase(target, index, id) => { 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) => { WebGLCommand::ClearBufferfv(buffer, draw_buffer, ref value) => {
gl.clear_buffer_fv(buffer, draw_buffer, value) gl.clear_buffer_fv(buffer, draw_buffer, value)
}, },
@ -2065,47 +2229,17 @@ impl WebGLImpl {
bits | if enabled { bit } else { 0 } bits | if enabled { bit } else { 0 }
}); });
if state.scissor_test_enabled { gl.disable(gl::SCISSOR_TEST);
gl.disable(gl::SCISSOR_TEST); gl.color_mask(true, true, true, true);
} gl.clear_color(0., 0., 0., 0.);
gl.depth_mask(true);
if color { gl.clear_depth(1.);
gl.clear_color(0., 0., 0., 0.); gl.stencil_mask_separate(gl::FRONT, 0xFFFFFFFF);
} gl.stencil_mask_separate(gl::BACK, 0xFFFFFFFF);
gl.clear_stencil(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.clear(bits); gl.clear(bits);
if state.scissor_test_enabled { state.restore_invariant(gl);
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);
}
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
@ -2213,6 +2347,7 @@ impl WebGLImpl {
&mut transform_feedback_mode, &mut transform_feedback_mode,
); );
} }
ProgramLinkInfo { ProgramLinkInfo {
linked: true, linked: true,
active_attribs, active_attribs,
@ -2243,7 +2378,7 @@ impl WebGLImpl {
// array object functions, but support a set of APPLE extension functions that // array object functions, but support a set of APPLE extension functions that
// provide VAO support instead. // provide VAO support instead.
fn needs_apple_vertex_arrays(gl_version: GLVersion) -> bool { 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)] #[allow(unsafe_code)]
@ -2427,8 +2562,8 @@ impl WebGLImpl {
/// Updates the swap buffers if the context surface needs to be changed /// Updates the swap buffers if the context surface needs to be changed
fn attach_surface( fn attach_surface(
context_id: WebGLContextId, context_id: WebGLContextId,
webrender_swap_chains: &SwapChains<WebGLContextId>, webrender_swap_chains: &SwapChains<WebGLContextId, Device>,
webxr_swap_chains: &SwapChains<WebXRSwapChainId>, webxr_swap_chains: &SwapChains<WebXRSwapChainId, Device>,
request: WebGLFramebufferBindingRequest, request: WebGLFramebufferBindingRequest,
ctx: &mut Context, ctx: &mut Context,
device: &mut Device, device: &mut Device,
@ -2479,6 +2614,7 @@ impl WebGLImpl {
request: WebGLFramebufferBindingRequest, request: WebGLFramebufferBindingRequest,
ctx: &Context, ctx: &Context,
device: &Device, device: &Device,
state: &mut GLState,
) { ) {
let id = match request { let id = match request {
WebGLFramebufferBindingRequest::Explicit(WebGLFramebufferId::Transparent(id)) => { WebGLFramebufferBindingRequest::Explicit(WebGLFramebufferId::Transparent(id)) => {
@ -2496,6 +2632,12 @@ impl WebGLImpl {
debug!("WebGLImpl::bind_framebuffer: {:?}", id); debug!("WebGLImpl::bind_framebuffer: {:?}", id);
gl.bind_framebuffer(target, 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] #[inline]
@ -2885,27 +3027,41 @@ fn flip_pixels_y(
// Clamp a size to the current GL context's max viewport // Clamp a size to the current GL context's max viewport
fn clamp_viewport(gl: &Gl, size: Size2D<u32>) -> Size2D<u32> { 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)] #[allow(unsafe_code)]
unsafe { 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); debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
} }
Size2D::new( Size2D::new(
size.width.min(max_size[0] as u32).max(1), size.width
size.height.min(max_size[1] as u32).max(1), .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 { trait ToSurfmanVersion {
fn to_surfman_version(self) -> GLVersion; fn to_surfman_version(self, api_type: gl::GlType) -> GLVersion;
} }
impl ToSurfmanVersion for WebGLVersion { 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 { match self {
WebGLVersion::WebGL1 => GLVersion::new(2, 0), // We make use of GL_PACK_PIXEL_BUFFER, which needs at least GL2.1
WebGLVersion::WebGL2 => GLVersion::new(3, 0), // 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( fn to_surfman_context_attribute_flags(
&self, &self,
webgl_version: WebGLVersion, webgl_version: WebGLVersion,
api_type: gl::GlType,
) -> ContextAttributeFlags; ) -> ContextAttributeFlags;
} }
@ -2921,12 +3078,13 @@ impl SurfmanContextAttributeFlagsConvert for GLContextAttributes {
fn to_surfman_context_attribute_flags( fn to_surfman_context_attribute_flags(
&self, &self,
webgl_version: WebGLVersion, webgl_version: WebGLVersion,
api_type: gl::GlType,
) -> ContextAttributeFlags { ) -> ContextAttributeFlags {
let mut flags = ContextAttributeFlags::empty(); let mut flags = ContextAttributeFlags::empty();
flags.set(ContextAttributeFlags::ALPHA, self.alpha); flags.set(ContextAttributeFlags::ALPHA, self.alpha);
flags.set(ContextAttributeFlags::DEPTH, self.depth); flags.set(ContextAttributeFlags::DEPTH, self.depth);
flags.set(ContextAttributeFlags::STENCIL, self.stencil); 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.set(ContextAttributeFlags::COMPATIBILITY_PROFILE, true);
} }
flags flags

View file

@ -667,7 +667,7 @@ pub enum WebGLFramebufferId {
Opaque(WebGLOpaqueFramebufferId), Opaque(WebGLOpaqueFramebufferId),
} }
#[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum WebGLFramebufferBindingRequest { pub enum WebGLFramebufferBindingRequest {
Explicit(WebGLFramebufferId), Explicit(WebGLFramebufferId),
Default, Default,

View file

@ -40,6 +40,7 @@ style_traits = {path = "../style_traits"}
time = "0.1.17" time = "0.1.17"
webrender = {git = "https://github.com/servo/webrender", features = ["capture"]} webrender = {git = "https://github.com/servo/webrender", features = ["capture"]}
webrender_api = {git = "https://github.com/servo/webrender"} webrender_api = {git = "https://github.com/servo/webrender"}
webrender_surfman = {path = "../webrender_surfman"}
webxr = {git = "https://github.com/servo/webxr"} webxr = {git = "https://github.com/servo/webxr"}
[build-dependencies] [build-dependencies]

View file

@ -19,6 +19,7 @@ use gfx_traits::Epoch;
use image::{DynamicImage, ImageFormat}; use image::{DynamicImage, ImageFormat};
use ipc_channel::ipc; use ipc_channel::ipc;
use libc::c_void; use libc::c_void;
use log::warn;
use msg::constellation_msg::{PipelineId, PipelineIndex, PipelineNamespaceId}; use msg::constellation_msg::{PipelineId, PipelineIndex, PipelineNamespaceId};
use net_traits::image::base::Image; use net_traits::image::base::Image;
use net_traits::image_cache::CorsStatus; 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 time::{now, precise_time_ns, precise_time_s};
use webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePoint, LayoutVector2D}; use webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePoint, LayoutVector2D};
use webrender_api::{self, HitTestFlags, HitTestResult, ScrollLocation}; use webrender_api::{self, HitTestFlags, HitTestResult, ScrollLocation};
use webrender_surfman::WebrenderSurfman;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
enum UnableToComposite { enum UnableToComposite {
@ -178,6 +180,12 @@ pub struct IOCompositor<Window: WindowMethods + ?Sized> {
/// The webrender interface, if enabled. /// The webrender interface, if enabled.
webrender_api: webrender_api::RenderApi, 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. /// Some XR devices want to run on the main thread.
pub webxr_main_thread: webxr::MainThreadRegistry, pub webxr_main_thread: webxr::MainThreadRegistry,
@ -316,6 +324,8 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
webrender: state.webrender, webrender: state.webrender,
webrender_document: state.webrender_document, webrender_document: state.webrender_document,
webrender_api: state.webrender_api, webrender_api: state.webrender_api,
webrender_surfman: state.webrender_surfman,
webrender_gl: state.webrender_gl,
webxr_main_thread: state.webxr_main_thread, webxr_main_thread: state.webxr_main_thread,
pending_paint_metrics: HashMap::new(), pending_paint_metrics: HashMap::new(),
cursor: Cursor::None, cursor: Cursor::None,
@ -345,6 +355,9 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
convert_mouse_to_touch, convert_mouse_to_touch,
); );
// Make sure the GL state is OK
compositor.assert_gl_framebuffer_complete();
// Set the size of the root layer. // Set the size of the root layer.
compositor.update_zoom_transform(); compositor.update_zoom_transform();
@ -352,7 +365,9 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
} }
pub fn deinit(self) { 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(); self.webrender.deinit();
} }
@ -1238,7 +1253,22 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
) -> Result<Option<Image>, UnableToComposite> { ) -> Result<Option<Image>, UnableToComposite> {
let size = self.embedder_coordinates.framebuffer.to_u32(); 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(); self.webrender.update();
let wait_for_stable_image = match target { let wait_for_stable_image = match target {
@ -1266,7 +1296,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
CompositeTarget::Window => gl::RenderTargetInfo::default(), CompositeTarget::Window => gl::RenderTargetInfo::default(),
#[cfg(feature = "gl")] #[cfg(feature = "gl")]
CompositeTarget::WindowAndPng | CompositeTarget::PngFile => gl::initialize_png( CompositeTarget::WindowAndPng | CompositeTarget::PngFile => gl::initialize_png(
&*self.window.gl(), &*self.webrender_gl,
FramebufferUintLength::new(size.width), FramebufferUintLength::new(size.width),
FramebufferUintLength::new(size.height), FramebufferUintLength::new(size.height),
), ),
@ -1347,7 +1377,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
#[cfg(feature = "gl")] #[cfg(feature = "gl")]
CompositeTarget::WindowAndPng => { CompositeTarget::WindowAndPng => {
let img = gl::draw_img( let img = gl::draw_img(
&*self.window.gl(), &*self.webrender_gl,
rt_info, rt_info,
x, x,
y, y,
@ -1365,7 +1395,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
}, },
#[cfg(feature = "gl")] #[cfg(feature = "gl")]
CompositeTarget::PngFile => { CompositeTarget::PngFile => {
let gl = &*self.window.gl(); let gl = &*self.webrender_gl;
profile( profile(
ProfilerCategory::ImageSaving, ProfilerCategory::ImageSaving,
None, None,
@ -1399,7 +1429,9 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
}; };
// Perform the page flip. This will likely block for a while. // 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(); self.last_composite_time = precise_time_ns();
@ -1426,11 +1458,13 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
} }
fn clear_background(&self) { fn clear_background(&self) {
let gl = self.window.gl(); let gl = &self.webrender_gl;
self.assert_gl_framebuffer_complete();
// Make framebuffer fully transparent. // Make framebuffer fully transparent.
gl.clear_color(0.0, 0.0, 0.0, 0.0); gl.clear_color(0.0, 0.0, 0.0, 0.0);
gl.clear(gleam::gl::COLOR_BUFFER_BIT); gl.clear(gleam::gl::COLOR_BUFFER_BIT);
self.assert_gl_framebuffer_complete();
// Make the viewport white. // Make the viewport white.
let viewport = self.embedder_coordinates.get_flipped_viewport(); 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.enable(gleam::gl::SCISSOR_TEST);
gl.clear(gleam::gl::COLOR_BUFFER_BIT); gl.clear(gleam::gl::COLOR_BUFFER_BIT);
gl.disable(gleam::gl::SCISSOR_TEST); 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> { fn get_root_pipeline_id(&self) -> Option<PipelineId> {

View file

@ -17,12 +17,14 @@ use profile_traits::mem;
use profile_traits::time; use profile_traits::time;
use script_traits::{AnimationState, EventResult, MouseButton, MouseEventType}; use script_traits::{AnimationState, EventResult, MouseButton, MouseEventType};
use std::fmt::{Debug, Error, Formatter}; use std::fmt::{Debug, Error, Formatter};
use std::rc::Rc;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use std::sync::Arc; use std::sync::Arc;
use style_traits::viewport::ViewportConstraints; use style_traits::viewport::ViewportConstraints;
use style_traits::CSSPixel; use style_traits::CSSPixel;
use webrender_api; use webrender_api;
use webrender_api::units::{DeviceIntPoint, DeviceIntSize}; use webrender_api::units::{DeviceIntPoint, DeviceIntSize};
use webrender_surfman::WebrenderSurfman;
/// Sends messages to the compositor. /// Sends messages to the compositor.
pub struct CompositorProxy { pub struct CompositorProxy {
@ -166,6 +168,8 @@ pub struct InitialCompositorState {
pub webrender: webrender::Renderer, pub webrender: webrender::Renderer,
pub webrender_document: webrender_api::DocumentId, pub webrender_document: webrender_api::DocumentId,
pub webrender_api: webrender_api::RenderApi, 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 webxr_main_thread: webxr::MainThreadRegistry,
pub pending_wr_frame: Arc<AtomicBool>, pub pending_wr_frame: Arc<AtomicBool>,
} }

View file

@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![feature(track_caller)]
#[macro_use] #[macro_use]
extern crate log; extern crate log;

View file

@ -7,8 +7,6 @@
use canvas::{SurfaceProviders, WebGlExecutor}; use canvas::{SurfaceProviders, WebGlExecutor};
use embedder_traits::{EmbedderProxy, EventLoopWaker}; use embedder_traits::{EmbedderProxy, EventLoopWaker};
use euclid::Scale; use euclid::Scale;
#[cfg(feature = "gl")]
use gleam::gl;
use keyboard_types::KeyboardEvent; use keyboard_types::KeyboardEvent;
use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId, TraversalDirection}; use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId, TraversalDirection};
use script_traits::{MediaSessionActionType, MouseButton, TouchEventType, TouchId, WheelDelta}; 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_media::player::context::{GlApi, GlContext, NativeDisplay};
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::fmt::{Debug, Error, Formatter}; use std::fmt::{Debug, Error, Formatter};
#[cfg(feature = "gl")]
use std::rc::Rc;
use std::time::Duration; use std::time::Duration;
use style_traits::DevicePixel; use style_traits::DevicePixel;
use webrender_api::units::DevicePoint; use webrender_api::units::DevicePoint;
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use webrender_api::ScrollLocation; use webrender_api::ScrollLocation;
use webrender_surfman::WebrenderSurfman;
#[derive(Clone)] #[derive(Clone)]
pub enum MouseWindowEvent { pub enum MouseWindowEvent {
@ -148,14 +145,10 @@ pub enum AnimationState {
Animating, 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 { 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. /// Get the coordinates of the native window, the screen and the framebuffer.
fn get_coordinates(&self) -> EmbedderCoordinates; fn get_coordinates(&self) -> EmbedderCoordinates;
/// Set whether the application is currently animating. /// Set whether the application is currently animating.
@ -163,12 +156,14 @@ pub trait WindowMethods {
/// will want to avoid blocking on UI events, and just /// will want to avoid blocking on UI events, and just
/// run the event loop at the vsync interval. /// run the event loop at the vsync interval.
fn set_animation_state(&self, _state: AnimationState); fn set_animation_state(&self, _state: AnimationState);
/// Get the GL context /// Get the media GL context
fn get_gl_context(&self) -> GlContext; fn get_gl_context(&self) -> GlContext;
/// Get the native display /// Get the media native display
fn get_native_display(&self) -> NativeDisplay; fn get_native_display(&self) -> NativeDisplay;
/// Get the GL api /// Get the GL api
fn get_gl_api(&self) -> GlApi; fn get_gl_api(&self) -> GlApi;
/// Get the webrender surfman instance
fn webrender_surfman(&self) -> WebrenderSurfman;
} }
pub trait EmbedderMethods { pub trait EmbedderMethods {

View file

@ -321,7 +321,11 @@ mod gen {
subpixel_text_antialiasing: { subpixel_text_antialiasing: {
#[serde(rename = "gfx.subpixel-text-antialiasing.enabled")] #[serde(rename = "gfx.subpixel-text-antialiasing.enabled")]
enabled: bool, enabled: bool,
} },
texture_swizzling: {
#[serde(rename = "gfx.texture-swizzling.enabled")]
enabled: bool,
},
}, },
js: { js: {
asmjs: { asmjs: {

View file

@ -52,12 +52,24 @@ const DEFAULT_DISABLED_GET_PARAMETER_NAMES_WEBGL1: [GLenum; 3] = [
OESVertexArrayObjectConstants::VERTEX_ARRAY_BINDING_OES, 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 // 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. // but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
// Example: https://www.khronos.org/registry/webgl/extensions/OES_standard_derivatives/ // Example: https://www.khronos.org/registry/webgl/extensions/OES_standard_derivatives/
const DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL1: [GLenum; 1] = const DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL1: [GLenum; 1] =
[EXTTextureFilterAnisotropicConstants::TEXTURE_MAX_ANISOTROPY_EXT]; [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 // 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. // but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
// Example: https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/ // Example: https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
@ -116,8 +128,14 @@ impl WebGLExtensionFeatures {
), ),
WebGLVersion::WebGL2 => ( WebGLVersion::WebGL2 => (
Default::default(), Default::default(),
Default::default(), DEFAULT_DISABLED_GET_PARAMETER_NAMES_WEBGL2
Default::default(), .iter()
.cloned()
.collect(),
DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL2
.iter()
.cloned()
.collect(),
Default::default(), Default::default(),
true, true,
true, true,

View file

@ -233,7 +233,7 @@ impl WebGLRenderbuffer {
), ),
); );
let samples = receiver.recv().unwrap(); 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); return Err(WebGLError::InvalidOperation);
} }
} }

View file

@ -277,8 +277,49 @@ impl WebGLShader {
}, },
}; };
match validator.compile_and_translate(&[&source]) { // Replicating
Ok(translated_source) => { // 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); debug!("Shader translated: {}", translated_source);
// NOTE: At this point we should be pretty sure that the compilation in the paint thread // NOTE: At this point we should be pretty sure that the compilation in the paint thread
// will succeed. // will succeed.

View file

@ -81,11 +81,12 @@ style_traits = {path = "../style_traits", features = ["servo"]}
webgpu = {path = "../webgpu"} webgpu = {path = "../webgpu"}
webrender = {git = "https://github.com/servo/webrender"} webrender = {git = "https://github.com/servo/webrender"}
webrender_api = {git = "https://github.com/servo/webrender"} webrender_api = {git = "https://github.com/servo/webrender"}
webrender_surfman = {path = "../webrender_surfman"}
webrender_traits = {path = "../webrender_traits"} webrender_traits = {path = "../webrender_traits"}
webdriver_server = {path = "../webdriver_server", optional = true} webdriver_server = {path = "../webdriver_server", optional = true}
webxr-api = {git = "https://github.com/servo/webxr"} webxr-api = {git = "https://github.com/servo/webxr"}
webxr = {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 } 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] [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 style_traits;
pub use webgpu; pub use webgpu;
pub use webrender_api; pub use webrender_api;
pub use webrender_surfman;
pub use webrender_traits; pub use webrender_traits;
#[cfg(feature = "webdriver")] #[cfg(feature = "webdriver")]
@ -116,14 +117,9 @@ use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
#[cfg(not(target_os = "windows"))] use surfman::GLApi;
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 webrender::{RendererKind, ShaderPrecacheFlags}; use webrender::{RendererKind, ShaderPrecacheFlags};
use webrender_surfman::WebrenderSurfman;
use webrender_traits::WebrenderImageHandlerType; use webrender_traits::WebrenderImageHandlerType;
use webrender_traits::{WebrenderExternalImageHandlers, WebrenderExternalImageRegistry}; use webrender_traits::{WebrenderExternalImageHandlers, WebrenderExternalImageRegistry};
@ -353,8 +349,28 @@ where
.unwrap_or(default_user_agent_string_for(DEFAULT_USER_AGENT).into()), .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. // 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. // Reserving a namespace to create TopLevelBrowserContextId.
PipelineNamespace::install(PipelineNamespaceId(0)); PipelineNamespace::install(PipelineNamespaceId(0));
@ -407,7 +423,7 @@ where
let window_size = Size2D::from_untyped(viewport_size.to_i32().to_untyped()); let window_size = Size2D::from_untyped(viewport_size.to_i32().to_untyped());
webrender::Renderer::new( webrender::Renderer::new(
window.gl(), webrender_gl.clone(),
render_notifier, render_notifier,
webrender::RendererOptions { webrender::RendererOptions {
device_pixel_ratio, device_pixel_ratio,
@ -422,6 +438,7 @@ where
}, },
renderer_kind: renderer_kind, renderer_kind: renderer_kind,
enable_subpixel_aa: opts.enable_subpixel_text_antialiasing, enable_subpixel_aa: opts.enable_subpixel_text_antialiasing,
allow_texture_swizzling: pref!(gfx.texture_swizzling.enabled),
clear_color: None, clear_color: None,
..Default::default() ..Default::default()
}, },
@ -451,7 +468,8 @@ where
.expect("Failed to create WebXR device registry"); .expect("Failed to create WebXR device registry");
let (webgl_threads, webgl_extras) = create_webgl_threads( let (webgl_threads, webgl_extras) = create_webgl_threads(
&*window, webrender_surfman.clone(),
webrender_gl.clone(),
&mut webrender, &mut webrender,
webrender_api_sender.clone(), webrender_api_sender.clone(),
&mut webxr_main_thread, &mut webxr_main_thread,
@ -542,6 +560,8 @@ where
webrender, webrender,
webrender_document, webrender_document,
webrender_api, webrender_api,
webrender_surfman,
webrender_gl,
webxr_main_thread, webxr_main_thread,
pending_wr_frame, pending_wr_frame,
}, },
@ -806,6 +826,10 @@ where
log::set_max_level(filter); log::set_max_level(filter);
} }
pub fn window(&self) -> &Window {
&self.compositor.window
}
pub fn deinit(self) { pub fn deinit(self) {
self.compositor.deinit(); self.compositor.deinit();
} }
@ -1030,8 +1054,9 @@ fn create_sandbox() {
} }
// Initializes the WebGL thread. // Initializes the WebGL thread.
fn create_webgl_threads<W>( fn create_webgl_threads(
window: &W, webrender_surfman: WebrenderSurfman,
webrender_gl: Rc<dyn gl::Gl>,
webrender: &mut webrender::Renderer, webrender: &mut webrender::Renderer,
webrender_api_sender: webrender_api::RenderApiSender, webrender_api_sender: webrender_api::RenderApiSender,
webxr_main_thread: &mut webxr::MainThreadRegistry, webxr_main_thread: &mut webxr::MainThreadRegistry,
@ -1040,45 +1065,8 @@ fn create_webgl_threads<W>(
) -> ( ) -> (
Option<WebGLThreads>, Option<WebGLThreads>,
Option<(SurfaceProviders, WebGlExecutor)>, Option<(SurfaceProviders, WebGlExecutor)>,
) ) {
where let gl_type = match webrender_gl.get_type() {
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() {
gleam::gl::GlType::Gl => sparkle::gl::GlType::Gl, gleam::gl::GlType::Gl => sparkle::gl::GlType::Gl,
gleam::gl::GlType::Gles => sparkle::gl::GlType::Gles, gleam::gl::GlType::Gles => sparkle::gl::GlType::Gles,
}; };
@ -1091,9 +1079,8 @@ where
output_handler, output_handler,
webgl_executor, webgl_executor,
} = WebGLComm::new( } = WebGLComm::new(
device, webrender_surfman,
context, webrender_gl,
window.gl(),
webrender_api_sender, webrender_api_sender,
external_images, external_images,
gl_type, 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] [dependencies]
euclid = "0.20" euclid = "0.20"
servo_geometry = {path = "../geometry"}
webrender_api = {git = "https://github.com/servo/webrender"} webrender_api = {git = "https://github.com/servo/webrender"}

View file

@ -5,8 +5,10 @@
#![deny(unsafe_code)] #![deny(unsafe_code)]
use euclid::default::Size2D; use euclid::default::Size2D;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use webrender_api::units::TexelRect; use webrender_api::units::TexelRect;
/// This trait is used as a bridge between the different GL clients /// This trait is used as a bridge between the different GL clients

View file

@ -492,9 +492,7 @@ def macos_release_build_with_debug_assertions(priority=None):
"./etc/ci/lockfile_changed.sh", "./etc/ci/lockfile_changed.sh",
"tar -czf target.tar.gz" + "tar -czf target.tar.gz" +
" target/release/servo" + " target/release/servo" +
" target/release/build/osmesa-src-*/output" + " resources",
" target/release/build/osmesa-src-*/out/src/gallium/targets/osmesa/.libs" +
" target/release/build/osmesa-src-*/out/src/mapi/shared-glapi/.libs",
])) ]))
.with_artifacts("repo/target.tar.gz") .with_artifacts("repo/target.tar.gz")
.find_or_create("build.macos_x64_release_w_assertions." + CONFIG.tree_hash()) .find_or_create("build.macos_x64_release_w_assertions." + CONFIG.tree_hash())
@ -522,8 +520,7 @@ def linux_release_build_with_debug_assertions(layout_2020):
./etc/ci/lockfile_changed.sh ./etc/ci/lockfile_changed.sh
tar -czf /target.tar.gz \ tar -czf /target.tar.gz \
target/release/servo \ target/release/servo \
target/release/build/osmesa-src-*/output \ resources
target/release/build/osmesa-src-*/out/lib/gallium
sccache --show-stats sccache --show-stats
""" % build_args) """ % build_args)
.with_artifacts("/target.tar.gz") .with_artifacts("/target.tar.gz")
@ -573,12 +570,17 @@ def wpt_chunks(platform, make_chunk_task, build_task, total_chunks, processes,
start = 1 # Skip the "extra" WPT testing, a.k.a. chunk 0 start = 1 # Skip the "extra" WPT testing, a.k.a. chunk 0
name_prefix = "Layout 2020 " name_prefix = "Layout 2020 "
job_id_prefix = "2020-" job_id_prefix = "2020-"
args = "--layout-2020" args = ["--layout-2020"]
else: else:
start = 0 start = 0
name_prefix = "" name_prefix = ""
job_id_prefix = "" job_id_prefix = ""
args = "" args = []
# Our Mac CI runs on machines with an Intel 4000 GPU, so need to work around
# https://github.com/servo/webrender/wiki/Driver-issues#bug-1570736---texture-swizzling-affects-wrap-modes-on-some-intel-gpus
if platform == "macOS x64":
args += ["--pref gfx.texture-swizzling.enabled=false"]
if chunks == "all": if chunks == "all":
chunks = range(start, total_chunks + 1) chunks = range(start, total_chunks + 1)
@ -604,7 +606,7 @@ def wpt_chunks(platform, make_chunk_task, build_task, total_chunks, processes,
TOTAL_CHUNKS=str(total_chunks), TOTAL_CHUNKS=str(total_chunks),
THIS_CHUNK=str(this_chunk), THIS_CHUNK=str(this_chunk),
PROCESSES=str(processes), PROCESSES=str(processes),
WPT_ARGS=args, WPT_ARGS=" ".join(args),
GST_DEBUG="3", GST_DEBUG="3",
) )
) )
@ -613,7 +615,6 @@ def wpt_chunks(platform, make_chunk_task, build_task, total_chunks, processes,
# https://github.com/servo/servo/issues/22438 # https://github.com/servo/servo/issues/22438
if this_chunk == 0: if this_chunk == 0:
task.with_script(""" task.with_script("""
./mach test-wpt-failure
time python2 ./mach test-wpt --release --binary-arg=--multiprocess \ time python2 ./mach test-wpt --release --binary-arg=--multiprocess \
--processes $PROCESSES \ --processes $PROCESSES \
--log-raw test-wpt-mp.log \ --log-raw test-wpt-mp.log \

View file

@ -53,7 +53,6 @@ clipboard = "0.5"
euclid = "0.20" euclid = "0.20"
getopts = "0.2.11" getopts = "0.2.11"
gleam = "0.9" gleam = "0.9"
glutin = "0.21.0"
keyboard-types = "0.4.3" keyboard-types = "0.4.3"
lazy_static = "1" lazy_static = "1"
libservo = {path = "../../components/servo"} libservo = {path = "../../components/servo"}
@ -61,19 +60,17 @@ libc = "0.2"
log = "0.4" log = "0.4"
servo-media = {git = "https://github.com/servo/media"} servo-media = {git = "https://github.com/servo/media"}
shellwords = "1.0.0" shellwords = "1.0.0"
surfman = { version = "0.2", features = ["sm-winit", "sm-x11"] }
tinyfiledialogs = "3.0" tinyfiledialogs = "3.0"
webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] } webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] }
webxr = { git = "https://github.com/servo/webxr", features = ["ipc", "glwindow", "headless"] } webxr = { git = "https://github.com/servo/webxr", features = ["ipc", "glwindow", "headless"] }
winit = "0.19"
[target.'cfg(any(target_os = "linux", target_os = "windows"))'.dependencies] [target.'cfg(any(target_os = "linux", target_os = "windows"))'.dependencies]
image = "0.23" image = "0.23"
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies] [target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
osmesa-sys = "0.1.2"
sig = "1.0" sig = "1.0"
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["wingdi", "winuser", "winnt", "winbase", "processenv", "namedpipeapi", "ntdef", "minwindef", "handleapi", "debugapi"] } winapi = { version = "0.3", features = ["wingdi", "winuser", "winnt", "winbase", "processenv", "namedpipeapi", "ntdef", "minwindef", "handleapi", "debugapi"] }
[target.'cfg(any(target_os = "macos", all(target_arch = "x86_64", target_os = "linux")))'.dependencies]
osmesa-src = {git = "https://github.com/servo/osmesa-src"}

View file

@ -9,7 +9,7 @@ use crate::embedder::EmbedderCallbacks;
use crate::events_loop::EventsLoop; use crate::events_loop::EventsLoop;
use crate::window_trait::WindowPortsMethods; use crate::window_trait::WindowPortsMethods;
use crate::{headed_window, headless_window}; use crate::{headed_window, headless_window};
use glutin::WindowId; use winit::WindowId;
use servo::compositing::windowing::WindowEvent; use servo::compositing::windowing::WindowEvent;
use servo::config::opts::{self, parse_url_or_filename}; use servo::config::opts::{self, parse_url_or_filename};
use servo::servo_config::pref; use servo::servo_config::pref;
@ -20,6 +20,7 @@ use std::collections::HashMap;
use std::env; use std::env;
use std::mem; use std::mem;
use std::rc::Rc; use std::rc::Rc;
use webxr::glwindow::GlWindowDiscovery;
thread_local! { thread_local! {
pub static WINDOWS: RefCell<HashMap<WindowId, Rc<dyn WindowPortsMethods>>> = RefCell::new(HashMap::new()); pub static WINDOWS: RefCell<HashMap<WindowId, Rc<dyn WindowPortsMethods>>> = RefCell::new(HashMap::new());
@ -35,9 +36,6 @@ pub struct App {
impl App { impl App {
pub fn run( pub fn run(
angle: bool,
enable_vsync: bool,
use_msaa: bool,
no_native_titlebar: bool, no_native_titlebar: bool,
device_pixels_per_px: Option<f32>, device_pixels_per_px: Option<f32>,
user_agent: Option<String>, user_agent: Option<String>,
@ -50,21 +48,31 @@ impl App {
} else { } else {
Rc::new(headed_window::Window::new( Rc::new(headed_window::Window::new(
opts::get().initial_window_size, opts::get().initial_window_size,
None,
events_loop.clone(), events_loop.clone(),
angle,
enable_vsync,
use_msaa,
no_native_titlebar, no_native_titlebar,
device_pixels_per_px, device_pixels_per_px,
)) ))
}; };
let xr_discovery = if pref!(dom.webxr.glwindow) {
let window = window.clone();
let surfman = window.webrender_surfman();
let events_loop = events_loop.clone();
let factory = Box::new(move || Ok(window.new_glwindow(&*events_loop.borrow())));
Some(GlWindowDiscovery::new(
surfman.connection(),
surfman.adapter(),
surfman.context_attributes(),
factory,
))
} else {
None
};
// Implements embedder methods, used by libservo and constellation. // Implements embedder methods, used by libservo and constellation.
let embedder = Box::new(EmbedderCallbacks::new( let embedder = Box::new(EmbedderCallbacks::new(
window.clone(),
events_loop.clone(), events_loop.clone(),
window.gl(), xr_discovery,
)); ));
// Handle browser state. // Handle browser state.
@ -93,36 +101,36 @@ impl App {
} }
// This function decides whether the event should be handled during `run_forever`. // This function decides whether the event should be handled during `run_forever`.
fn winit_event_to_servo_event(&self, event: glutin::Event) -> glutin::ControlFlow { fn winit_event_to_servo_event(&self, event: winit::Event) -> winit::ControlFlow {
match event { match event {
// App level events // App level events
glutin::Event::Suspended(suspended) => { winit::Event::Suspended(suspended) => {
self.suspended.set(suspended); self.suspended.set(suspended);
if !suspended { if !suspended {
self.event_queue.borrow_mut().push(WindowEvent::Idle); self.event_queue.borrow_mut().push(WindowEvent::Idle);
} }
}, },
glutin::Event::Awakened => { winit::Event::Awakened => {
self.event_queue.borrow_mut().push(WindowEvent::Idle); self.event_queue.borrow_mut().push(WindowEvent::Idle);
}, },
glutin::Event::DeviceEvent { .. } => {}, winit::Event::DeviceEvent { .. } => {},
// Window level events // Window level events
glutin::Event::WindowEvent { winit::Event::WindowEvent {
window_id, event, .. window_id, event, ..
} => { } => {
return WINDOWS.with(|windows| { return WINDOWS.with(|windows| {
match windows.borrow().get(&window_id) { match windows.borrow().get(&window_id) {
None => { None => {
warn!("Got an event from unknown window"); warn!("Got an event from unknown window");
glutin::ControlFlow::Break winit::ControlFlow::Break
}, },
Some(window) => { Some(window) => {
// Resize events need to be handled during run_forever // Resize events need to be handled during run_forever
let cont = if let glutin::WindowEvent::Resized(_) = event { let cont = if let winit::WindowEvent::Resized(_) = event {
glutin::ControlFlow::Continue winit::ControlFlow::Continue
} else { } else {
glutin::ControlFlow::Break winit::ControlFlow::Break
}; };
window.winit_event_to_servo_event(event); window.winit_event_to_servo_event(event);
return cont; return cont;
@ -131,7 +139,7 @@ impl App {
}); });
}, },
} }
glutin::ControlFlow::Break winit::ControlFlow::Break
} }
fn run_loop(self) { fn run_loop(self) {
@ -146,7 +154,7 @@ impl App {
// If there's no animations running then we block on the window event loop. // If there's no animations running then we block on the window event loop.
self.events_loop.borrow_mut().run_forever(|e| { self.events_loop.borrow_mut().run_forever(|e| {
let cont = self.winit_event_to_servo_event(e); let cont = self.winit_event_to_servo_event(e);
if cont == glutin::ControlFlow::Continue { if cont == winit::ControlFlow::Continue {
// Note we need to be careful to make sure that any events // Note we need to be careful to make sure that any events
// that are handled during run_forever aren't re-entrant, // that are handled during run_forever aren't re-entrant,
// since we are handling them while holding onto a mutable borrow // since we are handling them while holding onto a mutable borrow
@ -237,14 +245,3 @@ pub fn register_window(window: Rc<dyn WindowPortsMethods>) {
w.borrow_mut().insert(window.id(), window); w.borrow_mut().insert(window.id(), window);
}); });
} }
pub fn gl_version(angle: bool) -> glutin::GlRequest {
if angle {
glutin::GlRequest::Specific(glutin::Api::OpenGlEs, (3, 0))
} else {
glutin::GlRequest::GlThenGles {
opengl_version: (3, 2),
opengles_version: (3, 0),
}
}
}

View file

@ -1,172 +0,0 @@
/* 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/. */
use glutin::os::ContextTraitExt;
use glutin::{ContextBuilder, CreationError, EventsLoop, NotCurrent, PossiblyCurrent, WindowedContext, WindowBuilder};
use servo_media::player::context::GlContext as RawContext;
use std::os::raw;
pub enum GlContext {
Current(WindowedContext<PossiblyCurrent>),
NotCurrent(WindowedContext<NotCurrent>),
// Used a temporary value as we switch from Current to NotCurrent.
None,
}
impl GlContext {
pub fn window(&self) -> &glutin::Window {
match self {
GlContext::Current(c) => c.window(),
GlContext::NotCurrent(c) => c.window(),
GlContext::None => unreachable!(),
}
}
pub fn resize(&mut self, size: glutin::dpi::PhysicalSize) {
if let GlContext::NotCurrent(_) = self {
self.make_current();
}
match self {
GlContext::Current(c) => c.resize(size),
_ => unreachable!(),
}
}
pub fn make_current(&mut self) {
*self = match std::mem::replace(self, GlContext::None) {
GlContext::Current(c) => {
warn!("Making an already current context current");
// Servo thinks that that this window is current,
// but it might be wrong, since other code may have
// changed the current GL context. Just to be on
// the safe side, we make it current anyway.
let c = unsafe {
c.make_current().expect("Couldn't make window current")
};
GlContext::Current(c)
},
GlContext::NotCurrent(c) => {
let c = unsafe {
c.make_current().expect("Couldn't make window current")
};
GlContext::Current(c)
}
GlContext::None => unreachable!(),
}
}
pub fn make_not_current(&mut self) {
*self = match std::mem::replace(self, GlContext::None) {
GlContext::Current(c) => {
let c = unsafe {
c.make_not_current().expect("Couldn't make window not current")
};
GlContext::NotCurrent(c)
},
GlContext::NotCurrent(c) => {
warn!("Making an already not current context not current");
GlContext::NotCurrent(c)
}
GlContext::None => unreachable!(),
}
}
pub fn swap_buffers(&self) {
match self {
GlContext::Current(c) => {
if let Err(err) = c.swap_buffers() {
warn!("Failed to swap window buffers ({}).", err);
}
},
GlContext::NotCurrent(_) => {
error!("Context is not current. Forgot to call prepare_for_composite?");
},
GlContext::None => unreachable!(),
};
}
#[allow(unreachable_code, unused_variables)]
pub fn raw_context(&self) -> RawContext {
match self {
GlContext::Current(c) => {
#[cfg(target_os = "linux")]
{
use glutin::os::unix::RawHandle;
let raw_handle = unsafe { c.raw_handle() };
return match raw_handle {
RawHandle::Egl(handle) => RawContext::Egl(handle as usize),
RawHandle::Glx(handle) => RawContext::Glx(handle as usize),
};
}
#[cfg(target_os = "windows")]
{
use glutin::os::windows::RawHandle;
let raw_handle = unsafe { c.raw_handle() };
return match raw_handle {
RawHandle::Egl(handle) => RawContext::Egl(handle as usize),
// @TODO(victor): RawContext::Wgl in servo-media
RawHandle::Wgl(_) => unimplemented!(),
}
}
// @TODO(victor): https://github.com/rust-windowing/glutin/pull/1221
// https://github.com/servo/media/pull/315
#[cfg(target_os = "macos")]
return unimplemented!();
#[cfg(not(any(
target_os = "linux",
target_os = "windows",
target_os = "macos",
)))]
unimplemented!()
}
GlContext::NotCurrent(_) => {
error!("Context is not current.");
RawContext::Unknown
}
GlContext::None => unreachable!(),
}
}
pub fn new_window<T>(
&self,
cb: ContextBuilder<T>,
wb: WindowBuilder,
el: &EventsLoop
) -> Result<WindowedContext<NotCurrent>, CreationError>
where
T: glutin::ContextCurrentState,
{
match self {
GlContext::Current(ref c) => {
cb.with_shared_lists(c).build_windowed(wb, el)
},
GlContext::NotCurrent(ref c) => {
cb.with_shared_lists(c).build_windowed(wb, el)
},
GlContext::None => {
cb.build_windowed(wb, el)
},
}
}
#[allow(dead_code)]
pub fn egl_display(&self) -> Option<*const raw::c_void> {
match self {
GlContext::Current(c) => unsafe { c.get_egl_display() },
GlContext::NotCurrent(_) => {
error!("Context is not current.");
None
},
GlContext::None => unreachable!(),
}
}
pub fn get_api(&self) -> glutin::Api {
match self {
GlContext::Current(c) => c.get_api(),
GlContext::NotCurrent(c) => c.get_api(),
GlContext::None => unreachable!(),
}
}
}

View file

@ -5,31 +5,27 @@
//! Implements the global methods required by Servo (not window/gl/compositor related). //! Implements the global methods required by Servo (not window/gl/compositor related).
use crate::events_loop::EventsLoop; use crate::events_loop::EventsLoop;
use crate::window_trait::WindowPortsMethods;
use gleam::gl;
use servo::canvas::{SurfaceProviders, WebGlExecutor}; use servo::canvas::{SurfaceProviders, WebGlExecutor};
use servo::compositing::windowing::EmbedderMethods; use servo::compositing::windowing::EmbedderMethods;
use servo::embedder_traits::{EmbedderProxy, EventLoopWaker}; use servo::embedder_traits::{EmbedderProxy, EventLoopWaker};
use servo::servo_config::{opts, pref}; use servo::servo_config::pref;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use webxr::glwindow::GlWindowDiscovery;
pub struct EmbedderCallbacks { pub struct EmbedderCallbacks {
window: Rc<dyn WindowPortsMethods>,
events_loop: Rc<RefCell<EventsLoop>>, events_loop: Rc<RefCell<EventsLoop>>,
gl: Rc<dyn gl::Gl>, xr_discovery: Option<GlWindowDiscovery>,
} }
impl EmbedderCallbacks { impl EmbedderCallbacks {
pub fn new( pub fn new(
window: Rc<dyn WindowPortsMethods>,
events_loop: Rc<RefCell<EventsLoop>>, events_loop: Rc<RefCell<EventsLoop>>,
gl: Rc<dyn gl::Gl>, xr_discovery: Option<GlWindowDiscovery>,
) -> EmbedderCallbacks { ) -> EmbedderCallbacks {
EmbedderCallbacks { EmbedderCallbacks {
window,
events_loop, events_loop,
gl, xr_discovery,
} }
} }
} }
@ -48,13 +44,8 @@ impl EmbedderMethods for EmbedderCallbacks {
) { ) {
if pref!(dom.webxr.test) { if pref!(dom.webxr.test) {
xr.register_mock(webxr::headless::HeadlessMockDiscovery::new()); xr.register_mock(webxr::headless::HeadlessMockDiscovery::new());
} else if !opts::get().headless && pref!(dom.webxr.glwindow) { } else if let Some(xr_discovery) = self.xr_discovery.take() {
warn!("Creating test XR device"); xr.register(xr_discovery);
let gl = self.gl.clone();
let window = self.window.clone();
let factory = Box::new(move || window.new_window());
let discovery = webxr::glwindow::GlWindowDiscovery::new(gl, factory);
xr.register(discovery);
} }
} }
} }

View file

@ -5,7 +5,7 @@
//! An event loop implementation that works in headless mode. //! An event loop implementation that works in headless mode.
use glutin; use winit;
use servo::embedder_traits::EventLoopWaker; use servo::embedder_traits::EventLoopWaker;
use std::sync::{Arc, Condvar, Mutex}; use std::sync::{Arc, Condvar, Mutex};
use std::rc::Rc; use std::rc::Rc;
@ -14,8 +14,8 @@ use std::time;
#[allow(dead_code)] #[allow(dead_code)]
enum EventLoop { enum EventLoop {
/// A real Glutin windowing event loop. /// A real Winit windowing event loop.
Glutin(Option<glutin::EventsLoop>), Winit(Option<winit::EventsLoop>),
/// A fake event loop which contains a signalling flag used to ensure /// A fake event loop which contains a signalling flag used to ensure
/// that pending events get processed in a timely fashion, and a condition /// that pending events get processed in a timely fashion, and a condition
/// variable to allow waiting on that flag changing state. /// variable to allow waiting on that flag changing state.
@ -29,14 +29,14 @@ impl EventsLoop {
// but on Linux, the event loop requires a X11 server. // but on Linux, the event loop requires a X11 server.
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))]
pub fn new(_headless: bool) -> Rc<RefCell<EventsLoop>> { pub fn new(_headless: bool) -> Rc<RefCell<EventsLoop>> {
Rc::new(RefCell::new(EventsLoop(EventLoop::Glutin(Some(glutin::EventsLoop::new()))))) Rc::new(RefCell::new(EventsLoop(EventLoop::Winit(Some(winit::EventsLoop::new())))))
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub fn new(headless: bool) -> Rc<RefCell<EventsLoop>> { pub fn new(headless: bool) -> Rc<RefCell<EventsLoop>> {
let events_loop = if headless { let events_loop = if headless {
EventLoop::Headless(Arc::new((Mutex::new(false), Condvar::new()))) EventLoop::Headless(Arc::new((Mutex::new(false), Condvar::new())))
} else { } else {
EventLoop::Glutin(Some(glutin::EventsLoop::new())) EventLoop::Winit(Some(winit::EventsLoop::new()))
}; };
Rc::new(RefCell::new(EventsLoop(events_loop))) Rc::new(RefCell::new(EventsLoop(events_loop)))
} }
@ -45,7 +45,7 @@ impl EventsLoop {
impl EventsLoop { impl EventsLoop {
pub fn create_event_loop_waker(&self) -> Box<dyn EventLoopWaker> { pub fn create_event_loop_waker(&self) -> Box<dyn EventLoopWaker> {
match self.0 { match self.0 {
EventLoop::Glutin(ref events_loop) => { EventLoop::Winit(ref events_loop) => {
let events_loop = events_loop let events_loop = events_loop
.as_ref() .as_ref()
.expect("Can't create waker for unavailable event loop."); .expect("Can't create waker for unavailable event loop.");
@ -55,17 +55,18 @@ impl EventsLoop {
Box::new(HeadlessEventLoopWaker(data.clone())), Box::new(HeadlessEventLoopWaker(data.clone())),
} }
} }
pub fn as_winit(&self) -> &glutin::EventsLoop { pub fn as_winit(&self) -> &winit::EventsLoop {
match self.0 { match self.0 {
EventLoop::Glutin(Some(ref event_loop)) => event_loop, EventLoop::Winit(Some(ref event_loop)) => event_loop,
EventLoop::Glutin(None) | EventLoop::Headless(..) => EventLoop::Winit(None) | EventLoop::Headless(..) =>
panic!("Can't access winit event loop while using the fake headless event loop"), panic!("Can't access winit event loop while using the fake headless event loop"),
} }
} }
pub fn poll_events<F>(&mut self, callback: F) where F: FnMut(glutin::Event) {
pub fn poll_events<F>(&mut self, callback: F) where F: FnMut(winit::Event) {
match self.0 { match self.0 {
EventLoop::Glutin(Some(ref mut events_loop)) => events_loop.poll_events(callback), EventLoop::Winit(Some(ref mut events_loop)) => events_loop.poll_events(callback),
EventLoop::Glutin(None) => (), EventLoop::Winit(None) => (),
EventLoop::Headless(ref data) => { EventLoop::Headless(ref data) => {
// This is subtle - the use of the event loop in App::run_loop // This is subtle - the use of the event loop in App::run_loop
// optionally calls run_forever, then always calls poll_events. // optionally calls run_forever, then always calls poll_events.
@ -80,9 +81,9 @@ impl EventsLoop {
} }
} }
} }
pub fn run_forever<F>(&mut self, mut callback: F) where F: FnMut(glutin::Event) -> glutin::ControlFlow { pub fn run_forever<F>(&mut self, mut callback: F) where F: FnMut(winit::Event) -> winit::ControlFlow {
match self.0 { match self.0 {
EventLoop::Glutin(ref mut events_loop) => { EventLoop::Winit(ref mut events_loop) => {
let events_loop = events_loop let events_loop = events_loop
.as_mut() .as_mut()
.expect("Can't run an unavailable event loop."); .expect("Can't run an unavailable event loop.");
@ -92,7 +93,7 @@ impl EventsLoop {
let &(ref flag, ref condvar) = &**data; let &(ref flag, ref condvar) = &**data;
while !*flag.lock().unwrap() { while !*flag.lock().unwrap() {
self.sleep(flag, condvar); self.sleep(flag, condvar);
if callback(glutin::Event::Awakened) == glutin::ControlFlow::Break { if callback(winit::Event::Awakened) == winit::ControlFlow::Break {
break; break;
} }
} }
@ -115,10 +116,10 @@ impl EventsLoop {
} }
struct HeadedEventLoopWaker { struct HeadedEventLoopWaker {
proxy: Arc<glutin::EventsLoopProxy>, proxy: Arc<winit::EventsLoopProxy>,
} }
impl HeadedEventLoopWaker { impl HeadedEventLoopWaker {
fn new(events_loop: &glutin::EventsLoop) -> HeadedEventLoopWaker { fn new(events_loop: &winit::EventsLoop) -> HeadedEventLoopWaker {
let proxy = Arc::new(events_loop.create_proxy()); let proxy = Arc::new(events_loop.create_proxy());
HeadedEventLoopWaker { proxy } HeadedEventLoopWaker { proxy }
} }

View file

@ -2,27 +2,21 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! A glutin window implementation. //! A winit window implementation.
use crate::app;
use crate::context::GlContext;
use crate::events_loop::EventsLoop; use crate::events_loop::EventsLoop;
use crate::keyutils::keyboard_event_from_winit; use crate::keyutils::keyboard_event_from_winit;
use crate::window_trait::{WindowPortsMethods, LINE_HEIGHT}; use crate::window_trait::{WindowPortsMethods, LINE_HEIGHT};
use euclid::{ use euclid::{
Angle, default::Size2D as UntypedSize2D, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Angle, Point2D, Rotation3D, Scale, Size2D, UnknownUnit,
Vector2D, Vector3D, Vector2D, Vector3D,
}; };
use gleam::gl; use winit::dpi::{LogicalPosition, LogicalSize, PhysicalSize};
use glutin::dpi::{LogicalPosition, LogicalSize, PhysicalSize};
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
use glutin::os::macos::{ActivationPolicy, WindowBuilderExt}; use winit::os::macos::{ActivationPolicy, WindowBuilderExt};
#[cfg(target_os = "linux")]
use glutin::os::unix::WindowExt;
use glutin::Api;
#[cfg(any(target_os = "linux", target_os = "windows"))] #[cfg(any(target_os = "linux", target_os = "windows"))]
use glutin::Icon; use winit::Icon;
use glutin::{ElementState, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode}; use winit::{ElementState, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
#[cfg(any(target_os = "linux", target_os = "windows"))] #[cfg(any(target_os = "linux", target_os = "windows"))]
use image; use image;
use keyboard_types::{Key, KeyState, KeyboardEvent}; use keyboard_types::{Key, KeyState, KeyboardEvent};
@ -30,22 +24,32 @@ use servo::compositing::windowing::{AnimationState, MouseWindowEvent, WindowEven
use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods}; use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods};
use servo::embedder_traits::Cursor; use servo::embedder_traits::Cursor;
use servo::script_traits::{TouchEventType, WheelMode, WheelDelta}; use servo::script_traits::{TouchEventType, WheelMode, WheelDelta};
use servo::servo_config::{opts, pref}; use servo::servo_config::opts;
use servo::servo_config::pref;
use servo::servo_geometry::DeviceIndependentPixel; use servo::servo_geometry::DeviceIndependentPixel;
use servo::style_traits::DevicePixel; use servo::style_traits::DevicePixel;
use servo::webrender_api::ScrollLocation; use servo::webrender_api::ScrollLocation;
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use servo::webrender_surfman::WebrenderSurfman;
use servo_media::player::context::{GlApi, GlContext as PlayerGLContext, NativeDisplay}; use servo_media::player::context::{GlApi, GlContext as PlayerGLContext, NativeDisplay};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::mem; use std::mem;
use std::rc::Rc; use std::rc::Rc;
#[cfg(target_os = "linux")]
use surfman::platform::generic::multi::connection::NativeConnection;
#[cfg(target_os = "linux")]
use surfman::platform::generic::multi::context::NativeContext;
use surfman::Connection;
use surfman::Device;
use surfman::GLApi;
use surfman::GLVersion;
use surfman::NativeWidget;
use surfman::SurfaceType;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use winapi; use winapi;
const MULTISAMPLES: u16 = 16;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
fn builder_with_platform_options(mut builder: glutin::WindowBuilder) -> glutin::WindowBuilder { fn builder_with_platform_options(mut builder: winit::WindowBuilder) -> winit::WindowBuilder {
if opts::get().output_file.is_some() { if opts::get().output_file.is_some() {
// Prevent the window from showing in Dock.app, stealing focus, // Prevent the window from showing in Dock.app, stealing focus,
// when generating an output file. // when generating an output file.
@ -55,31 +59,25 @@ fn builder_with_platform_options(mut builder: glutin::WindowBuilder) -> glutin::
} }
#[cfg(not(target_os = "macos"))] #[cfg(not(target_os = "macos"))]
fn builder_with_platform_options(builder: glutin::WindowBuilder) -> glutin::WindowBuilder { fn builder_with_platform_options(builder: winit::WindowBuilder) -> winit::WindowBuilder {
builder builder
} }
pub struct Window { pub struct Window {
gl_context: RefCell<GlContext>, winit_window: winit::Window,
events_loop: Rc<RefCell<EventsLoop>>, webrender_surfman: WebrenderSurfman,
screen_size: Size2D<u32, DeviceIndependentPixel>, screen_size: Size2D<u32, DeviceIndependentPixel>,
inner_size: Cell<Size2D<u32, DeviceIndependentPixel>>, inner_size: Cell<Size2D<u32, DeviceIndependentPixel>>,
mouse_down_button: Cell<Option<glutin::MouseButton>>, mouse_down_button: Cell<Option<winit::MouseButton>>,
mouse_down_point: Cell<Point2D<i32, DevicePixel>>, mouse_down_point: Cell<Point2D<i32, DevicePixel>>,
primary_monitor: glutin::MonitorId, primary_monitor: winit::MonitorId,
event_queue: RefCell<Vec<WindowEvent>>, event_queue: RefCell<Vec<WindowEvent>>,
mouse_pos: Cell<Point2D<i32, DevicePixel>>, mouse_pos: Cell<Point2D<i32, DevicePixel>>,
last_pressed: Cell<Option<KeyboardEvent>>, last_pressed: Cell<Option<KeyboardEvent>>,
animation_state: Cell<AnimationState>, animation_state: Cell<AnimationState>,
fullscreen: Cell<bool>, fullscreen: Cell<bool>,
gl: Rc<dyn gl::Gl>,
xr_rotation: Cell<Rotation3D<f32, UnknownUnit, UnknownUnit>>,
xr_translation: Cell<Vector3D<f32, UnknownUnit>>,
angle: bool,
enable_vsync: bool,
use_msaa: bool,
no_native_titlebar: bool,
device_pixels_per_px: Option<f32>, device_pixels_per_px: Option<f32>,
xr_window_poses: RefCell<Vec<Rc<XRWindowPose>>>,
} }
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
@ -97,11 +95,7 @@ fn window_creation_scale_factor() -> Scale<f32, DeviceIndependentPixel, DevicePi
impl Window { impl Window {
pub fn new( pub fn new(
win_size: Size2D<u32, DeviceIndependentPixel>, win_size: Size2D<u32, DeviceIndependentPixel>,
sharing: Option<&Window>,
events_loop: Rc<RefCell<EventsLoop>>, events_loop: Rc<RefCell<EventsLoop>>,
angle: bool,
enable_vsync: bool,
use_msaa: bool,
no_native_titlebar: bool, no_native_titlebar: bool,
device_pixels_per_px: Option<f32>, device_pixels_per_px: Option<f32>,
) -> Window { ) -> Window {
@ -117,7 +111,7 @@ impl Window {
let width = win_size.to_untyped().width; let width = win_size.to_untyped().width;
let height = win_size.to_untyped().height; let height = win_size.to_untyped().height;
let mut window_builder = glutin::WindowBuilder::new() let mut window_builder = winit::WindowBuilder::new()
.with_title("Servo".to_string()) .with_title("Servo".to_string())
.with_decorations(!no_native_titlebar) .with_decorations(!no_native_titlebar)
.with_transparency(no_native_titlebar) .with_transparency(no_native_titlebar)
@ -127,39 +121,14 @@ impl Window {
window_builder = builder_with_platform_options(window_builder); window_builder = builder_with_platform_options(window_builder);
let mut context_builder = glutin::ContextBuilder::new() let winit_window = window_builder.build(events_loop.borrow().as_winit()).expect("Failed to create window.");
.with_gl(app::gl_version(angle))
.with_vsync(enable_vsync);
if use_msaa {
context_builder = context_builder.with_multisampling(MULTISAMPLES)
}
let context = match sharing {
Some(sharing) => sharing.gl_context.borrow().new_window(
context_builder,
window_builder,
events_loop.borrow().as_winit()
),
None => context_builder.build_windowed(window_builder, events_loop.borrow().as_winit()),
}.expect("Failed to create window.");
#[cfg(any(target_os = "linux", target_os = "windows"))] #[cfg(any(target_os = "linux", target_os = "windows"))]
{ {
let icon_bytes = include_bytes!("../../resources/servo64.png"); let icon_bytes = include_bytes!("../../resources/servo64.png");
context.window().set_window_icon(Some(load_icon(icon_bytes))); winit_window.set_window_icon(Some(load_icon(icon_bytes)));
} }
if let Some(sharing) = sharing {
debug!("Making window {:?} not current", sharing.gl_context.borrow().window().id());
sharing.gl_context.borrow_mut().make_not_current();
}
let context = unsafe {
debug!("Making window {:?} current", context.window().id());
context.make_current().expect("Couldn't make window current")
};
let primary_monitor = events_loop.borrow().as_winit().get_primary_monitor(); let primary_monitor = events_loop.borrow().as_winit().get_primary_monitor();
let PhysicalSize { let PhysicalSize {
@ -168,59 +137,43 @@ impl Window {
} = primary_monitor.get_dimensions(); } = primary_monitor.get_dimensions();
let screen_size = Size2D::new(screen_width as u32, screen_height as u32); let screen_size = Size2D::new(screen_width as u32, screen_height as u32);
// TODO(ajeffrey): can this fail? // TODO(ajeffrey): can this fail?
let LogicalSize { width, height } = context let LogicalSize { width, height } = winit_window
.window()
.get_inner_size() .get_inner_size()
.expect("Failed to get window inner size."); .expect("Failed to get window inner size.");
let inner_size = Size2D::new(width as u32, height as u32); let inner_size = Size2D::new(width as u32, height as u32);
context.window().show(); winit_window.show();
let gl = if let Some(sharing) = sharing { // Initialize surfman
sharing.gl.clone() let connection = Connection::from_winit_window(&winit_window).expect("Failed to create connection");
} else { match context.get_api() { let adapter = connection.create_adapter().expect("Failed to create adapter");
Api::OpenGl => unsafe { let native_widget = connection
gl::GlFns::load_with(|s| context.get_proc_address(s) as *const _) .create_native_widget_from_winit_window(&winit_window)
}, .expect("Failed to create native widget");
Api::OpenGlEs => unsafe { let surface_type = SurfaceType::Widget { native_widget };
gl::GlesFns::load_with(|s| context.get_proc_address(s) as *const _) let webrender_surfman = WebrenderSurfman::create(
}, &connection,
Api::WebGl => unreachable!("webgl is unsupported"), &adapter,
} }; surface_type,
).expect("Failed to create WR surfman");
gl.clear_color(0.6, 0.6, 0.6, 1.0); debug!("Created window {:?}", winit_window.id());
gl.clear(gl::COLOR_BUFFER_BIT); Window {
gl.finish(); winit_window,
webrender_surfman,
let context = GlContext::Current(context);
debug!("Created window {:?}", context.window().id());
let window = Window {
gl_context: RefCell::new(context),
events_loop,
event_queue: RefCell::new(vec![]), event_queue: RefCell::new(vec![]),
mouse_down_button: Cell::new(None), mouse_down_button: Cell::new(None),
mouse_down_point: Cell::new(Point2D::new(0, 0)), mouse_down_point: Cell::new(Point2D::new(0, 0)),
mouse_pos: Cell::new(Point2D::new(0, 0)), mouse_pos: Cell::new(Point2D::new(0, 0)),
last_pressed: Cell::new(None), last_pressed: Cell::new(None),
gl: gl.clone(),
animation_state: Cell::new(AnimationState::Idle), animation_state: Cell::new(AnimationState::Idle),
fullscreen: Cell::new(false), fullscreen: Cell::new(false),
inner_size: Cell::new(inner_size), inner_size: Cell::new(inner_size),
primary_monitor, primary_monitor,
screen_size, screen_size,
xr_rotation: Cell::new(Rotation3D::identity()),
xr_translation: Cell::new(Vector3D::zero()),
angle,
enable_vsync,
use_msaa,
no_native_titlebar,
device_pixels_per_px, device_pixels_per_px,
}; xr_window_poses: RefCell::new(vec![]),
}
window.present();
window
} }
fn handle_received_character(&self, mut ch: char) { fn handle_received_character(&self, mut ch: char) {
@ -245,7 +198,10 @@ impl Window {
KeyboardEvent::default() KeyboardEvent::default()
}; };
event.key = Key::Character(ch.to_string()); event.key = Key::Character(ch.to_string());
self.handle_xr_translation(&event); let xr_poses = self.xr_window_poses.borrow();
for xr_window_pose in &*xr_poses {
xr_window_pose.handle_xr_translation(&event);
}
self.event_queue self.event_queue
.borrow_mut() .borrow_mut()
.push(WindowEvent::Keyboard(event)); .push(WindowEvent::Keyboard(event));
@ -258,68 +214,21 @@ impl Window {
self.last_pressed.set(Some(event)); self.last_pressed.set(Some(event));
} else if event.key != Key::Unidentified { } else if event.key != Key::Unidentified {
self.last_pressed.set(None); self.last_pressed.set(None);
self.handle_xr_rotation(&input); let xr_poses = self.xr_window_poses.borrow();
for xr_window_pose in &*xr_poses {
xr_window_pose.handle_xr_rotation(&input);
}
self.event_queue self.event_queue
.borrow_mut() .borrow_mut()
.push(WindowEvent::Keyboard(event)); .push(WindowEvent::Keyboard(event));
} }
} }
fn handle_xr_translation(&self, input: &KeyboardEvent) {
if input.state != KeyState::Down {
return;
}
const NORMAL_TRANSLATE: f32 = 0.1;
const QUICK_TRANSLATE: f32 = 1.0;
let mut x = 0.0;
let mut z = 0.0;
match input.key {
Key::Character(ref k) => match &**k {
"w" => z = -NORMAL_TRANSLATE,
"W" => z = -QUICK_TRANSLATE,
"s" => z = NORMAL_TRANSLATE,
"S" => z = QUICK_TRANSLATE,
"a" => x = -NORMAL_TRANSLATE,
"A" => x = -QUICK_TRANSLATE,
"d" => x = NORMAL_TRANSLATE,
"D" => x = QUICK_TRANSLATE,
_ => return,
},
_ => return,
};
let (old_x, old_y, old_z) = self.xr_translation.get().to_tuple();
let vec = Vector3D::new(x + old_x, old_y, z + old_z);
self.xr_translation.set(vec);
}
fn handle_xr_rotation(&self, input: &KeyboardInput) {
if input.state != glutin::ElementState::Pressed {
return;
}
let mut x = 0.0;
let mut y = 0.0;
match input.virtual_keycode {
Some(VirtualKeyCode::Up) => x = 1.0,
Some(VirtualKeyCode::Down) => x = -1.0,
Some(VirtualKeyCode::Left) => y = 1.0,
Some(VirtualKeyCode::Right) => y = -1.0,
_ => return,
};
if input.modifiers.shift {
x = 10.0 * x;
y = 10.0 * y;
}
let x: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::around_x(Angle::degrees(x));
let y: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::around_y(Angle::degrees(y));
let rotation = self.xr_rotation.get().post_rotate(&x).post_rotate(&y);
self.xr_rotation.set(rotation);
}
/// Helper function to handle a click /// Helper function to handle a click
fn handle_mouse( fn handle_mouse(
&self, &self,
button: glutin::MouseButton, button: winit::MouseButton,
action: glutin::ElementState, action: winit::ElementState,
coords: Point2D<i32, DevicePixel>, coords: Point2D<i32, DevicePixel>,
) { ) {
use servo::script_traits::MouseButton; use servo::script_traits::MouseButton;
@ -359,7 +268,7 @@ impl Window {
} }
fn device_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> { fn device_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
Scale::new(self.gl_context.borrow().window().get_hidpi_factor() as f32) Scale::new(self.winit_window.get_hidpi_factor() as f32)
} }
fn servo_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> { fn servo_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
@ -385,33 +294,31 @@ impl WindowPortsMethods for Window {
fn page_height(&self) -> f32 { fn page_height(&self) -> f32 {
let dpr = self.servo_hidpi_factor(); let dpr = self.servo_hidpi_factor();
let size = self let size = self
.gl_context .winit_window
.borrow()
.window()
.get_inner_size() .get_inner_size()
.expect("Failed to get window inner size."); .expect("Failed to get window inner size.");
size.height as f32 * dpr.get() size.height as f32 * dpr.get()
} }
fn set_title(&self, title: &str) { fn set_title(&self, title: &str) {
self.gl_context.borrow().window().set_title(title); self.winit_window.set_title(title);
} }
fn set_inner_size(&self, size: DeviceIntSize) { fn set_inner_size(&self, size: DeviceIntSize) {
let size = size.to_f32() / self.device_hidpi_factor(); let size = size.to_f32() / self.device_hidpi_factor();
self.gl_context.borrow_mut().window() self.winit_window
.set_inner_size(LogicalSize::new(size.width.into(), size.height.into())) .set_inner_size(LogicalSize::new(size.width.into(), size.height.into()))
} }
fn set_position(&self, point: DeviceIntPoint) { fn set_position(&self, point: DeviceIntPoint) {
let point = point.to_f32() / self.device_hidpi_factor(); let point = point.to_f32() / self.device_hidpi_factor();
self.gl_context.borrow_mut().window() self.winit_window
.set_position(LogicalPosition::new(point.x.into(), point.y.into())) .set_position(LogicalPosition::new(point.x.into(), point.y.into()))
} }
fn set_fullscreen(&self, state: bool) { fn set_fullscreen(&self, state: bool) {
if self.fullscreen.get() != state { if self.fullscreen.get() != state {
self.gl_context.borrow_mut().window() self.winit_window
.set_fullscreen(if state { Some(self.primary_monitor.clone()) } else { None }); .set_fullscreen(if state { Some(self.primary_monitor.clone()) } else { None });
} }
self.fullscreen.set(state); self.fullscreen.set(state);
@ -422,7 +329,7 @@ impl WindowPortsMethods for Window {
} }
fn set_cursor(&self, cursor: Cursor) { fn set_cursor(&self, cursor: Cursor) {
use glutin::MouseCursor; use winit::MouseCursor;
let winit_cursor = match cursor { let winit_cursor = match cursor {
Cursor::Default => MouseCursor::Default, Cursor::Default => MouseCursor::Default,
@ -461,27 +368,27 @@ impl WindowPortsMethods for Window {
Cursor::ZoomOut => MouseCursor::ZoomOut, Cursor::ZoomOut => MouseCursor::ZoomOut,
_ => MouseCursor::Default, _ => MouseCursor::Default,
}; };
self.gl_context.borrow_mut().window().set_cursor(winit_cursor); self.winit_window.set_cursor(winit_cursor);
} }
fn is_animating(&self) -> bool { fn is_animating(&self) -> bool {
self.animation_state.get() == AnimationState::Animating self.animation_state.get() == AnimationState::Animating
} }
fn id(&self) -> glutin::WindowId { fn id(&self) -> winit::WindowId {
self.gl_context.borrow().window().id() self.winit_window.id()
} }
fn winit_event_to_servo_event(&self, event: glutin::WindowEvent) { fn winit_event_to_servo_event(&self, event: winit::WindowEvent) {
match event { match event {
glutin::WindowEvent::ReceivedCharacter(ch) => self.handle_received_character(ch), winit::WindowEvent::ReceivedCharacter(ch) => self.handle_received_character(ch),
glutin::WindowEvent::KeyboardInput { input, .. } => self.handle_keyboard_input(input), winit::WindowEvent::KeyboardInput { input, .. } => self.handle_keyboard_input(input),
glutin::WindowEvent::MouseInput { state, button, .. } => { winit::WindowEvent::MouseInput { state, button, .. } => {
if button == MouseButton::Left || button == MouseButton::Right { if button == MouseButton::Left || button == MouseButton::Right {
self.handle_mouse(button, state, self.mouse_pos.get()); self.handle_mouse(button, state, self.mouse_pos.get());
} }
}, },
glutin::WindowEvent::CursorMoved { position, .. } => { winit::WindowEvent::CursorMoved { position, .. } => {
let pos = position.to_physical(self.device_hidpi_factor().get() as f64); let pos = position.to_physical(self.device_hidpi_factor().get() as f64);
let (x, y): (i32, i32) = pos.into(); let (x, y): (i32, i32) = pos.into();
self.mouse_pos.set(Point2D::new(x, y)); self.mouse_pos.set(Point2D::new(x, y));
@ -491,7 +398,7 @@ impl WindowPortsMethods for Window {
x as f32, y as f32, x as f32, y as f32,
))); )));
}, },
glutin::WindowEvent::MouseWheel { delta, phase, .. } => { winit::WindowEvent::MouseWheel { delta, phase, .. } => {
let (mut dx, mut dy, mode) = match delta { let (mut dx, mut dy, mode) = match delta {
MouseScrollDelta::LineDelta(dx, dy) => (dx as f64, (dy * LINE_HEIGHT) as f64, MouseScrollDelta::LineDelta(dx, dy) => (dx as f64, (dy * LINE_HEIGHT) as f64,
WheelMode::DeltaLine), WheelMode::DeltaLine),
@ -524,7 +431,7 @@ impl WindowPortsMethods for Window {
self.event_queue.borrow_mut().push(wheel_event); self.event_queue.borrow_mut().push(wheel_event);
self.event_queue.borrow_mut().push(scroll_event); self.event_queue.borrow_mut().push(scroll_event);
}, },
glutin::WindowEvent::Touch(touch) => { winit::WindowEvent::Touch(touch) => {
use servo::script_traits::TouchId; use servo::script_traits::TouchId;
let phase = winit_phase_to_touch_event_type(touch.phase); let phase = winit_phase_to_touch_event_type(touch.phase);
@ -537,19 +444,19 @@ impl WindowPortsMethods for Window {
.borrow_mut() .borrow_mut()
.push(WindowEvent::Touch(phase, id, point)); .push(WindowEvent::Touch(phase, id, point));
}, },
glutin::WindowEvent::Refresh => { winit::WindowEvent::Refresh => {
self.event_queue.borrow_mut().push(WindowEvent::Refresh); self.event_queue.borrow_mut().push(WindowEvent::Refresh);
}, },
glutin::WindowEvent::CloseRequested => { winit::WindowEvent::CloseRequested => {
self.event_queue.borrow_mut().push(WindowEvent::Quit); self.event_queue.borrow_mut().push(WindowEvent::Quit);
}, },
glutin::WindowEvent::Resized(size) => { winit::WindowEvent::Resized(size) => {
let physical_size = size.to_physical(self.device_hidpi_factor().get() as f64);
self.gl_context.borrow_mut().resize(physical_size);
// window.set_inner_size() takes DeviceIndependentPixel.
let (width, height) = size.into(); let (width, height) = size.into();
let new_size = Size2D::new(width, height); let new_size = Size2D::new(width, height);
if self.inner_size.get() != new_size { if self.inner_size.get() != new_size {
let physical_size = size.to_physical(self.device_hidpi_factor().get() as f64);
let physical_size = Size2D::new(physical_size.width, physical_size.height);
self.webrender_surfman.resize(physical_size.to_i32()).expect("Failed to resize");
self.inner_size.set(new_size); self.inner_size.set(new_size);
self.event_queue.borrow_mut().push(WindowEvent::Resize); self.event_queue.borrow_mut().push(WindowEvent::Resize);
} }
@ -557,75 +464,40 @@ impl WindowPortsMethods for Window {
_ => {}, _ => {},
} }
} }
}
impl webxr::glwindow::GlWindow for Window { fn new_glwindow(&self, events_loop: &EventsLoop) -> Box<dyn webxr::glwindow::GlWindow> {
fn make_current(&self) { let size = self.winit_window.get_outer_size()
debug!("Making window {:?} current", self.gl_context.borrow().window().id()); .expect("Failed to get window outer size");
self.gl_context.borrow_mut().make_current();
}
fn swap_buffers(&self) { let mut window_builder = winit::WindowBuilder::new()
debug!("Swapping buffers on window {:?}", self.gl_context.borrow().window().id()); .with_title("Servo XR".to_string())
self.gl_context.borrow().swap_buffers(); .with_dimensions(size)
self.gl_context.borrow_mut().make_not_current(); .with_visibility(true);
}
fn size(&self) -> UntypedSize2D<gl::GLsizei> { window_builder = builder_with_platform_options(window_builder);
let dpr = self.device_hidpi_factor().get() as f64;
let size = self
.gl_context
.borrow()
.window()
.get_inner_size()
.expect("Failed to get window inner size.");
let size = size.to_physical(dpr);
let (w, h): (u32, u32) = size.into();
Size2D::new(w as i32, h as i32)
}
fn get_rotation(&self) -> Rotation3D<f32, UnknownUnit, UnknownUnit> { let winit_window = window_builder.build(events_loop.as_winit())
self.xr_rotation.get().clone() .expect("Failed to create window.");
}
fn get_translation(&self) -> Vector3D<f32, UnknownUnit> { let pose = Rc::new(XRWindowPose {
self.xr_translation.get().clone() xr_rotation: Cell::new(Rotation3D::identity()),
} xr_translation: Cell::new(Vector3D::zero()),
});
fn new_window(&self) -> Result<Rc<dyn webxr::glwindow::GlWindow>, ()> { self.xr_window_poses.borrow_mut().push(pose.clone());
let window = Rc::new(Window::new( Box::new(XRWindow { winit_window, pose })
self.inner_size.get(),
Some(self),
self.events_loop.clone(),
self.angle,
self.enable_vsync,
self.use_msaa,
self.no_native_titlebar,
self.device_pixels_per_px,
));
app::register_window(window.clone());
Ok(window)
} }
} }
impl WindowMethods for Window { impl WindowMethods for Window {
fn gl(&self) -> Rc<dyn gl::Gl> {
self.gl.clone()
}
fn get_coordinates(&self) -> EmbedderCoordinates { fn get_coordinates(&self) -> EmbedderCoordinates {
// TODO(ajeffrey): can this fail? // TODO(ajeffrey): can this fail?
let dpr = self.device_hidpi_factor(); let dpr = self.device_hidpi_factor();
let LogicalSize { width, height } = self let LogicalSize { width, height } = self
.gl_context .winit_window
.borrow()
.window()
.get_outer_size() .get_outer_size()
.expect("Failed to get window outer size."); .expect("Failed to get window outer size.");
let LogicalPosition { x, y } = self let LogicalPosition { x, y } = self
.gl_context .winit_window
.borrow()
.window()
.get_position() .get_position()
.unwrap_or(LogicalPosition::new(0., 0.)); .unwrap_or(LogicalPosition::new(0., 0.));
let win_size = (Size2D::new(width as f32, height as f32) * dpr).to_i32(); let win_size = (Size2D::new(width as f32, height as f32) * dpr).to_i32();
@ -633,45 +505,58 @@ impl WindowMethods for Window {
let screen = (self.screen_size.to_f32() * dpr).to_i32(); let screen = (self.screen_size.to_f32() * dpr).to_i32();
let LogicalSize { width, height } = self let LogicalSize { width, height } = self
.gl_context .winit_window
.borrow()
.window()
.get_inner_size() .get_inner_size()
.expect("Failed to get window inner size."); .expect("Failed to get window inner size.");
let inner_size = (Size2D::new(width as f32, height as f32) * dpr).to_i32(); let inner_size = (Size2D::new(width as f32, height as f32) * dpr).to_i32();
let viewport = DeviceIntRect::new(Point2D::zero(), inner_size); let viewport = DeviceIntRect::new(Point2D::zero(), inner_size);
let framebuffer = DeviceIntSize::from_untyped(viewport.size.to_untyped()); let framebuffer = DeviceIntSize::from_untyped(viewport.size.to_untyped());
EmbedderCoordinates { EmbedderCoordinates {
viewport, viewport,
framebuffer, framebuffer,
window: (win_size, win_origin), window: (win_size, win_origin),
screen: screen, screen: screen,
// FIXME: Glutin doesn't have API for available size. Fallback to screen size // FIXME: Winit doesn't have API for available size. Fallback to screen size
screen_avail: screen, screen_avail: screen,
hidpi_factor: self.servo_hidpi_factor(), hidpi_factor: self.servo_hidpi_factor(),
} }
} }
fn present(&self) {
self.gl_context.borrow().swap_buffers();
self.gl_context.borrow_mut().make_not_current();
}
fn set_animation_state(&self, state: AnimationState) { fn set_animation_state(&self, state: AnimationState) {
self.animation_state.set(state); self.animation_state.set(state);
} }
fn make_gl_context_current(&self) { fn webrender_surfman(&self) -> WebrenderSurfman {
self.gl_context.borrow_mut().make_current(); self.webrender_surfman.clone()
} }
fn get_gl_context(&self) -> PlayerGLContext { fn get_gl_context(&self) -> PlayerGLContext {
if pref!(media.glvideo.enabled) { if !pref!(media.glvideo.enabled) {
return self.gl_context.borrow().raw_context(); return PlayerGLContext::Unknown;
} }
return PlayerGLContext::Unknown; #[allow(unused_variables)]
let native_context = self.webrender_surfman.native_context();
#[cfg(target_os = "windows")]
return PlayerGLContext::Egl(native_context.egl_context as usize);
#[cfg(target_os = "linux")]
return match native_context {
NativeContext::Default(NativeContext::Default(native_context)) =>
PlayerGLContext::Egl(native_context.egl_context as usize),
NativeContext::Default(NativeContext::Alternate(native_context)) =>
PlayerGLContext::Egl(native_context.egl_context as usize),
NativeContext::Alternate(_) => unimplemented!(),
};
// @TODO(victor): https://github.com/servo/media/pull/315
#[cfg(target_os = "macos")]
#[allow(unreachable_code)]
return unimplemented!();
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
return unimplemented!();
} }
fn get_native_display(&self) -> NativeDisplay { fn get_native_display(&self) -> NativeDisplay {
@ -679,48 +564,41 @@ impl WindowMethods for Window {
return NativeDisplay::Unknown; return NativeDisplay::Unknown;
} }
#[allow(unused_variables)]
let native_connection = self.webrender_surfman.connection().native_connection();
#[allow(unused_variables)]
let native_device = self.webrender_surfman.native_device();
#[cfg(target_os = "windows")]
return NativeDisplay::Egl(native_device.egl_display as usize);
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ return match native_connection {
if let Some(display) = self.gl_context.borrow().window().get_wayland_display() { NativeConnection::Default(NativeConnection::Default(conn)) =>
return NativeDisplay::Wayland(display as usize); NativeDisplay::Egl(conn.0 as usize),
} else if let Some(display) = NativeConnection::Default(NativeConnection::Alternate(conn)) =>
self.gl_context.borrow().window().get_xlib_display() NativeDisplay::X11(conn.x11_display as usize),
{ NativeConnection::Alternate(_) => unimplemented!(),
return NativeDisplay::X11(display as usize); };
}
}
#[cfg(any(target_os = "linux", target_os = "windows"))] // @TODO(victor): https://github.com/servo/media/pull/315
{ #[cfg(target_os = "macos")]
if let Some(display) = self.gl_context.borrow().egl_display() { #[allow(unreachable_code)]
return NativeDisplay::Egl(display as usize); return unimplemented!();
}
}
NativeDisplay::Unknown #[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
return unimplemented!();
} }
fn get_gl_api(&self) -> GlApi { fn get_gl_api(&self) -> GlApi {
let api = self.gl_context.borrow().get_api(); let api = self.webrender_surfman.connection().gl_api();
let attributes = self.webrender_surfman.context_attributes();
let version = self.gl.get_string(gl::VERSION); let GLVersion { major, minor } = attributes.version;
let version = version.trim_start_matches("OpenGL ES ");
let mut values = version.split(&['.', ' '][..]);
let major = values
.next()
.and_then(|v| v.parse::<u32>().ok())
.unwrap_or(1);
let minor = values
.next()
.and_then(|v| v.parse::<u32>().ok())
.unwrap_or(20);
match api { match api {
glutin::Api::OpenGl if major >= 3 && minor >= 2 => GlApi::OpenGL3, GLApi::GL if major >= 3 && minor >= 2 => GlApi::OpenGL3,
glutin::Api::OpenGl => GlApi::OpenGL, GLApi::GL => GlApi::OpenGL,
glutin::Api::OpenGlEs if major > 1 => GlApi::Gles2, GLApi::GLES if major > 1 => GlApi::Gles2,
glutin::Api::OpenGlEs => GlApi::Gles1, GLApi::GLES => GlApi::Gles1,
_ => GlApi::None,
} }
} }
} }
@ -748,3 +626,81 @@ fn load_icon(icon_bytes: &[u8]) -> Icon {
}; };
Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to load icon") Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to load icon")
} }
struct XRWindow {
winit_window: winit::Window,
pose: Rc<XRWindowPose>,
}
struct XRWindowPose {
xr_rotation: Cell<Rotation3D<f32, UnknownUnit, UnknownUnit>>,
xr_translation: Cell<Vector3D<f32, UnknownUnit>>,
}
impl webxr::glwindow::GlWindow for XRWindow {
fn get_native_widget(&self, device: &Device) -> NativeWidget {
device.connection()
.create_native_widget_from_winit_window(&self.winit_window)
.expect("Failed to create native widget")
}
fn get_rotation(&self) -> Rotation3D<f32, UnknownUnit, UnknownUnit> {
self.pose.xr_rotation.get().clone()
}
fn get_translation(&self) -> Vector3D<f32, UnknownUnit> {
self.pose.xr_translation.get().clone()
}
}
impl XRWindowPose {
fn handle_xr_translation(&self, input: &KeyboardEvent) {
if input.state != KeyState::Down {
return;
}
const NORMAL_TRANSLATE: f32 = 0.1;
const QUICK_TRANSLATE: f32 = 1.0;
let mut x = 0.0;
let mut z = 0.0;
match input.key {
Key::Character(ref k) => match &**k {
"w" => z = -NORMAL_TRANSLATE,
"W" => z = -QUICK_TRANSLATE,
"s" => z = NORMAL_TRANSLATE,
"S" => z = QUICK_TRANSLATE,
"a" => x = -NORMAL_TRANSLATE,
"A" => x = -QUICK_TRANSLATE,
"d" => x = NORMAL_TRANSLATE,
"D" => x = QUICK_TRANSLATE,
_ => return,
},
_ => return,
};
let (old_x, old_y, old_z) = self.xr_translation.get().to_tuple();
let vec = Vector3D::new(x + old_x, old_y, z + old_z);
self.xr_translation.set(vec);
}
fn handle_xr_rotation(&self, input: &KeyboardInput) {
if input.state != winit::ElementState::Pressed {
return;
}
let mut x = 0.0;
let mut y = 0.0;
match input.virtual_keycode {
Some(VirtualKeyCode::Up) => x = 1.0,
Some(VirtualKeyCode::Down) => x = -1.0,
Some(VirtualKeyCode::Left) => y = 1.0,
Some(VirtualKeyCode::Right) => y = -1.0,
_ => return,
};
if input.modifiers.shift {
x = 10.0 * x;
y = 10.0 * y;
}
let x: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::around_x(Angle::degrees(x));
let y: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::around_y(Angle::degrees(y));
let rotation = self.xr_rotation.get().post_rotate(&x).post_rotate(&y);
self.xr_rotation.set(rotation);
}
}

View file

@ -4,93 +4,28 @@
//! A headless window implementation. //! A headless window implementation.
use crate::events_loop::EventsLoop;
use crate::window_trait::WindowPortsMethods; use crate::window_trait::WindowPortsMethods;
use euclid::{default::Size2D as UntypedSize2D, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector3D}; use euclid::{Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector3D};
use gleam::gl; use winit;
use glutin;
use servo::compositing::windowing::{AnimationState, WindowEvent}; use servo::compositing::windowing::{AnimationState, WindowEvent};
use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods}; use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods};
use servo::servo_geometry::DeviceIndependentPixel; use servo::servo_geometry::DeviceIndependentPixel;
use servo::style_traits::DevicePixel; use servo::style_traits::DevicePixel;
use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize}; use servo::webrender_api::units::DeviceIntRect;
use servo_media::player::context as MediaPlayerCtxt; use servo_media::player::context as MediaPlayerCtxt;
use servo::webrender_surfman::WebrenderSurfman;
use std::cell::Cell; use std::cell::Cell;
#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::cell::RefCell;
#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::ffi::CString;
#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::mem;
use std::os::raw::c_void;
use std::ptr;
use std::rc::Rc; use std::rc::Rc;
use surfman::Connection;
#[cfg(any(target_os = "linux", target_os = "macos"))] use surfman::Device;
struct HeadlessContext { use surfman::NativeWidget;
width: u32, use surfman::SurfaceType;
height: u32,
context: osmesa_sys::OSMesaContext,
buffer: RefCell<Vec<u32>>,
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
struct HeadlessContext {
width: u32,
height: u32,
}
impl HeadlessContext {
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn new(width: u32, height: u32, share: Option<&HeadlessContext>) -> HeadlessContext {
let mut attribs = Vec::new();
attribs.push(osmesa_sys::OSMESA_PROFILE);
attribs.push(osmesa_sys::OSMESA_CORE_PROFILE);
attribs.push(osmesa_sys::OSMESA_CONTEXT_MAJOR_VERSION);
attribs.push(3);
attribs.push(osmesa_sys::OSMESA_CONTEXT_MINOR_VERSION);
attribs.push(3);
attribs.push(0);
let share = share.map_or(ptr::null_mut(), |share| share.context as *mut _);
let context = unsafe { osmesa_sys::OSMesaCreateContextAttribs(attribs.as_ptr(), share) };
assert!(!context.is_null());
HeadlessContext {
width: width,
height: height,
context: context,
buffer: RefCell::new(vec![0; (width * height) as usize]),
}
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn new(width: u32, height: u32, _share: Option<&HeadlessContext>) -> HeadlessContext {
HeadlessContext {
width: width,
height: height,
}
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn get_proc_address(s: &str) -> *const c_void {
let c_str = CString::new(s).expect("Unable to create CString");
unsafe { mem::transmute(osmesa_sys::OSMesaGetProcAddress(c_str.as_ptr())) }
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn get_proc_address(_: &str) -> *const c_void {
ptr::null() as *const _
}
}
pub struct Window { pub struct Window {
context: HeadlessContext, webrender_surfman: WebrenderSurfman,
animation_state: Cell<AnimationState>, animation_state: Cell<AnimationState>,
fullscreen: Cell<bool>, fullscreen: Cell<bool>,
gl: Rc<dyn gl::Gl>,
device_pixels_per_px: Option<f32>, device_pixels_per_px: Option<f32>,
} }
@ -99,18 +34,19 @@ impl Window {
size: Size2D<u32, DeviceIndependentPixel>, size: Size2D<u32, DeviceIndependentPixel>,
device_pixels_per_px: Option<f32>, device_pixels_per_px: Option<f32>,
) -> Rc<dyn WindowPortsMethods> { ) -> Rc<dyn WindowPortsMethods> {
let context = HeadlessContext::new(size.width, size.height, None); // Initialize surfman
let gl = unsafe { gl::GlFns::load_with(|s| HeadlessContext::get_proc_address(s)) }; let connection = Connection::new().expect("Failed to create connection");
let adapter = connection.create_software_adapter().expect("Failed to create adapter");
// Print some information about the headless renderer that let size = size.to_untyped().to_i32();
// can be useful in diagnosing CI failures on build machines. let surface_type = SurfaceType::Generic { size };
println!("{}", gl.get_string(gl::VENDOR)); let webrender_surfman = WebrenderSurfman::create(
println!("{}", gl.get_string(gl::RENDERER)); &connection,
println!("{}", gl.get_string(gl::VERSION)); &adapter,
surface_type,
).expect("Failed to create WR surfman");
let window = Window { let window = Window {
context, webrender_surfman,
gl,
animation_state: Cell::new(AnimationState::Idle), animation_state: Cell::new(AnimationState::Idle),
fullscreen: Cell::new(false), fullscreen: Cell::new(false),
device_pixels_per_px, device_pixels_per_px,
@ -136,13 +72,18 @@ impl WindowPortsMethods for Window {
false false
} }
fn id(&self) -> glutin::WindowId { fn id(&self) -> winit::WindowId {
unsafe { glutin::WindowId::dummy() } unsafe { winit::WindowId::dummy() }
} }
fn page_height(&self) -> f32 { fn page_height(&self) -> f32 {
let height = self.webrender_surfman
.context_surface_info()
.unwrap_or(None)
.map(|info| info.size.height)
.unwrap_or(0);
let dpr = self.servo_hidpi_factor(); let dpr = self.servo_hidpi_factor();
self.context.height as f32 * dpr.get() height as f32 * dpr.get()
} }
fn set_fullscreen(&self, state: bool) { fn set_fullscreen(&self, state: bool) {
@ -157,24 +98,27 @@ impl WindowPortsMethods for Window {
self.animation_state.get() == AnimationState::Animating self.animation_state.get() == AnimationState::Animating
} }
fn winit_event_to_servo_event(&self, _event: glutin::WindowEvent) { fn winit_event_to_servo_event(&self, _event: winit::WindowEvent) {
// Not expecting any winit events. // Not expecting any winit events.
} }
fn new_glwindow(&self, _events_loop: &EventsLoop) -> Box<dyn webxr::glwindow::GlWindow> {
unimplemented!()
}
} }
impl WindowMethods for Window { impl WindowMethods for Window {
fn gl(&self) -> Rc<dyn gl::Gl> { fn get_coordinates(&self) -> EmbedderCoordinates {
self.gl.clone()
}
fn get_coordinates(&self) -> EmbedderCoordinates {
let dpr = self.servo_hidpi_factor(); let dpr = self.servo_hidpi_factor();
let size = (Size2D::new(self.context.width, self.context.height).to_f32() * dpr).to_i32(); let size = self.webrender_surfman
.context_surface_info()
.unwrap_or(None)
.map(|info| Size2D::from_untyped(info.size))
.unwrap_or(Size2D::new(0, 0));
let viewport = DeviceIntRect::new(Point2D::zero(), size); let viewport = DeviceIntRect::new(Point2D::zero(), size);
let framebuffer = DeviceIntSize::from_untyped(size.to_untyped());
EmbedderCoordinates { EmbedderCoordinates {
viewport, viewport,
framebuffer, framebuffer: size,
window: (size, Point2D::zero()), window: (size, Point2D::zero()),
screen: size, screen: size,
screen_avail: size, screen_avail: size,
@ -182,31 +126,11 @@ impl WindowMethods for Window {
} }
} }
fn present(&self) {} fn set_animation_state(&self, state: AnimationState) {
fn set_animation_state(&self, state: AnimationState) {
self.animation_state.set(state); self.animation_state.set(state);
} }
#[cfg(any(target_os = "linux", target_os = "macos"))] fn get_gl_context(&self) -> MediaPlayerCtxt::GlContext {
fn make_gl_context_current(&self) {
unsafe {
let mut buffer = self.context.buffer.borrow_mut();
let ret = osmesa_sys::OSMesaMakeCurrent(
self.context.context,
buffer.as_mut_ptr() as *mut _,
gl::UNSIGNED_BYTE,
self.context.width as i32,
self.context.height as i32,
);
assert_ne!(ret, 0);
};
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn make_gl_context_current(&self) {}
fn get_gl_context(&self) -> MediaPlayerCtxt::GlContext {
MediaPlayerCtxt::GlContext::Unknown MediaPlayerCtxt::GlContext::Unknown
} }
@ -217,32 +141,17 @@ impl WindowMethods for Window {
fn get_gl_api(&self) -> MediaPlayerCtxt::GlApi { fn get_gl_api(&self) -> MediaPlayerCtxt::GlApi {
MediaPlayerCtxt::GlApi::None MediaPlayerCtxt::GlApi::None
} }
fn webrender_surfman(&self) -> WebrenderSurfman {
self.webrender_surfman.clone()
}
} }
impl webxr::glwindow::GlWindow for Window { impl webxr::glwindow::GlWindow for Window {
fn make_current(&self) {} fn get_native_widget(&self, _device: &Device) -> NativeWidget {
fn swap_buffers(&self) {} unimplemented!()
fn size(&self) -> UntypedSize2D<gl::GLsizei> {
let dpr = self.servo_hidpi_factor().get();
Size2D::new(
(self.context.width as f32 * dpr) as gl::GLsizei,
(self.context.height as f32 * dpr) as gl::GLsizei,
)
}
fn new_window(&self) -> Result<Rc<dyn webxr::glwindow::GlWindow>, ()> {
let width = self.context.width;
let height = self.context.height;
let share = Some(&self.context);
let context = HeadlessContext::new(width, height, share);
let gl = self.gl.clone();
Ok(Rc::new(Window {
context,
gl,
animation_state: Cell::new(AnimationState::Idle),
fullscreen: Cell::new(false),
device_pixels_per_px: self.device_pixels_per_px,
}))
} }
fn get_rotation(&self) -> Rotation3D<f32, UnknownUnit, UnknownUnit> { fn get_rotation(&self) -> Rotation3D<f32, UnknownUnit, UnknownUnit> {
Rotation3D::identity() Rotation3D::identity()
} }

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use glutin::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode}; use winit::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode};
use keyboard_types::{Code, Key, KeyState, KeyboardEvent, Location, Modifiers}; use keyboard_types::{Code, Key, KeyState, KeyboardEvent, Location, Modifiers};
// Some shortcuts use Cmd on Mac and Control on other systems. // Some shortcuts use Cmd on Mac and Control on other systems.
@ -18,7 +18,7 @@ pub const CMD_OR_ALT: Modifiers = Modifiers::META;
pub const CMD_OR_ALT: Modifiers = Modifiers::ALT; pub const CMD_OR_ALT: Modifiers = Modifiers::ALT;
fn get_servo_key_from_winit_key(key: Option<VirtualKeyCode>) -> Key { fn get_servo_key_from_winit_key(key: Option<VirtualKeyCode>) -> Key {
use glutin::VirtualKeyCode::*; use winit::VirtualKeyCode::*;
// TODO: figure out how to map NavigateForward, NavigateBackward // TODO: figure out how to map NavigateForward, NavigateBackward
// TODO: map the remaining keys if possible // TODO: map the remaining keys if possible
let key = if let Some(key) = key { let key = if let Some(key) = key {
@ -127,7 +127,7 @@ fn get_servo_key_from_winit_key(key: Option<VirtualKeyCode>) -> Key {
} }
fn get_servo_location_from_winit_key(key: Option<VirtualKeyCode>) -> Location { fn get_servo_location_from_winit_key(key: Option<VirtualKeyCode>) -> Location {
use glutin::VirtualKeyCode::*; use winit::VirtualKeyCode::*;
// TODO: add more numpad keys // TODO: add more numpad keys
let key = if let Some(key) = key { let key = if let Some(key) = key {
key key

View file

@ -13,7 +13,6 @@ extern crate sig;
mod app; mod app;
mod backtrace; mod backtrace;
mod browser; mod browser;
mod context;
mod embedder; mod embedder;
mod events_loop; mod events_loop;
mod headed_window; mod headed_window;
@ -95,12 +94,6 @@ pub fn main() {
"clean-shutdown", "clean-shutdown",
"Do not shutdown until all threads have finished (macos only)", "Do not shutdown until all threads have finished (macos only)",
); );
opts.optflag(
"",
"disable-vsync",
"Disable vsync mode in the compositor to allow profiling at more than monitor refresh rate",
);
opts.optflag("", "msaa", "Use multisample antialiasing in WebRender.");
opts.optflag("b", "no-native-titlebar", "Do not use native titlebar"); opts.optflag("b", "no-native-titlebar", "Do not use native titlebar");
opts.optopt("", "device-pixel-ratio", "Device pixels per px", ""); opts.optopt("", "device-pixel-ratio", "Device pixels per px", "");
opts.optopt( opts.optopt(
@ -170,28 +163,19 @@ pub fn main() {
process::exit(0); process::exit(0);
} }
let angle = opts_matches.opt_present("angle");
let clean_shutdown = opts_matches.opt_present("clean-shutdown"); let clean_shutdown = opts_matches.opt_present("clean-shutdown");
let do_not_use_native_titlebar = let do_not_use_native_titlebar =
opts_matches.opt_present("no-native-titlebar") || !(pref!(shell.native_titlebar.enabled)); opts_matches.opt_present("no-native-titlebar") || !(pref!(shell.native_titlebar.enabled));
let enable_vsync = !opts_matches.opt_present("disable-vsync");
let use_msaa = opts_matches.opt_present("msaa");
let device_pixels_per_px = opts_matches.opt_str("device-pixel-ratio").map(|dppx_str| { let device_pixels_per_px = opts_matches.opt_str("device-pixel-ratio").map(|dppx_str| {
dppx_str.parse().unwrap_or_else(|err| { dppx_str.parse().unwrap_or_else(|err| {
error!("Error parsing option: --device-pixel-ratio ({})", err); error!("Error parsing option: --device-pixel-ratio ({})", err);
process::exit(1); process::exit(1);
}) })
}); });
let user_agent = opts_matches.opt_str("u"); let user_agent = opts_matches.opt_str("u");
App::run( App::run(do_not_use_native_titlebar, device_pixels_per_px, user_agent);
angle,
enable_vsync,
use_msaa,
do_not_use_native_titlebar,
device_pixels_per_px,
user_agent,
);
platform::deinit(clean_shutdown) platform::deinit(clean_shutdown)
} }

View file

@ -5,7 +5,8 @@
//! Definition of Window. //! Definition of Window.
//! Implemented by headless and headed windows. //! Implemented by headless and headed windows.
use glutin; use crate::events_loop::EventsLoop;
use winit;
use servo::compositing::windowing::{WindowEvent, WindowMethods}; use servo::compositing::windowing::{WindowEvent, WindowMethods};
use servo::embedder_traits::Cursor; use servo::embedder_traits::Cursor;
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize}; use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize};
@ -13,17 +14,18 @@ use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize};
// This should vary by zoom level and maybe actual text size (focused or under cursor) // This should vary by zoom level and maybe actual text size (focused or under cursor)
pub const LINE_HEIGHT: f32 = 38.0; pub const LINE_HEIGHT: f32 = 38.0;
pub trait WindowPortsMethods: WindowMethods + webxr::glwindow::GlWindow { pub trait WindowPortsMethods: WindowMethods {
fn get_events(&self) -> Vec<WindowEvent>; fn get_events(&self) -> Vec<WindowEvent>;
fn id(&self) -> glutin::WindowId; fn id(&self) -> winit::WindowId;
fn has_events(&self) -> bool; fn has_events(&self) -> bool;
fn page_height(&self) -> f32; fn page_height(&self) -> f32;
fn get_fullscreen(&self) -> bool; fn get_fullscreen(&self) -> bool;
fn winit_event_to_servo_event(&self, event: glutin::WindowEvent); fn winit_event_to_servo_event(&self, event: winit::WindowEvent);
fn is_animating(&self) -> bool; fn is_animating(&self) -> bool;
fn set_title(&self, _title: &str) {} fn set_title(&self, _title: &str) {}
fn set_inner_size(&self, _size: DeviceIntSize) {} fn set_inner_size(&self, _size: DeviceIntSize) {}
fn set_position(&self, _point: DeviceIntPoint) {} fn set_position(&self, _point: DeviceIntPoint) {}
fn set_fullscreen(&self, _state: bool) {} fn set_fullscreen(&self, _state: bool) {}
fn set_cursor(&self, _cursor: Cursor) {} fn set_cursor(&self, _cursor: Cursor) {}
fn new_glwindow(&self, events_loop: &EventsLoop) -> Box<dyn webxr::glwindow::GlWindow>;
} }

View file

@ -30,9 +30,9 @@ lazy_static = "1.4"
libservo = {path = "../../components/servo"} libservo = {path = "../../components/servo"}
servo-media = {git = "https://github.com/servo/media"} servo-media = {git = "https://github.com/servo/media"}
sparkle = "0.1" sparkle = "0.1"
surfman = { git = "https://github.com/pcwalton/surfman", branch = "multi" } surfman = { git = "https://github.com/servo/surfman" }
surfman-chains-api = "0.2" surfman-chains-api = "0.2"
surfman-chains = { git = "https://github.com/asajeffrey/surfman-chains", branch = "multi" } surfman-chains = { git = "https://github.com/asajeffrey/surfman-chains" }
[build-dependencies] [build-dependencies]
gst-plugin-version-helper = "0.1" gst-plugin-version-helper = "0.1"

View file

@ -76,35 +76,20 @@ use servo::embedder_traits::EventLoopWaker;
use servo::msg::constellation_msg::TopLevelBrowsingContextId; use servo::msg::constellation_msg::TopLevelBrowsingContextId;
use servo::servo_url::ServoUrl; use servo::servo_url::ServoUrl;
use servo::webrender_api::units::DevicePixel; use servo::webrender_api::units::DevicePixel;
use servo::webrender_surfman::WebrenderSurfman;
use servo::Servo; use servo::Servo;
use sparkle::gl; use sparkle::gl;
use sparkle::gl::types::GLuint; use sparkle::gl::types::GLuint;
use sparkle::gl::Gl; use sparkle::gl::Gl;
use surfman::connection::Connection as ConnectionAPI; use surfman::Connection;
use surfman::device::Device as DeviceAPI; use surfman::Context;
use surfman::ContextAttributeFlags; use surfman::Device;
use surfman::ContextAttributes;
use surfman::GLApi;
use surfman::GLVersion;
use surfman::SurfaceAccess;
use surfman::SurfaceType; use surfman::SurfaceType;
use surfman_chains::SurfmanProvider;
use surfman_chains::SwapChain; use surfman_chains::SwapChain;
use surfman_chains_api::SwapChainAPI; use surfman_chains_api::SwapChainAPI;
// For the moment, we only support wayland and cgl.
#[cfg(target_os = "macos")]
use surfman::platform::macos::cgl::device::Device;
#[cfg(all(unix, not(target_os = "macos")))]
use surfman::platform::unix::wayland::device::Device;
type Context = <Device as DeviceAPI>::Context;
type Connection = <Device as DeviceAPI>::Connection;
type NativeContext = <Device as DeviceAPI>::NativeContext;
type NativeConnection = <Connection as ConnectionAPI>::NativeConnection;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryFrom; use std::convert::TryFrom;
@ -165,7 +150,7 @@ impl std::fmt::Debug for ConnectionWhichImplementsDebug {
#[derive(Debug)] #[derive(Debug)]
enum ServoWebSrcMsg { enum ServoWebSrcMsg {
Start(ConnectionWhichImplementsDebug, GLVersion, ServoUrl), Start(ConnectionWhichImplementsDebug, ServoUrl),
GetSwapChain(Sender<SwapChain<Device>>), GetSwapChain(Sender<SwapChain<Device>>),
Resize(Size2D<i32, DevicePixel>), Resize(Size2D<i32, DevicePixel>),
Heartbeat, Heartbeat,
@ -180,41 +165,25 @@ const DEFAULT_FRAME_DURATION: Duration = Duration::from_micros(16_667);
struct ServoThread { struct ServoThread {
receiver: Receiver<ServoWebSrcMsg>, receiver: Receiver<ServoWebSrcMsg>,
swap_chain: SwapChain<Device>,
gfx: Rc<RefCell<ServoThreadGfx>>,
servo: Servo<ServoWebSrcWindow>, servo: Servo<ServoWebSrcWindow>,
} }
struct ServoThreadGfx {
device: Device,
context: Context,
gl: Rc<Gl>,
}
impl ServoThread { impl ServoThread {
fn new(receiver: Receiver<ServoWebSrcMsg>) -> Self { fn new(receiver: Receiver<ServoWebSrcMsg>) -> Self {
let (connection, version, url) = match receiver.recv() { let (connection, url) = match receiver.recv() {
Ok(ServoWebSrcMsg::Start(connection, version, url)) => (connection.0, version, url), Ok(ServoWebSrcMsg::Start(connection, url)) => (connection.0, url),
e => panic!("Failed to start ({:?})", e), e => panic!("Failed to start ({:?})", e),
}; };
info!( info!("Created new servo thread for {}", url);
"Created new servo thread (GL v{}.{} for {})",
version.major, version.minor, url
);
let embedder = Box::new(ServoWebSrcEmbedder); let embedder = Box::new(ServoWebSrcEmbedder);
let window = Rc::new(ServoWebSrcWindow::new(connection, version)); let window = Rc::new(ServoWebSrcWindow::new(connection));
let swap_chain = window.swap_chain.clone();
let gfx = window.gfx.clone();
let mut servo = Servo::new(embedder, window, None); let mut servo = Servo::new(embedder, window, None);
let id = TopLevelBrowsingContextId::new(); let id = TopLevelBrowsingContextId::new();
servo.handle_events(vec![WindowEvent::NewBrowser(url, id)]); servo.handle_events(vec![WindowEvent::NewBrowser(url, id)]);
Self { Self { receiver, servo }
receiver,
swap_chain,
gfx,
servo,
}
} }
fn run(&mut self) { fn run(&mut self) {
@ -222,9 +191,7 @@ impl ServoThread {
debug!("Servo thread handling message {:?}", msg); debug!("Servo thread handling message {:?}", msg);
match msg { match msg {
ServoWebSrcMsg::Start(..) => error!("Already started"), ServoWebSrcMsg::Start(..) => error!("Already started"),
ServoWebSrcMsg::GetSwapChain(sender) => sender ServoWebSrcMsg::GetSwapChain(sender) => self.send_swap_chain(sender),
.send(self.swap_chain.clone())
.expect("Failed to send swap chain"),
ServoWebSrcMsg::Resize(size) => self.resize(size), ServoWebSrcMsg::Resize(size) => self.resize(size),
ServoWebSrcMsg::Heartbeat => self.servo.handle_events(vec![]), ServoWebSrcMsg::Heartbeat => self.servo.handle_events(vec![]),
ServoWebSrcMsg::Stop => break, ServoWebSrcMsg::Stop => break,
@ -233,43 +200,24 @@ impl ServoThread {
self.servo.handle_events(vec![WindowEvent::Quit]); self.servo.handle_events(vec![WindowEvent::Quit]);
} }
fn resize(&mut self, size: Size2D<i32, DevicePixel>) { fn send_swap_chain(&mut self, sender: Sender<SwapChain<Device>>) {
{ let swap_chain = self
let mut gfx = self.gfx.borrow_mut(); .servo
let gfx = &mut *gfx; .window()
self.swap_chain .webrender_surfman
.resize(&mut gfx.device, &mut gfx.context, size.to_untyped()) .swap_chain()
.expect("Failed to resize"); .expect("Failed to get swap chain")
gfx.gl.viewport(0, 0, size.width, size.height); .clone();
let fbo = gfx sender.send(swap_chain).expect("Failed to send swap chain");
.device
.context_surface_info(&gfx.context)
.expect("Failed to get context info")
.expect("Failed to get context info")
.framebuffer_object;
gfx.device
.make_context_current(&gfx.context)
.expect("Failed to make current");
gfx.gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
debug_assert_eq!(
(
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
gfx.gl.get_error()
),
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
);
}
self.servo.handle_events(vec![WindowEvent::Resize]);
} }
}
impl Drop for ServoThread { fn resize(&mut self, size: Size2D<i32, DevicePixel>) {
fn drop(&mut self) { let _ = self
let mut gfx = self.gfx.borrow_mut(); .servo
let gfx = &mut *gfx; .window()
self.swap_chain .webrender_surfman
.destroy(&mut gfx.device, &mut gfx.context) .resize(size.to_untyped());
.expect("Failed to destroy swap chain") self.servo.handle_events(vec![WindowEvent::Resize]);
} }
} }
@ -290,154 +238,35 @@ impl EventLoopWaker for ServoWebSrcEmbedder {
} }
struct ServoWebSrcWindow { struct ServoWebSrcWindow {
swap_chain: SwapChain<Device>, webrender_surfman: WebrenderSurfman,
gfx: Rc<RefCell<ServoThreadGfx>>,
gl: Rc<dyn gleam::gl::Gl>,
} }
impl ServoWebSrcWindow { impl ServoWebSrcWindow {
fn new(connection: Connection, version: GLVersion) -> Self { fn new(connection: Connection) -> Self {
let flags = ContextAttributeFlags::DEPTH |
ContextAttributeFlags::STENCIL |
ContextAttributeFlags::ALPHA;
let attributes = ContextAttributes { version, flags };
let adapter = connection let adapter = connection
.create_adapter() .create_adapter()
.expect("Failed to create adapter"); .expect("Failed to create adapter");
let mut device = connection
.create_device(&adapter)
.expect("Failed to create device");
let descriptor = device
.create_context_descriptor(&attributes)
.expect("Failed to create descriptor");
let mut context = device
.create_context(&descriptor)
.expect("Failed to create context");
let (gleam, gl) = unsafe {
match device.gl_api() {
GLApi::GL => (
gleam::gl::GlFns::load_with(|s| device.get_proc_address(&context, s)),
Gl::gl_fns(gl::ffi_gl::Gl::load_with(|s| {
device.get_proc_address(&context, s)
})),
),
GLApi::GLES => (
gleam::gl::GlesFns::load_with(|s| device.get_proc_address(&context, s)),
Gl::gles_fns(gl::ffi_gles::Gles2::load_with(|s| {
device.get_proc_address(&context, s)
})),
),
}
};
device
.make_context_current(&mut context)
.expect("Failed to make context current");
debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
let access = SurfaceAccess::GPUOnly;
let size = Size2D::new(512, 512); let size = Size2D::new(512, 512);
let surface_type = SurfaceType::Generic { size }; let surface_type = SurfaceType::Generic { size };
let surface = device let webrender_surfman = WebrenderSurfman::create(&connection, &adapter, surface_type)
.create_surface(&mut context, access, surface_type) .expect("Failed to create surfman");
.expect("Failed to create surface");
device Self { webrender_surfman }
.bind_surface_to_context(&mut context, surface)
.expect("Failed to bind surface");
let fbo = device
.context_surface_info(&context)
.expect("Failed to get context info")
.expect("Failed to get context info")
.framebuffer_object;
gl.viewport(0, 0, size.width, size.height);
gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
gl.clear_color(0.0, 0.0, 0.0, 1.0);
gl.clear(gl::COLOR_BUFFER_BIT);
debug_assert_eq!(
(gl.check_framebuffer_status(gl::FRAMEBUFFER), gl.get_error()),
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
);
let provider = Box::new(SurfmanProvider::new(access));
let swap_chain = SwapChain::create_attached(&mut device, &mut context, provider)
.expect("Failed to create swap chain");
device.make_no_context_current().unwrap();
let gfx = Rc::new(RefCell::new(ServoThreadGfx {
device,
context,
gl,
}));
Self {
swap_chain,
gfx,
gl: gleam,
}
} }
} }
impl WindowMethods for ServoWebSrcWindow { impl WindowMethods for ServoWebSrcWindow {
fn present(&self) { fn webrender_surfman(&self) -> WebrenderSurfman {
debug!("EMBEDDER present"); self.webrender_surfman.clone()
let mut gfx = self.gfx.borrow_mut();
let gfx = &mut *gfx;
gfx.device
.make_context_current(&mut gfx.context)
.expect("Failed to make context current");
debug_assert_eq!(
(
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
gfx.gl.get_error()
),
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
);
self.swap_chain
.swap_buffers(&mut gfx.device, &mut gfx.context)
.expect("Failed to swap buffers");
let fbo = gfx
.device
.context_surface_info(&gfx.context)
.expect("Failed to get context info")
.expect("Failed to get context info")
.framebuffer_object;
gfx.gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
debug_assert_eq!(
(
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
gfx.gl.get_error()
),
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
);
let _ = gfx.device.make_no_context_current();
}
fn make_gl_context_current(&self) {
debug!("EMBEDDER make_context_current");
let mut gfx = self.gfx.borrow_mut();
let gfx = &mut *gfx;
gfx.device
.make_context_current(&mut gfx.context)
.expect("Failed to make context current");
debug!("EMBEDDER done make_context_current");
debug_assert_eq!(
(
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
gfx.gl.get_error()
),
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
);
}
fn gl(&self) -> Rc<dyn gleam::gl::Gl> {
self.gl.clone()
} }
fn get_coordinates(&self) -> EmbedderCoordinates { fn get_coordinates(&self) -> EmbedderCoordinates {
let size = Size2D::from_untyped(self.swap_chain.size()); let size = self
.webrender_surfman
.context_surface_info()
.unwrap_or(None)
.map(|info| Size2D::from_untyped(info.size))
.unwrap_or(Size2D::new(0, 0));
info!("EMBEDDER coordinates {}", size); info!("EMBEDDER coordinates {}", size);
let origin = Point2D::origin(); let origin = Point2D::origin();
EmbedderCoordinates { EmbedderCoordinates {
@ -658,11 +487,6 @@ impl BaseSrcImpl for ServoWebSrc {
)); ));
} }
let gl_context = unsafe { GLContext::from_glib_borrow(gst_gl_context) }; let gl_context = unsafe { GLContext::from_glib_borrow(gst_gl_context) };
let gl_version = gl_context.get_gl_version();
let version = GLVersion {
major: gl_version.0 as u8,
minor: gl_version.1 as u8,
};
// Get the surfman connection on the GL thread // Get the surfman connection on the GL thread
let mut task = BootstrapSurfmanOnGLThread { let mut task = BootstrapSurfmanOnGLThread {
@ -683,7 +507,6 @@ impl BaseSrcImpl for ServoWebSrc {
// Inform servo we're starting // Inform servo we're starting
let _ = self.sender.send(ServoWebSrcMsg::Start( let _ = self.sender.send(ServoWebSrcMsg::Start(
ConnectionWhichImplementsDebug(connection), ConnectionWhichImplementsDebug(connection),
version,
url, url,
)); ));
Ok(()) Ok(())
@ -784,11 +607,32 @@ impl ServoWebSrc {
gl_context gl_context
.activate(true) .activate(true)
.expect("Failed to activate GL context"); .expect("Failed to activate GL context");
let native_connection = // TODO: support other connections on linux?
NativeConnection::current().expect("Failed to bootstrap native connection"); #[cfg(target_os = "linux")]
let connection = unsafe { Connection::from_native_connection(native_connection) } {
.expect("Failed to bootstrap surfman connection"); use surfman::platform::generic::multi;
Some(connection) use surfman::platform::unix::wayland;
let native_connection = wayland::connection::NativeConnection::current()
.expect("Failed to bootstrap native connection");
let wayland_connection = unsafe {
wayland::connection::Connection::from_native_connection(native_connection)
.expect("Failed to bootstrap wayland connection")
};
let connection = multi::connection::Connection::Default(
multi::connection::Connection::Default(wayland_connection),
);
Some(connection)
}
#[cfg(not(target_os = "linux"))]
{
use surfman::connection::Connection as ConnectionAPI;
type NativeConnection = <Connection as ConnectionAPI>::NativeConnection;
let native_connection =
NativeConnection::current().expect("Failed to bootstrap native connection");
let connection = unsafe { Connection::from_native_connection(native_connection) }
.expect("Failed to bootstrap surfman connection");
Some(connection)
}
} }
} }
@ -840,8 +684,21 @@ impl ServoWebSrc {
let device = connection let device = connection
.create_device(&adapter) .create_device(&adapter)
.expect("Failed to bootstrap surfman device"); .expect("Failed to bootstrap surfman device");
let native_context = #[cfg(target_os = "linux")]
NativeContext::current().expect("Failed to bootstrap native context"); let native_context = {
use surfman::platform::generic::multi;
use surfman::platform::unix::wayland;
multi::context::NativeContext::Default(multi::context::NativeContext::Default(
wayland::context::NativeContext::current()
.expect("Failed to bootstrap native context"),
))
};
#[cfg(not(target_os = "linux"))]
let native_context = {
use surfman::device::Device as DeviceAPI;
type NativeContext = <Device as DeviceAPI>::NativeContext;
NativeContext::current().expect("Failed to bootstrap native context")
};
let context = unsafe { let context = unsafe {
device device
.create_context_from_native_context(native_context) .create_context_from_native_context(native_context)
@ -995,5 +852,3 @@ impl ServoWebSrc {
Ok(()) Ok(())
} }
} }
// TODO: Implement that trait for more platforms

View file

@ -12,6 +12,7 @@ ipc-channel = "0.14"
libservo = { path = "../../../components/servo" } libservo = { path = "../../../components/servo" }
log = "0.4" log = "0.4"
servo-media = { git = "https://github.com/servo/media" } servo-media = { git = "https://github.com/servo/media" }
surfman = { version = "0.2", features = ["sm-angle-default"] }
webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] } webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] }
webxr = { git = "https://github.com/servo/webxr"} webxr = { git = "https://github.com/servo/webxr"}

View file

@ -32,6 +32,7 @@ use servo::servo_config::{pref, set_pref};
use servo::servo_url::ServoUrl; use servo::servo_url::ServoUrl;
use servo::webrender_api::units::DevicePixel; use servo::webrender_api::units::DevicePixel;
use servo::webrender_api::ScrollLocation; use servo::webrender_api::ScrollLocation;
use servo::webrender_surfman::WebrenderSurfman;
use servo::{self, gl, BrowserId, Servo}; use servo::{self, gl, BrowserId, Servo};
use servo_media::player::context as MediaPlayerContext; use servo_media::player::context as MediaPlayerContext;
use std::cell::RefCell; use std::cell::RefCell;
@ -39,6 +40,8 @@ use std::mem;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use surfman::Connection;
use surfman::SurfaceType;
thread_local! { thread_local! {
pub static SERVO: RefCell<Option<ServoGlue>> = RefCell::new(None); pub static SERVO: RefCell<Option<ServoGlue>> = RefCell::new(None);
@ -58,6 +61,7 @@ pub struct InitOptions {
pub enable_subpixel_text_antialiasing: bool, pub enable_subpixel_text_antialiasing: bool,
pub gl_context_pointer: Option<*const c_void>, pub gl_context_pointer: Option<*const c_void>,
pub native_display_pointer: Option<*const c_void>, pub native_display_pointer: Option<*const c_void>,
pub native_widget: *mut c_void,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -84,12 +88,6 @@ impl Coordinates {
/// Callbacks. Implemented by embedder. Called by Servo. /// Callbacks. Implemented by embedder. Called by Servo.
pub trait HostTrait { pub trait HostTrait {
/// Will be called from the thread used for the init call.
/// Will be called when the GL buffer has been updated.
fn flush(&self);
/// Will be called before drawing.
/// Time to make the targetted GL context current.
fn make_current(&self);
/// Show alert. /// Show alert.
fn prompt_alert(&self, msg: String, trusted: bool); fn prompt_alert(&self, msg: String, trusted: bool);
/// Ask Yes/No question. /// Ask Yes/No question.
@ -211,13 +209,28 @@ pub fn init(
gl.clear(gl::COLOR_BUFFER_BIT); gl.clear(gl::COLOR_BUFFER_BIT);
gl.finish(); gl.finish();
// Initialize surfman
let connection = Connection::new().or(Err("Failed to create connection"))?;
let adapter = connection
.create_adapter()
.or(Err("Failed to create adapter"))?;
let native_widget = unsafe {
connection.create_native_widget_from_ptr(
init_opts.native_widget,
init_opts.coordinates.framebuffer.to_untyped(),
)
};
let surface_type = SurfaceType::Widget { native_widget };
let webrender_surfman = WebrenderSurfman::create(&connection, &adapter, surface_type)
.or(Err("Failed to create surface manager"))?;
let window_callbacks = Rc::new(ServoWindowCallbacks { let window_callbacks = Rc::new(ServoWindowCallbacks {
host_callbacks: callbacks, host_callbacks: callbacks,
gl: gl.clone(),
coordinates: RefCell::new(init_opts.coordinates), coordinates: RefCell::new(init_opts.coordinates),
density: init_opts.density, density: init_opts.density,
gl_context_pointer: init_opts.gl_context_pointer, gl_context_pointer: init_opts.gl_context_pointer,
native_display_pointer: init_opts.native_display_pointer, native_display_pointer: init_opts.native_display_pointer,
webrender_surfman,
}); });
let embedder_callbacks = Box::new(ServoEmbedderCallbacks { let embedder_callbacks = Box::new(ServoEmbedderCallbacks {
@ -723,12 +736,12 @@ struct ServoEmbedderCallbacks {
} }
struct ServoWindowCallbacks { struct ServoWindowCallbacks {
gl: Rc<dyn gl::Gl>,
host_callbacks: Box<dyn HostTrait>, host_callbacks: Box<dyn HostTrait>,
coordinates: RefCell<Coordinates>, coordinates: RefCell<Coordinates>,
density: f32, density: f32,
gl_context_pointer: Option<*const c_void>, gl_context_pointer: Option<*const c_void>,
native_display_pointer: Option<*const c_void>, native_display_pointer: Option<*const c_void>,
webrender_surfman: WebrenderSurfman,
} }
impl EmbedderMethods for ServoEmbedderCallbacks { impl EmbedderMethods for ServoEmbedderCallbacks {
@ -798,7 +811,7 @@ impl EmbedderMethods for ServoEmbedderCallbacks {
struct GlThread(WebGlExecutor); struct GlThread(WebGlExecutor);
impl webxr::openxr::GlThread for GlThread { impl webxr::openxr::GlThread for GlThread {
fn execute(&self, runnable: Box<dyn FnOnce() + Send>) { fn execute(&self, runnable: Box<dyn FnOnce(&surfman::Device) + Send>) {
let _ = self.0.send(runnable); let _ = self.0.send(runnable);
} }
fn clone(&self) -> Box<dyn webxr::openxr::GlThread> { fn clone(&self) -> Box<dyn webxr::openxr::GlThread> {
@ -835,19 +848,8 @@ impl EmbedderMethods for ServoEmbedderCallbacks {
} }
impl WindowMethods for ServoWindowCallbacks { impl WindowMethods for ServoWindowCallbacks {
fn make_gl_context_current(&self) { fn webrender_surfman(&self) -> WebrenderSurfman {
debug!("WindowMethods::prepare_for_composite"); self.webrender_surfman.clone()
self.host_callbacks.make_current();
}
fn present(&self) {
debug!("WindowMethods::present");
self.host_callbacks.flush();
}
fn gl(&self) -> Rc<dyn gl::Gl> {
debug!("WindowMethods::gl");
self.gl.clone()
} }
fn set_animation_state(&self, state: AnimationState) { fn set_animation_state(&self, state: AnimationState) {

View file

@ -18,6 +18,7 @@ log = "0.4"
lazy_static = "1" lazy_static = "1"
env_logger = "0.7" env_logger = "0.7"
backtrace = "0.3" backtrace = "0.3"
surfman = "0.2"
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
libc = "0.2" libc = "0.2"

View file

@ -203,8 +203,6 @@ where
/// Callback used by Servo internals /// Callback used by Servo internals
#[repr(C)] #[repr(C)]
pub struct CHostCallbacks { pub struct CHostCallbacks {
pub flush: extern "C" fn(),
pub make_current: extern "C" fn(),
pub on_load_started: extern "C" fn(), pub on_load_started: extern "C" fn(),
pub on_load_ended: extern "C" fn(), pub on_load_ended: extern "C" fn(),
pub on_title_changed: extern "C" fn(title: *const c_char), pub on_title_changed: extern "C" fn(title: *const c_char),
@ -245,6 +243,7 @@ pub struct CInitOptions {
pub enable_subpixel_text_antialiasing: bool, pub enable_subpixel_text_antialiasing: bool,
pub vslogger_mod_list: *const *const c_char, pub vslogger_mod_list: *const *const c_char,
pub vslogger_mod_size: u32, pub vslogger_mod_size: u32,
pub native_widget: *mut c_void,
} }
#[repr(C)] #[repr(C)]
@ -442,6 +441,7 @@ unsafe fn init(
enable_subpixel_text_antialiasing: opts.enable_subpixel_text_antialiasing, enable_subpixel_text_antialiasing: opts.enable_subpixel_text_antialiasing,
gl_context_pointer: gl_context, gl_context_pointer: gl_context,
native_display_pointer: display, native_display_pointer: display,
native_widget: opts.native_widget,
}; };
let wakeup = Box::new(WakeupCallback::new(wakeup)); let wakeup = Box::new(WakeupCallback::new(wakeup));
@ -750,16 +750,6 @@ impl HostCallbacks {
} }
impl HostTrait for HostCallbacks { impl HostTrait for HostCallbacks {
fn flush(&self) {
debug!("flush");
(self.0.flush)();
}
fn make_current(&self) {
debug!("make_current");
(self.0.make_current)();
}
fn on_load_started(&self) { fn on_load_started(&self) {
debug!("on_load_started"); debug!("on_load_started");
(self.0.on_load_started)(); (self.0.on_load_started)();

View file

@ -223,34 +223,6 @@ def append_to_path_env(string, env, name):
env[name] = variable env[name] = variable
def set_osmesa_env(bin_path, env, show_vars):
"""Set proper LD_LIBRARY_PATH and DRIVE for software rendering on Linux and OSX"""
if is_linux():
dep_path = find_dep_path_newest('osmesa-src', bin_path)
if not dep_path:
return None
osmesa_path = path.join(dep_path, "out", "lib", "gallium")
append_to_path_env(osmesa_path, env, "LD_LIBRARY_PATH")
env["GALLIUM_DRIVER"] = "softpipe"
if show_vars:
print("GALLIUM_DRIVER=" + env["GALLIUM_DRIVER"])
print("LD_LIBRARY_PATH=" + env["LD_LIBRARY_PATH"])
elif is_macosx():
osmesa_dep_path = find_dep_path_newest('osmesa-src', bin_path)
if not osmesa_dep_path:
return None
osmesa_path = path.join(osmesa_dep_path,
"out", "src", "gallium", "targets", "osmesa", ".libs")
glapi_path = path.join(osmesa_dep_path,
"out", "src", "mapi", "shared-glapi", ".libs")
append_to_path_env(osmesa_path + ":" + glapi_path, env, "DYLD_LIBRARY_PATH")
env["GALLIUM_DRIVER"] = "softpipe"
if show_vars:
print("GALLIUM_DRIVER=" + env["GALLIUM_DRIVER"])
print("DYLD_LIBRARY_PATH=" + env["DYLD_LIBRARY_PATH"])
return env
def gstreamer_root(target, env, topdir=None): def gstreamer_root(target, env, topdir=None):
if is_windows(): if is_windows():
arch = { arch = {

View file

@ -24,7 +24,7 @@ from mach.decorators import (
from servo.command_base import ( from servo.command_base import (
CommandBase, CommandBase,
check_call, check_output, BIN_SUFFIX, check_call, check_output, BIN_SUFFIX,
is_linux, set_osmesa_env, is_linux,
) )
@ -126,7 +126,6 @@ class PostBuildCommands(CommandBase):
args = [bin or self.get_nightly_binary_path(nightly) or self.get_binary_path(release, dev)] args = [bin or self.get_nightly_binary_path(nightly) or self.get_binary_path(release, dev)]
if headless: if headless:
set_osmesa_env(args[0], env, debugger is not None)
args.append('-z') args.append('-z')
if software: if software:

View file

@ -33,8 +33,8 @@ from mach.decorators import (
) )
from servo.command_base import ( from servo.command_base import (
BuildNotFound, CommandBase, CommandBase,
call, check_call, check_output, set_osmesa_env, call, check_call, check_output,
) )
from servo.util import host_triple from servo.util import host_triple
@ -197,8 +197,6 @@ class MachCommands(CommandBase):
@CommandArgument('--submit', '-a', default=False, action="store_true", @CommandArgument('--submit', '-a', default=False, action="store_true",
help="submit the data to perfherder") help="submit the data to perfherder")
def test_perf(self, base=None, date=None, submit=False): def test_perf(self, base=None, date=None, submit=False):
self.set_software_rendering_env(True, False)
env = self.build_env() env = self.build_env()
cmd = ["bash", "test_perf.sh"] cmd = ["bash", "test_perf.sh"]
if base: if base:
@ -441,8 +439,6 @@ class MachCommands(CommandBase):
# Helper for test_css and test_wpt: # Helper for test_css and test_wpt:
def wptrunner(self, run_file, **kwargs): def wptrunner(self, run_file, **kwargs):
self.set_software_rendering_env(kwargs['release'], kwargs['debugger'])
# By default, Rayon selects the number of worker threads # By default, Rayon selects the number of worker threads
# based on the available CPU count. This doesn't work very # based on the available CPU count. This doesn't work very
# well when running tests on CI, since we run so many # well when running tests on CI, since we run so many
@ -753,18 +749,6 @@ class MachCommands(CommandBase):
return check_call( return check_call(
[run_file, "|".join(tests), bin_path, base_dir]) [run_file, "|".join(tests), bin_path, base_dir])
def set_software_rendering_env(self, use_release, show_vars):
# On Linux and mac, find the OSMesa software rendering library and
# add it to the dynamic linker search path.
try:
bin_path = self.get_binary_path(use_release, not use_release)
if not set_osmesa_env(bin_path, os.environ, show_vars):
print("Warning: Cannot set the path to OSMesa library.")
except BuildNotFound:
# This can occur when cross compiling (e.g. arm64), in which case
# we won't run the tests anyway so can safely ignore this step.
pass
def setup_clangfmt(env): def setup_clangfmt(env):
cmd = "clang-format.exe" if sys.platform == "win32" else "clang-format" cmd = "clang-format.exe" if sys.platform == "win32" else "clang-format"

View file

@ -38,6 +38,7 @@
"dom.webxr.test": false, "dom.webxr.test": false,
"dom.worklet.timeout_ms": 10, "dom.worklet.timeout_ms": 10,
"gfx.subpixel-text-antialiasing.enabled": true, "gfx.subpixel-text-antialiasing.enabled": true,
"gfx.texture-swizzling.enabled": true,
"js.asmjs.enabled": true, "js.asmjs.enabled": true,
"js.asyncstack.enabled": false, "js.asyncstack.enabled": false,
"js.baseline.enabled": true, "js.baseline.enabled": true,

View file

@ -48,10 +48,6 @@ packages = [
"quote", "quote",
"unicode-xid", "unicode-xid",
# These can be removed once servo is updated to surfman 0.2
"surfman",
"surfman-chains",
# https://github.com/servo/servo/pull/25518 # https://github.com/servo/servo/pull/25518
"core-foundation", "core-foundation",
"core-foundation-sys", "core-foundation-sys",

View file

@ -1,3 +1,3 @@
#pragma once #pragma once
#define DEFAULT_URL L"https://servo.org/hl-home/" #define DEFAULT_URL L"https://servo.org/hl-home/"

View file

@ -947,7 +947,7 @@
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.190620.2\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.190620.2\build\native\Microsoft.Windows.CppWinRT.targets')" /> <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.190620.2\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.190620.2\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\packages\OpenXR.Loader.1.0.3\build\native\OpenXR.Loader.targets" Condition="Exists('..\packages\OpenXR.Loader.1.0.3\build\native\OpenXR.Loader.targets')" /> <Import Project="..\packages\OpenXR.Loader.1.0.3\build\native\OpenXR.Loader.targets" Condition="Exists('..\packages\OpenXR.Loader.1.0.3\build\native\OpenXR.Loader.targets')" />
<Import Project="..\packages\ANGLE.WindowsStore.Servo.2.1.16\build\native\ANGLE.WindowsStore.Servo.targets" Condition="Exists('..\packages\ANGLE.WindowsStore.Servo.2.1.16\build\native\ANGLE.WindowsStore.Servo.targets')" /> <Import Project="..\packages\ANGLE.WindowsStore.Servo.2.1.19\build\native\ANGLE.WindowsStore.Servo.targets" Condition="Exists('..\packages\ANGLE.WindowsStore.Servo.2.1.19\build\native\ANGLE.WindowsStore.Servo.targets')" />
</ImportGroup> </ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <PropertyGroup>
@ -957,6 +957,6 @@
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.190620.2\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.190620.2\build\native\Microsoft.Windows.CppWinRT.targets'))" /> <Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.190620.2\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.190620.2\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\packages\OpenXR.Loader.1.0.3\build\native\OpenXR.Loader.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\OpenXR.Loader.1.0.3\build\native\OpenXR.Loader.props'))" /> <Error Condition="!Exists('..\packages\OpenXR.Loader.1.0.3\build\native\OpenXR.Loader.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\OpenXR.Loader.1.0.3\build\native\OpenXR.Loader.props'))" />
<Error Condition="!Exists('..\packages\OpenXR.Loader.1.0.3\build\native\OpenXR.Loader.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\OpenXR.Loader.1.0.3\build\native\OpenXR.Loader.targets'))" /> <Error Condition="!Exists('..\packages\OpenXR.Loader.1.0.3\build\native\OpenXR.Loader.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\OpenXR.Loader.1.0.3\build\native\OpenXR.Loader.targets'))" />
<Error Condition="!Exists('..\packages\ANGLE.WindowsStore.Servo.2.1.16\build\native\ANGLE.WindowsStore.Servo.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\ANGLE.WindowsStore.Servo.2.1.16\build\native\ANGLE.WindowsStore.Servo.targets'))" /> <Error Condition="!Exists('..\packages\ANGLE.WindowsStore.Servo.2.1.19\build\native\ANGLE.WindowsStore.Servo.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\ANGLE.WindowsStore.Servo.2.1.19\build\native\ANGLE.WindowsStore.Servo.targets'))" />
</Target> </Target>
</Project> </Project>

View file

@ -187,51 +187,3 @@ void OpenGLES::Reset() {
Cleanup(); Cleanup();
Initialize(); Initialize();
} }
EGLSurface OpenGLES::CreateSurface(SwapChainPanel const &panel, float dpi) {
EGLSurface surface = EGL_NO_SURFACE;
const EGLint surfaceAttributes[] = {EGL_NONE};
PropertySet surfaceCreationProperties;
surfaceCreationProperties.Insert(EGLNativeWindowTypeProperty, panel);
// How to set size and or scale:
// Insert(EGLRenderSurfaceSizeProperty),
// PropertyValue::CreateSize(*renderSurfaceSize));
surfaceCreationProperties.Insert(EGLRenderResolutionScaleProperty,
PropertyValue::CreateSingle(dpi));
EGLNativeWindowType win = static_cast<EGLNativeWindowType>(
winrt::get_abi(surfaceCreationProperties));
surface =
eglCreateWindowSurface(mEglDisplay, mEglConfig, win, surfaceAttributes);
if (surface == EGL_NO_SURFACE) {
throw winrt::hresult_error(E_FAIL, L"Failed to create EGL surface");
}
return surface;
}
void OpenGLES::GetSurfaceDimensions(const EGLSurface surface, EGLint *width,
EGLint *height) {
eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, width);
eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);
}
void OpenGLES::DestroySurface(const EGLSurface surface) {
if (mEglDisplay != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE) {
eglDestroySurface(mEglDisplay, surface);
}
}
void OpenGLES::MakeCurrent(const EGLSurface surface) {
if (eglMakeCurrent(mEglDisplay, surface, surface, mEglContext) == EGL_FALSE) {
throw winrt::hresult_error(E_FAIL, L"Failed to make EGLSurface current");
}
}
EGLBoolean OpenGLES::SwapBuffers(const EGLSurface surface) {
return (eglSwapBuffers(mEglDisplay, surface));
}

View file

@ -9,15 +9,10 @@ public:
OpenGLES(); OpenGLES();
~OpenGLES(); ~OpenGLES();
EGLSurface EGLNativeWindowType
CreateSurface(winrt::Windows::UI::Xaml::Controls::SwapChainPanel const &, GetNativeWindow(winrt::Windows::UI::Xaml::Controls::SwapChainPanel const &,
float dpi); float dpi);
void GetSurfaceDimensions(const EGLSurface surface, EGLint *width,
EGLint *height);
void DestroySurface(const EGLSurface surface);
void MakeCurrent(const EGLSurface surface);
EGLBoolean SwapBuffers(const EGLSurface surface);
void Reset(); void Reset();
private: private:

View file

@ -1,5 +1,6 @@
#include "pch.h" #include "pch.h"
#include "Servo.h" #include "Servo.h"
#include <EGL/egl.h>
namespace winrt::servo { namespace winrt::servo {
@ -21,10 +22,6 @@ void on_url_changed(const char *url) {
sServo->Delegate().OnServoURLChanged(char2hstring(url)); sServo->Delegate().OnServoURLChanged(char2hstring(url));
} }
void flush() { sServo->Delegate().Flush(); }
void make_current() { sServo->Delegate().MakeCurrent(); }
void wakeup() { sServo->Delegate().WakeUp(); } void wakeup() { sServo->Delegate().WakeUp(); }
bool on_allow_navigation(const char *url) { bool on_allow_navigation(const char *url) {
@ -107,7 +104,8 @@ const char *prompt_input(const char *message, const char *default,
} }
Servo::Servo(hstring url, hstring args, GLsizei width, GLsizei height, Servo::Servo(hstring url, hstring args, GLsizei width, GLsizei height,
float dpi, ServoDelegate &aDelegate) EGLNativeWindowType eglNativeWindow, float dpi,
ServoDelegate &aDelegate)
: mWindowHeight(height), mWindowWidth(width), mDelegate(aDelegate) { : mWindowHeight(height), mWindowWidth(width), mDelegate(aDelegate) {
SetEnvironmentVariableA("PreviewRuntimeEnabled", "1"); SetEnvironmentVariableA("PreviewRuntimeEnabled", "1");
@ -119,6 +117,7 @@ Servo::Servo(hstring url, hstring args, GLsizei width, GLsizei height,
o.height = mWindowHeight; o.height = mWindowHeight;
o.density = dpi; o.density = dpi;
o.enable_subpixel_text_antialiasing = false; o.enable_subpixel_text_antialiasing = false;
o.native_widget = eglNativeWindow;
// Note about logs: // Note about logs:
// By default: all modules are enabled. Only warn level-logs are displayed. // By default: all modules are enabled. Only warn level-logs are displayed.
@ -142,8 +141,6 @@ Servo::Servo(hstring url, hstring args, GLsizei width, GLsizei height,
sServo = this; // FIXME; sServo = this; // FIXME;
capi::CHostCallbacks c; capi::CHostCallbacks c;
c.flush = &flush;
c.make_current = &make_current;
c.on_load_started = &on_load_started; c.on_load_started = &on_load_started;
c.on_load_ended = &on_load_ended; c.on_load_ended = &on_load_ended;
c.on_title_changed = &on_title_changed; c.on_title_changed = &on_title_changed;

View file

@ -5,6 +5,7 @@
#pragma once #pragma once
#include "pch.h" #include "pch.h"
#include <EGL/egl.h>
#include "logs.h" #include "logs.h"
#include <stdlib.h> #include <stdlib.h>
@ -23,7 +24,8 @@ class ServoDelegate;
class Servo { class Servo {
public: public:
Servo(hstring, hstring, GLsizei, GLsizei, float, ServoDelegate &); Servo(hstring, hstring, GLsizei, GLsizei, EGLNativeWindowType, float,
ServoDelegate &);
~Servo(); ~Servo();
ServoDelegate &Delegate() { return mDelegate; } ServoDelegate &Delegate() { return mDelegate; }
@ -100,8 +102,6 @@ public:
virtual void OnServoAnimatingChanged(bool) = 0; virtual void OnServoAnimatingChanged(bool) = 0;
virtual void OnServoIMEStateChanged(bool) = 0; virtual void OnServoIMEStateChanged(bool) = 0;
virtual void OnServoDevtoolsStarted(bool, const unsigned int) = 0; virtual void OnServoDevtoolsStarted(bool, const unsigned int) = 0;
virtual void Flush() = 0;
virtual void MakeCurrent() = 0;
virtual void OnServoMediaSessionMetadata(hstring, hstring, hstring) = 0; virtual void OnServoMediaSessionMetadata(hstring, hstring, hstring) = 0;
virtual void OnServoMediaSessionPlaybackStateChange(int) = 0; virtual void OnServoMediaSessionPlaybackStateChange(int) = 0;
virtual void OnServoPromptAlert(hstring, bool) = 0; virtual void OnServoPromptAlert(hstring, bool) = 0;

View file

@ -72,7 +72,7 @@ void ServoControl::OnLoaded(IInspectable const &, RoutedEventArgs const &) {
InitializeCriticalSection(&mGLLock); InitializeCriticalSection(&mGLLock);
InitializeConditionVariable(&mDialogCondVar); InitializeConditionVariable(&mDialogCondVar);
InitializeCriticalSection(&mDialogLock); InitializeCriticalSection(&mDialogLock);
CreateRenderSurface(); CreateNativeWindow();
StartRenderLoop(); StartRenderLoop();
} }
@ -80,22 +80,26 @@ Controls::SwapChainPanel ServoControl::Panel() {
return GetTemplateChild(L"swapChainPanel").as<Controls::SwapChainPanel>(); return GetTemplateChild(L"swapChainPanel").as<Controls::SwapChainPanel>();
} }
void ServoControl::CreateRenderSurface() { void ServoControl::CreateNativeWindow() {
if (mRenderSurface == EGL_NO_SURFACE) { mPanelWidth = Panel().ActualWidth() * mDPI;
mRenderSurface = mOpenGLES.CreateSurface(Panel(), mDPI); mPanelHeight = Panel().ActualHeight() * mDPI;
} mNativeWindowProperties.Insert(EGLNativeWindowTypeProperty, Panel());
// How to set size and or scale:
// Insert(EGLRenderSurfaceSizeProperty),
// PropertyValue::CreateSize(*renderSurfaceSize));
mNativeWindowProperties.Insert(EGLRenderResolutionScaleProperty,
PropertyValue::CreateSingle(mDPI));
} }
void ServoControl::DestroyRenderSurface() { EGLNativeWindowType ServoControl::GetNativeWindow() {
mOpenGLES.DestroySurface(mRenderSurface); EGLNativeWindowType win =
mRenderSurface = EGL_NO_SURFACE; static_cast<EGLNativeWindowType>(winrt::get_abi(mNativeWindowProperties));
return win;
} }
void ServoControl::RecoverFromLostDevice() { void ServoControl::RecoverFromLostDevice() {
StopRenderLoop(); StopRenderLoop();
DestroyRenderSurface();
mOpenGLES.Reset();
CreateRenderSurface();
StartRenderLoop(); StartRenderLoop();
} }
@ -311,18 +315,12 @@ void ServoControl::RunOnGLThread(std::function<void()> task) {
void ServoControl::Loop() { void ServoControl::Loop() {
log("BrowserPage::Loop(). GL thread: %i", GetCurrentThreadId()); log("BrowserPage::Loop(). GL thread: %i", GetCurrentThreadId());
mOpenGLES.MakeCurrent(mRenderSurface);
EGLint panelWidth = 0;
EGLint panelHeight = 0;
mOpenGLES.GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
glViewport(0, 0, panelWidth, panelHeight);
if (mServo == nullptr) { if (mServo == nullptr) {
log("Entering loop"); log("Entering loop");
ServoDelegate *sd = static_cast<ServoDelegate *>(this); ServoDelegate *sd = static_cast<ServoDelegate *>(this);
mServo = std::make_unique<Servo>(mInitialURL, mArgs, panelWidth, EGLNativeWindowType win = GetNativeWindow();
panelHeight, mDPI, *sd); mServo = std::make_unique<Servo>(mInitialURL, mArgs, mPanelWidth,
mPanelHeight, win, mDPI, *sd);
} else { } else {
// FIXME: this will fail since create_task didn't pick the thread // FIXME: this will fail since create_task didn't pick the thread
// where Servo was running initially. // where Servo was running initially.
@ -406,17 +404,6 @@ void ServoControl::OnServoURLChanged(hstring url) {
}); });
} }
void ServoControl::Flush() {
if (mOpenGLES.SwapBuffers(mRenderSurface) != GL_TRUE) {
// The call to eglSwapBuffers might not be successful (i.e. due to Device
// Lost) If the call fails, then we must reinitialize EGL and the GL
// resources.
RunOnUIThread([=] { RecoverFromLostDevice(); });
}
}
void ServoControl::MakeCurrent() { mOpenGLES.MakeCurrent(mRenderSurface); }
void ServoControl::WakeUp() { void ServoControl::WakeUp() {
RunOnGLThread([=] {}); RunOnGLThread([=] {});
} }

View file

@ -4,6 +4,8 @@
#include "Servo.h" #include "Servo.h"
#include "DefaultUrl.h" #include "DefaultUrl.h"
using namespace winrt::Windows::Foundation::Collections;
namespace winrt::ServoApp::implementation { namespace winrt::ServoApp::implementation {
struct ServoControl : ServoControlT<ServoControl>, public servo::ServoDelegate { struct ServoControl : ServoControlT<ServoControl>, public servo::ServoDelegate {
@ -108,8 +110,6 @@ struct ServoControl : ServoControlT<ServoControl>, public servo::ServoDelegate {
virtual void OnServoShutdownComplete(); virtual void OnServoShutdownComplete();
virtual void OnServoTitleChanged(winrt::hstring); virtual void OnServoTitleChanged(winrt::hstring);
virtual void OnServoURLChanged(winrt::hstring); virtual void OnServoURLChanged(winrt::hstring);
virtual void Flush();
virtual void MakeCurrent();
virtual bool OnServoAllowNavigation(winrt::hstring); virtual bool OnServoAllowNavigation(winrt::hstring);
virtual void OnServoAnimatingChanged(bool); virtual void OnServoAnimatingChanged(bool);
virtual void OnServoIMEStateChanged(bool); virtual void OnServoIMEStateChanged(bool);
@ -150,14 +150,16 @@ private:
std::optional<hstring> secondaryButton, std::optional<hstring> secondaryButton,
std::optional<hstring> input); std::optional<hstring> input);
int mPanelHeight = 0;
int mPanelWidth = 0;
float mDPI = 1; float mDPI = 1;
hstring mInitialURL = DEFAULT_URL; hstring mInitialURL = DEFAULT_URL;
hstring mCurrentUrl = L""; hstring mCurrentUrl = L"";
bool mTransient = false; bool mTransient = false;
Windows::UI::Xaml::Controls::SwapChainPanel ServoControl::Panel(); Windows::UI::Xaml::Controls::SwapChainPanel ServoControl::Panel();
void CreateRenderSurface(); void CreateNativeWindow();
void DestroyRenderSurface(); EGLNativeWindowType GetNativeWindow();
void RecoverFromLostDevice(); void RecoverFromLostDevice();
void StartRenderLoop(); void StartRenderLoop();
@ -204,7 +206,7 @@ private:
void TryLoadUri(hstring); void TryLoadUri(hstring);
std::unique_ptr<servo::Servo> mServo; std::unique_ptr<servo::Servo> mServo;
EGLSurface mRenderSurface{EGL_NO_SURFACE}; PropertySet mNativeWindowProperties;
OpenGLES mOpenGLES; OpenGLES mOpenGLES;
bool mAnimating = false; bool mAnimating = false;
bool mLooping = false; bool mLooping = false;

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="ANGLE.WindowsStore.Servo" version="2.1.16" targetFramework="native" /> <package id="ANGLE.WindowsStore.Servo" version="2.1.19" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.190620.2" targetFramework="native" /> <package id="Microsoft.Windows.CppWinRT" version="2.0.190620.2" targetFramework="native" />
<package id="OpenXR.Loader" version="1.0.3" targetFramework="native" /> <package id="OpenXR.Loader" version="1.0.3" targetFramework="native" />
</packages> </packages>

View file

@ -0,0 +1,4 @@
[gradients-with-border.html]
type: reftest
fuzzy: /css/css-images/gradients-with-border-ref.html:0-1;0-1
expected: PASS

View file

@ -1,2 +0,0 @@
[text_node_opacity.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[text_node_opacity.html]
expected: FAIL

View file

@ -10867,7 +10867,7 @@
] ]
], ],
"shader-varying-packing-restrictions.html": [ "shader-varying-packing-restrictions.html": [
"8a7fd1a4201883e63af071122cd5003120dfb23e", "d289bbeabb9b2db31cb6ba50df97d63ccce7d5c6",
[ [
null, null,
{} {}

View file

@ -0,0 +1,6 @@
[gl-disabled-vertex-attrib.html]
bug: https://github.com/servo/servo/issues/26004
[WebGL test #15: should be green\nat (0, 0) expected: 0,255,0,255 was 255,255,255,255]
expected:
if os == "mac": FAIL

View file

@ -0,0 +1,4 @@
[gl-vertex-attrib-unconsumed-out-of-bounds.html]
bug: https://github.com/servo/servo/issues/26004
expected:
if os == "mac": CRASH

View file

@ -0,0 +1,42 @@
[gl-vertex-attrib-zero-issues.html]
bug: https://github.com/servo/servo/issues/26004
[WebGL test #19: canvas should be green\nat (0, 0) expected: 0,255,0,255 was 0,0,0,0]
expected:
if os == "mac": FAIL
[WebGL test #31: canvas should be green\nat (0, 0) expected: 0,255,0,255 was 0,0,0,0]
expected:
if os == "mac": FAIL
[WebGL test #11: canvas should be green\nat (0, 0) expected: 0,255,0,255 was 0,0,0,0]
expected:
if os == "mac": FAIL
[WebGL test #13: canvas should be green\nat (0, 0) expected: 0,255,0,255 was 0,0,0,0]
expected:
if os == "mac": FAIL
[WebGL test #25: canvas should be green\nat (0, 0) expected: 0,255,0,255 was 0,0,0,0]
expected:
if os == "mac": FAIL
[WebGL test #7: canvas should be green\nat (0, 0) expected: 0,255,0,255 was 0,0,0,0]
expected:
if os == "mac": FAIL
[WebGL test #23: canvas should be green\nat (0, 0) expected: 0,255,0,255 was 0,0,0,0]
expected:
if os == "mac": FAIL
[WebGL test #29: canvas should be green\nat (0, 0) expected: 0,255,0,255 was 0,0,0,0]
expected:
if os == "mac": FAIL
[WebGL test #5: canvas should be green\nat (0, 0) expected: 0,255,0,255 was 0,0,0,0]
expected:
if os == "mac": FAIL
[WebGL test #17: canvas should be green\nat (0, 0) expected: 0,255,0,255 was 0,0,0,0]
expected:
if os == "mac": FAIL

View file

@ -1,5 +1,8 @@
[angle-instanced-arrays-out-of-bounds.html] [angle-instanced-arrays-out-of-bounds.html]
bug: https://github.com/servo/servo/issues/20599 bug: https://github.com/servo/servo/issues/20599 https://github.com/servo/servo/issues/25990
expected:
if os == "mac": CRASH
[WebGL test #32: getError expected: INVALID_OPERATION. Was NO_ERROR : after evaluating: ext.drawElementsInstancedANGLE(gl.TRIANGLES, 0, gl.UNSIGNED_BYTE, 0, 1)] [WebGL test #32: getError expected: INVALID_OPERATION. Was NO_ERROR : after evaluating: ext.drawElementsInstancedANGLE(gl.TRIANGLES, 0, gl.UNSIGNED_BYTE, 0, 1)]
expected: FAIL expected: FAIL

View file

@ -1,41 +1,72 @@
[shader-varying-packing-restrictions.html] [shader-varying-packing-restrictions.html]
bug: https://github.com/servo/servo/issues/20601 [WebGL test #9: [unexpected link status\] shaders with varying array of vec2 with one more than the maximum number of elements accessing first element should fail]
[WebGL test #2: [unexpected link status\] shaders with varying array of float with 33 elements (one past maximum) accessing last element should fail]
expected: FAIL expected: FAIL
[WebGL test #3: [unexpected link status\] shaders with varying array of float with 33 elements (one past maximum) accessing first element should fail] [WebGL test #8: [unexpected link status\] shaders with varying array of vec2 with one more than the maximum number of elements accessing last element should fail]
expected: FAIL expected: FAIL
[WebGL test #8: [unexpected link status\] shaders with varying array of vec2 with 33 elements (one past maximum) accessing last element should fail] [WebGL test #34: [unexpected link status\] shaders with one more than the maximum number of varyings of mat3 should fail]
expected: FAIL expected: FAIL
[WebGL test #9: [unexpected link status\] shaders with varying array of vec2 with 33 elements (one past maximum) accessing first element should fail] [WebGL test #14: [unexpected link status\] shaders with varying array of vec3 with one more than the maximum number of elements accessing last element should fail]
expected: FAIL expected: FAIL
[WebGL test #14: [unexpected link status\] shaders with varying array of vec3 with 33 elements (one past maximum) accessing last element should fail] [WebGL test #32: [unexpected link status\] shaders with varying array of mat3 with one more than the maximum number of elements accessing last element should fail]
expected: FAIL expected: FAIL
[WebGL test #15: [unexpected link status\] shaders with varying array of vec3 with 33 elements (one past maximum) accessing first element should fail] [WebGL test #28: [unexpected link status\] shaders with one more than the maximum number of varyings of mat2 should fail]
expected: FAIL expected: FAIL
[WebGL test #16: [unexpected link status\] shaders with 33 varyings of vec3 (one past maximum) should fail] [WebGL test #16: [unexpected link status\] shaders with one more than the maximum number of varyings of vec3 should fail]
expected: FAIL expected: FAIL
[WebGL test #26: [unexpected link status\] shaders with varying array of mat2 with 17 elements (one past maximum) accessing last element should fail] [WebGL test #26: [unexpected link status\] shaders with varying array of mat2 with one more than the maximum number of elements accessing last element should fail]
expected: FAIL expected: FAIL
[WebGL test #27: [unexpected link status\] shaders with varying array of mat2 with 17 elements (one past maximum) accessing first element should fail] [WebGL test #27: [unexpected link status\] shaders with varying array of mat2 with one more than the maximum number of elements accessing first element should fail]
expected: FAIL expected: FAIL
[WebGL test #28: [unexpected link status\] shaders with 17 varyings of mat2 (one past maximum) should fail] [WebGL test #33: [unexpected link status\] shaders with varying array of mat3 with one more than the maximum number of elements accessing first element should fail]
expected: FAIL expected: FAIL
[WebGL test #32: [unexpected link status\] shaders with varying array of mat3 with 11 elements (one past maximum) accessing last element should fail] [WebGL test #3: [unexpected link status\] shaders with varying array of float with one more than the maximum number of elements accessing first element should fail]
expected: FAIL expected: FAIL
[WebGL test #33: [unexpected link status\] shaders with varying array of mat3 with 11 elements (one past maximum) accessing first element should fail] [WebGL test #2: [unexpected link status\] shaders with varying array of float with one more than the maximum number of elements accessing last element should fail]
expected: FAIL expected: FAIL
[WebGL test #34: [unexpected link status\] shaders with 11 varyings of mat3 (one past maximum) should fail] [WebGL test #15: [unexpected link status\] shaders with varying array of vec3 with one more than the maximum number of elements accessing first element should fail]
expected: FAIL expected: FAIL
[WebGL test #10: [unexpected link status\] shaders with one more than the maximum number of varyings of vec2 should fail]
expected:
if os == "mac": FAIL
[WebGL test #38: [unexpected link status\] shaders with varying array of mat4 with one more than the maximum number of elements accessing last element should fail]
expected:
if os == "mac": FAIL
[WebGL test #21: [unexpected link status\] shaders with varying array of vec4 with one more than the maximum number of elements accessing first element should fail]
expected:
if os == "mac": FAIL
[WebGL test #40: [unexpected link status\] shaders with one more than the maximum number of varyings of mat4 should fail]
expected:
if os == "mac": FAIL
[WebGL test #22: [unexpected link status\] shaders with one more than the maximum number of varyings of vec4 should fail]
expected:
if os == "mac": FAIL
[WebGL test #4: [unexpected link status\] shaders with one more than the maximum number of varyings of float should fail]
expected:
if os == "mac": FAIL
[WebGL test #39: [unexpected link status\] shaders with varying array of mat4 with one more than the maximum number of elements accessing first element should fail]
expected:
if os == "mac": FAIL
[WebGL test #20: [unexpected link status\] shaders with varying array of vec4 with one more than the maximum number of elements accessing last element should fail]
expected:
if os == "mac": FAIL

View file

@ -9,3 +9,15 @@
[WebGL test #12: [unexpected link status\] vertex shader with variant gl_PointSize and fragment shader with invariant gl_PointCoord must fail] [WebGL test #12: [unexpected link status\] vertex shader with variant gl_PointSize and fragment shader with invariant gl_PointCoord must fail]
expected: FAIL expected: FAIL
[WebGL test #3: [unexpected link status\] vertex shader with invariant (global setting) varying and fragment shader with invariant varying must succeed]
expected:
if os == "mac": FAIL
[WebGL test #2: [unexpected link status\] vertex shader with invariant (global setting) varying and fragment shader with variant varying must fail]
expected:
if os == "mac": FAIL
[WebGL test #8: [unexpected link status\] vertex shader with invariant gl_Position and fragment shader with invariant gl_FragCoord must succeed]
expected:
if os == "mac": FAIL

View file

@ -0,0 +1,10 @@
[gl-bind-attrib-location-long-names-test.html]
bug: https://github.com/servo/servo/issues/26004
[WebGL test #4: should be green\nat (0, 0) expected: 0,255,0,255 was 255,255,255,255]
expected:
if os == "mac": FAIL
[WebGL test #8: should be green\nat (0, 0) expected: 255,0,0,255 was 255,255,255,255]
expected:
if os == "mac": FAIL

View file

@ -0,0 +1,10 @@
[gl-bind-attrib-location-test.html]
bug: https://github.com/servo/servo/issues/26004
[WebGL test #13: Line 15 should be red for at least 10 rgba pixels starting 20 pixels in\nat (20, 15) expected: 255,0,0,255 was 0,0,0,255]
expected:
if os == "mac": FAIL
[WebGL test #7: Line 15 should be red for at least 10 rgba pixels starting 20 pixels in\nat (20, 15) expected: 0,255,0,255 was 0,0,0,255]
expected:
if os == "mac": FAIL

View file

@ -1,3 +1,62 @@
[read-pixels-test.html] [read-pixels-test.html]
bug: https://github.com/servo/servo/issues/12859 bug: https://github.com/servo/servo/issues/12859
expected: TIMEOUT [WebGL test #49: getError expected: INVALID_OPERATION. Was INVALID_ENUM : Should not be able to read as ALPHA / UNSIGNED_BYTE]
expected: FAIL
[WebGL test #45: getError expected: INVALID_OPERATION. Was INVALID_ENUM : Should not be able to read as RGB / UNSIGNED_BYTE]
expected: FAIL
[WebGL test #47: getError expected: INVALID_OPERATION. Was INVALID_ENUM : Should not be able to read as RGBA / UNSIGNED_SHORT_5_5_5_1]
expected: FAIL
[WebGL test #46: getError expected: INVALID_OPERATION. Was INVALID_ENUM : Should not be able to read as RGB / UNSIGNED_SHORT_5_6_5]
expected: FAIL
[WebGL test #48: getError expected: INVALID_OPERATION. Was INVALID_ENUM : Should not be able to read as RGBA / UNSIGNED_SHORT_4_4_4_4]
expected: FAIL
[WebGL test #37: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as 0x8d99]
expected: FAIL
[WebGL test #33: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as LUMINANCE]
expected: FAIL
[WebGL test #42: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as UNSIGNED_INT]
expected: FAIL
[WebGL test #38: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as 0x84fa]
expected: FAIL
[WebGL test #30: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as DEPTH_STENCIL]
expected: FAIL
[WebGL test #43: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as 0x8368]
expected: FAIL
[WebGL test #29: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as DEPTH_COMPONENT]
expected: FAIL
[WebGL test #35: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as 0x1903]
expected: FAIL
[WebGL test #41: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as BYTE]
expected: FAIL
[WebGL test #31: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as 0x8229]
expected: FAIL
[WebGL test #36: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as 0x8228]
expected: FAIL
[WebGL test #32: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as RGBA4]
expected: FAIL
[WebGL test #40: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as SHORT]
expected: FAIL
[WebGL test #34: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as LUMINANCE_ALPHA]
expected: FAIL
[WebGL test #39: getError expected: INVALID_ENUM. Was INVALID_OPERATION : Should not be able to read as UNSIGNED_SHORT]
expected: FAIL

View file

@ -3,3 +3,6 @@
[WebGL test #3: getError expected: INVALID_OPERATION. Was NO_ERROR : after draw with invalid feedback loop] [WebGL test #3: getError expected: INVALID_OPERATION. Was NO_ERROR : after draw with invalid feedback loop]
expected: FAIL expected: FAIL
[WebGL test #5: Should be blue.\nat (0, 0) expected: 0,0,255,255 was 0,255,0,255]
expected: FAIL

View file

@ -0,0 +1,8 @@
[line-rendering-quality.html]
bug: https://github.com/servo/servo/issues/25937
[WebGL test #5: Found 0 lines, looking in the vertical direction, expected 2]
expected: FAIL
[WebGL test #11: Found 0 lines, looking in the vertical direction, expected 2]
expected: FAIL

View file

@ -0,0 +1,6 @@
[point-no-attributes.html]
bug: https://github.com/servo/servo/issues/26004
[WebGL test #1: should be 0,255,0,255\nat (0, 0) expected: 0,255,0,255 was 0,0,0,0]
expected:
if os == "mac": FAIL

View file

@ -1,2 +0,0 @@
[rendering-stencil-large-viewport.html]
expected: TIMEOUT

View file

@ -0,0 +1,18 @@
[copy-tex-image-2d-formats.html]
bug: https://github.com/servo/servo/issues/25995
[WebGL test #43: should be 64,64,64,255\nat (0, 0) expected: 64,64,64,255 was 0,0,0,255]
expected:
if os == "mac": FAIL
[WebGL test #2: should be 0,0,0,127\nat (0, 0) expected: 0,0,0,127 was 0,0,0,0]
expected:
if os == "mac": FAIL
[WebGL test #5: should be 64,64,64,255\nat (0, 0) expected: 64,64,64,255 was 0,0,0,255]
expected:
if os == "mac": FAIL
[WebGL test #8: should be 64,64,64,127\nat (0, 0) expected: 64,64,64,127 was 0,0,0,0]
expected:
if os == "mac": FAIL

View file

@ -1,4 +1,6 @@
[copy-tex-image-and-sub-image-2d.html] [copy-tex-image-and-sub-image-2d.html]
disabled:
if os == "mac": https://github.com/servo/servo/issues/26000
[WebGL test #315: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] [WebGL test #315: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136]
expected: FAIL expected: FAIL

View file

@ -1,5 +1,7 @@
[out-of-bounds-uniform-array-access.html] [out-of-bounds-uniform-array-access.html]
expected: TIMEOUT expected:
if os == "linux": TIMEOUT
[Overall test] [Overall test]
expected: NOTRUN expected:
if os == "linux": NOTRUN

View file

@ -0,0 +1,100 @@
[bound-buffer-size-change-test.html]
[WebGL test #38: gl.getIndexedParameter(gl.UNIFORM_BUFFER_BINDING, 1) should be [object WebGLBuffer\]. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #23: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0) should be [object WebGLBuffer\]. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #4: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0) should be 0. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #28: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0) should be 4. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #22: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0) should be 4. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #33: gl.getIndexedParameter(gl.UNIFORM_BUFFER_SIZE, 1) should be 12. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #16: gl.getIndexedParameter(gl.UNIFORM_BUFFER_START, 1) should be 0. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #7: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0) should be 0. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #35: gl.getIndexedParameter(gl.UNIFORM_BUFFER_BINDING, 1) should be [object WebGLBuffer\]. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #37: gl.getIndexedParameter(gl.UNIFORM_BUFFER_START, 1) should be 16. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #39: gl.getIndexedParameter(gl.UNIFORM_BUFFER_SIZE, 1) should be 12. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #21: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0) should be 8. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #40: gl.getIndexedParameter(gl.UNIFORM_BUFFER_START, 1) should be 16. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #15: gl.getIndexedParameter(gl.UNIFORM_BUFFER_SIZE, 1) should be 0. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #25: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0) should be 4. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #32: gl.getIndexedParameter(gl.UNIFORM_BUFFER_BINDING, 1) should be [object WebGLBuffer\]. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #14: gl.getIndexedParameter(gl.UNIFORM_BUFFER_BINDING, 1) should be [object WebGLBuffer\]. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #11: gl.getIndexedParameter(gl.UNIFORM_BUFFER_BINDING, 1) should be [object WebGLBuffer\]. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #36: gl.getIndexedParameter(gl.UNIFORM_BUFFER_SIZE, 1) should be 12. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #3: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0) should be 0. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #5: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0) should be [object WebGLBuffer\]. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #6: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0) should be 0. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #24: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0) should be 8. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #34: gl.getIndexedParameter(gl.UNIFORM_BUFFER_START, 1) should be 16. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #26: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0) should be [object WebGLBuffer\]. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #2: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0) should be [object WebGLBuffer\]. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #20: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0) should be [object WebGLBuffer\]. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #27: gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0) should be 8. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #12: gl.getIndexedParameter(gl.UNIFORM_BUFFER_SIZE, 1) should be 0. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #13: gl.getIndexedParameter(gl.UNIFORM_BUFFER_START, 1) should be 0. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #34: gl.getIndexedParameter(gl.UNIFORM_BUFFER_START, 1) should be 256. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #37: gl.getIndexedParameter(gl.UNIFORM_BUFFER_START, 1) should be 256. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL
[WebGL test #40: gl.getIndexedParameter(gl.UNIFORM_BUFFER_START, 1) should be 256. Threw exception TypeError: gl.getIndexedParameter is not a function]
expected: FAIL

View file

@ -0,0 +1,6 @@
[vector-dynamic-indexing-swizzled-lvalue.html]
bug: https://github.com/servo/servo/issues/26004
[WebGL test #0: should be green\nat (0, 0) expected: 0,255,0,255 was 255,0,0,255]
expected:
if os == "mac": FAIL

View file

@ -0,0 +1,58 @@
[read-pixels-pack-parameters.html]
bug: https://github.com/servo/servo/issues/26004
[WebGL test #243: last pixel of row 0: expected [249,102,0,255\], got [1,2,3,4\]]
expected:
if os == "mac": FAIL
[WebGL test #257: first pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]]
expected:
if os == "mac": FAIL
[WebGL test #246: first pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]]
expected:
if os == "mac": FAIL
[WebGL test #245: last pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]]
expected:
if os == "mac": FAIL
[WebGL test #256: last pixel of row 0: expected [249,102,0,255\], got [1,2,3,4\]]
expected:
if os == "mac": FAIL
[WebGL test #254: skipped bytes changed at index 0: expected 1 got 249]
expected:
if os == "mac": FAIL
[WebGL test #241: skipped bytes changed at index 0: expected 1 got 249]
expected:
if os == "mac": FAIL
[WebGL test #260: last pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]]
expected:
if os == "mac": FAIL
[WebGL test #244: first pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]]
expected:
if os == "mac": FAIL
[WebGL test #247: last pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]]
expected:
if os == "mac": FAIL
[WebGL test #242: first pixel of row 0: expected [249,102,0,255\], got [1,2,3,4\]]
expected:
if os == "mac": FAIL
[WebGL test #255: first pixel of row 0: expected [249,102,0,255\], got [1,2,3,4\]]
expected:
if os == "mac": FAIL
[WebGL test #259: first pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]]
expected:
if os == "mac": FAIL
[WebGL test #258: last pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]]
expected:
if os == "mac": FAIL

View file

@ -1,4 +1,6 @@
[framebuffer-object-attachment.html] [framebuffer-object-attachment.html]
expected:
if os == "mac": TIMEOUT
[WebGL test #45: getError expected: NO_ERROR. Was INVALID_ENUM : ] [WebGL test #45: getError expected: NO_ERROR. Was INVALID_ENUM : ]
expected: FAIL expected: FAIL

View file

@ -1,4 +1,8 @@
[framebuffer-test.html] [framebuffer-test.html]
[WebGL test #37: gl.getFramebufferAttachmentParameter(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_BLUE_SIZE) should be 0. Was 8.]
expected:
if os == "mac": FAIL
[WebGL test #38: getError expected: INVALID_OPERATION. Was INVALID_ENUM : getFramebufferAttachmentParameter(FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING) on read framebuffer with no attachment.] [WebGL test #38: getError expected: INVALID_OPERATION. Was INVALID_ENUM : getFramebufferAttachmentParameter(FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING) on read framebuffer with no attachment.]
expected: FAIL expected: FAIL

View file

@ -1,5 +1,8 @@
[invalidate-framebuffer.html] [invalidate-framebuffer.html]
expected: ERROR bug: https://github.com/servo/servo/issues/20529
expected:
if os == "linux": ERROR
if os == "mac": TIMEOUT
[WebGL test #17: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).] [WebGL test #17: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
expected: FAIL expected: FAIL

View file

@ -1,25 +1,25 @@
[blitframebuffer-filter-outofbounds.html] [blitframebuffer-filter-outofbounds.html]
[WebGL test #1: framebuffer not complete]
expected: FAIL
[WebGL test #2: framebuffer not complete]
expected: FAIL
[WebGL test #3: framebuffer not complete]
expected: FAIL
[WebGL test #4: framebuffer not complete] [WebGL test #4: framebuffer not complete]
expected: FAIL expected: FAIL
[WebGL test #5: framebuffer not complete]
expected: FAIL
[WebGL test #6: framebuffer not complete]
expected: FAIL
[WebGL test #7: framebuffer not complete]
expected: FAIL
[WebGL test #8: framebuffer not complete] [WebGL test #8: framebuffer not complete]
expected: FAIL expected: FAIL
[WebGL test #1: framebuffer not complete]
expected: FAIL
[WebGL test #6: framebuffer not complete]
expected: FAIL
[WebGL test #3: framebuffer not complete]
expected: FAIL
[WebGL test #2: framebuffer not complete]
expected: FAIL
[WebGL test #7: framebuffer not complete]
expected: FAIL
[WebGL test #5: framebuffer not complete]
expected: FAIL

View file

@ -1,7 +1,20 @@
[blitframebuffer-multisampled-readbuffer.html] [blitframebuffer-multisampled-readbuffer.html]
[WebGL test #2: Framebuffer incomplete.] expected:
expected: FAIL if os =="mac": ERROR
[WebGL test #1: Framebuffer incomplete.] [WebGL test #1: Framebuffer incomplete.]
expected: FAIL expected:
if os == "linux": FAIL
[WebGL test #2: Framebuffer incomplete.]
expected:
if os == "linux": FAIL
[WebGL test #1: getError expected: NO_ERROR. Was INVALID_ENUM : setup draw framebuffer should succeed]
expected:
if os == "mac": FAIL
[WebGL test #2: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
expected:
if os == "mac": FAIL

View file

@ -1,13 +1,13 @@
[blitframebuffer-outside-readbuffer.html] [blitframebuffer-outside-readbuffer.html]
[WebGL test #1: framebuffer not complete] [WebGL test #4: framebuffer not complete]
expected: FAIL expected: FAIL
[WebGL test #2: framebuffer not complete] [WebGL test #1: framebuffer not complete]
expected: FAIL expected: FAIL
[WebGL test #3: framebuffer not complete] [WebGL test #3: framebuffer not complete]
expected: FAIL expected: FAIL
[WebGL test #4: framebuffer not complete] [WebGL test #2: framebuffer not complete]
expected: FAIL expected: FAIL

View file

@ -1,17 +1,17 @@
[blitframebuffer-scissor-enabled.html] [blitframebuffer-scissor-enabled.html]
[WebGL test #1: Framebuffer incomplete.]
expected: FAIL
[WebGL test #2: Framebuffer incomplete.] [WebGL test #2: Framebuffer incomplete.]
expected: FAIL expected: FAIL
[WebGL test #3: Framebuffer incomplete.] [WebGL test #3: Framebuffer incomplete.]
expected: FAIL expected: FAIL
[WebGL test #4: Framebuffer incomplete.] [WebGL test #8: Framebuffer incomplete.]
expected: FAIL expected: FAIL
[WebGL test #5: Framebuffer incomplete.] [WebGL test #1: Framebuffer incomplete.]
expected: FAIL
[WebGL test #4: Framebuffer incomplete.]
expected: FAIL expected: FAIL
[WebGL test #6: Framebuffer incomplete.] [WebGL test #6: Framebuffer incomplete.]
@ -20,6 +20,6 @@
[WebGL test #7: Framebuffer incomplete.] [WebGL test #7: Framebuffer incomplete.]
expected: FAIL expected: FAIL
[WebGL test #8: Framebuffer incomplete.] [WebGL test #5: Framebuffer incomplete.]
expected: FAIL expected: FAIL

View file

@ -1,5 +1,31 @@
[clear-func-buffer-type-match.html] [clear-func-buffer-type-match.html]
expected: TIMEOUT [WebGL test #18: getError expected: INVALID_OPERATION. Was NO_ERROR : clearBufferiv and RGBA8 buffer]
[WebGL test #1: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).] expected: FAIL
[WebGL test #7: getError expected: INVALID_OPERATION. Was NO_ERROR : clearBufferuiv and float buffer]
expected: FAIL
[WebGL test #10: getError expected: INVALID_OPERATION. Was NO_ERROR : clearBufferfv and UINT buffer]
expected: FAIL
[WebGL test #14: getError expected: INVALID_OPERATION. Was NO_ERROR : clearBufferiv and float buffer]
expected: FAIL
[WebGL test #11: getError expected: INVALID_OPERATION. Was NO_ERROR : clearBufferiv and UINT buffer]
expected: FAIL
[WebGL test #4: getError expected: INVALID_OPERATION. Was NO_ERROR : clearBufferuiv and INT buffer]
expected: FAIL
[WebGL test #3: getError expected: INVALID_OPERATION. Was NO_ERROR : clearBufferfv and INT buffer]
expected: FAIL
[WebGL test #2: getError expected: INVALID_OPERATION. Was NO_ERROR : clear and INT buffer]
expected: FAIL
[WebGL test #9: getError expected: INVALID_OPERATION. Was NO_ERROR : clear and UINT buffer]
expected: FAIL
[WebGL test #19: getError expected: INVALID_OPERATION. Was NO_ERROR : clearBufferuiv and RGBA8 buffer]
expected: FAIL expected: FAIL

View file

@ -1,11 +1,11 @@
[framebuffer-unsupported.html] [framebuffer-unsupported.html]
expected: ERROR expected: ERROR
[WebGL test #4: checkFramebufferStatus expects [FRAMEBUFFER_UNSUPPORTED\], was FRAMEBUFFER_COMPLETE]
expected: FAIL
[WebGL test #7: checkFramebufferStatus expects [FRAMEBUFFER_UNSUPPORTED\], was FRAMEBUFFER_COMPLETE] [WebGL test #7: checkFramebufferStatus expects [FRAMEBUFFER_UNSUPPORTED\], was FRAMEBUFFER_COMPLETE]
expected: FAIL expected: FAIL
[WebGL test #8: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).] [WebGL test #8: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
expected: FAIL expected: FAIL
[WebGL test #4: checkFramebufferStatus expects [FRAMEBUFFER_UNSUPPORTED\], was FRAMEBUFFER_COMPLETE]
expected: FAIL

View file

@ -1,5 +1,28 @@
[fs-color-type-mismatch-color-buffer-type.html] [fs-color-type-mismatch-color-buffer-type.html]
expected: TIMEOUT [WebGL test #2: Framebuffer incomplete.]
[WebGL test #2: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).] expected: FAIL
[WebGL test #3: Framebuffer incomplete.]
expected: FAIL
[WebGL test #8: getError expected: NO_ERROR. Was INVALID_ENUM : If color buffers' type mismatch the type of fragment shader's outputs, geneate INVALID_OPERATION. Otherwise, it should be NO_ERROR]
expected: FAIL
[WebGL test #4: Framebuffer incomplete.]
expected: FAIL
[WebGL test #11: getError expected: INVALID_OPERATION. Was NO_ERROR : If color buffers' type mismatch the type of fragment shader's outputs, geneate INVALID_OPERATION. Otherwise, it should be NO_ERROR]
expected: FAIL
[WebGL test #6: Framebuffer incomplete.]
expected: FAIL
[WebGL test #7: Framebuffer incomplete.]
expected: FAIL
[WebGL test #13: getError expected: INVALID_OPERATION. Was NO_ERROR : If color buffers' type mismatch the type of fragment shader's outputs, geneate INVALID_OPERATION. Otherwise, it should be NO_ERROR]
expected: FAIL
[WebGL test #5: Framebuffer incomplete.]
expected: FAIL expected: FAIL

View file

@ -1,5 +1,9 @@
[line-rendering-quality.html] [line-rendering-quality.html]
expected: ERROR expected: ERROR
bug: https://github.com/servo/servo/issues/25937
[WebGL test #5: Found 0 lines, looking in the vertical direction, expected 2]
expected:
if os == "linux": FAIL
[WebGL test #10: successfullyParsed should be true. Threw exception ReferenceError: can't access lexical declaration `successfullyParsed' before initialization] [WebGL test #10: successfullyParsed should be true. Threw exception ReferenceError: can't access lexical declaration `successfullyParsed' before initialization]
expected: FAIL expected: FAIL

View file

@ -1,10 +1,25 @@
[rgb-format-support.html] [rgb-format-support.html]
[WebGL test #15: getError expected: NO_ERROR. Was INVALID_FRAMEBUFFER_OPERATION : should be no errors from clear()] [WebGL test #24: getError expected: NO_ERROR. Was INVALID_FRAMEBUFFER_OPERATION : should be no errors from clear()]
expected: FAIL expected:
if os == "linux": FAIL
[WebGL test #14: framebuffer with texture is incomplete] [WebGL test #23: framebuffer with texture is incomplete]
expected: FAIL expected:
if os == "linux": FAIL
[WebGL test #13: getError expected: NO_ERROR. Was INVALID_ENUM : should be no errors from texture setup] [WebGL test #22: getError expected: NO_ERROR. Was INVALID_ENUM : should be no errors from texture setup]
expected: FAIL expected:
if os == "linux": FAIL
[WebGL test #18: getError expected: NO_ERROR. Was INVALID_FRAMEBUFFER_OPERATION : should be no errors from clear()]
expected:
if os == "mac": FAIL
[WebGL test #17: framebuffer with texture is incomplete]
expected:
if os == "mac": FAIL
[WebGL test #16: getError expected: NO_ERROR. Was INVALID_ENUM : should be no errors from texture setup]
expected:
if os == "mac": FAIL

View file

@ -0,0 +1,4 @@
[uniform-block-buffer-size.html]
bug: https://github.com/servo/servo/issues/25990
expected:
if os == "mac": CRASH

View file

@ -1,4 +1,8 @@
[gl-object-get-calls.html] [gl-object-get-calls.html]
bug: https://github.com/servo/servo/issues/26128
expected:
if os == "mac": TIMEOUT
[WebGL test #201: gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_R) should be 33071 (of type number). Was null (of type object).] [WebGL test #201: gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_R) should be 33071 (of type number). Was null (of type object).]
expected: FAIL expected: FAIL
@ -104,3 +108,5 @@
[WebGL test #183: getRenderbufferParameter did not generate INVALID_ENUM for invalid parameter enum: NO_ERROR] [WebGL test #183: getRenderbufferParameter did not generate INVALID_ENUM for invalid parameter enum: NO_ERROR]
expected: FAIL expected: FAIL
[WebGL test #183: getRenderbufferParameter did not generate INVALID_ENUM for invalid parameter enum: NO_ERROR]
expected: FAIL

View file

@ -1,2 +1,360 @@
[too-small-buffers.html] [too-small-buffers.html]
expected: TIMEOUT expected:
if os == "linux": TIMEOUT
[WebGL test #60: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #87: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #121: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #11: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #71: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #47: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #9: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #110: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #84: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #107: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #117: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #54: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #29: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #19: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #83: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #37: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #78: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #130: getError expected: INVALID_OPERATION. Was NO_ERROR : integer overflow and/or buffer too small]
expected:
if os == "mac": FAIL
[WebGL test #66: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #12: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #7: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #34: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #77: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #74: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #31: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #15: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #120: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #49: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #56: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #73: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #33: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #97: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #116: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #91: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #90: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #95: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #119: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #65: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #23: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #35: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #68: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #16: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #57: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #61: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #38: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #21: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #129: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #89: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #32: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #115: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #14: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #25: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #113: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #102: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #5: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #42: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #108: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #18: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #36: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #99: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #100: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #55: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #67: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #80: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #53: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #105: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #79: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #63: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #24: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #125: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #76: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #96: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #98: buffer should match expected values]
expected:
if os == "mac": FAIL
[WebGL test #122: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #93: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #109: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #75: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #6: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #58: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #118: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #13: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #26: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #41: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #126: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #51: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #48: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #3: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL
[WebGL test #103: getError expected: INVALID_OPERATION. Was NO_ERROR : draw]
expected:
if os == "mac": FAIL
[WebGL test #45: getError expected: NO_ERROR. Was INVALID_OPERATION : before draw]
expected:
if os == "mac": FAIL

View file

@ -1,4 +0,0 @@
[unwritten-output-defaults-to-zero.html]
[WebGL test #4: buffer should match expected values]
expected: FAIL

View file

@ -135,7 +135,8 @@ for (var ii = 0; ii < varyingTypes.length; ++ii) {
fShaderSource: wtu.replaceParams(fArrayTestSource, {numTestType: minVars, fcode: fcode}, info), fShaderSource: wtu.replaceParams(fArrayTestSource, {numTestType: minVars, fcode: fcode}, info),
fShaderSuccess: true, fShaderSuccess: true,
linkSuccess: true, linkSuccess: true,
passMsg: "shaders with varying array of " + info.type + " with " + minVars + " elements (the minimum required) should succeed", // Try to use deterministic test names
passMsg: "shaders with varying array of " + info.type + " with the minimum number of elements should succeed",
}); });
// Test array[max + 1] accessing last element. WebGL requires this to fail. // Test array[max + 1] accessing last element. WebGL requires this to fail.
@ -147,7 +148,8 @@ for (var ii = 0; ii < varyingTypes.length; ++ii) {
fShaderSource: wtu.replaceParams(fArrayTestSource, {numTestType: numVars + 1, fcode: fcode}, info), fShaderSource: wtu.replaceParams(fArrayTestSource, {numTestType: numVars + 1, fcode: fcode}, info),
fShaderSuccess: false, fShaderSuccess: false,
linkSuccess: false, linkSuccess: false,
passMsg: "shaders with varying array of " + info.type + " with " + (numVars + 1) + " elements (one past maximum) accessing last element should fail", // Try to use deterministic test names
passMsg: "shaders with varying array of " + info.type + " with one more than the maximum number of elements accessing last element should fail",
}); });
// Test array[max + 1] accessing first element. WebGL requires this to fail but ES allows truncating array. // Test array[max + 1] accessing first element. WebGL requires this to fail but ES allows truncating array.
@ -159,7 +161,8 @@ for (var ii = 0; ii < varyingTypes.length; ++ii) {
fShaderSource: wtu.replaceParams(fArrayTestSource, {numTestType: numVars + 1, fcode: fcode}, info), fShaderSource: wtu.replaceParams(fArrayTestSource, {numTestType: numVars + 1, fcode: fcode}, info),
fShaderSuccess: false, fShaderSuccess: false,
linkSuccess: false, linkSuccess: false,
passMsg: "shaders with varying array of " + info.type + " with " + (numVars + 1) + " elements (one past maximum) accessing first element should fail", // Try to use deterministic test names
passMsg: "shaders with varying array of " + info.type + " with one more than the maximum number of elements accessing first element should fail",
}); });
// Note: We can't test max varyings as actual GL drivers are only required to be able to // Note: We can't test max varyings as actual GL drivers are only required to be able to
@ -189,7 +192,8 @@ for (var ii = 0; ii < varyingTypes.length; ++ii) {
fShaderSource: wtu.replaceParams(fVaryingTestSource, generateCode(numMax + 1), info), fShaderSource: wtu.replaceParams(fVaryingTestSource, generateCode(numMax + 1), info),
fShaderSuccess: false, fShaderSuccess: false,
linkSuccess: false, linkSuccess: false,
passMsg: "shaders with " + (numMax + 1) + " varyings of " + info.type + " (one past maximum) should fail", // Try to use deterministic test names
passMsg: "shaders with one more than the maximum number of varyings of " + info.type + " should fail",
}); });
// Test required varyings of type. // Test required varyings of type.
@ -199,7 +203,8 @@ for (var ii = 0; ii < varyingTypes.length; ++ii) {
fShaderSource: wtu.replaceParams(fVaryingTestSource, generateCode(minVars), info), fShaderSource: wtu.replaceParams(fVaryingTestSource, generateCode(minVars), info),
fShaderSuccess: true, fShaderSuccess: true,
linkSuccess: true, linkSuccess: true,
passMsg: "shaders with " + minVars + " varyings of " + info.type + " (the minimum required) should succeed", // Try to use deterministic test names
passMsg: "shaders with the minimum number of varyings of " + info.type + " should succeed",
}); });
} }

View file

@ -16,6 +16,7 @@ PATCHES = [
("timeout.patch", None), ("timeout.patch", None),
("set-zero-timeout.patch", "js/webgl-test-utils.js"), ("set-zero-timeout.patch", "js/webgl-test-utils.js"),
("compressed-images.patch", "conformance/extensions/webgl-compressed-texture-s3tc.html"), ("compressed-images.patch", "conformance/extensions/webgl-compressed-texture-s3tc.html"),
("shader-varying-packing-restrictions.patch", "conformance/glsl/misc/shader-varying-packing-restrictions.html"),
] ]
# Fix for 'UnicodeDecodeError: 'ascii' codec can't decode byte' # Fix for 'UnicodeDecodeError: 'ascii' codec can't decode byte'

View file

@ -0,0 +1,54 @@
diff --git a/tests/wpt/webgl/tests/conformance/glsl/misc/shader-varying-packing-restrictions.html b/tests/wpt/webgl/tests/conformance/glsl/misc/shader-varying-packing-restrictions.html
index 8a7fd1a420..d289bbeabb 100644
--- a/tests/wpt/webgl/tests/conformance/glsl/misc/shader-varying-packing-restrictions.html
+++ b/tests/wpt/webgl/tests/conformance/glsl/misc/shader-varying-packing-restrictions.html
@@ -135,7 +135,8 @@ for (var ii = 0; ii < varyingTypes.length; ++ii) {
fShaderSource: wtu.replaceParams(fArrayTestSource, {numTestType: minVars, fcode: fcode}, info),
fShaderSuccess: true,
linkSuccess: true,
- passMsg: "shaders with varying array of " + info.type + " with " + minVars + " elements (the minimum required) should succeed",
+ // Try to use deterministic test names
+ passMsg: "shaders with varying array of " + info.type + " with the minimum number of elements should succeed",
});
// Test array[max + 1] accessing last element. WebGL requires this to fail.
@@ -147,7 +148,8 @@ for (var ii = 0; ii < varyingTypes.length; ++ii) {
fShaderSource: wtu.replaceParams(fArrayTestSource, {numTestType: numVars + 1, fcode: fcode}, info),
fShaderSuccess: false,
linkSuccess: false,
- passMsg: "shaders with varying array of " + info.type + " with " + (numVars + 1) + " elements (one past maximum) accessing last element should fail",
+ // Try to use deterministic test names
+ passMsg: "shaders with varying array of " + info.type + " with one more than the maximum number of elements accessing last element should fail",
});
// Test array[max + 1] accessing first element. WebGL requires this to fail but ES allows truncating array.
@@ -159,7 +161,8 @@ for (var ii = 0; ii < varyingTypes.length; ++ii) {
fShaderSource: wtu.replaceParams(fArrayTestSource, {numTestType: numVars + 1, fcode: fcode}, info),
fShaderSuccess: false,
linkSuccess: false,
- passMsg: "shaders with varying array of " + info.type + " with " + (numVars + 1) + " elements (one past maximum) accessing first element should fail",
+ // Try to use deterministic test names
+ passMsg: "shaders with varying array of " + info.type + " with one more than the maximum number of elements accessing first element should fail",
});
// Note: We can't test max varyings as actual GL drivers are only required to be able to
@@ -189,7 +192,8 @@ for (var ii = 0; ii < varyingTypes.length; ++ii) {
fShaderSource: wtu.replaceParams(fVaryingTestSource, generateCode(numMax + 1), info),
fShaderSuccess: false,
linkSuccess: false,
- passMsg: "shaders with " + (numMax + 1) + " varyings of " + info.type + " (one past maximum) should fail",
+ // Try to use deterministic test names
+ passMsg: "shaders with one more than the maximum number of varyings of " + info.type + " should fail",
});
// Test required varyings of type.
@@ -199,7 +203,8 @@ for (var ii = 0; ii < varyingTypes.length; ++ii) {
fShaderSource: wtu.replaceParams(fVaryingTestSource, generateCode(minVars), info),
fShaderSuccess: true,
linkSuccess: true,
- passMsg: "shaders with " + minVars + " varyings of " + info.type + " (the minimum required) should succeed",
+ // Try to use deterministic test names
+ passMsg: "shaders with the minimum number of varyings of " + info.type + " should succeed",
});
}