servo: Merge #11072 - Implement IsShader fn and IsTexture fn for WebGLRenderingContext (from DDEFISHER:master); r=emilio
authorDaniel <ddefisher@gmail.com>
Tue, 10 May 2016 03:16:20 -0700
changeset 338753 76319454bcd8f64d5e134f63fd637d7763fbc6b4
parent 338752 178acc29f88caba6bf29f0d5dbc68c974aef1906
child 338754 baf7772d3cee4a6d1564e4f0c27c5eb000f0fbb5
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
servo: Merge #11072 - Implement IsShader fn and IsTexture fn for WebGLRenderingContext (from DDEFISHER:master); r=emilio fixes #11064 Source-Repo: https://github.com/servo/servo Source-Revision: f45a99c9fe5a4b05dd0d27f129d53ed1f75ea8ff
servo/components/script/dom/webglprogram.rs
servo/components/script/dom/webglrenderingcontext.rs
servo/components/script/dom/webglshader.rs
servo/components/script/dom/webgltexture.rs
servo/components/script/dom/webidls/WebGLRenderingContext.webidl
--- a/servo/components/script/dom/webglprogram.rs
+++ b/servo/components/script/dom/webglprogram.rs
@@ -63,16 +63,24 @@ impl WebGLProgram {
         self.id
     }
 
     /// glDeleteProgram
     pub fn delete(&self) {
         if !self.is_deleted.get() {
             self.is_deleted.set(true);
             let _ = self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DeleteProgram(self.id)));
+
+            if let Some(shader) = self.fragment_shader.get() {
+                shader.decrement_attached_counter();
+            }
+
+            if let Some(shader) = self.vertex_shader.get() {
+                shader.decrement_attached_counter();
+            }
         }
     }
 
     /// glLinkProgram
     pub fn link(&self) {
         self.linked.set(false);
 
         match self.fragment_shader.get() {
@@ -113,16 +121,17 @@ impl WebGLProgram {
 
         // TODO(emilio): Differentiate between same shader already assigned and other previous
         // shader.
         if shader_slot.get().is_some() {
             return Err(WebGLError::InvalidOperation);
         }
 
         shader_slot.set(Some(shader));
+        shader.increment_attached_counter();
 
         self.renderer.send(CanvasMsg::WebGL(WebGLCommand::AttachShader(self.id, shader.id()))).unwrap();
 
         Ok(())
     }
 
     /// glDetachShader
     pub fn detach_shader(&self, shader: &WebGLShader) -> WebGLResult<()> {
@@ -139,16 +148,17 @@ impl WebGLProgram {
             Some(ref attached_shader) if attached_shader.id() != shader.id() =>
                 return Err(WebGLError::InvalidOperation),
             None =>
                 return Err(WebGLError::InvalidOperation),
             _ => {}
         }
 
         shader_slot.set(None);
+        shader.decrement_attached_counter();
 
         self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DetachShader(self.id, shader.id()))).unwrap();
 
         Ok(())
     }
 
     /// glBindAttribLocation
     pub fn bind_attrib_location(&self, index: u32, name: DOMString) -> WebGLResult<()> {
--- a/servo/components/script/dom/webglrenderingcontext.rs
+++ b/servo/components/script/dom/webglrenderingcontext.rs
@@ -1152,16 +1152,26 @@ impl WebGLRenderingContextMethods for We
             _ => return self.webgl_error(InvalidEnum),
         }
 
         self.ipc_renderer
             .send(CanvasMsg::WebGL(WebGLCommand::Hint(target, mode)))
             .unwrap()
     }
 
+    // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
+    fn IsShader(&self, shader: Option<&WebGLShader>) -> bool {
+        shader.map_or(false, |s| !s.is_deleted() || s.is_attached())
+    }
+
+    // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
+    fn IsTexture(&self, texture: Option<&WebGLTexture>) -> bool {
+        texture.map_or(false, |tex| tex.target().is_some() && !tex.is_deleted())
+    }
+
     // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
     fn LineWidth(&self, width: f32) {
         if width.is_nan() || width <= 0f32 {
             return self.webgl_error(InvalidValue);
         }
 
         self.ipc_renderer
             .send(CanvasMsg::WebGL(WebGLCommand::LineWidth(width)))
--- a/servo/components/script/dom/webglshader.rs
+++ b/servo/components/script/dom/webglshader.rs
@@ -27,16 +27,17 @@ pub enum ShaderCompilationStatus {
 #[dom_struct]
 pub struct WebGLShader {
     webgl_object: WebGLObject,
     id: u32,
     gl_type: u32,
     source: DOMRefCell<Option<DOMString>>,
     info_log: DOMRefCell<Option<String>>,
     is_deleted: Cell<bool>,
+    attached_counter: Cell<u32>,
     compilation_status: Cell<ShaderCompilationStatus>,
     #[ignore_heap_size_of = "Defined in ipc-channel"]
     renderer: IpcSender<CanvasMsg>,
 }
 
 #[cfg(not(target_os = "android"))]
 const SHADER_OUTPUT_FORMAT: Output = Output::Glsl;
 
@@ -50,16 +51,17 @@ impl WebGLShader {
         GLSLANG_INITIALIZATION.call_once(|| ::angle::hl::initialize().unwrap());
         WebGLShader {
             webgl_object: WebGLObject::new_inherited(),
             id: id,
             gl_type: shader_type,
             source: DOMRefCell::new(None),
             info_log: DOMRefCell::new(None),
             is_deleted: Cell::new(false),
+            attached_counter: Cell::new(0),
             compilation_status: Cell::new(ShaderCompilationStatus::NotCompiled),
             renderer: renderer,
         }
     }
 
     pub fn maybe_new(global: GlobalRef,
                      renderer: IpcSender<CanvasMsg>,
                      shader_type: u32) -> Option<Root<WebGLShader>> {
@@ -121,23 +123,41 @@ impl WebGLShader {
             //
             // This requires a more complex interface with ANGLE, using C++
             // bindings and being extremely cautious about destructing things.
         }
     }
 
     /// Mark this shader as deleted (if it wasn't previously)
     /// and delete it as if calling glDeleteShader.
+    /// Currently does not check if shader is attached
     pub fn delete(&self) {
         if !self.is_deleted.get() {
             self.is_deleted.set(true);
             let _ = self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DeleteShader(self.id)));
         }
     }
 
+    pub fn is_deleted(&self) -> bool {
+        self.is_deleted.get()
+    }
+
+    pub fn is_attached(&self) -> bool {
+        self.attached_counter.get() > 0
+    }
+
+    pub fn increment_attached_counter(&self) {
+        self.attached_counter.set(self.attached_counter.get() + 1);
+    }
+
+    pub fn decrement_attached_counter(&self) {
+        assert!(self.attached_counter.get() > 0);
+        self.attached_counter.set(self.attached_counter.get() - 1);
+    }
+
     /// glGetShaderInfoLog
     pub fn info_log(&self) -> Option<String> {
         self.info_log.borrow().clone()
     }
 
     /// glGetParameter
     pub fn parameter(&self, param_id: u32) -> WebGLResult<WebGLParameter> {
         let (sender, receiver) = ipc::channel().unwrap();
@@ -157,11 +177,12 @@ impl WebGLShader {
 
     pub fn successfully_compiled(&self) -> bool {
         self.compilation_status.get() == ShaderCompilationStatus::Succeeded
     }
 }
 
 impl Drop for WebGLShader {
     fn drop(&mut self) {
+        assert!(self.attached_counter.get() == 0);
         self.delete();
     }
 }
--- a/servo/components/script/dom/webgltexture.rs
+++ b/servo/components/script/dom/webgltexture.rs
@@ -171,16 +171,24 @@ impl WebGLTexture {
 
     pub fn delete(&self) {
         if !self.is_deleted.get() {
             self.is_deleted.set(true);
             let _ = self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DeleteTexture(self.id)));
         }
     }
 
+    pub fn is_deleted(&self) -> bool {
+        self.is_deleted.get()
+    }
+
+    pub fn target(&self) -> Option<u32> {
+        self.target.get()
+    }
+
     /// We have to follow the conversion rules for GLES 2.0. See:
     ///   https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html
     ///
     pub fn tex_parameter(&self,
                      target: u32,
                      name: u32,
                      value: TexParameterValue) -> WebGLResult<()> {
         let (int_value, _float_value) = match value {
--- a/servo/components/script/dom/webidls/WebGLRenderingContext.webidl
+++ b/servo/components/script/dom/webidls/WebGLRenderingContext.webidl
@@ -600,18 +600,18 @@ interface WebGLRenderingContextBase
     //[WebGLHandlesContextLoss] GLsizeiptr getVertexAttribOffset(GLuint index, GLenum pname);
 
     void hint(GLenum target, GLenum mode);
     //[WebGLHandlesContextLoss] GLboolean isBuffer(WebGLBuffer? buffer);
     //[WebGLHandlesContextLoss] GLboolean isEnabled(GLenum cap);
     //[WebGLHandlesContextLoss] GLboolean isFramebuffer(WebGLFramebuffer? framebuffer);
     //[WebGLHandlesContextLoss] GLboolean isProgram(WebGLProgram? program);
     //[WebGLHandlesContextLoss] GLboolean isRenderbuffer(WebGLRenderbuffer? renderbuffer);
-    //[WebGLHandlesContextLoss] GLboolean isShader(WebGLShader? shader);
-    //[WebGLHandlesContextLoss] GLboolean isTexture(WebGLTexture? texture);
+    [WebGLHandlesContextLoss] GLboolean isShader(WebGLShader? shader);
+    [WebGLHandlesContextLoss] GLboolean isTexture(WebGLTexture? texture);
     void lineWidth(GLfloat width);
     void linkProgram(WebGLProgram? program);
     void pixelStorei(GLenum pname, GLint param);
     void polygonOffset(GLfloat factor, GLfloat units);
 
     //void readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
     //                GLenum format, GLenum type, ArrayBufferView? pixels);