diff options
author | Martin Robinson <mrobinson@igalia.com> | 2023-10-05 19:47:39 +0200 |
---|---|---|
committer | Martin Robinson <mrobinson@igalia.com> | 2023-11-03 15:38:18 +0000 |
commit | f4d3af296c05260dfbb3deea4f8fa400cb6887d3 (patch) | |
tree | 169db2cc68e01a755b30500dd525f1a2ec2da861 /components/shared/canvas | |
parent | 863529d9622c68f0a9535225237eb5e5c5b8c757 (diff) | |
download | servo-f4d3af296c05260dfbb3deea4f8fa400cb6887d3.tar.gz servo-f4d3af296c05260dfbb3deea4f8fa400cb6887d3.zip |
Move `*_traits` and other shared types to `shared`
This is the start of the organization of types that are in their own
crates in order to break dependency cycles between other crates. The
idea here is that putting these packages into their own directory is the
first step toward cleaning them up. They have grown organically and it
is difficult to explain to new folks where to put new shared types. Many
of these crates contain more than traits or don't contain traits at all.
Notably, `script_traits` isn't touched because it is vendored from
Gecko. Eventually this will move to `third_party`.
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); |