aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/canvas/webgl_thread.rs16
-rw-r--r--components/canvas_traits/webgl.rs7
-rw-r--r--components/script/dom/webgl2renderingcontext.rs28
-rw-r--r--components/script/dom/webgl_extensions/ext/angleinstancedarrays.rs92
-rw-r--r--components/script/dom/webgl_extensions/ext/mod.rs1
-rw-r--r--components/script/dom/webgl_extensions/extensions.rs31
-rw-r--r--components/script/dom/webglrenderingcontext.rs371
-rw-r--r--components/script/dom/webglshader.rs42
-rw-r--r--components/script/dom/webidls/ANGLEInstancedArrays.webidl15
-rw-r--r--components/script/dom/webidls/WebGL2RenderingContext.webidl6
10 files changed, 531 insertions, 78 deletions
diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs
index abdda3c812a..a90c996f8bb 100644
--- a/components/canvas/webgl_thread.rs
+++ b/components/canvas/webgl_thread.rs
@@ -885,6 +885,13 @@ impl WebGLImpl {
}
sender.send(value[0]).unwrap()
}
+ WebGLCommand::GetParameterInt2(param, ref sender) => {
+ let mut value = [0; 2];
+ unsafe {
+ ctx.gl().get_integer_v(param as u32, &mut value);
+ }
+ sender.send(value).unwrap()
+ }
WebGLCommand::GetParameterInt4(param, ref sender) => {
let mut value = [0; 4];
unsafe {
@@ -966,6 +973,15 @@ impl WebGLImpl {
WebGLCommand::UseProgram(program_id) => {
ctx.gl().use_program(program_id.map_or(0, |p| p.get()))
}
+ WebGLCommand::DrawArraysInstanced { mode, first, count, primcount } => {
+ ctx.gl().draw_arrays_instanced(mode, first, count, primcount)
+ }
+ WebGLCommand::DrawElementsInstanced { mode, count, type_, offset, primcount } => {
+ ctx.gl().draw_elements_instanced(mode, count, type_, offset, primcount)
+ }
+ WebGLCommand::VertexAttribDivisor { index, divisor } => {
+ ctx.gl().vertex_attrib_divisor(index, divisor)
+ }
}
// TODO: update test expectations in order to enable debug assertions
diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs
index 6446c0c18d8..793f687698b 100644
--- a/components/canvas_traits/webgl.rs
+++ b/components/canvas_traits/webgl.rs
@@ -268,6 +268,7 @@ pub enum WebGLCommand {
GetParameterBool(ParameterBool, WebGLSender<bool>),
GetParameterBool4(ParameterBool4, WebGLSender<[bool; 4]>),
GetParameterInt(ParameterInt, WebGLSender<i32>),
+ GetParameterInt2(ParameterInt2, WebGLSender<[i32; 2]>),
GetParameterInt4(ParameterInt4, WebGLSender<[i32; 4]>),
GetParameterFloat(ParameterFloat, WebGLSender<f32>),
GetParameterFloat2(ParameterFloat2, WebGLSender<[f32; 2]>),
@@ -281,6 +282,9 @@ pub enum WebGLCommand {
GetTexParameterInt(u32, TexParameterInt, WebGLSender<i32>),
TexParameteri(u32, TexParameterInt, i32),
TexParameterf(u32, TexParameterFloat, f32),
+ DrawArraysInstanced { mode: u32, first: i32, count: i32, primcount: i32 },
+ DrawElementsInstanced { mode: u32, count: i32, type_: u32, offset: u32, primcount: i32 },
+ VertexAttribDivisor { index: u32, divisor: u32 },
}
macro_rules! define_resource_id_struct {
@@ -522,6 +526,9 @@ parameters! {
SubpixelBits = gl::SUBPIXEL_BITS,
UnpackAlignment = gl::UNPACK_ALIGNMENT,
}),
+ Int2(ParameterInt2 {
+ MaxViewportDims = gl::MAX_VIEWPORT_DIMS,
+ }),
Int4(ParameterInt4 {
ScissorBox = gl::SCISSOR_BOX,
Viewport = gl::VIEWPORT,
diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs
index c06a07a9e3e..deb82e9ced2 100644
--- a/components/script/dom/webgl2renderingcontext.rs
+++ b/components/script/dom/webgl2renderingcontext.rs
@@ -937,6 +937,34 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
) -> Option<Vec<DomRoot<WebGLShader>>> {
self.base.GetAttachedShaders(program)
}
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.9
+ fn DrawArraysInstanced(
+ &self,
+ mode: u32,
+ first: i32,
+ count: i32,
+ primcount: i32,
+ ) {
+ self.base.draw_arrays_instanced(mode, first, count, primcount);
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.9
+ fn DrawElementsInstanced(
+ &self,
+ mode: u32,
+ count: i32,
+ type_: u32,
+ offset: i64,
+ primcount: i32,
+ ) {
+ self.base.draw_elements_instanced(mode, count, type_, offset, primcount);
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.9
+ fn VertexAttribDivisor(&self, index: u32, divisor: u32) {
+ self.base.vertex_attrib_divisor(index, divisor);
+ }
}
diff --git a/components/script/dom/webgl_extensions/ext/angleinstancedarrays.rs b/components/script/dom/webgl_extensions/ext/angleinstancedarrays.rs
new file mode 100644
index 00000000000..f35abaf15af
--- /dev/null
+++ b/components/script/dom/webgl_extensions/ext/angleinstancedarrays.rs
@@ -0,0 +1,92 @@
+/* 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::webgl::WebGLVersion;
+use dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding;
+use dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants;
+use dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysMethods;
+use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
+use dom::bindings::root::{Dom, DomRoot};
+use dom::webglrenderingcontext::WebGLRenderingContext;
+use dom_struct::dom_struct;
+use super::{WebGLExtension, WebGLExtensions, WebGLExtensionSpec};
+
+#[dom_struct]
+pub struct ANGLEInstancedArrays {
+ reflector_: Reflector,
+ ctx: Dom<WebGLRenderingContext>,
+}
+
+impl ANGLEInstancedArrays {
+ fn new_inherited(ctx: &WebGLRenderingContext) -> Self {
+ Self {
+ reflector_: Reflector::new(),
+ ctx: Dom::from_ref(ctx),
+ }
+ }
+}
+
+impl WebGLExtension for ANGLEInstancedArrays {
+ type Extension = Self;
+
+ fn new(ctx: &WebGLRenderingContext) -> DomRoot<Self> {
+ reflect_dom_object(
+ Box::new(ANGLEInstancedArrays::new_inherited(ctx)),
+ &*ctx.global(),
+ ANGLEInstancedArraysBinding::Wrap,
+ )
+ }
+
+ fn spec() -> WebGLExtensionSpec {
+ WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
+ }
+
+ fn is_supported(ext: &WebGLExtensions) -> bool {
+ ext.supports_any_gl_extension(&[
+ "GL_ANGLE_instanced_arrays",
+ "GL_ARB_instanced_arrays",
+ "GL_EXT_instanced_arrays",
+ "GL_NV_instanced_arrays",
+ ])
+ }
+
+ fn enable(ext: &WebGLExtensions) {
+ ext.enable_get_vertex_attrib_name(
+ ANGLEInstancedArraysConstants::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
+ );
+ }
+
+ fn name() -> &'static str {
+ "ANGLE_instanced_arrays"
+ }
+}
+
+impl ANGLEInstancedArraysMethods for ANGLEInstancedArrays {
+ // https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
+ fn DrawArraysInstancedANGLE(
+ &self,
+ mode: u32,
+ first: i32,
+ count: i32,
+ primcount: i32,
+ ) {
+ self.ctx.draw_arrays_instanced(mode, first, count, primcount);
+ }
+
+ // https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
+ fn DrawElementsInstancedANGLE(
+ &self,
+ mode: u32,
+ count: i32,
+ type_: u32,
+ offset: i64,
+ primcount: i32,
+ ) {
+ self.ctx.draw_elements_instanced(mode, count, type_, offset, primcount);
+ }
+
+ fn VertexAttribDivisorANGLE(&self, index: u32, divisor: u32) {
+ self.ctx.vertex_attrib_divisor(index, divisor);
+ }
+}
diff --git a/components/script/dom/webgl_extensions/ext/mod.rs b/components/script/dom/webgl_extensions/ext/mod.rs
index bdf19d5327a..62f75cb048a 100644
--- a/components/script/dom/webgl_extensions/ext/mod.rs
+++ b/components/script/dom/webgl_extensions/ext/mod.rs
@@ -5,6 +5,7 @@
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use super::{ext_constants, WebGLExtension, WebGLExtensions, WebGLExtensionSpec};
+pub mod angleinstancedarrays;
pub mod extblendminmax;
pub mod extshadertexturelod;
pub mod exttexturefilteranisotropic;
diff --git a/components/script/dom/webgl_extensions/extensions.rs b/components/script/dom/webgl_extensions/extensions.rs
index c5413ea1eb2..b3812f51cf5 100644
--- a/components/script/dom/webgl_extensions/extensions.rs
+++ b/components/script/dom/webgl_extensions/extensions.rs
@@ -4,6 +4,7 @@
use canvas_traits::webgl::{WebGLError, WebGLVersion};
use dom::bindings::cell::DomRefCell;
+use dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants;
use dom::bindings::codegen::Bindings::EXTTextureFilterAnisotropicBinding::EXTTextureFilterAnisotropicConstants;
use dom::bindings::codegen::Bindings::OESStandardDerivativesBinding::OESStandardDerivativesConstants;
use dom::bindings::codegen::Bindings::OESTextureHalfFloatBinding::OESTextureHalfFloatConstants;
@@ -54,6 +55,13 @@ const DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL1: [GLenum; 1] = [
EXTTextureFilterAnisotropicConstants::TEXTURE_MAX_ANISOTROPY_EXT,
];
+// Param names that are implemented for glGetVertexAttrib in a WebGL 1.0 context
+// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
+// Example: https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
+const DEFAULT_DISABLED_GET_VERTEX_ATTRIB_NAMES_WEBGL1: [GLenum; 1] = [
+ ANGLEInstancedArraysConstants::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
+];
+
/// WebGL features that are enabled/disabled by WebGL Extensions.
#[derive(JSTraceable, MallocSizeOf)]
struct WebGLExtensionFeatures {
@@ -68,6 +76,8 @@ struct WebGLExtensionFeatures {
disabled_get_parameter_names: FnvHashSet<GLenum>,
/// WebGL GetTexParameter() names enabled by extensions.
disabled_get_tex_parameter_names: FnvHashSet<GLenum>,
+ /// WebGL GetAttribVertex() names enabled by extensions.
+ disabled_get_vertex_attrib_names: FnvHashSet<GLenum>,
/// WebGL OES_element_index_uint extension.
element_index_uint_enabled: bool,
/// WebGL EXT_blend_minmax extension.
@@ -80,6 +90,7 @@ impl WebGLExtensionFeatures {
disabled_tex_types,
disabled_get_parameter_names,
disabled_get_tex_parameter_names,
+ disabled_get_vertex_attrib_names,
element_index_uint_enabled,
blend_minmax_enabled,
) = match webgl_version {
@@ -88,12 +99,20 @@ impl WebGLExtensionFeatures {
DEFAULT_DISABLED_TEX_TYPES_WEBGL1.iter().cloned().collect(),
DEFAULT_DISABLED_GET_PARAMETER_NAMES_WEBGL1.iter().cloned().collect(),
DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL1.iter().cloned().collect(),
+ DEFAULT_DISABLED_GET_VERTEX_ATTRIB_NAMES_WEBGL1.iter().cloned().collect(),
false,
false,
)
},
WebGLVersion::WebGL2 => {
- (Default::default(), Default::default(), Default::default(), true, true)
+ (
+ Default::default(),
+ Default::default(),
+ Default::default(),
+ Default::default(),
+ true,
+ true,
+ )
}
};
Self {
@@ -105,6 +124,7 @@ impl WebGLExtensionFeatures {
hint_targets: Default::default(),
disabled_get_parameter_names,
disabled_get_tex_parameter_names,
+ disabled_get_vertex_attrib_names,
element_index_uint_enabled,
blend_minmax_enabled,
}
@@ -269,7 +289,16 @@ impl WebGLExtensions {
!self.features.borrow().disabled_get_tex_parameter_names.contains(&name)
}
+ pub fn enable_get_vertex_attrib_name(&self, name: GLenum) {
+ self.features.borrow_mut().disabled_get_vertex_attrib_names.remove(&name);
+ }
+
+ pub fn is_get_vertex_attrib_name_enabled(&self, name: GLenum) -> bool {
+ !self.features.borrow().disabled_get_vertex_attrib_names.contains(&name)
+ }
+
fn register_all_extensions(&self) {
+ self.register::<ext::angleinstancedarrays::ANGLEInstancedArrays>();
self.register::<ext::extblendminmax::EXTBlendMinmax>();
self.register::<ext::extshadertexturelod::EXTShaderTextureLod>();
self.register::<ext::exttexturefilteranisotropic::EXTTextureFilterAnisotropic>();
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index cb4c5dbcfb0..3988c93646f 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -4,7 +4,7 @@
use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
use canvas_traits::canvas::{byte_swap, multiply_u8_pixel};
-use canvas_traits::webgl::{DOMToTextureCommand, Parameter};
+use canvas_traits::webgl::{ActiveAttribInfo, DOMToTextureCommand, Parameter};
use canvas_traits::webgl::{ShaderParameter, TexParameter, WebGLCommand};
use canvas_traits::webgl::{WebGLContextShareMode, WebGLError};
use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender};
@@ -12,6 +12,7 @@ use canvas_traits::webgl::{WebGLResult, WebGLSLVersion, WebGLVersion};
use canvas_traits::webgl::{WebVRCommand, webgl_channel};
use canvas_traits::webgl::WebGLError::*;
use dom::bindings::cell::DomRefCell;
+use dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants;
use dom::bindings::codegen::Bindings::EXTBlendMinmaxBinding::EXTBlendMinmaxConstants;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{self, WebGLContextAttributes};
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
@@ -52,9 +53,10 @@ use euclid::Size2D;
use fnv::FnvHashMap;
use half::f16;
use js::jsapi::{JSContext, JSObject, Type};
-use js::jsval::{BooleanValue, DoubleValue, Int32Value, UInt32Value, JSVal, NullValue, UndefinedValue};
+use js::jsval::{BooleanValue, DoubleValue, Int32Value, UInt32Value, JSVal};
+use js::jsval::{ObjectValue, NullValue, UndefinedValue};
use js::rust::CustomAutoRooterGuard;
-use js::typedarray::ArrayBufferView;
+use js::typedarray::{ArrayBufferView, CreateWith, Float32Array, Int32Array, Uint32Array};
use net_traits::image::base::PixelFormat;
use net_traits::image_cache::ImageResponse;
use offscreen_gl_context::{GLContextAttributes, GLLimits};
@@ -63,7 +65,7 @@ use script_layout_interface::HTMLCanvasDataSource;
use servo_config::prefs::PREFS;
use std::cell::{Cell, Ref};
use std::cmp;
-use std::ptr::NonNull;
+use std::ptr::{self, NonNull};
use webrender_api;
type ImagePixelResult = Result<(Vec<u8>, Size2D<i32>, bool), ()>;
@@ -250,7 +252,7 @@ impl WebGLRenderingContext {
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)),
- extension_manager: WebGLExtensions::new(webgl_version)
+ extension_manager: WebGLExtensions::new(webgl_version),
}
})
}
@@ -1155,6 +1157,142 @@ impl WebGLRenderingContext {
}
}
+ // https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
+ pub fn draw_arrays_instanced(
+ &self,
+ mode: u32,
+ first: i32,
+ count: i32,
+ primcount: i32,
+ ) {
+ match mode {
+ constants::POINTS | constants::LINE_STRIP |
+ constants::LINE_LOOP | constants::LINES |
+ constants::TRIANGLE_STRIP | constants::TRIANGLE_FAN |
+ constants::TRIANGLES => {},
+ _ => {
+ return self.webgl_error(InvalidEnum);
+ }
+ }
+ if first < 0 || count < 0 || primcount < 0 {
+ return self.webgl_error(InvalidValue);
+ }
+
+ let current_program = handle_potential_webgl_error!(
+ self,
+ self.current_program.get().ok_or(InvalidOperation),
+ return
+ );
+
+ let required_len = if count > 0 {
+ handle_potential_webgl_error!(
+ self,
+ first.checked_add(count).map(|len| len as u32).ok_or(InvalidOperation),
+ return
+ )
+ } else {
+ 0
+ };
+
+ handle_potential_webgl_error!(
+ self,
+ self.vertex_attribs.validate_for_draw(required_len, primcount as u32, &current_program.active_attribs()),
+ return
+ );
+
+ if !self.validate_framebuffer_complete() {
+ return;
+ }
+
+ self.send_command(
+ WebGLCommand::DrawArraysInstanced { mode, first, count, primcount },
+ );
+ self.mark_as_dirty();
+ }
+
+ // https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
+ pub fn draw_elements_instanced(
+ &self,
+ mode: u32,
+ count: i32,
+ type_: u32,
+ offset: i64,
+ primcount: i32,
+ ) {
+ match mode {
+ constants::POINTS | constants::LINE_STRIP |
+ constants::LINE_LOOP | constants::LINES |
+ constants::TRIANGLE_STRIP | constants::TRIANGLE_FAN |
+ constants::TRIANGLES => {},
+ _ => {
+ return self.webgl_error(InvalidEnum);
+ }
+ }
+ if count < 0 || offset < 0 || primcount < 0 {
+ return self.webgl_error(InvalidValue);
+ }
+ let type_size = match type_ {
+ constants::UNSIGNED_BYTE => 1,
+ constants::UNSIGNED_SHORT => 2,
+ _ => return self.webgl_error(InvalidEnum),
+ };
+ if offset % type_size != 0 {
+ return self.webgl_error(InvalidOperation);
+ }
+
+ let current_program = handle_potential_webgl_error!(
+ self,
+ self.current_program.get().ok_or(InvalidOperation),
+ return
+ );
+
+ if count > 0 && primcount > 0 {
+ if let Some(array_buffer) = self.bound_buffer_element_array.get() {
+ // WebGL Spec: check buffer overflows, must be a valid multiple of the size.
+ let val = offset as u64 + (count as u64 * type_size as u64);
+ if val > array_buffer.capacity() as u64 {
+ return self.webgl_error(InvalidOperation);
+ }
+ } else {
+ // From the WebGL spec
+ //
+ // a non-null WebGLBuffer must be bound to the ELEMENT_ARRAY_BUFFER binding point
+ // or an INVALID_OPERATION error will be generated.
+ //
+ return self.webgl_error(InvalidOperation);
+ }
+ }
+
+ // TODO(nox): Pass the correct number of vertices required.
+ handle_potential_webgl_error!(
+ self,
+ self.vertex_attribs.validate_for_draw(0, primcount as u32, &current_program.active_attribs()),
+ return
+ );
+
+ if !self.validate_framebuffer_complete() {
+ return;
+ }
+
+ self.send_command(WebGLCommand::DrawElementsInstanced {
+ mode,
+ count,
+ type_,
+ offset: offset as u32,
+ primcount,
+ });
+ self.mark_as_dirty();
+ }
+
+ pub fn vertex_attrib_divisor(&self, index: u32, divisor: u32) {
+ if index >= self.limits.max_vertex_attribs {
+ return self.webgl_error(InvalidValue);
+ }
+
+ self.vertex_attribs.set_divisor(index, divisor);
+ self.send_command(WebGLCommand::VertexAttribDivisor { index, divisor });
+ }
+
// Used by HTMLCanvasElement.toDataURL
//
// This emits errors quite liberally, but the spec says that this operation
@@ -1331,6 +1469,16 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
return Int32Value(constants::UNSIGNED_BYTE as i32);
}
}
+ constants::COMPRESSED_TEXTURE_FORMATS => {
+ // FIXME(nox): https://github.com/servo/servo/issues/20594
+ rooted!(in(cx) let mut rval = ptr::null_mut::<JSObject>());
+ let _ = Uint32Array::create(
+ cx,
+ CreateWith::Slice(&[]),
+ rval.handle_mut(),
+ ).unwrap();
+ return ObjectValue(rval.get());
+ }
constants::VERSION => {
rooted!(in(cx) let mut rval = UndefinedValue());
"WebGL 1.0".to_jsval(cx, rval.handle_mut());
@@ -1422,13 +1570,27 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
self.send_command(WebGLCommand::GetParameterInt(param, sender));
Int32Value(receiver.recv().unwrap())
}
+ Parameter::Int2(param) => {
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.send_command(WebGLCommand::GetParameterInt2(param, sender));
+ rooted!(in(cx) let mut rval = ptr::null_mut::<JSObject>());
+ let _ = Int32Array::create(
+ cx,
+ CreateWith::Slice(&receiver.recv().unwrap()),
+ rval.handle_mut(),
+ ).unwrap();
+ ObjectValue(rval.get())
+ }
Parameter::Int4(param) => {
let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetParameterInt4(param, sender));
- // FIXME(nox): https://github.com/servo/servo/issues/20655
- rooted!(in(cx) let mut rval = UndefinedValue());
- receiver.recv().unwrap().to_jsval(cx, rval.handle_mut());
- rval.get()
+ rooted!(in(cx) let mut rval = ptr::null_mut::<JSObject>());
+ let _ = Int32Array::create(
+ cx,
+ CreateWith::Slice(&receiver.recv().unwrap()),
+ rval.handle_mut(),
+ ).unwrap();
+ ObjectValue(rval.get())
}
Parameter::Float(param) => {
let (sender, receiver) = webgl_channel().unwrap();
@@ -1438,18 +1600,24 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
Parameter::Float2(param) => {
let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetParameterFloat2(param, sender));
- // FIXME(nox): https://github.com/servo/servo/issues/20655
- rooted!(in(cx) let mut rval = UndefinedValue());
- receiver.recv().unwrap().to_jsval(cx, rval.handle_mut());
- rval.get()
+ rooted!(in(cx) let mut rval = ptr::null_mut::<JSObject>());
+ let _ = Float32Array::create(
+ cx,
+ CreateWith::Slice(&receiver.recv().unwrap()),
+ rval.handle_mut(),
+ ).unwrap();
+ ObjectValue(rval.get())
}
Parameter::Float4(param) => {
let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetParameterFloat4(param, sender));
- // FIXME(nox): https://github.com/servo/servo/issues/20655
- rooted!(in(cx) let mut rval = UndefinedValue());
- receiver.recv().unwrap().to_jsval(cx, rval.handle_mut());
- rval.get()
+ rooted!(in(cx) let mut rval = ptr::null_mut::<JSObject>());
+ let _ = Float32Array::create(
+ cx,
+ CreateWith::Slice(&receiver.recv().unwrap()),
+ rval.handle_mut(),
+ ).unwrap();
+ ObjectValue(rval.get())
}
}
}
@@ -2021,7 +2189,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
fn CompileShader(&self, shader: &WebGLShader) {
handle_potential_webgl_error!(
self,
- shader.compile(self.webgl_version, self.glsl_version, &self.extension_manager)
+ shader.compile(
+ self.webgl_version,
+ self.glsl_version,
+ &self.limits,
+ &self.extension_manager,
+ )
)
}
@@ -2193,16 +2366,28 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
if first < 0 || count < 0 {
return self.webgl_error(InvalidValue);
}
- if self.current_program.get().is_none() {
- return self.webgl_error(InvalidOperation);
- }
- if let Some(array_buffer) = self.bound_buffer_array.get() {
- if count > 0 && (first as u64 + count as u64 > array_buffer.capacity() as u64) {
- return self.webgl_error(InvalidOperation);
- }
- }
- handle_potential_webgl_error!(self, self.vertex_attribs.validate_for_draw(), return);
+ let current_program = handle_potential_webgl_error!(
+ self,
+ self.current_program.get().ok_or(InvalidOperation),
+ return
+ );
+
+ let required_len = if count > 0 {
+ handle_potential_webgl_error!(
+ self,
+ first.checked_add(count).map(|len| len as u32).ok_or(InvalidOperation),
+ return
+ )
+ } else {
+ 0
+ };
+
+ handle_potential_webgl_error!(
+ self,
+ self.vertex_attribs.validate_for_draw(required_len, 1, &current_program.active_attribs()),
+ return
+ );
if !self.validate_framebuffer_complete() {
return;
@@ -2244,15 +2429,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
return self.webgl_error(InvalidValue);
}
- if self.current_program.get().is_none() {
- // From the WebGL spec
- //
- // If the CURRENT_PROGRAM is null, an INVALID_OPERATION error will be generated.
- // WebGL performs additional error checking beyond that specified
- // in OpenGL ES 2.0 during calls to drawArrays and drawElements.
- //
- return self.webgl_error(InvalidOperation);
- }
+ let current_program = handle_potential_webgl_error!(
+ self,
+ self.current_program.get().ok_or(InvalidOperation),
+ return
+ );
if count > 0 {
if let Some(array_buffer) = self.bound_buffer_element_array.get() {
@@ -2271,7 +2452,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
}
}
- handle_potential_webgl_error!(self, self.vertex_attribs.validate_for_draw(), return);
+ // TODO(nox): Pass the correct number of vertices required.
+ handle_potential_webgl_error!(
+ self,
+ self.vertex_attribs.validate_for_draw(0, 1, &current_program.active_attribs()),
+ return
+ );
if !self.validate_framebuffer_complete() {
return;
@@ -2522,7 +2708,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn GetShaderInfoLog(&self, shader: &WebGLShader) -> Option<DOMString> {
- shader.info_log().map(DOMString::from)
+ // TODO(nox): https://github.com/servo/servo/issues/21133
+ Some(shader.info_log())
}
#[allow(unsafe_code)]
@@ -2602,10 +2789,18 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
self.send_command(WebGLCommand::GetCurrentVertexAttrib(index, sender));
receiver.recv().unwrap()
};
- // FIXME(nox): https://github.com/servo/servo/issues/20655
- rooted!(in(cx) let mut result = UndefinedValue());
- value.to_jsval(cx, result.handle_mut());
- return result.get();
+ rooted!(in(cx) let mut result = ptr::null_mut::<JSObject>());
+ let _ = Float32Array::create(
+ cx,
+ CreateWith::Slice(&value),
+ result.handle_mut(),
+ ).unwrap();
+ return ObjectValue(result.get());
+ }
+
+ if !self.extension_manager.is_get_vertex_attrib_name_enabled(param) {
+ self.webgl_error(WebGLError::InvalidEnum);
+ return NullValue();
}
match param {
@@ -2623,6 +2818,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
}
jsval.get()
}
+ ANGLEInstancedArraysConstants::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE => {
+ Int32Value(data.divisor as i32)
+ }
_ => {
self.webgl_error(InvalidEnum);
NullValue()
@@ -2968,7 +3166,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn GetShaderSource(&self, shader: &WebGLShader) -> Option<DOMString> {
- shader.source()
+ // TODO(nox): https://github.com/servo/servo/issues/21133
+ Some(shader.source())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -3828,19 +4027,14 @@ impl VertexAttribs {
if stride < 0 || stride > 255 || offset < 0 {
return Err(InvalidValue);
}
- match type_ {
- constants::BYTE | constants::UNSIGNED_BYTE => {},
- constants::SHORT | constants::UNSIGNED_SHORT => {
- if offset % 2 > 0 || stride % 2 > 0 {
- return Err(InvalidOperation);
- }
- },
- constants::FLOAT => {
- if offset % 4 > 0 || stride % 4 > 0 {
- return Err(InvalidOperation);
- }
- },
+ let bytes_per_component: i32 = match type_ {
+ constants::BYTE | constants::UNSIGNED_BYTE => 1,
+ constants::SHORT | constants::UNSIGNED_SHORT => 2,
+ constants::FLOAT => 4,
_ => return Err(InvalidEnum),
+ };
+ if offset % bytes_per_component as i64 > 0 || stride % bytes_per_component > 0 {
+ return Err(InvalidOperation);
}
let buffer = buffer.ok_or(InvalidOperation)?;
@@ -3849,10 +4043,12 @@ impl VertexAttribs {
enabled_as_array: data.enabled_as_array,
size: size as u8,
type_,
+ bytes_per_vertex: size as u8 * bytes_per_component as u8,
normalized,
stride: stride as u8,
offset: offset as u32,
buffer: Some(Dom::from_ref(buffer)),
+ divisor: data.divisor,
};
Ok(())
}
@@ -3877,9 +4073,49 @@ impl VertexAttribs {
self.attribs.borrow_mut()[index as usize].enabled_as_array = value;
}
- fn validate_for_draw(&self) -> WebGLResult<()> {
+ fn set_divisor(&self, index: u32, value: u32) {
+ self.attribs.borrow_mut()[index as usize].divisor = value;
+ }
+
+ fn validate_for_draw(
+ &self,
+ required_len: u32,
+ instance_count: u32,
+ active_attribs: &[ActiveAttribInfo],
+ ) -> WebGLResult<()> {
+ // TODO(nox): Cache limits per VAO.
+ let attribs = self.attribs.borrow();
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.2
- if self.borrow().iter().any(|data| data.enabled_as_array && data.buffer.is_none()) {
+ if attribs.iter().any(|data| data.enabled_as_array && data.buffer.is_none()) {
+ return Err(InvalidOperation);
+ }
+ let mut has_active_attrib = false;
+ let mut has_divisor_0 = false;
+ for active_info in active_attribs {
+ if active_info.location < 0 {
+ continue;
+ }
+ has_active_attrib = true;
+ let attrib = &attribs[active_info.location as usize];
+ if attrib.divisor == 0 {
+ has_divisor_0 = true;
+ }
+ if !attrib.enabled_as_array {
+ continue;
+ }
+ // https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.6
+ if required_len > 0 && instance_count > 0 {
+ let max_vertices = attrib.max_vertices();
+ if attrib.divisor == 0 {
+ if max_vertices < required_len {
+ return Err(InvalidOperation);
+ }
+ } else if max_vertices.checked_mul(attrib.divisor).map_or(false, |v| v < instance_count) {
+ return Err(InvalidOperation);
+ }
+ }
+ }
+ if has_active_attrib && !has_divisor_0 {
return Err(InvalidOperation);
}
Ok(())
@@ -3892,10 +4128,12 @@ pub struct VertexAttribData {
enabled_as_array: bool,
size: u8,
type_: u32,
+ bytes_per_vertex: u8,
normalized: bool,
stride: u8,
offset: u32,
buffer: Option<Dom<WebGLBuffer>>,
+ divisor: u32,
}
impl Default for VertexAttribData {
@@ -3905,10 +4143,12 @@ impl Default for VertexAttribData {
enabled_as_array: false,
size: 4,
type_: constants::FLOAT,
+ bytes_per_vertex: 16,
normalized: false,
stride: 0,
offset: 0,
buffer: None,
+ divisor: 0,
}
}
}
@@ -3917,4 +4157,21 @@ impl VertexAttribData {
pub fn buffer(&self) -> Option<&WebGLBuffer> {
self.buffer.as_ref().map(|b| &**b)
}
+
+ fn max_vertices(&self) -> u32 {
+ let capacity = (self.buffer().unwrap().capacity() as u32).saturating_sub(self.offset);
+ if capacity < self.bytes_per_vertex as u32 {
+ 0
+ } else if self.stride == 0 {
+ capacity / self.bytes_per_vertex as u32
+ } else if self.stride < self.bytes_per_vertex {
+ (capacity - (self.bytes_per_vertex - self.stride) as u32) / self.stride as u32
+ } else {
+ let mut max = capacity / self.stride as u32;
+ if capacity % self.stride as u32 >= self.bytes_per_vertex as u32 {
+ max += 1;
+ }
+ max
+ }
+ }
}
diff --git a/components/script/dom/webglshader.rs b/components/script/dom/webglshader.rs
index 0ec5c262803..1feb73d2d3a 100644
--- a/components/script/dom/webglshader.rs
+++ b/components/script/dom/webglshader.rs
@@ -18,7 +18,9 @@ use dom::webglobject::WebGLObject;
use dom::window::Window;
use dom_struct::dom_struct;
use mozangle::shaders::{BuiltInResources, Output, ShaderValidator};
+use offscreen_gl_context::GLLimits;
use std::cell::Cell;
+use std::os::raw::c_int;
use std::sync::{ONCE_INIT, Once};
#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
@@ -33,8 +35,8 @@ pub struct WebGLShader {
webgl_object: WebGLObject,
id: WebGLShaderId,
gl_type: u32,
- source: DomRefCell<Option<DOMString>>,
- info_log: DomRefCell<Option<String>>,
+ source: DomRefCell<DOMString>,
+ info_log: DomRefCell<DOMString>,
is_deleted: Cell<bool>,
attached_counter: Cell<u32>,
compilation_status: Cell<ShaderCompilationStatus>,
@@ -54,8 +56,8 @@ impl WebGLShader {
webgl_object: WebGLObject::new_inherited(),
id: id,
gl_type: shader_type,
- source: DomRefCell::new(None),
- info_log: DomRefCell::new(None),
+ source: Default::default(),
+ info_log: Default::default(),
is_deleted: Cell::new(false),
attached_counter: Cell::new(0),
compilation_status: Cell::new(ShaderCompilationStatus::NotCompiled),
@@ -100,6 +102,7 @@ impl WebGLShader {
&self,
webgl_version: WebGLVersion,
glsl_version: WebGLSLVersion,
+ limits: &GLLimits,
ext: &WebGLExtensions,
) -> WebGLResult<()> {
if self.is_deleted.get() && !self.is_attached() {
@@ -110,15 +113,20 @@ impl WebGLShader {
}
let source = self.source.borrow();
- let source = match source.as_ref() {
- Some(source) => source,
- None => return Ok(()),
- };
- let mut params = BuiltInResources::default();
- params.FragmentPrecisionHigh = 1;
- params.OES_standard_derivatives = ext.is_enabled::<OESStandardDerivatives>() as i32;
- params.EXT_shader_texture_lod = ext.is_enabled::<EXTShaderTextureLod>() as i32;
+ let params = BuiltInResources {
+ MaxVertexAttribs: limits.max_vertex_attribs as c_int,
+ MaxVertexUniformVectors: limits.max_vertex_uniform_vectors as c_int,
+ MaxVaryingVectors: limits.max_varying_vectors as c_int,
+ MaxVertexTextureImageUnits: limits.max_vertex_texture_image_units as c_int,
+ MaxCombinedTextureImageUnits: limits.max_combined_texture_image_units as c_int,
+ MaxTextureImageUnits: limits.max_texture_image_units as c_int,
+ MaxFragmentUniformVectors: limits.max_fragment_uniform_vectors as c_int,
+ OES_standard_derivatives: ext.is_enabled::<OESStandardDerivatives>() as c_int,
+ EXT_shader_texture_lod: ext.is_enabled::<EXTShaderTextureLod>() as c_int,
+ FragmentPrecisionHigh: 1,
+ ..BuiltInResources::default()
+ };
let validator = match webgl_version {
WebGLVersion::WebGL1 => {
let output_format = if cfg!(any(target_os = "android", target_os = "ios")) {
@@ -154,7 +162,7 @@ impl WebGLShader {
},
};
- match validator.compile_and_translate(&[source]) {
+ match validator.compile_and_translate(&[&source]) {
Ok(translated_source) => {
debug!("Shader translated: {}", translated_source);
// NOTE: At this point we should be pretty sure that the compilation in the paint thread
@@ -170,7 +178,7 @@ impl WebGLShader {
},
}
- *self.info_log.borrow_mut() = Some(validator.info_log());
+ *self.info_log.borrow_mut() = validator.info_log().into();
// TODO(emilio): More data (like uniform data) should be collected
// here to properly validate uniforms.
@@ -208,18 +216,18 @@ impl WebGLShader {
}
/// glGetShaderInfoLog
- pub fn info_log(&self) -> Option<String> {
+ pub fn info_log(&self) -> DOMString {
self.info_log.borrow().clone()
}
/// Get the shader source
- pub fn source(&self) -> Option<DOMString> {
+ pub fn source(&self) -> DOMString {
self.source.borrow().clone()
}
/// glShaderSource
pub fn set_source(&self, source: DOMString) {
- *self.source.borrow_mut() = Some(source);
+ *self.source.borrow_mut() = source;
}
pub fn successfully_compiled(&self) -> bool {
diff --git a/components/script/dom/webidls/ANGLEInstancedArrays.webidl b/components/script/dom/webidls/ANGLEInstancedArrays.webidl
new file mode 100644
index 00000000000..a4ae955826a
--- /dev/null
+++ b/components/script/dom/webidls/ANGLEInstancedArrays.webidl
@@ -0,0 +1,15 @@
+/* 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/ANGLE_instanced_arrays/
+ */
+
+[NoInterfaceObject]
+interface ANGLEInstancedArrays {
+ const GLenum VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
+ void drawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+ void drawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, GLintptr offset, GLsizei primcount);
+ void vertexAttribDivisorANGLE(GLuint index, GLuint divisor);
+};
diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl
index 76b04e277ea..b14711d107e 100644
--- a/components/script/dom/webidls/WebGL2RenderingContext.webidl
+++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl
@@ -502,9 +502,9 @@ interface WebGL2RenderingContextBase
// void vertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
/* Writing to the drawing buffer */
- // void vertexAttribDivisor(GLuint index, GLuint divisor);
- // void drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
- // void drawElementsInstanced(GLenum mode, GLsizei count, GLenum type, GLintptr offset, GLsizei instanceCount);
+ void vertexAttribDivisor(GLuint index, GLuint divisor);
+ void drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
+ void drawElementsInstanced(GLenum mode, GLsizei count, GLenum type, GLintptr offset, GLsizei instanceCount);
// void drawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLintptr offset);
/* Reading back pixels */