aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/webglrenderingcontext.rs
diff options
context:
space:
mode:
authorAnthony Ramine <n.oxyde@gmail.com>2018-08-03 15:18:17 +0200
committerAnthony Ramine <n.oxyde@gmail.com>2018-08-23 15:15:33 +0200
commit8b1c753c6c7bb6359e9cfb27ada86185a966dce1 (patch)
tree5fa54dc4116d4005df53cf3c39a31298e4689636 /components/script/dom/webglrenderingcontext.rs
parent73df3ad2ea27c562311993599e1af9f9b4232ee9 (diff)
downloadservo-8b1c753c6c7bb6359e9cfb27ada86185a966dce1.tar.gz
servo-8b1c753c6c7bb6359e9cfb27ada86185a966dce1.zip
Properly check limit in gl.activeTexture()
Diffstat (limited to 'components/script/dom/webglrenderingcontext.rs')
-rw-r--r--components/script/dom/webglrenderingcontext.rs292
1 files changed, 153 insertions, 139 deletions
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index e265c83aa90..3c2f5f459cb 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -10,7 +10,6 @@ use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSen
use canvas_traits::webgl::{WebGLProgramId, WebGLResult, WebGLSLVersion, WebGLSender};
use canvas_traits::webgl::{WebGLVersion, 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::OESVertexArrayObjectBinding::OESVertexArrayObjectConstants;
@@ -52,7 +51,6 @@ use dom::webglvertexarrayobjectoes::WebGLVertexArrayObjectOES;
use dom::window::Window;
use dom_struct::dom_struct;
use euclid::Size2D;
-use fnv::FnvHashMap;
use half::f16;
use js::jsapi::{JSContext, JSObject, Type};
use js::jsval::{BooleanValue, DoubleValue, Int32Value, UInt32Value, JSVal};
@@ -135,41 +133,6 @@ bitflags! {
}
}
-/// Information about the bound textures of a WebGL texture unit.
-#[must_root]
-#[derive(JSTraceable, MallocSizeOf)]
-struct TextureUnitBindings {
- bound_texture_2d: MutNullableDom<WebGLTexture>,
- bound_texture_cube_map: MutNullableDom<WebGLTexture>,
-}
-
-impl TextureUnitBindings {
- fn new() -> Self {
- Self {
- bound_texture_2d: MutNullableDom::new(None),
- bound_texture_cube_map: MutNullableDom::new(None),
- }
- }
-
- /// Clears the slot associated to the given texture.
- /// Returns the GL target of the cleared slot, if any.
- fn clear_slot(&self, texture: &WebGLTexture) -> Option<u32> {
- let fields = [(&self.bound_texture_2d, constants::TEXTURE_2D),
- (&self.bound_texture_cube_map, constants::TEXTURE_CUBE_MAP)];
-
- fields.iter().find(|field| {
- match field.0.get() {
- Some(t) => t.id() == texture.id(),
- _ => false,
- }
- }).and_then(|field| {
- field.0.set(None);
- Some(field.1)
- })
- }
-}
-
-
#[dom_struct]
pub struct WebGLRenderingContext {
reflector_: Reflector,
@@ -189,8 +152,6 @@ pub struct WebGLRenderingContext {
texture_unpacking_alignment: Cell<u32>,
bound_framebuffer: MutNullableDom<WebGLFramebuffer>,
bound_renderbuffer: MutNullableDom<WebGLRenderbuffer>,
- bound_textures: DomRefCell<FnvHashMap<u32, TextureUnitBindings>>,
- bound_texture_unit: Cell<u32>,
bound_buffer_array: MutNullableDom<WebGLBuffer>,
current_program: MutNullableDom<WebGLProgram>,
/// https://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences#Vertex_Attribute_0
@@ -204,6 +165,7 @@ pub struct WebGLRenderingContext {
capabilities: Capabilities,
default_vao: DomOnceCell<WebGLVertexArrayObjectOES>,
current_vao: MutNullableDom<WebGLVertexArrayObjectOES>,
+ textures: Textures,
}
impl WebGLRenderingContext {
@@ -229,6 +191,7 @@ impl WebGLRenderingContext {
let result = receiver.recv().unwrap();
result.map(|ctx_data| {
+ let max_combined_texture_image_units = ctx_data.limits.max_combined_texture_image_units;
WebGLRenderingContext {
reflector_: Reflector::new(),
webgl_sender: ctx_data.sender,
@@ -242,8 +205,6 @@ impl WebGLRenderingContext {
texture_unpacking_settings: Cell::new(TextureUnpacking::CONVERT_COLORSPACE),
texture_unpacking_alignment: Cell::new(4),
bound_framebuffer: MutNullableDom::new(None),
- bound_textures: DomRefCell::new(Default::default()),
- bound_texture_unit: Cell::new(constants::TEXTURE0),
bound_buffer_array: MutNullableDom::new(None),
bound_renderbuffer: MutNullableDom::new(None),
current_program: MutNullableDom::new(None),
@@ -254,6 +215,7 @@ impl WebGLRenderingContext {
capabilities: Default::default(),
default_vao: Default::default(),
current_vao: Default::default(),
+ textures: Textures::new(max_combined_texture_image_units),
}
})
}
@@ -293,36 +255,6 @@ impl WebGLRenderingContext {
})
}
- fn bound_texture(&self, target: u32) -> Option<DomRoot<WebGLTexture>> {
- match target {
- constants::TEXTURE_2D => {
- self.bound_textures.borrow().get(&self.bound_texture_unit.get()).and_then(|t| {
- t.bound_texture_2d.get()
- })
- },
- constants::TEXTURE_CUBE_MAP => {
- self.bound_textures.borrow().get(&self.bound_texture_unit.get()).and_then(|t| {
- t.bound_texture_cube_map.get()
- })
- },
- _ => None,
- }
- }
-
- pub fn bound_texture_for_target(&self, target: &TexImageTarget) -> Option<DomRoot<WebGLTexture>> {
- self.bound_textures.borrow().get(&self.bound_texture_unit.get()).and_then(|binding| {
- match *target {
- TexImageTarget::Texture2D => binding.bound_texture_2d.get(),
- TexImageTarget::CubeMapPositiveX |
- TexImageTarget::CubeMapNegativeX |
- TexImageTarget::CubeMapPositiveY |
- TexImageTarget::CubeMapNegativeY |
- TexImageTarget::CubeMapPositiveZ |
- TexImageTarget::CubeMapNegativeZ => binding.bound_texture_cube_map.get(),
- }
- })
- }
-
pub fn recreate(&self, size: Size2D<i32>) {
let (sender, receiver) = webgl_channel().unwrap();
self.webgl_sender.send_resize(size, sender).unwrap();
@@ -348,7 +280,7 @@ impl WebGLRenderingContext {
// Right now offscreen_gl_context generates a new FBO and the bound texture is changed
// in order to create a new render to texture attachment.
// Send a command to re-bind the TEXTURE_2D, if any.
- if let Some(texture) = self.bound_texture(constants::TEXTURE_2D) {
+ if let Some(texture) = self.textures.active_texture_slot(constants::TEXTURE_2D).unwrap().get() {
self.send_command(WebGLCommand::BindTexture(constants::TEXTURE_2D, Some(texture.id())));
}
@@ -446,17 +378,21 @@ impl WebGLRenderingContext {
handle_potential_webgl_error!(self, f(location));
}
- fn tex_parameter(&self, target: u32, param: u32, value: TexParameterValue) {
- let texture = match target {
- constants::TEXTURE_2D |
- constants::TEXTURE_CUBE_MAP => self.bound_texture(target),
- _ => return self.webgl_error(InvalidEnum),
- };
+ pub fn textures(&self) -> &Textures {
+ &self.textures
+ }
- let texture = match texture {
- Some(tex) => tex,
- None => return self.webgl_error(InvalidOperation),
- };
+ fn tex_parameter(&self, target: u32, param: u32, value: TexParameterValue) {
+ let texture_slot = handle_potential_webgl_error!(
+ self,
+ self.textures.active_texture_slot(target),
+ return
+ );
+ let texture = handle_potential_webgl_error!(
+ self,
+ texture_slot.get().ok_or(InvalidOperation),
+ return
+ );
if !self.extension_manager.is_get_tex_parameter_name_enabled(param) {
return self.webgl_error(InvalidEnum);
@@ -1483,11 +1419,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
return optional_root_object_to_js_or_null!(cx, &self.bound_renderbuffer.get());
}
constants::TEXTURE_BINDING_2D => {
- let texture = self.bound_texture(constants::TEXTURE_2D);
+ let texture = self.textures.active_texture_slot(constants::TEXTURE_2D).unwrap().get();
return optional_root_object_to_js_or_null!(cx, texture);
}
constants::TEXTURE_BINDING_CUBE_MAP => {
- let texture = self.bound_texture(constants::TEXTURE_CUBE_MAP);
+ let texture = self.textures.active_texture_slot(constants::TEXTURE_CUBE_MAP).unwrap().get();
return optional_root_object_to_js_or_null!(cx, texture);
}
OESVertexArrayObjectConstants::VERTEX_ARRAY_BINDING_OES => {
@@ -1655,28 +1591,22 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
#[allow(unsafe_code)]
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
unsafe fn GetTexParameter(&self, _cx: *mut JSContext, target: u32, pname: u32) -> JSVal {
- match target {
- constants::TEXTURE_2D |
- constants::TEXTURE_CUBE_MAP => {},
- _ => {
- self.webgl_error(InvalidEnum);
- return NullValue();
- }
- };
+ let texture_slot = handle_potential_webgl_error!(
+ self,
+ self.textures.active_texture_slot(target),
+ return NullValue()
+ );
+ let texture = handle_potential_webgl_error!(
+ self,
+ texture_slot.get().ok_or(InvalidOperation),
+ return NullValue()
+ );
if !self.extension_manager.is_get_tex_parameter_name_enabled(pname) {
self.webgl_error(InvalidEnum);
return NullValue();
}
- let texture = match self.bound_texture(target) {
- Some(texture) => texture,
- None => {
- self.webgl_error(InvalidOperation);
- return NullValue();
- }
- };
-
match pname {
constants::TEXTURE_MAG_FILTER => return UInt32Value(texture.mag_filter()),
constants::TEXTURE_MIN_FILTER => return UInt32Value(texture.min_filter()),
@@ -1759,7 +1689,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
fn ActiveTexture(&self, texture: u32) {
- self.bound_texture_unit.set(texture);
+ handle_potential_webgl_error!(
+ self,
+ self.textures.set_active_unit_enum(texture),
+ return
+ );
self.send_command(WebGLCommand::ActiveTexture(texture));
}
@@ -1929,39 +1863,33 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
handle_potential_webgl_error!(self, self.validate_ownership(texture), return);
}
- let mut bound_textures = self.bound_textures.borrow_mut();
- let binding = bound_textures.entry(self.bound_texture_unit.get())
- .or_insert(TextureUnitBindings::new());
- let slot = match target {
- constants::TEXTURE_2D => &binding.bound_texture_2d,
- constants::TEXTURE_CUBE_MAP => &binding.bound_texture_cube_map,
- _ => return self.webgl_error(InvalidEnum),
- };
+ let texture_slot = handle_potential_webgl_error!(
+ self,
+ self.textures.active_texture_slot(target),
+ return
+ );
if let Some(texture) = texture {
- match texture.bind(target) {
- Ok(_) => slot.set(Some(texture)),
- Err(err) => return self.webgl_error(err),
- }
+ handle_potential_webgl_error!(self, texture.bind(target), return);
} else {
- slot.set(None);
- // Unbind the currently bound texture
self.send_command(WebGLCommand::BindTexture(target, None));
}
+ texture_slot.set(texture);
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
fn GenerateMipmap(&self, target: u32) {
- let texture = match target {
- constants::TEXTURE_2D |
- constants::TEXTURE_CUBE_MAP => self.bound_texture(target),
- _ => return self.webgl_error(InvalidEnum),
- };
-
- match texture {
- Some(texture) => handle_potential_webgl_error!(self, texture.generate_mipmap()),
- None => self.webgl_error(InvalidOperation)
- }
+ let texture_slot = handle_potential_webgl_error!(
+ self,
+ self.textures.active_texture_slot(target),
+ return
+ );
+ let texture = handle_potential_webgl_error!(
+ self,
+ texture_slot.get().ok_or(InvalidOperation),
+ return
+ );
+ handle_potential_webgl_error!(self, texture.generate_mipmap());
}
#[allow(unsafe_code)]
@@ -2367,20 +2295,22 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// zero."
//
// The same texture may be bound to multiple texture units.
- let mut bound_unit = self.bound_texture_unit.get();
- for (texture_unit, binding) in self.bound_textures.borrow().iter() {
- if let Some(target) = binding.clear_slot(texture) {
- if *texture_unit != bound_unit {
- self.send_command(WebGLCommand::ActiveTexture(*texture_unit));
- bound_unit = *texture_unit;
+ let mut active_unit_enum = self.textures.active_unit_enum();
+ for (unit_enum, slot) in self.textures.iter() {
+ if let Some(target) = slot.unbind(texture) {
+ if unit_enum != active_unit_enum {
+ self.send_command(WebGLCommand::ActiveTexture(unit_enum));
+ active_unit_enum = unit_enum;
}
self.send_command(WebGLCommand::BindTexture(target, None));
}
}
// Restore bound texture unit if it has been changed.
- if self.bound_texture_unit.get() != bound_unit {
- self.send_command(WebGLCommand::ActiveTexture(self.bound_texture_unit.get()));
+ if active_unit_enum == self.textures.active_unit_enum() {
+ self.send_command(WebGLCommand::ActiveTexture(
+ self.textures.active_unit_enum(),
+ ));
}
// From the GLES 2.0.25 spec, page 113:
@@ -2394,6 +2324,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
if let Some(fb) = self.bound_framebuffer.get() {
fb.detach_texture(texture);
}
+
texture.delete()
}
}
@@ -3944,12 +3875,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
}
// Get bound texture
- let texture = match self.bound_texture(constants::TEXTURE_2D) {
- Some(texture) => texture,
- None => {
- return Ok(self.webgl_error(InvalidOperation));
- }
- };
+ let texture = handle_potential_webgl_error!(
+ self,
+ self.textures.active_texture_slot(constants::TEXTURE_2D).unwrap().get().ok_or(InvalidOperation),
+ return Ok(())
+ );
let pipeline_id = source.pipeline_id().ok_or(Error::InvalidState)?;
let document_id = self.global().downcast::<Window>().ok_or(Error::InvalidState)?.webrender_document();
@@ -4257,3 +4187,87 @@ capabilities! {
SCISSOR_TEST,
STENCIL_TEST,
}
+
+#[must_root]
+#[derive(JSTraceable, MallocSizeOf)]
+pub struct Textures {
+ active_unit: Cell<u32>,
+ units: Box<[TextureUnit]>,
+}
+
+impl Textures {
+ fn new(max_combined_textures: u32) -> Self {
+ Self {
+ active_unit: Default::default(),
+ units: (0..max_combined_textures).map(|_| Default::default()).collect::<Vec<_>>().into(),
+ }
+ }
+
+ fn active_unit_enum(&self) -> u32 {
+ self.active_unit.get() + constants::TEXTURE0
+ }
+
+ fn set_active_unit_enum(&self, index: u32) -> WebGLResult<()> {
+ if index < constants::TEXTURE0 || (index - constants::TEXTURE0) as usize > self.units.len() {
+ return Err(InvalidEnum);
+ }
+ self.active_unit.set(index - constants::TEXTURE0);
+ Ok(())
+ }
+
+ fn active_texture_slot(&self, target: u32) -> WebGLResult<&MutNullableDom<WebGLTexture>> {
+ let active_unit = self.active_unit();
+ match target {
+ constants::TEXTURE_2D => Ok(&active_unit.tex_2d),
+ constants::TEXTURE_CUBE_MAP => Ok(&active_unit.tex_cube_map),
+ _ => Err(InvalidEnum),
+ }
+ }
+
+ pub fn active_texture_for_image_target(
+ &self,
+ target: TexImageTarget,
+ ) -> Option<DomRoot<WebGLTexture>> {
+ let active_unit = self.active_unit();
+ match target {
+ TexImageTarget::Texture2D => active_unit.tex_2d.get(),
+ TexImageTarget::CubeMapPositiveX |
+ TexImageTarget::CubeMapNegativeX |
+ TexImageTarget::CubeMapPositiveY |
+ TexImageTarget::CubeMapNegativeY |
+ TexImageTarget::CubeMapPositiveZ |
+ TexImageTarget::CubeMapNegativeZ => active_unit.tex_cube_map.get(),
+ }
+ }
+
+ fn active_unit(&self) -> &TextureUnit {
+ &self.units[self.active_unit.get() as usize]
+ }
+
+ fn iter(&self) -> impl Iterator<Item = (u32, &TextureUnit)> {
+ self.units.iter().enumerate().map(|(index, unit)| (index as u32 + constants::TEXTURE0, unit))
+ }
+}
+
+#[must_root]
+#[derive(Default, JSTraceable, MallocSizeOf)]
+struct TextureUnit {
+ tex_2d: MutNullableDom<WebGLTexture>,
+ tex_cube_map: MutNullableDom<WebGLTexture>,
+}
+
+impl TextureUnit {
+ fn unbind(&self, texture: &WebGLTexture) -> Option<u32> {
+ let fields = [
+ (&self.tex_2d, constants::TEXTURE_2D),
+ (&self.tex_cube_map, constants::TEXTURE_CUBE_MAP),
+ ];
+ for &(slot, target) in &fields {
+ if slot.get().map_or(false, |t| texture == &*t) {
+ slot.set(None);
+ return Some(target);
+ }
+ }
+ None
+ }
+}