diff options
Diffstat (limited to 'components/shared/canvas')
-rw-r--r-- | components/shared/canvas/Cargo.toml | 33 | ||||
-rw-r--r-- | components/shared/canvas/canvas.rs | 491 | ||||
-rw-r--r-- | components/shared/canvas/lib.rs | 26 | ||||
-rw-r--r-- | components/shared/canvas/webgl.rs | 1431 | ||||
-rw-r--r-- | components/shared/canvas/webgl_channel/ipc.rs | 15 | ||||
-rw-r--r-- | components/shared/canvas/webgl_channel/mod.rs | 149 | ||||
-rw-r--r-- | components/shared/canvas/webgl_channel/mpsc.rs | 62 |
7 files changed, 2207 insertions, 0 deletions
diff --git a/components/shared/canvas/Cargo.toml b/components/shared/canvas/Cargo.toml new file mode 100644 index 00000000000..6f3eca8c160 --- /dev/null +++ b/components/shared/canvas/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "canvas_traits" +version = "0.0.1" +authors = ["The Servo Project Developers"] +license = "MPL-2.0" +edition = "2018" +publish = false + +[lib] +name = "canvas_traits" +path = "lib.rs" + +[features] +webgl_backtrace = [] +xr-profile = ["webxr-api/profile", "time"] + +[dependencies] +crossbeam-channel = { workspace = true } +cssparser = { workspace = true } +euclid = { workspace = true } +ipc-channel = { workspace = true } +lazy_static = { workspace = true } +malloc_size_of = { path = "../../malloc_size_of" } +malloc_size_of_derive = { workspace = true } +pixels = { path = "../../pixels" } +serde = { workspace = true } +serde_bytes = { workspace = true } +servo_config = { path = "../../config" } +sparkle = { workspace = true } +style = { path = "../../style" } +time = { workspace = true, optional = true } +webrender_api = { workspace = true } +webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] } diff --git a/components/shared/canvas/canvas.rs b/components/shared/canvas/canvas.rs new file mode 100644 index 00000000000..0ed7faed559 --- /dev/null +++ b/components/shared/canvas/canvas.rs @@ -0,0 +1,491 @@ +/* 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 std::default::Default; +use std::str::FromStr; + +use cssparser::RGBA; +use euclid::default::{Point2D, Rect, Size2D, Transform2D}; +use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender, IpcSender, IpcSharedMemory}; +use malloc_size_of_derive::MallocSizeOf; +use serde::{Deserialize, Serialize}; +use serde_bytes::ByteBuf; +use style::properties::style_structs::Font as FontStyleStruct; +use webrender_api::ImageKey; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum FillRule { + Nonzero, + Evenodd, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +pub struct CanvasId(pub u64); + +#[derive(Deserialize, Serialize)] +pub enum CanvasMsg { + Canvas2d(Canvas2dMsg, CanvasId), + FromLayout(FromLayoutMsg, CanvasId), + FromScript(FromScriptMsg, CanvasId), + Recreate(Size2D<u64>, CanvasId), + Close(CanvasId), +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct CanvasImageData { + pub image_key: ImageKey, +} + +#[derive(Debug, Deserialize, Serialize)] +pub enum Canvas2dMsg { + Arc(Point2D<f32>, f32, f32, f32, bool), + ArcTo(Point2D<f32>, Point2D<f32>, f32), + DrawImage(IpcSharedMemory, Size2D<f64>, Rect<f64>, Rect<f64>, bool), + DrawEmptyImage(Size2D<f64>, Rect<f64>, Rect<f64>), + DrawImageInOther(CanvasId, Size2D<f64>, Rect<f64>, Rect<f64>, bool), + BeginPath, + BezierCurveTo(Point2D<f32>, Point2D<f32>, Point2D<f32>), + ClearRect(Rect<f32>), + Clip, + ClosePath, + Ellipse(Point2D<f32>, f32, f32, f32, f32, f32, bool), + Fill(FillOrStrokeStyle), + FillText(String, f64, f64, Option<f64>, FillOrStrokeStyle, bool), + FillRect(Rect<f32>, FillOrStrokeStyle), + GetImageData(Rect<u64>, Size2D<u64>, IpcBytesSender), + GetTransform(IpcSender<Transform2D<f32>>), + IsPointInPath(f64, f64, FillRule, IpcSender<bool>), + LineTo(Point2D<f32>), + MoveTo(Point2D<f32>), + PutImageData(Rect<u64>, IpcBytesReceiver), + QuadraticCurveTo(Point2D<f32>, Point2D<f32>), + Rect(Rect<f32>), + RestoreContext, + SaveContext, + StrokeRect(Rect<f32>, FillOrStrokeStyle), + Stroke(FillOrStrokeStyle), + SetLineWidth(f32), + SetLineCap(LineCapStyle), + SetLineJoin(LineJoinStyle), + SetMiterLimit(f32), + SetGlobalAlpha(f32), + SetGlobalComposition(CompositionOrBlending), + SetTransform(Transform2D<f32>), + SetShadowOffsetX(f64), + SetShadowOffsetY(f64), + SetShadowBlur(f64), + SetShadowColor(RGBA), + SetFont(FontStyleStruct), + SetTextAlign(TextAlign), + SetTextBaseline(TextBaseline), +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum FromLayoutMsg { + SendData(IpcSender<CanvasImageData>), +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum FromScriptMsg { + SendPixels(IpcSender<IpcSharedMemory>), +} + +#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)] +pub struct CanvasGradientStop { + pub offset: f64, + pub color: RGBA, +} + +#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)] +pub struct LinearGradientStyle { + pub x0: f64, + pub y0: f64, + pub x1: f64, + pub y1: f64, + pub stops: Vec<CanvasGradientStop>, +} + +impl LinearGradientStyle { + pub fn new( + x0: f64, + y0: f64, + x1: f64, + y1: f64, + stops: Vec<CanvasGradientStop>, + ) -> LinearGradientStyle { + LinearGradientStyle { + x0: x0, + y0: y0, + x1: x1, + y1: y1, + stops: stops, + } + } +} + +#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)] +pub struct RadialGradientStyle { + pub x0: f64, + pub y0: f64, + pub r0: f64, + pub x1: f64, + pub y1: f64, + pub r1: f64, + pub stops: Vec<CanvasGradientStop>, +} + +impl RadialGradientStyle { + pub fn new( + x0: f64, + y0: f64, + r0: f64, + x1: f64, + y1: f64, + r1: f64, + stops: Vec<CanvasGradientStop>, + ) -> RadialGradientStyle { + RadialGradientStyle { + x0: x0, + y0: y0, + r0: r0, + x1: x1, + y1: y1, + r1: r1, + stops: stops, + } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct SurfaceStyle { + pub surface_data: ByteBuf, + pub surface_size: Size2D<u32>, + pub repeat_x: bool, + pub repeat_y: bool, +} + +impl SurfaceStyle { + pub fn new( + surface_data: Vec<u8>, + surface_size: Size2D<u32>, + repeat_x: bool, + repeat_y: bool, + ) -> Self { + Self { + surface_data: ByteBuf::from(surface_data), + surface_size, + repeat_x, + repeat_y, + } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum FillOrStrokeStyle { + Color(RGBA), + LinearGradient(LinearGradientStyle), + RadialGradient(RadialGradientStyle), + Surface(SurfaceStyle), +} + +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +pub enum LineCapStyle { + Butt = 0, + Round = 1, + Square = 2, +} + +impl FromStr for LineCapStyle { + type Err = (); + + fn from_str(string: &str) -> Result<LineCapStyle, ()> { + match string { + "butt" => Ok(LineCapStyle::Butt), + "round" => Ok(LineCapStyle::Round), + "square" => Ok(LineCapStyle::Square), + _ => Err(()), + } + } +} + +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +pub enum LineJoinStyle { + Round = 0, + Bevel = 1, + Miter = 2, +} + +impl FromStr for LineJoinStyle { + type Err = (); + + fn from_str(string: &str) -> Result<LineJoinStyle, ()> { + match string { + "round" => Ok(LineJoinStyle::Round), + "bevel" => Ok(LineJoinStyle::Bevel), + "miter" => Ok(LineJoinStyle::Miter), + _ => Err(()), + } + } +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub enum RepetitionStyle { + Repeat, + RepeatX, + RepeatY, + NoRepeat, +} + +impl FromStr for RepetitionStyle { + type Err = (); + + fn from_str(string: &str) -> Result<RepetitionStyle, ()> { + match string { + "repeat" => Ok(RepetitionStyle::Repeat), + "repeat-x" => Ok(RepetitionStyle::RepeatX), + "repeat-y" => Ok(RepetitionStyle::RepeatY), + "no-repeat" => Ok(RepetitionStyle::NoRepeat), + _ => Err(()), + } + } +} + +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +pub enum CompositionStyle { + SrcIn, + SrcOut, + SrcOver, + SrcAtop, + DestIn, + DestOut, + DestOver, + DestAtop, + Copy, + Lighter, + Xor, + Clear, +} + +impl FromStr for CompositionStyle { + type Err = (); + + fn from_str(string: &str) -> Result<CompositionStyle, ()> { + match string { + "source-in" => Ok(CompositionStyle::SrcIn), + "source-out" => Ok(CompositionStyle::SrcOut), + "source-over" => Ok(CompositionStyle::SrcOver), + "source-atop" => Ok(CompositionStyle::SrcAtop), + "destination-in" => Ok(CompositionStyle::DestIn), + "destination-out" => Ok(CompositionStyle::DestOut), + "destination-over" => Ok(CompositionStyle::DestOver), + "destination-atop" => Ok(CompositionStyle::DestAtop), + "copy" => Ok(CompositionStyle::Copy), + "lighter" => Ok(CompositionStyle::Lighter), + "xor" => Ok(CompositionStyle::Xor), + "clear" => Ok(CompositionStyle::Clear), + _ => Err(()), + } + } +} + +impl CompositionStyle { + pub fn to_str(&self) -> &str { + match *self { + CompositionStyle::SrcIn => "source-in", + CompositionStyle::SrcOut => "source-out", + CompositionStyle::SrcOver => "source-over", + CompositionStyle::SrcAtop => "source-atop", + CompositionStyle::DestIn => "destination-in", + CompositionStyle::DestOut => "destination-out", + CompositionStyle::DestOver => "destination-over", + CompositionStyle::DestAtop => "destination-atop", + CompositionStyle::Copy => "copy", + CompositionStyle::Lighter => "lighter", + CompositionStyle::Xor => "xor", + CompositionStyle::Clear => "clear", + } + } +} + +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +pub enum BlendingStyle { + Multiply, + Screen, + Overlay, + Darken, + Lighten, + ColorDodge, + ColorBurn, + HardLight, + SoftLight, + Difference, + Exclusion, + Hue, + Saturation, + Color, + Luminosity, +} + +impl FromStr for BlendingStyle { + type Err = (); + + fn from_str(string: &str) -> Result<BlendingStyle, ()> { + match string { + "multiply" => Ok(BlendingStyle::Multiply), + "screen" => Ok(BlendingStyle::Screen), + "overlay" => Ok(BlendingStyle::Overlay), + "darken" => Ok(BlendingStyle::Darken), + "lighten" => Ok(BlendingStyle::Lighten), + "color-dodge" => Ok(BlendingStyle::ColorDodge), + "color-burn" => Ok(BlendingStyle::ColorBurn), + "hard-light" => Ok(BlendingStyle::HardLight), + "soft-light" => Ok(BlendingStyle::SoftLight), + "difference" => Ok(BlendingStyle::Difference), + "exclusion" => Ok(BlendingStyle::Exclusion), + "hue" => Ok(BlendingStyle::Hue), + "saturation" => Ok(BlendingStyle::Saturation), + "color" => Ok(BlendingStyle::Color), + "luminosity" => Ok(BlendingStyle::Luminosity), + _ => Err(()), + } + } +} + +impl BlendingStyle { + pub fn to_str(&self) -> &str { + match *self { + BlendingStyle::Multiply => "multiply", + BlendingStyle::Screen => "screen", + BlendingStyle::Overlay => "overlay", + BlendingStyle::Darken => "darken", + BlendingStyle::Lighten => "lighten", + BlendingStyle::ColorDodge => "color-dodge", + BlendingStyle::ColorBurn => "color-burn", + BlendingStyle::HardLight => "hard-light", + BlendingStyle::SoftLight => "soft-light", + BlendingStyle::Difference => "difference", + BlendingStyle::Exclusion => "exclusion", + BlendingStyle::Hue => "hue", + BlendingStyle::Saturation => "saturation", + BlendingStyle::Color => "color", + BlendingStyle::Luminosity => "luminosity", + } + } +} + +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +pub enum CompositionOrBlending { + Composition(CompositionStyle), + Blending(BlendingStyle), +} + +impl Default for CompositionOrBlending { + fn default() -> CompositionOrBlending { + CompositionOrBlending::Composition(CompositionStyle::SrcOver) + } +} + +impl FromStr for CompositionOrBlending { + type Err = (); + + fn from_str(string: &str) -> Result<CompositionOrBlending, ()> { + if let Ok(op) = CompositionStyle::from_str(string) { + return Ok(CompositionOrBlending::Composition(op)); + } + + if let Ok(op) = BlendingStyle::from_str(string) { + return Ok(CompositionOrBlending::Blending(op)); + } + + Err(()) + } +} + +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +pub enum TextAlign { + Start, + End, + Left, + Right, + Center, +} + +impl FromStr for TextAlign { + type Err = (); + + fn from_str(string: &str) -> Result<TextAlign, ()> { + match string { + "start" => Ok(TextAlign::Start), + "end" => Ok(TextAlign::End), + "left" => Ok(TextAlign::Left), + "right" => Ok(TextAlign::Right), + "center" => Ok(TextAlign::Center), + _ => Err(()), + } + } +} + +impl Default for TextAlign { + fn default() -> TextAlign { + TextAlign::Start + } +} + +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +pub enum TextBaseline { + Top, + Hanging, + Middle, + Alphabetic, + Ideographic, + Bottom, +} + +impl FromStr for TextBaseline { + type Err = (); + + fn from_str(string: &str) -> Result<TextBaseline, ()> { + match string { + "top" => Ok(TextBaseline::Top), + "hanging" => Ok(TextBaseline::Hanging), + "middle" => Ok(TextBaseline::Middle), + "alphabetic" => Ok(TextBaseline::Alphabetic), + "ideographic" => Ok(TextBaseline::Ideographic), + "bottom" => Ok(TextBaseline::Bottom), + _ => Err(()), + } + } +} + +impl Default for TextBaseline { + fn default() -> TextBaseline { + TextBaseline::Alphabetic + } +} + +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +pub enum Direction { + Ltr, + Rtl, + Inherit, +} + +impl FromStr for Direction { + type Err = (); + + fn from_str(string: &str) -> Result<Direction, ()> { + match string { + "ltr" => Ok(Direction::Ltr), + "rtl" => Ok(Direction::Rtl), + "inherit" => Ok(Direction::Inherit), + _ => Err(()), + } + } +} + +impl Default for Direction { + fn default() -> Direction { + Direction::Inherit + } +} diff --git a/components/shared/canvas/lib.rs b/components/shared/canvas/lib.rs new file mode 100644 index 00000000000..e0c4050e7be --- /dev/null +++ b/components/shared/canvas/lib.rs @@ -0,0 +1,26 @@ +/* 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/. */ + +#![crate_name = "canvas_traits"] +#![crate_type = "rlib"] +#![deny(unsafe_code)] + +use crossbeam_channel::Sender; +use euclid::default::Size2D; + +use crate::canvas::CanvasId; + +pub mod canvas; +#[macro_use] +pub mod webgl; +mod webgl_channel; + +pub enum ConstellationCanvasMsg { + Create { + id_sender: Sender<CanvasId>, + size: Size2D<u64>, + antialias: bool, + }, + Exit, +} diff --git a/components/shared/canvas/webgl.rs b/components/shared/canvas/webgl.rs new file mode 100644 index 00000000000..2a2e0f0c3b3 --- /dev/null +++ b/components/shared/canvas/webgl.rs @@ -0,0 +1,1431 @@ +/* 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 std::borrow::Cow; +use std::fmt; +use std::num::{NonZeroU32, NonZeroU64}; +use std::ops::Deref; + +use euclid::default::{Rect, Size2D}; +use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender, IpcSharedMemory}; +use malloc_size_of_derive::MallocSizeOf; +use pixels::PixelFormat; +use serde::{Deserialize, Serialize}; +use sparkle::gl; +use webrender_api::ImageKey; +use webxr_api::{ + ContextId as WebXRContextId, Error as WebXRError, LayerId as WebXRLayerId, + LayerInit as WebXRLayerInit, SubImages as WebXRSubImages, +}; + +/// 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<String>, +} + +/// WebGL Threading API entry point that lives in the constellation. +pub struct WebGLThreads(pub WebGLSender<WebGLMsg>); + +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<u32>, + GLContextAttributes, + WebGLSender<Result<WebGLCreateContextResult, String>>, + ), + /// Resizes a WebGLContext. + ResizeContext(WebGLContextId, Size2D<u32>, WebGLSender<Result<(), String>>), + /// Drops a WebGLContext. + RemoveContext(WebGLContextId), + /// Runs a WebGLCommand in a specific WebGLContext. + WebGLCommand(WebGLContextId, WebGLCommand, WebGLCommandBacktrace), + /// Runs a WebXRCommand (WebXR layers need to be created in the WebGL + /// thread, as they may have thread affinity). + WebXRCommand(WebXRCommand), + /// Performs a buffer swap. + /// + /// The third field contains the time (in ns) when the request + /// was initiated. The u64 in the second field will be the time the + /// request is fulfilled + SwapBuffers(Vec<WebGLContextId>, WebGLSender<u64>, u64), + /// 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, PartialOrd, 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, Ord, PartialEq, PartialOrd, 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 resize message + #[inline] + pub fn send_resize( + &self, + size: Size2D<u32>, + 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)) + } +} + +#[derive(Deserialize, Serialize)] +pub struct TruncatedDebug<T>(T); + +impl<T> From<T> for TruncatedDebug<T> { + fn from(v: T) -> TruncatedDebug<T> { + TruncatedDebug(v) + } +} + +impl<T: fmt::Debug> fmt::Debug for TruncatedDebug<T> { + 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<T> Deref for TruncatedDebug<T> { + type Target = T; + fn deref(&self) -> &T { + &self.0 + } +} + +/// WebGL Commands for a specific WebGLContext +#[derive(Debug, 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, 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<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), + EnableVertexAttribArray(u32), + FramebufferRenderbuffer(u32, u32, u32, Option<WebGLRenderbufferId>), + FramebufferTexture2D(u32, u32, u32, Option<WebGLTextureId>, i32), + GetExtensions(WebGLSender<String>), + GetShaderPrecisionFormat(u32, u32, WebGLSender<(i32, i32, i32)>), + GetFragDataLocation(WebGLProgramId, String, WebGLSender<i32>), + GetUniformLocation(WebGLProgramId, String, WebGLSender<i32>), + GetShaderInfoLog(WebGLShaderId, WebGLSender<String>), + GetProgramInfoLog(WebGLProgramId, WebGLSender<String>), + GetFramebufferAttachmentParameter(u32, u32, u32, WebGLSender<i32>), + GetRenderbufferParameter(u32, u32, WebGLSender<i32>), + CreateTransformFeedback(WebGLSender<u32>), + DeleteTransformFeedback(u32), + IsTransformFeedback(u32, WebGLSender<bool>), + BindTransformFeedback(u32, u32), + BeginTransformFeedback(u32), + EndTransformFeedback(), + PauseTransformFeedback(), + ResumeTransformFeedback(), + GetTransformFeedbackVarying(WebGLProgramId, u32, WebGLSender<(i32, u32, String)>), + TransformFeedbackVaryings(WebGLProgramId, Vec<String>, u32), + PolygonOffset(f32, f32), + RenderbufferStorage(u32, u32, i32, i32), + RenderbufferStorageMultisample(u32, i32, u32, i32, i32), + ReadPixels(Rect<u32>, u32, u32, IpcBytesSender), + ReadPixelsPP(Rect<i32>, 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<WebGLSyncId>), + IsSync(WebGLSyncId, WebGLSender<bool>), + ClientWaitSync(WebGLSyncId, u32, u64, WebGLSender<u32>), + WaitSync(WebGLSyncId, u32, i64), + GetSyncParameter(WebGLSyncId, u32, WebGLSender<u32>), + DeleteSync(WebGLSyncId), + Hint(u32, u32), + LineWidth(f32), + PixelStorei(u32, i32), + LinkProgram(WebGLProgramId, WebGLSender<ProgramLinkInfo>), + Uniform1f(i32, f32), + Uniform1fv(i32, Vec<f32>), + Uniform1i(i32, i32), + Uniform1ui(i32, u32), + Uniform1iv(i32, Vec<i32>), + Uniform1uiv(i32, Vec<u32>), + Uniform2f(i32, f32, f32), + Uniform2fv(i32, Vec<f32>), + Uniform2i(i32, i32, i32), + Uniform2ui(i32, u32, u32), + Uniform2iv(i32, Vec<i32>), + Uniform2uiv(i32, Vec<u32>), + Uniform3f(i32, f32, f32, f32), + Uniform3fv(i32, Vec<f32>), + Uniform3i(i32, i32, i32, i32), + Uniform3ui(i32, u32, u32, u32), + Uniform3iv(i32, Vec<i32>), + Uniform3uiv(i32, Vec<u32>), + Uniform4f(i32, f32, f32, f32, f32), + Uniform4fv(i32, Vec<f32>), + Uniform4i(i32, i32, i32, i32, i32), + Uniform4ui(i32, u32, u32, u32, u32), + Uniform4iv(i32, Vec<i32>), + Uniform4uiv(i32, Vec<u32>), + UniformMatrix2fv(i32, Vec<f32>), + UniformMatrix3fv(i32, Vec<f32>), + UniformMatrix4fv(i32, Vec<f32>), + UniformMatrix3x2fv(i32, Vec<f32>), + UniformMatrix4x2fv(i32, Vec<f32>), + UniformMatrix2x3fv(i32, Vec<f32>), + UniformMatrix4x3fv(i32, Vec<f32>), + UniformMatrix2x4fv(i32, Vec<f32>), + UniformMatrix3x4fv(i32, Vec<f32>), + UseProgram(Option<WebGLProgramId>), + ValidateProgram(WebGLProgramId), + VertexAttrib(u32, f32, f32, f32, f32), + VertexAttribI(u32, i32, i32, i32, i32), + VertexAttribU(u32, u32, u32, u32, u32), + VertexAttribPointer(u32, i32, u32, bool, i32, u32), + VertexAttribPointer2f(u32, i32, bool, i32, u32), + SetViewport(i32, i32, i32, i32), + TexImage2D { + target: u32, + level: u32, + internal_format: TexFormat, + size: Size2D<u32>, + 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<AlphaTreatment>, + y_axis_treatment: YAxisTreatment, + pixel_format: Option<PixelFormat>, + data: TruncatedDebug<IpcSharedMemory>, + }, + TexImage2DPBO { + target: u32, + level: u32, + internal_format: TexFormat, + size: Size2D<u32>, + format: TexFormat, + effective_data_type: u32, + unpacking_alignment: u32, + offset: i64, + }, + TexSubImage2D { + target: u32, + level: u32, + xoffset: i32, + yoffset: i32, + size: Size2D<u32>, + 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<AlphaTreatment>, + y_axis_treatment: YAxisTreatment, + pixel_format: Option<PixelFormat>, + data: TruncatedDebug<IpcSharedMemory>, + }, + CompressedTexImage2D { + target: u32, + level: u32, + internal_format: u32, + size: Size2D<u32>, + data: TruncatedDebug<IpcSharedMemory>, + }, + CompressedTexSubImage2D { + target: u32, + level: i32, + xoffset: i32, + yoffset: i32, + size: Size2D<u32>, + format: u32, + data: TruncatedDebug<IpcSharedMemory>, + }, + DrawingBufferWidth(WebGLSender<i32>), + DrawingBufferHeight(WebGLSender<i32>), + Finish(WebGLSender<()>), + Flush, + GenerateMipmap(u32), + CreateVertexArray(WebGLSender<Option<WebGLVertexArrayId>>), + DeleteVertexArray(WebGLVertexArrayId), + BindVertexArray(Option<WebGLVertexArrayId>), + GetParameterBool(ParameterBool, WebGLSender<bool>), + GetParameterBool4(ParameterBool4, WebGLSender<[bool; 4]>), + GetParameterInt(ParameterInt, WebGLSender<i32>), + GetParameterInt2(ParameterInt2, WebGLSender<[i32; 2]>), + GetParameterInt4(ParameterInt4, WebGLSender<[i32; 4]>), + GetParameterFloat(ParameterFloat, WebGLSender<f32>), + GetParameterFloat2(ParameterFloat2, WebGLSender<[f32; 2]>), + GetParameterFloat4(ParameterFloat4, WebGLSender<[f32; 4]>), + GetProgramValidateStatus(WebGLProgramId, WebGLSender<bool>), + GetProgramActiveUniforms(WebGLProgramId, WebGLSender<i32>), + GetCurrentVertexAttrib(u32, WebGLSender<[f32; 4]>), + GetTexParameterFloat(u32, TexParameterFloat, WebGLSender<f32>), + GetTexParameterInt(u32, TexParameterInt, WebGLSender<i32>), + GetTexParameterBool(u32, TexParameterBool, WebGLSender<bool>), + GetInternalFormatIntVec(u32, u32, InternalFormatIntVec, WebGLSender<Vec<i32>>), + TexParameteri(u32, u32, i32), + TexParameterf(u32, u32, f32), + TexStorage2D(u32, u32, TexFormat, u32, u32), + TexStorage3D(u32, u32, TexFormat, u32, u32, u32), + 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<bool>), + GetUniformBool2(WebGLProgramId, i32, WebGLSender<[bool; 2]>), + GetUniformBool3(WebGLProgramId, i32, WebGLSender<[bool; 3]>), + GetUniformBool4(WebGLProgramId, i32, WebGLSender<[bool; 4]>), + GetUniformInt(WebGLProgramId, i32, WebGLSender<i32>), + GetUniformInt2(WebGLProgramId, i32, WebGLSender<[i32; 2]>), + GetUniformInt3(WebGLProgramId, i32, WebGLSender<[i32; 3]>), + GetUniformInt4(WebGLProgramId, i32, WebGLSender<[i32; 4]>), + GetUniformUint(WebGLProgramId, i32, WebGLSender<u32>), + GetUniformUint2(WebGLProgramId, i32, WebGLSender<[u32; 2]>), + GetUniformUint3(WebGLProgramId, i32, WebGLSender<[u32; 3]>), + GetUniformUint4(WebGLProgramId, i32, WebGLSender<[u32; 4]>), + GetUniformFloat(WebGLProgramId, i32, WebGLSender<f32>), + 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<u32>), + GetUniformIndices(WebGLProgramId, Vec<String>, WebGLSender<Vec<u32>>), + GetActiveUniforms(WebGLProgramId, Vec<u32>, u32, WebGLSender<Vec<i32>>), + GetActiveUniformBlockName(WebGLProgramId, u32, WebGLSender<String>), + GetActiveUniformBlockParameter(WebGLProgramId, u32, u32, WebGLSender<Vec<i32>>), + UniformBlockBinding(WebGLProgramId, u32, u32), + InitializeFramebuffer { + color: bool, + depth: bool, + stencil: bool, + }, + BeginQuery(u32, WebGLQueryId), + DeleteQuery(WebGLQueryId), + EndQuery(u32), + GenerateQuery(WebGLSender<WebGLQueryId>), + GetQueryState(WebGLSender<u32>, WebGLQueryId, u32), + GenerateSampler(WebGLSender<WebGLSamplerId>), + DeleteSampler(WebGLSamplerId), + BindSampler(u32, WebGLSamplerId), + SetSamplerParameterFloat(WebGLSamplerId, u32, f32), + SetSamplerParameterInt(WebGLSamplerId, u32, i32), + GetSamplerParameterFloat(WebGLSamplerId, u32, WebGLSender<f32>), + GetSamplerParameterInt(WebGLSamplerId, u32, WebGLSender<i32>), + BindBufferBase(u32, u32, Option<WebGLBufferId>), + BindBufferRange(u32, u32, Option<WebGLBufferId>, i64, i64), + ClearBufferfv(u32, i32, Vec<f32>), + ClearBufferiv(u32, i32, Vec<i32>), + ClearBufferuiv(u32, i32, Vec<u32>), + ClearBufferfi(u32, i32, f32, i32), + InvalidateFramebuffer(u32, Vec<u32>), + InvalidateSubFramebuffer(u32, Vec<u32>, i32, i32, i32, i32), + FramebufferTextureLayer(u32, u32, Option<WebGLTextureId>, i32, i32), + ReadBuffer(u32), + DrawBuffers(Vec<u32>), +} + +/// WebXR layer management +#[derive(Debug, Deserialize, Serialize)] +pub enum WebXRCommand { + CreateLayerManager(WebGLSender<Result<WebXRLayerManagerId, WebXRError>>), + DestroyLayerManager(WebXRLayerManagerId), + CreateLayer( + WebXRLayerManagerId, + WebXRContextId, + WebXRLayerInit, + WebGLSender<Result<WebXRLayerId, WebXRError>>, + ), + DestroyLayer(WebXRLayerManagerId, WebXRContextId, WebXRLayerId), + BeginFrame( + WebXRLayerManagerId, + Vec<(WebXRContextId, WebXRLayerId)>, + WebGLSender<Result<Vec<WebXRSubImages>, WebXRError>>, + ), + EndFrame( + WebXRLayerManagerId, + Vec<(WebXRContextId, WebXRLayerId)>, + WebGLSender<Result<(), WebXRError>>, + ), +} + +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(<nonzero_type!($type)>::new_unchecked(id)) + } + + #[inline] + pub fn maybe_new(id: $type) -> Option<Self> { + <nonzero_type!($type)>::new(id).map($name) + } + + #[inline] + pub fn get(self) -> $type { + self.0.get() + } + } + + #[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 = <$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<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 ::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!(WebGLFramebufferId, 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); +define_resource_id!(WebXRLayerManagerId, u32); + +#[derive( + Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize, +)] +pub struct WebGLContextId(pub u64); + +impl From<WebXRContextId> for WebGLContextId { + fn from(id: WebXRContextId) -> Self { + Self(id.0) + } +} + +impl From<WebGLContextId> for WebXRContextId { + fn from(id: WebGLContextId) -> Self { + Self(id.0) + } +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub enum WebGLError { + InvalidEnum, + InvalidFramebufferOperation, + InvalidOperation, + InvalidValue, + OutOfMemory, + ContextLost, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub enum WebGLFramebufferBindingRequest { + Explicit(WebGLFramebufferId), + Default, +} + +pub type WebGLResult<T> = Result<T, WebGLError>; + +/// 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<str>, + /// The size of the uniform, if it is an array. + pub size: Option<i32>, + /// The type of the uniform. + pub type_: u32, + /// The index of the indexed uniform buffer binding, if it is bound. + pub bind_index: Option<u32>, +} + +impl ActiveUniformInfo { + pub fn name(&self) -> Cow<str> { + 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<Self> { + 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, + RasterizerDiscard = gl::RASTERIZER_DISCARD, + }), + 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, + PackRowLength = gl::PACK_ROW_LENGTH, + PackSkipPixels = gl::PACK_SKIP_PIXELS, + PackSkipRows = gl::PACK_SKIP_ROWS, + UnpackImageHeight = gl::UNPACK_IMAGE_HEIGHT, + UnpackRowLength = gl::UNPACK_ROW_LENGTH, + UnpackSkipImages = gl::UNPACK_SKIP_IMAGES, + UnpackSkipPixels = gl::UNPACK_SKIP_PIXELS, + UnpackSkipRows = gl::UNPACK_SKIP_ROWS, + }), + 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, + TextureMaxLod = gl::TEXTURE_MAX_LOD, + TextureMinLod = gl::TEXTURE_MIN_LOD, + }), + Int(TexParameterInt { + TextureWrapS = gl::TEXTURE_WRAP_S, + TextureWrapT = gl::TEXTURE_WRAP_T, + TextureWrapR = gl::TEXTURE_WRAP_R, + TextureBaseLevel = gl::TEXTURE_BASE_LEVEL, + TextureMinFilter = gl::TEXTURE_MIN_FILTER, + TextureMagFilter = gl::TEXTURE_MAG_FILTER, + TextureMaxLevel = gl::TEXTURE_MAX_LEVEL, + TextureCompareFunc = gl::TEXTURE_COMPARE_FUNC, + TextureCompareMode = gl::TEXTURE_COMPARE_MODE, + TextureImmutableLevels = gl::TEXTURE_IMMUTABLE_LEVELS, + }), + Bool(TexParameterBool { + TextureImmutableFormat = gl::TEXTURE_IMMUTABLE_FORMAT, + }), + } +} + +impl TexParameter { + pub fn required_webgl_version(self) -> WebGLVersion { + match self { + Self::Float(TexParameterFloat::TextureMaxAnisotropyExt) | + Self::Int(TexParameterInt::TextureWrapS) | + Self::Int(TexParameterInt::TextureWrapT) => WebGLVersion::WebGL1, + _ => WebGLVersion::WebGL2, + } + } +} + +parameters! { + InternalFormatParameter { + IntVec(InternalFormatIntVec { + Samples = gl::SAMPLES, + }), + } +} + +#[macro_export] +macro_rules! gl_enums { + ($(pub enum $name:ident { $($variant:ident = $mod:ident::$constant:ident,)+ })*) => { + $( + #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, malloc_size_of_derive::MallocSizeOf)] + #[derive(PartialEq, Serialize)] + #[repr(u32)] + pub enum $name { $($variant = $mod::$constant,)+ } + + impl $name { + pub fn from_gl_constant(constant: u32) -> Option<Self> { + 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, + ]; + + pub const ALPHA16F_ARB: u32 = 0x881C; + pub const ALPHA32F_ARB: u32 = 0x8816; + pub const LUMINANCE16F_ARB: u32 = 0x881E; + pub const LUMINANCE32F_ARB: u32 = 0x8818; + pub const LUMINANCE_ALPHA16F_ARB: u32 = 0x881F; + pub const LUMINANCE_ALPHA32F_ARB: u32 = 0x8819; +} + +gl_enums! { + pub enum TexFormat { + DepthComponent = gl::DEPTH_COMPONENT, + DepthStencil = gl::DEPTH_STENCIL, + Alpha = gl::ALPHA, + Alpha32f = gl_ext_constants::ALPHA32F_ARB, + Alpha16f = gl_ext_constants::ALPHA16F_ARB, + Red = gl::RED, + RedInteger = gl::RED_INTEGER, + RG = gl::RG, + RGInteger = gl::RG_INTEGER, + RGB = gl::RGB, + RGBInteger = gl::RGB_INTEGER, + RGBA = gl::RGBA, + RGBAInteger = gl::RGBA_INTEGER, + Luminance = gl::LUMINANCE, + LuminanceAlpha = gl::LUMINANCE_ALPHA, + Luminance32f = gl_ext_constants::LUMINANCE32F_ARB, + Luminance16f = gl_ext_constants::LUMINANCE16F_ARB, + LuminanceAlpha32f = gl_ext_constants::LUMINANCE_ALPHA32F_ARB, + LuminanceAlpha16f = gl_ext_constants::LUMINANCE_ALPHA16F_ARB, + 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, + R8 = gl::R8, + R8SNorm = gl::R8_SNORM, + R16f = gl::R16F, + R32f = gl::R32F, + R8ui = gl::R8UI, + R8i = gl::R8I, + R16ui = gl::R16UI, + R16i = gl::R16I, + R32ui = gl::R32UI, + R32i = gl::R32I, + RG8 = gl::RG8, + RG8SNorm = gl::RG8_SNORM, + RG16f = gl::RG16F, + RG32f = gl::RG32F, + RG8ui = gl::RG8UI, + RG8i = gl::RG8I, + RG16ui = gl::RG16UI, + RG16i = gl::RG16I, + RG32ui = gl::RG32UI, + RG32i = gl::RG32I, + RGB8 = gl::RGB8, + SRGB8 = gl::SRGB8, + RGB565 = gl::RGB565, + RGB8SNorm = gl::RGB8_SNORM, + R11fG11fB10f = gl::R11F_G11F_B10F, + RGB9E5 = gl::RGB9_E5, + RGB16f = gl::RGB16F, + RGB32f = gl::RGB32F, + RGB8ui = gl::RGB8UI, + RGB8i = gl::RGB8I, + RGB16ui = gl::RGB16UI, + RGB16i = gl::RGB16I, + RGB32ui = gl::RGB32UI, + RGB32i = gl::RGB32I, + RGBA8 = gl::RGBA8, + SRGB8Alpha8 = gl::SRGB8_ALPHA8, + RGBA8SNorm = gl::RGBA8_SNORM, + RGB5A1 = gl::RGB5_A1, + RGBA4 = gl::RGBA4, + RGB10A2 = gl::RGB10_A2, + RGBA16f = gl::RGBA16F, + RGBA32f = gl::RGBA32F, + RGBA8ui = gl::RGBA8UI, + RGBA8i = gl::RGBA8I, + RGB10A2ui = gl::RGB10_A2UI, + RGBA16ui = gl::RGBA16UI, + RGBA16i = gl::RGBA16I, + RGBA32i = gl::RGBA32I, + RGBA32ui = gl::RGBA32UI, + DepthComponent16 = gl::DEPTH_COMPONENT16, + DepthComponent24 = gl::DEPTH_COMPONENT24, + DepthComponent32f = gl::DEPTH_COMPONENT32F, + Depth24Stencil8 = gl::DEPTH24_STENCIL8, + Depth32fStencil8 = gl::DEPTH32F_STENCIL8, + } + + pub enum TexDataType { + Byte = gl::BYTE, + Int = gl::INT, + Short = gl::SHORT, + UnsignedByte = gl::UNSIGNED_BYTE, + UnsignedInt = gl::UNSIGNED_INT, + UnsignedInt10f11f11fRev = gl::UNSIGNED_INT_10F_11F_11F_REV, + UnsignedInt2101010Rev = gl::UNSIGNED_INT_2_10_10_10_REV, + UnsignedInt5999Rev = gl::UNSIGNED_INT_5_9_9_9_REV, + UnsignedInt248 = gl::UNSIGNED_INT_24_8, + UnsignedShort = gl::UNSIGNED_SHORT, + 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, + Float32UnsignedInt248Rev = gl::FLOAT_32_UNSIGNED_INT_24_8_REV, + } +} + +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.to_unsized() { + TexFormat::DepthStencil => 2, + TexFormat::LuminanceAlpha => 2, + TexFormat::RG | TexFormat::RGInteger => 2, + TexFormat::RGB | TexFormat::RGBInteger => 3, + TexFormat::RGBA | TexFormat::RGBAInteger => 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()) + } + + /// Returns whether this format is a known sized or unsized format. + pub fn is_sized(&self) -> bool { + match self { + TexFormat::DepthComponent | + TexFormat::DepthStencil | + TexFormat::Alpha | + TexFormat::Red | + TexFormat::RG | + TexFormat::RGB | + TexFormat::RGBA | + TexFormat::Luminance | + TexFormat::LuminanceAlpha => false, + _ => true, + } + } + + pub fn to_unsized(self) -> TexFormat { + match self { + TexFormat::R8 => TexFormat::Red, + TexFormat::R8SNorm => TexFormat::Red, + TexFormat::R16f => TexFormat::Red, + TexFormat::R32f => TexFormat::Red, + TexFormat::R8ui => TexFormat::RedInteger, + TexFormat::R8i => TexFormat::RedInteger, + TexFormat::R16ui => TexFormat::RedInteger, + TexFormat::R16i => TexFormat::RedInteger, + TexFormat::R32ui => TexFormat::RedInteger, + TexFormat::R32i => TexFormat::RedInteger, + TexFormat::RG8 => TexFormat::RG, + TexFormat::RG8SNorm => TexFormat::RG, + TexFormat::RG16f => TexFormat::RG, + TexFormat::RG32f => TexFormat::RG, + TexFormat::RG8ui => TexFormat::RGInteger, + TexFormat::RG8i => TexFormat::RGInteger, + TexFormat::RG16ui => TexFormat::RGInteger, + TexFormat::RG16i => TexFormat::RGInteger, + TexFormat::RG32ui => TexFormat::RGInteger, + TexFormat::RG32i => TexFormat::RGInteger, + TexFormat::RGB8 => TexFormat::RGB, + TexFormat::SRGB8 => TexFormat::RGB, + TexFormat::RGB565 => TexFormat::RGB, + TexFormat::RGB8SNorm => TexFormat::RGB, + TexFormat::R11fG11fB10f => TexFormat::RGB, + TexFormat::RGB9E5 => TexFormat::RGB, + TexFormat::RGB16f => TexFormat::RGB, + TexFormat::RGB32f => TexFormat::RGB, + TexFormat::RGB8ui => TexFormat::RGBInteger, + TexFormat::RGB8i => TexFormat::RGBInteger, + TexFormat::RGB16ui => TexFormat::RGBInteger, + TexFormat::RGB16i => TexFormat::RGBInteger, + TexFormat::RGB32ui => TexFormat::RGBInteger, + TexFormat::RGB32i => TexFormat::RGBInteger, + TexFormat::RGBA8 => TexFormat::RGBA, + TexFormat::SRGB8Alpha8 => TexFormat::RGBA, + TexFormat::RGBA8SNorm => TexFormat::RGBA, + TexFormat::RGB5A1 => TexFormat::RGBA, + TexFormat::RGBA4 => TexFormat::RGBA, + TexFormat::RGB10A2 => TexFormat::RGBA, + TexFormat::RGBA16f => TexFormat::RGBA, + TexFormat::RGBA32f => TexFormat::RGBA, + TexFormat::RGBA8ui => TexFormat::RGBAInteger, + TexFormat::RGBA8i => TexFormat::RGBAInteger, + TexFormat::RGB10A2ui => TexFormat::RGBAInteger, + TexFormat::RGBA16ui => TexFormat::RGBAInteger, + TexFormat::RGBA16i => TexFormat::RGBAInteger, + TexFormat::RGBA32i => TexFormat::RGBAInteger, + TexFormat::RGBA32ui => TexFormat::RGBAInteger, + TexFormat::DepthComponent16 => TexFormat::DepthComponent, + TexFormat::DepthComponent24 => TexFormat::DepthComponent, + TexFormat::DepthComponent32f => TexFormat::DepthComponent, + TexFormat::Depth24Stencil8 => TexFormat::DepthStencil, + TexFormat::Depth32fStencil8 => TexFormat::DepthStencil, + TexFormat::Alpha32f => TexFormat::Alpha, + TexFormat::Alpha16f => TexFormat::Alpha, + TexFormat::Luminance32f => TexFormat::Luminance, + TexFormat::Luminance16f => TexFormat::Luminance, + TexFormat::LuminanceAlpha32f => TexFormat::LuminanceAlpha, + TexFormat::LuminanceAlpha16f => TexFormat::LuminanceAlpha, + _ => self, + } + } + + pub fn compatible_data_types(self) -> &'static [TexDataType] { + match self { + TexFormat::RGB => &[ + TexDataType::UnsignedByte, + TexDataType::UnsignedShort565, + TexDataType::Float, + TexDataType::HalfFloat, + ][..], + TexFormat::RGBA => &[ + TexDataType::UnsignedByte, + TexDataType::UnsignedShort4444, + TexDataType::UnsignedShort5551, + TexDataType::Float, + TexDataType::HalfFloat, + ][..], + TexFormat::LuminanceAlpha => &[ + TexDataType::UnsignedByte, + TexDataType::Float, + TexDataType::HalfFloat, + ][..], + TexFormat::Luminance => &[ + TexDataType::UnsignedByte, + TexDataType::Float, + TexDataType::HalfFloat, + ][..], + TexFormat::Alpha => &[ + TexDataType::UnsignedByte, + TexDataType::Float, + TexDataType::HalfFloat, + ][..], + TexFormat::LuminanceAlpha32f => &[TexDataType::Float][..], + TexFormat::LuminanceAlpha16f => &[TexDataType::HalfFloat][..], + TexFormat::Luminance32f => &[TexDataType::Float][..], + TexFormat::Luminance16f => &[TexDataType::HalfFloat][..], + TexFormat::Alpha32f => &[TexDataType::Float][..], + TexFormat::Alpha16f => &[TexDataType::HalfFloat][..], + TexFormat::R8 => &[TexDataType::UnsignedByte][..], + TexFormat::R8SNorm => &[TexDataType::Byte][..], + TexFormat::R16f => &[TexDataType::HalfFloat, TexDataType::Float][..], + TexFormat::R32f => &[TexDataType::Float][..], + TexFormat::R8ui => &[TexDataType::UnsignedByte][..], + TexFormat::R8i => &[TexDataType::Byte][..], + TexFormat::R16ui => &[TexDataType::UnsignedShort][..], + TexFormat::R16i => &[TexDataType::Short][..], + TexFormat::R32ui => &[TexDataType::UnsignedInt][..], + TexFormat::R32i => &[TexDataType::Int][..], + TexFormat::RG8 => &[TexDataType::UnsignedByte][..], + TexFormat::RG8SNorm => &[TexDataType::Byte][..], + TexFormat::RG16f => &[TexDataType::HalfFloat, TexDataType::Float][..], + TexFormat::RG32f => &[TexDataType::Float][..], + TexFormat::RG8ui => &[TexDataType::UnsignedByte][..], + TexFormat::RG8i => &[TexDataType::Byte][..], + TexFormat::RG16ui => &[TexDataType::UnsignedShort][..], + TexFormat::RG16i => &[TexDataType::Short][..], + TexFormat::RG32ui => &[TexDataType::UnsignedInt][..], + TexFormat::RG32i => &[TexDataType::Int][..], + TexFormat::RGB8 => &[TexDataType::UnsignedByte][..], + TexFormat::SRGB8 => &[TexDataType::UnsignedByte][..], + TexFormat::RGB565 => &[TexDataType::UnsignedByte, TexDataType::UnsignedShort565][..], + TexFormat::RGB8SNorm => &[TexDataType::Byte][..], + TexFormat::R11fG11fB10f => &[ + TexDataType::UnsignedInt10f11f11fRev, + TexDataType::HalfFloat, + TexDataType::Float, + ][..], + TexFormat::RGB9E5 => &[ + TexDataType::UnsignedInt5999Rev, + TexDataType::HalfFloat, + TexDataType::Float, + ][..], + TexFormat::RGB16f => &[TexDataType::HalfFloat, TexDataType::Float][..], + TexFormat::RGB32f => &[TexDataType::Float][..], + TexFormat::RGB8ui => &[TexDataType::UnsignedByte][..], + TexFormat::RGB8i => &[TexDataType::Byte][..], + TexFormat::RGB16ui => &[TexDataType::UnsignedShort][..], + TexFormat::RGB16i => &[TexDataType::Short][..], + TexFormat::RGB32ui => &[TexDataType::UnsignedInt][..], + TexFormat::RGB32i => &[TexDataType::Int][..], + TexFormat::RGBA8 => &[TexDataType::UnsignedByte][..], + TexFormat::SRGB8Alpha8 => &[TexDataType::UnsignedByte][..], + TexFormat::RGBA8SNorm => &[TexDataType::Byte][..], + TexFormat::RGB5A1 => &[ + TexDataType::UnsignedByte, + TexDataType::UnsignedShort5551, + TexDataType::UnsignedInt2101010Rev, + ][..], + TexFormat::RGBA4 => &[TexDataType::UnsignedByte, TexDataType::UnsignedShort4444][..], + TexFormat::RGB10A2 => &[TexDataType::UnsignedInt2101010Rev][..], + TexFormat::RGBA16f => &[TexDataType::HalfFloat, TexDataType::Float][..], + TexFormat::RGBA32f => &[TexDataType::Float][..], + TexFormat::RGBA8ui => &[TexDataType::UnsignedByte][..], + TexFormat::RGBA8i => &[TexDataType::Byte][..], + TexFormat::RGB10A2ui => &[TexDataType::UnsignedInt2101010Rev][..], + TexFormat::RGBA16ui => &[TexDataType::UnsignedShort][..], + TexFormat::RGBA16i => &[TexDataType::Short][..], + TexFormat::RGBA32i => &[TexDataType::Int][..], + TexFormat::RGBA32ui => &[TexDataType::UnsignedInt][..], + TexFormat::DepthComponent16 => { + &[TexDataType::UnsignedShort, TexDataType::UnsignedInt][..] + }, + TexFormat::DepthComponent24 => &[TexDataType::UnsignedInt][..], + TexFormat::DepthComponent32f => &[TexDataType::Float][..], + TexFormat::Depth24Stencil8 => &[TexDataType::UnsignedInt248][..], + TexFormat::Depth32fStencil8 => &[TexDataType::Float32UnsignedInt248Rev][..], + TexFormat::CompressedRgbS3tcDxt1 | + TexFormat::CompressedRgbaS3tcDxt1 | + TexFormat::CompressedRgbaS3tcDxt3 | + TexFormat::CompressedRgbaS3tcDxt5 => &[TexDataType::UnsignedByte][..], + _ => &[][..], + } + } + + pub fn required_webgl_version(self) -> WebGLVersion { + match self { + TexFormat::DepthComponent | + TexFormat::Alpha | + TexFormat::RGB | + TexFormat::RGBA | + TexFormat::Luminance | + TexFormat::LuminanceAlpha | + TexFormat::CompressedRgbS3tcDxt1 | + TexFormat::CompressedRgbaS3tcDxt1 | + TexFormat::CompressedRgbaS3tcDxt3 | + TexFormat::CompressedRgbaS3tcDxt5 => WebGLVersion::WebGL1, + _ => WebGLVersion::WebGL2, + } + } + + pub fn usable_as_internal(self) -> bool { + !self.compatible_data_types().is_empty() + } +} + +#[derive(PartialEq)] +pub enum SizedDataType { + Int8, + Int16, + Int32, + Uint8, + Uint16, + Uint32, + Float32, +} + +impl TexDataType { + /// Returns the compatible sized data type for this texture data type. + pub fn sized_data_type(&self) -> SizedDataType { + match self { + TexDataType::Byte => SizedDataType::Int8, + TexDataType::UnsignedByte => SizedDataType::Uint8, + TexDataType::Short => SizedDataType::Int16, + TexDataType::UnsignedShort | + TexDataType::UnsignedShort4444 | + TexDataType::UnsignedShort5551 | + TexDataType::UnsignedShort565 => SizedDataType::Uint16, + TexDataType::Int => SizedDataType::Int32, + TexDataType::UnsignedInt | + TexDataType::UnsignedInt10f11f11fRev | + TexDataType::UnsignedInt2101010Rev | + TexDataType::UnsignedInt5999Rev | + TexDataType::UnsignedInt248 => SizedDataType::Uint32, + TexDataType::HalfFloat => SizedDataType::Uint16, + TexDataType::Float | TexDataType::Float32UnsignedInt248Rev => SizedDataType::Float32, + } + } + + /// Returns the size in bytes of each element of data. + pub fn element_size(&self) -> u32 { + use self::*; + match *self { + TexDataType::Byte | TexDataType::UnsignedByte => 1, + TexDataType::Short | + TexDataType::UnsignedShort | + TexDataType::UnsignedShort4444 | + TexDataType::UnsignedShort5551 | + TexDataType::UnsignedShort565 => 2, + TexDataType::Int | + TexDataType::UnsignedInt | + TexDataType::UnsignedInt10f11f11fRev | + TexDataType::UnsignedInt2101010Rev | + TexDataType::UnsignedInt5999Rev => 4, + TexDataType::UnsignedInt248 => 4, + TexDataType::Float => 4, + TexDataType::HalfFloat => 2, + TexDataType::Float32UnsignedInt248Rev => 4, + } + } + + /// 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::Byte => 1, + TexDataType::UnsignedByte => 1, + TexDataType::Short => 1, + TexDataType::UnsignedShort => 1, + TexDataType::UnsignedShort565 => 3, + TexDataType::UnsignedShort5551 => 4, + TexDataType::UnsignedShort4444 => 4, + TexDataType::Int => 1, + TexDataType::UnsignedInt => 1, + TexDataType::UnsignedInt10f11f11fRev => 3, + TexDataType::UnsignedInt2101010Rev => 4, + TexDataType::UnsignedInt5999Rev => 4, + TexDataType::UnsignedInt248 => 2, + TexDataType::Float => 1, + TexDataType::HalfFloat => 1, + TexDataType::Float32UnsignedInt248Rev => 2, + } + } + + pub fn required_webgl_version(self) -> WebGLVersion { + match self { + TexDataType::UnsignedByte | + TexDataType::UnsignedShort4444 | + TexDataType::UnsignedShort5551 | + TexDataType::UnsignedShort565 | + TexDataType::Float | + TexDataType::HalfFloat => WebGLVersion::WebGL1, + _ => WebGLVersion::WebGL2, + } + } +} + +#[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: i32, + pub max_program_texel_offset: u32, + pub max_uniform_block_size: u64, + pub max_combined_uniform_blocks: u32, + pub max_combined_vertex_uniform_components: u64, + pub max_combined_fragment_uniform_components: u64, + 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 max_3d_texture_size: u32, + pub max_array_texture_layers: u32, + pub uniform_buffer_offset_alignment: u32, + pub max_element_index: u64, + pub max_elements_indices: u32, + pub max_elements_vertices: u32, + pub max_fragment_input_components: u32, + pub max_samples: u32, + pub max_server_wait_timeout: std::time::Duration, + pub max_texture_lod_bias: f32, + pub max_varying_components: u32, + pub max_vertex_output_components: u32, +} diff --git a/components/shared/canvas/webgl_channel/ipc.rs b/components/shared/canvas/webgl_channel/ipc.rs new file mode 100644 index 00000000000..be320a69624 --- /dev/null +++ b/components/shared/canvas/webgl_channel/ipc.rs @@ -0,0 +1,15 @@ +/* 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 std::io; + +use serde::{Deserialize, Serialize}; + +pub type WebGLSender<T> = ipc_channel::ipc::IpcSender<T>; +pub type WebGLReceiver<T> = ipc_channel::ipc::IpcReceiver<T>; + +pub fn webgl_channel<T: Serialize + for<'de> Deserialize<'de>>( +) -> Result<(WebGLSender<T>, WebGLReceiver<T>), io::Error> { + ipc_channel::ipc::channel() +} diff --git a/components/shared/canvas/webgl_channel/mod.rs b/components/shared/canvas/webgl_channel/mod.rs new file mode 100644 index 00000000000..edfb90c8806 --- /dev/null +++ b/components/shared/canvas/webgl_channel/mod.rs @@ -0,0 +1,149 @@ +/* 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/. */ + +//! Enum wrappers to be able to select different channel implementations at runtime. + +mod ipc; +mod mpsc; + +use std::fmt; + +use ipc_channel::ipc::IpcSender; +use ipc_channel::router::ROUTER; +use lazy_static::lazy_static; +use serde::{Deserialize, Serialize}; +use servo_config::opts; + +use crate::webgl::WebGLMsg; + +lazy_static! { + static ref IS_MULTIPROCESS: bool = opts::multiprocess(); +} + +#[derive(Deserialize, Serialize)] +pub enum WebGLSender<T: Serialize> { + Ipc(ipc::WebGLSender<T>), + Mpsc(mpsc::WebGLSender<T>), +} + +impl<T> Clone for WebGLSender<T> +where + T: Serialize, +{ + fn clone(&self) -> Self { + match *self { + WebGLSender::Ipc(ref chan) => WebGLSender::Ipc(chan.clone()), + WebGLSender::Mpsc(ref chan) => WebGLSender::Mpsc(chan.clone()), + } + } +} + +impl<T: Serialize> fmt::Debug for WebGLSender<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "WebGLSender(..)") + } +} + +impl<T: Serialize> WebGLSender<T> { + #[inline] + pub fn send(&self, msg: T) -> WebGLSendResult { + match *self { + WebGLSender::Ipc(ref sender) => sender.send(msg).map_err(|_| ()), + WebGLSender::Mpsc(ref sender) => sender.send(msg).map_err(|_| ()), + } + } +} + +pub type WebGLSendResult = Result<(), ()>; + +pub enum WebGLReceiver<T> +where + T: for<'de> Deserialize<'de> + Serialize, +{ + Ipc(ipc::WebGLReceiver<T>), + Mpsc(mpsc::WebGLReceiver<T>), +} + +impl<T> WebGLReceiver<T> +where + T: for<'de> Deserialize<'de> + Serialize, +{ + pub fn recv(&self) -> Result<T, ()> { + match *self { + WebGLReceiver::Ipc(ref receiver) => receiver.recv().map_err(|_| ()), + WebGLReceiver::Mpsc(ref receiver) => receiver.recv().map_err(|_| ()), + } + } + + pub fn try_recv(&self) -> Result<T, ()> { + match *self { + WebGLReceiver::Ipc(ref receiver) => receiver.try_recv().map_err(|_| ()), + WebGLReceiver::Mpsc(ref receiver) => receiver.try_recv().map_err(|_| ()), + } + } + + pub fn into_inner(self) -> crossbeam_channel::Receiver<T> + where + T: Send + 'static, + { + match self { + WebGLReceiver::Ipc(receiver) => { + ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(receiver) + }, + WebGLReceiver::Mpsc(receiver) => receiver.into_inner(), + } + } +} + +pub fn webgl_channel<T>() -> Result<(WebGLSender<T>, WebGLReceiver<T>), ()> +where + T: for<'de> Deserialize<'de> + Serialize, +{ + if *IS_MULTIPROCESS { + ipc::webgl_channel() + .map(|(tx, rx)| (WebGLSender::Ipc(tx), WebGLReceiver::Ipc(rx))) + .map_err(|_| ()) + } else { + mpsc::webgl_channel().map(|(tx, rx)| (WebGLSender::Mpsc(tx), WebGLReceiver::Mpsc(rx))) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct WebGLChan(pub WebGLSender<WebGLMsg>); + +impl WebGLChan { + #[inline] + pub fn send(&self, msg: WebGLMsg) -> WebGLSendResult { + self.0.send(msg) + } + + pub fn to_ipc(&self) -> IpcSender<WebGLMsg> { + match self.0 { + WebGLSender::Ipc(ref sender) => sender.clone(), + WebGLSender::Mpsc(ref mpsc_sender) => { + let (sender, receiver) = + ipc_channel::ipc::channel().expect("IPC Channel creation failed"); + let mpsc_sender = mpsc_sender.clone(); + ipc_channel::router::ROUTER.add_route( + receiver.to_opaque(), + Box::new(move |message| { + if let Ok(message) = message.to() { + let _ = mpsc_sender.send(message); + } + }), + ); + sender + }, + } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct WebGLPipeline(pub WebGLChan); + +impl WebGLPipeline { + pub fn channel(&self) -> WebGLChan { + self.0.clone() + } +} diff --git a/components/shared/canvas/webgl_channel/mpsc.rs b/components/shared/canvas/webgl_channel/mpsc.rs new file mode 100644 index 00000000000..b7d0bfcc3da --- /dev/null +++ b/components/shared/canvas/webgl_channel/mpsc.rs @@ -0,0 +1,62 @@ +/* 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 serde::{Deserialize, Deserializer, Serialize, Serializer}; + +macro_rules! unreachable_serializable { + ($name:ident) => { + impl<T> Serialize for $name<T> { + fn serialize<S: Serializer>(&self, _: S) -> Result<S::Ok, S::Error> { + unreachable!(); + } + } + + impl<'a, T> Deserialize<'a> for $name<T> { + fn deserialize<D>(_: D) -> Result<$name<T>, D::Error> + where + D: Deserializer<'a>, + { + unreachable!(); + } + } + }; +} + +pub struct WebGLSender<T>(crossbeam_channel::Sender<T>); +pub struct WebGLReceiver<T>(crossbeam_channel::Receiver<T>); + +impl<T> Clone for WebGLSender<T> { + fn clone(&self) -> Self { + WebGLSender(self.0.clone()) + } +} + +impl<T> WebGLSender<T> { + #[inline] + pub fn send(&self, data: T) -> Result<(), crossbeam_channel::SendError<T>> { + self.0.send(data) + } +} + +impl<T> WebGLReceiver<T> { + #[inline] + pub fn recv(&self) -> Result<T, crossbeam_channel::RecvError> { + self.0.recv() + } + #[inline] + pub fn try_recv(&self) -> Result<T, crossbeam_channel::TryRecvError> { + self.0.try_recv() + } + pub fn into_inner(self) -> crossbeam_channel::Receiver<T> { + self.0 + } +} + +pub fn webgl_channel<T>() -> Result<(WebGLSender<T>, WebGLReceiver<T>), ()> { + let (sender, receiver) = crossbeam_channel::unbounded(); + Ok((WebGLSender(sender), WebGLReceiver(receiver))) +} + +unreachable_serializable!(WebGLReceiver); +unreachable_serializable!(WebGLSender); |