diff options
author | Imanol Fernandez <mortimergoro@gmail.com> | 2017-05-16 11:14:23 +0200 |
---|---|---|
committer | Imanol Fernandez <mortimergoro@gmail.com> | 2017-05-18 18:44:07 +0200 |
commit | 32e23c4db4a80f8ebe01bead141c5ca04bc6b215 (patch) | |
tree | 3062608b9ac6441f73d6507ebe4d25100e2676d1 /components/script/dom/webglrenderingcontext.rs | |
parent | ac99a48aeaa184d3acdb39d249636a140c4b7393 (diff) | |
download | servo-32e23c4db4a80f8ebe01bead141c5ca04bc6b215.tar.gz servo-32e23c4db4a80f8ebe01bead141c5ca04bc6b215.zip |
Implement WebGL extensions.
Diffstat (limited to 'components/script/dom/webglrenderingcontext.rs')
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 335 |
1 files changed, 319 insertions, 16 deletions
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 1826a877331..9b144f91572 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -4,7 +4,10 @@ use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; use canvas_traits::{CanvasCommonMsg, CanvasMsg, byte_swap, multiply_u8_pixel}; +use core::cell::Ref; +use core::iter::FromIterator; use core::nonzero::NonZero; +use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{self, WebGLContextAttributes}; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods; @@ -20,6 +23,7 @@ use dom::globalscope::GlobalScope; use dom::htmlcanvaselement::HTMLCanvasElement; use dom::htmlcanvaselement::utils as canvas_utils; use dom::node::{Node, NodeDamage, window_from_node}; +use dom::webgl_extensions::WebGLExtensions; use dom::webgl_validations::WebGLValidator; use dom::webgl_validations::tex_image_2d::{CommonTexImage2DValidator, CommonTexImage2DValidatorResult}; use dom::webgl_validations::tex_image_2d::{TexImage2DValidator, TexImage2DValidatorResult}; @@ -37,6 +41,7 @@ use dom::webgluniformlocation::WebGLUniformLocation; use dom::window::Window; use dom_struct::dom_struct; use euclid::size::Size2D; +use half::f16; use ipc_channel::ipc::{self, IpcSender}; use js::conversions::ConversionBehavior; use js::jsapi::{JSContext, JSObject, Type, Rooted}; @@ -47,6 +52,7 @@ use net_traits::image_cache::ImageResponse; use offscreen_gl_context::{GLContextAttributes, GLLimits}; use script_traits::ScriptMsg as ConstellationMsg; use std::cell::Cell; +use std::collections::HashMap; use webrender_traits; use webrender_traits::{WebGLCommand, WebGLError, WebGLFramebufferBindingRequest, WebGLParameter}; use webrender_traits::WebGLError::*; @@ -143,6 +149,7 @@ pub struct WebGLRenderingContext { bound_texture_cube_map: MutNullableJS<WebGLTexture>, bound_buffer_array: MutNullableJS<WebGLBuffer>, bound_buffer_element_array: MutNullableJS<WebGLBuffer>, + bound_attrib_buffers: DOMRefCell<HashMap<u32, JS<WebGLBuffer>>>, current_program: MutNullableJS<WebGLProgram>, #[ignore_heap_size_of = "Because it's small"] current_vertex_attrib_0: Cell<(f32, f32, f32, f32)>, @@ -150,6 +157,7 @@ pub struct WebGLRenderingContext { current_scissor: Cell<(i32, i32, i32, i32)>, #[ignore_heap_size_of = "Because it's small"] current_clear_color: Cell<(f32, f32, f32, f32)>, + extension_manager: WebGLExtensions } impl WebGLRenderingContext { @@ -178,11 +186,13 @@ impl WebGLRenderingContext { bound_texture_cube_map: MutNullableJS::new(None), bound_buffer_array: MutNullableJS::new(None), bound_buffer_element_array: MutNullableJS::new(None), + bound_attrib_buffers: DOMRefCell::new(HashMap::new()), bound_renderbuffer: MutNullableJS::new(None), current_program: MutNullableJS::new(None), current_vertex_attrib_0: Cell::new((0f32, 0f32, 0f32, 1f32)), current_scissor: Cell::new((0, 0, size.width, size.height)), - current_clear_color: Cell::new((0.0, 0.0, 0.0, 0.0)) + current_clear_color: Cell::new((0.0, 0.0, 0.0, 0.0)), + extension_manager: WebGLExtensions::new() } }) } @@ -221,6 +231,22 @@ impl WebGLRenderingContext { } } + pub fn borrow_bound_attrib_buffers(&self) -> Ref<HashMap<u32, JS<WebGLBuffer>>> { + self.bound_attrib_buffers.borrow() + } + + pub fn set_bound_attrib_buffers<'a, T>(&self, iter: T) where T: Iterator<Item=(u32, &'a WebGLBuffer)> { + *self.bound_attrib_buffers.borrow_mut() = HashMap::from_iter(iter.map(|(k,v)| (k, JS::from_ref(v)))); + } + + pub fn bound_buffer_element_array(&self) -> Option<Root<WebGLBuffer>> { + self.bound_buffer_element_array.get() + } + + pub fn set_bound_buffer_element_array(&self, buffer: Option<&WebGLBuffer>) { + self.bound_buffer_element_array.set(buffer); + } + pub fn recreate(&self, size: Size2D<i32>) { self.ipc_renderer.send(CanvasMsg::Common(CanvasCommonMsg::Recreate(size))).unwrap(); @@ -245,6 +271,14 @@ impl WebGLRenderingContext { self.ipc_renderer.clone() } + pub fn send_renderer_message(&self, msg: CanvasMsg) { + self.ipc_renderer.send(msg).unwrap(); + } + + pub fn get_extension_manager<'a>(&'a self) -> &'a WebGLExtensions { + &self.extension_manager + } + pub fn webgl_error(&self, err: WebGLError) { // TODO(emilio): Add useful debug messages to this warn!("WebGL error: {:?}, previous error was {:?}", err, self.last_error.get()); @@ -296,6 +330,23 @@ impl WebGLRenderingContext { }; if let Some(texture) = texture { handle_potential_webgl_error!(self, texture.tex_parameter(target, name, value)); + + // Validate non filterable TEXTURE_2D data_types + if target != constants::TEXTURE_2D { + return; + } + + let target = TexImageTarget::Texture2D; + let info = texture.image_info_for_target(&target, 0); + if info.is_initialized() { + self.validate_filterable_texture(&texture, + target, + 0, + info.internal_format().unwrap_or(TexFormat::RGBA), + info.width(), + info.height(), + info.data_type().unwrap_or(TexDataType::UnsignedByte)); + } } else { self.webgl_error(InvalidOperation) } @@ -329,6 +380,37 @@ impl WebGLRenderingContext { } } + // LINEAR filtering may be forbidden when using WebGL extensions. + // https://www.khronos.org/registry/webgl/extensions/OES_texture_float_linear/ + fn validate_filterable_texture(&self, + texture: &WebGLTexture, + target: TexImageTarget, + level: u32, + format: TexFormat, + width: u32, + height: u32, + data_type: TexDataType) + -> bool + { + if self.extension_manager.is_filterable(data_type.as_gl_constant()) || !texture.is_using_linear_filtering() { + return true; + } + + // Handle validation failed: LINEAR filtering not valid for this texture + // WebGL Conformance tests expect to fallback to [0, 0, 0, 255] RGBA UNSIGNED_BYTE + let data_type = TexDataType::UnsignedByte; + let expected_byte_length = width * height * 4; + let mut pixels = vec![0u8; expected_byte_length as usize]; + for rgba8 in pixels.chunks_mut(4) { + rgba8[3] = 255u8; + } + + let pixels = self.prepare_pixels(format, data_type, width, height, 1, true, true, pixels); + self.tex_image_2d(texture, target, data_type, format, level, width, height, 0, 1, pixels); + + false + } + fn validate_stencil_actions(&self, action: u32) -> bool { match action { 0 | constants::KEEP | constants::REPLACE | constants::INCR | constants::DECR | @@ -369,6 +451,14 @@ impl WebGLRenderingContext { true } + // https://en.wikipedia.org/wiki/Relative_luminance + #[inline] + fn luminance(r: u8, g: u8, b: u8) -> u8 { + (0.2126 * (r as f32) + + 0.7152 * (g as f32) + + 0.0722 * (b as f32)) as u8 + } + /// Translates an image in rgba8 (red in the first byte) format to /// the format that was requested of TexImage. /// @@ -391,7 +481,6 @@ impl WebGLRenderingContext { (TexFormat::RGBA, TexDataType::UnsignedByte) => pixels, (TexFormat::RGB, TexDataType::UnsignedByte) => { // Remove alpha channel - let pixel_count = pixels.len() / 4; let mut rgb8 = Vec::<u8>::with_capacity(pixel_count * 3); for rgba8 in pixels.chunks(4) { rgb8.push(rgba8[0]); @@ -400,6 +489,32 @@ impl WebGLRenderingContext { } rgb8 }, + + (TexFormat::Alpha, TexDataType::UnsignedByte) => { + let mut alpha = Vec::<u8>::with_capacity(pixel_count); + for rgba8 in pixels.chunks(4) { + alpha.push(rgba8[3]); + } + alpha + }, + + (TexFormat::Luminance, TexDataType::UnsignedByte) => { + let mut luminance = Vec::<u8>::with_capacity(pixel_count); + for rgba8 in pixels.chunks(4) { + luminance.push(Self::luminance(rgba8[0], rgba8[1], rgba8[2])); + } + luminance + }, + + (TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => { + let mut data = Vec::<u8>::with_capacity(pixel_count * 2); + for rgba8 in pixels.chunks(4) { + data.push(Self::luminance(rgba8[0], rgba8[1], rgba8[2])); + data.push(rgba8[3]); + } + data + }, + (TexFormat::RGBA, TexDataType::UnsignedShort4444) => { let mut rgba4 = Vec::<u8>::with_capacity(pixel_count * 2); for rgba8 in pixels.chunks(4) { @@ -432,10 +547,107 @@ impl WebGLRenderingContext { rgb565 } + + (TexFormat::RGBA, TexDataType::Float) => { + let mut rgbaf32 = Vec::<u8>::with_capacity(pixel_count * 16); + for rgba8 in pixels.chunks(4) { + rgbaf32.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap(); + rgbaf32.write_f32::<NativeEndian>(rgba8[1] as f32).unwrap(); + rgbaf32.write_f32::<NativeEndian>(rgba8[2] as f32).unwrap(); + rgbaf32.write_f32::<NativeEndian>(rgba8[3] as f32).unwrap(); + } + rgbaf32 + } + + (TexFormat::RGB, TexDataType::Float) => { + let mut rgbf32 = Vec::<u8>::with_capacity(pixel_count * 12); + for rgba8 in pixels.chunks(4) { + rgbf32.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap(); + rgbf32.write_f32::<NativeEndian>(rgba8[1] as f32).unwrap(); + rgbf32.write_f32::<NativeEndian>(rgba8[2] as f32).unwrap(); + } + rgbf32 + } + + (TexFormat::Alpha, TexDataType::Float) => { + let mut alpha = Vec::<u8>::with_capacity(pixel_count * 4); + for rgba8 in pixels.chunks(4) { + alpha.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap(); + } + alpha + }, + + (TexFormat::Luminance, TexDataType::Float) => { + let mut luminance = Vec::<u8>::with_capacity(pixel_count * 4); + for rgba8 in pixels.chunks(4) { + let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]); + luminance.write_f32::<NativeEndian>(p as f32).unwrap(); + } + luminance + }, + + (TexFormat::LuminanceAlpha, TexDataType::Float) => { + let mut data = Vec::<u8>::with_capacity(pixel_count * 8); + for rgba8 in pixels.chunks(4) { + let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]); + data.write_f32::<NativeEndian>(p as f32).unwrap(); + data.write_f32::<NativeEndian>(rgba8[3] as f32).unwrap(); + } + data + }, + + (TexFormat::RGBA, TexDataType::HalfFloat) => { + let mut rgbaf16 = Vec::<u8>::with_capacity(pixel_count * 8); + for rgba8 in pixels.chunks(4) { + rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[0] as f32).as_bits()).unwrap(); + rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[1] as f32).as_bits()).unwrap(); + rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[2] as f32).as_bits()).unwrap(); + rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()).unwrap(); + } + rgbaf16 + }, + + (TexFormat::RGB, TexDataType::HalfFloat) => { + let mut rgbf16 = Vec::<u8>::with_capacity(pixel_count * 6); + for rgba8 in pixels.chunks(4) { + rgbf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[0] as f32).as_bits()).unwrap(); + rgbf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[1] as f32).as_bits()).unwrap(); + rgbf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[2] as f32).as_bits()).unwrap(); + } + rgbf16 + }, + + (TexFormat::Alpha, TexDataType::HalfFloat) => { + let mut alpha = Vec::<u8>::with_capacity(pixel_count * 2); + for rgba8 in pixels.chunks(4) { + alpha.write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()).unwrap(); + } + alpha + }, + + (TexFormat::Luminance, TexDataType::HalfFloat) => { + let mut luminance = Vec::<u8>::with_capacity(pixel_count * 4); + for rgba8 in pixels.chunks(4) { + let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]); + luminance.write_u16::<NativeEndian>(f16::from_f32(p as f32).as_bits()).unwrap(); + } + luminance + }, + + (TexFormat::LuminanceAlpha, TexDataType::HalfFloat) => { + let mut data = Vec::<u8>::with_capacity(pixel_count * 8); + for rgba8 in pixels.chunks(4) { + let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]); + data.write_u16::<NativeEndian>(f16::from_f32(p as f32).as_bits()).unwrap(); + data.write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()).unwrap(); + } + data + }, + // Validation should have ensured that we only hit the // above cases, but we haven't turned the (format, type) // into an enum yet so there's a default case here. - _ => unreachable!() + _ => unreachable!("Unsupported formats {:?} {:?}", format, data_type) } } @@ -522,9 +734,11 @@ impl WebGLRenderingContext { // If it is UNSIGNED_BYTE, a Uint8Array must be supplied; // if it is UNSIGNED_SHORT_5_6_5, UNSIGNED_SHORT_4_4_4_4, // or UNSIGNED_SHORT_5_5_5_1, a Uint16Array must be supplied. + // or FLOAT, a Float32Array must be supplied. // If the types do not match, an INVALID_OPERATION error is generated. typedarray!(in(cx) let typedarray_u8: Uint8Array = data); typedarray!(in(cx) let typedarray_u16: Uint16Array = data); + typedarray!(in(cx) let typedarray_f32: Float32Array = data); let received_size = if data.is_null() { element_size } else { @@ -532,6 +746,8 @@ impl WebGLRenderingContext { 2 } else if typedarray_u8.is_ok() { 1 + } else if typedarray_f32.is_ok() { + 4 } else { self.webgl_error(InvalidOperation); return Err(()); @@ -700,7 +916,7 @@ impl WebGLRenderingContext { } fn tex_image_2d(&self, - texture: Root<WebGLTexture>, + texture: &WebGLTexture, target: TexImageTarget, data_type: TexDataType, internal_format: TexFormat, @@ -728,12 +944,17 @@ impl WebGLRenderingContext { .send(CanvasMsg::WebGL(WebGLCommand::PixelStorei(constants::UNPACK_ALIGNMENT, unpacking_alignment as i32))) .unwrap(); + let format = internal_format.as_gl_constant(); + let data_type = data_type.as_gl_constant(); + let internal_format = self.extension_manager.get_effective_tex_internal_format(format, data_type); + // TODO(emilio): convert colorspace if requested let msg = WebGLCommand::TexImage2D(target.as_gl_constant(), level as i32, - internal_format.as_gl_constant() as i32, + internal_format as i32, width as i32, height as i32, - internal_format.as_gl_constant(), - data_type.as_gl_constant(), pixels); + format, + data_type, + pixels); self.ipc_renderer .send(CanvasMsg::WebGL(msg)) @@ -807,6 +1028,14 @@ impl WebGLRenderingContext { }, } } + + fn get_gl_extensions(&self) -> String { + let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap(); + self.ipc_renderer + .send(CanvasMsg::WebGL(WebGLCommand::GetExtensions(sender))) + .unwrap(); + receiver.recv().unwrap() + } } impl Drop for WebGLRenderingContext { @@ -958,6 +1187,19 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { _ => {} } + // Handle GetParameter getters injected via WebGL extensions + if let Some(query_handler) = self.extension_manager.get_query_parameter_handler(parameter) { + match query_handler(cx, &self) { + Ok(value) => { + return value; + }, + Err(error) => { + self.webgl_error(error); + return NullValue(); + } + } + } + let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap(); self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::GetParameter(parameter, sender))) @@ -1019,14 +1261,21 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.14 fn GetSupportedExtensions(&self) -> Option<Vec<DOMString>> { - Some(vec![]) + self.extension_manager.init_once(|| { + self.get_gl_extensions() + }); + let extensions = self.extension_manager.get_suported_extensions(); + Some(extensions.iter().map(|name| DOMString::from(*name)).collect()) } #[allow(unsafe_code)] // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.14 - unsafe fn GetExtension(&self, _cx: *mut JSContext, _name: DOMString) + unsafe fn GetExtension(&self, _cx: *mut JSContext, name: DOMString) -> Option<NonZero<*mut JSObject>> { - None + self.extension_manager.init_once(|| { + self.get_gl_extensions() + }); + self.extension_manager.get_or_init_extension(&name, self) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 @@ -1627,6 +1876,23 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 fn DeleteBuffer(&self, buffer: Option<&WebGLBuffer>) { if let Some(buffer) = buffer { + if buffer.is_attached_to_vao() { + // WebGL spec: The buffers attached to VAOs should still not be deleted. + // They are deleted after the VAO is deleted. + buffer.set_pending_delete(); + return; + } + + // Remove deleted buffer from bound attrib buffers. + let attrib_ids: Vec<_> = self.bound_attrib_buffers.borrow().iter() + .filter(|&(_, v)| v.id() == buffer.id()) + .map(|(&k, _)| k) + .collect(); + for id in attrib_ids { + self.bound_attrib_buffers.borrow_mut().remove(&id); + } + + // Delete buffer. handle_object_deletion!(self, self.bound_buffer_array, buffer, Some(WebGLCommand::BindBuffer(constants::ARRAY_BUFFER, None))); handle_object_deletion!(self, self.bound_buffer_element_array, buffer, @@ -1989,6 +2255,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return result.get() } + if pname == constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING { + rooted!(in(cx) let mut jsval = NullValue()); + if let Some(buffer) = self.bound_attrib_buffers.borrow().get(&index) { + buffer.to_jsval(cx, jsval.handle_mut()); + } + return jsval.get(); + } + let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap(); self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::GetVertexAttrib(index, pname, sender))).unwrap(); @@ -2006,6 +2280,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } } + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 + fn GetVertexAttribOffset(&self, index: u32, pname: u32) -> i64 { + let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap(); + self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::GetVertexAttribOffset(index, pname, sender))).unwrap(); + + handle_potential_webgl_error!(self, receiver.recv().unwrap(), 0) as i64 + } + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn Hint(&self, target: u32, mode: u32) { if target != constants::GENERATE_MIPMAP_HINT { @@ -2784,9 +3066,13 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if size < 1 || size > 4 { return self.webgl_error(InvalidValue); } - if self.bound_buffer_array.get().is_none() { - return self.webgl_error(InvalidOperation); - } + + let buffer_array = match self.bound_buffer_array.get() { + Some(buffer) => buffer, + None => { + return self.webgl_error(InvalidOperation); + } + }; // stride and offset must be multiple of data_type match data_type { @@ -2805,6 +3091,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } + self.bound_attrib_buffers.borrow_mut().insert(attrib_id, JS::from_ref(&*buffer_array)); + let msg = CanvasMsg::WebGL( WebGLCommand::VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset as u32)); self.ipc_renderer.send(msg).unwrap() @@ -2834,6 +3122,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { format: u32, data_type: u32, data_ptr: *mut JSObject) -> Fallible<()> { + if !self.extension_manager.is_tex_type_enabled(data_type) { + return Ok(self.webgl_error(InvalidEnum)); + } + let data = if data_ptr.is_null() { None } else { @@ -2885,10 +3177,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return Ok(self.webgl_error(InvalidOperation)); } + if !self.validate_filterable_texture(&texture, target, level, format, width, height, data_type) { + return Ok(()); // The validator sets the correct error for use + } + let pixels = self.prepare_pixels(format, data_type, width, height, unpacking_alignment, false, false, buff); - self.tex_image_2d(texture, target, data_type, format, + self.tex_image_2d(&texture, target, data_type, format, level, width, height, border, unpacking_alignment, pixels); Ok(()) @@ -2902,6 +3198,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { format: u32, data_type: u32, source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement>) -> Fallible<()> { + if !self.extension_manager.is_tex_type_enabled(data_type) { + return Ok(self.webgl_error(InvalidEnum)); + } + // Get pixels from image source let (pixels, size, premultiplied) = match self.get_image_pixels(source) { Ok((pixels, size, premultiplied)) => (pixels, size, premultiplied), @@ -2927,11 +3227,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { Err(_) => return Ok(()), // NB: The validator sets the correct error for us. }; + if !self.validate_filterable_texture(&texture, target, level, format, width, height, data_type) { + return Ok(()); // The validator sets the correct error for use + } + let unpacking_alignment = 1; let pixels = self.prepare_pixels(format, data_type, width, height, unpacking_alignment, premultiplied, true, pixels); - self.tex_image_2d(texture, target, data_type, format, + self.tex_image_2d(&texture, target, data_type, format, level, width, height, border, 1, pixels); Ok(()) } @@ -2955,7 +3259,6 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { Some(try!(fallible_array_buffer_view_to_vec(cx, data_ptr))) }; - let validator = TexImage2DValidator::new(self, target, level, format, width, height, 0, format, data_type); |