1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use canvas_traits::webgl::{webgl_channel, WebGLCommand, WebGLError, WebGLVersion}; 6 use dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::{self, OESVertexArrayObjectMethods}; 7 use dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::OESVertexArrayObjectConstants; 8 use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; 9 use dom::bindings::root::{Dom, DomRoot, MutNullableDom}; 10 use dom::webglrenderingcontext::WebGLRenderingContext; 11 use dom::webglvertexarrayobjectoes::WebGLVertexArrayObjectOES; 12 use dom_struct::dom_struct; 13 use js::conversions::ToJSValConvertible; 14 use js::jsapi::JSContext; 15 use js::jsval::{JSVal, NullValue}; 16 use std::iter; 17 use super::{WebGLExtension, WebGLExtensions, WebGLExtensionSpec}; 18 19 #[dom_struct] 20 pub struct OESVertexArrayObject { 21 reflector_: Reflector, 22 ctx: Dom<WebGLRenderingContext>, 23 bound_vao: MutNullableDom<WebGLVertexArrayObjectOES>, 24 } 25 26 impl OESVertexArrayObject { new_inherited(ctx: &WebGLRenderingContext) -> OESVertexArrayObject27 fn new_inherited(ctx: &WebGLRenderingContext) -> OESVertexArrayObject { 28 Self { 29 reflector_: Reflector::new(), 30 ctx: Dom::from_ref(ctx), 31 bound_vao: MutNullableDom::new(None) 32 } 33 } 34 35 #[allow(unsafe_code)] get_current_binding(&self, cx:*mut JSContext) -> JSVal36 fn get_current_binding(&self, cx:*mut JSContext) -> JSVal { 37 rooted!(in(cx) let mut rval = NullValue()); 38 if let Some(bound_vao) = self.bound_vao.get() { 39 unsafe { 40 bound_vao.to_jsval(cx, rval.handle_mut()); 41 } 42 } 43 rval.get() 44 } 45 } 46 47 impl OESVertexArrayObjectMethods for OESVertexArrayObject { 48 // https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/ CreateVertexArrayOES(&self) -> Option<DomRoot<WebGLVertexArrayObjectOES>>49 fn CreateVertexArrayOES(&self) -> Option<DomRoot<WebGLVertexArrayObjectOES>> { 50 let (sender, receiver) = webgl_channel().unwrap(); 51 self.ctx.send_command(WebGLCommand::CreateVertexArray(sender)); 52 53 let result = receiver.recv().unwrap(); 54 result.map(|vao_id| WebGLVertexArrayObjectOES::new(&self.global(), vao_id)) 55 } 56 57 // https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/ DeleteVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>)58 fn DeleteVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>) { 59 if let Some(vao) = vao { 60 if vao.is_deleted() { 61 return; 62 } 63 64 // Unbind deleted VAO if currently bound 65 if let Some(bound_vao) = self.bound_vao.get() { 66 if bound_vao.id() == vao.id() { 67 self.bound_vao.set(None); 68 self.ctx.send_command(WebGLCommand::BindVertexArray(None)); 69 } 70 } 71 72 // Remove VAO references from buffers 73 let buffers = vao.bound_attrib_buffers(); 74 for buffer in buffers { 75 buffer.remove_vao_reference(vao.id()); 76 } 77 if let Some(buffer) = vao.bound_buffer_element_array() { 78 buffer.remove_vao_reference(vao.id()); 79 } 80 81 // Delete the vao 82 self.ctx.send_command(WebGLCommand::DeleteVertexArray(vao.id())); 83 vao.set_deleted(); 84 } 85 } 86 87 // https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/ IsVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>) -> bool88 fn IsVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>) -> bool { 89 // Conformance tests expect false if vao never bound 90 vao.map_or(false, |vao| !vao.is_deleted() && vao.ever_bound()) 91 } 92 93 // https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/ BindVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>)94 fn BindVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>) { 95 if let Some(bound_vao) = self.bound_vao.get() { 96 // Store buffers attached to attrib pointers 97 let buffers = self.ctx.borrow_bound_attrib_buffers(); 98 bound_vao.set_bound_attrib_buffers(buffers.iter().map(|(key, buffer)| { 99 (*buffer).add_vao_reference(bound_vao.id()); 100 (*key, &**buffer) 101 })); 102 // Store element array buffer 103 let element_array = self.ctx.bound_buffer_element_array(); 104 bound_vao.set_bound_buffer_element_array(element_array.as_ref().map(|buffer| { 105 buffer.add_vao_reference(bound_vao.id()); 106 &**buffer 107 })); 108 } 109 110 if let Some(vao) = vao { 111 if vao.is_deleted() { 112 self.ctx.webgl_error(WebGLError::InvalidOperation); 113 return; 114 } 115 116 self.ctx.send_command(WebGLCommand::BindVertexArray(Some(vao.id()))); 117 vao.set_ever_bound(); 118 self.bound_vao.set(Some(&vao)); 119 120 // Restore WebGLRenderingContext current bindings 121 let buffers = vao.borrow_bound_attrib_buffers(); 122 self.ctx.set_bound_attrib_buffers(buffers.iter().map(|(k, v)| (*k, &**v))); 123 let element_array = vao.bound_buffer_element_array(); 124 self.ctx.set_bound_buffer_element_array(element_array.as_ref().map(|buffer| &**buffer)); 125 } else { 126 self.ctx.send_command(WebGLCommand::BindVertexArray(None)); 127 self.bound_vao.set(None); 128 self.ctx.set_bound_attrib_buffers(iter::empty()); 129 } 130 } 131 } 132 133 impl WebGLExtension for OESVertexArrayObject { 134 type Extension = OESVertexArrayObject; new(ctx: &WebGLRenderingContext) -> DomRoot<OESVertexArrayObject>135 fn new(ctx: &WebGLRenderingContext) -> DomRoot<OESVertexArrayObject> { 136 reflect_dom_object(Box::new(OESVertexArrayObject::new_inherited(ctx)), 137 &*ctx.global(), 138 OESVertexArrayObjectBinding::Wrap) 139 } 140 spec() -> WebGLExtensionSpec141 fn spec() -> WebGLExtensionSpec { 142 WebGLExtensionSpec::Specific(WebGLVersion::WebGL1) 143 } 144 is_supported(ext: &WebGLExtensions) -> bool145 fn is_supported(ext: &WebGLExtensions) -> bool { 146 ext.supports_any_gl_extension(&["GL_OES_vertex_array_object", 147 "GL_ARB_vertex_array_object", 148 "GL_APPLE_vertex_array_object"]) 149 } 150 enable(ext: &WebGLExtensions)151 fn enable(ext: &WebGLExtensions) { 152 let query = OESVertexArrayObjectConstants::VERTEX_ARRAY_BINDING_OES; 153 ext.add_query_parameter_handler(query, Box::new(|cx, webgl_ctx| { 154 match webgl_ctx.get_extension_manager().get_dom_object::<OESVertexArrayObject>() { 155 Some(dom_object) => { 156 Ok(dom_object.get_current_binding(cx)) 157 }, 158 None => { 159 // Extension instance not found! 160 Err(WebGLError::InvalidOperation) 161 } 162 } 163 })); 164 } 165 name() -> &'static str166 fn name() -> &'static str { 167 "OES_vertex_array_object" 168 } 169 } 170