Auto merge of #16893 - MortimerGoro:webgl_extensions, r=emilio

Implement WebGL extensions

<!-- Please describe your changes on the following line: -->

This PR provides the base for implementing WebGL extensions. It comes with the following ones already implemented and passing all related WebGL conformance tests:

- OES_texture_float
- OES_texture_float_linear
- OES_texture_half_float
- OES_texture_half_float_linear
- OES_vertex_array_object

I'll submit other extensions like compressed textures in a separate PR to ease the review process. I included the 5 extensions in this PR because it's easier to show/review how the WebGL extension base works.

To pass all OES_texture_float_xxx tests I had to add some missing format conversions in WebGLRenderingContext.rs

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

<!-- Either: -->
- [x] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16893)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-05-19 01:09:48 -05:00 committed by GitHub
commit b0976566fb
40 changed files with 1346 additions and 86 deletions

8
Cargo.lock generated
View file

@ -1116,6 +1116,11 @@ dependencies = [
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[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"
@ -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)",
@ -3511,6 +3518,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"

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +0,0 @@
[oes-texture-float-linear.html]
type: testharness
[WebGL test #0: Unable to fetch WebGL rendering context for Canvas]
expected: FAIL

View file

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

View file

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

View file

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

View file

@ -1,3 +0,0 @@
[oes-texture-float.html]
type: testharness
disabled: flaky

View file

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

View file

@ -0,0 +1,5 @@
[oes-texture-half-float-with-canvas.html]
type: testharness
expected: ERROR
[Overall test]
expected: NOTRUN

View file

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

View file

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

View file

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

View file

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