tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

shade.rs (52260B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 use api::{ImageBufferKind, units::DeviceSize};
      6 use crate::batch::{BatchKey, BatchKind, BrushBatchKind, BatchFeatures};
      7 use crate::composite::{CompositeFeatures, CompositeSurfaceFormat};
      8 use crate::device::{Device, Program, ShaderError};
      9 use crate::pattern::PatternKind;
     10 use crate::telemetry::Telemetry;
     11 use euclid::default::Transform3D;
     12 use glyph_rasterizer::GlyphFormat;
     13 use crate::renderer::{
     14    desc,
     15    BlendMode, DebugFlags, RendererError, WebRenderOptions,
     16    TextureSampler, VertexArrayKind, ShaderPrecacheFlags,
     17 };
     18 use crate::profiler::{self, RenderCommandLog, TransactionProfile, ns_to_ms};
     19 
     20 use gleam::gl::GlType;
     21 
     22 use std::cell::RefCell;
     23 use std::collections::VecDeque;
     24 use std::rc::Rc;
     25 
     26 use webrender_build::shader::{ShaderFeatures, ShaderFeatureFlags, get_shader_features};
     27 
     28 /// Which extension version to use for texture external support.
     29 #[derive(Clone, Copy, Debug, PartialEq)]
     30 enum TextureExternalVersion {
     31    // GL_OES_EGL_image_external_essl3 (Compatible with ESSL 3.0 and
     32    // later shaders, but not supported on all GLES 3 devices.)
     33    ESSL3,
     34    // GL_OES_EGL_image_external (Compatible with ESSL 1.0 shaders)
     35    ESSL1,
     36 }
     37 
     38 fn get_feature_string(kind: ImageBufferKind, texture_external_version: TextureExternalVersion) -> &'static str {
     39    match (kind, texture_external_version) {
     40        (ImageBufferKind::Texture2D, _) => "TEXTURE_2D",
     41        (ImageBufferKind::TextureRect, _) => "TEXTURE_RECT",
     42        (ImageBufferKind::TextureExternal, TextureExternalVersion::ESSL3) => "TEXTURE_EXTERNAL",
     43        (ImageBufferKind::TextureExternal, TextureExternalVersion::ESSL1) => "TEXTURE_EXTERNAL_ESSL1",
     44        (ImageBufferKind::TextureExternalBT709, _) => "TEXTURE_EXTERNAL_BT709",
     45    }
     46 }
     47 
     48 fn has_platform_support(kind: ImageBufferKind, device: &Device) -> bool {
     49    match (kind, device.gl().get_type()) {
     50        (ImageBufferKind::Texture2D, _) => true,
     51        (ImageBufferKind::TextureRect, GlType::Gles) => false,
     52        (ImageBufferKind::TextureRect, GlType::Gl) => true,
     53        (ImageBufferKind::TextureExternal, GlType::Gles) => true,
     54        (ImageBufferKind::TextureExternal, GlType::Gl) => false,
     55        (ImageBufferKind::TextureExternalBT709, GlType::Gles) => device.supports_extension("GL_EXT_YUV_target"),
     56        (ImageBufferKind::TextureExternalBT709, GlType::Gl) => false,
     57    }
     58 }
     59 
     60 pub const IMAGE_BUFFER_KINDS: [ImageBufferKind; 4] = [
     61    ImageBufferKind::Texture2D,
     62    ImageBufferKind::TextureRect,
     63    ImageBufferKind::TextureExternal,
     64    ImageBufferKind::TextureExternalBT709,
     65 ];
     66 
     67 const ADVANCED_BLEND_FEATURE: &str = "ADVANCED_BLEND";
     68 const ALPHA_FEATURE: &str = "ALPHA_PASS";
     69 const DEBUG_OVERDRAW_FEATURE: &str = "DEBUG_OVERDRAW";
     70 const DITHERING_FEATURE: &str = "DITHERING";
     71 const DUAL_SOURCE_FEATURE: &str = "DUAL_SOURCE_BLENDING";
     72 const FAST_PATH_FEATURE: &str = "FAST_PATH";
     73 
     74 pub(crate) enum ShaderKind {
     75    Primitive,
     76    Cache(VertexArrayKind),
     77    ClipCache(VertexArrayKind),
     78    Brush,
     79    Text,
     80    Composite,
     81    Clear,
     82    Copy,
     83 }
     84 
     85 pub struct LazilyCompiledShader {
     86    program: Option<Program>,
     87    name: &'static str,
     88    kind: ShaderKind,
     89    cached_projection: Transform3D<f32>,
     90    features: Vec<&'static str>,
     91 }
     92 
     93 impl LazilyCompiledShader {
     94    pub(crate) fn new(
     95        kind: ShaderKind,
     96        name: &'static str,
     97        unsorted_features: &[&'static str],
     98        shader_list: &ShaderFeatures,
     99    ) -> Result<Self, ShaderError> {
    100 
    101        let mut features = unsorted_features.to_vec();
    102        features.sort();
    103 
    104        // Ensure this shader config is in the available shader list so that we get
    105        // alerted if the list gets out-of-date when shaders or features are added.
    106        let config = features.join(",");
    107        assert!(
    108            shader_list.get(name).map_or(false, |f| f.contains(&config)),
    109            "shader \"{}\" with features \"{}\" not in available shader list",
    110            name,
    111            config,
    112        );
    113 
    114        let shader = LazilyCompiledShader {
    115            program: None,
    116            name,
    117            kind,
    118            //Note: this isn't really the default state, but there is no chance
    119            // an actual projection passed here would accidentally match.
    120            cached_projection: Transform3D::identity(),
    121            features,
    122        };
    123 
    124        Ok(shader)
    125    }
    126 
    127    pub fn precache(
    128        &mut self,
    129        device: &mut Device,
    130        flags: ShaderPrecacheFlags,
    131    ) -> Result<(), ShaderError> {
    132        let t0 = zeitstempel::now();
    133        let timer_id = Telemetry::start_shaderload_time();
    134        self.get_internal(device, flags, None)?;
    135        Telemetry::stop_and_accumulate_shaderload_time(timer_id);
    136        let t1 = zeitstempel::now();
    137        debug!("[C: {:.1} ms ] Precache {} {:?}",
    138            (t1 - t0) as f64 / 1000000.0,
    139            self.name,
    140            self.features
    141        );
    142        Ok(())
    143    }
    144 
    145    pub fn bind(
    146        &mut self,
    147        device: &mut Device,
    148        projection: &Transform3D<f32>,
    149        texture_size: Option<DeviceSize>,
    150        renderer_errors: &mut Vec<RendererError>,
    151        profile: &mut TransactionProfile,
    152        history: &mut Option<RenderCommandLog>,
    153    ) {
    154        if let Some(history) = history {
    155            history.set_shader(self.name);
    156        }
    157        let update_projection = self.cached_projection != *projection;
    158        let program = match self.get_internal(device, ShaderPrecacheFlags::FULL_COMPILE, Some(profile)) {
    159            Ok(program) => program,
    160            Err(e) => {
    161                renderer_errors.push(RendererError::from(e));
    162                return;
    163            }
    164        };
    165        device.bind_program(program);
    166        if let Some(texture_size) = texture_size {
    167            device.set_shader_texture_size(program, texture_size);
    168        }
    169        if update_projection {
    170            device.set_uniforms(program, projection);
    171            // thanks NLL for this (`program` technically borrows `self`)
    172            self.cached_projection = *projection;
    173        }
    174    }
    175 
    176    fn get_internal(
    177        &mut self,
    178        device: &mut Device,
    179        precache_flags: ShaderPrecacheFlags,
    180        mut profile: Option<&mut TransactionProfile>,
    181    ) -> Result<&mut Program, ShaderError> {
    182        if self.program.is_none() {
    183            let start_time = zeitstempel::now();
    184            let program = match self.kind {
    185                ShaderKind::Primitive | ShaderKind::Brush | ShaderKind::Text | ShaderKind::Clear | ShaderKind::Copy => {
    186                    create_prim_shader(
    187                        self.name,
    188                        device,
    189                        &self.features,
    190                    )
    191                }
    192                ShaderKind::Cache(..) => {
    193                    create_prim_shader(
    194                        self.name,
    195                        device,
    196                        &self.features,
    197                    )
    198                }
    199                ShaderKind::Composite => {
    200                    create_prim_shader(
    201                        self.name,
    202                        device,
    203                        &self.features,
    204                    )
    205                }
    206                ShaderKind::ClipCache(..) => {
    207                    create_clip_shader(
    208                        self.name,
    209                        device,
    210                        &self.features,
    211                    )
    212                }
    213            };
    214            self.program = Some(program?);
    215 
    216            if let Some(profile) = &mut profile {
    217                let end_time = zeitstempel::now();
    218                profile.add(profiler::SHADER_BUILD_TIME, ns_to_ms(end_time - start_time));
    219            }
    220        }
    221 
    222        let program = self.program.as_mut().unwrap();
    223 
    224        if precache_flags.contains(ShaderPrecacheFlags::FULL_COMPILE) && !program.is_initialized() {
    225            let start_time = zeitstempel::now();
    226 
    227            let vertex_format = match self.kind {
    228                ShaderKind::Primitive |
    229                ShaderKind::Brush |
    230                ShaderKind::Text => VertexArrayKind::Primitive,
    231                ShaderKind::Cache(format) => format,
    232                ShaderKind::ClipCache(format) => format,
    233                ShaderKind::Composite => VertexArrayKind::Composite,
    234                ShaderKind::Clear => VertexArrayKind::Clear,
    235                ShaderKind::Copy => VertexArrayKind::Copy,
    236            };
    237 
    238            let vertex_descriptor = match vertex_format {
    239                VertexArrayKind::Primitive => &desc::PRIM_INSTANCES,
    240                VertexArrayKind::LineDecoration => &desc::LINE,
    241                VertexArrayKind::FastLinearGradient => &desc::FAST_LINEAR_GRADIENT,
    242                VertexArrayKind::LinearGradient => &desc::LINEAR_GRADIENT,
    243                VertexArrayKind::RadialGradient => &desc::RADIAL_GRADIENT,
    244                VertexArrayKind::ConicGradient => &desc::CONIC_GRADIENT,
    245                VertexArrayKind::Blur => &desc::BLUR,
    246                VertexArrayKind::ClipRect => &desc::CLIP_RECT,
    247                VertexArrayKind::ClipBoxShadow => &desc::CLIP_BOX_SHADOW,
    248                VertexArrayKind::Border => &desc::BORDER,
    249                VertexArrayKind::Scale => &desc::SCALE,
    250                VertexArrayKind::SvgFilterNode => &desc::SVG_FILTER_NODE,
    251                VertexArrayKind::Composite => &desc::COMPOSITE,
    252                VertexArrayKind::Clear => &desc::CLEAR,
    253                VertexArrayKind::Copy => &desc::COPY,
    254                VertexArrayKind::Mask => &desc::MASK,
    255            };
    256 
    257            device.link_program(program, vertex_descriptor)?;
    258            device.bind_program(program);
    259            match self.kind {
    260                ShaderKind::ClipCache(..) => {
    261                    device.bind_shader_samplers(
    262                        &program,
    263                        &[
    264                            ("sColor0", TextureSampler::Color0),
    265                            ("sTransformPalette", TextureSampler::TransformPalette),
    266                            ("sRenderTasks", TextureSampler::RenderTasks),
    267                            ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF),
    268                            ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI),
    269                            ("sGpuBufferF", TextureSampler::GpuBufferF),
    270                            ("sGpuBufferI", TextureSampler::GpuBufferI),
    271                        ],
    272                    );
    273                }
    274                _ => {
    275                    device.bind_shader_samplers(
    276                        &program,
    277                        &[
    278                            ("sColor0", TextureSampler::Color0),
    279                            ("sColor1", TextureSampler::Color1),
    280                            ("sColor2", TextureSampler::Color2),
    281                            ("sDither", TextureSampler::Dither),
    282                            ("sTransformPalette", TextureSampler::TransformPalette),
    283                            ("sRenderTasks", TextureSampler::RenderTasks),
    284                            ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF),
    285                            ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI),
    286                            ("sClipMask", TextureSampler::ClipMask),
    287                            ("sGpuBufferF", TextureSampler::GpuBufferF),
    288                            ("sGpuBufferI", TextureSampler::GpuBufferI),
    289                        ],
    290                    );
    291                }
    292            }
    293 
    294            if let Some(profile) = &mut profile {
    295                let end_time = zeitstempel::now();
    296                profile.add(profiler::SHADER_BUILD_TIME, ns_to_ms(end_time - start_time));
    297            }
    298        }
    299 
    300        Ok(program)
    301    }
    302 
    303    fn deinit(self, device: &mut Device) {
    304        if let Some(program) = self.program {
    305            device.delete_program(program);
    306        }
    307    }
    308 }
    309 
    310 // A brush shader supports two modes:
    311 // opaque:
    312 //   Used for completely opaque primitives,
    313 //   or inside segments of partially
    314 //   opaque primitives. Assumes no need
    315 //   for clip masks, AA etc.
    316 // alpha:
    317 //   Used for brush primitives in the alpha
    318 //   pass. Assumes that AA should be applied
    319 //   along the primitive edge, and also that
    320 //   clip mask is present.
    321 struct BrushShader {
    322    opaque: ShaderHandle,
    323    alpha: ShaderHandle,
    324    advanced_blend: Option<ShaderHandle>,
    325    dual_source: Option<ShaderHandle>,
    326    debug_overdraw: ShaderHandle,
    327 }
    328 
    329 impl BrushShader {
    330    fn new(
    331        name: &'static str,
    332        features: &[&'static str],
    333        shader_list: &ShaderFeatures,
    334        use_advanced_blend: bool,
    335        use_dual_source: bool,
    336        loader: &mut ShaderLoader,
    337    ) -> Result<Self, ShaderError> {
    338        let opaque_features = features.to_vec();
    339        let opaque = loader.create_shader(
    340            ShaderKind::Brush,
    341            name,
    342            &opaque_features,
    343            &shader_list,
    344        )?;
    345 
    346        let mut alpha_features = opaque_features.to_vec();
    347        alpha_features.push(ALPHA_FEATURE);
    348 
    349        let alpha = loader.create_shader(
    350            ShaderKind::Brush,
    351            name,
    352            &alpha_features,
    353            &shader_list,
    354        )?;
    355 
    356        let advanced_blend = if use_advanced_blend {
    357            let mut advanced_blend_features = alpha_features.to_vec();
    358            advanced_blend_features.push(ADVANCED_BLEND_FEATURE);
    359 
    360            let shader = loader.create_shader(
    361                ShaderKind::Brush,
    362                name,
    363                &advanced_blend_features,
    364                &shader_list,
    365            )?;
    366 
    367            Some(shader)
    368        } else {
    369            None
    370        };
    371 
    372        let dual_source = if use_dual_source {
    373            let mut dual_source_features = alpha_features.to_vec();
    374            dual_source_features.push(DUAL_SOURCE_FEATURE);
    375 
    376            let shader = loader.create_shader(
    377                ShaderKind::Brush,
    378                name,
    379                &dual_source_features,
    380                &shader_list,
    381            )?;
    382 
    383            Some(shader)
    384        } else {
    385            None
    386        };
    387 
    388        let mut debug_overdraw_features = features.to_vec();
    389        debug_overdraw_features.push(DEBUG_OVERDRAW_FEATURE);
    390 
    391        let debug_overdraw = loader.create_shader(
    392            ShaderKind::Brush,
    393            name,
    394            &debug_overdraw_features,
    395            &shader_list,
    396        )?;
    397 
    398        Ok(BrushShader {
    399            opaque,
    400            alpha,
    401            advanced_blend,
    402            dual_source,
    403            debug_overdraw,
    404        })
    405    }
    406 
    407    fn get_handle(
    408        &mut self,
    409        blend_mode: BlendMode,
    410        features: BatchFeatures,
    411        debug_flags: DebugFlags,
    412    ) -> ShaderHandle {
    413        match blend_mode {
    414            _ if debug_flags.contains(DebugFlags::SHOW_OVERDRAW) => self.debug_overdraw,
    415            BlendMode::None => self.opaque,
    416            BlendMode::Alpha |
    417            BlendMode::PremultipliedAlpha |
    418            BlendMode::PremultipliedDestOut |
    419            BlendMode::Screen |
    420            BlendMode::PlusLighter |
    421            BlendMode::Exclusion => {
    422                if features.contains(BatchFeatures::ALPHA_PASS) {
    423                    self.alpha
    424                } else {
    425                    self.opaque
    426                }
    427            }
    428            BlendMode::Advanced(_) => {
    429                self.advanced_blend.expect("bug: no advanced blend shader loaded")
    430            }
    431            BlendMode::SubpixelDualSource |
    432            BlendMode::MultiplyDualSource => {
    433                self.dual_source.expect("bug: no dual source shader loaded")
    434            }
    435        }
    436    }
    437 }
    438 
    439 pub struct TextShader {
    440    simple: ShaderHandle,
    441    glyph_transform: ShaderHandle,
    442    debug_overdraw: ShaderHandle,
    443 }
    444 
    445 impl TextShader {
    446    fn new(
    447        name: &'static str,
    448        features: &[&'static str],
    449        shader_list: &ShaderFeatures,
    450        loader: &mut ShaderLoader,
    451    ) -> Result<Self, ShaderError> {
    452        let mut simple_features = features.to_vec();
    453        simple_features.push("ALPHA_PASS");
    454        simple_features.push("TEXTURE_2D");
    455 
    456        let simple = loader.create_shader(
    457            ShaderKind::Text,
    458            name,
    459            &simple_features,
    460            &shader_list,
    461        )?;
    462 
    463        let mut glyph_transform_features = features.to_vec();
    464        glyph_transform_features.push("GLYPH_TRANSFORM");
    465        glyph_transform_features.push("ALPHA_PASS");
    466        glyph_transform_features.push("TEXTURE_2D");
    467 
    468        let glyph_transform = loader.create_shader(
    469            ShaderKind::Text,
    470            name,
    471            &glyph_transform_features,
    472            &shader_list,
    473        )?;
    474 
    475        let mut debug_overdraw_features = features.to_vec();
    476        debug_overdraw_features.push("DEBUG_OVERDRAW");
    477        debug_overdraw_features.push("TEXTURE_2D");
    478 
    479        let debug_overdraw = loader.create_shader(
    480            ShaderKind::Text,
    481            name,
    482            &debug_overdraw_features,
    483            &shader_list,
    484        )?;
    485 
    486        Ok(TextShader { simple, glyph_transform, debug_overdraw })
    487    }
    488 
    489    pub fn get_handle(
    490        &mut self,
    491        glyph_format: GlyphFormat,
    492        debug_flags: DebugFlags,
    493    ) -> ShaderHandle {
    494        match glyph_format {
    495            _ if debug_flags.contains(DebugFlags::SHOW_OVERDRAW) => self.debug_overdraw,
    496            GlyphFormat::Alpha |
    497            GlyphFormat::Subpixel |
    498            GlyphFormat::Bitmap |
    499            GlyphFormat::ColorBitmap => self.simple,
    500            GlyphFormat::TransformedAlpha |
    501            GlyphFormat::TransformedSubpixel => self.glyph_transform,
    502        }
    503    }
    504 }
    505 
    506 fn create_prim_shader(
    507    name: &'static str,
    508    device: &mut Device,
    509    features: &[&'static str],
    510 ) -> Result<Program, ShaderError> {
    511    debug!("PrimShader {}", name);
    512 
    513    device.create_program(name, features)
    514 }
    515 
    516 fn create_clip_shader(
    517    name: &'static str,
    518    device: &mut Device,
    519    features: &[&'static str],
    520 ) -> Result<Program, ShaderError> {
    521    debug!("ClipShader {}", name);
    522 
    523    device.create_program(name, features)
    524 }
    525 
    526 #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
    527 pub struct ShaderHandle(usize);
    528 
    529 #[derive(Default)]
    530 pub struct ShaderLoader {
    531    shaders: Vec<LazilyCompiledShader>,
    532 }
    533 
    534 impl ShaderLoader {
    535    pub fn new() -> Self {
    536        Default::default()
    537    }
    538 
    539    pub fn create_shader(
    540        &mut self,
    541        kind: ShaderKind,
    542        name: &'static str,
    543        unsorted_features: &[&'static str],
    544        shader_list: &ShaderFeatures,
    545    ) -> Result<ShaderHandle, ShaderError> {
    546        let index = self.shaders.len();
    547        let shader = LazilyCompiledShader::new(
    548            kind,
    549            name,
    550            unsorted_features,
    551            shader_list,
    552        )?;
    553        self.shaders.push(shader);
    554        Ok(ShaderHandle(index))
    555    }
    556 
    557    pub fn precache(
    558        &mut self,
    559        shader: ShaderHandle,
    560        device: &mut Device,
    561        flags: ShaderPrecacheFlags,
    562    ) -> Result<(), ShaderError> {
    563        if !flags.intersects(ShaderPrecacheFlags::ASYNC_COMPILE | ShaderPrecacheFlags::FULL_COMPILE) {
    564            return Ok(());
    565        }
    566 
    567        self.shaders[shader.0].precache(device, flags)
    568    }
    569 
    570    pub fn all_handles(&self) -> Vec<ShaderHandle> {
    571        self.shaders.iter().enumerate().map(|(index, _)| ShaderHandle(index)).collect()
    572    }
    573 
    574    pub fn get(&mut self, handle: ShaderHandle) -> &mut LazilyCompiledShader {
    575        &mut self.shaders[handle.0]
    576    }
    577 
    578    pub fn deinit(self, device: &mut Device) {
    579        for shader in self.shaders {
    580            shader.deinit(device);
    581        }
    582    }
    583 }
    584 
    585 pub struct Shaders {
    586    loader: ShaderLoader,
    587 
    588    // These are "cache shaders". These shaders are used to
    589    // draw intermediate results to cache targets. The results
    590    // of these shaders are then used by the primitive shaders.
    591    cs_blur_rgba8: ShaderHandle,
    592    cs_border_segment: ShaderHandle,
    593    cs_border_solid: ShaderHandle,
    594    cs_scale: Vec<Option<ShaderHandle>>,
    595    cs_line_decoration: ShaderHandle,
    596    cs_fast_linear_gradient: ShaderHandle,
    597    cs_linear_gradient: ShaderHandle,
    598    cs_radial_gradient: ShaderHandle,
    599    cs_conic_gradient: ShaderHandle,
    600    cs_svg_filter_node: ShaderHandle,
    601 
    602    // Brush shaders
    603    brush_solid: BrushShader,
    604    brush_image: Vec<Option<BrushShader>>,
    605    brush_fast_image: Vec<Option<BrushShader>>,
    606    brush_blend: BrushShader,
    607    brush_mix_blend: BrushShader,
    608    brush_yuv_image: Vec<Option<BrushShader>>,
    609    brush_linear_gradient: BrushShader,
    610    brush_opacity: BrushShader,
    611    brush_opacity_aa: BrushShader,
    612 
    613    /// These are "cache clip shaders". These shaders are used to
    614    /// draw clip instances into the cached clip mask. The results
    615    /// of these shaders are also used by the primitive shaders.
    616    cs_clip_rectangle_slow: ShaderHandle,
    617    cs_clip_rectangle_fast: ShaderHandle,
    618    cs_clip_box_shadow: ShaderHandle,
    619 
    620    // The are "primitive shaders". These shaders draw and blend
    621    // final results on screen. They are aware of tile boundaries.
    622    // Most draw directly to the framebuffer, but some use inputs
    623    // from the cache shaders to draw. Specifically, the box
    624    // shadow primitive shader stretches the box shadow cache
    625    // output, and the cache_image shader blits the results of
    626    // a cache shader (e.g. blur) to the screen.
    627    ps_text_run: TextShader,
    628    ps_text_run_dual_source: Option<TextShader>,
    629 
    630    ps_split_composite: ShaderHandle,
    631    ps_quad_textured: ShaderHandle,
    632    ps_quad_gradient: ShaderHandle,
    633    #[allow(unused)] ps_quad_radial_gradient: ShaderHandle,
    634    #[allow(unused)] ps_quad_conic_gradient: ShaderHandle,
    635    ps_mask: ShaderHandle,
    636    ps_mask_fast: ShaderHandle,
    637    ps_clear: ShaderHandle,
    638    ps_copy: ShaderHandle,
    639 
    640    composite: CompositorShaders,
    641 }
    642 
    643 pub struct PendingShadersToPrecache {
    644    precache_flags: ShaderPrecacheFlags,
    645    remaining_shaders: VecDeque<ShaderHandle>,
    646 }
    647 
    648 impl Shaders {
    649    pub fn new(
    650        device: &mut Device,
    651        gl_type: GlType,
    652        options: &WebRenderOptions,
    653    ) -> Result<Self, ShaderError> {
    654        let use_dual_source_blending =
    655            device.get_capabilities().supports_dual_source_blending &&
    656            options.allow_dual_source_blending;
    657        let use_advanced_blend_equation =
    658            device.get_capabilities().supports_advanced_blend_equation &&
    659            options.allow_advanced_blend_equation;
    660 
    661        let texture_external_version = if device.get_capabilities().supports_image_external_essl3 {
    662            TextureExternalVersion::ESSL3
    663        } else {
    664            TextureExternalVersion::ESSL1
    665        };
    666        let mut shader_flags = get_shader_feature_flags(gl_type, texture_external_version, device);
    667        shader_flags.set(ShaderFeatureFlags::ADVANCED_BLEND_EQUATION, use_advanced_blend_equation);
    668        shader_flags.set(ShaderFeatureFlags::DUAL_SOURCE_BLENDING, use_dual_source_blending);
    669        shader_flags.set(ShaderFeatureFlags::DITHERING, options.enable_dithering);
    670        let shader_list = get_shader_features(shader_flags);
    671 
    672        let mut loader = ShaderLoader::new();
    673 
    674        let brush_solid = BrushShader::new(
    675            "brush_solid",
    676            &[],
    677            &shader_list,
    678            false /* advanced blend */,
    679            false /* dual source */,
    680            &mut loader,
    681        )?;
    682 
    683        let brush_blend = BrushShader::new(
    684            "brush_blend",
    685            &[],
    686            &shader_list,
    687            false /* advanced blend */,
    688            false /* dual source */,
    689            &mut loader,
    690        )?;
    691 
    692        let brush_mix_blend = BrushShader::new(
    693            "brush_mix_blend",
    694            &[],
    695            &shader_list,
    696            false /* advanced blend */,
    697            false /* dual source */,
    698            &mut loader,
    699        )?;
    700 
    701        let brush_linear_gradient = BrushShader::new(
    702            "brush_linear_gradient",
    703            if options.enable_dithering {
    704               &[DITHERING_FEATURE]
    705            } else {
    706               &[]
    707            },
    708            &shader_list,
    709            false /* advanced blend */,
    710            false /* dual source */,
    711            &mut loader,
    712        )?;
    713 
    714        let brush_opacity_aa = BrushShader::new(
    715            "brush_opacity",
    716            &["ANTIALIASING"],
    717            &shader_list,
    718            false /* advanced blend */,
    719            false /* dual source */,
    720            &mut loader,
    721        )?;
    722 
    723        let brush_opacity = BrushShader::new(
    724            "brush_opacity",
    725            &[],
    726            &shader_list,
    727            false /* advanced blend */,
    728            false /* dual source */,
    729            &mut loader,
    730        )?;
    731 
    732        let cs_blur_rgba8 = loader.create_shader(
    733            ShaderKind::Cache(VertexArrayKind::Blur),
    734            "cs_blur",
    735            &["COLOR_TARGET"],
    736            &shader_list,
    737        )?;
    738 
    739        let cs_svg_filter_node = loader.create_shader(
    740            ShaderKind::Cache(VertexArrayKind::SvgFilterNode),
    741            "cs_svg_filter_node",
    742            &[],
    743            &shader_list,
    744        )?;
    745 
    746        let ps_mask = loader.create_shader(
    747            ShaderKind::Cache(VertexArrayKind::Mask),
    748            "ps_quad_mask",
    749            &[],
    750            &shader_list,
    751        )?;
    752 
    753        let ps_mask_fast = loader.create_shader(
    754            ShaderKind::Cache(VertexArrayKind::Mask),
    755            "ps_quad_mask",
    756            &[FAST_PATH_FEATURE],
    757            &shader_list,
    758        )?;
    759 
    760        let cs_clip_rectangle_slow = loader.create_shader(
    761            ShaderKind::ClipCache(VertexArrayKind::ClipRect),
    762            "cs_clip_rectangle",
    763            &[],
    764            &shader_list,
    765        )?;
    766 
    767        let cs_clip_rectangle_fast = loader.create_shader(
    768            ShaderKind::ClipCache(VertexArrayKind::ClipRect),
    769            "cs_clip_rectangle",
    770            &[FAST_PATH_FEATURE],
    771            &shader_list,
    772        )?;
    773 
    774        let cs_clip_box_shadow = loader.create_shader(
    775            ShaderKind::ClipCache(VertexArrayKind::ClipBoxShadow),
    776            "cs_clip_box_shadow",
    777            &["TEXTURE_2D"],
    778            &shader_list,
    779        )?;
    780 
    781        let mut cs_scale = Vec::new();
    782        let scale_shader_num = IMAGE_BUFFER_KINDS.len();
    783        // PrimitiveShader is not clonable. Use push() to initialize the vec.
    784        for _ in 0 .. scale_shader_num {
    785            cs_scale.push(None);
    786        }
    787        for image_buffer_kind in &IMAGE_BUFFER_KINDS {
    788            if has_platform_support(*image_buffer_kind, device) {
    789                let feature_string = get_feature_string(
    790                    *image_buffer_kind,
    791                    texture_external_version,
    792                );
    793 
    794                let mut features = Vec::new();
    795                if feature_string != "" {
    796                    features.push(feature_string);
    797                }
    798 
    799                let shader = loader.create_shader(
    800                    ShaderKind::Cache(VertexArrayKind::Scale),
    801                    "cs_scale",
    802                    &features,
    803                    &shader_list,
    804                 )?;
    805 
    806                 let index = Self::get_compositing_shader_index(
    807                    *image_buffer_kind,
    808                 );
    809                 cs_scale[index] = Some(shader);
    810            }
    811        }
    812 
    813        // TODO(gw): The split composite + text shader are special cases - the only
    814        //           shaders used during normal scene rendering that aren't a brush
    815        //           shader. Perhaps we can unify these in future?
    816 
    817        let ps_text_run = TextShader::new("ps_text_run",
    818            &[],
    819            &shader_list,
    820            &mut loader,
    821        )?;
    822 
    823        let ps_text_run_dual_source = if use_dual_source_blending {
    824            let dual_source_features = vec![DUAL_SOURCE_FEATURE];
    825            Some(TextShader::new("ps_text_run",
    826                &dual_source_features,
    827                &shader_list,
    828                &mut loader,
    829            )?)
    830        } else {
    831            None
    832        };
    833 
    834        let ps_quad_textured = loader.create_shader(
    835            ShaderKind::Primitive,
    836            "ps_quad_textured",
    837            &[],
    838            &shader_list,
    839        )?;
    840 
    841        let ps_quad_gradient = loader.create_shader(
    842            ShaderKind::Primitive,
    843            "ps_quad_gradient",
    844            if options.enable_dithering {
    845               &[DITHERING_FEATURE]
    846            } else {
    847               &[]
    848            },
    849            &shader_list,
    850        )?;
    851 
    852        let ps_quad_radial_gradient = loader.create_shader(
    853            ShaderKind::Primitive,
    854            "ps_quad_radial_gradient",
    855            if options.enable_dithering {
    856               &[DITHERING_FEATURE]
    857            } else {
    858               &[]
    859            },
    860            &shader_list,
    861        )?;
    862 
    863        let ps_quad_conic_gradient = loader.create_shader(
    864            ShaderKind::Primitive,
    865            "ps_quad_conic_gradient",
    866            if options.enable_dithering {
    867               &[DITHERING_FEATURE]
    868            } else {
    869               &[]
    870            },
    871            &shader_list,
    872        )?;
    873 
    874        let ps_split_composite = loader.create_shader(
    875            ShaderKind::Primitive,
    876            "ps_split_composite",
    877            &[],
    878            &shader_list,
    879        )?;
    880 
    881        let ps_clear = loader.create_shader(
    882            ShaderKind::Clear,
    883            "ps_clear",
    884            &[],
    885            &shader_list,
    886        )?;
    887 
    888        let ps_copy = loader.create_shader(
    889            ShaderKind::Copy,
    890            "ps_copy",
    891            &[],
    892            &shader_list,
    893        )?;
    894 
    895        // All image configuration.
    896        let mut image_features = Vec::new();
    897        let mut brush_image = Vec::new();
    898        let mut brush_fast_image = Vec::new();
    899        // PrimitiveShader is not clonable. Use push() to initialize the vec.
    900        for _ in 0 .. IMAGE_BUFFER_KINDS.len() {
    901            brush_image.push(None);
    902            brush_fast_image.push(None);
    903        }
    904        for buffer_kind in 0 .. IMAGE_BUFFER_KINDS.len() {
    905            if !has_platform_support(IMAGE_BUFFER_KINDS[buffer_kind], device)
    906                // Brush shaders are not ESSL1 compatible
    907                || (IMAGE_BUFFER_KINDS[buffer_kind] == ImageBufferKind::TextureExternal
    908                    && texture_external_version == TextureExternalVersion::ESSL1)
    909            {
    910                continue;
    911            }
    912 
    913            let feature_string = get_feature_string(
    914                IMAGE_BUFFER_KINDS[buffer_kind],
    915                texture_external_version,
    916            );
    917            if feature_string != "" {
    918                image_features.push(feature_string);
    919            }
    920 
    921            brush_fast_image[buffer_kind] = Some(BrushShader::new(
    922                "brush_image",
    923                &image_features,
    924                &shader_list,
    925                use_advanced_blend_equation,
    926                use_dual_source_blending,
    927                &mut loader,
    928            )?);
    929 
    930            image_features.push("REPETITION");
    931            image_features.push("ANTIALIASING");
    932 
    933            brush_image[buffer_kind] = Some(BrushShader::new(
    934                "brush_image",
    935                &image_features,
    936                &shader_list,
    937                use_advanced_blend_equation,
    938                use_dual_source_blending,
    939                &mut loader,
    940            )?);
    941 
    942            image_features.clear();
    943        }
    944 
    945        // All yuv_image configuration.
    946        let mut yuv_features = Vec::new();
    947        let mut rgba_features = Vec::new();
    948        let mut fast_path_features = Vec::new();
    949        let yuv_shader_num = IMAGE_BUFFER_KINDS.len();
    950        let mut brush_yuv_image = Vec::new();
    951        // PrimitiveShader is not clonable. Use push() to initialize the vec.
    952        for _ in 0 .. yuv_shader_num {
    953            brush_yuv_image.push(None);
    954        }
    955        for image_buffer_kind in &IMAGE_BUFFER_KINDS {
    956            if has_platform_support(*image_buffer_kind, device) {
    957                yuv_features.push("YUV");
    958                fast_path_features.push("FAST_PATH");
    959 
    960                let index = Self::get_compositing_shader_index(
    961                    *image_buffer_kind,
    962                );
    963 
    964                let feature_string = get_feature_string(
    965                    *image_buffer_kind,
    966                    texture_external_version,
    967                );
    968                if feature_string != "" {
    969                    yuv_features.push(feature_string);
    970                    rgba_features.push(feature_string);
    971                    fast_path_features.push(feature_string);
    972                }
    973 
    974                // YUV shaders are not compatible with ESSL1
    975                if *image_buffer_kind != ImageBufferKind::TextureExternal ||
    976                    texture_external_version == TextureExternalVersion::ESSL3 {
    977                    let brush_shader = BrushShader::new(
    978                        "brush_yuv_image",
    979                        &yuv_features,
    980                        &shader_list,
    981                        false /* advanced blend */,
    982                        false /* dual source */,
    983                        &mut loader,
    984                    )?;
    985                    brush_yuv_image[index] = Some(brush_shader);
    986                }
    987 
    988                yuv_features.clear();
    989                rgba_features.clear();
    990                fast_path_features.clear();
    991            }
    992        }
    993 
    994        let cs_line_decoration = loader.create_shader(
    995            ShaderKind::Cache(VertexArrayKind::LineDecoration),
    996            "cs_line_decoration",
    997            &[],
    998            &shader_list,
    999        )?;
   1000 
   1001        let cs_fast_linear_gradient = loader.create_shader(
   1002            ShaderKind::Cache(VertexArrayKind::FastLinearGradient),
   1003            "cs_fast_linear_gradient",
   1004            &[],
   1005            &shader_list,
   1006        )?;
   1007 
   1008        let cs_linear_gradient = loader.create_shader(
   1009            ShaderKind::Cache(VertexArrayKind::LinearGradient),
   1010            "cs_linear_gradient",
   1011            if options.enable_dithering {
   1012               &[DITHERING_FEATURE]
   1013            } else {
   1014               &[]
   1015            },
   1016            &shader_list,
   1017        )?;
   1018 
   1019        let cs_radial_gradient = loader.create_shader(
   1020            ShaderKind::Cache(VertexArrayKind::RadialGradient),
   1021            "cs_radial_gradient",
   1022            if options.enable_dithering {
   1023               &[DITHERING_FEATURE]
   1024            } else {
   1025               &[]
   1026            },
   1027            &shader_list,
   1028        )?;
   1029 
   1030        let cs_conic_gradient = loader.create_shader(
   1031            ShaderKind::Cache(VertexArrayKind::ConicGradient),
   1032            "cs_conic_gradient",
   1033            if options.enable_dithering {
   1034               &[DITHERING_FEATURE]
   1035            } else {
   1036               &[]
   1037            },
   1038            &shader_list,
   1039        )?;
   1040 
   1041        let cs_border_segment = loader.create_shader(
   1042            ShaderKind::Cache(VertexArrayKind::Border),
   1043            "cs_border_segment",
   1044             &[],
   1045            &shader_list,
   1046        )?;
   1047 
   1048        let cs_border_solid = loader.create_shader(
   1049            ShaderKind::Cache(VertexArrayKind::Border),
   1050            "cs_border_solid",
   1051            &[],
   1052            &shader_list,
   1053        )?;
   1054 
   1055        let composite = CompositorShaders::new(device, gl_type, &mut loader)?;
   1056 
   1057        Ok(Shaders {
   1058            loader,
   1059 
   1060            cs_blur_rgba8,
   1061            cs_border_segment,
   1062            cs_line_decoration,
   1063            cs_fast_linear_gradient,
   1064            cs_linear_gradient,
   1065            cs_radial_gradient,
   1066            cs_conic_gradient,
   1067            cs_border_solid,
   1068            cs_scale,
   1069            cs_svg_filter_node,
   1070            brush_solid,
   1071            brush_image,
   1072            brush_fast_image,
   1073            brush_blend,
   1074            brush_mix_blend,
   1075            brush_yuv_image,
   1076            brush_linear_gradient,
   1077            brush_opacity,
   1078            brush_opacity_aa,
   1079            cs_clip_rectangle_slow,
   1080            cs_clip_rectangle_fast,
   1081            cs_clip_box_shadow,
   1082            ps_text_run,
   1083            ps_text_run_dual_source,
   1084            ps_quad_textured,
   1085            ps_quad_gradient,
   1086            ps_quad_radial_gradient,
   1087            ps_quad_conic_gradient,
   1088            ps_mask,
   1089            ps_mask_fast,
   1090            ps_split_composite,
   1091            ps_clear,
   1092            ps_copy,
   1093            composite,
   1094        })
   1095    }
   1096 
   1097    #[must_use]
   1098    pub fn precache_all(
   1099        &mut self,
   1100        precache_flags: ShaderPrecacheFlags,
   1101    ) -> PendingShadersToPrecache {
   1102        PendingShadersToPrecache {
   1103            precache_flags,
   1104            remaining_shaders: self.loader.all_handles().into(),
   1105        }
   1106    }
   1107 
   1108    /// Returns true if another call is needed, false if precaching is finished.
   1109    pub fn resume_precache(
   1110        &mut self,
   1111        device: &mut Device,
   1112        pending_shaders: &mut PendingShadersToPrecache,
   1113    ) -> Result<bool, ShaderError> {
   1114        let Some(next_shader) = pending_shaders.remaining_shaders.pop_front() else {
   1115            return Ok(false)
   1116        };
   1117 
   1118        self.loader.precache(next_shader, device, pending_shaders.precache_flags)?;
   1119        Ok(true)
   1120    }
   1121 
   1122    fn get_compositing_shader_index(buffer_kind: ImageBufferKind) -> usize {
   1123        buffer_kind as usize
   1124    }
   1125 
   1126    pub fn get_composite_shader(
   1127        &mut self,
   1128        format: CompositeSurfaceFormat,
   1129        buffer_kind: ImageBufferKind,
   1130        features: CompositeFeatures,
   1131    ) -> &mut LazilyCompiledShader {
   1132        let shader_handle = self.composite.get_handle(format, buffer_kind, features);
   1133        self.loader.get(shader_handle)
   1134    }
   1135 
   1136    pub fn get_scale_shader(
   1137        &mut self,
   1138        buffer_kind: ImageBufferKind,
   1139    ) -> &mut LazilyCompiledShader {
   1140        let shader_index = Self::get_compositing_shader_index(buffer_kind);
   1141        let shader_handle = self.cs_scale[shader_index]
   1142            .expect("bug: unsupported scale shader requested");
   1143        self.loader.get(shader_handle)
   1144    }
   1145 
   1146    pub fn get_quad_shader(
   1147        &mut self,
   1148        pattern: PatternKind
   1149    ) -> &mut LazilyCompiledShader {
   1150        let shader_handle = match pattern {
   1151            PatternKind::ColorOrTexture => self.ps_quad_textured,
   1152            PatternKind::RadialGradient => self.ps_quad_radial_gradient,
   1153            PatternKind::ConicGradient => self.ps_quad_conic_gradient,
   1154            PatternKind::Gradient => self.ps_quad_gradient,
   1155            PatternKind::Mask => unreachable!(),
   1156        };
   1157        self.loader.get(shader_handle)
   1158    }
   1159 
   1160    pub fn get(
   1161        &mut self,
   1162        key: &BatchKey,
   1163        features: BatchFeatures,
   1164        debug_flags: DebugFlags,
   1165        device: &Device,
   1166    ) -> &mut LazilyCompiledShader {
   1167        let shader_handle = self.get_handle(key, features, debug_flags, device);
   1168        self.loader.get(shader_handle)
   1169    }
   1170 
   1171    pub fn get_handle(
   1172        &mut self,
   1173        key: &BatchKey,
   1174        mut features: BatchFeatures,
   1175        debug_flags: DebugFlags,
   1176        device: &Device,
   1177    ) -> ShaderHandle {
   1178        match key.kind {
   1179            BatchKind::Quad(PatternKind::ColorOrTexture) => {
   1180                self.ps_quad_textured
   1181            }
   1182            BatchKind::Quad(PatternKind::RadialGradient) => {
   1183                self.ps_quad_radial_gradient
   1184            }
   1185            BatchKind::Quad(PatternKind::ConicGradient) => {
   1186                self.ps_quad_conic_gradient
   1187            }
   1188            BatchKind::Quad(PatternKind::Gradient) => {
   1189                self.ps_quad_gradient
   1190            }
   1191            BatchKind::Quad(PatternKind::Mask) => {
   1192                unreachable!();
   1193            }
   1194            BatchKind::SplitComposite => {
   1195                self.ps_split_composite
   1196            }
   1197            BatchKind::Brush(brush_kind) => {
   1198                // SWGL uses a native anti-aliasing implementation that bypasses the shader.
   1199                // Don't consider it in that case when deciding whether or not to use
   1200                // an alpha-pass shader.
   1201                if device.get_capabilities().uses_native_antialiasing {
   1202                    features.remove(BatchFeatures::ANTIALIASING);
   1203                }
   1204                let brush_shader = match brush_kind {
   1205                    BrushBatchKind::Solid => {
   1206                        &mut self.brush_solid
   1207                    }
   1208                    BrushBatchKind::Image(image_buffer_kind) => {
   1209                        if features.contains(BatchFeatures::ANTIALIASING) ||
   1210                            features.contains(BatchFeatures::REPETITION) {
   1211 
   1212                            self.brush_image[image_buffer_kind as usize]
   1213                                .as_mut()
   1214                                .expect("Unsupported image shader kind")
   1215                        } else {
   1216                            self.brush_fast_image[image_buffer_kind as usize]
   1217                            .as_mut()
   1218                                .expect("Unsupported image shader kind")
   1219                        }
   1220                    }
   1221                    BrushBatchKind::Blend => {
   1222                        &mut self.brush_blend
   1223                    }
   1224                    BrushBatchKind::MixBlend { .. } => {
   1225                        &mut self.brush_mix_blend
   1226                    }
   1227                    BrushBatchKind::LinearGradient => {
   1228                        // SWGL uses a native clip mask implementation that bypasses the shader.
   1229                        // Don't consider it in that case when deciding whether or not to use
   1230                        // an alpha-pass shader.
   1231                        if device.get_capabilities().uses_native_clip_mask {
   1232                            features.remove(BatchFeatures::CLIP_MASK);
   1233                        }
   1234                        // Gradient brushes can optimistically use the opaque shader even
   1235                        // with a blend mode if they don't require any features.
   1236                        if !features.intersects(
   1237                            BatchFeatures::ANTIALIASING
   1238                                | BatchFeatures::REPETITION
   1239                                | BatchFeatures::CLIP_MASK,
   1240                        ) {
   1241                            features.remove(BatchFeatures::ALPHA_PASS);
   1242                        }
   1243                        match brush_kind {
   1244                            BrushBatchKind::LinearGradient => &mut self.brush_linear_gradient,
   1245                            _ => panic!(),
   1246                        }
   1247                    }
   1248                    BrushBatchKind::YuvImage(image_buffer_kind, ..) => {
   1249                        let shader_index =
   1250                            Self::get_compositing_shader_index(image_buffer_kind);
   1251                        self.brush_yuv_image[shader_index]
   1252                            .as_mut()
   1253                            .expect("Unsupported YUV shader kind")
   1254                    }
   1255                    BrushBatchKind::Opacity => {
   1256                        if features.contains(BatchFeatures::ANTIALIASING) {
   1257                            &mut self.brush_opacity_aa
   1258                        } else {
   1259                            &mut self.brush_opacity
   1260                        }
   1261                    }
   1262                };
   1263                brush_shader.get_handle(key.blend_mode, features, debug_flags)
   1264            }
   1265            BatchKind::TextRun(glyph_format) => {
   1266                let text_shader = match key.blend_mode {
   1267                    BlendMode::SubpixelDualSource => self.ps_text_run_dual_source.as_mut().unwrap(),
   1268                    _ => &mut self.ps_text_run,
   1269                };
   1270                text_shader.get_handle(glyph_format, debug_flags)
   1271            }
   1272        }
   1273    }
   1274 
   1275    pub fn cs_blur_rgba8(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_blur_rgba8) }
   1276    pub fn cs_border_segment(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_segment) }
   1277    pub fn cs_border_solid(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_solid) }
   1278    pub fn cs_line_decoration(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_line_decoration) }
   1279    pub fn cs_fast_linear_gradient(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_fast_linear_gradient) }
   1280    pub fn cs_linear_gradient(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_linear_gradient) }
   1281    pub fn cs_radial_gradient(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_radial_gradient) }
   1282    pub fn cs_conic_gradient(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_conic_gradient) }
   1283    pub fn cs_svg_filter_node(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_svg_filter_node) }
   1284    pub fn cs_clip_rectangle_slow(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_clip_rectangle_slow) }
   1285    pub fn cs_clip_rectangle_fast(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_clip_rectangle_fast) }
   1286    pub fn cs_clip_box_shadow(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_clip_box_shadow) }
   1287    pub fn ps_quad_textured(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_quad_textured) }
   1288    pub fn ps_mask(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_mask) }
   1289    pub fn ps_mask_fast(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_mask_fast) }
   1290    pub fn ps_clear(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_clear) }
   1291    pub fn ps_copy(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_copy) }
   1292 
   1293    pub fn deinit(self, device: &mut Device) {
   1294        self.loader.deinit(device);
   1295    }
   1296 }
   1297 
   1298 pub type SharedShaders = Rc<RefCell<Shaders>>;
   1299 
   1300 pub struct CompositorShaders {
   1301    // Composite shaders. These are very simple shaders used to composite
   1302    // picture cache tiles into the framebuffer on platforms that do not have an
   1303    // OS Compositor (or we cannot use it).  Such an OS Compositor (such as
   1304    // DirectComposite or CoreAnimation) handles the composition of the picture
   1305    // cache tiles at a lower level (e.g. in DWM for Windows); in that case we
   1306    // directly hand the picture cache surfaces over to the OS Compositor, and
   1307    // our own Composite shaders below never run.
   1308    // To composite external (RGB) surfaces we need various permutations of
   1309    // shaders with WR_FEATURE flags on or off based on the type of image
   1310    // buffer we're sourcing from (see IMAGE_BUFFER_KINDS).
   1311    rgba: Vec<Option<ShaderHandle>>,
   1312    // A faster set of rgba composite shaders that do not support UV clamping
   1313    // or color modulation.
   1314    rgba_fast_path: Vec<Option<ShaderHandle>>,
   1315    // The same set of composite shaders but with WR_FEATURE_YUV added.
   1316    yuv_clip: Vec<Option<ShaderHandle>>,
   1317    yuv_fast: Vec<Option<ShaderHandle>>,
   1318 }
   1319 
   1320 impl CompositorShaders {
   1321    pub fn new(
   1322        device: &mut Device,
   1323        gl_type: GlType,
   1324        loader: &mut ShaderLoader,
   1325    )  -> Result<Self, ShaderError>  {
   1326        let mut yuv_clip_features = Vec::new();
   1327        let mut yuv_fast_features = Vec::new();
   1328        let mut rgba_features = Vec::new();
   1329        let mut fast_path_features = Vec::new();
   1330        let mut rgba = Vec::new();
   1331        let mut rgba_fast_path = Vec::new();
   1332        let mut yuv_clip = Vec::new();
   1333        let mut yuv_fast = Vec::new();
   1334 
   1335        let texture_external_version = if device.get_capabilities().supports_image_external_essl3 {
   1336            TextureExternalVersion::ESSL3
   1337        } else {
   1338            TextureExternalVersion::ESSL1
   1339        };
   1340 
   1341        let feature_flags = get_shader_feature_flags(gl_type, texture_external_version, device);
   1342        let shader_list = get_shader_features(feature_flags);
   1343 
   1344        for _ in 0..IMAGE_BUFFER_KINDS.len() {
   1345            yuv_clip.push(None);
   1346            yuv_fast.push(None);
   1347            rgba.push(None);
   1348            rgba_fast_path.push(None);
   1349        }
   1350 
   1351        for image_buffer_kind in &IMAGE_BUFFER_KINDS {
   1352            if !has_platform_support(*image_buffer_kind, device) {
   1353                continue;
   1354            }
   1355 
   1356            yuv_clip_features.push("YUV");
   1357            yuv_fast_features.push("YUV");
   1358            yuv_fast_features.push("FAST_PATH");
   1359            fast_path_features.push("FAST_PATH");
   1360 
   1361            let index = Self::get_shader_index(*image_buffer_kind);
   1362 
   1363            let feature_string = get_feature_string(
   1364                *image_buffer_kind,
   1365                texture_external_version,
   1366            );
   1367            if feature_string != "" {
   1368                yuv_clip_features.push(feature_string);
   1369                yuv_fast_features.push(feature_string);
   1370                rgba_features.push(feature_string);
   1371                fast_path_features.push(feature_string);
   1372            }
   1373 
   1374            // YUV shaders are not compatible with ESSL1
   1375            if *image_buffer_kind != ImageBufferKind::TextureExternal ||
   1376                texture_external_version == TextureExternalVersion::ESSL3 {
   1377 
   1378                yuv_clip[index] = Some(loader.create_shader(
   1379                    ShaderKind::Composite,
   1380                    "composite",
   1381                    &yuv_clip_features,
   1382                    &shader_list,
   1383                )?);
   1384 
   1385                yuv_fast[index] = Some(loader.create_shader(
   1386                    ShaderKind::Composite,
   1387                    "composite",
   1388                    &yuv_fast_features,
   1389                    &shader_list,
   1390                )?);
   1391            }
   1392 
   1393            rgba[index] = Some(loader.create_shader(
   1394                ShaderKind::Composite,
   1395                "composite",
   1396                &rgba_features,
   1397                &shader_list,
   1398            )?);
   1399 
   1400            rgba_fast_path[index] = Some(loader.create_shader(
   1401                ShaderKind::Composite,
   1402                "composite",
   1403                &fast_path_features,
   1404                &shader_list,
   1405            )?);
   1406 
   1407            yuv_fast_features.clear();
   1408            yuv_clip_features.clear();
   1409            rgba_features.clear();
   1410            fast_path_features.clear();
   1411        }
   1412 
   1413        Ok(CompositorShaders {
   1414            rgba,
   1415            rgba_fast_path,
   1416            yuv_clip,
   1417            yuv_fast,
   1418        })
   1419    }
   1420 
   1421    pub fn get_handle(
   1422        &mut self,
   1423        format: CompositeSurfaceFormat,
   1424        buffer_kind: ImageBufferKind,
   1425        features: CompositeFeatures,
   1426    ) -> ShaderHandle {
   1427        match format {
   1428            CompositeSurfaceFormat::Rgba => {
   1429                if features.contains(CompositeFeatures::NO_UV_CLAMP)
   1430                    && features.contains(CompositeFeatures::NO_COLOR_MODULATION)
   1431                    && features.contains(CompositeFeatures::NO_CLIP_MASK)
   1432                {
   1433                    let shader_index = Self::get_shader_index(buffer_kind);
   1434                    self.rgba_fast_path[shader_index]
   1435                        .expect("bug: unsupported rgba fast path shader requested")
   1436                } else {
   1437                    let shader_index = Self::get_shader_index(buffer_kind);
   1438                    self.rgba[shader_index]
   1439                        .expect("bug: unsupported rgba shader requested")
   1440                }
   1441            }
   1442            CompositeSurfaceFormat::Yuv => {
   1443                let shader_index = Self::get_shader_index(buffer_kind);
   1444                if features.contains(CompositeFeatures::NO_CLIP_MASK) {
   1445                    self.yuv_fast[shader_index]
   1446                        .expect("bug: unsupported yuv shader requested")
   1447                } else {
   1448                    self.yuv_clip[shader_index]
   1449                        .expect("bug: unsupported yuv shader requested")
   1450                }
   1451            }
   1452        }
   1453    }
   1454 
   1455    fn get_shader_index(buffer_kind: ImageBufferKind) -> usize {
   1456        buffer_kind as usize
   1457    }
   1458 }
   1459 
   1460 fn get_shader_feature_flags(
   1461    gl_type: GlType,
   1462    texture_external_version: TextureExternalVersion,
   1463    device: &Device
   1464 ) -> ShaderFeatureFlags {
   1465    match gl_type {
   1466        GlType::Gl => ShaderFeatureFlags::GL,
   1467        GlType::Gles => {
   1468            let mut flags = ShaderFeatureFlags::GLES;
   1469            flags |= match texture_external_version {
   1470                TextureExternalVersion::ESSL3 => ShaderFeatureFlags::TEXTURE_EXTERNAL,
   1471                TextureExternalVersion::ESSL1 => ShaderFeatureFlags::TEXTURE_EXTERNAL_ESSL1,
   1472            };
   1473            if device.supports_extension("GL_EXT_YUV_target") {
   1474                flags |= ShaderFeatureFlags::TEXTURE_EXTERNAL_BT709;
   1475            }
   1476            flags
   1477        }
   1478    }
   1479 }