webrender/renderer/
shade.rs

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