diff --git a/Cargo.lock b/Cargo.lock index ab1a150e4f8..69c76155f37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -436,6 +436,7 @@ name = "canvas" version = "0.0.1" dependencies = [ "azure", + "bitflags", "byteorder", "canvas_traits", "cssparser", @@ -447,11 +448,12 @@ dependencies = [ "ipc-channel", "log", "num-traits", - "offscreen_gl_context", "pixels", "raqote", "servo_config", "sparkle", + "surfman", + "surfman-chains", "webrender", "webrender_api", "webrender_traits", @@ -475,6 +477,7 @@ dependencies = [ "sparkle", "webrender_api", "webvr_traits", + "webxr-api", ] [[package]] @@ -547,11 +550,10 @@ dependencies = [ [[package]] name = "cgl" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24cd014051545194d6e879b37d33eed1fcf4bf41e1f54644530c63d8cb912f5" +checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" dependencies = [ - "gleam 0.7.0", "libc", ] @@ -647,6 +649,21 @@ dependencies = [ "objc", ] +[[package]] +name = "cocoa" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29f7768b2d1be17b96158e3285951d366b40211320fb30826a76cb7a0da6400" +dependencies = [ + "bitflags", + "block", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + [[package]] name = "color_quant" version = "1.0.0" @@ -1098,6 +1115,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "display-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "303de632386f9c82eb7823456f5932bd40b4de9521078901767bf16a9f331491" +dependencies = [ + "foreign-types", + "objc", + "objc-foundation", + "time-point", +] + [[package]] name = "dlib" version = "0.4.1" @@ -1626,7 +1655,7 @@ checksum = "938ce7a2b1bbfe1535166133bea3f9c1b46350d2794b49561303575e9e1b9949" dependencies = [ "android_glue", "cgl 0.2.3", - "cocoa", + "cocoa 0.18.4", "core-foundation", "core-graphics", "derivative", @@ -2298,7 +2327,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2279a6faecd06034f88218f77f7a767693e0957bce0323a96d92747e2760b445" dependencies = [ - "cgl 0.3.0", + "cgl 0.3.2", "core-foundation", "gleam 0.7.0", "leaky-cow", @@ -2711,7 +2740,6 @@ dependencies = [ "msg", "net", "net_traits", - "offscreen_gl_context", "profile", "profile_traits", "script", @@ -2726,6 +2754,7 @@ dependencies = [ "sparkle", "style", "style_traits", + "surfman", "webdriver_server", "webrender", "webrender_api", @@ -2823,9 +2852,9 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" [[package]] name = "mach" -version = "0.2.3" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" dependencies = [ "libc", ] @@ -3377,27 +3406,6 @@ dependencies = [ "objc", ] -[[package]] -name = "offscreen_gl_context" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4df25a3f141e0f7c6e52d4e142879d5cea9b4f7ff2f975d0b9bbac8c60f46b" -dependencies = [ - "cgl 0.3.0", - "core-foundation", - "euclid", - "gl_generator 0.13.1", - "lazy_static", - "libloading", - "log", - "objc", - "osmesa-sys", - "serde", - "sparkle", - "winapi", - "x11", -] - [[package]] name = "opaque-debug" version = "0.2.1" @@ -3470,8 +3478,8 @@ checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" [[package]] name = "osmesa-src" -version = "0.1.0" -source = "git+https://github.com/servo/osmesa-src#97f4613fd80eee153ab134dfe349777bc5a27bab" +version = "0.1.1" +source = "git+https://github.com/servo/osmesa-src#1a9519c3675ebc1117cbb18ed6db420b5941cb8b" [[package]] name = "osmesa-sys" @@ -4589,7 +4597,7 @@ version = "0.30000023.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cf31d622cdfc24317eb1caa1018294f8058eb8315c9ed79103487b9504ddadb" dependencies = [ - "cgl 0.3.0", + "cgl 0.3.2", "cmake", "euclid", "expat-sys", @@ -4874,9 +4882,9 @@ dependencies = [ [[package]] name = "sparkle" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "035e10f288ef78257243f0a306b60940d0d3ab9cb3d9f06f0f0e9376d83ea769" +checksum = "25e193f97790240fc9208b077001c8331f4ccc801daa4df56efcb90e513c0989" dependencies = [ "gl_generator 0.13.1", ] @@ -5058,6 +5066,45 @@ dependencies = [ "webrender_api", ] +[[package]] +name = "surfman" +version = "0.23.0" +source = "git+https://github.com/pcwalton/surfman#a2a2999c07e8c650fac59ba371ebcf5cbf1b96f2" +dependencies = [ + "bitflags", + "cgl 0.3.2", + "cocoa 0.19.1", + "core-foundation", + "core-graphics", + "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]] +name = "surfman-chains" +version = "0.1.0" +source = "git+https://github.com/asajeffrey/surfman-chains#13576ac0cd1573057472ba85ce520bd881e856dc" +dependencies = [ + "euclid", + "fnv", + "log", + "sparkle", + "surfman", +] + [[package]] name = "svg_fmt" version = "0.4.0" @@ -5234,6 +5281,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "time-point" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06535c958d6abe68dc4b4ef9e6845f758fc42fe463d0093d0aca40254f03fb14" + [[package]] name = "tinyfiledialogs" version = "3.3.9" @@ -5727,7 +5780,7 @@ dependencies = [ "nix", "wayland-commons", "wayland-scanner", - "wayland-sys", + "wayland-sys 0.21.13", ] [[package]] @@ -5737,7 +5790,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c08896768b667e1df195d88a62a53a2d1351a1ed96188be79c196b35bb32ec" dependencies = [ "nix", - "wayland-sys", + "wayland-sys 0.21.13", ] [[package]] @@ -5750,7 +5803,7 @@ dependencies = [ "wayland-client", "wayland-commons", "wayland-scanner", - "wayland-sys", + "wayland-sys 0.21.13", ] [[package]] @@ -5774,6 +5827,16 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "wayland-sys" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "695d1a3f30f853d3b9b530df7d9ed1c32ff9b025b5d51529827a231521f2f2e4" +dependencies = [ + "dlib", + "lazy_static", +] + [[package]] name = "webdriver" version = "0.40.1" @@ -5932,7 +5995,7 @@ dependencies = [ [[package]] name = "webxr" version = "0.0.1" -source = "git+https://github.com/servo/webxr#61344bc5d92bc218458063baa7bc5d2d388aa7f5" +source = "git+https://github.com/servo/webxr#94bf6c6f64007a42d74ee4d1d162a5ed4d32d12a" dependencies = [ "bindgen", "euclid", @@ -5942,6 +6005,7 @@ dependencies = [ "log", "openxr", "serde", + "surfman", "webxr-api", "winapi", "wio", @@ -5950,13 +6014,15 @@ dependencies = [ [[package]] name = "webxr-api" version = "0.0.1" -source = "git+https://github.com/servo/webxr#61344bc5d92bc218458063baa7bc5d2d388aa7f5" +source = "git+https://github.com/servo/webxr#94bf6c6f64007a42d74ee4d1d162a5ed4d32d12a" dependencies = [ "euclid", - "gleam 0.6.18", "ipc-channel", "log", "serde", + "surfman", + "surfman-chains", + "winit", ] [[package]] @@ -6015,7 +6081,7 @@ dependencies = [ "android_glue", "backtrace", "bitflags", - "cocoa", + "cocoa 0.18.4", "core-foundation", "core-graphics", "lazy_static", diff --git a/components/background_hang_monitor/Cargo.toml b/components/background_hang_monitor/Cargo.toml index 25c183a374c..0b2e3cea7ac 100644 --- a/components/background_hang_monitor/Cargo.toml +++ b/components/background_hang_monitor/Cargo.toml @@ -25,7 +25,7 @@ crossbeam-channel = "0.3" lazy_static = "1.0" [target.'cfg(target_os = "macos")'.dependencies] -mach = "0.2.3" +mach = "0.3" [target.'cfg(all(target_os = "linux", not(any(target_arch = "arm", target_arch = "aarch64"))))'.dependencies] nix = "0.14" diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index b96b6a9b81c..6b0f1005b47 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -14,10 +14,11 @@ path = "lib.rs" canvas2d-azure = ["azure"] canvas2d-raqote = ["raqote"] webgl_backtrace = ["canvas_traits/webgl_backtrace"] -no_wgl = ["offscreen_gl_context/no_wgl"] +no-wgl = ["surfman/sm-no-wgl"] [dependencies] azure = {git = "https://github.com/servo/rust-azure", optional = true} +bitflags = "1.0" byteorder = "1" canvas_traits = {path = "../canvas_traits"} cssparser = "0.27.1" @@ -29,12 +30,14 @@ half = "1" ipc-channel = "0.12" log = "0.4" num-traits = "0.2" -offscreen_gl_context = {version = "0.25", features = ["serde", "osmesa"]} raqote = {git = "https://github.com/jrmuizel/raqote", optional = true} pixels = {path = "../pixels"} servo_config = {path = "../config"} -sparkle = "0.1" +sparkle = "0.1.8" webrender = {git = "https://github.com/servo/webrender"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} webrender_traits = {path = "../webrender_traits"} webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]} +# NOTE: the sm-angle feature only enables angle on windows, not other platforms! +surfman = { git = "https://github.com/pcwalton/surfman", features = ["sm-angle", "sm-osmesa"] } +surfman-chains = { git = "https://github.com/asajeffrey/surfman-chains" } diff --git a/components/canvas/gl_context.rs b/components/canvas/gl_context.rs deleted file mode 100644 index 7e6c4c135a2..00000000000 --- a/components/canvas/gl_context.rs +++ /dev/null @@ -1,283 +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 super::webgl_thread::{GLState, WebGLImpl}; -use canvas_traits::webgl::{ - GLContextAttributes, GLFormats, GLLimits, WebGLCommand, WebGLCommandBacktrace, WebGLVersion, -}; -use euclid::default::Size2D; -use offscreen_gl_context::{ - ColorAttachmentType, DrawBuffer, GLContext, GLContextAttributes as RawGLContextAttributes, - GLContextDispatcher, -}; -use offscreen_gl_context::{GLFormats as RawGLFormats, GLLimits as RawGLLimits, GLVersion}; -use offscreen_gl_context::{NativeGLContext, NativeGLContextHandle, NativeGLContextMethods}; -use offscreen_gl_context::{OSMesaContext, OSMesaContextHandle}; -use sparkle::gl; - -pub trait CloneableDispatcher: GLContextDispatcher { - fn clone(&self) -> Box; -} - -/// The GLContextFactory is used to create shared GL contexts with the main thread GL context. -/// Currently, shared textures are used to render WebGL textures into the WR compositor. -/// In order to create a shared context, the GLContextFactory stores the handle of the main GL context. -pub enum GLContextFactory { - Native( - NativeGLContextHandle, - Option>, - gl::GlType, - ), - OSMesa(OSMesaContextHandle), -} - -impl GLContextFactory { - /// Creates a new GLContextFactory that uses the currently bound GL context to create shared contexts. - pub fn current_native_handle( - dispatcher: Box, - api_type: gl::GlType, - ) -> Option { - let dispatcher = if cfg!(target_os = "windows") { - // Used to dispatch functions from the GLContext thread to the main thread's - // event loop. Required to allow WGL GLContext sharing in Windows. - Some(dispatcher) - } else { - None - }; - // FIXME(emilio): This assumes a single GL backend per platform which is - // not true on Linux, we probably need a third `Egl` variant or abstract - // it a bit more... - NativeGLContext::current_handle() - .map(|handle| GLContextFactory::Native(handle, dispatcher, api_type)) - } - - /// Creates a new GLContextFactory that uses the currently bound OSMesa context to create shared contexts. - pub fn current_osmesa_handle() -> Option { - OSMesaContext::current_handle().map(GLContextFactory::OSMesa) - } - - /// Creates a new shared GLContext with the main GLContext - pub fn new_shared_context( - &self, - webgl_version: WebGLVersion, - size: Size2D, - attributes: GLContextAttributes, - ) -> Result { - let attributes = map_attrs(attributes); - Ok(match *self { - GLContextFactory::Native(ref handle, ref dispatcher, ref api_type) => { - GLContextWrapper::Native(GLContext::new_shared_with_dispatcher( - // FIXME(nox): Why are those i32 values? - size.to_i32(), - attributes, - ColorAttachmentType::Texture, - *api_type, - Self::gl_version(webgl_version), - Some(handle), - dispatcher.as_ref().map(|d| (**d).clone()), - )?) - }, - GLContextFactory::OSMesa(ref handle) => { - GLContextWrapper::OSMesa(GLContext::new_shared_with_dispatcher( - // FIXME(nox): Why are those i32 values? - size.to_i32(), - attributes, - ColorAttachmentType::Texture, - gl::GlType::Gl, - Self::gl_version(webgl_version), - Some(handle), - None, - )?) - }, - }) - } - - /// Creates a new non-shared GLContext - pub fn new_context( - &self, - webgl_version: WebGLVersion, - size: Size2D, - attributes: GLContextAttributes, - ) -> Result { - let attributes = map_attrs(attributes); - Ok(match *self { - GLContextFactory::Native(_, _, ref api_type) => { - GLContextWrapper::Native(GLContext::new_shared_with_dispatcher( - // FIXME(nox): Why are those i32 values? - size.to_i32(), - attributes, - ColorAttachmentType::Texture, - *api_type, - Self::gl_version(webgl_version), - None, - None, - )?) - }, - GLContextFactory::OSMesa(_) => { - GLContextWrapper::OSMesa(GLContext::new_shared_with_dispatcher( - // FIXME(nox): Why are those i32 values? - size.to_i32(), - attributes, - ColorAttachmentType::Texture, - gl::GlType::Gl, - Self::gl_version(webgl_version), - None, - None, - )?) - }, - }) - } - - fn gl_version(webgl_version: WebGLVersion) -> GLVersion { - match webgl_version { - WebGLVersion::WebGL1 => GLVersion::Major(2), - WebGLVersion::WebGL2 => GLVersion::Major(3), - } - } -} - -/// GLContextWrapper used to abstract NativeGLContext and OSMesaContext types -pub enum GLContextWrapper { - Native(GLContext), - OSMesa(GLContext), -} - -impl GLContextWrapper { - pub fn make_current(&self) { - match *self { - GLContextWrapper::Native(ref ctx) => { - ctx.make_current().unwrap(); - }, - GLContextWrapper::OSMesa(ref ctx) => { - ctx.make_current().unwrap(); - }, - } - } - - pub fn apply_command( - &self, - cmd: WebGLCommand, - use_apple_vertex_array: bool, - backtrace: WebGLCommandBacktrace, - state: &mut GLState, - ) { - match *self { - GLContextWrapper::Native(ref ctx) => { - WebGLImpl::apply(ctx, state, use_apple_vertex_array, cmd, backtrace); - }, - GLContextWrapper::OSMesa(ref ctx) => { - WebGLImpl::apply(ctx, state, false, cmd, backtrace); - }, - } - } - - pub fn gl(&self) -> &gl::Gl { - match *self { - GLContextWrapper::Native(ref ctx) => ctx.gl(), - GLContextWrapper::OSMesa(ref ctx) => ctx.gl(), - } - } - - pub fn framebuffer(&self) -> gl::GLuint { - match *self { - GLContextWrapper::Native(ref ctx) => { - ctx.borrow_draw_buffer().unwrap().get_framebuffer() - }, - GLContextWrapper::OSMesa(ref ctx) => { - ctx.borrow_draw_buffer().unwrap().get_framebuffer() - }, - } - } - - pub fn get_info(&self) -> (Size2D, u32, GLLimits, GLFormats) { - match *self { - GLContextWrapper::Native(ref ctx) => { - let (real_size, texture_id) = { - let draw_buffer = ctx.borrow_draw_buffer().unwrap(); - ( - draw_buffer.size(), - draw_buffer.get_bound_texture_id().unwrap(), - ) - }; - - let limits = ctx.borrow_limits().clone(); - let formats = map_formats(ctx.borrow_formats()); - - (real_size, texture_id, map_limits(limits), formats) - }, - GLContextWrapper::OSMesa(ref ctx) => { - let (real_size, texture_id) = { - let draw_buffer = ctx.borrow_draw_buffer().unwrap(); - ( - draw_buffer.size(), - draw_buffer.get_bound_texture_id().unwrap(), - ) - }; - - let limits = ctx.borrow_limits().clone(); - let formats = map_formats(ctx.borrow_formats()); - - (real_size, texture_id, map_limits(limits), formats) - }, - } - } - - pub fn resize(&mut self, size: Size2D) -> Result { - match *self { - GLContextWrapper::Native(ref mut ctx) => { - // FIXME(nox): Why are those i32 values? - ctx.resize(size.to_i32()) - }, - GLContextWrapper::OSMesa(ref mut ctx) => { - // FIXME(nox): Why are those i32 values? - ctx.resize(size.to_i32()) - }, - } - } -} - -fn map_limits(limits: RawGLLimits) -> GLLimits { - GLLimits { - max_vertex_attribs: limits.max_vertex_attribs, - max_tex_size: limits.max_tex_size, - max_cube_map_tex_size: limits.max_cube_map_tex_size, - max_combined_texture_image_units: limits.max_combined_texture_image_units, - max_fragment_uniform_vectors: limits.max_fragment_uniform_vectors, - max_renderbuffer_size: limits.max_renderbuffer_size, - max_texture_image_units: limits.max_texture_image_units, - max_varying_vectors: limits.max_varying_vectors, - max_vertex_texture_image_units: limits.max_vertex_texture_image_units, - max_vertex_uniform_vectors: limits.max_vertex_uniform_vectors, - max_client_wait_timeout_webgl: std::time::Duration::new(1, 0), - } -} - -pub fn map_attrs(attrs: GLContextAttributes) -> RawGLContextAttributes { - RawGLContextAttributes { - alpha: attrs.alpha, - depth: attrs.depth, - stencil: attrs.stencil, - antialias: attrs.antialias, - premultiplied_alpha: attrs.premultiplied_alpha, - preserve_drawing_buffer: attrs.preserve_drawing_buffer, - } -} - -pub fn map_attrs_to_script_attrs(attrs: RawGLContextAttributes) -> GLContextAttributes { - GLContextAttributes { - alpha: attrs.alpha, - depth: attrs.depth, - stencil: attrs.stencil, - antialias: attrs.antialias, - premultiplied_alpha: attrs.premultiplied_alpha, - preserve_drawing_buffer: attrs.preserve_drawing_buffer, - } -} - -fn map_formats(formats: &RawGLFormats) -> GLFormats { - GLFormats { - texture_format: formats.texture, - texture_type: formats.texture_type, - } -} diff --git a/components/canvas/lib.rs b/components/canvas/lib.rs index ba10f02636c..b61e32a63e8 100644 --- a/components/canvas/lib.rs +++ b/components/canvas/lib.rs @@ -4,6 +4,8 @@ #![deny(unsafe_code)] +#[macro_use] +extern crate bitflags; #[macro_use] extern crate log; @@ -13,8 +15,10 @@ mod azure_backend; #[cfg(feature = "canvas2d-raqote")] mod raqote_backend; +pub use webgl_mode::WebGLComm; + pub mod canvas_data; pub mod canvas_paint_thread; -pub mod gl_context; +mod webgl_limits; mod webgl_mode; pub mod webgl_thread; diff --git a/components/canvas/webgl_limits.rs b/components/canvas/webgl_limits.rs new file mode 100644 index 00000000000..23630117515 --- /dev/null +++ b/components/canvas/webgl_limits.rs @@ -0,0 +1,96 @@ +/* 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 canvas_traits::webgl::GLLimits; +use sparkle::gl; +use sparkle::gl::GLenum; +use sparkle::gl::Gl; + +pub trait GLLimitsDetect { + fn detect(gl: &Gl) -> Self; +} + +impl GLLimitsDetect for GLLimits { + fn detect(gl: &Gl) -> GLLimits { + let max_vertex_attribs = gl.get_integer(gl::MAX_VERTEX_ATTRIBS); + let max_tex_size = gl.get_integer(gl::MAX_TEXTURE_SIZE); + let max_cube_map_tex_size = gl.get_integer(gl::MAX_CUBE_MAP_TEXTURE_SIZE); + let max_combined_texture_image_units = gl.get_integer(gl::MAX_COMBINED_TEXTURE_IMAGE_UNITS); + let max_renderbuffer_size = gl.get_integer(gl::MAX_RENDERBUFFER_SIZE); + let max_texture_image_units = gl.get_integer(gl::MAX_TEXTURE_IMAGE_UNITS); + let max_vertex_texture_image_units = gl.get_integer(gl::MAX_VERTEX_TEXTURE_IMAGE_UNITS); + + // TODO: better value for this? + let max_client_wait_timeout_webgl = std::time::Duration::new(1, 0); + + // Based on: + // https://searchfox.org/mozilla-central/rev/5a744713370ec47969595e369fd5125f123e6d24/dom/canvas/WebGLContextValidate.cpp#523-558 + let (max_fragment_uniform_vectors, max_varying_vectors, max_vertex_uniform_vectors); + match gl.try_get_integer(gl::MAX_FRAGMENT_UNIFORM_VECTORS) { + Some(max_vectors) => { + max_fragment_uniform_vectors = max_vectors; + max_varying_vectors = gl.get_integer(gl::MAX_VARYING_VECTORS); + max_vertex_uniform_vectors = gl.get_integer(gl::MAX_VERTEX_UNIFORM_VECTORS); + }, + None => { + let max_fragment_uniform_components = + gl.get_integer(gl::MAX_FRAGMENT_UNIFORM_COMPONENTS); + let max_vertex_uniform_components = + gl.get_integer(gl::MAX_VERTEX_UNIFORM_COMPONENTS); + + let max_vertex_output_components = gl + .try_get_integer(gl::MAX_VERTEX_OUTPUT_COMPONENTS) + .unwrap_or(0); + let max_fragment_input_components = gl + .try_get_integer(gl::MAX_FRAGMENT_INPUT_COMPONENTS) + .unwrap_or(0); + let max_varying_components = max_vertex_output_components + .min(max_fragment_input_components) + .max(16); + + max_fragment_uniform_vectors = max_fragment_uniform_components / 4; + max_varying_vectors = max_varying_components / 4; + max_vertex_uniform_vectors = max_vertex_uniform_components / 4; + }, + } + + GLLimits { + max_vertex_attribs, + max_tex_size, + max_cube_map_tex_size, + max_combined_texture_image_units, + max_fragment_uniform_vectors, + max_renderbuffer_size, + max_texture_image_units, + max_varying_vectors, + max_vertex_texture_image_units, + max_vertex_uniform_vectors, + max_client_wait_timeout_webgl, + } + } +} + +trait GLExt { + fn try_get_integer(self, parameter: GLenum) -> Option; + fn get_integer(self, parameter: GLenum) -> u32; +} + +impl<'a> GLExt for &'a Gl { + #[allow(unsafe_code)] + fn try_get_integer(self, parameter: GLenum) -> Option { + let mut value = [0]; + unsafe { + self.get_integer_v(parameter, &mut value); + } + if self.get_error() != gl::NO_ERROR { + None + } else { + Some(value[0] as u32) + } + } + + fn get_integer(self, parameter: GLenum) -> u32 { + self.try_get_integer(parameter).unwrap() + } +} diff --git a/components/canvas/webgl_mode/inprocess.rs b/components/canvas/webgl_mode/inprocess.rs index b7b7189bd96..3fff950a70d 100644 --- a/components/canvas/webgl_mode/inprocess.rs +++ b/components/canvas/webgl_mode/inprocess.rs @@ -1,224 +1,160 @@ /* 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 crate::gl_context::GLContextFactory; -use crate::webgl_thread::{WebGLMainThread, WebGLThread, WebGLThreadInit}; -use canvas_traits::webgl::webgl_channel; -use canvas_traits::webgl::DOMToTextureCommand; -use canvas_traits::webgl::{WebGLChan, WebGLContextId, WebGLMsg, WebGLPipeline, WebGLReceiver}; -use canvas_traits::webgl::{WebGLSender, WebVRRenderHandler}; -use embedder_traits::EventLoopWaker; + +use crate::webgl_thread::{WebGLThread, WebGLThreadInit}; +use canvas_traits::webgl::{webgl_channel, WebVRRenderHandler}; +use canvas_traits::webgl::{WebGLContextId, WebGLMsg, WebGLThreads}; use euclid::default::Size2D; use fnv::FnvHashMap; -use gleam::gl; +use gleam; use servo_config::pref; +use sparkle::gl; +use sparkle::gl::GlType; use std::default::Default; use std::rc::Rc; use std::sync::{Arc, Mutex}; +use surfman::platform::generic::universal::context::Context; +use surfman::platform::generic::universal::device::Device; +use surfman::platform::generic::universal::surface::SurfaceTexture; +use surfman_chains::SwapChains; use webrender_traits::{WebrenderExternalImageApi, WebrenderExternalImageRegistry}; -use webxr_api::WebGLExternalImageApi; +use webxr_api::SwapChainId as WebXRSwapChainId; -/// WebGL Threading API entry point that lives in the constellation. -pub struct WebGLThreads(WebGLSender); - -pub enum ThreadMode { - MainThread(Box), - OffThread, +pub struct WebGLComm { + pub webgl_threads: WebGLThreads, + pub webxr_swap_chains: SwapChains, + pub image_handler: Box, + pub output_handler: Option>, } -impl WebGLThreads { - /// Creates a new WebGLThreads object +impl WebGLComm { + /// Creates a new `WebGLComm` object. pub fn new( - gl_factory: GLContextFactory, - webrender_gl: Rc, + device: Device, + context: Context, + webrender_gl: Rc, webrender_api_sender: webrender_api::RenderApiSender, webvr_compositor: Option>, external_images: Arc>, - mode: ThreadMode, - ) -> ( - WebGLThreads, - Option>, - Box, - Box, - Option>, - ) { + api_type: GlType, + ) -> WebGLComm { + debug!("WebGLThreads::new()"); let (sender, receiver) = webgl_channel::().unwrap(); + let webrender_swap_chains = SwapChains::new(); + let webxr_swap_chains = SwapChains::new(); + // This implementation creates a single `WebGLThread` for all the pipelines. let init = WebGLThreadInit { - gl_factory, webrender_api_sender, webvr_compositor, external_images, sender: sender.clone(), receiver, + webrender_swap_chains: webrender_swap_chains.clone(), + webxr_swap_chains: webxr_swap_chains.clone(), + connection: device.connection(), + adapter: device.adapter(), + api_type, }; let output_handler = if pref!(dom.webgl.dom_to_texture.enabled) { - Some(Box::new(OutputHandler::new( - webrender_gl.clone(), - sender.clone(), - ))) + Some(Box::new(OutputHandler::new(webrender_gl.clone()))) } else { None }; - let external = WebGLExternalImages::new(webrender_gl, sender.clone()); + let external = WebGLExternalImages::new(device, context, webrender_swap_chains); - let webgl_thread = match mode { - ThreadMode::MainThread(event_loop_waker) => { - let thread = WebGLThread::run_on_current_thread(init, event_loop_waker); - Some(thread) - }, - ThreadMode::OffThread => { - WebGLThread::run_on_own_thread(init); - None - }, - }; + WebGLThread::run_on_own_thread(init); - ( - WebGLThreads(sender), - webgl_thread, - external.sendable.clone_box(), - Box::new(external), - output_handler.map(|b| b as Box<_>), - ) - } - - /// Gets the WebGLThread handle for each script pipeline. - pub fn pipeline(&self) -> WebGLPipeline { - // This mode creates a single thread, so the existing WebGLChan is just cloned. - WebGLPipeline(WebGLChan(self.0.clone())) - } - - /// Sends a exit message to close the WebGLThreads and release all WebGLContexts. - pub fn exit(&self) -> Result<(), &'static str> { - self.0 - .send(WebGLMsg::Exit) - .map_err(|_| "Failed to send Exit message") - } -} - -/// Bridge between the webxr_api::ExternalImage callbacks and the WebGLThreads. -struct SendableWebGLExternalImages { - webgl_channel: WebGLSender, - // Used to avoid creating a new channel on each received WebRender request. - lock_channel: ( - WebGLSender<(u32, Size2D, usize)>, - WebGLReceiver<(u32, Size2D, usize)>, - ), -} - -impl SendableWebGLExternalImages { - fn new(channel: WebGLSender) -> Self { - Self { - webgl_channel: channel, - lock_channel: webgl_channel().unwrap(), + WebGLComm { + webgl_threads: WebGLThreads(sender), + webxr_swap_chains, + image_handler: Box::new(external), + output_handler: output_handler.map(|b| b as Box<_>), } } } -impl SendableWebGLExternalImages { - fn lock_and_get_current_texture(&self, id: usize) -> (u32, Size2D, Option) { - if let Some(main_thread) = WebGLMainThread::on_current_thread() { - // If we're on the same thread as WebGL, we can get the data directly - let (image_id, size) = main_thread - .thread_data - .borrow_mut() - .handle_lock_unsync(WebGLContextId(id as usize)); - // We don't need a GLsync object if we're running on the main thread - // Might be better to return an option? - (image_id, size, None) - } else { - // WebGL Thread has it's own GL command queue that we need to synchronize with the WR GL command queue. - // The WebGLMsg::Lock message inserts a fence in the WebGL command queue. - self.webgl_channel - .send(WebGLMsg::Lock( - WebGLContextId(id as usize), - self.lock_channel.0.clone(), - )) - .unwrap(); - let (image_id, size, gl_sync) = self.lock_channel.1.recv().unwrap(); - (image_id, size, Some(gl_sync as gl::GLsync)) - } - } -} - -impl webxr_api::WebGLExternalImageApi for SendableWebGLExternalImages { - fn lock(&self, id: usize) -> Option { - let (_, _, gl_sync) = self.lock_and_get_current_texture(id); - gl_sync - } - - fn unlock(&self, id: usize) { - if let Some(main_thread) = WebGLMainThread::on_current_thread() { - // If we're on the same thread as WebGL, we can unlock directly - main_thread - .thread_data - .borrow_mut() - .handle_unlock(WebGLContextId(id as usize)) - } else { - self.webgl_channel - .send(WebGLMsg::Unlock(WebGLContextId(id as usize))) - .unwrap() - } - } - - fn clone_box(&self) -> Box { - Box::new(Self::new(self.webgl_channel.clone())) - } -} - /// Bridge between the webrender::ExternalImage callbacks and the WebGLThreads. struct WebGLExternalImages { - webrender_gl: Rc, - sendable: SendableWebGLExternalImages, + device: Device, + context: Context, + swap_chains: SwapChains, + locked_front_buffers: FnvHashMap, +} + +impl Drop for WebGLExternalImages { + fn drop(&mut self) { + let _ = self.device.destroy_context(&mut self.context); + } } impl WebGLExternalImages { - fn new(webrender_gl: Rc, channel: WebGLSender) -> Self { + fn new(device: Device, context: Context, swap_chains: SwapChains) -> Self { Self { - webrender_gl, - sendable: SendableWebGLExternalImages::new(channel), + device, + context, + swap_chains, + locked_front_buffers: FnvHashMap::default(), } } + + fn lock_swap_chain(&mut self, id: WebGLContextId) -> Option<(u32, Size2D)> { + debug!("... locking chain {:?}", id); + let front_buffer = self.swap_chains.get(id)?.take_surface()?; + + debug!("... getting texture for surface {:?}", front_buffer.id()); + let size = front_buffer.size(); + let front_buffer_texture = self + .device + .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); + + Some((gl_texture, size)) + } + + fn unlock_swap_chain(&mut self, id: WebGLContextId) -> Option<()> { + let locked_front_buffer = self.locked_front_buffers.remove(&id)?; + let locked_front_buffer = self + .device + .destroy_surface_texture(&mut self.context, locked_front_buffer) + .unwrap(); + + debug!("... unlocked chain {:?}", id); + self.swap_chains + .get(id)? + .recycle_surface(locked_front_buffer); + Some(()) + } } impl WebrenderExternalImageApi for WebGLExternalImages { fn lock(&mut self, id: u64) -> (u32, Size2D) { - let (image_id, size, gl_sync) = self.sendable.lock_and_get_current_texture(id as usize); - // The next glWaitSync call is run on the WR thread and it's used to synchronize the two - // flows of OpenGL commands in order to avoid WR using a semi-ready WebGL texture. - // glWaitSync doesn't block WR thread, it affects only internal OpenGL subsystem. - if let Some(gl_sync) = gl_sync { - self.webrender_gl.wait_sync(gl_sync, 0, gl::TIMEOUT_IGNORED); - } - (image_id, size) + let id = WebGLContextId(id); + self.lock_swap_chain(id).unwrap_or_default() } fn unlock(&mut self, id: u64) { - self.sendable.unlock(id as usize); + let id = WebGLContextId(id); + self.unlock_swap_chain(id); } } /// struct used to implement DOMToTexture feature and webrender::OutputImageHandler trait. -type OutputHandlerData = Option<(u32, Size2D)>; struct OutputHandler { - webrender_gl: Rc, - webgl_channel: WebGLSender, - // Used to avoid creating a new channel on each received WebRender request. - lock_channel: ( - WebGLSender, - WebGLReceiver, - ), - sync_objects: FnvHashMap, + webrender_gl: Rc, + sync_objects: FnvHashMap, } impl OutputHandler { - fn new(webrender_gl: Rc, channel: WebGLSender) -> Self { + fn new(webrender_gl: Rc) -> Self { OutputHandler { webrender_gl, - webgl_channel: channel, - lock_channel: webgl_channel().unwrap(), sync_objects: Default::default(), } } @@ -235,28 +171,8 @@ impl webrender::OutputImageHandler for OutputHandler { .webrender_gl .fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0); self.sync_objects.insert(id, gl_sync); - - let result = if let Some(main_thread) = WebGLMainThread::on_current_thread() { - main_thread - .thread_data - .borrow_mut() - .handle_dom_to_texture_lock(id, gl_sync as usize) - } else { - // The lock command adds a WaitSync call on the WebGL command flow. - let command = - DOMToTextureCommand::Lock(id, gl_sync as usize, self.lock_channel.0.clone()); - self.webgl_channel - .send(WebGLMsg::DOMToTextureCommand(command)) - .unwrap(); - self.lock_channel.1.recv().unwrap() - }; - - result.map(|(tex_id, size)| { - ( - tex_id, - webrender_api::units::FramebufferIntSize::new(size.width, size.height), - ) - }) + // https://github.com/servo/servo/issues/24615 + None } fn unlock(&mut self, id: webrender_api::PipelineId) { diff --git a/components/canvas/webgl_mode/mod.rs b/components/canvas/webgl_mode/mod.rs index 5aa85947d21..8bc74f6e244 100644 --- a/components/canvas/webgl_mode/mod.rs +++ b/components/canvas/webgl_mode/mod.rs @@ -3,4 +3,5 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ mod inprocess; -pub use self::inprocess::{ThreadMode, WebGLThreads}; + +pub use self::inprocess::WebGLComm; diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index a2e95955753..00e38dfc56f 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -2,63 +2,106 @@ * 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 super::gl_context::{map_attrs_to_script_attrs, GLContextFactory, GLContextWrapper}; +use crate::webgl_limits::GLLimitsDetect; use byteorder::{ByteOrder, NativeEndian, WriteBytesExt}; -use canvas_traits::webgl::*; -use embedder_traits::EventLoopWaker; +use canvas_traits::webgl; +use canvas_traits::webgl::ActiveAttribInfo; +use canvas_traits::webgl::ActiveUniformInfo; +use canvas_traits::webgl::AlphaTreatment; +use canvas_traits::webgl::DOMToTextureCommand; +use canvas_traits::webgl::GLContextAttributes; +use canvas_traits::webgl::GLLimits; +use canvas_traits::webgl::GlType; +use canvas_traits::webgl::ProgramLinkInfo; +use canvas_traits::webgl::SwapChainId; +use canvas_traits::webgl::TexDataType; +use canvas_traits::webgl::TexFormat; +use canvas_traits::webgl::WebGLBufferId; +use canvas_traits::webgl::WebGLChan; +use canvas_traits::webgl::WebGLCommand; +use canvas_traits::webgl::WebGLCommandBacktrace; +use canvas_traits::webgl::WebGLContextId; +use canvas_traits::webgl::WebGLCreateContextResult; +use canvas_traits::webgl::WebGLFramebufferBindingRequest; +use canvas_traits::webgl::WebGLFramebufferId; +use canvas_traits::webgl::WebGLMsg; +use canvas_traits::webgl::WebGLMsgSender; +use canvas_traits::webgl::WebGLOpaqueFramebufferId; +use canvas_traits::webgl::WebGLProgramId; +use canvas_traits::webgl::WebGLQueryId; +use canvas_traits::webgl::WebGLReceiver; +use canvas_traits::webgl::WebGLRenderbufferId; +use canvas_traits::webgl::WebGLSLVersion; +use canvas_traits::webgl::WebGLSamplerId; +use canvas_traits::webgl::WebGLSender; +use canvas_traits::webgl::WebGLShaderId; +use canvas_traits::webgl::WebGLSyncId; +use canvas_traits::webgl::WebGLTextureId; +use canvas_traits::webgl::WebGLTransparentFramebufferId; +use canvas_traits::webgl::WebGLVersion; +use canvas_traits::webgl::WebGLVertexArrayId; +use canvas_traits::webgl::WebVRCommand; +use canvas_traits::webgl::WebVRRenderHandler; +use canvas_traits::webgl::YAxisTreatment; use euclid::default::Size2D; use fnv::FnvHashMap; use half::f16; -use ipc_channel::ipc::{self, OpaqueIpcMessage}; -use ipc_channel::router::ROUTER; -use offscreen_gl_context::{DrawBuffer, GLContext, NativeGLContextMethods}; use pixels::{self, PixelFormat}; -use sparkle::gl::{self, Gl}; +use servo_config::opts; +use sparkle::gl; +use sparkle::gl::GLint; +use sparkle::gl::GLuint; +use sparkle::gl::Gl; use std::borrow::Cow; -use std::cell::Cell; -use std::cell::RefCell; -use std::mem; +use std::cell::{Cell, RefCell}; use std::rc::Rc; use std::sync::{Arc, Mutex}; use std::thread; +use surfman; +use surfman::platform::generic::universal::adapter::Adapter; +use surfman::platform::generic::universal::connection::Connection; +use surfman::platform::generic::universal::context::Context; +use surfman::platform::generic::universal::device::Device; +use surfman::ContextAttributeFlags; +use surfman::ContextAttributes; +use surfman::GLVersion; +use surfman::SurfaceAccess; +use surfman::SurfaceType; +use surfman_chains::SwapChains; use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType}; - -/// WebGL Threading API entry point that lives in the constellation. -/// It allows to get a WebGLThread handle for each script pipeline. -pub use crate::webgl_mode::{ThreadMode, WebGLThreads}; +use webxr_api::SwapChainId as WebXRSwapChainId; struct GLContextData { - ctx: GLContextWrapper, + ctx: Context, + gl: Rc, state: GLState, - use_apple_vertex_arrays: bool, -} - -// rust-offscreen-rendering-context creates a legacy OpenGL context on macOS when -// OpenGL 2 support is requested. Legacy contexts return GL errors for the vertex -// array object functions, but support a set of APPLE extension functions that -// provide VAO support instead. -fn needs_apple_vertex_arrays(gl: &gl::Gl, version: WebGLVersion) -> bool { - cfg!(target_os = "macos") && gl.get_type() == gl::GlType::Gl && version == WebGLVersion::WebGL1 + attributes: GLContextAttributes, } pub struct GLState { + webgl_version: WebGLVersion, + gl_version: GLVersion, clear_color: (f32, f32, f32, f32), scissor_test_enabled: bool, stencil_write_mask: (u32, u32), stencil_clear_value: i32, depth_write_mask: bool, depth_clear_value: f64, + default_vao: gl::GLuint, } impl Default for GLState { fn default() -> GLState { GLState { + gl_version: GLVersion { major: 1, minor: 0 }, + webgl_version: WebGLVersion::WebGL1, clear_color: (0., 0., 0., 0.), scissor_test_enabled: false, stencil_write_mask: (0, 0), stencil_clear_value: 0, depth_write_mask: true, depth_clear_value: 1., + default_vao: 0, } } } @@ -66,8 +109,8 @@ impl Default for GLState { /// A WebGLThread manages the life cycle and message multiplexing of /// a set of WebGLContexts living in the same thread. pub(crate) struct WebGLThread { - /// Factory used to create a new GLContext shared with the WR/Main thread. - gl_factory: GLContextFactory, + /// The GPU device. + device: Device, /// Channel used to generate/update or delete `webrender_api::ImageKey`s. webrender_api: webrender_api::RenderApi, /// Map of live WebGLContexts. @@ -77,6 +120,8 @@ pub(crate) struct WebGLThread { /// Current bound context. bound_context_id: Option, /// Handler user to send WebVR commands. + // TODO: replace webvr implementation with one built on top of webxr + #[allow(dead_code)] webvr_compositor: Option>, /// Texture ids and sizes used in DOM to texture outputs. dom_outputs: FnvHashMap, @@ -87,6 +132,12 @@ pub(crate) struct WebGLThread { receiver: WebGLReceiver, /// The receiver that should be used to send WebGL messages for processing. sender: WebGLSender, + /// The swap chains used by webrender + webrender_swap_chains: SwapChains, + /// The swap chains used by webxr + webxr_swap_chains: SwapChains, + /// Whether this context is a GL or GLES context. + api_type: gl::GlType, } #[derive(PartialEq)] @@ -97,12 +148,16 @@ enum EventLoop { /// The data required to initialize an instance of the WebGLThread type. pub(crate) struct WebGLThreadInit { - pub gl_factory: GLContextFactory, pub webrender_api_sender: webrender_api::RenderApiSender, pub webvr_compositor: Option>, pub external_images: Arc>, pub sender: WebGLSender, pub receiver: WebGLReceiver, + pub webrender_swap_chains: SwapChains, + pub webxr_swap_chains: SwapChains, + pub connection: Connection, + pub adapter: Adapter, + pub api_type: gl::GlType, } /// The extra data required to run an instance of WebGLThread when it is @@ -130,32 +185,33 @@ impl WebGLMainThread { WEBGL_MAIN_THREAD.with(|thread_data| thread_data.borrow_mut().take()); } } - - /// Returns the main GL thread if called from the main thread, - /// and `None` otherwise. - pub(crate) fn on_current_thread() -> Option> { - WEBGL_MAIN_THREAD.with(|main_thread| main_thread.borrow().clone()) - } } thread_local! { static WEBGL_MAIN_THREAD: RefCell>> = RefCell::new(None); } +// A size at which it should be safe to create GL contexts +const SAFE_VIEWPORT_DIMS: [u32; 2] = [1024, 1024]; + impl WebGLThread { /// Create a new instance of WebGLThread. pub(crate) fn new( WebGLThreadInit { - gl_factory, webrender_api_sender, webvr_compositor, external_images, sender, receiver, + webrender_swap_chains, + webxr_swap_chains, + connection, + adapter, + api_type, }: WebGLThreadInit, ) -> Self { WebGLThread { - gl_factory, + device: Device::new(&connection, &adapter).expect("Couldn't open WebGL device!"), webrender_api: webrender_api_sender.create_api(), contexts: Default::default(), cached_context_info: Default::default(), @@ -165,46 +221,12 @@ impl WebGLThread { external_images, sender, receiver, + webrender_swap_chains, + webxr_swap_chains, + api_type, } } - /// Perform all initialization required to run an instance of WebGLThread - /// concurrently on the current thread. Returns a `WebGLMainThread` instance - /// that can be used to process any outstanding WebGL messages at any given - /// point in time. - pub(crate) fn run_on_current_thread( - mut init: WebGLThreadInit, - event_loop_waker: Box, - ) -> Rc { - if let WebGLReceiver::Ipc(ref mut receiver) = init.receiver { - // Interpose a new channel in between the existing WebGL channel endpoints. - // This will bounce all WebGL messages through the router thread adding a small - // delay, but this will also ensure that the main thread will wake up and - // process the WebGL message when it arrives. - let (from_router_sender, from_router_receiver) = ipc::channel::().unwrap(); - let old_receiver = mem::replace(receiver, from_router_receiver); - ROUTER.add_route( - old_receiver.to_opaque(), - Box::new(move |msg: OpaqueIpcMessage| { - let _ = from_router_sender.send(msg.to().unwrap()); - event_loop_waker.wake(); - }), - ); - } - - let result = Rc::new(WebGLMainThread { - thread_data: RefCell::new(WebGLThread::new(init)), - shut_down: Cell::new(false), - }); - - WEBGL_MAIN_THREAD.with(|main_thread| { - debug_assert!(main_thread.borrow().is_none()); - *main_thread.borrow_mut() = Some(result.clone()); - }); - - result - } - /// Perform all initialization required to run an instance of WebGLThread /// in parallel on its own dedicated thread. pub(crate) fn run_on_own_thread(init: WebGLThreadInit) { @@ -237,8 +259,9 @@ impl WebGLThread { match msg { WebGLMsg::CreateContext(version, size, attributes, result_sender) => { let result = self.create_webgl_context(version, size, attributes); + result_sender - .send(result.map(|(id, limits, share_mode, framebuffer_format)| { + .send(result.map(|(id, limits)| { let image_key = self .cached_context_info .get_mut(&id) @@ -246,31 +269,32 @@ impl WebGLThread { .image_key; let data = Self::make_current_if_needed( + &self.device, id, &self.contexts, &mut self.bound_context_id, ) .expect("WebGLContext not found"); - let glsl_version = Self::get_glsl_version(&data.ctx); - let api_type = match data.ctx.gl().get_type() { + let glsl_version = Self::get_glsl_version(&*data.gl); + let api_type = match data.gl.get_type() { gl::GlType::Gl => GlType::Gl, gl::GlType::Gles => GlType::Gles, }; - // FIXME(nox): Should probably be done by offscreen_gl_context. + // FIXME(nox): Should probably be done by surfman. if api_type != GlType::Gles { // Points sprites are enabled by default in OpenGL 3.2 core // and in GLES. Rather than doing version detection, it does // not hurt to enable them anyways. - data.ctx.gl().enable(gl::POINT_SPRITE); - let err = data.ctx.gl().get_error(); + data.gl.enable(gl::POINT_SPRITE); + let err = data.gl.get_error(); if err != 0 { warn!("Error enabling GL point sprites: {}", err); } - data.ctx.gl().enable(gl::PROGRAM_POINT_SIZE); - let err = data.ctx.gl().get_error(); + data.gl.enable(gl::PROGRAM_POINT_SIZE); + let err = data.gl.get_error(); if err != 0 { warn!("Error enabling GL program point size: {}", err); } @@ -279,10 +303,8 @@ impl WebGLThread { WebGLCreateContextResult { sender: WebGLMsgSender::new(id, webgl_chan.clone()), limits, - share_mode, glsl_version, api_type, - framebuffer_format, image_key, } })) @@ -300,18 +322,15 @@ impl WebGLThread { WebGLMsg::WebVRCommand(ctx_id, command) => { self.handle_webvr_command(ctx_id, command); }, - WebGLMsg::Lock(ctx_id, sender) => { - self.handle_lock(ctx_id, sender); + WebGLMsg::CreateWebXRSwapChain(ctx_id, size, sender) => { + let _ = sender.send(self.create_webxr_swap_chain(ctx_id, size)); }, - WebGLMsg::Unlock(ctx_id) => { - self.handle_unlock(ctx_id); + WebGLMsg::SwapBuffers(swap_ids, sender) => { + self.handle_swap_buffers(swap_ids, sender); }, WebGLMsg::DOMToTextureCommand(command) => { self.handle_dom_to_texture(command); }, - WebGLMsg::SwapBuffers(context_ids, sender) => { - self.handle_swap_buffers(context_ids, sender); - }, WebGLMsg::Exit => { return true; }, @@ -327,256 +346,268 @@ impl WebGLThread { command: WebGLCommand, backtrace: WebGLCommandBacktrace, ) { + if self.cached_context_info.get_mut(&context_id).is_none() { + return; + } let data = Self::make_current_if_needed_mut( + &self.device, context_id, &mut self.contexts, &mut self.bound_context_id, ); + if let Some(data) = data { - let info = self.cached_context_info.get_mut(&context_id).unwrap(); - if info.clear_required { - info.clear_required = false; - Self::clear_drawing_buffer(data); + match command { + // We have to handle framebuffer binding differently, because `apply` + // assumes that the currently attached surface is the right one for binding + // the framebuffer, and since it doesn't get passed the swap buffers + // it casn't do that itself. At some point we could refactor apply so + // it takes a self parameter, at which point that won't be necessary. + WebGLCommand::BindFramebuffer(_, request) => { + WebGLImpl::attach_surface( + context_id, + &self.webrender_swap_chains, + &self.webxr_swap_chains, + request, + &mut data.ctx, + &mut self.device, + ); + }, + // Similarly, dropping a WebGL framebuffer needs access to the swap chains, + // in order to delete the entry. + WebGLCommand::DeleteFramebuffer(WebGLFramebufferId::Opaque( + WebGLOpaqueFramebufferId::WebXR(id), + )) => { + let _ = self + .webxr_swap_chains + .destroy(id, &mut self.device, &mut data.ctx); + }, + _ => {}, } - data.ctx.apply_command( - command, - data.use_apple_vertex_arrays, - backtrace, + + WebGLImpl::apply( + &self.device, + &data.ctx, + &*data.gl, &mut data.state, + &data.attributes, + command, + backtrace, ); } } /// Handles a WebVRCommand for a specific WebGLContext - fn handle_webvr_command(&mut self, context_id: WebGLContextId, command: WebVRCommand) { - if let Some(context) = - Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id) - { - let texture = match command { - WebVRCommand::SubmitFrame(..) => self.cached_context_info.get(&context_id), - _ => None, - }; - self.webvr_compositor.as_mut().unwrap().handle( - context.ctx.gl(), - command, - texture.map(|t| (t.texture_id, t.size)), - ); - } - } - /// Handles a lock external callback received from webrender::ExternalImageHandler - fn handle_lock( - &mut self, - context_id: WebGLContextId, - sender: WebGLSender<(u32, Size2D, usize)>, - ) { - let data = - Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id) - .expect("WebGLContext not found in a WebGLMsg::Lock message"); - let info = self.cached_context_info.get_mut(&context_id).unwrap(); - info.render_state = ContextRenderState::Locked(None); - // Insert a OpenGL Fence sync object that sends a signal when all the WebGL commands are finished. - // The related gl().wait_sync call is performed in the WR thread. See WebGLExternalImageApi for mor details. - let gl_sync = data.ctx.gl().fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0); - info.gl_sync = Some(gl_sync); - debug_assert!(data.ctx.gl().get_error() == gl::NO_ERROR); - - // It is important that the fence sync is properly flushed into the GPU's command queue. - // Without proper flushing, the sync object may never be signaled. - data.ctx.gl().flush(); - debug_assert!(data.ctx.gl().get_error() == gl::NO_ERROR); - - let _ = sender.send((info.texture_id, info.size, gl_sync as usize)); - } - - /// A version of locking that doesn't return a GLsync object, - /// used when it's being called from the same thread. - pub(crate) fn handle_lock_unsync(&mut self, context_id: WebGLContextId) -> (u32, Size2D) { - let info = self.cached_context_info.get_mut(&context_id).unwrap(); - info.render_state = ContextRenderState::Locked(None); - (info.texture_id, info.size) - } - - /// Handles an unlock external callback received from webrender::ExternalImageHandler - pub(crate) fn handle_unlock(&mut self, context_id: WebGLContextId) { - let info = self.cached_context_info.get_mut(&context_id).unwrap(); - info.render_state = ContextRenderState::Unlocked; - - if let Some(gl_sync) = info.gl_sync.take() { - let data = Self::make_current_if_needed( - context_id, - &self.contexts, - &mut self.bound_context_id, - ) - .expect("WebGLContext not found in a WebGLMsg::Unlock message"); - // Release the GLSync object. - data.ctx.gl().delete_sync(gl_sync); - debug_assert!(data.ctx.gl().get_error() == gl::NO_ERROR); - } - } - - #[allow(unsafe_code)] - fn clear_drawing_buffer(data: &mut GLContextData) { - trace!("clearing GL framebuffer"); - - // Ensure we're clearing the default framebuffer. - let mut fb = [0]; - unsafe { - data.ctx - .gl() - .get_integer_v(gl::FRAMEBUFFER_BINDING, &mut fb); - } - data.ctx - .gl() - .bind_framebuffer(gl::FRAMEBUFFER, data.ctx.framebuffer()); - - data.ctx.gl().clear_color(0., 0., 0., 0.); - data.ctx.gl().clear_depth(1.0); - data.ctx.gl().clear_stencil(0); - data.ctx - .gl() - .clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT); - - let (r, g, b, a) = data.state.clear_color; - data.ctx.gl().clear_color(r, g, b, a); - data.ctx.gl().clear_depth(data.state.depth_clear_value); - data.ctx.gl().clear_stencil(data.state.stencil_clear_value); - - data.ctx.gl().bind_framebuffer(gl::FRAMEBUFFER, fb[0] as _); + fn handle_webvr_command(&mut self, _context_id: WebGLContextId, _command: WebVRCommand) { + // TODO(pcwalton): Reenable. } /// Creates a new WebGLContext + #[allow(unsafe_code)] fn create_webgl_context( &mut self, - version: WebGLVersion, - size: Size2D, + webgl_version: WebGLVersion, + requested_size: Size2D, attributes: GLContextAttributes, - ) -> Result<(WebGLContextId, GLLimits, WebGLContextShareMode, GLFormats), String> { + ) -> Result<(WebGLContextId, webgl::GLLimits), String> { + debug!("WebGLThread::create_webgl_context({:?})", requested_size); + // Creating a new GLContext may make the current bound context_id dirty. // Clear it to ensure that make_current() is called in subsequent commands. self.bound_context_id = None; - let preserve_drawing_buffer = attributes.preserve_drawing_buffer; + let context_attributes = &ContextAttributes { + version: webgl_version.to_surfman_version(), + flags: attributes.to_surfman_context_attribute_flags(), + }; - // First try to create a shared context for the best performance. - // Fallback to readback mode if the shared context creation fails. - let (ctx, share_mode) = self - .gl_factory - .new_shared_context(version, size, attributes) - .map(|r| (r, WebGLContextShareMode::SharedTexture)) - .or_else(|err| { - warn!( - "Couldn't create shared GL context ({}), using slow readback context instead.", - err - ); - let ctx = self.gl_factory.new_context(version, size, attributes)?; - Ok((ctx, WebGLContextShareMode::Readback)) - }) - .map_err(|msg: &str| msg.to_owned())?; + let context_descriptor = self + .device + .create_context_descriptor(&context_attributes) + .unwrap(); + + let safe_size = Size2D::new( + requested_size.width.min(SAFE_VIEWPORT_DIMS[0]).max(1), + requested_size.height.min(SAFE_VIEWPORT_DIMS[1]).max(1), + ); + let surface_type = SurfaceType::Generic { + size: safe_size.to_i32(), + }; + let surface_access = self.surface_access(); + + let mut ctx = self + .device + .create_context(&context_descriptor, surface_access, &surface_type) + .expect("Failed to create the GL context!"); + // https://github.com/pcwalton/surfman/issues/7 + self.device + .make_context_current(&ctx) + .expect("failed to make new context current"); let id = WebGLContextId( self.external_images .lock() .unwrap() .next_id(WebrenderImageHandlerType::WebGL) - .0 as usize, + .0, ); - let (size, texture_id, limits, framebuffer_formats) = ctx.get_info(); - let use_apple_vertex_arrays = needs_apple_vertex_arrays(ctx.gl(), version); + + self.webrender_swap_chains + .create_attached_swap_chain(id, &mut self.device, &mut ctx, surface_access) + .expect("Failed to create the swap chain"); + + let swap_chain = self + .webrender_swap_chains + .get(id) + .expect("Failed to get the swap chain"); + + debug!( + "Created webgl context {:?}/{:?}", + id, + self.device.context_id(&ctx) + ); + + let gl = match self.api_type { + gl::GlType::Gl => Gl::gl_fns(gl::ffi_gl::Gl::load_with(|symbol_name| { + self.device.get_proc_address(&ctx, symbol_name) + })), + gl::GlType::Gles => Gl::gles_fns(gl::ffi_gles::Gles2::load_with(|symbol_name| { + self.device.get_proc_address(&ctx, symbol_name) + })), + }; + + let limits = GLLimits::detect(&*gl); + + let size = clamp_viewport(&gl, requested_size); + if safe_size != size { + debug!("Resizing swap chain from {} to {}", safe_size, size); + swap_chain + .resize(&mut self.device, &mut ctx, size.to_i32()) + .expect("Failed to resize swap chain"); + } + + self.device.make_context_current(&ctx).unwrap(); + let framebuffer = self + .device + .context_surface_framebuffer_object(&ctx) + .unwrap(); + gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer); + gl.viewport(0, 0, size.width as i32, size.height as i32); + gl.scissor(0, 0, size.width as i32, size.height as i32); + gl.clear_color(0., 0., 0., 0.); + gl.clear_depth(1.); + gl.clear_stencil(0); + gl.clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT); + debug_assert_eq!(gl.get_error(), gl::NO_ERROR); + + let descriptor = self.device.context_descriptor(&ctx); + let descriptor_attributes = self.device.context_descriptor_attributes(&descriptor); + + let gl_version = descriptor_attributes.version; + let has_alpha = descriptor_attributes + .flags + .contains(ContextAttributeFlags::ALPHA); + let texture_target = current_wr_texture_target(&self.device); + + let use_apple_vertex_array = WebGLImpl::needs_apple_vertex_arrays(gl_version); + let default_vao = if let Some(vao) = + WebGLImpl::create_vertex_array(&gl, use_apple_vertex_array, webgl_version) + { + let vao = vao.get(); + WebGLImpl::bind_vertex_array(&gl, vao, use_apple_vertex_array, webgl_version); + vao + } else { + 0 + }; + + let state = GLState { + gl_version, + webgl_version, + default_vao, + ..Default::default() + }; self.contexts.insert( id, GLContextData { ctx, - state: Default::default(), - use_apple_vertex_arrays, + gl, + state, + attributes, }, ); - let image_key = match share_mode { - WebGLContextShareMode::Readback => Self::create_wr_readback_image( - &self.webrender_api, - size, - attributes.alpha, - vec![0; 4 * size.width as usize * size.height as usize], - ), - WebGLContextShareMode::SharedTexture => Self::create_wr_external_image( - &self.webrender_api, - size.to_i32(), - attributes.alpha, - id, - ), - }; - - self.cached_context_info.insert( + let image_key = Self::create_wr_external_image( + &self.webrender_api, + size.to_i32(), + has_alpha, id, - WebGLContextInfo { - texture_id, - size, - alpha: attributes.alpha, - image_key: image_key, - share_mode, - gl_sync: None, - render_state: ContextRenderState::Unlocked, - preserve_drawing_buffer, - clear_required: false, - }, + texture_target, ); - Ok((id, limits, share_mode, framebuffer_formats)) + self.cached_context_info + .insert(id, WebGLContextInfo { image_key }); + + Ok((id, limits)) } /// Resizes a WebGLContext fn resize_webgl_context( &mut self, context_id: WebGLContextId, - size: Size2D, + requested_size: Size2D, sender: WebGLSender>, ) { let data = Self::make_current_if_needed_mut( + &self.device, context_id, &mut self.contexts, &mut self.bound_context_id, ) .expect("Missing WebGL context!"); - match data.ctx.resize(size) { - Ok(old_draw_buffer) => { - let (real_size, texture_id, _, _) = data.ctx.get_info(); - let info = self.cached_context_info.get_mut(&context_id).unwrap(); - if let ContextRenderState::Locked(ref mut in_use) = info.render_state { - // If there's already an outdated draw buffer present, we can ignore - // the newly resized one since it's not in use by the renderer. - if in_use.is_none() { - // We're resizing the context while WR is actively rendering - // it, so we need to retain the GL resources until WR is - // finished with them. - *in_use = Some(old_draw_buffer); - } - } - // Update webgl texture size. Texture id may change too. - info.texture_id = texture_id; - info.size = real_size; - // Update WR image if needed. Resize image updates are only required for SharedTexture mode. - // Readback mode already updates the image every frame to send the raw pixels. - // See `handle_update_wr_image`. - match (info.image_key, info.share_mode) { - (image_key, WebGLContextShareMode::SharedTexture) => { - Self::update_wr_external_image( - &self.webrender_api, - info.size, - info.alpha, - context_id, - image_key, - ); - }, - _ => {}, - } + let size = clamp_viewport(&data.gl, requested_size); - sender.send(Ok(())).unwrap(); - }, - Err(msg) => { - sender.send(Err(msg.into())).unwrap(); - }, + // Check to see if any of the current framebuffer bindings are the surface we're about to + // throw out. If so, we'll have to reset them after destroying the surface. + let framebuffer_rebinding_info = + FramebufferRebindingInfo::detect(&self.device, &data.ctx, &*data.gl); + + // Resize the swap chains + if let Some(swap_chain) = self.webrender_swap_chains.get(context_id) { + swap_chain + .resize(&mut self.device, &mut data.ctx, size.to_i32()) + .expect("Failed to resize swap chain"); + swap_chain + .clear_surface(&mut self.device, &mut data.ctx, &*data.gl) + .expect("Failed to clear resized swap chain"); + } else { + error!("Failed to find swap chain"); } + + // Reset framebuffer bindings as appropriate. + framebuffer_rebinding_info.apply(&self.device, &data.ctx, &*data.gl); + + // Update WR image if needed. + let info = self.cached_context_info.get_mut(&context_id).unwrap(); + let context_descriptor = self.device.context_descriptor(&data.ctx); + let has_alpha = self + .device + .context_descriptor_attributes(&context_descriptor) + .flags + .contains(ContextAttributeFlags::ALPHA); + let texture_target = current_wr_texture_target(&self.device); + Self::update_wr_external_image( + &self.webrender_api, + size.to_i32(), + has_alpha, + context_id, + info.image_key, + texture_target, + ); + + debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR); + + sender.send(Ok(())).unwrap(); } /// Removes a WebGLContext and releases attached resources. @@ -584,18 +615,33 @@ impl WebGLThread { // Release webrender image keys. if let Some(info) = self.cached_context_info.remove(&context_id) { let mut txn = webrender_api::Transaction::new(); - txn.delete_image(info.image_key); - self.webrender_api.update_resources(txn.resource_updates) } // We need to make the context current so its resources can be disposed of. - let _ = - Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id); - + Self::make_current_if_needed( + &self.device, + context_id, + &self.contexts, + &mut self.bound_context_id, + ); // Release GL context. - self.contexts.remove(&context_id); + let mut data = match self.contexts.remove(&context_id) { + Some(data) => data, + None => return, + }; + + // Destroy the swap chains + self.webrender_swap_chains + .destroy(context_id, &mut self.device, &mut data.ctx) + .unwrap(); + self.webxr_swap_chains + .destroy_all(&mut self.device, &mut data.ctx) + .unwrap(); + + // Destroy the context + self.device.destroy_context(&mut data.ctx).unwrap(); // Removing a GLContext may make the current bound context_id dirty. self.bound_context_id = None; @@ -603,44 +649,105 @@ impl WebGLThread { fn handle_swap_buffers( &mut self, - context_ids: Vec, + swap_ids: Vec, completed_sender: WebGLSender<()>, ) { - for context_id in context_ids { - let info = self.cached_context_info.get_mut(&context_id).unwrap(); - let webrender_api = &self.webrender_api; + debug!("handle_swap_buffers()"); + for swap_id in swap_ids { + let context_id = swap_id.context_id(); - if let WebGLContextShareMode::Readback = info.share_mode { - let pixels = Self::raw_pixels(&self.contexts[&context_id].ctx, info.size); - // WR Images must be updated every frame in readback mode to send the new raw pixels. - Self::update_wr_readback_image( - webrender_api, - info.size, - info.alpha, - info.image_key, - pixels, - ); - } + let data = Self::make_current_if_needed_mut( + &self.device, + context_id, + &mut self.contexts, + &mut self.bound_context_id, + ) + .expect("Where's the GL data?"); - if !info.preserve_drawing_buffer { - info.clear_required = true; + // Check to see if any of the current framebuffer bindings are the surface we're about + // to swap out. If so, we'll have to reset them after destroying the surface. + let framebuffer_rebinding_info = + FramebufferRebindingInfo::detect(&self.device, &data.ctx, &*data.gl); + + debug!("Getting swap chain for {:?}", swap_id); + let swap_chain = match swap_id { + SwapChainId::Context(id) => self.webrender_swap_chains.get(id), + SwapChainId::Framebuffer(_, WebGLOpaqueFramebufferId::WebXR(id)) => { + self.webxr_swap_chains.get(id) + }, } + .expect("Where's the swap chain?"); + + debug!("Swapping {:?}", swap_id); + swap_chain + .swap_buffers(&mut self.device, &mut data.ctx) + .unwrap(); + + // TODO: if preserveDrawingBuffer is true, then blit the front buffer to the back buffer + // https://github.com/servo/servo/issues/24604 + debug!("Clearing {:?}", swap_id); + swap_chain + .clear_surface(&mut self.device, &mut data.ctx, &*data.gl) + .unwrap(); + + // Rebind framebuffers as appropriate. + debug!("Rebinding {:?}", swap_id); + framebuffer_rebinding_info.apply(&self.device, &data.ctx, &*data.gl); + + let framebuffer = self + .device + .context_surface_framebuffer_object(&data.ctx) + .unwrap(); + debug!( + "... rebound framebuffer {}, new back buffer surface is {:?}", + framebuffer, + self.device.context_surface_id(&data.ctx).unwrap() + ); } - let _ = completed_sender.send(()); + completed_sender.send(()).unwrap(); + } + + /// Creates a new WebXR swap chain + #[allow(unsafe_code)] + fn create_webxr_swap_chain( + &mut self, + context_id: WebGLContextId, + size: Size2D, + ) -> Option { + debug!("WebGLThread::create_webxr_swap_chain()"); + let id = WebXRSwapChainId::new(); + let surface_access = self.surface_access(); + let data = Self::make_current_if_needed_mut( + &self.device, + context_id, + &mut self.contexts, + &mut self.bound_context_id, + )?; + self.webxr_swap_chains + .create_detached_swap_chain(id, size, &mut self.device, &mut data.ctx, surface_access) + .ok()?; + debug!("Created swap chain {:?}", id); + Some(id) + } + + /// Which access mode to use + fn surface_access(&self) -> SurfaceAccess { + SurfaceAccess::GPUOnly } fn handle_dom_to_texture(&mut self, command: DOMToTextureCommand) { match command { DOMToTextureCommand::Attach(context_id, texture_id, document_id, pipeline_id, size) => { let data = Self::make_current_if_needed( + &self.device, context_id, &self.contexts, &mut self.bound_context_id, ) .expect("WebGLContext not found in a WebGL DOMToTextureCommand::Attach command"); // Initialize the texture that WR will use for frame outputs. - data.ctx.gl().tex_image_2d( + data.gl.tex_image_2d( gl::TEXTURE_2D, 0, gl::RGBA as gl::GLint, @@ -690,25 +797,30 @@ impl WebGLThread { pipeline_id: webrender_api::PipelineId, gl_sync: usize, ) -> Option<(u32, Size2D)> { + let device = &self.device; let contexts = &self.contexts; let bound_context_id = &mut self.bound_context_id; self.dom_outputs.get(&pipeline_id).and_then(|dom_data| { - let data = - Self::make_current_if_needed(dom_data.context_id, contexts, bound_context_id); + let data = Self::make_current_if_needed( + device, + dom_data.context_id, + contexts, + bound_context_id, + ); data.and_then(|data| { // The next glWaitSync call is used to synchronize the two flows of // OpenGL commands (WR and WebGL) in order to avoid using semi-ready WR textures. // glWaitSync doesn't block WebGL CPU thread. - data.ctx - .gl() + data.gl .wait_sync(gl_sync as gl::GLsync, 0, gl::TIMEOUT_IGNORED); Some((dom_data.texture_id.get(), dom_data.size)) }) }) } - /// Gets a reference to a GLContextWrapper for a given WebGLContextId and makes it current if required. + /// Gets a reference to a Context for a given WebGLContextId and makes it current if required. fn make_current_if_needed<'a>( + device: &Device, context_id: WebGLContextId, contexts: &'a FnvHashMap, bound_id: &mut Option, @@ -717,7 +829,7 @@ impl WebGLThread { if let Some(data) = data { if Some(context_id) != *bound_id { - data.ctx.make_current(); + device.make_context_current(&data.ctx).unwrap(); *bound_id = Some(context_id); } } @@ -727,6 +839,7 @@ impl WebGLThread { /// Gets a mutable reference to a GLContextWrapper for a WebGLContextId and makes it current if required. fn make_current_if_needed_mut<'a>( + device: &Device, context_id: WebGLContextId, contexts: &'a mut FnvHashMap, bound_id: &mut Option, @@ -735,7 +848,7 @@ impl WebGLThread { if let Some(ref data) = data { if Some(context_id) != *bound_id { - data.ctx.make_current(); + device.make_context_current(&data.ctx).unwrap(); *bound_id = Some(context_id); } } @@ -749,9 +862,10 @@ impl WebGLThread { size: Size2D, alpha: bool, context_id: WebGLContextId, + target: webrender_api::TextureTarget, ) -> webrender_api::ImageKey { let descriptor = Self::image_descriptor(size, alpha); - let data = Self::external_image_data(context_id); + let data = Self::external_image_data(context_id, target); let image_key = webrender_api.generate_image_key(); let mut txn = webrender_api::Transaction::new(); @@ -768,43 +882,10 @@ impl WebGLThread { alpha: bool, context_id: WebGLContextId, image_key: webrender_api::ImageKey, + target: webrender_api::TextureTarget, ) { let descriptor = Self::image_descriptor(size, alpha); - let data = Self::external_image_data(context_id); - - let mut txn = webrender_api::Transaction::new(); - txn.update_image(image_key, descriptor, data, &webrender_api::DirtyRect::All); - webrender_api.update_resources(txn.resource_updates); - } - - /// Creates a `webrender_api::ImageKey` that uses raw pixels. - fn create_wr_readback_image( - webrender_api: &webrender_api::RenderApi, - size: Size2D, - alpha: bool, - data: Vec, - ) -> webrender_api::ImageKey { - let descriptor = Self::image_descriptor(size, alpha); - let data = webrender_api::ImageData::new(data); - - let image_key = webrender_api.generate_image_key(); - let mut txn = webrender_api::Transaction::new(); - txn.add_image(image_key, descriptor, data, None); - webrender_api.update_resources(txn.resource_updates); - - image_key - } - - /// Updates a `webrender_api::ImageKey` that uses raw pixels. - fn update_wr_readback_image( - webrender_api: &webrender_api::RenderApi, - size: Size2D, - alpha: bool, - image_key: webrender_api::ImageKey, - data: Vec, - ) { - let descriptor = Self::image_descriptor(size, alpha); - let data = webrender_api::ImageData::new(data); + let data = Self::external_image_data(context_id, target); let mut txn = webrender_api::Transaction::new(); txn.update_image(image_key, descriptor, data, &webrender_api::DirtyRect::All); @@ -824,46 +905,21 @@ impl WebGLThread { } /// Helper function to create a `webrender_api::ImageData::External` instance. - fn external_image_data(context_id: WebGLContextId) -> webrender_api::ImageData { + fn external_image_data( + context_id: WebGLContextId, + target: webrender_api::TextureTarget, + ) -> webrender_api::ImageData { let data = webrender_api::ExternalImageData { id: webrender_api::ExternalImageId(context_id.0 as u64), channel_index: 0, - image_type: webrender_api::ExternalImageType::TextureHandle( - webrender_api::TextureTarget::Default, - ), + image_type: webrender_api::ExternalImageType::TextureHandle(target), }; webrender_api::ImageData::External(data) } - /// Helper function to fetch the raw pixels used in readback mode. - fn raw_pixels(context: &GLContextWrapper, size: Size2D) -> Vec { - let width = size.width as usize; - let height = size.height as usize; - - let mut pixels = context.gl().read_pixels( - 0, - 0, - size.width as gl::GLsizei, - size.height as gl::GLsizei, - gl::RGBA, - gl::UNSIGNED_BYTE, - ); - // flip image vertically (texture is upside down) - let orig_pixels = pixels.clone(); - let stride = width * 4; - for y in 0..height { - let dst_start = y * stride; - let src_start = (height - y - 1) * stride; - let src_slice = &orig_pixels[src_start..src_start + stride]; - (&mut pixels[dst_start..dst_start + stride]).clone_from_slice(&src_slice[..stride]); - } - pixels::rgba8_byte_swap_colors_inplace(&mut pixels); - pixels - } - /// Gets the GLSL Version supported by a GLContext. - fn get_glsl_version(context: &GLContextWrapper) -> WebGLSLVersion { - let version = context.gl().get_string(gl::SHADING_LANGUAGE_VERSION); + fn get_glsl_version(gl: &Gl) -> WebGLSLVersion { + let version = gl.get_string(gl::SHADING_LANGUAGE_VERSION); // Fomat used by SHADING_LANGUAGE_VERSION query : major.minor[.release] [vendor info] let mut values = version.split(&['.', ' '][..]); let major = values @@ -889,34 +945,18 @@ impl Drop for WebGLThread { } } -enum ContextRenderState { - /// The context is not being actively rendered. - Unlocked, - /// The context is actively being rendered. If a DrawBuffer value is present, - /// it is outdated but in use as long as the context is locked. - Locked(Option), -} - /// Helper struct to store cached WebGLContext information. struct WebGLContextInfo { - /// Render to texture identifier used by the WebGLContext. - texture_id: u32, - /// Size of the WebGLContext. - size: Size2D, - /// True if the WebGLContext uses an alpha channel. - alpha: bool, /// Currently used WebRender image key. image_key: webrender_api::ImageKey, - /// The sharing mode used to send the image to WebRender. - share_mode: WebGLContextShareMode, - /// GLSync Object used for a correct synchronization with Webrender external image callbacks. - gl_sync: Option, - /// The status of this context with respect to external consumers. - render_state: ContextRenderState, - /// Should the drawing buffer be preserved between frames? - preserve_drawing_buffer: bool, - /// Does the canvas need to be cleared before executing further WebGL commands? - clear_required: bool, +} + +// TODO(pcwalton): Add `GL_TEXTURE_EXTERNAL_OES`? +fn current_wr_texture_target(device: &Device) -> webrender_api::TextureTarget { + match device.surface_gl_texture_target() { + gl::TEXTURE_RECTANGLE => webrender_api::TextureTarget::Rect, + _ => webrender_api::TextureTarget::Default, + } } /// Data about the linked DOM<->WebGLTexture elements. @@ -932,57 +972,64 @@ pub struct WebGLImpl; impl WebGLImpl { #[allow(unsafe_code)] - pub fn apply( - ctx: &GLContext, + pub fn apply( + device: &Device, + ctx: &Context, + gl: &Gl, state: &mut GLState, - use_apple_vertex_array: bool, + attributes: &GLContextAttributes, command: WebGLCommand, _backtrace: WebGLCommandBacktrace, ) { + debug!("WebGLImpl::apply({:?})", command); + + // Ensure there are no pending GL errors from other parts of the pipeline. + debug_assert_eq!(gl.get_error(), gl::NO_ERROR); + match command { - WebGLCommand::GetContextAttributes(ref sender) => sender - .send(map_attrs_to_script_attrs(*ctx.borrow_attributes())) - .unwrap(), - WebGLCommand::ActiveTexture(target) => ctx.gl().active_texture(target), + WebGLCommand::GetContextAttributes(ref sender) => sender.send(*attributes).unwrap(), + WebGLCommand::ActiveTexture(target) => gl.active_texture(target), WebGLCommand::AttachShader(program_id, shader_id) => { - ctx.gl().attach_shader(program_id.get(), shader_id.get()) + gl.attach_shader(program_id.get(), shader_id.get()) }, WebGLCommand::DetachShader(program_id, shader_id) => { - ctx.gl().detach_shader(program_id.get(), shader_id.get()) + gl.detach_shader(program_id.get(), shader_id.get()) }, - WebGLCommand::BindAttribLocation(program_id, index, ref name) => ctx - .gl() - .bind_attrib_location(program_id.get(), index, &to_name_in_compiled_shader(name)), - WebGLCommand::BlendColor(r, g, b, a) => ctx.gl().blend_color(r, g, b, a), - WebGLCommand::BlendEquation(mode) => ctx.gl().blend_equation(mode), + WebGLCommand::BindAttribLocation(program_id, index, ref name) => { + gl.bind_attrib_location(program_id.get(), index, &to_name_in_compiled_shader(name)) + }, + WebGLCommand::BlendColor(r, g, b, a) => gl.blend_color(r, g, b, a), + WebGLCommand::BlendEquation(mode) => gl.blend_equation(mode), WebGLCommand::BlendEquationSeparate(mode_rgb, mode_alpha) => { - ctx.gl().blend_equation_separate(mode_rgb, mode_alpha) + gl.blend_equation_separate(mode_rgb, mode_alpha) + }, + WebGLCommand::BlendFunc(src, dest) => gl.blend_func(src, dest), + WebGLCommand::BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha) => { + gl.blend_func_separate(src_rgb, dest_rgb, src_alpha, dest_alpha) }, - WebGLCommand::BlendFunc(src, dest) => ctx.gl().blend_func(src, dest), - WebGLCommand::BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha) => ctx - .gl() - .blend_func_separate(src_rgb, dest_rgb, src_alpha, dest_alpha), WebGLCommand::BufferData(buffer_type, ref receiver, usage) => { - gl::buffer_data(ctx.gl(), buffer_type, &receiver.recv().unwrap(), usage) + gl::buffer_data(gl, buffer_type, &receiver.recv().unwrap(), usage) }, WebGLCommand::BufferSubData(buffer_type, offset, ref receiver) => { - gl::buffer_sub_data(ctx.gl(), buffer_type, offset, &receiver.recv().unwrap()) + gl::buffer_sub_data(gl, buffer_type, offset, &receiver.recv().unwrap()) + }, + WebGLCommand::Clear(mask) => { + gl.clear(mask); }, - WebGLCommand::Clear(mask) => ctx.gl().clear(mask), WebGLCommand::ClearColor(r, g, b, a) => { state.clear_color = (r, g, b, a); - ctx.gl().clear_color(r, g, b, a); + gl.clear_color(r, g, b, a); }, WebGLCommand::ClearDepth(depth) => { let value = depth.max(0.).min(1.) as f64; state.depth_clear_value = value; - ctx.gl().clear_depth(value) + gl.clear_depth(value) }, WebGLCommand::ClearStencil(stencil) => { state.stencil_clear_value = stencil; - ctx.gl().clear_stencil(stencil); + gl.clear_stencil(stencil); }, - WebGLCommand::ColorMask(r, g, b, a) => ctx.gl().color_mask(r, g, b, a), + WebGLCommand::ColorMask(r, g, b, a) => gl.color_mask(r, g, b, a), WebGLCommand::CopyTexImage2D( target, level, @@ -992,16 +1039,7 @@ impl WebGLImpl { width, height, border, - ) => ctx.gl().copy_tex_image_2d( - target, - level, - internal_format, - x, - y, - width, - height, - border, - ), + ) => gl.copy_tex_image_2d(target, level, internal_format, x, y, width, height, border), WebGLCommand::CopyTexSubImage2D( target, level, @@ -1011,33 +1049,31 @@ impl WebGLImpl { y, width, height, - ) => ctx - .gl() - .copy_tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height), - WebGLCommand::CullFace(mode) => ctx.gl().cull_face(mode), - WebGLCommand::DepthFunc(func) => ctx.gl().depth_func(func), + ) => gl.copy_tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height), + WebGLCommand::CullFace(mode) => gl.cull_face(mode), + WebGLCommand::DepthFunc(func) => gl.depth_func(func), WebGLCommand::DepthMask(flag) => { state.depth_write_mask = flag; - ctx.gl().depth_mask(flag); + gl.depth_mask(flag); + }, + WebGLCommand::DepthRange(near, far) => { + gl.depth_range(near.max(0.).min(1.) as f64, far.max(0.).min(1.) as f64) }, - WebGLCommand::DepthRange(near, far) => ctx - .gl() - .depth_range(near.max(0.).min(1.) as f64, far.max(0.).min(1.) as f64), WebGLCommand::Disable(cap) => { if cap == gl::SCISSOR_TEST { state.scissor_test_enabled = false; } - ctx.gl().disable(cap); + gl.disable(cap); }, WebGLCommand::Enable(cap) => { if cap == gl::SCISSOR_TEST { state.scissor_test_enabled = true; } - ctx.gl().enable(cap); + gl.enable(cap); }, WebGLCommand::FramebufferRenderbuffer(target, attachment, renderbuffertarget, rb) => { let attach = |attachment| { - ctx.gl().framebuffer_renderbuffer( + gl.framebuffer_renderbuffer( target, attachment, renderbuffertarget, @@ -1053,7 +1089,7 @@ impl WebGLImpl { }, WebGLCommand::FramebufferTexture2D(target, attachment, textarget, texture, level) => { let attach = |attachment| { - ctx.gl().framebuffer_texture_2d( + gl.framebuffer_texture_2d( target, attachment, textarget, @@ -1068,19 +1104,19 @@ impl WebGLImpl { attach(attachment) } }, - WebGLCommand::FrontFace(mode) => ctx.gl().front_face(mode), + WebGLCommand::FrontFace(mode) => gl.front_face(mode), WebGLCommand::DisableVertexAttribArray(attrib_id) => { - ctx.gl().disable_vertex_attrib_array(attrib_id) + gl.disable_vertex_attrib_array(attrib_id) }, WebGLCommand::EnableVertexAttribArray(attrib_id) => { - ctx.gl().enable_vertex_attrib_array(attrib_id) + gl.enable_vertex_attrib_array(attrib_id) }, - WebGLCommand::Hint(name, val) => ctx.gl().hint(name, val), - WebGLCommand::LineWidth(width) => ctx.gl().line_width(width), - WebGLCommand::PixelStorei(name, val) => ctx.gl().pixel_store_i(name, val), - WebGLCommand::PolygonOffset(factor, units) => ctx.gl().polygon_offset(factor, units), + WebGLCommand::Hint(name, val) => gl.hint(name, val), + WebGLCommand::LineWidth(width) => gl.line_width(width), + WebGLCommand::PixelStorei(name, val) => gl.pixel_store_i(name, val), + WebGLCommand::PolygonOffset(factor, units) => gl.polygon_offset(factor, units), WebGLCommand::ReadPixels(rect, format, pixel_type, ref sender) => { - let pixels = ctx.gl().read_pixels( + let pixels = gl.read_pixels( rect.origin.x as i32, rect.origin.y as i32, rect.size.width as i32, @@ -1091,22 +1127,22 @@ impl WebGLImpl { sender.send(&pixels).unwrap(); }, WebGLCommand::RenderbufferStorage(target, format, width, height) => { - ctx.gl().renderbuffer_storage(target, format, width, height) + gl.renderbuffer_storage(target, format, width, height) }, - WebGLCommand::SampleCoverage(value, invert) => ctx.gl().sample_coverage(value, invert), + WebGLCommand::SampleCoverage(value, invert) => gl.sample_coverage(value, invert), WebGLCommand::Scissor(x, y, width, height) => { // FIXME(nox): Kinda unfortunate that some u32 values could // end up as negative numbers here, but I don't even think // that can happen in the real world. - ctx.gl().scissor(x, y, width as i32, height as i32); + gl.scissor(x, y, width as i32, height as i32); }, - WebGLCommand::StencilFunc(func, ref_, mask) => ctx.gl().stencil_func(func, ref_, mask), + WebGLCommand::StencilFunc(func, ref_, mask) => gl.stencil_func(func, ref_, mask), WebGLCommand::StencilFuncSeparate(face, func, ref_, mask) => { - ctx.gl().stencil_func_separate(face, func, ref_, mask) + gl.stencil_func_separate(face, func, ref_, mask) }, WebGLCommand::StencilMask(mask) => { state.stencil_write_mask = (mask, mask); - ctx.gl().stencil_mask(mask); + gl.stencil_mask(mask); }, WebGLCommand::StencilMaskSeparate(face, mask) => { if face == gl::FRONT { @@ -1114,111 +1150,102 @@ impl WebGLImpl { } else { state.stencil_write_mask.1 = mask; } - ctx.gl().stencil_mask_separate(face, mask); + gl.stencil_mask_separate(face, mask); }, - WebGLCommand::StencilOp(fail, zfail, zpass) => ctx.gl().stencil_op(fail, zfail, zpass), + WebGLCommand::StencilOp(fail, zfail, zpass) => gl.stencil_op(fail, zfail, zpass), WebGLCommand::StencilOpSeparate(face, fail, zfail, zpass) => { - ctx.gl().stencil_op_separate(face, fail, zfail, zpass) + gl.stencil_op_separate(face, fail, zfail, zpass) }, WebGLCommand::GetRenderbufferParameter(target, pname, ref chan) => { - Self::get_renderbuffer_parameter(ctx.gl(), target, pname, chan) + Self::get_renderbuffer_parameter(gl, target, pname, chan) }, WebGLCommand::GetFramebufferAttachmentParameter( target, attachment, pname, ref chan, - ) => Self::get_framebuffer_attachment_parameter( - ctx.gl(), - target, - attachment, - pname, - chan, - ), + ) => Self::get_framebuffer_attachment_parameter(gl, target, attachment, pname, chan), WebGLCommand::GetShaderPrecisionFormat(shader_type, precision_type, ref chan) => { - Self::shader_precision_format(ctx.gl(), shader_type, precision_type, chan) + Self::shader_precision_format(gl, shader_type, precision_type, chan) }, - WebGLCommand::GetExtensions(ref chan) => Self::get_extensions(ctx.gl(), chan), + WebGLCommand::GetExtensions(ref chan) => Self::get_extensions(gl, chan), WebGLCommand::GetUniformLocation(program_id, ref name, ref chan) => { - Self::uniform_location(ctx.gl(), program_id, &name, chan) + Self::uniform_location(gl, program_id, &name, chan) }, WebGLCommand::GetShaderInfoLog(shader_id, ref chan) => { - Self::shader_info_log(ctx.gl(), shader_id, chan) + Self::shader_info_log(gl, shader_id, chan) }, WebGLCommand::GetProgramInfoLog(program_id, ref chan) => { - Self::program_info_log(ctx.gl(), program_id, chan) + Self::program_info_log(gl, program_id, chan) }, WebGLCommand::CompileShader(shader_id, ref source) => { - Self::compile_shader(ctx.gl(), shader_id, &source) + Self::compile_shader(gl, shader_id, &source) }, - WebGLCommand::CreateBuffer(ref chan) => Self::create_buffer(ctx.gl(), chan), - WebGLCommand::CreateFramebuffer(ref chan) => Self::create_framebuffer(ctx.gl(), chan), - WebGLCommand::CreateRenderbuffer(ref chan) => Self::create_renderbuffer(ctx.gl(), chan), - WebGLCommand::CreateTexture(ref chan) => Self::create_texture(ctx.gl(), chan), - WebGLCommand::CreateProgram(ref chan) => Self::create_program(ctx.gl(), chan), + WebGLCommand::CreateBuffer(ref chan) => Self::create_buffer(gl, chan), + WebGLCommand::CreateFramebuffer(ref chan) => Self::create_framebuffer(gl, chan), + WebGLCommand::CreateRenderbuffer(ref chan) => Self::create_renderbuffer(gl, chan), + WebGLCommand::CreateTexture(ref chan) => Self::create_texture(gl, chan), + WebGLCommand::CreateProgram(ref chan) => Self::create_program(gl, chan), WebGLCommand::CreateShader(shader_type, ref chan) => { - Self::create_shader(ctx.gl(), shader_type, chan) + Self::create_shader(gl, shader_type, chan) + }, + WebGLCommand::DeleteBuffer(id) => gl.delete_buffers(&[id.get()]), + WebGLCommand::DeleteFramebuffer(WebGLFramebufferId::Transparent(id)) => { + gl.delete_framebuffers(&[id.get()]) + }, + WebGLCommand::DeleteFramebuffer(WebGLFramebufferId::Opaque(_)) => {}, + WebGLCommand::DeleteRenderbuffer(id) => gl.delete_renderbuffers(&[id.get()]), + WebGLCommand::DeleteTexture(id) => gl.delete_textures(&[id.get()]), + WebGLCommand::DeleteProgram(id) => gl.delete_program(id.get()), + WebGLCommand::DeleteShader(id) => gl.delete_shader(id.get()), + WebGLCommand::BindBuffer(target, id) => { + gl.bind_buffer(target, id.map_or(0, WebGLBufferId::get)) }, - WebGLCommand::DeleteBuffer(id) => ctx.gl().delete_buffers(&[id.get()]), - WebGLCommand::DeleteFramebuffer(id) => ctx.gl().delete_framebuffers(&[id.get()]), - WebGLCommand::DeleteRenderbuffer(id) => ctx.gl().delete_renderbuffers(&[id.get()]), - WebGLCommand::DeleteTexture(id) => ctx.gl().delete_textures(&[id.get()]), - WebGLCommand::DeleteProgram(id) => ctx.gl().delete_program(id.get()), - WebGLCommand::DeleteShader(id) => ctx.gl().delete_shader(id.get()), - WebGLCommand::BindBuffer(target, id) => ctx - .gl() - .bind_buffer(target, id.map_or(0, WebGLBufferId::get)), WebGLCommand::BindFramebuffer(target, request) => { - Self::bind_framebuffer(ctx.gl(), target, request, ctx) + Self::bind_framebuffer(gl, target, request, ctx, device) }, - WebGLCommand::BindRenderbuffer(target, id) => ctx - .gl() - .bind_renderbuffer(target, id.map_or(0, WebGLRenderbufferId::get)), - WebGLCommand::BindTexture(target, id) => ctx - .gl() - .bind_texture(target, id.map_or(0, WebGLTextureId::get)), - WebGLCommand::Uniform1f(uniform_id, v) => ctx.gl().uniform_1f(uniform_id, v), - WebGLCommand::Uniform1fv(uniform_id, ref v) => ctx.gl().uniform_1fv(uniform_id, v), - WebGLCommand::Uniform1i(uniform_id, v) => ctx.gl().uniform_1i(uniform_id, v), - WebGLCommand::Uniform1iv(uniform_id, ref v) => ctx.gl().uniform_1iv(uniform_id, v), - WebGLCommand::Uniform2f(uniform_id, x, y) => ctx.gl().uniform_2f(uniform_id, x, y), - WebGLCommand::Uniform2fv(uniform_id, ref v) => ctx.gl().uniform_2fv(uniform_id, v), - WebGLCommand::Uniform2i(uniform_id, x, y) => ctx.gl().uniform_2i(uniform_id, x, y), - WebGLCommand::Uniform2iv(uniform_id, ref v) => ctx.gl().uniform_2iv(uniform_id, v), - WebGLCommand::Uniform3f(uniform_id, x, y, z) => { - ctx.gl().uniform_3f(uniform_id, x, y, z) + WebGLCommand::BindRenderbuffer(target, id) => { + gl.bind_renderbuffer(target, id.map_or(0, WebGLRenderbufferId::get)) }, - WebGLCommand::Uniform3fv(uniform_id, ref v) => ctx.gl().uniform_3fv(uniform_id, v), - WebGLCommand::Uniform3i(uniform_id, x, y, z) => { - ctx.gl().uniform_3i(uniform_id, x, y, z) + WebGLCommand::BindTexture(target, id) => { + gl.bind_texture(target, id.map_or(0, WebGLTextureId::get)) }, - WebGLCommand::Uniform3iv(uniform_id, ref v) => ctx.gl().uniform_3iv(uniform_id, v), + WebGLCommand::Uniform1f(uniform_id, v) => gl.uniform_1f(uniform_id, v), + WebGLCommand::Uniform1fv(uniform_id, ref v) => gl.uniform_1fv(uniform_id, v), + WebGLCommand::Uniform1i(uniform_id, v) => gl.uniform_1i(uniform_id, v), + WebGLCommand::Uniform1iv(uniform_id, ref v) => gl.uniform_1iv(uniform_id, v), + WebGLCommand::Uniform2f(uniform_id, x, y) => gl.uniform_2f(uniform_id, x, y), + WebGLCommand::Uniform2fv(uniform_id, ref v) => gl.uniform_2fv(uniform_id, v), + WebGLCommand::Uniform2i(uniform_id, x, y) => gl.uniform_2i(uniform_id, x, y), + WebGLCommand::Uniform2iv(uniform_id, ref v) => gl.uniform_2iv(uniform_id, v), + WebGLCommand::Uniform3f(uniform_id, x, y, z) => gl.uniform_3f(uniform_id, x, y, z), + WebGLCommand::Uniform3fv(uniform_id, ref v) => gl.uniform_3fv(uniform_id, v), + WebGLCommand::Uniform3i(uniform_id, x, y, z) => gl.uniform_3i(uniform_id, x, y, z), + WebGLCommand::Uniform3iv(uniform_id, ref v) => gl.uniform_3iv(uniform_id, v), WebGLCommand::Uniform4f(uniform_id, x, y, z, w) => { - ctx.gl().uniform_4f(uniform_id, x, y, z, w) + gl.uniform_4f(uniform_id, x, y, z, w) }, - WebGLCommand::Uniform4fv(uniform_id, ref v) => ctx.gl().uniform_4fv(uniform_id, v), + WebGLCommand::Uniform4fv(uniform_id, ref v) => gl.uniform_4fv(uniform_id, v), WebGLCommand::Uniform4i(uniform_id, x, y, z, w) => { - ctx.gl().uniform_4i(uniform_id, x, y, z, w) + gl.uniform_4i(uniform_id, x, y, z, w) }, - WebGLCommand::Uniform4iv(uniform_id, ref v) => ctx.gl().uniform_4iv(uniform_id, v), + WebGLCommand::Uniform4iv(uniform_id, ref v) => gl.uniform_4iv(uniform_id, v), WebGLCommand::UniformMatrix2fv(uniform_id, ref v) => { - ctx.gl().uniform_matrix_2fv(uniform_id, false, v) + gl.uniform_matrix_2fv(uniform_id, false, v) }, WebGLCommand::UniformMatrix3fv(uniform_id, ref v) => { - ctx.gl().uniform_matrix_3fv(uniform_id, false, v) + gl.uniform_matrix_3fv(uniform_id, false, v) }, WebGLCommand::UniformMatrix4fv(uniform_id, ref v) => { - ctx.gl().uniform_matrix_4fv(uniform_id, false, v) - }, - WebGLCommand::ValidateProgram(program_id) => { - ctx.gl().validate_program(program_id.get()) + gl.uniform_matrix_4fv(uniform_id, false, v) }, + WebGLCommand::ValidateProgram(program_id) => gl.validate_program(program_id.get()), WebGLCommand::VertexAttrib(attrib_id, x, y, z, w) => { - ctx.gl().vertex_attrib_4f(attrib_id, x, y, z, w) + gl.vertex_attrib_4f(attrib_id, x, y, z, w) + }, + WebGLCommand::VertexAttribPointer2f(attrib_id, size, normalized, stride, offset) => { + gl.vertex_attrib_pointer_f32(attrib_id, size, normalized, stride, offset) }, - WebGLCommand::VertexAttribPointer2f(attrib_id, size, normalized, stride, offset) => ctx - .gl() - .vertex_attrib_pointer_f32(attrib_id, size, normalized, stride, offset), WebGLCommand::VertexAttribPointer( attrib_id, size, @@ -1226,12 +1253,8 @@ impl WebGLImpl { normalized, stride, offset, - ) => ctx - .gl() - .vertex_attrib_pointer(attrib_id, size, data_type, normalized, stride, offset), - WebGLCommand::SetViewport(x, y, width, height) => { - ctx.gl().viewport(x, y, width, height); - }, + ) => gl.vertex_attrib_pointer(attrib_id, size, data_type, normalized, stride, offset), + WebGLCommand::SetViewport(x, y, width, height) => gl.viewport(x, y, width, height), WebGLCommand::TexImage2D { target, level, @@ -1257,9 +1280,8 @@ impl WebGLImpl { Cow::Borrowed(&*data), ); - ctx.gl() - .pixel_store_i(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32); - ctx.gl().tex_image_2d( + gl.pixel_store_i(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32); + gl.tex_image_2d( target, level as i32, effective_internal_format as i32, @@ -1297,9 +1319,8 @@ impl WebGLImpl { Cow::Borrowed(&*data), ); - ctx.gl() - .pixel_store_i(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32); - ctx.gl().tex_sub_image_2d( + gl.pixel_store_i(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32); + gl.tex_sub_image_2d( target, level as i32, xoffset, @@ -1318,7 +1339,7 @@ impl WebGLImpl { size, ref data, } => { - ctx.gl().compressed_tex_image_2d( + gl.compressed_tex_image_2d( target, level as i32, internal_format, @@ -1337,7 +1358,7 @@ impl WebGLImpl { format, ref data, } => { - ctx.gl().compressed_tex_sub_image_2d( + gl.compressed_tex_sub_image_2d( target, level as i32, xoffset as i32, @@ -1348,84 +1369,71 @@ impl WebGLImpl { &*data, ); }, - WebGLCommand::DrawingBufferWidth(ref sender) => sender - .send(ctx.borrow_draw_buffer().unwrap().size().width) - .unwrap(), - WebGLCommand::DrawingBufferHeight(ref sender) => sender - .send(ctx.borrow_draw_buffer().unwrap().size().height) - .unwrap(), - WebGLCommand::Finish(ref sender) => Self::finish(ctx.gl(), sender), - WebGLCommand::Flush => ctx.gl().flush(), - WebGLCommand::GenerateMipmap(target) => ctx.gl().generate_mipmap(target), + WebGLCommand::DrawingBufferWidth(ref sender) => { + let size = device + .context_surface_size(&ctx) + .expect("Where's the front buffer?"); + sender.send(size.width).unwrap() + }, + WebGLCommand::DrawingBufferHeight(ref sender) => { + let size = device + .context_surface_size(&ctx) + .expect("Where's the front buffer?"); + sender.send(size.height).unwrap() + }, + WebGLCommand::Finish(ref sender) => Self::finish(gl, sender), + WebGLCommand::Flush => gl.flush(), + WebGLCommand::GenerateMipmap(target) => gl.generate_mipmap(target), WebGLCommand::CreateVertexArray(ref chan) => { - Self::create_vertex_array(ctx.gl(), use_apple_vertex_array, chan) + let use_apple_vertex_array = Self::needs_apple_vertex_arrays(state.gl_version); + let id = Self::create_vertex_array(gl, use_apple_vertex_array, state.webgl_version); + let _ = chan.send(id); }, WebGLCommand::DeleteVertexArray(id) => { - let gl = ctx.gl(); - let ids = [id.get()]; - if use_apple_vertex_array { - match gl { - Gl::Gl(gl) => unsafe { - gl.DeleteVertexArraysAPPLE(ids.len() as gl::GLsizei, ids.as_ptr()); - }, - Gl::Gles(_) => unimplemented!("No GLES on macOS"), - } - } else { - gl.delete_vertex_arrays(&ids) - } + let use_apple_vertex_array = Self::needs_apple_vertex_arrays(state.gl_version); + let id = id.get(); + Self::delete_vertex_array(gl, id, use_apple_vertex_array, state.webgl_version); }, WebGLCommand::BindVertexArray(id) => { - let gl = ctx.gl(); - let id = id.map_or(0, WebGLVertexArrayId::get); - if use_apple_vertex_array { - match gl { - Gl::Gl(gl) => unsafe { - gl.BindVertexArrayAPPLE(id); - }, - Gl::Gles(_) => unimplemented!("No GLES on macOS"), - } - } else { - gl.bind_vertex_array(id) - } + let id = id.map_or(state.default_vao, WebGLVertexArrayId::get); + let use_apple_vertex_array = Self::needs_apple_vertex_arrays(state.gl_version); + Self::bind_vertex_array(gl, id, use_apple_vertex_array, state.webgl_version); }, WebGLCommand::GetParameterBool(param, ref sender) => { let mut value = [0]; unsafe { - ctx.gl().get_boolean_v(param as u32, &mut value); + gl.get_boolean_v(param as u32, &mut value); } sender.send(value[0] != 0).unwrap() }, WebGLCommand::FenceSync(ref sender) => { - let value = ctx.gl().fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0); + let value = gl.fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0); sender .send(unsafe { WebGLSyncId::new(value as u64) }) .unwrap(); }, WebGLCommand::IsSync(sync_id, ref sender) => { - let value = ctx.gl().is_sync(sync_id.get() as *const _); + let value = gl.is_sync(sync_id.get() as *const _); sender.send(value).unwrap(); }, WebGLCommand::ClientWaitSync(sync_id, flags, timeout, ref sender) => { - let value = - ctx.gl() - .client_wait_sync(sync_id.get() as *const _, flags, timeout as u64); + let value = gl.client_wait_sync(sync_id.get() as *const _, flags, timeout as u64); sender.send(value).unwrap(); }, WebGLCommand::WaitSync(sync_id, flags, timeout) => { - ctx.gl() - .wait_sync(sync_id.get() as *const _, flags, timeout as u64); + gl.wait_sync(sync_id.get() as *const _, flags, timeout as u64); }, WebGLCommand::GetSyncParameter(sync_id, param, ref sender) => { - let value = ctx.gl().get_sync_iv(sync_id.get() as *const _, param); + let value = gl.get_sync_iv(sync_id.get() as *const _, param); sender.send(value[0] as u32).unwrap(); }, WebGLCommand::DeleteSync(sync_id) => { - ctx.gl().delete_sync(sync_id.get() as *const _); + gl.delete_sync(sync_id.get() as *const _); }, WebGLCommand::GetParameterBool4(param, ref sender) => { let mut value = [0; 4]; unsafe { - ctx.gl().get_boolean_v(param as u32, &mut value); + 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() @@ -1433,133 +1441,122 @@ impl WebGLImpl { WebGLCommand::GetParameterInt(param, ref sender) => { let mut value = [0]; unsafe { - ctx.gl().get_integer_v(param as u32, &mut value); + gl.get_integer_v(param as u32, &mut value); } sender.send(value[0]).unwrap() }, WebGLCommand::GetParameterInt2(param, ref sender) => { let mut value = [0; 2]; unsafe { - ctx.gl().get_integer_v(param as u32, &mut value); + gl.get_integer_v(param as u32, &mut value); } sender.send(value).unwrap() }, WebGLCommand::GetParameterInt4(param, ref sender) => { let mut value = [0; 4]; unsafe { - ctx.gl().get_integer_v(param as u32, &mut value); + gl.get_integer_v(param as u32, &mut value); } sender.send(value).unwrap() }, WebGLCommand::GetParameterFloat(param, ref sender) => { let mut value = [0.]; unsafe { - ctx.gl().get_float_v(param as u32, &mut value); + gl.get_float_v(param as u32, &mut value); } sender.send(value[0]).unwrap() }, WebGLCommand::GetParameterFloat2(param, ref sender) => { let mut value = [0.; 2]; unsafe { - ctx.gl().get_float_v(param as u32, &mut value); + gl.get_float_v(param as u32, &mut value); } sender.send(value).unwrap() }, WebGLCommand::GetParameterFloat4(param, ref sender) => { let mut value = [0.; 4]; unsafe { - ctx.gl().get_float_v(param as u32, &mut value); + gl.get_float_v(param as u32, &mut value); } sender.send(value).unwrap() }, WebGLCommand::GetProgramValidateStatus(program, ref sender) => { let mut value = [0]; unsafe { - ctx.gl() - .get_program_iv(program.get(), gl::VALIDATE_STATUS, &mut value); + gl.get_program_iv(program.get(), gl::VALIDATE_STATUS, &mut value); } sender.send(value[0] != 0).unwrap() }, WebGLCommand::GetProgramActiveUniforms(program, ref sender) => { let mut value = [0]; unsafe { - ctx.gl() - .get_program_iv(program.get(), gl::ACTIVE_UNIFORMS, &mut value); + gl.get_program_iv(program.get(), gl::ACTIVE_UNIFORMS, &mut value); } sender.send(value[0]).unwrap() }, WebGLCommand::GetCurrentVertexAttrib(index, ref sender) => { let mut value = [0.; 4]; unsafe { - ctx.gl() - .get_vertex_attrib_fv(index, gl::CURRENT_VERTEX_ATTRIB, &mut value); + gl.get_vertex_attrib_fv(index, gl::CURRENT_VERTEX_ATTRIB, &mut value); } sender.send(value).unwrap(); }, WebGLCommand::GetTexParameterFloat(target, param, ref sender) => { sender - .send(ctx.gl().get_tex_parameter_fv(target, param as u32)) + .send(gl.get_tex_parameter_fv(target, param as u32)) .unwrap(); }, WebGLCommand::GetTexParameterInt(target, param, ref sender) => { sender - .send(ctx.gl().get_tex_parameter_iv(target, param as u32)) + .send(gl.get_tex_parameter_iv(target, param as u32)) .unwrap(); }, WebGLCommand::TexParameteri(target, param, value) => { - ctx.gl().tex_parameter_i(target, param as u32, value) + gl.tex_parameter_i(target, param as u32, value) }, WebGLCommand::TexParameterf(target, param, value) => { - ctx.gl().tex_parameter_f(target, param as u32, value) + gl.tex_parameter_f(target, param as u32, value) }, WebGLCommand::LinkProgram(program_id, ref sender) => { - return sender - .send(Self::link_program(ctx.gl(), program_id)) - .unwrap(); + return sender.send(Self::link_program(gl, program_id)).unwrap(); }, WebGLCommand::UseProgram(program_id) => { - ctx.gl().use_program(program_id.map_or(0, |p| p.get())) - }, - WebGLCommand::DrawArrays { mode, first, count } => { - ctx.gl().draw_arrays(mode, first, count) + gl.use_program(program_id.map_or(0, |p| p.get())) }, + WebGLCommand::DrawArrays { mode, first, count } => gl.draw_arrays(mode, first, count), WebGLCommand::DrawArraysInstanced { mode, first, count, primcount, - } => ctx - .gl() - .draw_arrays_instanced(mode, first, count, primcount), + } => gl.draw_arrays_instanced(mode, first, count, primcount), WebGLCommand::DrawElements { mode, count, type_, offset, - } => ctx.gl().draw_elements(mode, count, type_, offset), + } => gl.draw_elements(mode, count, type_, offset), WebGLCommand::DrawElementsInstanced { mode, count, type_, offset, primcount, - } => ctx - .gl() - .draw_elements_instanced(mode, count, type_, offset, primcount), + } => gl.draw_elements_instanced(mode, count, type_, offset, primcount), WebGLCommand::VertexAttribDivisor { index, divisor } => { - ctx.gl().vertex_attrib_divisor(index, divisor) + gl.vertex_attrib_divisor(index, divisor) }, WebGLCommand::GetUniformBool(program_id, loc, ref sender) => { let mut value = [0]; unsafe { - ctx.gl().get_uniform_iv(program_id.get(), loc, &mut value); + gl.get_uniform_iv(program_id.get(), loc, &mut value); } sender.send(value[0] != 0).unwrap(); }, WebGLCommand::GetUniformBool2(program_id, loc, ref sender) => { let mut value = [0; 2]; unsafe { - ctx.gl().get_uniform_iv(program_id.get(), loc, &mut value); + gl.get_uniform_iv(program_id.get(), loc, &mut value); } let value = [value[0] != 0, value[1] != 0]; sender.send(value).unwrap(); @@ -1567,7 +1564,7 @@ impl WebGLImpl { WebGLCommand::GetUniformBool3(program_id, loc, ref sender) => { let mut value = [0; 3]; unsafe { - ctx.gl().get_uniform_iv(program_id.get(), loc, &mut value); + gl.get_uniform_iv(program_id.get(), loc, &mut value); } let value = [value[0] != 0, value[1] != 0, value[2] != 0]; sender.send(value).unwrap(); @@ -1575,7 +1572,7 @@ impl WebGLImpl { WebGLCommand::GetUniformBool4(program_id, loc, ref sender) => { let mut value = [0; 4]; unsafe { - ctx.gl().get_uniform_iv(program_id.get(), loc, &mut value); + gl.get_uniform_iv(program_id.get(), loc, &mut value); } let value = [value[0] != 0, value[1] != 0, value[2] != 0, value[3] != 0]; sender.send(value).unwrap(); @@ -1583,70 +1580,70 @@ impl WebGLImpl { WebGLCommand::GetUniformInt(program_id, loc, ref sender) => { let mut value = [0]; unsafe { - ctx.gl().get_uniform_iv(program_id.get(), loc, &mut value); + gl.get_uniform_iv(program_id.get(), loc, &mut value); } sender.send(value[0]).unwrap(); }, WebGLCommand::GetUniformInt2(program_id, loc, ref sender) => { let mut value = [0; 2]; unsafe { - ctx.gl().get_uniform_iv(program_id.get(), loc, &mut value); + gl.get_uniform_iv(program_id.get(), loc, &mut value); } sender.send(value).unwrap(); }, WebGLCommand::GetUniformInt3(program_id, loc, ref sender) => { let mut value = [0; 3]; unsafe { - ctx.gl().get_uniform_iv(program_id.get(), loc, &mut value); + gl.get_uniform_iv(program_id.get(), loc, &mut value); } sender.send(value).unwrap(); }, WebGLCommand::GetUniformInt4(program_id, loc, ref sender) => { let mut value = [0; 4]; unsafe { - ctx.gl().get_uniform_iv(program_id.get(), loc, &mut value); + gl.get_uniform_iv(program_id.get(), loc, &mut value); } sender.send(value).unwrap(); }, WebGLCommand::GetUniformFloat(program_id, loc, ref sender) => { let mut value = [0.]; unsafe { - ctx.gl().get_uniform_fv(program_id.get(), loc, &mut value); + gl.get_uniform_fv(program_id.get(), loc, &mut value); } sender.send(value[0]).unwrap(); }, WebGLCommand::GetUniformFloat2(program_id, loc, ref sender) => { let mut value = [0.; 2]; unsafe { - ctx.gl().get_uniform_fv(program_id.get(), loc, &mut value); + gl.get_uniform_fv(program_id.get(), loc, &mut value); } sender.send(value).unwrap(); }, WebGLCommand::GetUniformFloat3(program_id, loc, ref sender) => { let mut value = [0.; 3]; unsafe { - ctx.gl().get_uniform_fv(program_id.get(), loc, &mut value); + gl.get_uniform_fv(program_id.get(), loc, &mut value); } sender.send(value).unwrap(); }, WebGLCommand::GetUniformFloat4(program_id, loc, ref sender) => { let mut value = [0.; 4]; unsafe { - ctx.gl().get_uniform_fv(program_id.get(), loc, &mut value); + gl.get_uniform_fv(program_id.get(), loc, &mut value); } sender.send(value).unwrap(); }, WebGLCommand::GetUniformFloat9(program_id, loc, ref sender) => { let mut value = [0.; 9]; unsafe { - ctx.gl().get_uniform_fv(program_id.get(), loc, &mut value); + gl.get_uniform_fv(program_id.get(), loc, &mut value); } sender.send(value).unwrap(); }, WebGLCommand::GetUniformFloat16(program_id, loc, ref sender) => { let mut value = [0.; 16]; unsafe { - ctx.gl().get_uniform_fv(program_id.get(), loc, &mut value); + gl.get_uniform_fv(program_id.get(), loc, &mut value); } sender.send(value).unwrap(); }, @@ -1654,78 +1651,83 @@ impl WebGLImpl { color, depth, stencil, - } => Self::initialize_framebuffer(ctx.gl(), state, color, depth, stencil), + } => Self::initialize_framebuffer(gl, state, color, depth, stencil), WebGLCommand::BeginQuery(target, query_id) => { - ctx.gl().begin_query(target, query_id.get()); + gl.begin_query(target, query_id.get()); }, WebGLCommand::EndQuery(target) => { - ctx.gl().end_query(target); + gl.end_query(target); }, WebGLCommand::DeleteQuery(query_id) => { - ctx.gl().delete_queries(&[query_id.get()]); + gl.delete_queries(&[query_id.get()]); }, WebGLCommand::GenerateQuery(ref sender) => { - let id = ctx.gl().gen_queries(1)[0]; + let id = gl.gen_queries(1)[0]; sender.send(unsafe { WebGLQueryId::new(id) }).unwrap() }, WebGLCommand::GetQueryState(ref sender, query_id, pname) => { - let value = ctx.gl().get_query_object_uiv(query_id.get(), pname); + let value = gl.get_query_object_uiv(query_id.get(), pname); sender.send(value).unwrap() }, WebGLCommand::GenerateSampler(ref sender) => { - let id = ctx.gl().gen_samplers(1)[0]; + let id = gl.gen_samplers(1)[0]; sender.send(unsafe { WebGLSamplerId::new(id) }).unwrap() }, WebGLCommand::DeleteSampler(sampler_id) => { - ctx.gl().delete_samplers(&[sampler_id.get()]); + gl.delete_samplers(&[sampler_id.get()]); }, WebGLCommand::BindSampler(unit, sampler_id) => { - ctx.gl().bind_sampler(unit, sampler_id.get()); + gl.bind_sampler(unit, sampler_id.get()); }, WebGLCommand::SetSamplerParameterInt(sampler_id, pname, value) => { - ctx.gl().sampler_parameter_i(sampler_id.get(), pname, value); + gl.sampler_parameter_i(sampler_id.get(), pname, value); }, WebGLCommand::SetSamplerParameterFloat(sampler_id, pname, value) => { - ctx.gl().sampler_parameter_f(sampler_id.get(), pname, value); + gl.sampler_parameter_f(sampler_id.get(), pname, value); }, WebGLCommand::GetSamplerParameterInt(sampler_id, pname, ref sender) => { - let value = ctx.gl().get_sampler_parameter_iv(sampler_id.get(), pname)[0]; + let value = gl.get_sampler_parameter_iv(sampler_id.get(), pname)[0]; sender.send(value).unwrap(); }, WebGLCommand::GetSamplerParameterFloat(sampler_id, pname, ref sender) => { - let value = ctx.gl().get_sampler_parameter_fv(sampler_id.get(), pname)[0]; + let value = gl.get_sampler_parameter_fv(sampler_id.get(), pname)[0]; sender.send(value).unwrap(); }, } - // TODO: update test expectations in order to enable debug assertions - let error = ctx.gl().get_error(); - if error != gl::NO_ERROR { - error!("Last GL operation failed: {:?}", command); - #[cfg(feature = "webgl_backtrace")] - { - error!("Backtrace from failed WebGL API:\n{}", _backtrace.backtrace); - if let Some(backtrace) = _backtrace.js_backtrace { - error!("JS backtrace from failed WebGL API:\n{}", backtrace); + // If debug asertions are enabled, then check the error state. + #[cfg(debug_assertions)] + { + let error = gl.get_error(); + if error != gl::NO_ERROR { + error!("Last GL operation failed: {:?}", command); + if error == gl::INVALID_FRAMEBUFFER_OPERATION { + let mut framebuffer_bindings = [0]; + unsafe { + gl.get_integer_v(gl::DRAW_FRAMEBUFFER_BINDING, &mut framebuffer_bindings); + } + debug!( + "(thread {:?}) Current draw framebuffer binding: {}", + ::std::thread::current().id(), + framebuffer_bindings[0] + ); } + #[cfg(feature = "webgl_backtrace")] + { + error!("Backtrace from failed WebGL API:\n{}", _backtrace.backtrace); + if let Some(backtrace) = _backtrace.js_backtrace { + error!("JS backtrace from failed WebGL API:\n{}", backtrace); + } + } + panic!( + "Unexpected WebGL error: 0x{:x} ({}) [{:?}]", + error, error, command + ); } } - assert_eq!( - error, - gl::NO_ERROR, - "Unexpected WebGL error: 0x{:x} ({})", - error, - error - ); } - fn initialize_framebuffer( - gl: &gl::Gl, - state: &GLState, - color: bool, - depth: bool, - stencil: bool, - ) { + fn initialize_framebuffer(gl: &Gl, state: &GLState, color: bool, depth: bool, stencil: bool) { let bits = [ (color, gl::COLOR_BUFFER_BIT), (depth, gl::DEPTH_BUFFER_BIT), @@ -1780,7 +1782,7 @@ impl WebGLImpl { } #[allow(unsafe_code)] - fn link_program(gl: &gl::Gl, program: WebGLProgramId) -> ProgramLinkInfo { + fn link_program(gl: &Gl, program: WebGLProgramId) -> ProgramLinkInfo { gl.link_program(program.get()); let mut linked = [0]; unsafe { @@ -1853,13 +1855,13 @@ impl WebGLImpl { } } - fn finish(gl: &gl::Gl, chan: &WebGLSender<()>) { + fn finish(gl: &Gl, chan: &WebGLSender<()>) { gl.finish(); chan.send(()).unwrap(); } fn shader_precision_format( - gl: &gl::Gl, + gl: &Gl, shader_type: u32, precision_type: u32, chan: &WebGLSender<(i32, i32, i32)>, @@ -1868,8 +1870,16 @@ impl WebGLImpl { chan.send(result).unwrap(); } + // surfman creates a legacy OpenGL context on macOS when + // OpenGL 2 support is requested. Legacy contexts return GL errors for the vertex + // array object functions, but support a set of APPLE extension functions that + // provide VAO support instead. + fn needs_apple_vertex_arrays(gl_version: GLVersion) -> bool { + cfg!(target_os = "macos") && !opts::get().headless && gl_version.major < 3 + } + #[allow(unsafe_code)] - fn get_extensions(gl: &gl::Gl, chan: &WebGLSender) { + fn get_extensions(gl: &Gl, chan: &WebGLSender) { let mut ext_count = [0]; unsafe { gl.get_integer_v(gl::NUM_EXTENSIONS, &mut ext_count); @@ -1890,7 +1900,7 @@ impl WebGLImpl { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6 fn get_framebuffer_attachment_parameter( - gl: &gl::Gl, + gl: &Gl, target: u32, attachment: u32, pname: u32, @@ -1901,34 +1911,29 @@ impl WebGLImpl { } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7 - fn get_renderbuffer_parameter(gl: &gl::Gl, target: u32, pname: u32, chan: &WebGLSender) { + fn get_renderbuffer_parameter(gl: &Gl, target: u32, pname: u32, chan: &WebGLSender) { let parameter = gl.get_renderbuffer_parameter_iv(target, pname); chan.send(parameter).unwrap(); } - fn uniform_location( - gl: &gl::Gl, - program_id: WebGLProgramId, - name: &str, - chan: &WebGLSender, - ) { + fn uniform_location(gl: &Gl, program_id: WebGLProgramId, name: &str, chan: &WebGLSender) { let location = gl.get_uniform_location(program_id.get(), &to_name_in_compiled_shader(name)); assert!(location >= 0); chan.send(location).unwrap(); } - fn shader_info_log(gl: &gl::Gl, shader_id: WebGLShaderId, chan: &WebGLSender) { + fn shader_info_log(gl: &Gl, shader_id: WebGLShaderId, chan: &WebGLSender) { let log = gl.get_shader_info_log(shader_id.get()); chan.send(log).unwrap(); } - fn program_info_log(gl: &gl::Gl, program_id: WebGLProgramId, chan: &WebGLSender) { + fn program_info_log(gl: &Gl, program_id: WebGLProgramId, chan: &WebGLSender) { let log = gl.get_program_info_log(program_id.get()); chan.send(log).unwrap(); } #[allow(unsafe_code)] - fn create_buffer(gl: &gl::Gl, chan: &WebGLSender>) { + fn create_buffer(gl: &Gl, chan: &WebGLSender>) { let buffer = gl.gen_buffers(1)[0]; let buffer = if buffer == 0 { None @@ -1939,18 +1944,18 @@ impl WebGLImpl { } #[allow(unsafe_code)] - fn create_framebuffer(gl: &gl::Gl, chan: &WebGLSender>) { + fn create_framebuffer(gl: &Gl, chan: &WebGLSender>) { let framebuffer = gl.gen_framebuffers(1)[0]; let framebuffer = if framebuffer == 0 { None } else { - Some(unsafe { WebGLFramebufferId::new(framebuffer) }) + Some(unsafe { WebGLTransparentFramebufferId::new(framebuffer) }) }; chan.send(framebuffer).unwrap(); } #[allow(unsafe_code)] - fn create_renderbuffer(gl: &gl::Gl, chan: &WebGLSender>) { + fn create_renderbuffer(gl: &Gl, chan: &WebGLSender>) { let renderbuffer = gl.gen_renderbuffers(1)[0]; let renderbuffer = if renderbuffer == 0 { None @@ -1961,7 +1966,7 @@ impl WebGLImpl { } #[allow(unsafe_code)] - fn create_texture(gl: &gl::Gl, chan: &WebGLSender>) { + fn create_texture(gl: &Gl, chan: &WebGLSender>) { let texture = gl.gen_textures(1)[0]; let texture = if texture == 0 { None @@ -1972,7 +1977,7 @@ impl WebGLImpl { } #[allow(unsafe_code)] - fn create_program(gl: &gl::Gl, chan: &WebGLSender>) { + fn create_program(gl: &Gl, chan: &WebGLSender>) { let program = gl.create_program(); let program = if program == 0 { None @@ -1983,7 +1988,7 @@ impl WebGLImpl { } #[allow(unsafe_code)] - fn create_shader(gl: &gl::Gl, shader_type: u32, chan: &WebGLSender>) { + fn create_shader(gl: &Gl, shader_type: u32, chan: &WebGLSender>) { let shader = gl.create_shader(shader_type); let shader = if shader == 0 { None @@ -1995,51 +2000,135 @@ impl WebGLImpl { #[allow(unsafe_code)] fn create_vertex_array( - gl: &gl::Gl, + gl: &Gl, use_apple_ext: bool, - chan: &WebGLSender>, - ) { - let vao = if use_apple_ext { - match gl { - Gl::Gl(gl) => { - let mut ids = vec![0]; - unsafe { - gl.GenVertexArraysAPPLE(ids.len() as gl::GLsizei, ids.as_mut_ptr()); - } - ids[0] - }, - Gl::Gles(_) => unimplemented!("No GLES on macOS"), - } - } else { - gl.gen_vertex_arrays(1)[0] + version: WebGLVersion, + ) -> Option { + let vao = match gl { + Gl::Gl(ref gl) if use_apple_ext => { + let mut ids = vec![0]; + unsafe { + gl.GenVertexArraysAPPLE(ids.len() as gl::GLsizei, ids.as_mut_ptr()); + } + ids[0] + }, + Gl::Gles(ref gles) if version == WebGLVersion::WebGL1 => { + let mut ids = vec![0]; + unsafe { gles.GenVertexArraysOES(ids.len() as gl::GLsizei, ids.as_mut_ptr()) } + ids[0] + }, + _ => gl.gen_vertex_arrays(1)[0], }; - let vao = if vao == 0 { + if vao == 0 { + let code = gl.get_error(); + warn!("Failed to create vertex array with error code {:x}", code); None } else { Some(unsafe { WebGLVertexArrayId::new(vao) }) + } + } + + #[allow(unsafe_code)] + fn bind_vertex_array(gl: &Gl, vao: GLuint, use_apple_ext: bool, version: WebGLVersion) { + match gl { + Gl::Gl(ref gl) if use_apple_ext => unsafe { + gl.BindVertexArrayAPPLE(vao); + }, + Gl::Gles(ref gles) if version == WebGLVersion::WebGL1 => unsafe { + gles.BindVertexArrayOES(vao); + }, + _ => gl.bind_vertex_array(vao), + } + debug_assert_eq!(gl.get_error(), gl::NO_ERROR); + } + + #[allow(unsafe_code)] + fn delete_vertex_array(gl: &Gl, vao: GLuint, use_apple_ext: bool, version: WebGLVersion) { + let vaos = [vao]; + match gl { + Gl::Gl(ref gl) if use_apple_ext => unsafe { + gl.DeleteVertexArraysAPPLE(vaos.len() as gl::GLsizei, vaos.as_ptr()); + }, + Gl::Gles(ref gl) if version == WebGLVersion::WebGL1 => unsafe { + gl.DeleteVertexArraysOES(vaos.len() as gl::GLsizei, vaos.as_ptr()); + }, + _ => gl.delete_vertex_arrays(&vaos), + } + debug_assert_eq!(gl.get_error(), gl::NO_ERROR); + } + + /// Updates the swap buffers if the context surface needs to be changed + fn attach_surface( + context_id: WebGLContextId, + webrender_swap_chains: &SwapChains, + webxr_swap_chains: &SwapChains, + request: WebGLFramebufferBindingRequest, + ctx: &mut Context, + device: &mut Device, + ) -> Option<()> { + debug!( + "WebGLImpl::attach_surface({:?} in {:?})", + request, context_id + ); + let requested_framebuffer = match request { + WebGLFramebufferBindingRequest::Explicit(WebGLFramebufferId::Opaque(id)) => Some(id), + WebGLFramebufferBindingRequest::Explicit(WebGLFramebufferId::Transparent(_)) => { + return None + }, + WebGLFramebufferBindingRequest::Default => None, }; - chan.send(vao).unwrap(); + let attached_framebuffer = webxr_swap_chains + .iter(device, ctx) + .filter_map(|(id, swap_chain)| { + if swap_chain.is_attached() { + Some(id) + } else { + None + } + }) + .map(WebGLOpaqueFramebufferId::WebXR) + .next(); + if requested_framebuffer == attached_framebuffer { + return None; + } + let requested_swap_chain = match requested_framebuffer { + Some(WebGLOpaqueFramebufferId::WebXR(id)) => webxr_swap_chains.get(id)?, + None => webrender_swap_chains.get(context_id)?, + }; + let current_swap_chain = match attached_framebuffer { + Some(WebGLOpaqueFramebufferId::WebXR(id)) => webxr_swap_chains.get(id)?, + None => webrender_swap_chains.get(context_id)?, + }; + requested_swap_chain + .take_attachment_from(device, ctx, ¤t_swap_chain) + .unwrap(); + Some(()) } #[inline] - fn bind_framebuffer( - gl: &gl::Gl, + fn bind_framebuffer( + gl: &Gl, target: u32, request: WebGLFramebufferBindingRequest, - ctx: &GLContext, + ctx: &Context, + device: &Device, ) { let id = match request { - WebGLFramebufferBindingRequest::Explicit(id) => id.get(), - WebGLFramebufferBindingRequest::Default => { - ctx.borrow_draw_buffer().unwrap().get_framebuffer() + WebGLFramebufferBindingRequest::Explicit(WebGLFramebufferId::Transparent(id)) => { + id.get() }, + WebGLFramebufferBindingRequest::Explicit(WebGLFramebufferId::Opaque(_)) | + WebGLFramebufferBindingRequest::Default => device + .context_surface_framebuffer_object(ctx) + .expect("No surface attached!"), }; + debug!("WebGLImpl::bind_framebuffer: {:?}", id); gl.bind_framebuffer(target, id); } #[inline] - fn compile_shader(gl: &gl::Gl, shader_id: WebGLShaderId, source: &str) { + fn compile_shader(gl: &Gl, shader_id: WebGLShaderId, source: &str) { gl.shader_source(shader_id.get(), &[source.as_bytes()]); gl.compile_shader(shader_id.get()); } @@ -2422,3 +2511,113 @@ fn flip_pixels_y( flipped } + +// Clamp a size to the current GL context's max viewport +fn clamp_viewport(gl: &Gl, size: Size2D) -> Size2D { + let mut max_size = [i32::max_value(), i32::max_value()]; + #[allow(unsafe_code)] + unsafe { + gl.get_integer_v(gl::MAX_VIEWPORT_DIMS, &mut max_size); + debug_assert_eq!(gl.get_error(), gl::NO_ERROR); + } + Size2D::new( + size.width.min(max_size[0] as u32).max(1), + size.height.min(max_size[1] as u32).max(1), + ) +} + +trait ToSurfmanVersion { + fn to_surfman_version(self) -> GLVersion; +} + +impl ToSurfmanVersion for WebGLVersion { + fn to_surfman_version(self) -> GLVersion { + match self { + WebGLVersion::WebGL1 => GLVersion::new(2, 0), + WebGLVersion::WebGL2 => GLVersion::new(3, 0), + } + } +} + +trait SurfmanContextAttributeFlagsConvert { + fn to_surfman_context_attribute_flags(&self) -> ContextAttributeFlags; +} + +impl SurfmanContextAttributeFlagsConvert for GLContextAttributes { + fn to_surfman_context_attribute_flags(&self) -> ContextAttributeFlags { + let mut flags = ContextAttributeFlags::empty(); + flags.set(ContextAttributeFlags::ALPHA, self.alpha); + flags.set(ContextAttributeFlags::DEPTH, self.depth); + flags.set(ContextAttributeFlags::STENCIL, self.stencil); + // TODO: should we always set this to true? + flags.set(ContextAttributeFlags::COMPATIBILITY_PROFILE, true); + flags + } +} + +bitflags! { + struct FramebufferRebindingFlags: u8 { + const REBIND_READ_FRAMEBUFFER = 0x1; + const REBIND_DRAW_FRAMEBUFFER = 0x2; + } +} + +struct FramebufferRebindingInfo { + flags: FramebufferRebindingFlags, + viewport: [GLint; 4], +} + +impl FramebufferRebindingInfo { + #[allow(unsafe_code)] + fn detect(device: &Device, context: &Context, gl: &Gl) -> FramebufferRebindingInfo { + unsafe { + let (mut read_framebuffer, mut draw_framebuffer) = ([0], [0]); + gl.get_integer_v(gl::READ_FRAMEBUFFER_BINDING, &mut read_framebuffer); + gl.get_integer_v(gl::DRAW_FRAMEBUFFER_BINDING, &mut draw_framebuffer); + + let context_surface_framebuffer = + device.context_surface_framebuffer_object(context).unwrap(); + + let mut flags = FramebufferRebindingFlags::empty(); + if context_surface_framebuffer == read_framebuffer[0] as GLuint { + flags.insert(FramebufferRebindingFlags::REBIND_READ_FRAMEBUFFER); + } + if context_surface_framebuffer == draw_framebuffer[0] as GLuint { + flags.insert(FramebufferRebindingFlags::REBIND_DRAW_FRAMEBUFFER); + } + + let mut viewport = [0; 4]; + gl.get_integer_v(gl::VIEWPORT, &mut viewport); + + FramebufferRebindingInfo { flags, viewport } + } + } + + fn apply(self, device: &Device, context: &Context, gl: &Gl) { + if self.flags.is_empty() { + return; + } + + let context_surface_framebuffer = + device.context_surface_framebuffer_object(context).unwrap(); + if self + .flags + .contains(FramebufferRebindingFlags::REBIND_READ_FRAMEBUFFER) + { + gl.bind_framebuffer(gl::READ_FRAMEBUFFER, context_surface_framebuffer); + } + if self + .flags + .contains(FramebufferRebindingFlags::REBIND_DRAW_FRAMEBUFFER) + { + gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, context_surface_framebuffer); + } + + gl.viewport( + self.viewport[0], + self.viewport[1], + self.viewport[2], + self.viewport[3], + ); + } +} diff --git a/components/canvas_traits/Cargo.toml b/components/canvas_traits/Cargo.toml index 516f4d66932..faf5aebcf32 100644 --- a/components/canvas_traits/Cargo.toml +++ b/components/canvas_traits/Cargo.toml @@ -27,3 +27,4 @@ servo_config = {path = "../config"} sparkle = "0.1" webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} webvr_traits = {path = "../webvr_traits"} +webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]} diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 62a04cac7fc..88b5f3e0bbc 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -5,6 +5,7 @@ use euclid::default::{Rect, Size2D}; use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender, IpcSharedMemory}; use pixels::PixelFormat; +use serde::{Deserialize, Serialize}; use sparkle::gl; use sparkle::gl::Gl; use std::borrow::Cow; @@ -13,6 +14,7 @@ use std::num::{NonZeroU32, NonZeroU64}; use std::ops::Deref; use webrender_api::{DocumentId, ImageKey, PipelineId}; use webvr_traits::WebVRPoseInformation; +use webxr_api::SwapChainId as WebXRSwapChainId; /// Helper function that creates a WebGL channel (WebGLSender, WebGLReceiver) to be used in WebGLCommands. pub use crate::webgl_channel::webgl_channel; @@ -35,6 +37,24 @@ pub struct WebGLCommandBacktrace { pub js_backtrace: Option, } +/// WebGL Threading API entry point that lives in the constellation. +pub struct WebGLThreads(pub WebGLSender); + +impl WebGLThreads { + /// Gets the WebGLThread handle for each script pipeline. + pub fn pipeline(&self) -> WebGLPipeline { + // This mode creates a single thread, so the existing WebGLChan is just cloned. + WebGLPipeline(WebGLChan(self.0.clone())) + } + + /// Sends a exit message to close the WebGLThreads and release all WebGLContexts. + pub fn exit(&self) -> Result<(), &'static str> { + self.0 + .send(WebGLMsg::Exit) + .map_err(|_| "Failed to send Exit message") + } +} + /// WebGL Message API #[derive(Debug, Deserialize, Serialize)] pub enum WebGLMsg { @@ -53,21 +73,16 @@ pub enum WebGLMsg { WebGLCommand(WebGLContextId, WebGLCommand, WebGLCommandBacktrace), /// Runs a WebVRCommand in a specific WebGLContext. WebVRCommand(WebGLContextId, WebVRCommand), - /// Locks a specific WebGLContext. Lock messages are used for a correct synchronization - /// with WebRender external image API. - /// WR locks a external texture when it wants to use the shared texture contents. - /// The WR client should not change the shared texture content until the Unlock call. - /// Currently OpenGL Sync Objects are used to implement the synchronization mechanism. - Lock(WebGLContextId, WebGLSender<(u32, Size2D, usize)>), - /// Unlocks a specific WebGLContext. Unlock messages are used for a correct synchronization - /// with WebRender external image API. - /// The WR unlocks a context when it finished reading the shared texture contents. - /// Unlock messages are always sent after a Lock message. - Unlock(WebGLContextId), /// Commands used for the DOMToTexture feature. DOMToTextureCommand(DOMToTextureCommand), + /// Creates a new opaque framebuffer for WebXR. + CreateWebXRSwapChain( + WebGLContextId, + Size2D, + WebGLSender>, + ), /// Performs a buffer swap. - SwapBuffers(Vec, WebGLSender<()>), + SwapBuffers(Vec, WebGLSender<()>), /// Frees all resources and closes the thread. Exit, } @@ -85,26 +100,14 @@ pub struct WebGLCreateContextResult { pub sender: WebGLMsgSender, /// Information about the internal GL Context. pub limits: GLLimits, - /// How the WebGLContext is shared with WebRender. - pub share_mode: WebGLContextShareMode, /// The GLSL version supported by the context. pub glsl_version: WebGLSLVersion, /// The GL API used by the context. pub api_type: GlType, - /// The format for creating new offscreen framebuffers for this context. - pub framebuffer_format: GLFormats, /// The WebRender image key. pub image_key: ImageKey, } -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)] -pub enum WebGLContextShareMode { - /// Fast: a shared texture_id is used in WebRender. - SharedTexture, - /// Slow: glReadPixels is used to send pixels to WebRender each frame. - Readback, -} - /// Defines the WebGL version #[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)] pub enum WebGLVersion { @@ -176,6 +179,28 @@ impl WebGLMsgSender { self.sender.send(WebGLMsg::RemoveContext(self.ctx_id)) } + #[inline] + pub fn send_create_webxr_swap_chain( + &self, + size: Size2D, + sender: WebGLSender>, + ) -> WebGLSendResult { + self.sender + .send(WebGLMsg::CreateWebXRSwapChain(self.ctx_id, size, sender)) + } + + #[inline] + pub fn send_swap_buffers(&self, id: Option) -> WebGLSendResult { + let swap_id = id + .map(|id| SwapChainId::Framebuffer(self.ctx_id, id)) + .unwrap_or_else(|| SwapChainId::Context(self.ctx_id)); + let (sender, receiver) = webgl_channel()?; + self.sender + .send(WebGLMsg::SwapBuffers(vec![swap_id], sender))?; + receiver.recv()?; + Ok(()) + } + pub fn send_dom_to_texture(&self, command: DOMToTextureCommand) -> WebGLSendResult { self.sender.send(WebGLMsg::DOMToTextureCommand(command)) } @@ -239,7 +264,7 @@ pub enum WebGLCommand { CopyTexImage2D(u32, i32, u32, i32, i32, i32, i32, i32), CopyTexSubImage2D(u32, i32, i32, i32, i32, i32, i32, i32), CreateBuffer(WebGLSender>), - CreateFramebuffer(WebGLSender>), + CreateFramebuffer(WebGLSender>), CreateRenderbuffer(WebGLSender>), CreateTexture(WebGLSender>), CreateProgram(WebGLSender>), @@ -517,7 +542,7 @@ macro_rules! define_resource_id { } define_resource_id!(WebGLBufferId, u32); -define_resource_id!(WebGLFramebufferId, u32); +define_resource_id!(WebGLTransparentFramebufferId, u32); define_resource_id!(WebGLRenderbufferId, u32); define_resource_id!(WebGLTextureId, u32); define_resource_id!(WebGLProgramId, u32); @@ -530,7 +555,22 @@ define_resource_id!(WebGLVertexArrayId, u32); #[derive( Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize, )] -pub struct WebGLContextId(pub usize); +pub struct WebGLContextId(pub u64); + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub enum SwapChainId { + Context(WebGLContextId), + Framebuffer(WebGLContextId, WebGLOpaqueFramebufferId), +} + +impl SwapChainId { + pub fn context_id(&self) -> WebGLContextId { + match *self { + SwapChainId::Context(id) => id, + SwapChainId::Framebuffer(id, _) => id, + } + } +} #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub enum WebGLError { @@ -542,6 +582,18 @@ pub enum WebGLError { ContextLost, } +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +pub enum WebGLOpaqueFramebufferId { + // At the moment the only source of opaque framebuffers is webxr + WebXR(#[ignore_malloc_size_of = "ids don't malloc"] WebXRSwapChainId), +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +pub enum WebGLFramebufferId { + Transparent(WebGLTransparentFramebufferId), + Opaque(WebGLOpaqueFramebufferId), +} + #[derive(Clone, Copy, Debug, Deserialize, Serialize)] pub enum WebGLFramebufferBindingRequest { Explicit(WebGLFramebufferId), @@ -915,9 +967,3 @@ pub struct GLLimits { pub max_vertex_uniform_vectors: u32, pub max_client_wait_timeout_webgl: std::time::Duration, } - -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)] -pub struct GLFormats { - pub texture_format: u32, - pub texture_type: u32, -} diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 22f9a9958c1..94f578d48f1 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -360,7 +360,7 @@ impl IOCompositor { } pub fn deinit(self) { - self.window.prepare_for_composite(); + self.window.make_gl_context_current(); self.webrender.deinit(); } @@ -1263,7 +1263,7 @@ impl IOCompositor { ) -> Result, UnableToComposite> { let size = self.embedder_coordinates.framebuffer.to_u32(); - self.window.prepare_for_composite(); + self.window.make_gl_context_current(); self.webrender.update(); let wait_for_stable_image = match target { diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 7e5b1530931..e2438e40518 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -144,9 +144,8 @@ pub enum AnimationState { pub trait WindowMethods { /// Presents the window to the screen (perhaps by page flipping). fn present(&self); - /// Requests that the window system prepare a composite. Typically this will involve making - /// some type of platform-specific graphics context current. - fn prepare_for_composite(&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; diff --git a/components/constellation/Cargo.toml b/components/constellation/Cargo.toml index 7b53d443e5c..ec360006aad 100644 --- a/components/constellation/Cargo.toml +++ b/components/constellation/Cargo.toml @@ -13,7 +13,6 @@ path = "lib.rs" [features] canvas2d-azure = ["canvas/canvas2d-azure"] canvas2d-raqote = ["canvas/canvas2d-raqote"] -no_wgl = ["canvas/no_wgl"] [dependencies] background_hang_monitor = { path = "../background_hang_monitor"} diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index a819bd65a1b..af069dafb63 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -104,9 +104,8 @@ use background_hang_monitor::HangMonitorRegister; use backtrace::Backtrace; use bluetooth_traits::BluetoothRequest; use canvas::canvas_paint_thread::CanvasPaintThread; -use canvas::webgl_thread::WebGLThreads; -use canvas_traits::canvas::CanvasId; -use canvas_traits::canvas::CanvasMsg; +use canvas_traits::canvas::{CanvasId, CanvasMsg}; +use canvas_traits::webgl::WebGLThreads; use compositing::compositor_thread::CompositorProxy; use compositing::compositor_thread::Msg as ToCompositorMsg; use compositing::SendableFrameTree; diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 4b79bc7085b..7869d1499ac 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -47,11 +47,10 @@ use canvas_traits::canvas::{ use canvas_traits::canvas::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle}; use canvas_traits::webgl::WebGLVertexArrayId; use canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, GlType, TexDataType, TexFormat}; -use canvas_traits::webgl::{GLFormats, GLLimits, WebGLQueryId, WebGLSamplerId}; -use canvas_traits::webgl::{ - WebGLBufferId, WebGLChan, WebGLContextId, WebGLContextShareMode, WebGLError, -}; +use canvas_traits::webgl::{GLLimits, WebGLQueryId, WebGLSamplerId}; +use canvas_traits::webgl::{WebGLBufferId, WebGLChan, WebGLContextId, WebGLError}; use canvas_traits::webgl::{WebGLFramebufferId, WebGLMsgSender, WebGLPipeline, WebGLProgramId}; +use canvas_traits::webgl::{WebGLOpaqueFramebufferId, WebGLTransparentFramebufferId}; use canvas_traits::webgl::{WebGLReceiver, WebGLRenderbufferId, WebGLSLVersion, WebGLSender}; use canvas_traits::webgl::{WebGLShaderId, WebGLSyncId, WebGLTextureId, WebGLVersion}; use content_security_policy::CspList; @@ -147,6 +146,7 @@ use time::{Duration, Timespec}; use uuid::Uuid; use webrender_api::{DocumentId, ImageKey, RenderApiSender}; use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState}; +use webxr_api::SwapChainId as WebXRSwapChainId; /// A trait to allow tracing (only) DOM objects. pub unsafe trait JSTraceable { @@ -451,7 +451,7 @@ unsafe_no_jsmanaged_fields!(StorageType); unsafe_no_jsmanaged_fields!(CanvasGradientStop, LinearGradientStyle, RadialGradientStyle); unsafe_no_jsmanaged_fields!(LineCapStyle, LineJoinStyle, CompositionOrBlending); unsafe_no_jsmanaged_fields!(RepetitionStyle); -unsafe_no_jsmanaged_fields!(WebGLError, GLFormats, GLLimits, GlType); +unsafe_no_jsmanaged_fields!(WebGLError, GLLimits, GlType); unsafe_no_jsmanaged_fields!(TimeProfilerChan); unsafe_no_jsmanaged_fields!(MemProfilerChan); unsafe_no_jsmanaged_fields!(PseudoElement); @@ -486,8 +486,9 @@ unsafe_no_jsmanaged_fields!(DocumentId); unsafe_no_jsmanaged_fields!(ImageKey); unsafe_no_jsmanaged_fields!(WebGLBufferId); unsafe_no_jsmanaged_fields!(WebGLChan); -unsafe_no_jsmanaged_fields!(WebGLContextShareMode); unsafe_no_jsmanaged_fields!(WebGLFramebufferId); +unsafe_no_jsmanaged_fields!(WebGLOpaqueFramebufferId); +unsafe_no_jsmanaged_fields!(WebGLTransparentFramebufferId); unsafe_no_jsmanaged_fields!(WebGLMsgSender); unsafe_no_jsmanaged_fields!(WebGLPipeline); unsafe_no_jsmanaged_fields!(WebGLProgramId); @@ -500,6 +501,7 @@ unsafe_no_jsmanaged_fields!(WebGLTextureId); unsafe_no_jsmanaged_fields!(WebGLVertexArrayId); unsafe_no_jsmanaged_fields!(WebGLVersion); unsafe_no_jsmanaged_fields!(WebGLSLVersion); +unsafe_no_jsmanaged_fields!(WebXRSwapChainId); unsafe_no_jsmanaged_fields!(MediaList); unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand); unsafe_no_jsmanaged_fields!( diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index fd5994925c1..0efb0856098 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -98,6 +98,7 @@ use crate::dom::treewalker::TreeWalker; use crate::dom::uievent::UIEvent; use crate::dom::virtualmethods::vtable_for; use crate::dom::webglcontextevent::WebGLContextEvent; +use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::wheelevent::WheelEvent; use crate::dom::window::{ReflowReason, Window}; use crate::dom::windowproxy::WindowProxy; @@ -109,7 +110,7 @@ use crate::stylesheet_set::StylesheetSetRef; use crate::task::TaskBox; use crate::task_source::{TaskSource, TaskSourceName}; use crate::timers::OneshotTimerCallback; -use canvas_traits::webgl::{self, WebGLContextId, WebGLMsg}; +use canvas_traits::webgl::{self, SwapChainId, WebGLContextId, WebGLMsg}; use content_security_policy::{self as csp, CspList}; use cookie::Cookie; use devtools_traits::ScriptToDevtoolsControlMsg; @@ -399,7 +400,7 @@ pub struct Document { /// hosting the media controls UI. media_controls: DomRefCell>>, /// List of all WebGL context IDs that need flushing. - dirty_webgl_contexts: DomRefCell>, + dirty_webgl_contexts: DomRefCell>>, /// https://html.spec.whatwg.org/multipage/#concept-document-csp-list #[ignore_malloc_size_of = "Defined in rust-content-security-policy"] csp_list: DomRefCell>, @@ -2486,15 +2487,26 @@ impl Document { } } - pub fn add_dirty_canvas(&self, context_id: WebGLContextId) { - self.dirty_webgl_contexts.borrow_mut().insert(context_id); + pub fn add_dirty_canvas(&self, context: &WebGLRenderingContext) { + self.dirty_webgl_contexts + .borrow_mut() + .entry(context.context_id()) + .or_insert_with(|| Dom::from_ref(context)); } pub fn flush_dirty_canvases(&self) { - let dirty_context_ids: Vec<_> = self.dirty_webgl_contexts.borrow_mut().drain().collect(); + let dirty_context_ids: Vec<_> = self + .dirty_webgl_contexts + .borrow_mut() + .drain() + .filter(|(_, context)| context.onscreen()) + .map(|(id, _)| SwapChainId::Context(id)) + .collect(); + if dirty_context_ids.is_empty() { return; } + let (sender, receiver) = webgl::webgl_channel().unwrap(); self.window .webgl_chan() @@ -2797,7 +2809,7 @@ impl Document { shadow_roots: DomRefCell::new(HashSet::new()), shadow_roots_styles_changed: Cell::new(false), media_controls: DomRefCell::new(HashMap::new()), - dirty_webgl_contexts: DomRefCell::new(HashSet::new()), + dirty_webgl_contexts: DomRefCell::new(HashMap::new()), csp_list: DomRefCell::new(None), } } diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs index 63cfd0bc530..4c7d9fb857a 100644 --- a/components/script/dom/webgl2renderingcontext.rs +++ b/components/script/dom/webgl2renderingcontext.rs @@ -1426,6 +1426,6 @@ impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom HTMLCanvasDataSource { let this = &*self.unsafe_get(); - HTMLCanvasDataSource::WebGL((*this.base.to_layout().unsafe_get()).layout_handle()) + (*this.base.to_layout().unsafe_get()).layout_handle() } } diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs index 3a31e99be33..0ab85f14e2f 100644 --- a/components/script/dom/webglframebuffer.rs +++ b/components/script/dom/webglframebuffer.rs @@ -8,15 +8,20 @@ use crate::dom::bindings::codegen::Bindings::WebGLFramebufferBinding; use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; -use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::webglobject::WebGLObject; use crate::dom::webglrenderbuffer::WebGLRenderbuffer; use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::webgltexture::WebGLTexture; +use crate::dom::xrsession::XRSession; use canvas_traits::webgl::{webgl_channel, WebGLError, WebGLResult}; -use canvas_traits::webgl::{WebGLCommand, WebGLFramebufferBindingRequest, WebGLFramebufferId}; +use canvas_traits::webgl::{WebGLCommand, WebGLFramebufferBindingRequest}; +use canvas_traits::webgl::{WebGLFramebufferId, WebGLOpaqueFramebufferId}; use dom_struct::dom_struct; +use euclid::Size2D; use std::cell::Cell; +use webxr_api::SwapChainId as WebXRSwapChainId; +use webxr_api::Viewport; pub enum CompleteForRendering { Complete, @@ -92,6 +97,9 @@ pub struct WebGLFramebuffer { stencil: DomRefCell>, depthstencil: DomRefCell>, is_initialized: Cell, + // Framebuffers for XR keep a reference to the XR session. + // https://github.com/immersive-web/webxr/issues/856 + xr_session: MutNullableDom, } impl WebGLFramebuffer { @@ -108,16 +116,37 @@ impl WebGLFramebuffer { stencil: DomRefCell::new(None), depthstencil: DomRefCell::new(None), is_initialized: Cell::new(false), + xr_session: Default::default(), } } pub fn maybe_new(context: &WebGLRenderingContext) -> Option> { let (sender, receiver) = webgl_channel().unwrap(); context.send_command(WebGLCommand::CreateFramebuffer(sender)); - receiver - .recv() - .unwrap() - .map(|id| WebGLFramebuffer::new(context, id)) + let id = receiver.recv().unwrap()?; + let framebuffer = WebGLFramebuffer::new(context, WebGLFramebufferId::Transparent(id)); + Some(framebuffer) + } + + // TODO: depth, stencil and alpha + // https://github.com/servo/servo/issues/24498 + pub fn maybe_new_webxr( + session: &XRSession, + context: &WebGLRenderingContext, + size: Size2D, + ) -> Option<(WebXRSwapChainId, DomRoot)> { + let (sender, receiver) = webgl_channel().unwrap(); + let _ = context + .webgl_sender() + .send_create_webxr_swap_chain(size.to_untyped(), sender); + let swap_chain_id = receiver.recv().unwrap()?; + let framebuffer_id = + WebGLFramebufferId::Opaque(WebGLOpaqueFramebufferId::WebXR(swap_chain_id)); + let framebuffer = WebGLFramebuffer::new(context, framebuffer_id); + framebuffer.size.set(Some((size.width, size.height))); + framebuffer.status.set(constants::FRAMEBUFFER_COMPLETE); + framebuffer.xr_session.set(Some(session)); + Some((swap_chain_id, framebuffer)) } pub fn new(context: &WebGLRenderingContext, id: WebGLFramebufferId) -> DomRoot { @@ -134,11 +163,25 @@ impl WebGLFramebuffer { self.id } + fn is_in_xr_session(&self) -> bool { + self.xr_session.get().is_some() + } + + pub fn validate_transparent(&self) -> WebGLResult<()> { + if self.is_in_xr_session() { + Err(WebGLError::InvalidOperation) + } else { + Ok(()) + } + } + pub fn bind(&self, target: u32) { - // Update the framebuffer status on binding. It may have - // changed if its attachments were resized or deleted while - // we've been unbound. - self.update_status(); + if !self.is_in_xr_session() { + // Update the framebuffer status on binding. It may have + // changed if its attachments were resized or deleted while + // we've been unbound. + self.update_status(); + } self.target.set(Some(target)); self.upcast::() @@ -267,7 +310,17 @@ impl WebGLFramebuffer { } pub fn check_status(&self) -> u32 { - return self.status.get(); + // For opaque framebuffers, check to see if the XR session is currently processing an rAF + // https://immersive-web.github.io/webxr/#opaque-framebuffer + if let Some(xr_session) = self.xr_session.get() { + if xr_session.is_outside_raf() { + constants::FRAMEBUFFER_UNSUPPORTED + } else { + constants::FRAMEBUFFER_COMPLETE + } + } else { + self.status.get() + } } pub fn check_status_for_rendering(&self) -> CompleteForRendering { @@ -276,6 +329,12 @@ impl WebGLFramebuffer { return CompleteForRendering::Incomplete; } + // XR framebuffers are complete inside an rAF + // https://github.com/immersive-web/webxr/issues/854 + if self.xr_session.get().is_some() { + return CompleteForRendering::Complete; + } + if self.color.borrow().is_none() { return CompleteForRendering::MissingColorAttachment; } @@ -309,6 +368,10 @@ impl WebGLFramebuffer { } pub fn renderbuffer(&self, attachment: u32, rb: Option<&WebGLRenderbuffer>) -> WebGLResult<()> { + // Opaque framebuffers cannot have their attachments changed + // https://immersive-web.github.io/webxr/#opaque-framebuffer + self.validate_transparent()?; + let binding = self .attachment_binding(attachment) .ok_or(WebGLError::InvalidEnum)?; @@ -337,7 +400,7 @@ impl WebGLFramebuffer { )); if rb.is_none() { - self.detach_binding(binding, attachment); + self.detach_binding(binding, attachment)?; } self.update_status(); @@ -349,14 +412,19 @@ impl WebGLFramebuffer { &self, binding: &DomRefCell>, attachment: u32, - ) { + ) -> WebGLResult<()> { + // Opaque framebuffers cannot have their attachments changed + // https://immersive-web.github.io/webxr/#opaque-framebuffer + self.validate_transparent()?; + if let Some(att) = &*binding.borrow() { att.detach(); } *binding.borrow_mut() = None; if INTERESTING_ATTACHMENT_POINTS.contains(&attachment) { - self.reattach_depth_stencil(); + self.reattach_depth_stencil()?; } + Ok(()) } fn attachment_binding( @@ -372,7 +440,11 @@ impl WebGLFramebuffer { } } - fn reattach_depth_stencil(&self) { + fn reattach_depth_stencil(&self) -> WebGLResult<()> { + // Opaque framebuffers cannot have their attachments changed + // https://immersive-web.github.io/webxr/#opaque-framebuffer + self.validate_transparent()?; + let reattach = |attachment: &WebGLFramebufferAttachment, attachment_point| { let context = self.upcast::().context(); match *attachment { @@ -411,6 +483,7 @@ impl WebGLFramebuffer { if let Some(ref depth_stencil) = *self.depthstencil.borrow() { reattach(depth_stencil, constants::DEPTH_STENCIL_ATTACHMENT); } + Ok(()) } pub fn attachment(&self, attachment: u32) -> Option { @@ -428,6 +501,10 @@ impl WebGLFramebuffer { texture: Option<&WebGLTexture>, level: i32, ) -> WebGLResult<()> { + // Opaque framebuffers cannot have their attachments changed + // https://immersive-web.github.io/webxr/#opaque-framebuffer + self.validate_transparent()?; + let binding = self .attachment_binding(attachment) .ok_or(WebGLError::InvalidEnum)?; @@ -498,7 +575,7 @@ impl WebGLFramebuffer { )); if texture.is_none() { - self.detach_binding(binding, attachment); + self.detach_binding(binding, attachment)?; } self.update_status(); @@ -563,7 +640,11 @@ impl WebGLFramebuffer { } } - pub fn detach_renderbuffer(&self, rb: &WebGLRenderbuffer) { + pub fn detach_renderbuffer(&self, rb: &WebGLRenderbuffer) -> WebGLResult<()> { + // Opaque framebuffers cannot have their attachments changed + // https://immersive-web.github.io/webxr/#opaque-framebuffer + self.validate_transparent()?; + let mut depth_or_stencil_updated = false; self.with_matching_renderbuffers(rb, |att, name| { depth_or_stencil_updated |= INTERESTING_ATTACHMENT_POINTS.contains(&name); @@ -575,11 +656,16 @@ impl WebGLFramebuffer { }); if depth_or_stencil_updated { - self.reattach_depth_stencil(); + self.reattach_depth_stencil()?; } + Ok(()) } - pub fn detach_texture(&self, texture: &WebGLTexture) { + pub fn detach_texture(&self, texture: &WebGLTexture) -> WebGLResult<()> { + // Opaque framebuffers cannot have their attachments changed + // https://immersive-web.github.io/webxr/#opaque-framebuffer + self.validate_transparent()?; + let mut depth_or_stencil_updated = false; self.with_matching_textures(texture, |att, name| { depth_or_stencil_updated |= INTERESTING_ATTACHMENT_POINTS.contains(&name); @@ -591,8 +677,9 @@ impl WebGLFramebuffer { }); if depth_or_stencil_updated { - self.reattach_depth_stencil(); + self.reattach_depth_stencil()?; } + Ok(()) } pub fn invalidate_renderbuffer(&self, rb: &WebGLRenderbuffer) { @@ -615,7 +702,7 @@ impl WebGLFramebuffer { impl Drop for WebGLFramebuffer { fn drop(&mut self) { - self.delete(true); + let _ = self.delete(true); } } diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs index bf198e5382c..6863bc89e53 100644 --- a/components/script/dom/webglprogram.rs +++ b/components/script/dom/webglprogram.rs @@ -392,10 +392,12 @@ impl WebGLProgram { sender, )); let location = receiver.recv().unwrap(); + let context_id = self.upcast::().context().context_id(); Ok(Some(WebGLUniformLocation::new( self.global().as_window(), location, + context_id, self.id, self.link_generation.get(), size, diff --git a/components/script/dom/webglrenderbuffer.rs b/components/script/dom/webglrenderbuffer.rs index 07afdbccb44..ca75f83c336 100644 --- a/components/script/dom/webglrenderbuffer.rs +++ b/components/script/dom/webglrenderbuffer.rs @@ -106,7 +106,7 @@ impl WebGLRenderbuffer { let currently_bound_framebuffer = self.upcast::().context().bound_framebuffer(); if let Some(fb) = currently_bound_framebuffer { - fb.detach_renderbuffer(self); + let _ = fb.detach_renderbuffer(self); } let context = self.upcast::().context(); diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index f19664ad0ad..7315d2516ab 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -54,11 +54,11 @@ use crate::script_runtime::JSContext as SafeJSContext; use backtrace::Backtrace; use canvas_traits::webgl::WebGLError::*; use canvas_traits::webgl::{ - webgl_channel, AlphaTreatment, DOMToTextureCommand, GLContextAttributes, GLFormats, GLLimits, - GlType, Parameter, TexDataType, TexFormat, TexParameter, WebGLChan, WebGLCommand, - WebGLCommandBacktrace, WebGLContextId, WebGLContextShareMode, WebGLError, - WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender, WebGLProgramId, WebGLResult, - WebGLSLVersion, WebGLSendResult, WebGLSender, WebGLVersion, WebVRCommand, YAxisTreatment, + webgl_channel, AlphaTreatment, DOMToTextureCommand, GLContextAttributes, GLLimits, GlType, + Parameter, TexDataType, TexFormat, TexParameter, WebGLChan, WebGLCommand, + WebGLCommandBacktrace, WebGLContextId, WebGLError, WebGLFramebufferBindingRequest, WebGLMsg, + WebGLMsgSender, WebGLOpaqueFramebufferId, WebGLProgramId, WebGLResult, WebGLSLVersion, + WebGLSendResult, WebGLSender, WebGLVersion, WebVRCommand, YAxisTreatment, }; use dom_struct::dom_struct; use embedder_traits::EventLoopWaker; @@ -81,6 +81,7 @@ use std::cell::Cell; use std::cmp; use std::ptr::{self, NonNull}; use std::rc::Rc; +use webxr_api::SwapChainId as WebXRSwapChainId; // From the GLES 2.0.25 spec, page 85: // @@ -130,10 +131,9 @@ pub struct WebGLRenderingContext { webgl_sender: WebGLMessageSender, #[ignore_malloc_size_of = "Defined in webrender"] webrender_image: webrender_api::ImageKey, - share_mode: WebGLContextShareMode, webgl_version: WebGLVersion, glsl_version: WebGLSLVersion, - #[ignore_malloc_size_of = "Defined in offscreen_gl_context"] + #[ignore_malloc_size_of = "Defined in surfman"] limits: GLLimits, canvas: Dom, #[ignore_malloc_size_of = "Defined in canvas_traits"] @@ -160,7 +160,6 @@ pub struct WebGLRenderingContext { current_vao: MutNullableDom, textures: Textures, api_type: GlType, - framebuffer_format: GLFormats, } impl WebGLRenderingContext { @@ -195,7 +194,6 @@ impl WebGLRenderingContext { window.get_event_loop_waker(), ), webrender_image: ctx_data.image_key, - share_mode: ctx_data.share_mode, webgl_version, glsl_version: ctx_data.glsl_version, limits: ctx_data.limits, @@ -220,7 +218,6 @@ impl WebGLRenderingContext { current_vao: Default::default(), textures: Textures::new(max_combined_texture_image_units), api_type: ctx_data.api_type, - framebuffer_format: ctx_data.framebuffer_format, } }) } @@ -292,7 +289,7 @@ impl WebGLRenderingContext { self.send_command(WebGLCommand::Scissor(rect.0, rect.1, rect.2, rect.3)); // Bound texture must not change when the canvas is resized. - // Right now offscreen_gl_context generates a new FBO and the bound texture is changed + // Right now surfman generates a new FBO and the bound texture is changed // in order to create a new render to texture attachment. // Send a command to re-bind the TEXTURE_2D, if any. if let Some(texture) = self @@ -308,7 +305,7 @@ impl WebGLRenderingContext { } // Bound framebuffer must not change when the canvas is resized. - // Right now offscreen_gl_context generates a new FBO on resize. + // Right now surfman generates a new FBO on resize. // Send a command to re-bind the framebuffer, if any. if let Some(fbo) = self.bound_framebuffer.get() { let id = WebGLFramebufferBindingRequest::Explicit(fbo.id()); @@ -324,6 +321,10 @@ impl WebGLRenderingContext { self.webgl_sender.context_id() } + pub fn onscreen(&self) -> bool { + self.canvas.upcast::().is_connected() + } + #[inline] pub fn send_command(&self, command: WebGLCommand) { self.webgl_sender @@ -337,6 +338,10 @@ impl WebGLRenderingContext { .send(command, capture_webgl_backtrace(self)); } + pub fn swap_buffers(&self, id: Option) { + let _ = self.webgl_sender.send_swap_buffers(id); + } + #[inline] pub fn send_vr_command(&self, command: WebVRCommand) { self.webgl_sender.send_vr(command).unwrap(); @@ -462,7 +467,7 @@ impl WebGLRenderingContext { .dirty(NodeDamage::OtherNodeDamage); let document = document_from_node(&*self.canvas); - document.add_dirty_canvas(self.context_id()); + document.add_dirty_canvas(self); } fn vertex_attrib(&self, indx: u32, x: f32, y: f32, z: f32, w: f32) { @@ -810,8 +815,9 @@ impl WebGLRenderingContext { receiver.recv().unwrap() } - pub fn layout_handle(&self) -> webrender_api::ImageKey { - self.webrender_image + pub(crate) fn layout_handle(&self) -> HTMLCanvasDataSource { + let image_key = self.webrender_image; + HTMLCanvasDataSource::WebGL(image_key) } // https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/ @@ -1086,17 +1092,9 @@ impl WebGLRenderingContext { self.bound_framebuffer.get() } - pub fn bound_renderbuffer(&self) -> Option> { - self.bound_renderbuffer.get() - } - pub fn extension_manager(&self) -> &WebGLExtensions { &self.extension_manager } - - pub fn formats(&self) -> &GLFormats { - &self.framebuffer_format - } } #[cfg(not(feature = "webgl_backtrace"))] @@ -2225,6 +2223,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6 fn DeleteFramebuffer(&self, framebuffer: Option<&WebGLFramebuffer>) { if let Some(framebuffer) = framebuffer { + // https://immersive-web.github.io/webxr/#opaque-framebuffer + // Can opaque framebuffers be deleted? + // https://github.com/immersive-web/webxr/issues/855 + handle_potential_webgl_error!(self, framebuffer.validate_transparent(), return); handle_potential_webgl_error!(self, self.validate_ownership(framebuffer), return); handle_object_deletion!( self, @@ -2384,7 +2386,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { pname: u32, ) -> JSVal { // Check if currently bound framebuffer is non-zero as per spec. - if self.bound_framebuffer.get().is_none() { + if let Some(fb) = self.bound_framebuffer.get() { + // Opaque framebuffers cannot have their attachments inspected + // https://immersive-web.github.io/webxr/#opaque-framebuffer + handle_potential_webgl_error!(self, fb.validate_transparent(), return NullValue()); + } else { self.webgl_error(InvalidOperation); return NullValue(); } @@ -2487,6 +2493,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7 fn GetRenderbufferParameter(&self, _cx: SafeJSContext, target: u32, pname: u32) -> JSVal { + // We do not check to see if the renderbuffer came from an opaque framebuffer + // https://github.com/immersive-web/webxr/issues/862 let target_matches = target == constants::RENDERBUFFER; let pname_matches = match pname { @@ -3477,6 +3485,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if program.is_deleted() || !program.is_linked() || + self.context_id() != location.context_id() || program.id() != location.program_id() || program.link_generation() != location.link_generation() { @@ -4153,7 +4162,7 @@ pub trait LayoutCanvasWebGLRenderingContextHelpers { impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom { #[allow(unsafe_code)] unsafe fn canvas_data_source(&self) -> HTMLCanvasDataSource { - HTMLCanvasDataSource::WebGL((*self.unsafe_get()).layout_handle()) + (*self.unsafe_get()).layout_handle() } } @@ -4347,7 +4356,7 @@ impl TexPixels { } #[derive(JSTraceable)] -pub(crate) struct WebGLCommandSender { +pub struct WebGLCommandSender { sender: WebGLChan, waker: Option>, } @@ -4410,6 +4419,18 @@ impl WebGLMessageSender { self.wake_after_send(|| self.sender.send_vr(command)) } + pub fn send_swap_buffers(&self, id: Option) -> WebGLSendResult { + self.wake_after_send(|| self.sender.send_swap_buffers(id)) + } + + pub fn send_create_webxr_swap_chain( + &self, + size: Size2D, + sender: WebGLSender>, + ) -> WebGLSendResult { + self.wake_after_send(|| self.sender.send_create_webxr_swap_chain(size, sender)) + } + pub fn send_resize( &self, size: Size2D, diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs index e4a18b519a3..a043528195c 100644 --- a/components/script/dom/webgltexture.rs +++ b/components/script/dom/webgltexture.rs @@ -210,7 +210,7 @@ impl WebGLTexture { let currently_bound_framebuffer = self.upcast::().context().bound_framebuffer(); if let Some(fb) = currently_bound_framebuffer { - fb.detach_texture(self); + let _ = fb.detach_texture(self); } let cmd = WebGLCommand::DeleteTexture(self.id); diff --git a/components/script/dom/webgluniformlocation.rs b/components/script/dom/webgluniformlocation.rs index bf142480dc7..5bdc661f17a 100644 --- a/components/script/dom/webgluniformlocation.rs +++ b/components/script/dom/webgluniformlocation.rs @@ -7,6 +7,7 @@ use crate::dom::bindings::codegen::Bindings::WebGLUniformLocationBinding; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::DomRoot; use crate::dom::window::Window; +use canvas_traits::webgl::WebGLContextId; use canvas_traits::webgl::WebGLProgramId; use dom_struct::dom_struct; @@ -14,6 +15,7 @@ use dom_struct::dom_struct; pub struct WebGLUniformLocation { reflector_: Reflector, id: i32, + context_id: WebGLContextId, program_id: WebGLProgramId, link_generation: u64, size: Option, @@ -23,6 +25,7 @@ pub struct WebGLUniformLocation { impl WebGLUniformLocation { fn new_inherited( id: i32, + context_id: WebGLContextId, program_id: WebGLProgramId, link_generation: u64, size: Option, @@ -31,6 +34,7 @@ impl WebGLUniformLocation { Self { reflector_: Reflector::new(), id, + context_id, program_id, link_generation, size, @@ -41,6 +45,7 @@ impl WebGLUniformLocation { pub fn new( window: &Window, id: i32, + context_id: WebGLContextId, program_id: WebGLProgramId, link_generation: u64, size: Option, @@ -49,6 +54,7 @@ impl WebGLUniformLocation { reflect_dom_object( Box::new(Self::new_inherited( id, + context_id, program_id, link_generation, size, @@ -67,6 +73,10 @@ impl WebGLUniformLocation { self.program_id } + pub fn context_id(&self) -> WebGLContextId { + self.context_id + } + pub fn link_generation(&self) -> u64 { self.link_generation } diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 41f8392acfb..6fbdc592b0e 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -6,7 +6,6 @@ use crate::compartments::InCompartment; use crate::dom::bindings::callback::ExceptionHandling; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorBinding::NavigatorMethods; -use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceType; @@ -30,7 +29,6 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::node::Node; use crate::dom::node::NodeDamage; use crate::dom::promise::Promise; -use crate::dom::webglframebuffer::WebGLFramebufferAttachmentRoot; use crate::dom::xrframe::XRFrame; use crate::dom::xrinputsourcearray::XRInputSourceArray; use crate::dom::xrinputsourceevent::XRInputSourceEvent; @@ -41,7 +39,6 @@ use crate::dom::xrspace::XRSpace; use crate::dom::xrwebgllayer::XRWebGLLayer; use crate::task_source::TaskSource; use dom_struct::dom_struct; -use euclid::default::Size2D; use euclid::RigidTransform3D; use ipc_channel::ipc::IpcSender; use ipc_channel::router::ROUTER; @@ -77,6 +74,9 @@ pub struct XRSession { end_promises: DomRefCell>>, /// https://immersive-web.github.io/webxr/#ended ended: Cell, + /// Opaque framebuffers need to know the session is "outside of a requestAnimationFrame" + /// https://immersive-web.github.io/webxr/#opaque-framebuffer + outside_raf: Cell, } impl XRSession { @@ -102,6 +102,7 @@ impl XRSession { input_sources: Dom::from_ref(input_sources), end_promises: DomRefCell::new(vec![]), ended: Cell::new(false), + outside_raf: Cell::new(true), } } @@ -169,6 +170,10 @@ impl XRSession { self.session.borrow_mut().request_animation_frame(sender); } + pub fn is_outside_raf(&self) -> bool { + self.outside_raf.get() + } + fn attach_event_handler(&self) { let this = Trusted::new(self); let global = self.global(); @@ -276,6 +281,8 @@ impl XRSession { /// https://immersive-web.github.io/webxr/#xr-animation-frame fn raf_callback(&self, (time, mut frame): (f64, Frame)) { + debug!("WebXR RAF callback"); + // Step 1 if let Some(pending) = self.pending_render_state.take() { // https://immersive-web.github.io/webxr/#apply-the-pending-render-state @@ -285,19 +292,8 @@ impl XRSession { // Step 6-7: XXXManishearth handle inlineVerticalFieldOfView // XXXManishearth handle inline sessions and composition disabled flag - if let Some(layer) = pending.GetBaseLayer() { - let attachment = layer.framebuffer().attachment(constants::COLOR_ATTACHMENT0); - if let Some(WebGLFramebufferAttachmentRoot::Texture(texture)) = attachment { - let context = layer.Context().context_id().0; - let texture_id = texture.id().get(); - if let Some((width, height)) = layer.framebuffer().size() { - let size = Size2D::new(width, height); - self.session - .borrow_mut() - .set_texture(context, texture_id, size); - } - } - } + let swap_chain_id = pending.GetBaseLayer().map(|layer| layer.swap_chain_id()); + self.session.borrow_mut().set_swap_chain(swap_chain_id); } for event in frame.events.drain(..) { @@ -321,13 +317,16 @@ impl XRSession { frame.set_animation_frame(true); // Step 8 + self.outside_raf.set(false); for (_, callback) in callbacks.drain(..) { if let Some(callback) = callback { let _ = callback.Call__(Finite::wrap(time), &frame, ExceptionHandling::Report); } } + self.outside_raf.set(true); frame.set_active(false); + base_layer.swap_buffers(); self.session.borrow_mut().render_animation_frame(); self.request_new_xr_frame(); diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs index f637f4ee96e..44bc10868b6 100644 --- a/components/script/dom/xrwebgllayer.rs +++ b/components/script/dom/xrwebgllayer.rs @@ -2,27 +2,26 @@ * 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 crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods; use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods}; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerInit; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerMethods; -use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextBinding::WebGLRenderingContextMethods; -use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use crate::dom::bindings::error::Error; use crate::dom::bindings::error::Fallible; -use crate::dom::bindings::reflector::{reflect_dom_object, Reflector, DomObject}; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::globalscope::GlobalScope; -use crate::dom::webgl_validations::types::TexImageTarget; use crate::dom::webglframebuffer::WebGLFramebuffer; use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::window::Window; use crate::dom::xrsession::XRSession; use crate::dom::xrview::XRView; use crate::dom::xrviewport::XRViewport; +use canvas_traits::webgl::WebGLFramebufferId; use dom_struct::dom_struct; -use js::rust::CustomAutoRooter; use std::convert::TryInto; +use webxr_api::SwapChainId as WebXRSwapChainId; use webxr_api::Views; #[dom_struct] @@ -32,6 +31,8 @@ pub struct XRWebGLLayer { depth: bool, stencil: bool, alpha: bool, + #[ignore_malloc_size_of = "ids don't malloc"] + swap_chain_id: WebXRSwapChainId, context: Dom, session: Dom, framebuffer: Dom, @@ -39,6 +40,7 @@ pub struct XRWebGLLayer { impl XRWebGLLayer { pub fn new_inherited( + swap_chain_id: WebXRSwapChainId, session: &XRSession, context: &WebGLRenderingContext, init: &XRWebGLLayerInit, @@ -50,6 +52,7 @@ impl XRWebGLLayer { depth: init.depth, stencil: init.stencil, alpha: init.alpha, + swap_chain_id, context: Dom::from_ref(context), session: Dom::from_ref(session), framebuffer: Dom::from_ref(framebuffer), @@ -58,6 +61,7 @@ impl XRWebGLLayer { pub fn new( global: &GlobalScope, + swap_chain_id: WebXRSwapChainId, session: &XRSession, context: &WebGLRenderingContext, init: &XRWebGLLayerInit, @@ -65,6 +69,7 @@ impl XRWebGLLayer { ) -> DomRoot { reflect_dom_object( Box::new(XRWebGLLayer::new_inherited( + swap_chain_id, session, context, init, @@ -89,108 +94,16 @@ impl XRWebGLLayer { // XXXManishearth step 3: throw error if context is lost // XXXManishearth step 4: check XR compat flag for immersive sessions - let cx = global.get_cx(); - let old_fbo = context.bound_framebuffer(); - let old_rbo = context.bound_renderbuffer(); - let old_texture = context - .textures() - .active_texture_for_image_target(TexImageTarget::Texture2D); - - // Step 9.2. "Initialize layer’s framebuffer to a new opaque framebuffer created with - // context and layerInit’s depth, stencil, and alpha values." - let framebuffer = context.CreateFramebuffer().ok_or(Error::Operation)?; + // Step 9.2. "Initialize layer’s framebuffer to a new opaque framebuffer created with context." + let size = session.with_session(|session| session.recommended_framebuffer_resolution()); + let (swap_chain_id, framebuffer) = + WebGLFramebuffer::maybe_new_webxr(session, context, size).ok_or(Error::Operation)?; // Step 9.3. "Allocate and initialize resources compatible with session’s XR device, // including GPU accessible memory buffers, as required to support the compositing of layer." - // Create a new texture with size given by the session's recommended resolution - let texture = context.CreateTexture().ok_or(Error::Operation)?; - let render_buffer = context.CreateRenderbuffer().ok_or(Error::Operation)?; - let resolution = session.with_session(|s| s.recommended_framebuffer_resolution()); - let mut pixels = CustomAutoRooter::new(None); - let mut clear_bits = constants::COLOR_BUFFER_BIT; - - let formats = context.formats(); - - context.BindTexture(constants::TEXTURE_2D, Some(&texture)); - let sc = context.TexImage2D( - constants::TEXTURE_2D, - 0, - formats.texture_format, - resolution.width, - resolution.height, - 0, - formats.texture_format, - formats.texture_type, - pixels.root(*cx), - ); - - // Bind the new texture to the framebuffer - context.BindFramebuffer(constants::FRAMEBUFFER, Some(&framebuffer)); - context.FramebufferTexture2D( - constants::FRAMEBUFFER, - constants::COLOR_ATTACHMENT0, - constants::TEXTURE_2D, - Some(&texture), - 0, - ); - - // Create backing store and bind a renderbuffer if requested - if init.depth || init.stencil { - let (internal_format, attachment) = if init.depth && init.stencil { - clear_bits |= constants::DEPTH_BUFFER_BIT | constants::STENCIL_BUFFER_BIT; - ( - constants::DEPTH_STENCIL, - constants::DEPTH_STENCIL_ATTACHMENT, - ) - } else if init.depth { - clear_bits |= constants::DEPTH_BUFFER_BIT; - (constants::DEPTH_COMPONENT16, constants::DEPTH_ATTACHMENT) - } else { - clear_bits |= constants::STENCIL_BUFFER_BIT; - (constants::STENCIL_INDEX8, constants::STENCIL_ATTACHMENT) - }; - context.BindRenderbuffer(constants::RENDERBUFFER, Some(&render_buffer)); - context.RenderbufferStorage( - constants::RENDERBUFFER, - internal_format, - resolution.width, - resolution.height, - ); - context.FramebufferRenderbuffer( - constants::FRAMEBUFFER, - attachment, - constants::RENDERBUFFER, - Some(&render_buffer), - ); - } - - context.initialize_framebuffer(clear_bits); - - // Restore the WebGL state while complaining about global mutable state - let fb_status = context.CheckFramebufferStatus(constants::FRAMEBUFFER); - let gl_status = context.GetError(); - context.BindTexture(constants::TEXTURE_2D, old_texture.as_ref().map(|t| &**t)); - context.BindFramebuffer(constants::FRAMEBUFFER, old_fbo.as_ref().map(|f| &**f)); - context.BindRenderbuffer(constants::RENDERBUFFER, old_rbo.as_ref().map(|f| &**f)); - // Step 9.4: "If layer’s resources were unable to be created for any reason, // throw an OperationError and abort these steps." - if let Err(err) = sc { - error!("TexImage2D error {:?} while creating XR context", err); - return Err(Error::Operation); - } - if fb_status != constants::FRAMEBUFFER_COMPLETE { - error!( - "Framebuffer error {:x} while creating XR context", - fb_status - ); - return Err(Error::Operation); - } - if gl_status != constants::NO_ERROR { - error!("GL error {:x} while creating XR context", gl_status); - return Err(Error::Operation); - } // Ensure that we finish setting up this layer before continuing. context.Finish(); @@ -198,6 +111,7 @@ impl XRWebGLLayer { // Step 10. "Return layer." Ok(XRWebGLLayer::new( &global.global(), + swap_chain_id, session, context, init, @@ -205,12 +119,18 @@ impl XRWebGLLayer { )) } + pub fn swap_chain_id(&self) -> WebXRSwapChainId { + self.swap_chain_id + } + pub fn session(&self) -> &XRSession { &self.session } - pub fn framebuffer(&self) -> &WebGLFramebuffer { - &self.framebuffer + pub fn swap_buffers(&self) { + if let WebGLFramebufferId::Opaque(id) = self.framebuffer.id() { + self.context.swap_buffers(Some(id)); + } } } diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index 5b657e7e33b..0ff3ecba8c6 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -24,7 +24,7 @@ layout-2013 = ["layout_thread_2013"] layout-2020 = ["layout_thread_2020"] max_log_level = ["log/release_max_level_info"] native-bluetooth = ["bluetooth/native-bluetooth"] -no_wgl = ["canvas/no_wgl"] +no-wgl = ["canvas/no-wgl"] uwp = ["servo_config/uwp", "script/uwp"] webrender_debugger = ["webrender/debugger"] no_static_freetype = ["webrender/no_static_freetype"] @@ -63,7 +63,6 @@ media = {path = "../media"} msg = {path = "../msg"} net = {path = "../net"} net_traits = {path = "../net_traits"} -offscreen_gl_context = "0.25" profile = {path = "../profile"} profile_traits = {path = "../profile_traits"} script = {path = "../script"} @@ -83,6 +82,7 @@ webdriver_server = {path = "../webdriver_server", optional = true} webvr = {path = "../webvr"} webvr_traits = {path = "../webvr_traits"} webxr-api = {git = "https://github.com/servo/webxr"} +surfman = { git = "https://github.com/pcwalton/surfman", features = ["sm-osmesa"] } [target.'cfg(all(not(target_os = "windows"), not(target_os = "ios"), not(target_os="android"), not(target_arch="arm"), not(target_arch="aarch64")))'.dependencies] gaol = "0.2.1" diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 86920bbe361..71430b3f6f4 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -64,8 +64,8 @@ fn webdriver(_port: u16, _constellation: Sender) {} use bluetooth::BluetoothThreadFactory; use bluetooth_traits::BluetoothRequest; -use canvas::gl_context::{CloneableDispatcher, GLContextFactory}; -use canvas::webgl_thread::{ThreadMode, WebGLMainThread, WebGLThreads}; +use canvas::WebGLComm; +use canvas_traits::webgl::WebGLThreads; use compositing::compositor_thread::{ CompositorProxy, CompositorReceiver, InitialCompositorState, Msg, }; @@ -100,7 +100,6 @@ use media::{GLPlayerThreads, WindowGLContext}; use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId}; use net::resource_thread::new_resource_threads; use net_traits::IpcSend; -use offscreen_gl_context::GLContextDispatcher; use profile::mem as profile_mem; use profile::time as profile_time; use profile_traits::mem; @@ -114,8 +113,17 @@ use std::borrow::Cow; use std::cmp::max; use std::path::PathBuf; use std::rc::Rc; +use std::sync::{Arc, Mutex}; +#[cfg(not(target_os = "windows"))] +use surfman::platform::default::device::Device as HWDevice; +#[cfg(not(target_os = "windows"))] +use surfman::platform::generic::osmesa::device::Device as SWDevice; +#[cfg(not(target_os = "windows"))] +use surfman::platform::generic::universal::context::Context; +use surfman::platform::generic::universal::device::Device; use webrender::{RendererKind, ShaderPrecacheFlags}; -use webrender_traits::{WebrenderExternalImageHandlers, WebrenderImageHandlerType}; +use webrender_traits::WebrenderImageHandlerType; +use webrender_traits::{WebrenderExternalImageHandlers, WebrenderExternalImageRegistry}; use webvr::{VRServiceManager, WebVRCompositorHandler, WebVRThread}; use webvr_traits::WebVRMsg; @@ -260,7 +268,6 @@ pub struct Servo { embedder_receiver: EmbedderReceiver, embedder_events: Vec<(Option, EmbedderMsg)>, profiler_enabled: bool, - webgl_thread_data: Option>, } #[derive(Clone)] @@ -328,7 +335,7 @@ where } // Make sure the gl context is made current. - window.prepare_for_composite(); + window.make_gl_context_current(); // Reserving a namespace to create TopLevelBrowserContextId. PipelineNamespace::install(PipelineNamespaceId(0)); @@ -451,58 +458,18 @@ where (None, None, None) }; - // GLContext factory used to create WebGL Contexts - let gl_factory = if opts.should_use_osmesa() { - GLContextFactory::current_osmesa_handle() - } else { - let dispatcher = - Box::new(MainThreadDispatcher::new(compositor_proxy.clone())) as Box<_>; - let gl_type = match window.gl().get_type() { - gl::GlType::Gl => sparkle::gl::GlType::Gl, - gl::GlType::Gles => sparkle::gl::GlType::Gles, - }; - GLContextFactory::current_native_handle(dispatcher, gl_type) - }; - let (external_image_handlers, external_images) = WebrenderExternalImageHandlers::new(); let mut external_image_handlers = Box::new(external_image_handlers); - let run_webgl_on_main_thread = - cfg!(windows) || std::env::var("SERVO_WEBGL_MAIN_THREAD").is_ok(); - - // Initialize WebGL Thread entry point. - let webgl_result = gl_factory.map(|factory| { - let (webgl_threads, thread_data, webxr_handler, image_handler, output_handler) = - WebGLThreads::new( - factory, - window.gl(), - webrender_api_sender.clone(), - webvr_compositor.map(|c| c as Box<_>), - external_images.clone(), - if run_webgl_on_main_thread { - ThreadMode::MainThread(embedder.create_event_loop_waker()) - } else { - ThreadMode::OffThread - }, - ); - - // Set webrender external image handler for WebGL textures - external_image_handlers.set_handler(image_handler, WebrenderImageHandlerType::WebGL); - - // Set webxr external image handler for WebGL textures - webxr_main_thread.set_webgl(webxr_handler); - - // Set DOM to texture handler, if enabled. - if let Some(output_handler) = output_handler { - webrender.set_output_image_handler(output_handler); - } - - (webgl_threads, thread_data) - }); - let (webgl_threads, webgl_thread_data) = match webgl_result { - Some((a, b)) => (Some(a), b), - None => (None, None), - }; + let webgl_threads = create_webgl_threads( + &*window, + &mut webrender, + webrender_api_sender.clone(), + webvr_compositor, + &mut webxr_main_thread, + &mut external_image_handlers, + external_images.clone(), + ); let glplayer_threads = match window.get_gl_context() { GlContext::Unknown => None, @@ -523,16 +490,7 @@ where webrender.set_external_image_handler(external_image_handlers); - // When webgl execution occurs on the main thread, and the script thread - // lives in the same process, then the script thread needs the ability to - // wake up the main thread's event loop when webgl commands need processing. - // When there are multiple processes, this is handled automatically by - // the IPC receiving handler instead. - let event_loop_waker = if run_webgl_on_main_thread && !opts.multiprocess { - Some(embedder.create_event_loop_waker()) - } else { - None - }; + let event_loop_waker = None; // Create the constellation, which maintains the engine // pipelines, including the script and layout threads, as well @@ -550,7 +508,7 @@ where webrender_api_sender, webxr_main_thread.registry(), player_context, - webgl_threads, + Some(webgl_threads), webvr_chan, webvr_constellation_sender, glplayer_threads, @@ -596,7 +554,6 @@ where embedder_receiver: embedder_receiver, embedder_events: Vec::new(), profiler_enabled: false, - webgl_thread_data, } } @@ -788,10 +745,6 @@ where } pub fn handle_events(&mut self, events: Vec) { - if let Some(ref mut webgl_thread) = self.webgl_thread_data { - webgl_thread.process(); - } - if self.compositor.receive_messages() { self.receive_messages(); } @@ -1052,28 +1005,68 @@ fn create_sandbox() { panic!("Sandboxing is not supported on Windows, iOS, ARM targets and android."); } -/// Implements GLContextDispatcher to dispatch functions from GLContext threads to the main thread's event loop. -/// It's used in Windows to allow WGL GLContext sharing. -pub struct MainThreadDispatcher { - compositor_proxy: CompositorProxy, -} +// Initializes the WebGL thread. +fn create_webgl_threads( + window: &W, + webrender: &mut webrender::Renderer, + webrender_api_sender: webrender_api::RenderApiSender, + webvr_compositor: Option>, + webxr_main_thread: &mut webxr_api::MainThreadRegistry, + external_image_handlers: &mut WebrenderExternalImageHandlers, + external_images: Arc>, +) -> WebGLThreads +where + W: WindowMethods + 'static + ?Sized, +{ + // Create a `surfman` device and context. + window.make_gl_context_current(); -impl MainThreadDispatcher { - fn new(proxy: CompositorProxy) -> Self { - Self { - compositor_proxy: proxy, + #[cfg(not(target_os = "windows"))] + let (device, context) = unsafe { + if opts::get().headless { + let (device, context) = SWDevice::from_current_context() + .expect("Failed to create software graphics context!"); + (Device::Software(device), Context::Software(context)) + } else { + let (device, context) = HWDevice::from_current_context() + .expect("Failed to create hardware graphics context!"); + (Device::Hardware(device), Context::Hardware(context)) } + }; + #[cfg(target_os = "windows")] + let (device, context) = + unsafe { Device::from_current_context().expect("Failed to create graphics context!") }; + + let gl_type = match window.gl().get_type() { + gleam::gl::GlType::Gl => sparkle::gl::GlType::Gl, + gleam::gl::GlType::Gles => sparkle::gl::GlType::Gles, + }; + + let WebGLComm { + webgl_threads, + webxr_swap_chains, + image_handler, + output_handler, + } = WebGLComm::new( + device, + context, + window.gl(), + webrender_api_sender, + webvr_compositor.map(|compositor| compositor as Box<_>), + external_images, + gl_type, + ); + + // Set webrender external image handler for WebGL textures + external_image_handlers.set_handler(image_handler, WebrenderImageHandlerType::WebGL); + + // Set webxr external image handler for WebGL textures + webxr_main_thread.set_swap_chains(webxr_swap_chains); + + // Set DOM to texture handler, if enabled. + if let Some(output_handler) = output_handler { + webrender.set_output_image_handler(output_handler); } -} -impl GLContextDispatcher for MainThreadDispatcher { - fn dispatch(&self, f: Box) { - self.compositor_proxy.send(Msg::Dispatch(f)); - } -} -impl CloneableDispatcher for MainThreadDispatcher { - fn clone(&self) -> Box { - Box::new(MainThreadDispatcher { - compositor_proxy: self.compositor_proxy.clone(), - }) as Box<_> - } + + webgl_threads } diff --git a/etc/ci/check_dynamic_symbols.py b/etc/ci/check_dynamic_symbols.py index 20dccca7d68..7003a86bca4 100644 --- a/etc/ci/check_dynamic_symbols.py +++ b/etc/ci/check_dynamic_symbols.py @@ -30,6 +30,8 @@ allowed_symbols = frozenset([ b'abs', b'fegetenv', b'sigemptyset', + b'AHardwareBuffer_allocate', + b'AHardwareBuffer_release', ]) actual_symbols = set() diff --git a/etc/taskcluster/decision_task.py b/etc/taskcluster/decision_task.py index 0a2664f32eb..b166c6d8fe9 100644 --- a/etc/taskcluster/decision_task.py +++ b/etc/taskcluster/decision_task.py @@ -16,15 +16,19 @@ def main(task_for): branch if not branch.startswith("try-") else "try" ) + + # Implemented but disabled for now: + linux_wpt = lambda: None # Shadows the existing top-level function + # The magicleap build is broken until there's a surfman back end + magicleap_dev = lambda: None + magicleap_nightly = lambda: None + if task_for == "github-push": # FIXME https://github.com/servo/servo/issues/22187 # In-emulator testing is disabled for now. (Instead we only compile.) # This local variable shadows the module-level function of the same name. android_x86_wpt = android_x86_release - # Implemented but disabled for now: - linux_wpt = lambda: None # Shadows the existing top-level function - all_tests = [ linux_tidy_unit_docs, windows_unit, @@ -101,6 +105,8 @@ def mocked_only(): windows_release() android_x86_wpt() linux_wpt() + magicleap_dev() + magicleap_nightly() decisionlib.DockerWorkerTask("Indexed by task definition").find_or_create() @@ -580,26 +586,26 @@ def update_wpt(): ) -def macos_release_build(): +def macos_release_build(args=""): return ( macos_build_task("Release build") .with_treeherder("macOS x64", "Release") - .with_script(""" - ./mach build --release --verbose - ./etc/ci/lockfile_changed.sh - tar -czf target.tar.gz \ - target/release/servo \ - target/release/build/osmesa-src-*/output \ - target/release/build/osmesa-src-*/out/src/gallium/targets/osmesa/.libs \ - target/release/build/osmesa-src-*/out/src/mapi/shared-glapi/.libs - """) + .with_script("\n".join([ + "./mach build --release --verbose " + args, + "./etc/ci/lockfile_changed.sh", + "tar -czf target.tar.gz" + + " target/release/servo" + + " target/release/build/osmesa-src-*/output" + + " 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") .find_or_create("build.macos_x64_release." + CONFIG.task_id()) ) def macos_wpt(): - build_task = macos_release_build() + build_task = macos_release_build("--with-debug-assertions") def macos_run_task(name): task = macos_task(name).with_python2() return with_homebrew(task, ["etc/taskcluster/macos/Brewfile-gstreamer"]) diff --git a/ports/glutin/Cargo.toml b/ports/glutin/Cargo.toml index 3b490d73e30..d4ad9f3a299 100644 --- a/ports/glutin/Cargo.toml +++ b/ports/glutin/Cargo.toml @@ -38,7 +38,7 @@ layout-2013 = ["libservo/layout-2013"] layout-2020 = ["libservo/layout-2020"] max_log_level = ["log/release_max_level_info"] native-bluetooth = ["libservo/native-bluetooth"] -no_wgl = ["libservo/no_wgl"] +no-wgl = ["libservo/no-wgl"] profilemozjs = ["libservo/profilemozjs"] webdriver = ["libservo/webdriver"] webgl_backtrace = ["libservo/webgl_backtrace"] diff --git a/ports/glutin/embedder.rs b/ports/glutin/embedder.rs index 678ecdd8064..fe8ed1ab5b7 100644 --- a/ports/glutin/embedder.rs +++ b/ports/glutin/embedder.rs @@ -91,8 +91,7 @@ impl EmbedderMethods for EmbedderCallbacks { fn register_webxr(&mut self, xr: &mut webxr_api::MainThreadRegistry) { if pref!(dom.webxr.test) { - let gl = self.gl.clone(); - xr.register_mock(webxr::headless::HeadlessMockDiscovery::new(gl)); + xr.register_mock(webxr::headless::HeadlessMockDiscovery::new()); } else if !opts::get().headless && pref!(dom.webxr.glwindow) { warn!("Creating test XR device"); let gl = self.gl.clone(); diff --git a/ports/glutin/headed_window.rs b/ports/glutin/headed_window.rs index dfaf980b6fb..fad971e3cf5 100644 --- a/ports/glutin/headed_window.rs +++ b/ports/glutin/headed_window.rs @@ -188,9 +188,7 @@ impl Window { gl.clear(gl::COLOR_BUFFER_BIT); gl.finish(); - let mut context = GlContext::Current(context); - - context.make_not_current(); + let context = GlContext::Current(context); debug!("Created window {:?}", context.window().id()); let window = Window { @@ -625,7 +623,7 @@ impl WindowMethods for Window { self.animation_state.set(state); } - fn prepare_for_composite(&self) { + fn make_gl_context_current(&self) { self.gl_context.borrow_mut().make_current(); } diff --git a/ports/glutin/headless_window.rs b/ports/glutin/headless_window.rs index c0c5c1fabb0..60ba0e3fc3a 100644 --- a/ports/glutin/headless_window.rs +++ b/ports/glutin/headless_window.rs @@ -189,7 +189,7 @@ impl WindowMethods for Window { } #[cfg(any(target_os = "linux", target_os = "macos"))] - fn prepare_for_composite(&self) { + fn make_gl_context_current(&self) { unsafe { let mut buffer = self.context.buffer.borrow_mut(); let ret = osmesa_sys::OSMesaMakeCurrent( @@ -204,7 +204,7 @@ impl WindowMethods for Window { } #[cfg(not(any(target_os = "linux", target_os = "macos")))] - fn prepare_for_composite(&self) {} + fn make_gl_context_current(&self) {} fn get_gl_context(&self) -> MediaPlayerCtxt::GlContext { MediaPlayerCtxt::GlContext::Unknown diff --git a/ports/libsimpleservo/api/Cargo.toml b/ports/libsimpleservo/api/Cargo.toml index afbd3f4c800..083012403bb 100644 --- a/ports/libsimpleservo/api/Cargo.toml +++ b/ports/libsimpleservo/api/Cargo.toml @@ -44,7 +44,7 @@ layout-2020 = ["libservo/layout-2020"] max_log_level = ["log/release_max_level_info"] native-bluetooth = ["libservo/native-bluetooth"] no_static_freetype = ["libservo/no_static_freetype"] -no_wgl = ["libservo/no_wgl"] +no-wgl = ["libservo/no-wgl"] oculusvr = ["libservo/oculusvr"] webdriver = ["libservo/webdriver"] uwp = ["libservo/uwp", "webxr", "webxr/openxr-api"] diff --git a/ports/libsimpleservo/api/src/lib.rs b/ports/libsimpleservo/api/src/lib.rs index 12fba7a6d3e..4f17dad9e7a 100644 --- a/ports/libsimpleservo/api/src/lib.rs +++ b/ports/libsimpleservo/api/src/lib.rs @@ -646,7 +646,7 @@ impl EmbedderMethods for ServoEmbedderCallbacks { } impl WindowMethods for ServoWindowCallbacks { - fn prepare_for_composite(&self) { + fn make_gl_context_current(&self) { debug!("WindowMethods::prepare_for_composite"); self.host_callbacks.make_current(); } diff --git a/ports/libsimpleservo/capi/Cargo.toml b/ports/libsimpleservo/capi/Cargo.toml index 594f1f8f36b..62c8b31632e 100644 --- a/ports/libsimpleservo/capi/Cargo.toml +++ b/ports/libsimpleservo/capi/Cargo.toml @@ -39,7 +39,7 @@ layout-2013 = ["simpleservo/layout-2013"] layout-2020 = ["simpleservo/layout-2020"] max_log_level = ["simpleservo/max_log_level"] native-bluetooth = ["simpleservo/native-bluetooth"] -no_wgl = ["simpleservo/no_wgl"] +no-wgl = ["simpleservo/no-wgl"] oculusvr = ["simpleservo/oculusvr"] uwp = ["simpleservo/uwp"] webdriver = ["simpleservo/webdriver"] diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py index 6702c571f3a..aa99557c7b7 100644 --- a/python/servo/build_commands.py +++ b/python/servo/build_commands.py @@ -694,13 +694,16 @@ class MachCommands(CommandBase): continue libs = remaining_libs if not libs: - return + return True for lib in libs: print("WARNING: could not find " + lib) # UWP build has its own ANGLE library that it packages. if not uwp: - package_generated_shared_libraries(["libEGL.dll", "libGLESv2.dll"], build_path, servo_exe_dir) + print("Packaging EGL DLLs") + egl_libs = ["libEGL.dll", "libGLESv2.dll"] + if not package_generated_shared_libraries(egl_libs, build_path, servo_exe_dir): + status = 1 # copy needed gstreamer DLLs in to servo.exe dir print("Packaging gstreamer DLLs") diff --git a/python/servo/command_base.py b/python/servo/command_base.py index 3b289e62491..2a82ec51612 100644 --- a/python/servo/command_base.py +++ b/python/servo/command_base.py @@ -890,7 +890,7 @@ install them, let us know by filing a bug!") features.append("native-bluetooth") if uwp: features.append("canvas2d-raqote") - features.append("no_wgl") + features.append("no-wgl") features.append("uwp") else: # Non-UWP builds provide their own libEGL via mozangle. @@ -907,7 +907,7 @@ install them, let us know by filing a bug!") env['RUSTFLAGS'] = env.get('RUSTFLAGS', "") + " -C force-frame-pointers=yes" features.append("profilemozjs") if without_wgl: - features.append("no_wgl") + features.append("no-wgl") if self.config["build"]["webgl-backtrace"]: features.append("webgl-backtrace") if self.config["build"]["dom-backtrace"]: diff --git a/servo-tidy.toml b/servo-tidy.toml index cc55ed17dc2..6c420c05d0f 100644 --- a/servo-tidy.toml +++ b/servo-tidy.toml @@ -28,6 +28,7 @@ rand = [ # Ignored packages with duplicated versions packages = [ "cgl", + "cocoa", "gl_generator", # https://github.com/servo/servo/pull/23288#issuecomment-494687746 "gleam", "proc-macro2", @@ -35,6 +36,7 @@ packages = [ "syn", "synstructure", "unicode-xid", + "wayland-sys", ] # Files that are ignored for all tidy and lint checks. files = [ diff --git a/support/hololens/ServoApp/ServoApp.vcxproj b/support/hololens/ServoApp/ServoApp.vcxproj index faebf1e00d5..1a5bd6452cb 100644 --- a/support/hololens/ServoApp/ServoApp.vcxproj +++ b/support/hololens/ServoApp/ServoApp.vcxproj @@ -1,4 +1,4 @@ - + diff --git a/tests/wpt/metadata/webxr/xrWebGLLayer_framebuffer_draw.https.html.ini b/tests/wpt/metadata/webxr/xrWebGLLayer_framebuffer_draw.https.html.ini deleted file mode 100644 index bf7eed9a971..00000000000 --- a/tests/wpt/metadata/webxr/xrWebGLLayer_framebuffer_draw.https.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[xrWebGLLayer_framebuffer_draw.https.html] - [Ensure a WebGL layer's framebuffer can only be drawn to inside a XR frame] - expected: FAIL - diff --git a/tests/wpt/metadata/webxr/xrWebGLLayer_opaque_framebuffer.https.html.ini b/tests/wpt/metadata/webxr/xrWebGLLayer_opaque_framebuffer.https.html.ini index 63c92e14304..1513198ae52 100644 --- a/tests/wpt/metadata/webxr/xrWebGLLayer_opaque_framebuffer.https.html.ini +++ b/tests/wpt/metadata/webxr/xrWebGLLayer_opaque_framebuffer.https.html.ini @@ -1,7 +1,4 @@ [xrWebGLLayer_opaque_framebuffer.https.html] - [Ensure that the framebuffer given by the WebGL layer is opaque for immersive] - expected: FAIL - [Ensure that the framebuffer given by the WebGL layer is opaque for non-immersive] expected: FAIL diff --git a/tests/wpt/webgl/meta/MANIFEST.json b/tests/wpt/webgl/meta/MANIFEST.json index 831dbd8c340..b7b54c924bd 100644 --- a/tests/wpt/webgl/meta/MANIFEST.json +++ b/tests/wpt/webgl/meta/MANIFEST.json @@ -14740,7 +14740,9 @@ "conformance/rendering/preservedrawingbuffer-leak.html": [ [ "conformance/rendering/preservedrawingbuffer-leak.html", - {} + { + "timeout": "long" + } ] ], "conformance/rendering/rendering-stencil-large-viewport.html": [ @@ -36755,7 +36757,7 @@ "testharness" ], "conformance/rendering/preservedrawingbuffer-leak.html": [ - "3df53551ef062f8c5a9b52003f2a564db14d990f", + "80571f50ffa06d33e5731c33b75898d4ad329209", "testharness" ], "conformance/rendering/rendering-stencil-large-viewport.html": [ diff --git a/tests/wpt/webgl/meta/conformance/canvas/drawingbuffer-static-canvas-test.html.ini b/tests/wpt/webgl/meta/conformance/canvas/drawingbuffer-static-canvas-test.html.ini deleted file mode 100644 index 55a1ba08a36..00000000000 --- a/tests/wpt/webgl/meta/conformance/canvas/drawingbuffer-static-canvas-test.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawingbuffer-static-canvas-test.html] - bug: https://github.com/servo/servo/issues/21556 - expected: CRASH diff --git a/tests/wpt/webgl/meta/conformance/canvas/drawingbuffer-test.html.ini b/tests/wpt/webgl/meta/conformance/canvas/drawingbuffer-test.html.ini deleted file mode 100644 index 1fe2084d611..00000000000 --- a/tests/wpt/webgl/meta/conformance/canvas/drawingbuffer-test.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[drawingbuffer-test.html] - bug: https://github.com/servo/servo/issues/21718 - expected: CRASH diff --git a/tests/wpt/webgl/meta/conformance/rendering/more-than-65536-indices.html.ini b/tests/wpt/webgl/meta/conformance/rendering/more-than-65536-indices.html.ini new file mode 100644 index 00000000000..89644b43e1a --- /dev/null +++ b/tests/wpt/webgl/meta/conformance/rendering/more-than-65536-indices.html.ini @@ -0,0 +1,5 @@ +[more-than-65536-indices.html] + bug: https://github.com/servo/servo/issues/24538 + [WebGL test #8: Should be green.\nat (0, 0) expected: 0,255,0,255 was 128,128,0,255] + expected: FAIL + diff --git a/tests/wpt/webgl/meta/conformance/rendering/rendering-stencil-large-viewport.html.ini b/tests/wpt/webgl/meta/conformance/rendering/rendering-stencil-large-viewport.html.ini index ef257e40bc2..436684031a6 100644 --- a/tests/wpt/webgl/meta/conformance/rendering/rendering-stencil-large-viewport.html.ini +++ b/tests/wpt/webgl/meta/conformance/rendering/rendering-stencil-large-viewport.html.ini @@ -1,2 +1,2 @@ [rendering-stencil-large-viewport.html] - expected: CRASH + expected: TIMEOUT diff --git a/tests/wpt/webgl/meta/conformance/textures/misc/copy-tex-image-and-sub-image-2d.html.ini b/tests/wpt/webgl/meta/conformance/textures/misc/copy-tex-image-and-sub-image-2d.html.ini index b0ee93c423f..bef676b52ff 100644 --- a/tests/wpt/webgl/meta/conformance/textures/misc/copy-tex-image-and-sub-image-2d.html.ini +++ b/tests/wpt/webgl/meta/conformance/textures/misc/copy-tex-image-and-sub-image-2d.html.ini @@ -2,19 +2,19 @@ [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 - [WebGL test #434: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - [WebGL test #333: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #285: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #184: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #215: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #384: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 0,0,255,255] + [WebGL test #493: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] + expected: FAIL + + [WebGL test #434: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 128,128,128,128] expected: FAIL [WebGL test #314: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] @@ -23,31 +23,22 @@ [WebGL test #276: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL + [WebGL test #485: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] + expected: FAIL + [WebGL test #303: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #223: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #425: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #45: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #488: 0, 0 should render 136,136,136,136 (+/-1)\nat (0, 0) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - - [WebGL test #436: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - - [WebGL test #489: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - [WebGL test #72: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #498: 0, 0 should render 136,136,136,136 (+/-1)\nat (0, 0) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #499: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #133: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 0,255,0,255] expected: FAIL [WebGL test #55: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] @@ -56,82 +47,61 @@ [WebGL test #164: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #240: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - - [WebGL test #242: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #233: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #293: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #199: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 128,128,128,128] + [WebGL test #475: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #54: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #479: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #192: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 0,255,0,255] expected: FAIL - [WebGL test #195: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,0,255,255] + [WebGL test #154: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #313: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL + [WebGL test #483: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] + expected: FAIL + [WebGL test #12: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #476: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #94: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 0,255,0,255] expected: FAIL - [WebGL test #494: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - - [WebGL test #188: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #405: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #283: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #451: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 128,128,128,128] + [WebGL test #455: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #264: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #227: 0, 0 should render 136,136,136,136 (+/-1)\nat (0, 0) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #152: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #336: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #174: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #193: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 0,0,255,255] + [WebGL test #404: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #453: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 128,128,128,128] + [WebGL test #153: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #491: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - - [WebGL test #443: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #446: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #213: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #205: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 128,128,128,128] - expected: FAIL - - [WebGL test #170: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #143: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #394: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #334: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] @@ -140,37 +110,19 @@ [WebGL test #214: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #399: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - [WebGL test #415: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #197: 0, 0 should render 136,136,136,136 (+/-1)\nat (0, 0) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - [WebGL test #296: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #274: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #495: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #222: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #475: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - - [WebGL test #354: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] - expected: FAIL - - [WebGL test #351: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - - [WebGL test #393: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - - [WebGL test #456: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 128,128,128,128] + [WebGL test #396: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #463: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] @@ -179,82 +131,28 @@ [WebGL test #34: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #394: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - [WebGL test #62: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #220: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - - [WebGL test #464: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #355: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 128,128,128,128] - expected: FAIL - [WebGL test #102: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #105: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 128,128,128,128] - expected: FAIL - - [WebGL test #228: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #395: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - - [WebGL test #174: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #203: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 128,128,128,128] - expected: FAIL - - [WebGL test #165: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - [WebGL test #304: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #481: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #421: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #474: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #363: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #142: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #165: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #485: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 0,0,255,255] + [WebGL test #456: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #244: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - - [WebGL test #439: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #148: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #103: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] - expected: FAIL - - [WebGL test #204: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 128,128,128,128] - expected: FAIL - - [WebGL test #484: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #391: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - - [WebGL test #350: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 128,128,128,128] + [WebGL test #83: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #305: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] @@ -263,10 +161,16 @@ [WebGL test #15: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #222: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #453: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #403: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 0,255,0,255] + [WebGL test #202: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] + expected: FAIL + + [WebGL test #345: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 0,255,0,255] + expected: FAIL + + [WebGL test #234: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #25: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] @@ -275,70 +179,52 @@ [WebGL test #323: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #239: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - - [WebGL test #190: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - [WebGL test #64: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #147: 0, 0 should render 136,136,136,136 (+/-1)\nat (0, 0) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #135: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,255,0,255] expected: FAIL - [WebGL test #245: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #183: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 128,128,128,128] expected: FAIL - [WebGL test #448: 0, 0 should render 136,136,136,136 (+/-1)\nat (0, 0) expected: 136,136,136,136 was 128,128,128,128] + [WebGL test #245: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #229: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #386: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,255,0,255] expected: FAIL - [WebGL test #396: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #224: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #155: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,255,0,255] + [WebGL test #243: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #154: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 0,255,0,255] + [WebGL test #444: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #180: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - - [WebGL test #425: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #416: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #484: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #353: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #138: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 128,128,128,128] + [WebGL test #213: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #237: 0, 0 should render 136,136,136,136 (+/-1)\nat (0, 0) expected: 136,136,136,136 was 128,128,128,128] + [WebGL test #354: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #112: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL + [WebGL test #476: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] + expected: FAIL + [WebGL test #306: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #471: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - - [WebGL test #175: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #202: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 128,128,128,128] - expected: FAIL - - [WebGL test #345: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 0,0,255,255] + [WebGL test #185: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #212: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] @@ -347,34 +233,16 @@ [WebGL test #22: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #153: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 0,255,0,255] - expected: FAIL - - [WebGL test #341: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #430: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - - [WebGL test #474: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #426: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #162: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #100: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 128,128,128,128] + [WebGL test #194: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #398: 0, 0 should render 136,136,136,136 (+/-1)\nat (0, 0) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #413: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] - expected: FAIL - - [WebGL test #250: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #144: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #242: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #33: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] @@ -383,85 +251,61 @@ [WebGL test #275: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #232: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 0,0,255,255] + [WebGL test #204: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #83: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] + [WebGL test #486: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #234: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 0,0,255,255] + [WebGL test #144: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 128,128,128,128] expected: FAIL - [WebGL test #215: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #149: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #493: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #184: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #114: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #95: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,0,255,255] + [WebGL test #195: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #145: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - - [WebGL test #386: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #248: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #193: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #273: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #194: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #496: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #406: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #23: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #249: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #203: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #230: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #192: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 0,0,255,255] + [WebGL test #104: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #284: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #431: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 128,128,128,128] + [WebGL test #244: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #400: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #436: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #441: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #478: 0, 0 should render 136,136,136,136 (+/-1)\nat (0, 0) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #225: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #53: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #224: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #356: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #140: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - - [WebGL test #469: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 128,128,128,128] + [WebGL test #494: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #63: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] @@ -476,108 +320,81 @@ [WebGL test #73: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #90: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #483: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 0,0,255,255] + [WebGL test #103: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #32: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #225: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - - [WebGL test #189: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #440: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 0,255,0,255] - expected: FAIL - - [WebGL test #454: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 128,128,128,128] - expected: FAIL - - [WebGL test #445: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - [WebGL test #13: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #99: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - [WebGL test #42: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL + [WebGL test #403: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] + expected: FAIL + [WebGL test #93: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #473: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #155: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] + expected: FAIL + + [WebGL test #446: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] + expected: FAIL + + [WebGL test #435: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] + expected: FAIL + + [WebGL test #495: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #266: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #94: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #85: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - - [WebGL test #426: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - [WebGL test #365: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #218: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 128,128,128,128] + [WebGL test #413: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #35: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #133: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 0,0,255,255] + [WebGL test #235: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #150: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #143: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #480: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #416: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #406: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,255,0,255] + [WebGL test #232: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #450: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 128,128,128,128] + [WebGL test #454: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #356: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 128,128,128,128] + [WebGL test #85: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 128,128,128,128] expected: FAIL [WebGL test #24: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #486: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - [WebGL test #82: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #185: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 255,0,0,255] + [WebGL test #395: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 128,128,128,128] + expected: FAIL + + [WebGL test #393: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 128,128,128,128] expected: FAIL [WebGL test #44: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #389: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - - [WebGL test #243: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - - [WebGL test #179: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - [WebGL test #43: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL @@ -593,40 +410,25 @@ [WebGL test #295: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #490: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - - [WebGL test #135: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #183: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - - [WebGL test #455: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 128,128,128,128] - expected: FAIL - - [WebGL test #346: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #449: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 128,128,128,128] - expected: FAIL - - [WebGL test #200: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 128,128,128,128] + [WebGL test #473: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #344: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #435: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 255,0,0,255] - expected: FAIL - [WebGL test #294: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #466: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,0,255,255] + [WebGL test #142: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 128,128,128,128] expected: FAIL - [WebGL test #233: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 0,0,255,255] + [WebGL test #445: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] + expected: FAIL + + [WebGL test #464: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] + expected: FAIL + + [WebGL test #175: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #465: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] @@ -635,45 +437,45 @@ [WebGL test #92: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #198: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 128,128,128,128] + [WebGL test #95: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #238: 1, 0 should render 136,136,136,136 (+/-1)\nat (1, 0) expected: 136,136,136,136 was 128,128,128,128] + [WebGL test #496: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #500: 0, 1 should render 136,136,136,136 (+/-1)\nat (0, 1) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #105: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #235: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 0,0,255,255] + [WebGL test #223: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] + expected: FAIL + + [WebGL test #336: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 128,128,128,128] + expected: FAIL + + [WebGL test #355: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 136,136,136,136] + expected: FAIL + + [WebGL test #346: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL [WebGL test #324: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #501: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #205: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #152: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 0,255,0,255] + [WebGL test #145: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #401: 1, 1 should render 136,136,136,136 (+/-1)\nat (1, 1) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #384: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 0,255,0,255] expected: FAIL - [WebGL test #404: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 0,255,0,255] - expected: FAIL - - [WebGL test #444: 1, 0 should render 0,0,0,0 (+/-1)\nat (1, 0) expected: 0,0,0,0 was 0,0,255,255] - expected: FAIL - - [WebGL test #247: 0, 0 should render 136,136,136,136 (+/-1)\nat (0, 0) expected: 136,136,136,136 was 0,255,0,255] + [WebGL test #443: 0, 0 should render 0,0,0,0 (+/-1)\nat (0, 0) expected: 0,0,0,0 was 0,255,0,255] expected: FAIL [WebGL test #286: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL - [WebGL test #405: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 0,255,0,255] - expected: FAIL - - [WebGL test #104: 0, 1 should render 0,0,0,0 (+/-1)\nat (0, 1) expected: 0,0,0,0 was 128,128,128,128] + [WebGL test #466: 1, 1 should render 0,0,0,0 (+/-1)\nat (1, 1) expected: 0,0,0,0 was 136,136,136,136] expected: FAIL diff --git a/tests/wpt/webgl/meta/conformance2/reading/read-pixels-pack-parameters.html.ini b/tests/wpt/webgl/meta/conformance2/reading/read-pixels-pack-parameters.html.ini index 92abc7c772e..936118db0fe 100644 --- a/tests/wpt/webgl/meta/conformance2/reading/read-pixels-pack-parameters.html.ini +++ b/tests/wpt/webgl/meta/conformance2/reading/read-pixels-pack-parameters.html.ini @@ -3,112 +3,70 @@ [WebGL test #15: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #135: last pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #237: last pixel of row 0: expected [249,102,0,255\], got [1,2,3,4\]] - expected: FAIL - - [WebGL test #77: last pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #125: Padding byte 0 of row 1 changed: expected 1, got 2] expected: FAIL [WebGL test #52: Padding byte 0 of row 0 changed: expected 1, got 249] expected: FAIL - [WebGL test #210: first pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #172: Padding byte 4 of row 0 changed: expected 1, got 249] - expected: FAIL - [WebGL test #54: Padding byte 0 of row 1 changed: expected 1, got 2] expected: FAIL - [WebGL test #208: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - [WebGL test #44: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #238: first pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]] + [WebGL test #177: first pixel of row 0: expected [249,102,0,255\], got [1,2,3,4\]] expected: FAIL [WebGL test #55: last pixel of row 2: expected [2,200,102,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #164: Padding byte 0 of row 0 changed: expected 1, got 249] + [WebGL test #147: Padding byte 4 of row 0 changed: expected 1, got 99] expected: FAIL - [WebGL test #191: last pixel of row 1: expected [99,5,76,255\], got [255,255,255,255\]] + [WebGL test #141: first pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #73: first pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #163: skipped bytes changed at index 0: expected 1 got 249] expected: FAIL - [WebGL test #78: last pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #148: last pixel of row 1: expected [99,5,76,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #225: first pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]] + [WebGL test #85: last pixel of row 2: expected [2,200,102,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #144: first pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #88: first pixel of row 1: expected [1,2,3,4\], got [249,102,0,255\]] expected: FAIL - [WebGL test #95: first pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #131: last pixel of row 1: expected [249,102,0,255\], got [2,200,102,255\]] expected: FAIL - [WebGL test #99: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + [WebGL test #115: Padding byte 8 of row 0 changed: expected 1, got 2] expected: FAIL - [WebGL test #89: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - - [WebGL test #129: last pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #146: first pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #207: Padding byte 0 of row 1 changed: expected 1, got 255] - expected: FAIL - - [WebGL test #104: last pixel of row 1: expected [249,102,0,255\], got [1,2,3,4\]] - expected: FAIL - - [WebGL test #205: first pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #80: last pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #91: first pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #93: first pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #143: last pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #88: last pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #120: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL [WebGL test #22: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #206: last pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #92: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #231: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + [WebGL test #83: last pixel of row 1: expected [249,102,0,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #134: first pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #171: getError expected: INVALID_OPERATION. Was NO_ERROR : Invalid pack params combination] expected: FAIL - [WebGL test #139: last pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #132: Padding byte 0 of row 1 changed: expected 1, got 2] expected: FAIL - [WebGL test #81: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + [WebGL test #172: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + expected: FAIL + + [WebGL test #124: last pixel of row 1: expected [249,102,0,255\], got [2,200,102,255\]] expected: FAIL [WebGL test #170: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] @@ -117,49 +75,31 @@ [WebGL test #17: getError expected: NO_ERROR. Was INVALID_ENUM : readPixels should succeed] expected: FAIL - [WebGL test #115: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + [WebGL test #80: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #106: last pixel of row 2: expected [2,200,102,255\], got [1,2,3,4\]] + [WebGL test #180: last pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #107: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - - [WebGL test #169: last pixel of row 2: expected [2,200,102,255\], got [1,2,3,4\]] - expected: FAIL - - [WebGL test #187: first pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] + [WebGL test #110: Padding byte 0 of row 1 changed: expected 1, got 134] expected: FAIL [WebGL test #56: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #125: last pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #121: last pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #160: Padding byte 0 of row 1 changed: expected 1, got 134] + [WebGL test #74: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL [WebGL test #58: first pixel of row 1: expected [1,2,3,4\], got [249,102,0,255\]] expected: FAIL - [WebGL test #190: Padding byte 4 of row 0 changed: expected 1, got 99] + [WebGL test #89: last pixel of row 1: expected [249,102,0,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #74: last pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #152: first pixel of row 1: expected [99,5,76,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #200: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - - [WebGL test #193: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - - [WebGL test #79: first pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #108: Padding byte 4 of row 0 changed: expected 1, got 2] expected: FAIL [WebGL test #62: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] @@ -168,121 +108,91 @@ [WebGL test #7: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #97: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + [WebGL test #158: getError expected: INVALID_OPERATION. Was NO_ERROR : Invalid pack params combination] expected: FAIL - [WebGL test #178: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + [WebGL test #166: first pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #130: first pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #144: first pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] + expected: FAIL + + [WebGL test #106: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL [WebGL test #53: last pixel of row 1: expected [249,102,0,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #148: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - [WebGL test #9: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #202: first pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - [WebGL test #59: last pixel of row 1: expected [249,102,0,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #176: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + [WebGL test #164: first pixel of row 0: expected [249,102,0,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #220: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - - [WebGL test #159: last pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]] + [WebGL test #76: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL [WebGL test #34: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #188: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + [WebGL test #142: last pixel of row 1: expected [1,2,3,4\], got [134,87,234,255\]] expected: FAIL - [WebGL test #235: skipped bytes changed at index 0: expected 1 got 249] + [WebGL test #143: Padding byte 0 of row 1 changed: expected 1, got 134] + expected: FAIL + + [WebGL test #134: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + expected: FAIL + + [WebGL test #91: last pixel of row 2: expected [2,200,102,255\], got [1,2,3,4\]] expected: FAIL [WebGL test #40: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #168: first pixel of row 2: expected [2,200,102,255\], got [1,2,3,4\]] + [WebGL test #169: last pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #94: last pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #195: last pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #182: last pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] expected: FAIL [WebGL test #18: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #71: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + [WebGL test #140: Padding byte 4 of row 0 changed: expected 1, got 2] expected: FAIL - [WebGL test #186: Padding byte 0 of row 1 changed: expected 1, got 134] - expected: FAIL - - [WebGL test #85: first pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #236: first pixel of row 0: expected [249,102,0,255\], got [1,2,3,4\]] - expected: FAIL - - [WebGL test #124: first pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #174: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL [WebGL test #20: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #147: last pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #218: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - - [WebGL test #68: last pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #185: last pixel of row 1: expected [1,2,3,4\], got [134,87,234,255\]] - expected: FAIL - [WebGL test #42: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #216: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - - [WebGL test #215: Padding byte 0 of row 1 changed: expected 1, got 255] - expected: FAIL - - [WebGL test #166: last pixel of row 1: expected [249,102,0,255\], got [2,200,102,255\]] - expected: FAIL - - [WebGL test #224: last pixel of row 0: expected [249,102,0,255\], got [1,2,3,4\]] + [WebGL test #136: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL [WebGL test #155: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #222: skipped bytes changed at index 0: expected 1 got 249] + [WebGL test #78: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #69: last pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #104: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #103: Padding byte 0 of row 0 changed: expected 1, got 249] + [WebGL test #145: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #232: getError expected: INVALID_OPERATION. Was NO_ERROR : Invalid pack params combination] + [WebGL test #118: Padding byte 0 of row 1 changed: expected 1, got 134] + expected: FAIL + + [WebGL test #165: last pixel of row 0: expected [249,102,0,255\], got [1,2,3,4\]] expected: FAIL [WebGL test #11: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] @@ -291,82 +201,67 @@ [WebGL test #3: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #162: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + [WebGL test #176: skipped bytes changed at index 0: expected 1 got 249] + expected: FAIL + + [WebGL test #94: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + expected: FAIL + + [WebGL test #102: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL [WebGL test #5: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #183: Padding byte 4 of row 0 changed: expected 1, got 2] - expected: FAIL - - [WebGL test #167: Padding byte 0 of row 1 changed: expected 1, got 2] - expected: FAIL - - [WebGL test #204: Padding byte 4 of row 0 changed: expected 1, got 255] - expected: FAIL - - [WebGL test #84: last pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #126: first pixel of row 2: expected [2,200,102,255\], got [1,2,3,4\]] expected: FAIL [WebGL test #24: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #198: last pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #157: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #153: first pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] + [WebGL test #117: last pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #120: last pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #98: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #128: last pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #161: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #226: last pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]] - expected: FAIL - - [WebGL test #182: last pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #214: last pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #178: last pixel of row 0: expected [249,102,0,255\], got [1,2,3,4\]] expected: FAIL [WebGL test #66: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #223: first pixel of row 0: expected [249,102,0,255\], got [1,2,3,4\]] - expected: FAIL - [WebGL test #36: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #217: getError expected: INVALID_OPERATION. Was NO_ERROR : Invalid pack params combination] - expected: FAIL - - [WebGL test #158: first pixel of row 1: expected [1,2,3,4\], got [2,200,102,255\]] - expected: FAIL - [WebGL test #32: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #173: last pixel of row 1: expected [249,102,0,255\], got [2,200,102,255\]] + [WebGL test #111: first pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #230: getError expected: INVALID_OPERATION. Was NO_ERROR : Invalid pack params combination] + [WebGL test #151: Padding byte 4 of row 0 changed: expected 1, got 99] expected: FAIL [WebGL test #28: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #180: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + [WebGL test #179: first pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #241: last pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] + [WebGL test #112: last pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #219: getError expected: INVALID_OPERATION. Was NO_ERROR : Invalid pack params combination] + [WebGL test #82: Padding byte 0 of row 0 changed: expected 1, got 249] + expected: FAIL + + [WebGL test #84: Padding byte 0 of row 1 changed: expected 1, got 2] expected: FAIL [WebGL test #61: last pixel of row 2: expected [2,200,102,255\], got [1,2,3,4\]] @@ -378,103 +273,82 @@ [WebGL test #64: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #46: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + [WebGL test #173: getError expected: INVALID_OPERATION. Was NO_ERROR : Invalid pack params combination] expected: FAIL - [WebGL test #86: last pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #109: last pixel of row 1: expected [2,200,102,255\], got [134,87,234,255\]] expected: FAIL - [WebGL test #96: last pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #119: last pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #142: first pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #86: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #196: Padding byte 4 of row 0 changed: expected 1, got 99] + [WebGL test #153: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #154: last pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] + [WebGL test #90: first pixel of row 2: expected [1,2,3,4\], got [2,200,102,255\]] expected: FAIL - [WebGL test #157: Padding byte 8 of row 0 changed: expected 1, got 2] + [WebGL test #68: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #212: Padding byte 4 of row 0 changed: expected 1, got 255] + [WebGL test #122: Padding byte 0 of row 0 changed: expected 1, got 249] expected: FAIL - [WebGL test #184: first pixel of row 1: expected [2,200,102,255\], got [255,255,255,255\]] + [WebGL test #116: first pixel of row 1: expected [1,2,3,4\], got [2,200,102,255\]] expected: FAIL [WebGL test #113: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #75: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - [WebGL test #26: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #101: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] + [WebGL test #96: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #109: first pixel of row 1: expected [1,2,3,4\], got [249,102,0,255\]] + [WebGL test #46: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #105: Padding byte 0 of row 1 changed: expected 1, got 2] + [WebGL test #123: first pixel of row 1: expected [249,102,0,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #87: first pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #183: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).] expected: FAIL - [WebGL test #132: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - - [WebGL test #126: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - - [WebGL test #112: last pixel of row 2: expected [2,200,102,255\], got [1,2,3,4\]] - expected: FAIL - - [WebGL test #174: Padding byte 0 of row 1 changed: expected 1, got 2] + [WebGL test #168: first pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] expected: FAIL [WebGL test #60: first pixel of row 2: expected [1,2,3,4\], got [2,200,102,255\]] expected: FAIL - [WebGL test #203: last pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #128: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #70: last pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #72: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL [WebGL test #13: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #145: last pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #130: Padding byte 4 of row 0 changed: expected 1, got 249] expected: FAIL - [WebGL test #211: last pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #167: last pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #175: last pixel of row 2: expected [2,200,102,255\], got [1,2,3,4\]] + [WebGL test #160: getError expected: INVALID_OPERATION. Was NO_ERROR : Invalid pack params combination] expected: FAIL - [WebGL test #111: first pixel of row 2: expected [1,2,3,4\], got [2,200,102,255\]] + [WebGL test #100: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #227: first pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] + [WebGL test #70: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #92: last pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #83: first pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #229: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - - [WebGL test #199: Padding byte 0 of row 1 changed: expected 1, got 255] + [WebGL test #181: first pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] expected: FAIL [WebGL test #50: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] @@ -483,75 +357,24 @@ [WebGL test #48: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #240: first pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] - expected: FAIL - - [WebGL test #110: last pixel of row 1: expected [249,102,0,255\], got [1,2,3,4\]] - expected: FAIL - - [WebGL test #117: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - - [WebGL test #138: first pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #233: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - - [WebGL test #140: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - [WebGL test #1: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #192: Padding byte 0 of row 1 changed: expected 1, got 255] + [WebGL test #149: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #119: last pixel of row 0: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #133: last pixel of row 2: expected [2,200,102,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #136: first pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #239: last pixel of row 1: expected [2,200,102,255\], got [1,2,3,4\]] - expected: FAIL - - [WebGL test #131: last pixel of row 2: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #197: first pixel of row 1: expected [99,5,76,255\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #161: last pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] - expected: FAIL - - [WebGL test #152: Padding byte 0 of row 1 changed: expected 1, got 134] + [WebGL test #159: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL [WebGL test #30: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL - [WebGL test #213: first pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] + [WebGL test #127: last pixel of row 2: expected [2,200,102,255\], got [1,2,3,4\]] expected: FAIL - [WebGL test #137: last pixel of row 1: expected [1,2,3,4\], got [255,255,255,255\]] - expected: FAIL - - [WebGL test #165: first pixel of row 1: expected [249,102,0,255\], got [1,2,3,4\]] - expected: FAIL - - [WebGL test #228: last pixel of row 2: expected [134,87,234,255\], got [1,2,3,4\]] - expected: FAIL - - [WebGL test #151: last pixel of row 1: expected [2,200,102,255\], got [134,87,234,255\]] - expected: FAIL - - [WebGL test #122: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] - expected: FAIL - - [WebGL test #242: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).] - expected: FAIL - - [WebGL test #150: Padding byte 4 of row 0 changed: expected 1, got 2] + [WebGL test #138: getError expected: INVALID_OPERATION. Was INVALID_ENUM : buffer too small] expected: FAIL diff --git a/tests/wpt/webgl/tests/conformance/rendering/preservedrawingbuffer-leak.html b/tests/wpt/webgl/tests/conformance/rendering/preservedrawingbuffer-leak.html index 3df53551ef0..80571f50ffa 100644 --- a/tests/wpt/webgl/tests/conformance/rendering/preservedrawingbuffer-leak.html +++ b/tests/wpt/webgl/tests/conformance/rendering/preservedrawingbuffer-leak.html @@ -29,6 +29,7 @@ + WebGL PreserveDrawingBuffer Leak Test diff --git a/tests/wpt/webgl/tools/timeout.patch b/tests/wpt/webgl/tools/timeout.patch index 557e4cd92b5..acc944179a4 100644 --- a/tests/wpt/webgl/tools/timeout.patch +++ b/tests/wpt/webgl/tools/timeout.patch @@ -1808,3 +1808,15 @@ index a2166e9df7..fb9067f6c2 100644 WebGL GLSL Conformance Tests - Reserved Words +diff --git a/tests/wpt/webgl/tests/conformance/rendering/preservedrawingbuffer-leak.html b/tests/wpt/webgl/tests/conformance/rendering/preservedrawingbuffer-leak.html +index 3df5355..80571f5 100644 +--- a/tests/wpt/webgl/tests/conformance/rendering/preservedrawingbuffer-leak.html ++++ b/tests/wpt/webgl/tests/conformance/rendering/preservedrawingbuffer-leak.html +@@ -29,6 +29,7 @@ + + + ++ + WebGL PreserveDrawingBuffer Leak Test + +