/* 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 https://mozilla.org/MPL/2.0/. */ use euclid::default::{Rect, Size2D}; use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender, IpcSharedMemory}; use pixels::PixelFormat; use serde::{Deserialize, Serialize}; use sparkle::gl; use sparkle::gl::Gl; use std::borrow::Cow; use std::fmt; use std::num::{NonZeroU32, NonZeroU64}; use std::ops::Deref; use webrender_api::{DocumentId, ImageKey, PipelineId}; use webvr_traits::WebVRPoseInformation; use webxr_api::SwapChainId as WebXRSwapChainId; /// Helper function that creates a WebGL channel (WebGLSender, WebGLReceiver) to be used in WebGLCommands. pub use crate::webgl_channel::webgl_channel; /// Entry point channel type used for sending WebGLMsg messages to the WebGL renderer. pub use crate::webgl_channel::WebGLChan; /// Entry point type used in a Script Pipeline to get the WebGLChan to be used in that thread. pub use crate::webgl_channel::WebGLPipeline; /// Receiver type used in WebGLCommands. pub use crate::webgl_channel::WebGLReceiver; /// Result type for send()/recv() calls in in WebGLCommands. pub use crate::webgl_channel::WebGLSendResult; /// Sender type used in WebGLCommands. pub use crate::webgl_channel::WebGLSender; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct WebGLCommandBacktrace { #[cfg(feature = "webgl_backtrace")] pub backtrace: String, #[cfg(feature = "webgl_backtrace")] pub js_backtrace: Option, } /// WebGL Threading API entry point that lives in the constellation. pub struct WebGLThreads(pub WebGLSender); impl WebGLThreads { /// Gets the WebGLThread handle for each script pipeline. pub fn pipeline(&self) -> WebGLPipeline { // This mode creates a single thread, so the existing WebGLChan is just cloned. WebGLPipeline(WebGLChan(self.0.clone())) } /// Sends a exit message to close the WebGLThreads and release all WebGLContexts. pub fn exit(&self) -> Result<(), &'static str> { self.0 .send(WebGLMsg::Exit) .map_err(|_| "Failed to send Exit message") } } /// WebGL Message API #[derive(Debug, Deserialize, Serialize)] pub enum WebGLMsg { /// Creates a new WebGLContext. CreateContext( WebGLVersion, Size2D, GLContextAttributes, WebGLSender>, ), /// Resizes a WebGLContext. ResizeContext(WebGLContextId, Size2D, WebGLSender>), /// Drops a WebGLContext. RemoveContext(WebGLContextId), /// Runs a WebGLCommand in a specific WebGLContext. WebGLCommand(WebGLContextId, WebGLCommand, WebGLCommandBacktrace), /// Runs a WebVRCommand in a specific WebGLContext. WebVRCommand(WebGLContextId, WebVRCommand), /// Commands used for the DOMToTexture feature. DOMToTextureCommand(DOMToTextureCommand), /// Creates a new opaque framebuffer for WebXR. CreateWebXRSwapChain( WebGLContextId, Size2D, WebGLSender>, ), /// Performs a buffer swap. SwapBuffers(Vec, WebGLSender<()>), /// Frees all resources and closes the thread. Exit, } #[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub enum GlType { Gl, Gles, } /// Contains the WebGLCommand sender and information about a WebGLContext #[derive(Clone, Debug, 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, /// The GLSL version supported by the context. pub glsl_version: WebGLSLVersion, /// The GL API used by the context. pub api_type: GlType, /// The WebRender image key. pub image_key: ImageKey, } /// Defines the WebGL version #[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)] pub enum WebGLVersion { /// https://www.khronos.org/registry/webgl/specs/1.0.2/ /// Conforms closely to the OpenGL ES 2.0 API WebGL1, /// https://www.khronos.org/registry/webgl/specs/latest/2.0/ /// Conforms closely to the OpenGL ES 3.0 API WebGL2, } /// Defines the GLSL version supported by the WebGL backend contexts. #[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)] pub struct WebGLSLVersion { /// Major GLSL version pub major: u32, /// Minor GLSL version pub minor: u32, } /// Helper struct to send WebGLCommands to a specific WebGLContext. #[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)] pub struct WebGLMsgSender { ctx_id: WebGLContextId, #[ignore_malloc_size_of = "channels are hard"] sender: WebGLChan, } impl WebGLMsgSender { pub fn new(id: WebGLContextId, sender: WebGLChan) -> Self { WebGLMsgSender { ctx_id: id, sender: sender, } } /// Returns the WebGLContextId associated to this sender pub fn context_id(&self) -> WebGLContextId { self.ctx_id } /// Send a WebGLCommand message #[inline] pub fn send(&self, command: WebGLCommand, backtrace: WebGLCommandBacktrace) -> WebGLSendResult { self.sender .send(WebGLMsg::WebGLCommand(self.ctx_id, command, backtrace)) } /// 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, sender: WebGLSender>, ) -> 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_create_webxr_swap_chain( &self, size: Size2D, sender: WebGLSender>, ) -> WebGLSendResult { self.sender .send(WebGLMsg::CreateWebXRSwapChain(self.ctx_id, size, sender)) } #[inline] pub fn send_swap_buffers(&self, id: Option) -> WebGLSendResult { let swap_id = id .map(|id| SwapChainId::Framebuffer(self.ctx_id, id)) .unwrap_or_else(|| SwapChainId::Context(self.ctx_id)); let (sender, receiver) = webgl_channel()?; self.sender .send(WebGLMsg::SwapBuffers(vec![swap_id], sender))?; receiver.recv()?; Ok(()) } pub fn send_dom_to_texture(&self, command: DOMToTextureCommand) -> WebGLSendResult { self.sender.send(WebGLMsg::DOMToTextureCommand(command)) } } #[derive(Deserialize, Serialize)] pub struct TruncatedDebug(T); impl From for TruncatedDebug { fn from(v: T) -> TruncatedDebug { TruncatedDebug(v) } } impl fmt::Debug for TruncatedDebug { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut s = format!("{:?}", self.0); if s.len() > 20 { s.truncate(20); s.push_str("..."); } write!(f, "{}", s) } } impl Deref for TruncatedDebug { type Target = T; fn deref(&self) -> &T { &self.0 } } /// WebGL Commands for a specific WebGLContext #[derive(Debug, Deserialize, Serialize)] pub enum WebGLCommand { GetContextAttributes(WebGLSender), 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, IpcBytesReceiver, u32), BufferSubData(u32, isize, IpcBytesReceiver), GetBufferSubData(u32, usize, usize, IpcBytesSender), CopyBufferSubData(u32, u32, i64, i64, i64), Clear(u32), ClearColor(f32, f32, f32, f32), ClearDepth(f32), ClearStencil(i32), ColorMask(bool, bool, bool, bool), CullFace(u32), FrontFace(u32), DepthFunc(u32), DepthMask(bool), DepthRange(f32, f32), 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>), CreateFramebuffer(WebGLSender>), CreateRenderbuffer(WebGLSender>), CreateTexture(WebGLSender>), CreateProgram(WebGLSender>), CreateShader(u32, WebGLSender>), DeleteBuffer(WebGLBufferId), DeleteFramebuffer(WebGLFramebufferId), DeleteRenderbuffer(WebGLRenderbufferId), DeleteTexture(WebGLTextureId), DeleteProgram(WebGLProgramId), DeleteShader(WebGLShaderId), BindBuffer(u32, Option), BindFramebuffer(u32, WebGLFramebufferBindingRequest), BindRenderbuffer(u32, Option), BindTexture(u32, Option), DisableVertexAttribArray(u32), EnableVertexAttribArray(u32), FramebufferRenderbuffer(u32, u32, u32, Option), FramebufferTexture2D(u32, u32, u32, Option, i32), GetExtensions(WebGLSender), GetShaderPrecisionFormat(u32, u32, WebGLSender<(i32, i32, i32)>), GetUniformLocation(WebGLProgramId, String, WebGLSender), GetShaderInfoLog(WebGLShaderId, WebGLSender), GetProgramInfoLog(WebGLProgramId, WebGLSender), GetFramebufferAttachmentParameter(u32, u32, u32, WebGLSender), GetRenderbufferParameter(u32, u32, WebGLSender), CreateTransformFeedback(WebGLSender), DeleteTransformFeedback(u32), IsTransformFeedback(u32, WebGLSender), BindTransformFeedback(u32, u32), BeginTransformFeedback(u32), EndTransformFeedback(), PauseTransformFeedback(), ResumeTransformFeedback(), GetTransformFeedbackVarying(WebGLProgramId, u32, WebGLSender<(i32, u32, String)>), TransformFeedbackVaryings(WebGLProgramId, Vec, u32), PolygonOffset(f32, f32), RenderbufferStorage(u32, u32, i32, i32), ReadPixels(Rect, u32, u32, IpcBytesSender), ReadPixelsPP(Rect, u32, u32, usize), SampleCoverage(f32, bool), Scissor(i32, i32, u32, u32), StencilFunc(u32, i32, u32), StencilFuncSeparate(u32, u32, i32, u32), StencilMask(u32), StencilMaskSeparate(u32, u32), StencilOp(u32, u32, u32), StencilOpSeparate(u32, u32, u32, u32), FenceSync(WebGLSender), IsSync(WebGLSyncId, WebGLSender), ClientWaitSync(WebGLSyncId, u32, u64, WebGLSender), WaitSync(WebGLSyncId, u32, i64), GetSyncParameter(WebGLSyncId, u32, WebGLSender), DeleteSync(WebGLSyncId), Hint(u32, u32), LineWidth(f32), PixelStorei(u32, i32), LinkProgram(WebGLProgramId, WebGLSender), Uniform1f(i32, f32), Uniform1fv(i32, Vec), Uniform1i(i32, i32), Uniform1ui(i32, u32), Uniform1iv(i32, Vec), Uniform1uiv(i32, Vec), Uniform2f(i32, f32, f32), Uniform2fv(i32, Vec), Uniform2i(i32, i32, i32), Uniform2ui(i32, u32, u32), Uniform2iv(i32, Vec), Uniform2uiv(i32, Vec), Uniform3f(i32, f32, f32, f32), Uniform3fv(i32, Vec), Uniform3i(i32, i32, i32, i32), Uniform3ui(i32, u32, u32, u32), Uniform3iv(i32, Vec), Uniform3uiv(i32, Vec), Uniform4f(i32, f32, f32, f32, f32), Uniform4fv(i32, Vec), Uniform4i(i32, i32, i32, i32, i32), Uniform4ui(i32, u32, u32, u32, u32), Uniform4iv(i32, Vec), Uniform4uiv(i32, Vec), UniformMatrix2fv(i32, Vec), UniformMatrix3fv(i32, Vec), UniformMatrix4fv(i32, Vec), UniformMatrix3x2fv(i32, Vec), UniformMatrix4x2fv(i32, Vec), UniformMatrix2x3fv(i32, Vec), UniformMatrix4x3fv(i32, Vec), UniformMatrix2x4fv(i32, Vec), UniformMatrix3x4fv(i32, Vec), UseProgram(Option), ValidateProgram(WebGLProgramId), VertexAttrib(u32, f32, f32, f32, f32), VertexAttribPointer(u32, i32, u32, bool, i32, u32), VertexAttribPointer2f(u32, i32, bool, i32, u32), SetViewport(i32, i32, i32, i32), TexImage2D { target: u32, level: u32, // FIXME(nox): This should be computed on the WebGL thread. effective_internal_format: u32, size: Size2D, format: TexFormat, data_type: TexDataType, // FIXME(nox): This should be computed on the WebGL thread. effective_data_type: u32, unpacking_alignment: u32, alpha_treatment: Option, y_axis_treatment: YAxisTreatment, pixel_format: Option, data: TruncatedDebug, }, TexSubImage2D { target: u32, level: u32, xoffset: i32, yoffset: i32, size: Size2D, format: TexFormat, data_type: TexDataType, // FIXME(nox): This should be computed on the WebGL thread. effective_data_type: u32, unpacking_alignment: u32, alpha_treatment: Option, y_axis_treatment: YAxisTreatment, pixel_format: Option, data: TruncatedDebug, }, CompressedTexImage2D { target: u32, level: u32, internal_format: u32, size: Size2D, data: TruncatedDebug, }, CompressedTexSubImage2D { target: u32, level: i32, xoffset: i32, yoffset: i32, size: Size2D, format: u32, data: TruncatedDebug, }, DrawingBufferWidth(WebGLSender), DrawingBufferHeight(WebGLSender), Finish(WebGLSender<()>), Flush, GenerateMipmap(u32), CreateVertexArray(WebGLSender>), DeleteVertexArray(WebGLVertexArrayId), BindVertexArray(Option), GetParameterBool(ParameterBool, WebGLSender), GetParameterBool4(ParameterBool4, WebGLSender<[bool; 4]>), GetParameterInt(ParameterInt, WebGLSender), GetParameterInt2(ParameterInt2, WebGLSender<[i32; 2]>), GetParameterInt4(ParameterInt4, WebGLSender<[i32; 4]>), GetParameterFloat(ParameterFloat, WebGLSender), GetParameterFloat2(ParameterFloat2, WebGLSender<[f32; 2]>), GetParameterFloat4(ParameterFloat4, WebGLSender<[f32; 4]>), GetProgramValidateStatus(WebGLProgramId, WebGLSender), GetProgramActiveUniforms(WebGLProgramId, WebGLSender), GetCurrentVertexAttrib(u32, WebGLSender<[f32; 4]>), GetTexParameterFloat(u32, TexParameterFloat, WebGLSender), GetTexParameterInt(u32, TexParameterInt, WebGLSender), TexParameteri(u32, u32, i32), TexParameterf(u32, u32, f32), DrawArrays { mode: u32, first: i32, count: i32, }, DrawArraysInstanced { mode: u32, first: i32, count: i32, primcount: i32, }, DrawElements { mode: u32, count: i32, type_: u32, offset: u32, }, DrawElementsInstanced { mode: u32, count: i32, type_: u32, offset: u32, primcount: i32, }, VertexAttribDivisor { index: u32, divisor: u32, }, GetUniformBool(WebGLProgramId, i32, WebGLSender), GetUniformBool2(WebGLProgramId, i32, WebGLSender<[bool; 2]>), GetUniformBool3(WebGLProgramId, i32, WebGLSender<[bool; 3]>), GetUniformBool4(WebGLProgramId, i32, WebGLSender<[bool; 4]>), GetUniformInt(WebGLProgramId, i32, WebGLSender), GetUniformInt2(WebGLProgramId, i32, WebGLSender<[i32; 2]>), GetUniformInt3(WebGLProgramId, i32, WebGLSender<[i32; 3]>), GetUniformInt4(WebGLProgramId, i32, WebGLSender<[i32; 4]>), GetUniformUint(WebGLProgramId, i32, WebGLSender), GetUniformUint2(WebGLProgramId, i32, WebGLSender<[u32; 2]>), GetUniformUint3(WebGLProgramId, i32, WebGLSender<[u32; 3]>), GetUniformUint4(WebGLProgramId, i32, WebGLSender<[u32; 4]>), GetUniformFloat(WebGLProgramId, i32, WebGLSender), GetUniformFloat2(WebGLProgramId, i32, WebGLSender<[f32; 2]>), GetUniformFloat3(WebGLProgramId, i32, WebGLSender<[f32; 3]>), GetUniformFloat4(WebGLProgramId, i32, WebGLSender<[f32; 4]>), GetUniformFloat9(WebGLProgramId, i32, WebGLSender<[f32; 9]>), GetUniformFloat16(WebGLProgramId, i32, WebGLSender<[f32; 16]>), GetUniformFloat2x3(WebGLProgramId, i32, WebGLSender<[f32; 2 * 3]>), GetUniformFloat2x4(WebGLProgramId, i32, WebGLSender<[f32; 2 * 4]>), GetUniformFloat3x2(WebGLProgramId, i32, WebGLSender<[f32; 3 * 2]>), GetUniformFloat3x4(WebGLProgramId, i32, WebGLSender<[f32; 3 * 4]>), GetUniformFloat4x2(WebGLProgramId, i32, WebGLSender<[f32; 4 * 2]>), GetUniformFloat4x3(WebGLProgramId, i32, WebGLSender<[f32; 4 * 3]>), GetUniformBlockIndex(WebGLProgramId, String, WebGLSender), GetUniformIndices(WebGLProgramId, Vec, WebGLSender>), GetActiveUniforms(WebGLProgramId, Vec, u32, WebGLSender>), GetActiveUniformBlockName(WebGLProgramId, u32, WebGLSender), GetActiveUniformBlockParameter(WebGLProgramId, u32, u32, WebGLSender>), UniformBlockBinding(WebGLProgramId, u32, u32), InitializeFramebuffer { color: bool, depth: bool, stencil: bool, }, BeginQuery(u32, WebGLQueryId), DeleteQuery(WebGLQueryId), EndQuery(u32), GenerateQuery(WebGLSender), GetQueryState(WebGLSender, WebGLQueryId, u32), GenerateSampler(WebGLSender), DeleteSampler(WebGLSamplerId), BindSampler(u32, WebGLSamplerId), SetSamplerParameterFloat(WebGLSamplerId, u32, f32), SetSamplerParameterInt(WebGLSamplerId, u32, i32), GetSamplerParameterFloat(WebGLSamplerId, u32, WebGLSender), GetSamplerParameterInt(WebGLSamplerId, u32, WebGLSender), BindBufferBase(u32, u32, Option), BindBufferRange(u32, u32, Option, i64, i64), } macro_rules! nonzero_type { (u32) => { NonZeroU32 }; (u64) => { NonZeroU64 }; } macro_rules! define_resource_id { ($name:ident, $type:tt) => { #[derive(Clone, Copy, Eq, Hash, PartialEq)] pub struct $name(nonzero_type!($type)); impl $name { #[allow(unsafe_code)] #[inline] pub unsafe fn new(id: $type) -> Self { $name(::new_unchecked(id)) } #[inline] pub fn get(self) -> $type { self.0.get() } } #[allow(unsafe_code)] impl<'de> ::serde::Deserialize<'de> for $name { fn deserialize(deserializer: D) -> Result where D: ::serde::Deserializer<'de>, { let id = <$type>::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(&self, serializer: S) -> Result 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 ::malloc_size_of::MallocSizeOf for $name { fn size_of(&self, _ops: &mut ::malloc_size_of::MallocSizeOfOps) -> usize { 0 } } }; } define_resource_id!(WebGLBufferId, u32); define_resource_id!(WebGLTransparentFramebufferId, u32); define_resource_id!(WebGLRenderbufferId, u32); define_resource_id!(WebGLTextureId, u32); define_resource_id!(WebGLProgramId, u32); define_resource_id!(WebGLQueryId, u32); define_resource_id!(WebGLSamplerId, u32); define_resource_id!(WebGLShaderId, u32); define_resource_id!(WebGLSyncId, u64); define_resource_id!(WebGLVertexArrayId, u32); #[derive( Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize, )] pub struct WebGLContextId(pub u64); #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub enum SwapChainId { Context(WebGLContextId), Framebuffer(WebGLContextId, WebGLOpaqueFramebufferId), } impl SwapChainId { pub fn context_id(&self) -> WebGLContextId { match *self { SwapChainId::Context(id) => id, SwapChainId::Framebuffer(id, _) => id, } } } #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub enum WebGLError { InvalidEnum, InvalidFramebufferOperation, InvalidOperation, InvalidValue, OutOfMemory, ContextLost, } #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum WebGLOpaqueFramebufferId { // At the moment the only source of opaque framebuffers is webxr WebXR(#[ignore_malloc_size_of = "ids don't malloc"] WebXRSwapChainId), } #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum WebGLFramebufferId { Transparent(WebGLTransparentFramebufferId), Opaque(WebGLOpaqueFramebufferId), } #[derive(Clone, Copy, Debug, Deserialize, Serialize)] pub enum WebGLFramebufferBindingRequest { Explicit(WebGLFramebufferId), Default, } pub type WebGLResult = Result; pub type WebVRDeviceId = u32; // WebVR commands that must be called in the WebGL render thread. #[derive(Clone, Debug, 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, // near f64, // far f64, // sync gamepads too bool, WebGLSender>, ), /// 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, gl: &Gl, command: WebVRCommand, texture: Option<(u32, Size2D)>); } /// WebGL commands required to implement DOMToTexture feature. #[derive(Clone, Debug, Deserialize, Serialize)] pub enum DOMToTextureCommand { /// Attaches a HTMLIFrameElement to a WebGLTexture. Attach( WebGLContextId, WebGLTextureId, DocumentId, PipelineId, Size2D, ), /// Releases the HTMLIFrameElement to WebGLTexture attachment. Detach(WebGLTextureId), /// Lock message used for a correct synchronization with WebRender GL flow. Lock(PipelineId, usize, WebGLSender)>>), } /// Information about a WebGL program linking operation. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct ProgramLinkInfo { /// Whether the program was linked successfully. pub linked: bool, /// The list of active attributes. pub active_attribs: Box<[ActiveAttribInfo]>, /// The list of active uniforms. pub active_uniforms: Box<[ActiveUniformInfo]>, /// The list of active uniform blocks. pub active_uniform_blocks: Box<[ActiveUniformBlockInfo]>, /// The number of varying variables pub transform_feedback_length: i32, /// The buffer mode used when transform feedback is active pub transform_feedback_mode: i32, } /// Description of a single active attribute. #[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)] pub struct ActiveAttribInfo { /// The name of the attribute. pub name: String, /// The size of the attribute. pub size: i32, /// The type of the attribute. pub type_: u32, /// The location of the attribute. pub location: i32, } /// Description of a single active uniform. #[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)] pub struct ActiveUniformInfo { /// The base name of the uniform. pub base_name: Box, /// The size of the uniform, if it is an array. pub size: Option, /// The type of the uniform. pub type_: u32, } impl ActiveUniformInfo { pub fn name(&self) -> Cow { if self.size.is_some() { let mut name = String::from(&*self.base_name); name.push_str("[0]"); Cow::Owned(name) } else { Cow::Borrowed(&self.base_name) } } } /// Description of a single uniform block. #[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)] pub struct ActiveUniformBlockInfo { /// The name of the uniform block. pub name: String, /// The size of the uniform block. pub size: i32, } macro_rules! parameters { ($name:ident { $( $variant:ident($kind:ident { $( $param:ident = gl::$value:ident, )+ }), )+ }) => { #[derive(Clone, Copy, Debug, Deserialize, Serialize)] pub enum $name { $( $variant($kind), )+} $( #[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[repr(u32)] pub enum $kind { $( $param = gl::$value, )+} )+ impl $name { pub fn from_u32(value: u32) -> WebGLResult { match value { $($(gl::$value => Ok($name::$variant($kind::$param)),)+)+ _ => Err(WebGLError::InvalidEnum) } } } } } parameters! { Parameter { Bool(ParameterBool { DepthWritemask = gl::DEPTH_WRITEMASK, SampleCoverageInvert = gl::SAMPLE_COVERAGE_INVERT, TransformFeedbackActive = gl::TRANSFORM_FEEDBACK_ACTIVE, TransformFeedbackPaused = gl::TRANSFORM_FEEDBACK_PAUSED, }), Bool4(ParameterBool4 { ColorWritemask = gl::COLOR_WRITEMASK, }), Int(ParameterInt { ActiveTexture = gl::ACTIVE_TEXTURE, AlphaBits = gl::ALPHA_BITS, BlendDstAlpha = gl::BLEND_DST_ALPHA, BlendDstRgb = gl::BLEND_DST_RGB, BlendEquationAlpha = gl::BLEND_EQUATION_ALPHA, BlendEquationRgb = gl::BLEND_EQUATION_RGB, BlendSrcAlpha = gl::BLEND_SRC_ALPHA, BlendSrcRgb = gl::BLEND_SRC_RGB, BlueBits = gl::BLUE_BITS, CullFaceMode = gl::CULL_FACE_MODE, DepthBits = gl::DEPTH_BITS, DepthFunc = gl::DEPTH_FUNC, FragmentShaderDerivativeHint = gl::FRAGMENT_SHADER_DERIVATIVE_HINT, FrontFace = gl::FRONT_FACE, GenerateMipmapHint = gl::GENERATE_MIPMAP_HINT, GreenBits = gl::GREEN_BITS, RedBits = gl::RED_BITS, SampleBuffers = gl::SAMPLE_BUFFERS, Samples = gl::SAMPLES, StencilBackFail = gl::STENCIL_BACK_FAIL, StencilBackFunc = gl::STENCIL_BACK_FUNC, StencilBackPassDepthFail = gl::STENCIL_BACK_PASS_DEPTH_FAIL, StencilBackPassDepthPass = gl::STENCIL_BACK_PASS_DEPTH_PASS, StencilBackRef = gl::STENCIL_BACK_REF, StencilBackValueMask = gl::STENCIL_BACK_VALUE_MASK, StencilBackWritemask = gl::STENCIL_BACK_WRITEMASK, StencilBits = gl::STENCIL_BITS, StencilClearValue = gl::STENCIL_CLEAR_VALUE, StencilFail = gl::STENCIL_FAIL, StencilFunc = gl::STENCIL_FUNC, StencilPassDepthFail = gl::STENCIL_PASS_DEPTH_FAIL, StencilPassDepthPass = gl::STENCIL_PASS_DEPTH_PASS, StencilRef = gl::STENCIL_REF, StencilValueMask = gl::STENCIL_VALUE_MASK, StencilWritemask = gl::STENCIL_WRITEMASK, SubpixelBits = gl::SUBPIXEL_BITS, TransformFeedbackBinding = gl::TRANSFORM_FEEDBACK_BINDING, MaxTransformFeedbackInterleavedComponents = gl::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, MaxTransformFeedbackSeparateAttribs = gl::MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, MaxTransformFeedbackSeparateComponents = gl::MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, TransformFeedbackBufferSize = gl::TRANSFORM_FEEDBACK_BUFFER_SIZE, TransformFeedbackBufferStart = gl::TRANSFORM_FEEDBACK_BUFFER_START, }), Int2(ParameterInt2 { MaxViewportDims = gl::MAX_VIEWPORT_DIMS, }), Int4(ParameterInt4 { ScissorBox = gl::SCISSOR_BOX, Viewport = gl::VIEWPORT, }), Float(ParameterFloat { DepthClearValue = gl::DEPTH_CLEAR_VALUE, LineWidth = gl::LINE_WIDTH, MaxTextureMaxAnisotropyExt = gl::MAX_TEXTURE_MAX_ANISOTROPY_EXT, PolygonOffsetFactor = gl::POLYGON_OFFSET_FACTOR, PolygonOffsetUnits = gl::POLYGON_OFFSET_UNITS, SampleCoverageValue = gl::SAMPLE_COVERAGE_VALUE, }), Float2(ParameterFloat2 { AliasedPointSizeRange = gl::ALIASED_POINT_SIZE_RANGE, AliasedLineWidthRange = gl::ALIASED_LINE_WIDTH_RANGE, DepthRange = gl::DEPTH_RANGE, }), Float4(ParameterFloat4 { BlendColor = gl::BLEND_COLOR, ColorClearValue = gl::COLOR_CLEAR_VALUE, }), } } parameters! { TexParameter { Float(TexParameterFloat { TextureMaxAnisotropyExt = gl::TEXTURE_MAX_ANISOTROPY_EXT, }), Int(TexParameterInt { TextureWrapS = gl::TEXTURE_WRAP_S, TextureWrapT = gl::TEXTURE_WRAP_T, }), } } #[macro_export] macro_rules! gl_enums { ($(pub enum $name:ident { $($variant:ident = $mod:ident::$constant:ident,)+ })*) => { $( #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf)] #[derive(PartialEq, Serialize)] #[repr(u32)] pub enum $name { $($variant = $mod::$constant,)+ } impl $name { pub fn from_gl_constant(constant: u32) -> Option { Some(match constant { $($mod::$constant => $name::$variant, )+ _ => return None, }) } #[inline] pub fn as_gl_constant(&self) -> u32 { *self as u32 } } )* } } // FIXME: These should come from sparkle mod gl_ext_constants { use sparkle::gl::types::GLenum; pub const COMPRESSED_RGB_S3TC_DXT1_EXT: GLenum = 0x83F0; pub const COMPRESSED_RGBA_S3TC_DXT1_EXT: GLenum = 0x83F1; pub const COMPRESSED_RGBA_S3TC_DXT3_EXT: GLenum = 0x83F2; pub const COMPRESSED_RGBA_S3TC_DXT5_EXT: GLenum = 0x83F3; pub const COMPRESSED_RGB_ETC1_WEBGL: GLenum = 0x8D64; pub static COMPRESSIONS: &'static [GLenum] = &[ COMPRESSED_RGB_S3TC_DXT1_EXT, COMPRESSED_RGBA_S3TC_DXT1_EXT, COMPRESSED_RGBA_S3TC_DXT3_EXT, COMPRESSED_RGBA_S3TC_DXT5_EXT, COMPRESSED_RGB_ETC1_WEBGL, ]; } gl_enums! { pub enum TexFormat { DepthComponent = gl::DEPTH_COMPONENT, Alpha = gl::ALPHA, RGB = gl::RGB, RGBA = gl::RGBA, Luminance = gl::LUMINANCE, LuminanceAlpha = gl::LUMINANCE_ALPHA, CompressedRgbS3tcDxt1 = gl_ext_constants::COMPRESSED_RGB_S3TC_DXT1_EXT, CompressedRgbaS3tcDxt1 = gl_ext_constants::COMPRESSED_RGBA_S3TC_DXT1_EXT, CompressedRgbaS3tcDxt3 = gl_ext_constants::COMPRESSED_RGBA_S3TC_DXT3_EXT, CompressedRgbaS3tcDxt5 = gl_ext_constants::COMPRESSED_RGBA_S3TC_DXT5_EXT, CompressedRgbEtc1 = gl_ext_constants::COMPRESSED_RGB_ETC1_WEBGL, } pub enum TexDataType { UnsignedByte = gl::UNSIGNED_BYTE, UnsignedShort4444 = gl::UNSIGNED_SHORT_4_4_4_4, UnsignedShort5551 = gl::UNSIGNED_SHORT_5_5_5_1, UnsignedShort565 = gl::UNSIGNED_SHORT_5_6_5, Float = gl::FLOAT, HalfFloat = gl::HALF_FLOAT_OES, } } impl TexFormat { /// Returns how many components does this format need. For example, RGBA /// needs 4 components, while RGB requires 3. pub fn components(&self) -> u32 { match *self { TexFormat::DepthComponent => 1, TexFormat::Alpha => 1, TexFormat::Luminance => 1, TexFormat::LuminanceAlpha => 2, TexFormat::RGB => 3, TexFormat::RGBA => 4, _ => 1, } } /// Returns whether this format is a known texture compression format. pub fn is_compressed(&self) -> bool { gl_ext_constants::COMPRESSIONS.contains(&self.as_gl_constant()) } } impl TexDataType { /// Returns the size in bytes of each element of data. pub fn element_size(&self) -> u32 { use self::*; match *self { TexDataType::UnsignedByte => 1, TexDataType::UnsignedShort4444 | TexDataType::UnsignedShort5551 | TexDataType::UnsignedShort565 => 2, TexDataType::Float => 4, TexDataType::HalfFloat => 2, } } /// Returns how many components a single element may hold. For example, a /// UnsignedShort4444 holds four components, each with 4 bits of data. pub fn components_per_element(&self) -> u32 { match *self { TexDataType::UnsignedByte => 1, TexDataType::UnsignedShort565 => 3, TexDataType::UnsignedShort5551 => 4, TexDataType::UnsignedShort4444 => 4, TexDataType::Float => 1, TexDataType::HalfFloat => 1, } } } #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum AlphaTreatment { Premultiply, Unmultiply, } #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum YAxisTreatment { AsIs, Flipped, } #[derive(Clone, Copy, Debug, Deserialize, Serialize)] pub struct GLContextAttributes { pub alpha: bool, pub depth: bool, pub stencil: bool, pub antialias: bool, pub premultiplied_alpha: bool, pub preserve_drawing_buffer: bool, } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct GLLimits { pub max_vertex_attribs: u32, pub max_tex_size: u32, pub max_cube_map_tex_size: u32, pub max_combined_texture_image_units: u32, pub max_fragment_uniform_vectors: u32, pub max_renderbuffer_size: u32, pub max_texture_image_units: u32, pub max_varying_vectors: u32, pub max_vertex_texture_image_units: u32, pub max_vertex_uniform_vectors: u32, pub max_client_wait_timeout_webgl: std::time::Duration, pub max_transform_feedback_separate_attribs: u32, pub max_vertex_output_vectors: u32, pub max_fragment_input_vectors: u32, pub max_draw_buffers: u32, pub max_color_attachments: u32, pub max_uniform_buffer_bindings: u32, pub min_program_texel_offset: u32, pub max_program_texel_offset: u32, pub max_uniform_block_size: u32, pub max_combined_uniform_blocks: u32, pub max_combined_vertex_uniform_components: u32, pub max_combined_fragment_uniform_components: u32, pub max_vertex_uniform_blocks: u32, pub max_vertex_uniform_components: u32, pub max_fragment_uniform_blocks: u32, pub max_fragment_uniform_components: u32, pub uniform_buffer_offset_alignment: u32, }