diff options
40 files changed, 1346 insertions, 86 deletions
diff --git a/Cargo.lock b/Cargo.lock index af6d4733ef3..77e1b2982b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1117,6 +1117,11 @@ dependencies = [ ] [[package]] +name = "half" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "harfbuzz-sys" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2323,6 +2328,8 @@ dependencies = [ "euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", + "gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "half 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3509,6 +3516,7 @@ dependencies = [ "checksum gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86944a6a4d7f54507f8ee930192d971f18a7b1da526ff529b7a0d4043935380" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum glx 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b280007fa9c7442cfd1e0b1addb8d1a59240267110e8705f8f7e2c7bfb7e2f72" +"checksum half 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63d68db75012a85555434ee079e7e6337931f87a087ab2988becbadf64673a7f" "checksum harfbuzz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6b76113246f5c089dcf272cf89c3f61168a4d77b50ec5b2c1fab8c628c9ea762" "checksum heapsize 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "556cd479866cf85c3f671209c85e8a6990211c916d1002c2fcb2e9b7cf60bc36" "checksum heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "46f96d52fb1564059fc97b85ef6165728cc30198ab60073bf114c66c4c89bb5d" diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 388801aa011..141bb95f78f 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -43,7 +43,9 @@ domobject_derive = {path = "../domobject_derive"} encoding = "0.2" euclid = "0.11" fnv = "1.0" +gleam = "0.4" gfx_traits = {path = "../gfx_traits"} +half = "1.0" heapsize = "0.3.6" heapsize_derive = "0.1" html5ever = {version = "0.16", features = ["heap_size", "unstable"]} diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 2b3bfceceb2..3b96d954dcb 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -107,7 +107,7 @@ use style::viewport::ViewportRule; use time::Duration; use uuid::Uuid; use webrender_traits::{WebGLBufferId, WebGLError, WebGLFramebufferId, WebGLProgramId}; -use webrender_traits::{WebGLRenderbufferId, WebGLShaderId, WebGLTextureId}; +use webrender_traits::{WebGLRenderbufferId, WebGLShaderId, WebGLTextureId, WebGLVertexArrayId}; use webvr_traits::WebVRGamepadHand; /// A trait to allow tracing (only) DOM objects. @@ -388,6 +388,7 @@ unsafe_no_jsmanaged_fields!(WebGLProgramId); unsafe_no_jsmanaged_fields!(WebGLRenderbufferId); unsafe_no_jsmanaged_fields!(WebGLShaderId); unsafe_no_jsmanaged_fields!(WebGLTextureId); +unsafe_no_jsmanaged_fields!(WebGLVertexArrayId); unsafe_no_jsmanaged_fields!(MediaList); unsafe_no_jsmanaged_fields!(WebVRGamepadHand); diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 62bffbdcbcd..bb5f5bf1a71 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -451,6 +451,8 @@ pub mod vrfieldofview; pub mod vrframedata; pub mod vrpose; pub mod vrstageparameters; +pub mod webgl_extensions; +pub use self::webgl_extensions::ext::*; pub mod webgl_validations; pub mod webglactiveinfo; pub mod webglbuffer; diff --git a/components/script/dom/webgl_extensions/ext/mod.rs b/components/script/dom/webgl_extensions/ext/mod.rs new file mode 100644 index 00000000000..ed3c77977ac --- /dev/null +++ b/components/script/dom/webgl_extensions/ext/mod.rs @@ -0,0 +1,13 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; +use super::{ext_constants, WebGLExtension, WebGLExtensions}; + +pub mod oestexturefloat; +pub mod oestexturefloatlinear; +pub mod oestexturehalffloat; +pub mod oestexturehalffloatlinear; +pub mod oesvertexarrayobject; +pub mod webglvertexarrayobjectoes; diff --git a/components/script/dom/webgl_extensions/ext/oestexturefloat.rs b/components/script/dom/webgl_extensions/ext/oestexturefloat.rs new file mode 100644 index 00000000000..7e5f5a56f26 --- /dev/null +++ b/components/script/dom/webgl_extensions/ext/oestexturefloat.rs @@ -0,0 +1,56 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::codegen::Bindings::OESTextureFloatBinding; +use dom::bindings::js::Root; +use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; +use dom::webglrenderingcontext::WebGLRenderingContext; +use dom_struct::dom_struct; +use super::{constants as webgl, ext_constants as gl, WebGLExtension, WebGLExtensions}; + +#[dom_struct] +pub struct OESTextureFloat { + reflector_: Reflector, +} + +impl OESTextureFloat { + fn new_inherited() -> OESTextureFloat { + Self { + reflector_: Reflector::new(), + } + } +} + +impl WebGLExtension for OESTextureFloat { + type Extension = OESTextureFloat; + fn new(ctx: &WebGLRenderingContext) -> Root<OESTextureFloat> { + reflect_dom_object(box OESTextureFloat::new_inherited(), + &*ctx.global(), + OESTextureFloatBinding::Wrap) + } + + fn is_supported(ext: &WebGLExtensions) -> bool { + ext.supports_any_gl_extension(&["GL_OES_texture_float", + "GL_ARB_texture_float"]) + } + + fn enable(ext: &WebGLExtensions) { + // Enable FLOAT text data type + ext.enable_tex_type(webgl::FLOAT); + let needs_replace = !ext.supports_gl_extension("GL_OES_texture_float"); + if needs_replace { + // Special internal formats must be used to avoid clamped float values + ext.add_effective_tex_internal_format(webgl::RGBA, webgl::FLOAT, gl::RGBA32F); + ext.add_effective_tex_internal_format(webgl::RGB, webgl::FLOAT, gl::RGB32F); + ext.add_effective_tex_internal_format(webgl::LUMINANCE, webgl::FLOAT, gl::LUMINANCE32F_ARB); + ext.add_effective_tex_internal_format(webgl::ALPHA, webgl::FLOAT, gl::ALPHA32F_ARB); + ext.add_effective_tex_internal_format(webgl::LUMINANCE_ALPHA, webgl::FLOAT, + gl::LUMINANCE_ALPHA32F_ARB); + } + } + + fn name() -> &'static str { + "OES_texture_float" + } +} diff --git a/components/script/dom/webgl_extensions/ext/oestexturefloatlinear.rs b/components/script/dom/webgl_extensions/ext/oestexturefloatlinear.rs new file mode 100644 index 00000000000..d9bd061a7f1 --- /dev/null +++ b/components/script/dom/webgl_extensions/ext/oestexturefloatlinear.rs @@ -0,0 +1,45 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::codegen::Bindings::OESTextureFloatLinearBinding; +use dom::bindings::js::Root; +use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; +use dom::webglrenderingcontext::WebGLRenderingContext; +use dom_struct::dom_struct; +use super::{constants as webgl, WebGLExtension, WebGLExtensions}; + +#[dom_struct] +pub struct OESTextureFloatLinear { + reflector_: Reflector, +} + +impl OESTextureFloatLinear { + fn new_inherited() -> OESTextureFloatLinear { + Self { + reflector_: Reflector::new(), + } + } +} + +impl WebGLExtension for OESTextureFloatLinear { + type Extension = OESTextureFloatLinear; + fn new(ctx: &WebGLRenderingContext) -> Root<OESTextureFloatLinear> { + reflect_dom_object(box OESTextureFloatLinear::new_inherited(), + &*ctx.global(), + OESTextureFloatLinearBinding::Wrap) + } + + fn is_supported(ext: &WebGLExtensions) -> bool { + ext.supports_any_gl_extension(&["GL_OES_texture_float_linear", + "GL_ARB_texture_float"]) + } + + fn enable(ext: &WebGLExtensions) { + ext.enable_filterable_tex_type(webgl::FLOAT); + } + + fn name() -> &'static str { + "OES_texture_float_linear" + } +} diff --git a/components/script/dom/webgl_extensions/ext/oestexturehalffloat.rs b/components/script/dom/webgl_extensions/ext/oestexturehalffloat.rs new file mode 100644 index 00000000000..d9e6aebde6a --- /dev/null +++ b/components/script/dom/webgl_extensions/ext/oestexturehalffloat.rs @@ -0,0 +1,57 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::codegen::Bindings::OESTextureHalfFloatBinding::{self, OESTextureHalfFloatConstants}; +use dom::bindings::js::Root; +use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; +use dom::webglrenderingcontext::WebGLRenderingContext; +use dom_struct::dom_struct; +use super::{constants as webgl, ext_constants as gl, WebGLExtension, WebGLExtensions}; + +#[dom_struct] +pub struct OESTextureHalfFloat { + reflector_: Reflector, +} + +impl OESTextureHalfFloat { + fn new_inherited() -> OESTextureHalfFloat { + Self { + reflector_: Reflector::new(), + } + } +} + +impl WebGLExtension for OESTextureHalfFloat { + type Extension = OESTextureHalfFloat; + fn new(ctx: &WebGLRenderingContext) -> Root<OESTextureHalfFloat> { + reflect_dom_object(box OESTextureHalfFloat::new_inherited(), + &*ctx.global(), + OESTextureHalfFloatBinding::Wrap) + } + + fn is_supported(ext: &WebGLExtensions) -> bool { + ext.supports_any_gl_extension(&["GL_OES_texture_half_float", + "GL_ARB_half_float_pixel", + "GL_NV_half_float"]) + } + + fn enable(ext: &WebGLExtensions) { + // Enable FLOAT text data type + let hf = OESTextureHalfFloatConstants::HALF_FLOAT_OES; + ext.enable_tex_type(hf); + let needs_replace = !ext.supports_gl_extension("GL_OES_texture_float"); + if needs_replace { + // Special internal formats must be used to avoid clamped float values + ext.add_effective_tex_internal_format(webgl::RGBA, hf, gl::RGBA16F); + ext.add_effective_tex_internal_format(webgl::RGB, hf, gl::RGB16F); + ext.add_effective_tex_internal_format(webgl::LUMINANCE, hf, gl::LUMINANCE16F_ARB); + ext.add_effective_tex_internal_format(webgl::ALPHA, hf, gl::ALPHA16F_ARB); + ext.add_effective_tex_internal_format(webgl::LUMINANCE_ALPHA, hf, gl::LUMINANCE_ALPHA16F_ARB); + } + } + + fn name() -> &'static str { + "OES_texture_half_float" + } +} diff --git a/components/script/dom/webgl_extensions/ext/oestexturehalffloatlinear.rs b/components/script/dom/webgl_extensions/ext/oestexturehalffloatlinear.rs new file mode 100644 index 00000000000..3bf9869b26a --- /dev/null +++ b/components/script/dom/webgl_extensions/ext/oestexturehalffloatlinear.rs @@ -0,0 +1,47 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::codegen::Bindings::OESTextureHalfFloatBinding::OESTextureHalfFloatConstants; +use dom::bindings::codegen::Bindings::OESTextureHalfFloatLinearBinding; +use dom::bindings::js::Root; +use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; +use dom::webglrenderingcontext::WebGLRenderingContext; +use dom_struct::dom_struct; +use super::{WebGLExtension, WebGLExtensions}; + +#[dom_struct] +pub struct OESTextureHalfFloatLinear { + reflector_: Reflector, +} + +impl OESTextureHalfFloatLinear { + fn new_inherited() -> OESTextureHalfFloatLinear { + Self { + reflector_: Reflector::new(), + } + } +} + +impl WebGLExtension for OESTextureHalfFloatLinear { + type Extension = OESTextureHalfFloatLinear; + fn new(ctx: &WebGLRenderingContext) -> Root<OESTextureHalfFloatLinear> { + reflect_dom_object(box OESTextureHalfFloatLinear::new_inherited(), + &*ctx.global(), + OESTextureHalfFloatLinearBinding::Wrap) + } + + fn is_supported(ext: &WebGLExtensions) -> bool { + ext.supports_any_gl_extension(&["GL_OES_texture_float_linear", + "GL_ARB_half_float_pixel", + "GL_NV_half_float"]) + } + + fn enable(ext: &WebGLExtensions) { + ext.enable_filterable_tex_type(OESTextureHalfFloatConstants::HALF_FLOAT_OES); + } + + fn name() -> &'static str { + "OES_texture_half_float_linear" + } +} diff --git a/components/script/dom/webgl_extensions/ext/oesvertexarrayobject.rs b/components/script/dom/webgl_extensions/ext/oesvertexarrayobject.rs new file mode 100644 index 00000000000..596af11ceff --- /dev/null +++ b/components/script/dom/webgl_extensions/ext/oesvertexarrayobject.rs @@ -0,0 +1,166 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use canvas_traits::CanvasMsg; +use dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::{self, OESVertexArrayObjectMethods}; +use dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::OESVertexArrayObjectConstants; +use dom::bindings::js::{JS, MutNullableJS, Root}; +use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; +use dom::webglrenderingcontext::WebGLRenderingContext; +use dom::webglvertexarrayobjectoes::WebGLVertexArrayObjectOES; +use dom_struct::dom_struct; +use js::conversions::ToJSValConvertible; +use js::jsapi::JSContext; +use js::jsval::{JSVal, NullValue}; +use std::iter; +use super::{WebGLExtension, WebGLExtensions}; +use webrender_traits::{self, WebGLCommand, WebGLError}; + +#[dom_struct] +pub struct OESVertexArrayObject { + reflector_: Reflector, + ctx: JS<WebGLRenderingContext>, + bound_vao: MutNullableJS<WebGLVertexArrayObjectOES>, +} + +impl OESVertexArrayObject { + fn new_inherited(ctx: &WebGLRenderingContext) -> OESVertexArrayObject { + Self { + reflector_: Reflector::new(), + ctx: JS::from_ref(ctx), + bound_vao: MutNullableJS::new(None) + } + } + + #[allow(unsafe_code)] + fn get_current_binding(&self, cx:*mut JSContext) -> JSVal { + rooted!(in(cx) let mut rval = NullValue()); + if let Some(bound_vao) = self.bound_vao.get() { + unsafe { + bound_vao.to_jsval(cx, rval.handle_mut()); + } + } + rval.get() + } +} + +impl OESVertexArrayObjectMethods for OESVertexArrayObject { + // https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/ + fn CreateVertexArrayOES(&self) -> Option<Root<WebGLVertexArrayObjectOES>> { + let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap(); + self.ctx.send_renderer_message(CanvasMsg::WebGL(WebGLCommand::CreateVertexArray(sender))); + + let result = receiver.recv().unwrap(); + result.map(|vao_id| WebGLVertexArrayObjectOES::new(&self.global(), vao_id)) + } + + // https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/ + fn DeleteVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>) { + if let Some(vao) = vao { + if vao.is_deleted() { + return; + } + + // Unbind deleted VAO if currently bound + if let Some(bound_vao) = self.bound_vao.get() { + if bound_vao.id() == vao.id() { + self.bound_vao.set(None); + self.ctx.send_renderer_message(CanvasMsg::WebGL(WebGLCommand::BindVertexArray(None))); + } + } + + // Remove VAO references from buffers + let buffers = vao.bound_attrib_buffers(); + for buffer in buffers { + buffer.remove_vao_reference(vao.id()); + } + if let Some(buffer) = vao.bound_buffer_element_array() { + buffer.remove_vao_reference(vao.id()); + } + + // Delete the vao + self.ctx.send_renderer_message(CanvasMsg::WebGL(WebGLCommand::DeleteVertexArray(vao.id()))); + vao.set_deleted(); + } + } + + // https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/ + fn IsVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>) -> bool { + // Conformance tests expect false if vao never bound + vao.map_or(false, |vao| !vao.is_deleted() && vao.ever_bound()) + } + + // https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/ + fn BindVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>) { + if let Some(bound_vao) = self.bound_vao.get() { + // Store buffers attached to attrib pointers + let buffers = self.ctx.borrow_bound_attrib_buffers(); + bound_vao.set_bound_attrib_buffers(buffers.iter().map(|(key, buffer)| { + (*buffer).add_vao_reference(bound_vao.id()); + (*key, &**buffer) + })); + // Store element array buffer + let element_array = self.ctx.bound_buffer_element_array(); + bound_vao.set_bound_buffer_element_array(element_array.as_ref().map(|buffer| { + buffer.add_vao_reference(bound_vao.id()); + &**buffer + })); + } + + if let Some(vao) = vao { + if vao.is_deleted() { + self.ctx.webgl_error(WebGLError::InvalidOperation); + return; + } + + self.ctx.send_renderer_message(CanvasMsg::WebGL(WebGLCommand::BindVertexArray(Some(vao.id())))); + vao.set_ever_bound(); + self.bound_vao.set(Some(&vao)); + + // Restore WebGLRenderingContext current bindings + let buffers = vao.borrow_bound_attrib_buffers(); + self.ctx.set_bound_attrib_buffers(buffers.iter().map(|(k, v)| (*k, &**v))); + let element_array = vao.bound_buffer_element_array(); + self.ctx.set_bound_buffer_element_array(element_array.as_ref().map(|buffer| &**buffer)); + } else { + self.ctx.send_renderer_message(CanvasMsg::WebGL(WebGLCommand::BindVertexArray(None))); + self.bound_vao.set(None); + self.ctx.set_bound_attrib_buffers(iter::empty()); + } + } +} + +impl WebGLExtension for OESVertexArrayObject { + type Extension = OESVertexArrayObject; + fn new(ctx: &WebGLRenderingContext) -> Root<OESVertexArrayObject> { + reflect_dom_object(box OESVertexArrayObject::new_inherited(ctx), + &*ctx.global(), + OESVertexArrayObjectBinding::Wrap) + } + + fn is_supported(ext: &WebGLExtensions) -> bool { + ext.supports_any_gl_extension(&["GL_OES_vertex_array_object", + "GL_ARB_vertex_array_object", + "GL_APPLE_vertex_array_object"]) + } + + fn enable(ext: &WebGLExtensions) { + let query = OESVertexArrayObjectConstants::VERTEX_ARRAY_BINDING_OES; + ext.add_query_parameter_handler(query, Box::new(|cx, webgl_ctx| { + match webgl_ctx.get_extension_manager().get_dom_object::<OESVertexArrayObject>() { + Some(dom_object) => { + Ok(dom_object.get_current_binding(cx)) + }, + None => { + // Extension instance not found! + Err(WebGLError::InvalidOperation) + } + } + })); + } + + fn name() -> &'static str { + "OES_vertex_array_object" + } +} diff --git a/components/script/dom/webgl_extensions/ext/webglvertexarrayobjectoes.rs b/components/script/dom/webgl_extensions/ext/webglvertexarrayobjectoes.rs new file mode 100644 index 00000000000..f15a797bf5a --- /dev/null +++ b/components/script/dom/webgl_extensions/ext/webglvertexarrayobjectoes.rs @@ -0,0 +1,87 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use core::cell::Ref; +use core::iter::FromIterator; +use dom::bindings::cell::DOMRefCell; +use dom::bindings::codegen::Bindings::WebGLVertexArrayObjectOESBinding; +use dom::bindings::js::{JS, MutNullableJS}; +use dom::bindings::js::Root; +use dom::bindings::reflector::reflect_dom_object; +use dom::globalscope::GlobalScope; +use dom::webglbuffer::WebGLBuffer; +use dom::webglobject::WebGLObject; +use dom_struct::dom_struct; +use std::cell::Cell; +use std::collections::HashMap; +use webrender_traits::WebGLVertexArrayId; + +#[dom_struct] +pub struct WebGLVertexArrayObjectOES { + webgl_object_: WebGLObject, + id: WebGLVertexArrayId, + ever_bound: Cell<bool>, + is_deleted: Cell<bool>, + bound_attrib_buffers: DOMRefCell<HashMap<u32, JS<WebGLBuffer>>>, + bound_buffer_element_array: MutNullableJS<WebGLBuffer>, +} + +impl WebGLVertexArrayObjectOES { + fn new_inherited(id: WebGLVertexArrayId) -> WebGLVertexArrayObjectOES { + Self { + webgl_object_: WebGLObject::new_inherited(), + id: id, + ever_bound: Cell::new(false), + is_deleted: Cell::new(false), + bound_attrib_buffers: DOMRefCell::new(HashMap::new()), + bound_buffer_element_array: MutNullableJS::new(None), + } + } + + pub fn new(global: &GlobalScope, id: WebGLVertexArrayId) -> Root<WebGLVertexArrayObjectOES> { + reflect_dom_object(box WebGLVertexArrayObjectOES::new_inherited(id), + global, + WebGLVertexArrayObjectOESBinding::Wrap) + } + + pub fn id(&self) -> WebGLVertexArrayId { + self.id + } + + pub fn is_deleted(&self) -> bool { + self.is_deleted.get() + } + + pub fn set_deleted(&self) { + self.is_deleted.set(true) + } + + pub fn ever_bound(&self) -> bool { + return self.ever_bound.get() + } + + pub fn set_ever_bound(&self) { + self.ever_bound.set(true); + } + + pub fn borrow_bound_attrib_buffers(&self) -> Ref<HashMap<u32, JS<WebGLBuffer>>> { + self.bound_attrib_buffers.borrow() + } + + pub fn bound_attrib_buffers(&self) -> Vec<Root<WebGLBuffer>> { + self.bound_attrib_buffers.borrow().iter().map(|(_, b)| Root::from_ref(&**b)).collect() + } + + pub fn set_bound_attrib_buffers<'a, T>(&self, iter: T) where T: Iterator<Item=(u32, &'a WebGLBuffer)> { + *self.bound_attrib_buffers.borrow_mut() = HashMap::from_iter(iter.map(|(k,v)| (k, JS::from_ref(v)))); + } + + pub fn bound_buffer_element_array(&self) -> Option<Root<WebGLBuffer>> { + self.bound_buffer_element_array.get() + } + + pub fn set_bound_buffer_element_array(&self, buffer: Option<&WebGLBuffer>) { + self.bound_buffer_element_array.set(buffer); + } +} diff --git a/components/script/dom/webgl_extensions/extension.rs b/components/script/dom/webgl_extensions/extension.rs new file mode 100644 index 00000000000..3463a1d3273 --- /dev/null +++ b/components/script/dom/webgl_extensions/extension.rs @@ -0,0 +1,26 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::js::Root; +use dom::bindings::reflector::DomObject; +use dom::bindings::trace::JSTraceable; +use dom::webglrenderingcontext::WebGLRenderingContext; +use super::WebGLExtensions; + +/// Trait implemented by WebGL extensions. +pub trait WebGLExtension: Sized where Self::Extension: DomObject + JSTraceable { + type Extension; + + /// Creates the DOM object of the WebGL extension. + fn new(ctx: &WebGLRenderingContext) -> Root<Self::Extension>; + + /// Checks if the extension is supported. + fn is_supported(ext: &WebGLExtensions) -> bool; + + /// Enable the extension. + fn enable(ext: &WebGLExtensions); + + /// Name of the WebGL Extension. + fn name() -> &'static str; +} diff --git a/components/script/dom/webgl_extensions/extensions.rs b/components/script/dom/webgl_extensions/extensions.rs new file mode 100644 index 00000000000..575597b84f3 --- /dev/null +++ b/components/script/dom/webgl_extensions/extensions.rs @@ -0,0 +1,197 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use core::iter::FromIterator; +use core::nonzero::NonZero; +use dom::bindings::cell::DOMRefCell; +use dom::bindings::codegen::Bindings::OESTextureHalfFloatBinding::OESTextureHalfFloatConstants; +use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; +use dom::bindings::js::Root; +use dom::bindings::trace::JSTraceable; +use dom::webglrenderingcontext::WebGLRenderingContext; +use gleam::gl::GLenum; +use heapsize::HeapSizeOf; +use js::jsapi::{JSContext, JSObject}; +use js::jsval::JSVal; +use ref_filter_map::ref_filter_map; +use std::cell::Ref; +use std::collections::{HashMap, HashSet}; +use super::{ext, WebGLExtension}; +use super::wrapper::{WebGLExtensionWrapper, TypedWebGLExtensionWrapper}; +use webrender_traits::WebGLError; + +// Data types that are implemented for texImage2D and texSubImage2D in WebGLRenderingContext +// but must trigger a InvalidValue error until the related WebGL Extensions are enabled. +// Example: https://www.khronos.org/registry/webgl/extensions/OES_texture_float/ +const DEFAULT_DISABLED_TEX_TYPES: [GLenum; 2] = [ + constants::FLOAT, OESTextureHalfFloatConstants::HALF_FLOAT_OES +]; + +// Data types that are implemented for textures in WebGLRenderingContext +// but not allowed to use with linear filtering until the related WebGL Extensions are enabled. +// Example: https://www.khronos.org/registry/webgl/extensions/OES_texture_float_linear/ +const DEFAULT_NOT_FILTERABLE_TEX_TYPES: [GLenum; 2] = [ + constants::FLOAT, OESTextureHalfFloatConstants::HALF_FLOAT_OES +]; + +/// WebGL features that are enabled/disabled by WebGL Extensions. +#[derive(JSTraceable, HeapSizeOf)] +struct WebGLExtensionFeatures { + gl_extensions: HashSet<String>, + disabled_tex_types: HashSet<GLenum>, + not_filterable_tex_types: HashSet<GLenum>, + effective_tex_internal_formats: HashMap<TexFormatType, u32>, + query_parameter_handlers: HashMap<GLenum, WebGLQueryParameterHandler> +} + +impl Default for WebGLExtensionFeatures { + fn default() -> WebGLExtensionFeatures { + WebGLExtensionFeatures { + gl_extensions: HashSet::new(), + disabled_tex_types: DEFAULT_DISABLED_TEX_TYPES.iter().cloned().collect(), + not_filterable_tex_types: DEFAULT_NOT_FILTERABLE_TEX_TYPES.iter().cloned().collect(), + effective_tex_internal_formats: HashMap::new(), + query_parameter_handlers: HashMap::new() + } + } +} + +/// Handles the list of implemented, supported and enabled WebGL extensions. +#[must_root] +#[derive(JSTraceable, HeapSizeOf)] +pub struct WebGLExtensions { + extensions: DOMRefCell<HashMap<String, Box<WebGLExtensionWrapper>>>, + features: DOMRefCell<WebGLExtensionFeatures>, +} + +impl WebGLExtensions { + pub fn new() -> WebGLExtensions { + Self { + extensions: DOMRefCell::new(HashMap::new()), + features: DOMRefCell::new(Default::default()) + } + } + + pub fn init_once<F>(&self, cb: F) where F: FnOnce() -> String { + if self.extensions.borrow().len() == 0 { + let gl_str = cb(); + self.features.borrow_mut().gl_extensions = HashSet::from_iter(gl_str.split(&[',', ' '][..]) + .map(|s| s.into())); + self.register_all_extensions(); + } + } + + pub fn register<T:'static + WebGLExtension + JSTraceable + HeapSizeOf>(&self) { + let name = T::name().to_uppercase(); + self.extensions.borrow_mut().insert(name, box TypedWebGLExtensionWrapper::<T>::new()); + } + + pub fn get_suported_extensions(&self) -> Vec<&'static str> { + self.extensions.borrow().iter() + .filter(|ref v| v.1.is_supported(&self)) + .map(|ref v| v.1.name()) + .collect() + } + + pub fn get_or_init_extension(&self, name: &str, ctx: &WebGLRenderingContext) -> Option<NonZero<*mut JSObject>> { + let name = name.to_uppercase(); + self.extensions.borrow().get(&name).and_then(|extension| { + if extension.is_supported(self) { + Some(extension.instance_or_init(ctx, self)) + } else { + None + } + }) + } + + pub fn get_dom_object<T>(&self) -> Option<Root<T::Extension>> + where T: 'static + WebGLExtension + JSTraceable + HeapSizeOf { + let name = T::name().to_uppercase(); + self.extensions.borrow().get(&name).and_then(|extension| { + extension.as_any().downcast_ref::<TypedWebGLExtensionWrapper<T>>().and_then(|extension| { + extension.dom_object() + }) + }) + } + + pub fn supports_gl_extension(&self, name: &str) -> bool { + self.features.borrow().gl_extensions.contains(name) + } + + pub fn supports_any_gl_extension(&self, names: &[&str]) -> bool { + let features = self.features.borrow(); + names.iter().any(|name| features.gl_extensions.contains(*name)) + } + + pub fn enable_tex_type(&self, data_type: GLenum) { + self.features.borrow_mut().disabled_tex_types.remove(&data_type); + } + + pub fn is_tex_type_enabled(&self, data_type: GLenum) -> bool { + self.features.borrow().disabled_tex_types.get(&data_type).is_none() + } + + pub fn add_effective_tex_internal_format(&self, + source_internal_format: u32, + source_data_type: u32, + effective_internal_format: u32) + { + let format = TexFormatType(source_internal_format, source_data_type); + self.features.borrow_mut().effective_tex_internal_formats.insert(format, + effective_internal_format); + + } + + pub fn get_effective_tex_internal_format(&self, + source_internal_format: u32, + source_data_type: u32) -> u32 { + let format = TexFormatType(source_internal_format, source_data_type); + *(self.features.borrow().effective_tex_internal_formats.get(&format) + .unwrap_or(&source_internal_format)) + } + + pub fn enable_filterable_tex_type(&self, text_data_type: GLenum) { + self.features.borrow_mut().not_filterable_tex_types.remove(&text_data_type); + } + + pub fn is_filterable(&self, text_data_type: u32) -> bool { + self.features.borrow().not_filterable_tex_types.get(&text_data_type).is_none() + } + + pub fn add_query_parameter_handler(&self, name: GLenum, f: Box<WebGLQueryParameterFunc>) { + let handler = WebGLQueryParameterHandler { + func: f + }; + self.features.borrow_mut().query_parameter_handlers.insert(name, handler); + } + + pub fn get_query_parameter_handler(&self, name: GLenum) -> Option<Ref<Box<WebGLQueryParameterFunc>>> { + ref_filter_map(self.features.borrow(), |features| { + features.query_parameter_handlers.get(&name).map(|item| &item.func) + }) + } + + fn register_all_extensions(&self) { + self.register::<ext::oestexturefloat::OESTextureFloat>(); + self.register::<ext::oestexturefloatlinear::OESTextureFloatLinear>(); + self.register::<ext::oestexturehalffloat::OESTextureHalfFloat>(); + self.register::<ext::oestexturehalffloatlinear::OESTextureHalfFloatLinear>(); + self.register::<ext::oesvertexarrayobject::OESVertexArrayObject>(); + } +} + +// Helper structs +#[derive(JSTraceable, HeapSizeOf, PartialEq, Eq, Hash)] +struct TexFormatType(u32, u32); + +type WebGLQueryParameterFunc = Fn(*mut JSContext, &WebGLRenderingContext) + -> Result<JSVal, WebGLError>; + +#[derive(HeapSizeOf)] +struct WebGLQueryParameterHandler { + #[ignore_heap_size_of = "Closures are hard"] + func: Box<WebGLQueryParameterFunc> +} + +unsafe_no_jsmanaged_fields!(WebGLQueryParameterHandler); diff --git a/components/script/dom/webgl_extensions/mod.rs b/components/script/dom/webgl_extensions/mod.rs new file mode 100644 index 00000000000..c9a468274a3 --- /dev/null +++ b/components/script/dom/webgl_extensions/mod.rs @@ -0,0 +1,25 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +pub mod ext; +mod extension; +mod extensions; +mod wrapper; + +// Some extra constants not exposed in WebGLRenderingContext constants +pub mod ext_constants { + pub const ALPHA16F_ARB: u32 = 0x881C; + pub const ALPHA32F_ARB: u32 = 0x8816; + pub const LUMINANCE16F_ARB: u32 = 0x881E; + pub const LUMINANCE32F_ARB: u32 = 0x8818; + pub const LUMINANCE_ALPHA16F_ARB: u32 = 0x881F; + pub const LUMINANCE_ALPHA32F_ARB: u32 = 0x8819; + pub const RGBA16F: u32 = 0x881A; + pub const RGB16F: u32 = 0x881B; + pub const RGBA32F: u32 = 0x8814; + pub const RGB32F: u32 = 0x8815; +} + +pub use self::extension::WebGLExtension; +pub use self::extensions::WebGLExtensions; diff --git a/components/script/dom/webgl_extensions/wrapper.rs b/components/script/dom/webgl_extensions/wrapper.rs new file mode 100644 index 00000000000..33fdd727529 --- /dev/null +++ b/components/script/dom/webgl_extensions/wrapper.rs @@ -0,0 +1,85 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use core::nonzero::NonZero; +use dom::bindings::js::{MutNullableJS, Root}; +use dom::bindings::reflector::DomObject; +use dom::bindings::trace::JSTraceable; +use dom::webglrenderingcontext::WebGLRenderingContext; +use heapsize::HeapSizeOf; +use js::jsapi::JSObject; +use std::any::Any; +use super::{WebGLExtension, WebGLExtensions}; + +/// Trait used internally by WebGLExtensions to store and +/// handle the different WebGL extensions in a common list. +pub trait WebGLExtensionWrapper: JSTraceable + HeapSizeOf { + fn instance_or_init(&self, + ctx: &WebGLRenderingContext, + ext: &WebGLExtensions) + -> NonZero<*mut JSObject>; + fn is_supported(&self, &WebGLExtensions) -> bool; + fn enable(&self, ext: &WebGLExtensions); + fn name(&self) -> &'static str; + fn as_any(&self) -> &Any; +} + +#[must_root] +#[derive(JSTraceable, HeapSizeOf)] +pub struct TypedWebGLExtensionWrapper<T: WebGLExtension> { + extension: MutNullableJS<T::Extension> +} + +/// Typed WebGL Extension implementation. +/// Exposes the exact MutNullableJS<DOMObject> type defined by the extension. +impl<T: WebGLExtension> TypedWebGLExtensionWrapper<T> { + pub fn new() -> TypedWebGLExtensionWrapper<T> { + TypedWebGLExtensionWrapper { + extension: MutNullableJS::new(None) + } + } +} + +impl<T> WebGLExtensionWrapper for TypedWebGLExtensionWrapper<T> + where T: WebGLExtension + JSTraceable + HeapSizeOf + 'static { + #[allow(unsafe_code)] + fn instance_or_init(&self, + ctx: &WebGLRenderingContext, + ext: &WebGLExtensions) + -> NonZero<*mut JSObject> { + let mut enabled = true; + let extension = self.extension.or_init(|| { + enabled = false; + T::new(ctx) + }); + if !enabled { + self.enable(ext); + } + unsafe { + NonZero::new(extension.reflector().get_jsobject().get()) + } + } + + fn is_supported(&self, ext: &WebGLExtensions) -> bool { + self.extension.get().is_some() || T::is_supported(ext) + } + + fn enable(&self, ext: &WebGLExtensions) { + T::enable(ext); + } + + fn name(&self) -> &'static str { + T::name() + } + + fn as_any<'a>(&'a self) -> &'a Any { + self + } +} + +impl<T> TypedWebGLExtensionWrapper<T> where T: WebGLExtension + JSTraceable + HeapSizeOf + 'static { + pub fn dom_object(&self) -> Option<Root<T::Extension>> { + self.extension.get() + } +} diff --git a/components/script/dom/webgl_validations/types.rs b/components/script/dom/webgl_validations/types.rs index f42eb548efd..3920866b0ea 100644 --- a/components/script/dom/webgl_validations/types.rs +++ b/components/script/dom/webgl_validations/types.rs @@ -2,24 +2,25 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use dom::bindings::codegen::Bindings::OESTextureHalfFloatBinding::OESTextureHalfFloatConstants; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; /// This macro creates type-safe wrappers for WebGL types, associating variants /// with gl constants. macro_rules! type_safe_wrapper { - ($name: ident, $($variant:ident => $constant:ident, )+) => { + ($name: ident, $($variant:ident => $mod:ident::$constant:ident, )+) => { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, JSTraceable, HeapSizeOf)] #[repr(u32)] pub enum $name { $( - $variant = constants::$constant, + $variant = $mod::$constant, )+ } impl $name { pub fn from_gl_constant(constant: u32) -> Option<Self> { Some(match constant { - $(constants::$constant => $name::$variant, )+ + $($mod::$constant => $name::$variant, )+ _ => return None, }) } @@ -33,13 +34,13 @@ macro_rules! type_safe_wrapper { } type_safe_wrapper! { TexImageTarget, - Texture2D => TEXTURE_2D, - CubeMapPositiveX => TEXTURE_CUBE_MAP_POSITIVE_X, - CubeMapNegativeX => TEXTURE_CUBE_MAP_NEGATIVE_X, - CubeMapPositiveY => TEXTURE_CUBE_MAP_POSITIVE_Y, - CubeMapNegativeY => TEXTURE_CUBE_MAP_NEGATIVE_Y, - CubeMapPositiveZ => TEXTURE_CUBE_MAP_POSITIVE_Z, - CubeMapNegativeZ => TEXTURE_CUBE_MAP_NEGATIVE_Z, + Texture2D => constants::TEXTURE_2D, + CubeMapPositiveX => constants::TEXTURE_CUBE_MAP_POSITIVE_X, + CubeMapNegativeX => constants::TEXTURE_CUBE_MAP_NEGATIVE_X, + CubeMapPositiveY => constants::TEXTURE_CUBE_MAP_POSITIVE_Y, + CubeMapNegativeY => constants::TEXTURE_CUBE_MAP_NEGATIVE_Y, + CubeMapPositiveZ => constants::TEXTURE_CUBE_MAP_POSITIVE_Z, + CubeMapNegativeZ => constants::TEXTURE_CUBE_MAP_NEGATIVE_Z, } impl TexImageTarget { @@ -52,10 +53,12 @@ impl TexImageTarget { } type_safe_wrapper! { TexDataType, - UnsignedByte => UNSIGNED_BYTE, - UnsignedShort4444 => UNSIGNED_SHORT_4_4_4_4, - UnsignedShort5551 => UNSIGNED_SHORT_5_5_5_1, - UnsignedShort565 => UNSIGNED_SHORT_5_6_5, + UnsignedByte => constants::UNSIGNED_BYTE, + UnsignedShort4444 => constants::UNSIGNED_SHORT_4_4_4_4, + UnsignedShort5551 => constants::UNSIGNED_SHORT_5_5_5_1, + UnsignedShort565 => constants::UNSIGNED_SHORT_5_6_5, + Float => constants::FLOAT, + HalfFloat => OESTextureHalfFloatConstants::HALF_FLOAT_OES, } impl TexDataType { @@ -67,6 +70,8 @@ impl TexDataType { UnsignedShort4444 | UnsignedShort5551 | UnsignedShort565 => 2, + Float => 4, + HalfFloat => 2, } } @@ -79,17 +84,19 @@ impl TexDataType { UnsignedShort565 => 3, UnsignedShort5551 => 4, UnsignedShort4444 => 4, + Float => 1, + HalfFloat => 1, } } } type_safe_wrapper! { TexFormat, - DepthComponent => DEPTH_COMPONENT, - Alpha => ALPHA, - RGB => RGB, - RGBA => RGBA, - Luminance => LUMINANCE, - LuminanceAlpha => LUMINANCE_ALPHA, + DepthComponent => constants::DEPTH_COMPONENT, + Alpha => constants::ALPHA, + RGB => constants::RGB, + RGBA => constants::RGBA, + Luminance => constants::LUMINANCE, + LuminanceAlpha => constants::LUMINANCE_ALPHA, } impl TexFormat { diff --git a/components/script/dom/webglbuffer.rs b/components/script/dom/webglbuffer.rs index 6678b3d0b92..13598135176 100644 --- a/components/script/dom/webglbuffer.rs +++ b/components/script/dom/webglbuffer.rs @@ -4,6 +4,7 @@ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl use canvas_traits::CanvasMsg; +use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::WebGLBufferBinding; use dom::bindings::js::Root; use dom::bindings::reflector::reflect_dom_object; @@ -12,8 +13,9 @@ use dom::window::Window; use dom_struct::dom_struct; use ipc_channel::ipc::IpcSender; use std::cell::Cell; +use std::collections::HashSet; use webrender_traits; -use webrender_traits::{WebGLBufferId, WebGLCommand, WebGLError, WebGLResult}; +use webrender_traits::{WebGLBufferId, WebGLCommand, WebGLError, WebGLResult, WebGLVertexArrayId}; #[dom_struct] pub struct WebGLBuffer { @@ -23,6 +25,9 @@ pub struct WebGLBuffer { target: Cell<Option<u32>>, capacity: Cell<usize>, is_deleted: Cell<bool>, + // The Vertex Array Objects that are referencing this buffer + vao_references: DOMRefCell<Option<HashSet<WebGLVertexArrayId>>>, + pending_delete: Cell<bool>, #[ignore_heap_size_of = "Defined in ipc-channel"] renderer: IpcSender<CanvasMsg>, } @@ -37,6 +42,8 @@ impl WebGLBuffer { target: Cell::new(None), capacity: Cell::new(0), is_deleted: Cell::new(false), + vao_references: DOMRefCell::new(None), + pending_delete: Cell::new(false), renderer: renderer, } } @@ -112,6 +119,36 @@ impl WebGLBuffer { pub fn target(&self) -> Option<u32> { self.target.get() } + + pub fn is_attached_to_vao(&self) -> bool { + self.vao_references.borrow().as_ref().map_or(false, |vaos| !vaos.is_empty()) + } + + pub fn set_pending_delete(&self) { + self.pending_delete.set(true); + } + + pub fn add_vao_reference(&self, id: WebGLVertexArrayId) { + let mut vao_refs = self.vao_references.borrow_mut(); + if let Some(ref mut vao_refs) = *vao_refs { + vao_refs.insert(id); + return; + } + + let mut map = HashSet::new(); + map.insert(id); + *vao_refs = Some(map); + } + + pub fn remove_vao_reference(&self, id: WebGLVertexArrayId) { + if let Some(ref mut vao_refs) = *self.vao_references.borrow_mut() { + if vao_refs.take(&id).is_some() && self.pending_delete.get() { + // WebGL spec: The deleted buffers should no longer be valid when the VAOs are deleted + let _ = self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DeleteBuffer(self.id))); + self.is_deleted.set(true); + } + } + } } impl Drop for WebGLBuffer { diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 1826a877331..9b144f91572 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -4,7 +4,10 @@ use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; use canvas_traits::{CanvasCommonMsg, CanvasMsg, byte_swap, multiply_u8_pixel}; +use core::cell::Ref; +use core::iter::FromIterator; use core::nonzero::NonZero; +use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{self, WebGLContextAttributes}; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods; @@ -20,6 +23,7 @@ use dom::globalscope::GlobalScope; use dom::htmlcanvaselement::HTMLCanvasElement; use dom::htmlcanvaselement::utils as canvas_utils; use dom::node::{Node, NodeDamage, window_from_node}; +use dom::webgl_extensions::WebGLExtensions; use dom::webgl_validations::WebGLValidator; use dom::webgl_validations::tex_image_2d::{CommonTexImage2DValidator, CommonTexImage2DValidatorResult}; use dom::webgl_validations::tex_image_2d::{TexImage2DValidator, TexImage2DValidatorResult}; @@ -37,6 +41,7 @@ use dom::webgluniformlocation::WebGLUniformLocation; use dom::window::Window; use dom_struct::dom_struct; use euclid::size::Size2D; +use half::f16; use ipc_channel::ipc::{self, IpcSender}; use js::conversions::ConversionBehavior; use js::jsapi::{JSContext, JSObject, Type, Rooted}; @@ -47,6 +52,7 @@ use net_traits::image_cache::ImageResponse; use offscreen_gl_context::{GLContextAttributes, GLLimits}; use script_traits::ScriptMsg as ConstellationMsg; use std::cell::Cell; +use std::collections::HashMap; use webrender_traits; use webrender_traits::{WebGLCommand, WebGLError, WebGLFramebufferBindingRequest, WebGLParameter}; use webrender_traits::WebGLError::*; @@ -143,6 +149,7 @@ pub struct WebGLRenderingContext { bound_texture_cube_map: MutNullableJS<WebGLTexture>, bound_buffer_array: MutNullableJS<WebGLBuffer>, bound_buffer_element_array: MutNullableJS<WebGLBuffer>, + bound_attrib_buffers: DOMRefCell<HashMap<u32, JS<WebGLBuffer>>>, current_program: MutNullableJS<WebGLProgram>, #[ignore_heap_size_of = "Because it's small"] current_vertex_attrib_0: Cell<(f32, f32, f32, f32)>, @@ -150,6 +157,7 @@ pub struct WebGLRenderingContext { current_scissor: Cell<(i32, i32, i32, i32)>, #[ignore_heap_size_of = "Because it's small"] current_clear_color: Cell<(f32, f32, f32, f32)>, + extension_manager: WebGLExtensions } impl WebGLRenderingContext { @@ -178,11 +186,13 @@ impl WebGLRenderingContext { bound_texture_cube_map: MutNullableJS::new(None), bound_buffer_array: MutNullableJS::new(None), bound_buffer_element_array: MutNullableJS::new(None), + bound_attrib_buffers: DOMRefCell::new(HashMap::new()), bound_renderbuffer: MutNullableJS::new(None), current_program: MutNullableJS::new(None), current_vertex_attrib_0: Cell::new((0f32, 0f32, 0f32, 1f32)), current_scissor: Cell::new((0, 0, size.width, size.height)), - current_clear_color: Cell::new((0.0, 0.0, 0.0, 0.0)) + current_clear_color: Cell::new((0.0, 0.0, 0.0, 0.0)), + extension_manager: WebGLExtensions::new() } }) } @@ -221,6 +231,22 @@ impl WebGLRenderingContext { } } + pub fn borrow_bound_attrib_buffers(&self) -> Ref<HashMap<u32, JS<WebGLBuffer>>> { + self.bound_attrib_buffers.borrow() + } + + pub fn set_bound_attrib_buffers<'a, T>(&self, iter: T) where T: Iterator<Item=(u32, &'a WebGLBuffer)> { + *self.bound_attrib_buffers.borrow_mut() = HashMap::from_iter(iter.map(|(k,v)| (k, JS::from_ref(v)))); + } + + pub fn bound_buffer_element_array(&self) -> Option<Root<WebGLBuffer>> { + self.bound_buffer_element_array.get() + } + + pub fn set_bound_buffer_element_array(&self, buffer: Option<&WebGLBuffer>) { + self.bound_buffer_element_array.set(buffer); + } + pub fn recreate(&self, size: Size2D<i32>) { self.ipc_renderer.send(CanvasMsg::Common(CanvasCommonMsg::Recreate(size))).unwrap(); @@ -245,6 +271,14 @@ impl WebGLRenderingContext { self.ipc_renderer.clone() } + pub fn send_renderer_message(&self, msg: CanvasMsg) { + self.ipc_renderer.send(msg).unwrap(); + } + + pub fn get_extension_manager<'a>(&'a self) -> &'a WebGLExtensions { + &self.extension_manager + } + pub fn webgl_error(&self, err: WebGLError) { // TODO(emilio): Add useful debug messages to this warn!("WebGL error: {:?}, previous error was {:?}", err, self.last_error.get()); @@ -296,6 +330,23 @@ impl WebGLRenderingContext { }; if let Some(texture) = texture { handle_potential_webgl_error!(self, texture.tex_parameter(target, name, value)); + + // Validate non filterable TEXTURE_2D data_types + if target != constants::TEXTURE_2D { + return; + } + + let target = TexImageTarget::Texture2D; + let info = texture.image_info_for_target(&target, 0); + if info.is_initialized() { + self.validate_filterable_texture(&texture, + target, + 0, + info.internal_format().unwrap_or(TexFormat::RGBA), + info.width(), + info.height(), + info.data_type().unwrap_or(TexDataType::UnsignedByte)); + } } else { self.webgl_error(InvalidOperation) } @@ -329,6 +380,37 @@ impl WebGLRenderingContext { } } + // LINEAR filtering may be forbidden when using WebGL extensions. + // https://www.khronos.org/registry/webgl/extensions/OES_texture_float_linear/ + fn validate_filterable_texture(&self, + texture: &WebGLTexture, + target: TexImageTarget, + level: u32, + format: TexFormat, + width: u32, + height: u32, + data_type: TexDataType) + -> bool + { + if self.extension_manager.is_filterable(data_type.as_gl_constant()) || !texture.is_using_linear_filtering() { + return true; + } + + // Handle validation failed: LINEAR filtering not valid for this texture + // WebGL Conformance tests expect to fallback to [0, 0, 0, 255] RGBA UNSIGNED_BYTE + let data_type = TexDataType::UnsignedByte; + let expected_byte_length = width * height * 4; + let mut pixels = vec![0u8; expected_byte_length as usize]; + for rgba8 in pixels.chunks_mut(4) { + rgba8[3] = 255u8; + } + + let pixels = self.prepare_pixels(format, data_type, width, height, 1, true, true, pixels); + self.tex_image_2d(texture, target, data_type, format, level, width, height, 0, 1, pixels); + + false + } + fn validate_stencil_actions(&self, action: u32) -> bool { match action { 0 | constants::KEEP | constants::REPLACE | constants::INCR | constants::DECR | @@ -369,6 +451,14 @@ impl WebGLRenderingContext { true } + // https://en.wikipedia.org/wiki/Relative_luminance + #[inline] + fn luminance(r: u8, g: u8, b: u8) -> u8 { + (0.2126 * (r as f32) + + 0.7152 * (g as f32) + + 0.0722 * (b as f32)) as u8 + } + /// Translates an image in rgba8 (red in the first byte) format to /// the format that was requested of TexImage. /// @@ -391,7 +481,6 @@ impl WebGLRenderingContext { (TexFormat::RGBA, TexDataType::UnsignedByte) => pixels, (TexFormat::RGB, TexDataType::UnsignedByte) => { // Remove alpha channel - let pixel_count = pixels.len() / 4; let mut rgb8 = Vec::<u8>::with_capacity(pixel_count * 3); for rgba8 in pixels.chunks(4) { rgb8.push(rgba8[0]); @@ -400,6 +489,32 @@ impl WebGLRenderingContext { } rgb8 }, + + (TexFormat::Alpha, TexDataType::UnsignedByte) => { + let mut alpha = Vec::<u8>::with_capacity(pixel_count); + for rgba8 in pixels.chunks(4) { + alpha.push(rgba8[3]); + } + alpha + }, + + (TexFormat::Luminance, TexDataType::UnsignedByte) => { + let mut luminance = Vec::<u8>::with_capacity(pixel_count); + for rgba8 in pixels.chunks(4) { + luminance.push(Self::luminance(rgba8[0], rgba8[1], rgba8[2])); + } + luminance + }, + + (TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => { + let mut data = Vec::<u8>::with_capacity(pixel_count * 2); + for rgba8 in pixels.chunks(4) { + data.push(Self::luminance(rgba8[0], rgba8[1], rgba8[2])); + data.push(rgba8[3]); + } + data + }, + (TexFormat::RGBA, TexDataType::UnsignedShort4444) => { let mut rgba4 = Vec::<u8>::with_capacity(pixel_count * 2); for rgba8 in pixels.chunks(4) { @@ -432,10 +547,107 @@ impl WebGLRenderingContext { rgb565 } + + (TexFormat::RGBA, TexDataType::Float) => { + let mut rgbaf32 = Vec::<u8>::with_capacity(pixel_count * 16); + for rgba8 in pixels.chunks(4) { + rgbaf32.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap(); + rgbaf32.write_f32::<NativeEndian>(rgba8[1] as f32).unwrap(); + rgbaf32.write_f32::<NativeEndian>(rgba8[2] as f32).unwrap(); + rgbaf32.write_f32::<NativeEndian>(rgba8[3] as f32).unwrap(); + } + rgbaf32 + } + + (TexFormat::RGB, TexDataType::Float) => { + let mut rgbf32 = Vec::<u8>::with_capacity(pixel_count * 12); + for rgba8 in pixels.chunks(4) { + rgbf32.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap(); + rgbf32.write_f32::<NativeEndian>(rgba8[1] as f32).unwrap(); + rgbf32.write_f32::<NativeEndian>(rgba8[2] as f32).unwrap(); + } + rgbf32 + } + + (TexFormat::Alpha, TexDataType::Float) => { + let mut alpha = Vec::<u8>::with_capacity(pixel_count * 4); + for rgba8 in pixels.chunks(4) { + alpha.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap(); + } + alpha + }, + + (TexFormat::Luminance, TexDataType::Float) => { + let mut luminance = Vec::<u8>::with_capacity(pixel_count * 4); + for rgba8 in pixels.chunks(4) { + let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]); + luminance.write_f32::<NativeEndian>(p as f32).unwrap(); + } + luminance + }, + + (TexFormat::LuminanceAlpha, TexDataType::Float) => { + let mut data = Vec::<u8>::with_capacity(pixel_count * 8); + for rgba8 in pixels.chunks(4) { + let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]); + data.write_f32::<NativeEndian>(p as f32).unwrap(); + data.write_f32::<NativeEndian>(rgba8[3] as f32).unwrap(); + } + data + }, + + (TexFormat::RGBA, TexDataType::HalfFloat) => { + let mut rgbaf16 = Vec::<u8>::with_capacity(pixel_count * 8); + for rgba8 in pixels.chunks(4) { + rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[0] as f32).as_bits()).unwrap(); + rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[1] as f32).as_bits()).unwrap(); + rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[2] as f32).as_bits()).unwrap(); + rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()).unwrap(); + } + rgbaf16 + }, + + (TexFormat::RGB, TexDataType::HalfFloat) => { + let mut rgbf16 = Vec::<u8>::with_capacity(pixel_count * 6); + for rgba8 in pixels.chunks(4) { + rgbf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[0] as f32).as_bits()).unwrap(); + rgbf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[1] as f32).as_bits()).unwrap(); + rgbf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[2] as f32).as_bits()).unwrap(); + } + rgbf16 + }, + + (TexFormat::Alpha, TexDataType::HalfFloat) => { + let mut alpha = Vec::<u8>::with_capacity(pixel_count * 2); + for rgba8 in pixels.chunks(4) { + alpha.write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()).unwrap(); + } + alpha + }, + + (TexFormat::Luminance, TexDataType::HalfFloat) => { + let mut luminance = Vec::<u8>::with_capacity(pixel_count * 4); + for rgba8 in pixels.chunks(4) { + let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]); + luminance.write_u16::<NativeEndian>(f16::from_f32(p as f32).as_bits()).unwrap(); + } + luminance + }, + + (TexFormat::LuminanceAlpha, TexDataType::HalfFloat) => { + let mut data = Vec::<u8>::with_capacity(pixel_count * 8); + for rgba8 in pixels.chunks(4) { + let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]); + data.write_u16::<NativeEndian>(f16::from_f32(p as f32).as_bits()).unwrap(); + data.write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()).unwrap(); + } + data + }, + // Validation should have ensured that we only hit the // above cases, but we haven't turned the (format, type) // into an enum yet so there's a default case here. - _ => unreachable!() + _ => unreachable!("Unsupported formats {:?} {:?}", format, data_type) } } @@ -522,9 +734,11 @@ impl WebGLRenderingContext { // If it is UNSIGNED_BYTE, a Uint8Array must be supplied; // if it is UNSIGNED_SHORT_5_6_5, UNSIGNED_SHORT_4_4_4_4, // or UNSIGNED_SHORT_5_5_5_1, a Uint16Array must be supplied. + // or FLOAT, a Float32Array must be supplied. // If the types do not match, an INVALID_OPERATION error is generated. typedarray!(in(cx) let typedarray_u8: Uint8Array = data); typedarray!(in(cx) let typedarray_u16: Uint16Array = data); + typedarray!(in(cx) let typedarray_f32: Float32Array = data); let received_size = if data.is_null() { element_size } else { @@ -532,6 +746,8 @@ impl WebGLRenderingContext { 2 } else if typedarray_u8.is_ok() { 1 + } else if typedarray_f32.is_ok() { + 4 } else { self.webgl_error(InvalidOperation); return Err(()); @@ -700,7 +916,7 @@ impl WebGLRenderingContext { } fn tex_image_2d(&self, - texture: Root<WebGLTexture>, + texture: &WebGLTexture, target: TexImageTarget, data_type: TexDataType, internal_format: TexFormat, @@ -728,12 +944,17 @@ impl WebGLRenderingContext { .send(CanvasMsg::WebGL(WebGLCommand::PixelStorei(constants::UNPACK_ALIGNMENT, unpacking_alignment as i32))) .unwrap(); + let format = internal_format.as_gl_constant(); + let data_type = data_type.as_gl_constant(); + let internal_format = self.extension_manager.get_effective_tex_internal_format(format, data_type); + // TODO(emilio): convert colorspace if requested let msg = WebGLCommand::TexImage2D(target.as_gl_constant(), level as i32, - internal_format.as_gl_constant() as i32, + internal_format as i32, width as i32, height as i32, - internal_format.as_gl_constant(), - data_type.as_gl_constant(), pixels); + format, + data_type, + pixels); self.ipc_renderer .send(CanvasMsg::WebGL(msg)) @@ -807,6 +1028,14 @@ impl WebGLRenderingContext { }, } } + + fn get_gl_extensions(&self) -> String { + let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap(); + self.ipc_renderer + .send(CanvasMsg::WebGL(WebGLCommand::GetExtensions(sender))) + .unwrap(); + receiver.recv().unwrap() + } } impl Drop for WebGLRenderingContext { @@ -958,6 +1187,19 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { _ => {} } + // Handle GetParameter getters injected via WebGL extensions + if let Some(query_handler) = self.extension_manager.get_query_parameter_handler(parameter) { + match query_handler(cx, &self) { + Ok(value) => { + return value; + }, + Err(error) => { + self.webgl_error(error); + return NullValue(); + } + } + } + let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap(); self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::GetParameter(parameter, sender))) @@ -1019,14 +1261,21 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.14 fn GetSupportedExtensions(&self) -> Option<Vec<DOMString>> { - Some(vec![]) + self.extension_manager.init_once(|| { + self.get_gl_extensions() + }); + let extensions = self.extension_manager.get_suported_extensions(); + Some(extensions.iter().map(|name| DOMString::from(*name)).collect()) } #[allow(unsafe_code)] // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.14 - unsafe fn GetExtension(&self, _cx: *mut JSContext, _name: DOMString) + unsafe fn GetExtension(&self, _cx: *mut JSContext, name: DOMString) -> Option<NonZero<*mut JSObject>> { - None + self.extension_manager.init_once(|| { + self.get_gl_extensions() + }); + self.extension_manager.get_or_init_extension(&name, self) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 @@ -1627,6 +1876,23 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 fn DeleteBuffer(&self, buffer: Option<&WebGLBuffer>) { if let Some(buffer) = buffer { + if buffer.is_attached_to_vao() { + // WebGL spec: The buffers attached to VAOs should still not be deleted. + // They are deleted after the VAO is deleted. + buffer.set_pending_delete(); + return; + } + + // Remove deleted buffer from bound attrib buffers. + let attrib_ids: Vec<_> = self.bound_attrib_buffers.borrow().iter() + .filter(|&(_, v)| v.id() == buffer.id()) + .map(|(&k, _)| k) + .collect(); + for id in attrib_ids { + self.bound_attrib_buffers.borrow_mut().remove(&id); + } + + // Delete buffer. handle_object_deletion!(self, self.bound_buffer_array, buffer, Some(WebGLCommand::BindBuffer(constants::ARRAY_BUFFER, None))); handle_object_deletion!(self, self.bound_buffer_element_array, buffer, @@ -1989,6 +2255,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return result.get() } + if pname == constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING { + rooted!(in(cx) let mut jsval = NullValue()); + if let Some(buffer) = self.bound_attrib_buffers.borrow().get(&index) { + buffer.to_jsval(cx, jsval.handle_mut()); + } + return jsval.get(); + } + let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap(); self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::GetVertexAttrib(index, pname, sender))).unwrap(); @@ -2006,6 +2280,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } } + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 + fn GetVertexAttribOffset(&self, index: u32, pname: u32) -> i64 { + let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap(); + self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::GetVertexAttribOffset(index, pname, sender))).unwrap(); + + handle_potential_webgl_error!(self, receiver.recv().unwrap(), 0) as i64 + } + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn Hint(&self, target: u32, mode: u32) { if target != constants::GENERATE_MIPMAP_HINT { @@ -2784,9 +3066,13 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if size < 1 || size > 4 { return self.webgl_error(InvalidValue); } - if self.bound_buffer_array.get().is_none() { - return self.webgl_error(InvalidOperation); - } + + let buffer_array = match self.bound_buffer_array.get() { + Some(buffer) => buffer, + None => { + return self.webgl_error(InvalidOperation); + } + }; // stride and offset must be multiple of data_type match data_type { @@ -2805,6 +3091,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } + self.bound_attrib_buffers.borrow_mut().insert(attrib_id, JS::from_ref(&*buffer_array)); + let msg = CanvasMsg::WebGL( WebGLCommand::VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset as u32)); self.ipc_renderer.send(msg).unwrap() @@ -2834,6 +3122,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { format: u32, data_type: u32, data_ptr: *mut JSObject) -> Fallible<()> { + if !self.extension_manager.is_tex_type_enabled(data_type) { + return Ok(self.webgl_error(InvalidEnum)); + } + let data = if data_ptr.is_null() { None } else { @@ -2885,10 +3177,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return Ok(self.webgl_error(InvalidOperation)); } + if !self.validate_filterable_texture(&texture, target, level, format, width, height, data_type) { + return Ok(()); // The validator sets the correct error for use + } + let pixels = self.prepare_pixels(format, data_type, width, height, unpacking_alignment, false, false, buff); - self.tex_image_2d(texture, target, data_type, format, + self.tex_image_2d(&texture, target, data_type, format, level, width, height, border, unpacking_alignment, pixels); Ok(()) @@ -2902,6 +3198,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { format: u32, data_type: u32, source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement>) -> Fallible<()> { + if !self.extension_manager.is_tex_type_enabled(data_type) { + return Ok(self.webgl_error(InvalidEnum)); + } + // Get pixels from image source let (pixels, size, premultiplied) = match self.get_image_pixels(source) { Ok((pixels, size, premultiplied)) => (pixels, size, premultiplied), @@ -2927,11 +3227,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { Err(_) => return Ok(()), // NB: The validator sets the correct error for us. }; + if !self.validate_filterable_texture(&texture, target, level, format, width, height, data_type) { + return Ok(()); // The validator sets the correct error for use + } + let unpacking_alignment = 1; let pixels = self.prepare_pixels(format, data_type, width, height, unpacking_alignment, premultiplied, true, pixels); - self.tex_image_2d(texture, target, data_type, format, + self.tex_image_2d(&texture, target, data_type, format, level, width, height, border, 1, pixels); Ok(()) } @@ -2955,7 +3259,6 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { Some(try!(fallible_array_buffer_view_to_vec(cx, data_ptr))) }; - let validator = TexImage2DValidator::new(self, target, level, format, width, height, 0, format, data_type); diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs index d88f955a862..184a9c39131 100644 --- a/components/script/dom/webgltexture.rs +++ b/components/script/dom/webgltexture.rs @@ -42,6 +42,9 @@ pub struct WebGLTexture { /// Face count can only be 1 or 6 face_count: Cell<u8>, base_mipmap_level: u32, + // Store information for min and mag filters + min_filter: Cell<Option<u32>>, + mag_filter: Cell<Option<u32>>, #[ignore_heap_size_of = "Defined in ipc-channel"] renderer: IpcSender<CanvasMsg>, } @@ -57,6 +60,8 @@ impl WebGLTexture { is_deleted: Cell::new(false), face_count: Cell::new(0), base_mipmap_level: 0, + min_filter: Cell::new(None), + mag_filter: Cell::new(None), image_info_array: DOMRefCell::new([ImageInfo::new(); MAX_LEVEL_COUNT * MAX_FACE_COUNT]), renderer: renderer, } @@ -209,6 +214,7 @@ impl WebGLTexture { constants::LINEAR_MIPMAP_NEAREST | constants::NEAREST_MIPMAP_LINEAR | constants::LINEAR_MIPMAP_LINEAR => { + self.min_filter.set(Some(int_value as u32)); self.renderer .send(CanvasMsg::WebGL(WebGLCommand::TexParameteri(target, name, int_value))) .unwrap(); @@ -222,6 +228,7 @@ impl WebGLTexture { match int_value as u32 { constants::NEAREST | constants::LINEAR => { + self.mag_filter.set(Some(int_value as u32)); self.renderer .send(CanvasMsg::WebGL(WebGLCommand::TexParameteri(target, name, int_value))) .unwrap(); @@ -251,6 +258,19 @@ impl WebGLTexture { } } + pub fn is_using_linear_filtering(&self) -> bool { + let filters = [self.min_filter.get(), self.mag_filter.get()]; + filters.iter().any(|filter| { + match *filter { + Some(constants::LINEAR) | + Some(constants::NEAREST_MIPMAP_LINEAR) | + Some(constants::LINEAR_MIPMAP_NEAREST) | + Some(constants::LINEAR_MIPMAP_LINEAR) => true, + _=> false + } + }) + } + pub fn populate_mip_chain(&self, first_level: u32, last_level: u32) -> WebGLResult<()> { let base_image_info = self.image_info_at_face(0, first_level); if !base_image_info.is_initialized() { @@ -408,7 +428,7 @@ impl ImageInfo { self.depth.is_power_of_two() } - fn is_initialized(&self) -> bool { + pub fn is_initialized(&self) -> bool { self.is_initialized } diff --git a/components/script/dom/webidls/OESTextureFloat.webidl b/components/script/dom/webidls/OESTextureFloat.webidl new file mode 100644 index 00000000000..518bd8f9050 --- /dev/null +++ b/components/script/dom/webidls/OESTextureFloat.webidl @@ -0,0 +1,11 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ +/* + * WebGL IDL definitions from the Khronos specification: + * https://www.khronos.org/registry/webgl/extensions/OES_texture_float/ + */ + +[NoInterfaceObject] +interface OESTextureFloat { +}; diff --git a/components/script/dom/webidls/OESTextureFloatLinear.webidl b/components/script/dom/webidls/OESTextureFloatLinear.webidl new file mode 100644 index 00000000000..3ac2e2758f4 --- /dev/null +++ b/components/script/dom/webidls/OESTextureFloatLinear.webidl @@ -0,0 +1,11 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ +/* + * WebGL IDL definitions from the Khronos specification: + * https://www.khronos.org/registry/webgl/extensions/OES_texture_float_linear/ + */ + +[NoInterfaceObject] +interface OESTextureFloatLinear { +}; diff --git a/components/script/dom/webidls/OESTextureHalfFloat.webidl b/components/script/dom/webidls/OESTextureHalfFloat.webidl new file mode 100644 index 00000000000..802d87d2b82 --- /dev/null +++ b/components/script/dom/webidls/OESTextureHalfFloat.webidl @@ -0,0 +1,12 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ +/* + * WebGL IDL definitions from the Khronos specification: + * https://www.khronos.org/registry/webgl/extensions/OES_texture_half_float/ + */ + +[NoInterfaceObject] +interface OESTextureHalfFloat { + const GLenum HALF_FLOAT_OES = 0x8D61; +}; diff --git a/components/script/dom/webidls/OESTextureHalfFloatLinear.webidl b/components/script/dom/webidls/OESTextureHalfFloatLinear.webidl new file mode 100644 index 00000000000..3a7826ad824 --- /dev/null +++ b/components/script/dom/webidls/OESTextureHalfFloatLinear.webidl @@ -0,0 +1,11 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ +/* + * WebGL IDL definitions from the Khronos specification: + * https://www.khronos.org/registry/webgl/extensions/OES_texture_half_float_linear/ + */ + +[NoInterfaceObject] +interface OESTextureHalfFloatLinear { +}; diff --git a/components/script/dom/webidls/OESVertexArrayObject.webidl b/components/script/dom/webidls/OESVertexArrayObject.webidl new file mode 100644 index 00000000000..cb73c57d558 --- /dev/null +++ b/components/script/dom/webidls/OESVertexArrayObject.webidl @@ -0,0 +1,17 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ +/* + * WebGL IDL definitions from the Khronos specification: + * https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/ + */ + +[NoInterfaceObject] +interface OESVertexArrayObject { + const unsigned long VERTEX_ARRAY_BINDING_OES = 0x85B5; + + WebGLVertexArrayObjectOES? createVertexArrayOES(); + void deleteVertexArrayOES(WebGLVertexArrayObjectOES? arrayObject); + boolean isVertexArrayOES(WebGLVertexArrayObjectOES? arrayObject); + void bindVertexArrayOES(WebGLVertexArrayObjectOES? arrayObject); +}; diff --git a/components/script/dom/webidls/WebGLRenderingContext.webidl b/components/script/dom/webidls/WebGLRenderingContext.webidl index 0d4c14a05df..885ad9486bb 100644 --- a/components/script/dom/webidls/WebGLRenderingContext.webidl +++ b/components/script/dom/webidls/WebGLRenderingContext.webidl @@ -608,7 +608,7 @@ interface WebGLRenderingContextBase any getVertexAttrib(GLuint index, GLenum pname); - //[WebGLHandlesContextLoss] GLsizeiptr getVertexAttribOffset(GLuint index, GLenum pname); + [WebGLHandlesContextLoss] GLsizeiptr getVertexAttribOffset(GLuint index, GLenum pname); void hint(GLenum target, GLenum mode); [WebGLHandlesContextLoss] GLboolean isBuffer(WebGLBuffer? buffer); diff --git a/components/script/dom/webidls/WebGLVertexArrayObjectOES.webidl b/components/script/dom/webidls/WebGLVertexArrayObjectOES.webidl new file mode 100644 index 00000000000..9355cf4004e --- /dev/null +++ b/components/script/dom/webidls/WebGLVertexArrayObjectOES.webidl @@ -0,0 +1,11 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ +/* + * WebGL IDL definitions scraped from the Khronos specification: + * https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/ + */ + +[NoInterfaceObject] +interface WebGLVertexArrayObjectOES: WebGLObject { +}; diff --git a/components/script/lib.rs b/components/script/lib.rs index 703209604b0..6e0b75d7ef9 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -48,6 +48,8 @@ extern crate encoding; extern crate euclid; extern crate fnv; extern crate gfx_traits; +extern crate gleam; +extern crate half; #[macro_use] extern crate heapsize; #[macro_use] extern crate heapsize_derive; #[macro_use] extern crate html5ever; diff --git a/python/tidy/servo_tidy/tidy.py b/python/tidy/servo_tidy/tidy.py index b8229e67d96..2e19a18e4e4 100644 --- a/python/tidy/servo_tidy/tidy.py +++ b/python/tidy/servo_tidy/tidy.py @@ -58,6 +58,7 @@ FILE_PATTERNS_TO_IGNORE = ["*.#*", "*.pyc", "fake-ld.sh"] SPEC_BASE_PATH = "components/script/dom/" WEBIDL_STANDARDS = [ + "//www.khronos.org/registry/webgl/extensions", "//www.khronos.org/registry/webgl/specs", "//developer.mozilla.org/en-US/docs/Web/API", "//dev.w3.org/2006/webapi", diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/context/methods.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/context/methods.html.ini index 798eb1b49b7..2c663c9ceb3 100644 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/context/methods.html.ini +++ b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/context/methods.html.ini @@ -15,9 +15,6 @@ [WebGL test #4: Property either does not exist or is not a function: getUniform] expected: FAIL - [WebGL test #5: Property either does not exist or is not a function: getVertexAttribOffset] - expected: FAIL - - [WebGL test #6: Property either does not exist or is not a function: isContextLost] + [WebGL test #5: Property either does not exist or is not a function: isContextLost] expected: FAIL diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float-linear.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float-linear.html.ini deleted file mode 100644 index b605dfb4a79..00000000000 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float-linear.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[oes-texture-float-linear.html] - type: testharness - [WebGL test #0: Unable to fetch WebGL rendering context for Canvas] - expected: FAIL - diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float-with-canvas.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float-with-canvas.html.ini index 9edc87baade..2c482688634 100644 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float-with-canvas.html.ini +++ b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float-with-canvas.html.ini @@ -1,5 +1,5 @@ [oes-texture-float-with-canvas.html] type: testharness - [WebGL test #0: Unable to fetch WebGL rendering context for Canvas] - expected: FAIL - + expected: ERROR + [Overall test] + expected: NOTRUN
\ No newline at end of file diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float-with-image-data.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float-with-image-data.html.ini deleted file mode 100644 index 6b331ea60bf..00000000000 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float-with-image-data.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[oes-texture-float-with-image-data.html] - type: testharness - [WebGL test #0: Unable to fetch WebGL rendering context for Canvas] - expected: FAIL - diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float-with-image.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float-with-image.html.ini deleted file mode 100644 index d4887ba03f2..00000000000 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float-with-image.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[oes-texture-float-with-image.html] - type: testharness - [WebGL test #0: Unable to fetch WebGL rendering context for Canvas] - expected: - if os == "linux": FAIL - diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float.html.ini deleted file mode 100644 index b52ca3b2827..00000000000 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-float.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[oes-texture-float.html] - type: testharness - disabled: flaky diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float-linear.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float-linear.html.ini deleted file mode 100644 index c26e8c0ec08..00000000000 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float-linear.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[oes-texture-half-float-linear.html] - type: testharness - [WebGL test #0: Unable to fetch WebGL rendering context for Canvas] - expected: FAIL - diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float-with-canvas.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float-with-canvas.html.ini new file mode 100644 index 00000000000..de7864b252e --- /dev/null +++ b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float-with-canvas.html.ini @@ -0,0 +1,5 @@ +[oes-texture-half-float-with-canvas.html] + type: testharness + expected: ERROR + [Overall test] + expected: NOTRUN
\ No newline at end of file diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float-with-image-data.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float-with-image-data.html.ini deleted file mode 100644 index 2a69bf28dbc..00000000000 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float-with-image-data.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[oes-texture-half-float-with-image-data.html] - type: testharness - [WebGL test #0: Unable to fetch WebGL rendering context for Canvas] - expected: FAIL - diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float-with-video.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float-with-video.html.ini index b5bfcb9b7bc..d8fe0d94541 100644 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float-with-video.html.ini +++ b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float-with-video.html.ini @@ -1,6 +1,3 @@ [oes-texture-half-float-with-video.html] type: testharness - [WebGL test #0: Unable to fetch WebGL rendering context for Canvas] - expected: - if os == "linux": FAIL - + disabled: flaky diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float.html.ini deleted file mode 100644 index 95ca3da7cef..00000000000 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/extensions/oes-texture-half-float.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[oes-texture-half-float.html] - type: testharness - [WebGL test #2: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).] - expected: FAIL - diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/textures/tex-image-with-format-and-type.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/textures/tex-image-with-format-and-type.html.ini index 6de5d1c40f0..0886c10762a 100644 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/textures/tex-image-with-format-and-type.html.ini +++ b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/textures/tex-image-with-format-and-type.html.ini @@ -1,3 +1,38 @@ [tex-image-with-format-and-type.html] type: testharness - expected: CRASH + + [WebGL test #6: LUMINANCE/UNSIGNED_BYTE should maintain full precision of data] + expected: FAIL + + [WebGL test #7: LUMINANCE_ALPHA/UNSIGNED_BYTE should maintain full precision of data] + expected: FAIL + + [WebGL test #14: LUMINANCE/UNSIGNED_BYTE should maintain full precision of data] + expected: FAIL + + [WebGL test #15: LUMINANCE_ALPHA/UNSIGNED_BYTE should maintain full precision of data] + expected: FAIL + + [WebGL test #22: LUMINANCE/UNSIGNED_BYTE should maintain full precision of data] + expected: FAIL + + [WebGL test #23: LUMINANCE_ALPHA/UNSIGNED_BYTE should maintain full precision of data] + expected: FAIL + + [WebGL test #30: LUMINANCE/UNSIGNED_BYTE should maintain full precision of data] + expected: FAIL + + [WebGL test #31: LUMINANCE_ALPHA/UNSIGNED_BYTE should maintain full precision of data] + expected: FAIL + + [WebGL test #65: UNPACK_PREMULTIPLY_ALPHA_WEBGL with RGBA/UNSIGNED_SHORT_4_4_4_4] + expected: FAIL + + [WebGL test #66: UNPACK_PREMULTIPLY_ALPHA_WEBGL with RGBA/UNSIGNED_SHORT_5_5_5_1] + expected: FAIL + + [WebGL test #69: UNPACK_PREMULTIPLY_ALPHA_WEBGL with RGBA/UNSIGNED_SHORT_4_4_4_4] + expected: FAIL + + [WebGL test #70: UNPACK_PREMULTIPLY_ALPHA_WEBGL with RGBA/UNSIGNED_SHORT_5_5_5_1] + expected: FAIL |