aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/webglrenderingcontext.rs
diff options
context:
space:
mode:
authorIstvan Miklos <istvan.miklos@h-lab.eu>2020-03-05 15:51:18 +0100
committerJosh Matthews <josh@joshmatthews.net>2020-03-13 11:38:28 -0400
commit1b4a3d8987077ce003ab0755b33663bda7f31935 (patch)
treeb48a0ce1fa85b29107455a0094a936a7eb7e9b50 /components/script/dom/webglrenderingcontext.rs
parent4b1bb895a30e798f3b0c293e4cf95630db692323 (diff)
downloadservo-1b4a3d8987077ce003ab0755b33663bda7f31935.tar.gz
servo-1b4a3d8987077ce003ab0755b33663bda7f31935.zip
Add VertexArrayObject support for WebGL2
The implementation was already in place for OpenGL ES. My approach with this patch is to add support for WebGL2 by sharing the implementation between the WebGL2 and GLES.
Diffstat (limited to 'components/script/dom/webglrenderingcontext.rs')
-rw-r--r--components/script/dom/webglrenderingcontext.rs290
1 files changed, 210 insertions, 80 deletions
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 65134a631e1..bda7c036d60 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+use crate::dom::bindings::cell::Ref;
use crate::dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants;
use crate::dom::bindings::codegen::Bindings::EXTBlendMinmaxBinding::EXTBlendMinmaxConstants;
use crate::dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::OESVertexArrayObjectConstants;
@@ -26,6 +27,7 @@ use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::htmliframeelement::HTMLIFrameElement;
use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage};
use crate::dom::promise::Promise;
+use crate::dom::vertexarrayobject::VertexAttribData;
use crate::dom::webgl_extensions::WebGLExtensions;
use crate::dom::webgl_validations::tex_image_2d::{
CommonCompressedTexImage2DValidatorResult, CommonTexImage2DValidator,
@@ -47,6 +49,7 @@ use crate::dom::webglshader::WebGLShader;
use crate::dom::webglshaderprecisionformat::WebGLShaderPrecisionFormat;
use crate::dom::webgltexture::{TexParameterValue, WebGLTexture};
use crate::dom::webgluniformlocation::WebGLUniformLocation;
+use crate::dom::webglvertexarrayobject::WebGLVertexArrayObject;
use crate::dom::webglvertexarrayobjectoes::WebGLVertexArrayObjectOES;
use crate::dom::window::Window;
use crate::script_runtime::JSContext as SafeJSContext;
@@ -183,6 +186,8 @@ pub struct WebGLRenderingContext {
capabilities: Capabilities,
default_vao: DomOnceCell<WebGLVertexArrayObjectOES>,
current_vao: MutNullableDom<WebGLVertexArrayObjectOES>,
+ default_vao_webgl2: DomOnceCell<WebGLVertexArrayObject>,
+ current_vao_webgl2: MutNullableDom<WebGLVertexArrayObject>,
textures: Textures,
api_type: GlType,
}
@@ -242,6 +247,8 @@ impl WebGLRenderingContext {
capabilities: Default::default(),
default_vao: Default::default(),
current_vao: Default::default(),
+ default_vao_webgl2: Default::default(),
+ current_vao_webgl2: Default::default(),
textures: Textures::new(max_combined_texture_image_units),
api_type: ctx_data.api_type,
}
@@ -294,6 +301,15 @@ impl WebGLRenderingContext {
})
}
+ pub fn current_vao_webgl2(&self) -> DomRoot<WebGLVertexArrayObject> {
+ self.current_vao_webgl2.or_init(|| {
+ DomRoot::from_ref(
+ self.default_vao_webgl2
+ .init_once(|| WebGLVertexArrayObject::new(self, None)),
+ )
+ })
+ }
+
pub fn recreate(&self, size: Size2D<u32>) {
let (sender, receiver) = webgl_channel().unwrap();
self.webgl_sender.send_resize(size, sender).unwrap();
@@ -889,11 +905,18 @@ impl WebGLRenderingContext {
0
};
- self.current_vao().validate_for_draw(
- required_len,
- primcount as u32,
- &current_program.active_attribs(),
- )?;
+ match self.webgl_version() {
+ WebGLVersion::WebGL1 => self.current_vao().validate_for_draw(
+ required_len,
+ primcount as u32,
+ &current_program.active_attribs(),
+ )?,
+ WebGLVersion::WebGL2 => self.current_vao_webgl2().validate_for_draw(
+ required_len,
+ primcount as u32,
+ &current_program.active_attribs(),
+ )?,
+ };
self.validate_framebuffer()?;
@@ -950,11 +973,11 @@ impl WebGLRenderingContext {
}
let current_program = self.current_program.get().ok_or(InvalidOperation)?;
- let array_buffer = self
- .current_vao()
- .element_array_buffer()
- .get()
- .ok_or(InvalidOperation)?;
+ let array_buffer = match self.webgl_version() {
+ WebGLVersion::WebGL1 => self.current_vao().element_array_buffer().get(),
+ WebGLVersion::WebGL2 => self.current_vao_webgl2().element_array_buffer().get(),
+ }
+ .ok_or(InvalidOperation)?;
if count > 0 && primcount > 0 {
// This operation cannot overflow in u64 and we know all those values are nonnegative.
@@ -965,11 +988,18 @@ impl WebGLRenderingContext {
}
// TODO(nox): Pass the correct number of vertices required.
- self.current_vao().validate_for_draw(
- 0,
- primcount as u32,
- &current_program.active_attribs(),
- )?;
+ match self.webgl_version() {
+ WebGLVersion::WebGL1 => self.current_vao().validate_for_draw(
+ 0,
+ primcount as u32,
+ &current_program.active_attribs(),
+ )?,
+ WebGLVersion::WebGL2 => self.current_vao_webgl2().validate_for_draw(
+ 0,
+ primcount as u32,
+ &current_program.active_attribs(),
+ )?,
+ };
self.validate_framebuffer()?;
@@ -1003,7 +1033,12 @@ impl WebGLRenderingContext {
return self.webgl_error(InvalidValue);
}
- self.current_vao().vertex_attrib_divisor(index, divisor);
+ match self.webgl_version() {
+ WebGLVersion::WebGL1 => self.current_vao().vertex_attrib_divisor(index, divisor),
+ WebGLVersion::WebGL2 => self
+ .current_vao_webgl2()
+ .vertex_attrib_divisor(index, divisor),
+ };
self.send_command(WebGLCommand::VertexAttribDivisor { index, divisor });
}
@@ -1066,6 +1101,15 @@ impl WebGLRenderingContext {
.map(|id| WebGLVertexArrayObjectOES::new(self, Some(id)))
}
+ pub fn create_vertex_array_webgl2(&self) -> Option<DomRoot<WebGLVertexArrayObject>> {
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.send_command(WebGLCommand::CreateVertexArray(sender));
+ receiver
+ .recv()
+ .unwrap()
+ .map(|id| WebGLVertexArrayObject::new(self, Some(id)))
+ }
+
pub fn delete_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) {
if let Some(vao) = vao {
handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
@@ -1084,6 +1128,24 @@ impl WebGLRenderingContext {
}
}
+ pub fn delete_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) {
+ if let Some(vao) = vao {
+ handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
+ // The default vertex array has no id and should never be passed around.
+ assert!(vao.id().is_some());
+ if vao.is_deleted() {
+ return;
+ }
+ if vao == &*self.current_vao_webgl2() {
+ // Setting it to None will make self.current_vao() reset it to the default one
+ // next time it is called.
+ self.current_vao_webgl2.set(None);
+ self.send_command(WebGLCommand::BindVertexArray(None));
+ }
+ vao.delete(false);
+ }
+ }
+
pub fn is_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) -> bool {
vao.map_or(false, |vao| {
// The default vertex array has no id and should never be passed around.
@@ -1092,6 +1154,14 @@ impl WebGLRenderingContext {
})
}
+ pub fn is_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) -> bool {
+ vao.map_or(false, |vao| {
+ // The default vertex array has no id and should never be passed around.
+ assert!(vao.id().is_some());
+ self.validate_ownership(vao).is_ok() && vao.ever_bound() && !vao.is_deleted()
+ })
+ }
+
pub fn bind_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) {
if let Some(vao) = vao {
// The default vertex array has no id and should never be passed around.
@@ -1108,6 +1178,22 @@ impl WebGLRenderingContext {
self.current_vao.set(vao);
}
+ pub fn bind_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) {
+ if let Some(vao) = vao {
+ // The default vertex array has no id and should never be passed around.
+ assert!(vao.id().is_some());
+ handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
+ if vao.is_deleted() {
+ return self.webgl_error(InvalidOperation);
+ }
+ vao.set_ever_bound();
+ }
+ self.send_command(WebGLCommand::BindVertexArray(vao.and_then(|vao| vao.id())));
+ // Setting it to None will make self.current_vao() reset it to the default one
+ // next time it is called.
+ self.current_vao_webgl2.set(vao);
+ }
+
fn validate_blend_mode(&self, mode: u32) -> WebGLResult<()> {
match mode {
constants::FUNC_ADD | constants::FUNC_SUBTRACT | constants::FUNC_REVERSE_SUBTRACT => {
@@ -2552,9 +2638,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
if attrib_id >= self.limits.max_vertex_attribs {
return self.webgl_error(InvalidValue);
}
-
- self.current_vao()
- .enabled_vertex_attrib_array(attrib_id, true);
+ match self.webgl_version() {
+ WebGLVersion::WebGL1 => self
+ .current_vao()
+ .enabled_vertex_attrib_array(attrib_id, true),
+ WebGLVersion::WebGL2 => self
+ .current_vao_webgl2()
+ .enabled_vertex_attrib_array(attrib_id, true),
+ };
self.send_command(WebGLCommand::EnableVertexAttribArray(attrib_id));
}
@@ -2563,9 +2654,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
if attrib_id >= self.limits.max_vertex_attribs {
return self.webgl_error(InvalidValue);
}
-
- self.current_vao()
- .enabled_vertex_attrib_array(attrib_id, false);
+ match self.webgl_version() {
+ WebGLVersion::WebGL1 => self
+ .current_vao()
+ .enabled_vertex_attrib_array(attrib_id, false),
+ WebGLVersion::WebGL2 => self
+ .current_vao_webgl2()
+ .enabled_vertex_attrib_array(attrib_id, false),
+ };
self.send_command(WebGLCommand::DisableVertexAttribArray(attrib_id));
}
@@ -2890,56 +2986,73 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
#[allow(unsafe_code)]
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn GetVertexAttrib(&self, cx: SafeJSContext, index: u32, param: u32) -> JSVal {
- let current_vao = self.current_vao();
- let data = handle_potential_webgl_error!(
- self,
- current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
- return NullValue()
- );
- if param == constants::CURRENT_VERTEX_ATTRIB {
- let value = if index == 0 {
- let (x, y, z, w) = self.current_vertex_attrib_0.get();
- [x, y, z, w]
- } else {
- let (sender, receiver) = webgl_channel().unwrap();
- self.send_command(WebGLCommand::GetCurrentVertexAttrib(index, sender));
- receiver.recv().unwrap()
- };
- unsafe {
- 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());
+ let get_attrib = |data: Ref<VertexAttribData>| -> JSVal {
+ if param == constants::CURRENT_VERTEX_ATTRIB {
+ let value = if index == 0 {
+ let (x, y, z, w) = self.current_vertex_attrib_0.get();
+ [x, y, z, w]
+ } else {
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.send_command(WebGLCommand::GetCurrentVertexAttrib(index, sender));
+ receiver.recv().unwrap()
+ };
+ unsafe {
+ 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();
}
- }
- if !self
- .extension_manager
- .is_get_vertex_attrib_name_enabled(param)
- {
- self.webgl_error(WebGLError::InvalidEnum);
- return NullValue();
- }
+ match param {
+ constants::VERTEX_ATTRIB_ARRAY_ENABLED => BooleanValue(data.enabled_as_array),
+ constants::VERTEX_ATTRIB_ARRAY_SIZE => Int32Value(data.size as i32),
+ constants::VERTEX_ATTRIB_ARRAY_TYPE => Int32Value(data.type_ as i32),
+ constants::VERTEX_ATTRIB_ARRAY_NORMALIZED => BooleanValue(data.normalized),
+ constants::VERTEX_ATTRIB_ARRAY_STRIDE => Int32Value(data.stride as i32),
+ constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING => unsafe {
+ rooted!(in(*cx) let mut jsval = NullValue());
+ if let Some(buffer) = data.buffer() {
+ buffer.to_jsval(*cx, jsval.handle_mut());
+ }
+ jsval.get()
+ },
+ ANGLEInstancedArraysConstants::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE => {
+ UInt32Value(data.divisor)
+ },
+ _ => {
+ self.webgl_error(InvalidEnum);
+ NullValue()
+ },
+ }
+ };
- match param {
- constants::VERTEX_ATTRIB_ARRAY_ENABLED => BooleanValue(data.enabled_as_array),
- constants::VERTEX_ATTRIB_ARRAY_SIZE => Int32Value(data.size as i32),
- constants::VERTEX_ATTRIB_ARRAY_TYPE => Int32Value(data.type_ as i32),
- constants::VERTEX_ATTRIB_ARRAY_NORMALIZED => BooleanValue(data.normalized),
- constants::VERTEX_ATTRIB_ARRAY_STRIDE => Int32Value(data.stride as i32),
- constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING => unsafe {
- rooted!(in(*cx) let mut jsval = NullValue());
- if let Some(buffer) = data.buffer() {
- buffer.to_jsval(*cx, jsval.handle_mut());
- }
- jsval.get()
- },
- ANGLEInstancedArraysConstants::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE => {
- UInt32Value(data.divisor)
+ match self.webgl_version() {
+ WebGLVersion::WebGL1 => {
+ let current_vao = self.current_vao();
+ let data = handle_potential_webgl_error!(
+ self,
+ current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
+ return NullValue()
+ );
+ get_attrib(data)
},
- _ => {
- self.webgl_error(InvalidEnum);
- NullValue()
+ WebGLVersion::WebGL2 => {
+ let current_vao = self.current_vao_webgl2();
+ let data = handle_potential_webgl_error!(
+ self,
+ current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
+ return NullValue()
+ );
+ get_attrib(data)
},
}
}
@@ -2950,13 +3063,26 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
self.webgl_error(InvalidEnum);
return 0;
}
- let vao = self.current_vao();
- let data = handle_potential_webgl_error!(
- self,
- vao.get_vertex_attrib(index).ok_or(InvalidValue),
- return 0
- );
- data.offset as i64
+ match self.webgl_version() {
+ WebGLVersion::WebGL1 => {
+ let current_vao = self.current_vao();
+ let data = handle_potential_webgl_error!(
+ self,
+ current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
+ return 0
+ );
+ data.offset as i64
+ },
+ WebGLVersion::WebGL2 => {
+ let current_vao = self.current_vao_webgl2();
+ let data = handle_potential_webgl_error!(
+ self,
+ current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
+ return 0
+ );
+ data.offset as i64
+ },
+ }
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
@@ -3819,11 +3945,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
stride: i32,
offset: i64,
) {
- handle_potential_webgl_error!(
- self,
- self.current_vao()
- .vertex_attrib_pointer(index, size, type_, normalized, stride, offset)
- );
+ let res = match self.webgl_version() {
+ WebGLVersion::WebGL1 => self
+ .current_vao()
+ .vertex_attrib_pointer(index, size, type_, normalized, stride, offset),
+ WebGLVersion::WebGL2 => self
+ .current_vao_webgl2()
+ .vertex_attrib_pointer(index, size, type_, normalized, stride, offset),
+ };
+ handle_potential_webgl_error!(self, res);
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4