diff options
Diffstat (limited to 'components/canvas_traits/webgl.rs')
-rw-r--r-- | components/canvas_traits/webgl.rs | 506 |
1 files changed, 506 insertions, 0 deletions
diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs new file mode 100644 index 00000000000..1bd6eb0649b --- /dev/null +++ b/components/canvas_traits/webgl.rs @@ -0,0 +1,506 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use core::nonzero::NonZero; +use euclid::Size2D; +use offscreen_gl_context::{GLContextAttributes, GLLimits}; +use std::fmt; +use webrender_api; + +/// Sender type used in WebGLCommands. +pub use ::webgl_channel::WebGLSender; +/// Receiver type used in WebGLCommands. +pub use ::webgl_channel::WebGLReceiver; +/// Result type for send()/recv() calls in in WebGLCommands. +pub use ::webgl_channel::WebGLSendResult; +/// Helper function that creates a WebGL channel (WebGLSender, WebGLReceiver) to be used in WebGLCommands. +pub use ::webgl_channel::webgl_channel; +/// Entry point type used in a Script Pipeline to get the WebGLChan to be used in that thread. +pub use ::webgl_channel::WebGLPipeline; +/// Entry point channel type used for sending WebGLMsg messages to the WebGL renderer. +pub use ::webgl_channel::WebGLChan; + +/// WebGL Message API +#[derive(Clone, Deserialize, Serialize)] +pub enum WebGLMsg { + /// Creates a new WebGLContext. + CreateContext(Size2D<i32>, GLContextAttributes, WebGLSender<Result<(WebGLCreateContextResult), String>>), + /// Resizes a WebGLContext. + ResizeContext(WebGLContextId, Size2D<i32>, WebGLSender<Result<(), String>>), + /// Drops a WebGLContext. + RemoveContext(WebGLContextId), + /// Runs a WebGLCommand in a specific WebGLContext. + WebGLCommand(WebGLContextId, WebGLCommand), + /// Runs a WebVRCommand in a specific WebGLContext. + WebVRCommand(WebGLContextId, WebVRCommand), + /// Locks a specific WebGLContext. Lock messages are used for a correct synchronization + /// with WebRender external image API. + /// WR locks a external texture when it wants to use the shared texture contents. + /// The WR client should not change the shared texture content until the Unlock call. + /// Currently OpenGL Sync Objects are used to implement the synchronization mechanism. + Lock(WebGLContextId, WebGLSender<(u32, Size2D<i32>)>), + /// Unlocks a specific WebGLContext. Unlock messages are used for a correct synchronization + /// with WebRender external image API. + /// The WR unlocks a context when it finished reading the shared texture contents. + /// Unlock messages are always sent after a Lock message. + Unlock(WebGLContextId), + /// Creates or updates the image keys required for WebRender. + UpdateWebRenderImage(WebGLContextId, WebGLSender<webrender_api::ImageKey>), + /// Frees all resources and closes the thread. + Exit, +} + +/// Contains the WebGLCommand sender and information about a WebGLContext +#[derive(Clone, Deserialize, Serialize)] +pub struct WebGLCreateContextResult { + /// Sender instance to send commands to the specific WebGLContext + pub sender: WebGLMsgSender, + /// Information about the internal GL Context. + pub limits: GLLimits, + /// How the WebGLContext is shared with WebRender. + pub share_mode: WebGLContextShareMode, +} + +#[derive(Clone, Copy, Deserialize, HeapSizeOf, Serialize)] +pub enum WebGLContextShareMode { + /// Fast: a shared texture_id is used in WebRender. + SharedTexture, + /// Slow: glReadPixels is used to send pixels to WebRender each frame. + Readback, +} + +/// Helper struct to send WebGLCommands to a specific WebGLContext. +#[derive(Clone, Deserialize, HeapSizeOf, Serialize)] +pub struct WebGLMsgSender { + ctx_id: WebGLContextId, + #[ignore_heap_size_of = "channels are hard"] + sender: WebGLChan, +} + +impl WebGLMsgSender { + pub fn new(id: WebGLContextId, sender: WebGLChan) -> Self { + WebGLMsgSender { + ctx_id: id, + sender: sender, + } + } + + /// Send a WebGLCommand message + #[inline] + pub fn send(&self, command: WebGLCommand) -> WebGLSendResult { + self.sender.send(WebGLMsg::WebGLCommand(self.ctx_id, command)) + } + + /// Send a WebVRCommand message + #[inline] + pub fn send_vr(&self, command: WebVRCommand) -> WebGLSendResult { + self.sender.send(WebGLMsg::WebVRCommand(self.ctx_id, command)) + } + + /// Send a resize message + #[inline] + pub fn send_resize(&self, + size: Size2D<i32>, + sender: WebGLSender<Result<(), String>>) + -> WebGLSendResult { + self.sender.send(WebGLMsg::ResizeContext(self.ctx_id, size, sender)) + } + + #[inline] + pub fn send_remove(&self) -> WebGLSendResult { + self.sender.send(WebGLMsg::RemoveContext(self.ctx_id)) + } + + #[inline] + pub fn send_update_wr_image(&self, sender: WebGLSender<webrender_api::ImageKey>) -> WebGLSendResult { + self.sender.send(WebGLMsg::UpdateWebRenderImage(self.ctx_id, sender)) + } +} + +/// WebGL Commands for a specific WebGLContext +#[derive(Clone, Deserialize, Serialize)] +pub enum WebGLCommand { + GetContextAttributes(WebGLSender<GLContextAttributes>), + ActiveTexture(u32), + BlendColor(f32, f32, f32, f32), + BlendEquation(u32), + BlendEquationSeparate(u32, u32), + BlendFunc(u32, u32), + BlendFuncSeparate(u32, u32, u32, u32), + AttachShader(WebGLProgramId, WebGLShaderId), + DetachShader(WebGLProgramId, WebGLShaderId), + BindAttribLocation(WebGLProgramId, u32, String), + BufferData(u32, Vec<u8>, u32), + BufferSubData(u32, isize, Vec<u8>), + Clear(u32), + ClearColor(f32, f32, f32, f32), + ClearDepth(f64), + ClearStencil(i32), + ColorMask(bool, bool, bool, bool), + CullFace(u32), + FrontFace(u32), + DepthFunc(u32), + DepthMask(bool), + DepthRange(f64, f64), + Enable(u32), + Disable(u32), + CompileShader(WebGLShaderId, String), + CopyTexImage2D(u32, i32, u32, i32, i32, i32, i32, i32), + CopyTexSubImage2D(u32, i32, i32, i32, i32, i32, i32, i32), + CreateBuffer(WebGLSender<Option<WebGLBufferId>>), + CreateFramebuffer(WebGLSender<Option<WebGLFramebufferId>>), + CreateRenderbuffer(WebGLSender<Option<WebGLRenderbufferId>>), + CreateTexture(WebGLSender<Option<WebGLTextureId>>), + CreateProgram(WebGLSender<Option<WebGLProgramId>>), + CreateShader(u32, WebGLSender<Option<WebGLShaderId>>), + DeleteBuffer(WebGLBufferId), + DeleteFramebuffer(WebGLFramebufferId), + DeleteRenderbuffer(WebGLRenderbufferId), + DeleteTexture(WebGLTextureId), + DeleteProgram(WebGLProgramId), + DeleteShader(WebGLShaderId), + BindBuffer(u32, Option<WebGLBufferId>), + BindFramebuffer(u32, WebGLFramebufferBindingRequest), + BindRenderbuffer(u32, Option<WebGLRenderbufferId>), + BindTexture(u32, Option<WebGLTextureId>), + DisableVertexAttribArray(u32), + DrawArrays(u32, i32, i32), + DrawElements(u32, i32, u32, i64), + EnableVertexAttribArray(u32), + FramebufferRenderbuffer(u32, u32, u32, Option<WebGLRenderbufferId>), + FramebufferTexture2D(u32, u32, u32, Option<WebGLTextureId>, i32), + GetBufferParameter(u32, u32, WebGLSender<WebGLResult<WebGLParameter>>), + GetExtensions(WebGLSender<String>), + GetParameter(u32, WebGLSender<WebGLResult<WebGLParameter>>), + GetProgramParameter(WebGLProgramId, u32, WebGLSender<WebGLResult<WebGLParameter>>), + GetShaderParameter(WebGLShaderId, u32, WebGLSender<WebGLResult<WebGLParameter>>), + GetShaderPrecisionFormat(u32, u32, WebGLSender<WebGLResult<(i32, i32, i32)>>), + GetActiveAttrib(WebGLProgramId, u32, WebGLSender<WebGLResult<(i32, u32, String)>>), + GetActiveUniform(WebGLProgramId, u32, WebGLSender<WebGLResult<(i32, u32, String)>>), + GetAttribLocation(WebGLProgramId, String, WebGLSender<Option<i32>>), + GetUniformLocation(WebGLProgramId, String, WebGLSender<Option<i32>>), + GetVertexAttrib(u32, u32, WebGLSender<WebGLResult<WebGLParameter>>), + GetVertexAttribOffset(u32, u32, WebGLSender<WebGLResult<isize>>), + GetShaderInfoLog(WebGLShaderId, WebGLSender<String>), + GetProgramInfoLog(WebGLProgramId, WebGLSender<String>), + PolygonOffset(f32, f32), + RenderbufferStorage(u32, u32, i32, i32), + ReadPixels(i32, i32, i32, i32, u32, u32, WebGLSender<Vec<u8>>), + SampleCoverage(f32, bool), + Scissor(i32, i32, i32, i32), + StencilFunc(u32, i32, u32), + StencilFuncSeparate(u32, u32, i32, u32), + StencilMask(u32), + StencilMaskSeparate(u32, u32), + StencilOp(u32, u32, u32), + StencilOpSeparate(u32, u32, u32, u32), + Hint(u32, u32), + IsEnabled(u32, WebGLSender<bool>), + LineWidth(f32), + PixelStorei(u32, i32), + LinkProgram(WebGLProgramId), + Uniform1f(i32, f32), + Uniform1fv(i32, Vec<f32>), + Uniform1i(i32, i32), + Uniform1iv(i32, Vec<i32>), + Uniform2f(i32, f32, f32), + Uniform2fv(i32, Vec<f32>), + Uniform2i(i32, i32, i32), + Uniform2iv(i32, Vec<i32>), + Uniform3f(i32, f32, f32, f32), + Uniform3fv(i32, Vec<f32>), + Uniform3i(i32, i32, i32, i32), + Uniform3iv(i32, Vec<i32>), + Uniform4f(i32, f32, f32, f32, f32), + Uniform4fv(i32, Vec<f32>), + Uniform4i(i32, i32, i32, i32, i32), + Uniform4iv(i32, Vec<i32>), + UniformMatrix2fv(i32, bool, Vec<f32>), + UniformMatrix3fv(i32, bool, Vec<f32>), + UniformMatrix4fv(i32, bool, Vec<f32>), + UseProgram(WebGLProgramId), + ValidateProgram(WebGLProgramId), + VertexAttrib(u32, f32, f32, f32, f32), + VertexAttribPointer(u32, i32, u32, bool, i32, u32), + VertexAttribPointer2f(u32, i32, bool, i32, u32), + Viewport(i32, i32, i32, i32), + TexImage2D(u32, i32, i32, i32, i32, u32, u32, Vec<u8>), + TexParameteri(u32, u32, i32), + TexParameterf(u32, u32, f32), + TexSubImage2D(u32, i32, i32, i32, i32, i32, u32, u32, Vec<u8>), + DrawingBufferWidth(WebGLSender<i32>), + DrawingBufferHeight(WebGLSender<i32>), + Finish(WebGLSender<()>), + Flush, + GenerateMipmap(u32), + CreateVertexArray(WebGLSender<Option<WebGLVertexArrayId>>), + DeleteVertexArray(WebGLVertexArrayId), + BindVertexArray(Option<WebGLVertexArrayId>), +} + +macro_rules! define_resource_id_struct { + ($name:ident) => { + #[derive(Clone, Copy, Eq, Hash, PartialEq)] + pub struct $name(NonZero<u32>); + + impl $name { + #[allow(unsafe_code)] + #[inline] + pub unsafe fn new(id: u32) -> Self { + $name(NonZero::new_unchecked(id)) + } + + #[inline] + pub fn get(self) -> u32 { + self.0.get() + } + } + + }; +} + +macro_rules! define_resource_id { + ($name:ident) => { + define_resource_id_struct!($name); + + #[allow(unsafe_code)] + impl<'de> ::serde::Deserialize<'de> for $name { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where D: ::serde::Deserializer<'de> + { + let id = try!(u32::deserialize(deserializer)); + if id == 0 { + Err(::serde::de::Error::custom("expected a non-zero value")) + } else { + Ok(unsafe { $name::new(id) }) + } + } + } + + impl ::serde::Serialize for $name { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where S: ::serde::Serializer + { + self.get().serialize(serializer) + } + } + + impl ::std::fmt::Debug for $name { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) + -> Result<(), ::std::fmt::Error> { + fmt.debug_tuple(stringify!($name)) + .field(&self.get()) + .finish() + } + } + + impl ::std::fmt::Display for $name { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) + -> Result<(), ::std::fmt::Error> { + write!(fmt, "{}", self.get()) + } + } + + impl ::heapsize::HeapSizeOf for $name { + fn heap_size_of_children(&self) -> usize { 0 } + } + } +} + +define_resource_id!(WebGLBufferId); +define_resource_id!(WebGLFramebufferId); +define_resource_id!(WebGLRenderbufferId); +define_resource_id!(WebGLTextureId); +define_resource_id!(WebGLProgramId); +define_resource_id!(WebGLShaderId); +define_resource_id!(WebGLVertexArrayId); + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] +pub struct WebGLContextId(pub usize); + +impl ::heapsize::HeapSizeOf for WebGLContextId { + fn heap_size_of_children(&self) -> usize { 0 } +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub enum WebGLError { + InvalidEnum, + InvalidFramebufferOperation, + InvalidOperation, + InvalidValue, + OutOfMemory, + ContextLost, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum WebGLFramebufferBindingRequest { + Explicit(WebGLFramebufferId), + Default, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum WebGLParameter { + Int(i32), + Bool(bool), + String(String), + Float(f32), + FloatArray(Vec<f32>), + Invalid, +} + +pub type WebGLResult<T> = Result<T, WebGLError>; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum WebGLShaderParameter { + Int(i32), + Bool(bool), + Invalid, +} + +pub type WebVRDeviceId = u32; + +// WebVR commands that must be called in the WebGL render thread. +#[derive(Clone, Deserialize, Serialize)] +pub enum WebVRCommand { + /// Start presenting to a VR device. + Create(WebVRDeviceId), + /// Synchronize the pose information to be used in the frame. + SyncPoses(WebVRDeviceId, f64, f64, WebGLSender<Result<Vec<u8>, ()>>), + /// Submit the frame to a VR device using the specified texture coordinates. + SubmitFrame(WebVRDeviceId, [f32; 4], [f32; 4]), + /// Stop presenting to a VR device + Release(WebVRDeviceId) +} + +// Trait object that handles WebVR commands. +// Receives the texture id and size associated to the WebGLContext. +pub trait WebVRRenderHandler: Send { + fn handle(&mut self, command: WebVRCommand, texture: Option<(u32, Size2D<i32>)>); +} + +impl fmt::Debug for WebGLCommand { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::WebGLCommand::*; + let name = match *self { + GetContextAttributes(..) => "GetContextAttributes", + ActiveTexture(..) => "ActiveTexture", + BlendColor(..) => "BlendColor", + BlendEquation(..) => "BlendEquation", + BlendEquationSeparate(..) => "BlendEquationSeparate", + BlendFunc(..) => "BlendFunc", + BlendFuncSeparate(..) => "BlendFuncSeparate", + AttachShader(..) => "AttachShader", + DetachShader(..) => "DetachShader", + BindAttribLocation(..) => "BindAttribLocation", + BufferData(..) => "BufferData", + BufferSubData(..) => "BufferSubData", + Clear(..) => "Clear", + ClearColor(..) => "ClearColor", + ClearDepth(..) => "ClearDepth", + ClearStencil(..) => "ClearStencil", + ColorMask(..) => "ColorMask", + CopyTexImage2D(..) => "CopyTexImage2D", + CopyTexSubImage2D(..) => "CopyTexSubImage2D", + CullFace(..) => "CullFace", + FrontFace(..) => "FrontFace", + DepthFunc(..) => "DepthFunc", + DepthMask(..) => "DepthMask", + DepthRange(..) => "DepthRange", + Enable(..) => "Enable", + Disable(..) => "Disable", + CompileShader(..) => "CompileShader", + CreateBuffer(..) => "CreateBuffer", + CreateFramebuffer(..) => "CreateFramebuffer", + CreateRenderbuffer(..) => "CreateRenderbuffer", + CreateTexture(..) => "CreateTexture", + CreateProgram(..) => "CreateProgram", + CreateShader(..) => "CreateShader", + DeleteBuffer(..) => "DeleteBuffer", + DeleteFramebuffer(..) => "DeleteFramebuffer", + DeleteRenderbuffer(..) => "DeleteRenderBuffer", + DeleteTexture(..) => "DeleteTexture", + DeleteProgram(..) => "DeleteProgram", + DeleteShader(..) => "DeleteShader", + BindBuffer(..) => "BindBuffer", + BindFramebuffer(..) => "BindFramebuffer", + BindRenderbuffer(..) => "BindRenderbuffer", + BindTexture(..) => "BindTexture", + DisableVertexAttribArray(..) => "DisableVertexAttribArray", + DrawArrays(..) => "DrawArrays", + DrawElements(..) => "DrawElements", + EnableVertexAttribArray(..) => "EnableVertexAttribArray", + FramebufferRenderbuffer(..) => "FramebufferRenderbuffer", + FramebufferTexture2D(..) => "FramebufferTexture2D", + GetBufferParameter(..) => "GetBufferParameter", + GetExtensions(..) => "GetExtensions", + GetParameter(..) => "GetParameter", + GetProgramParameter(..) => "GetProgramParameter", + GetShaderParameter(..) => "GetShaderParameter", + GetShaderPrecisionFormat(..) => "GetShaderPrecisionFormat", + GetActiveAttrib(..) => "GetActiveAttrib", + GetActiveUniform(..) => "GetActiveUniform", + GetAttribLocation(..) => "GetAttribLocation", + GetUniformLocation(..) => "GetUniformLocation", + GetShaderInfoLog(..) => "GetShaderInfoLog", + GetProgramInfoLog(..) => "GetProgramInfoLog", + GetVertexAttrib(..) => "GetVertexAttrib", + GetVertexAttribOffset(..) => "GetVertexAttribOffset", + PolygonOffset(..) => "PolygonOffset", + ReadPixels(..) => "ReadPixels", + RenderbufferStorage(..) => "RenderbufferStorage", + SampleCoverage(..) => "SampleCoverage", + Scissor(..) => "Scissor", + StencilFunc(..) => "StencilFunc", + StencilFuncSeparate(..) => "StencilFuncSeparate", + StencilMask(..) => "StencilMask", + StencilMaskSeparate(..) => "StencilMaskSeparate", + StencilOp(..) => "StencilOp", + StencilOpSeparate(..) => "StencilOpSeparate", + Hint(..) => "Hint", + IsEnabled(..) => "IsEnabled", + LineWidth(..) => "LineWidth", + PixelStorei(..) => "PixelStorei", + LinkProgram(..) => "LinkProgram", + Uniform1f(..) => "Uniform1f", + Uniform1fv(..) => "Uniform1fv", + Uniform1i(..) => "Uniform1i", + Uniform1iv(..) => "Uniform1iv", + Uniform2f(..) => "Uniform2f", + Uniform2fv(..) => "Uniform2fv", + Uniform2i(..) => "Uniform2i", + Uniform2iv(..) => "Uniform2iv", + Uniform3f(..) => "Uniform3f", + Uniform3fv(..) => "Uniform3fv", + Uniform3i(..) => "Uniform3i", + Uniform3iv(..) => "Uniform3iv", + Uniform4f(..) => "Uniform4f", + Uniform4fv(..) => "Uniform4fv", + Uniform4i(..) => "Uniform4i", + Uniform4iv(..) => "Uniform4iv", + UniformMatrix2fv(..) => "UniformMatrix2fv", + UniformMatrix3fv(..) => "UniformMatrix3fv", + UniformMatrix4fv(..) => "UniformMatrix4fv", + UseProgram(..) => "UseProgram", + ValidateProgram(..) => "ValidateProgram", + VertexAttrib(..) => "VertexAttrib", + VertexAttribPointer2f(..) => "VertexAttribPointer2f", + VertexAttribPointer(..) => "VertexAttribPointer", + Viewport(..) => "Viewport", + TexImage2D(..) => "TexImage2D", + TexParameteri(..) => "TexParameteri", + TexParameterf(..) => "TexParameterf", + TexSubImage2D(..) => "TexSubImage2D", + DrawingBufferWidth(..) => "DrawingBufferWidth", + DrawingBufferHeight(..) => "DrawingBufferHeight", + Finish(..) => "Finish", + Flush => "Flush", + GenerateMipmap(..) => "GenerateMipmap", + CreateVertexArray(..) => "CreateVertexArray", + DeleteVertexArray(..) => "DeleteVertexArray", + BindVertexArray(..) => "BindVertexArray" + }; + + write!(f, "CanvasWebGLMsg::{}(..)", name) + } +} |