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::{precise_time_ns, 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 = precise_time_ns();
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 = precise_time_ns();
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 = precise_time_ns();
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 = precise_time_ns();
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 = precise_time_ns();
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 = precise_time_ns();
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_radial_gradient: ShaderHandle,
659    ps_quad_conic_gradient: ShaderHandle,
660    ps_mask: ShaderHandle,
661    ps_mask_fast: ShaderHandle,
662    ps_clear: ShaderHandle,
663    ps_copy: ShaderHandle,
664
665    composite: CompositorShaders,
666}
667
668pub struct PendingShadersToPrecache {
669    precache_flags: ShaderPrecacheFlags,
670    remaining_shaders: VecDeque<ShaderHandle>,
671}
672
673impl Shaders {
674    pub fn new(
675        device: &mut Device,
676        gl_type: GlType,
677        options: &WebRenderOptions,
678    ) -> Result<Self, ShaderError> {
679        let use_dual_source_blending =
680            device.get_capabilities().supports_dual_source_blending &&
681            options.allow_dual_source_blending;
682        let use_advanced_blend_equation =
683            device.get_capabilities().supports_advanced_blend_equation &&
684            options.allow_advanced_blend_equation;
685
686        let texture_external_version = if device.get_capabilities().supports_image_external_essl3 {
687            TextureExternalVersion::ESSL3
688        } else {
689            TextureExternalVersion::ESSL1
690        };
691        let mut shader_flags = get_shader_feature_flags(gl_type, texture_external_version, device);
692        shader_flags.set(ShaderFeatureFlags::ADVANCED_BLEND_EQUATION, use_advanced_blend_equation);
693        shader_flags.set(ShaderFeatureFlags::DUAL_SOURCE_BLENDING, use_dual_source_blending);
694        shader_flags.set(ShaderFeatureFlags::DITHERING, options.enable_dithering);
695        let shader_list = get_shader_features(shader_flags);
696
697        let mut loader = ShaderLoader::new();
698
699        let brush_solid = BrushShader::new(
700            "brush_solid",
701            &[],
702            &shader_list,
703            false /* advanced blend */,
704            false /* dual source */,
705            &mut loader,
706        )?;
707
708        let brush_blend = BrushShader::new(
709            "brush_blend",
710            &[],
711            &shader_list,
712            false /* advanced blend */,
713            false /* dual source */,
714            &mut loader,
715        )?;
716
717        let brush_mix_blend = BrushShader::new(
718            "brush_mix_blend",
719            &[],
720            &shader_list,
721            false /* advanced blend */,
722            false /* dual source */,
723            &mut loader,
724        )?;
725
726        let brush_linear_gradient = BrushShader::new(
727            "brush_linear_gradient",
728            if options.enable_dithering {
729               &[DITHERING_FEATURE]
730            } else {
731               &[]
732            },
733            &shader_list,
734            false /* advanced blend */,
735            false /* dual source */,
736            &mut loader,
737        )?;
738
739        let brush_opacity_aa = BrushShader::new(
740            "brush_opacity",
741            &["ANTIALIASING"],
742            &shader_list,
743            false /* advanced blend */,
744            false /* dual source */,
745            &mut loader,
746        )?;
747
748        let brush_opacity = BrushShader::new(
749            "brush_opacity",
750            &[],
751            &shader_list,
752            false /* advanced blend */,
753            false /* dual source */,
754            &mut loader,
755        )?;
756
757        let cs_blur_rgba8 = loader.create_shader(
758            ShaderKind::Cache(VertexArrayKind::Blur),
759            "cs_blur",
760            &["COLOR_TARGET"],
761            &shader_list,
762        )?;
763
764        let cs_svg_filter = loader.create_shader(
765            ShaderKind::Cache(VertexArrayKind::SvgFilter),
766            "cs_svg_filter",
767            &[],
768            &shader_list,
769        )?;
770
771        let cs_svg_filter_node = loader.create_shader(
772            ShaderKind::Cache(VertexArrayKind::SvgFilterNode),
773            "cs_svg_filter_node",
774            &[],
775            &shader_list,
776        )?;
777
778        let ps_mask = loader.create_shader(
779            ShaderKind::Cache(VertexArrayKind::Mask),
780            "ps_quad_mask",
781            &[],
782            &shader_list,
783        )?;
784
785        let ps_mask_fast = loader.create_shader(
786            ShaderKind::Cache(VertexArrayKind::Mask),
787            "ps_quad_mask",
788            &[FAST_PATH_FEATURE],
789            &shader_list,
790        )?;
791
792        let cs_clip_rectangle_slow = loader.create_shader(
793            ShaderKind::ClipCache(VertexArrayKind::ClipRect),
794            "cs_clip_rectangle",
795            &[],
796            &shader_list,
797        )?;
798
799        let cs_clip_rectangle_fast = loader.create_shader(
800            ShaderKind::ClipCache(VertexArrayKind::ClipRect),
801            "cs_clip_rectangle",
802            &[FAST_PATH_FEATURE],
803            &shader_list,
804        )?;
805
806        let cs_clip_box_shadow = loader.create_shader(
807            ShaderKind::ClipCache(VertexArrayKind::ClipBoxShadow),
808            "cs_clip_box_shadow",
809            &["TEXTURE_2D"],
810            &shader_list,
811        )?;
812
813        let mut cs_scale = Vec::new();
814        let scale_shader_num = IMAGE_BUFFER_KINDS.len();
815        // PrimitiveShader is not clonable. Use push() to initialize the vec.
816        for _ in 0 .. scale_shader_num {
817            cs_scale.push(None);
818        }
819        for image_buffer_kind in &IMAGE_BUFFER_KINDS {
820            if has_platform_support(*image_buffer_kind, device) {
821                let feature_string = get_feature_string(
822                    *image_buffer_kind,
823                    texture_external_version,
824                );
825
826                let mut features = Vec::new();
827                if feature_string != "" {
828                    features.push(feature_string);
829                }
830
831                let shader = loader.create_shader(
832                    ShaderKind::Cache(VertexArrayKind::Scale),
833                    "cs_scale",
834                    &features,
835                    &shader_list,
836                 )?;
837
838                 let index = Self::get_compositing_shader_index(
839                    *image_buffer_kind,
840                 );
841                 cs_scale[index] = Some(shader);
842            }
843        }
844
845        // TODO(gw): The split composite + text shader are special cases - the only
846        //           shaders used during normal scene rendering that aren't a brush
847        //           shader. Perhaps we can unify these in future?
848
849        let ps_text_run = TextShader::new("ps_text_run",
850            &[],
851            &shader_list,
852            &mut loader,
853        )?;
854
855        let ps_text_run_dual_source = if use_dual_source_blending {
856            let dual_source_features = vec![DUAL_SOURCE_FEATURE];
857            Some(TextShader::new("ps_text_run",
858                &dual_source_features,
859                &shader_list,
860                &mut loader,
861            )?)
862        } else {
863            None
864        };
865
866        let ps_quad_textured = loader.create_shader(
867            ShaderKind::Primitive,
868            "ps_quad_textured",
869            &[],
870            &shader_list,
871        )?;
872
873        let ps_quad_radial_gradient = loader.create_shader(
874            ShaderKind::Primitive,
875            "ps_quad_radial_gradient",
876            &[],
877            &shader_list,
878        )?;
879
880        let ps_quad_conic_gradient = loader.create_shader(
881            ShaderKind::Primitive,
882            "ps_quad_conic_gradient",
883            &[],
884            &shader_list,
885        )?;
886
887        let ps_split_composite = loader.create_shader(
888            ShaderKind::Primitive,
889            "ps_split_composite",
890            &[],
891            &shader_list,
892        )?;
893
894        let ps_clear = loader.create_shader(
895            ShaderKind::Clear,
896            "ps_clear",
897            &[],
898            &shader_list,
899        )?;
900
901        let ps_copy = loader.create_shader(
902            ShaderKind::Copy,
903            "ps_copy",
904            &[],
905            &shader_list,
906        )?;
907
908        // All image configuration.
909        let mut image_features = Vec::new();
910        let mut brush_image = Vec::new();
911        let mut brush_fast_image = Vec::new();
912        // PrimitiveShader is not clonable. Use push() to initialize the vec.
913        for _ in 0 .. IMAGE_BUFFER_KINDS.len() {
914            brush_image.push(None);
915            brush_fast_image.push(None);
916        }
917        for buffer_kind in 0 .. IMAGE_BUFFER_KINDS.len() {
918            if !has_platform_support(IMAGE_BUFFER_KINDS[buffer_kind], device)
919                // Brush shaders are not ESSL1 compatible
920                || (IMAGE_BUFFER_KINDS[buffer_kind] == ImageBufferKind::TextureExternal
921                    && texture_external_version == TextureExternalVersion::ESSL1)
922            {
923                continue;
924            }
925
926            let feature_string = get_feature_string(
927                IMAGE_BUFFER_KINDS[buffer_kind],
928                texture_external_version,
929            );
930            if feature_string != "" {
931                image_features.push(feature_string);
932            }
933
934            brush_fast_image[buffer_kind] = Some(BrushShader::new(
935                "brush_image",
936                &image_features,
937                &shader_list,
938                use_advanced_blend_equation,
939                use_dual_source_blending,
940                &mut loader,
941            )?);
942
943            image_features.push("REPETITION");
944            image_features.push("ANTIALIASING");
945
946            brush_image[buffer_kind] = Some(BrushShader::new(
947                "brush_image",
948                &image_features,
949                &shader_list,
950                use_advanced_blend_equation,
951                use_dual_source_blending,
952                &mut loader,
953            )?);
954
955            image_features.clear();
956        }
957
958        // All yuv_image configuration.
959        let mut yuv_features = Vec::new();
960        let mut rgba_features = Vec::new();
961        let mut fast_path_features = Vec::new();
962        let yuv_shader_num = IMAGE_BUFFER_KINDS.len();
963        let mut brush_yuv_image = Vec::new();
964        // PrimitiveShader is not clonable. Use push() to initialize the vec.
965        for _ in 0 .. yuv_shader_num {
966            brush_yuv_image.push(None);
967        }
968        for image_buffer_kind in &IMAGE_BUFFER_KINDS {
969            if has_platform_support(*image_buffer_kind, device) {
970                yuv_features.push("YUV");
971                fast_path_features.push("FAST_PATH");
972
973                let index = Self::get_compositing_shader_index(
974                    *image_buffer_kind,
975                );
976
977                let feature_string = get_feature_string(
978                    *image_buffer_kind,
979                    texture_external_version,
980                );
981                if feature_string != "" {
982                    yuv_features.push(feature_string);
983                    rgba_features.push(feature_string);
984                    fast_path_features.push(feature_string);
985                }
986
987                // YUV shaders are not compatible with ESSL1
988                if *image_buffer_kind != ImageBufferKind::TextureExternal ||
989                    texture_external_version == TextureExternalVersion::ESSL3 {
990                    let brush_shader = BrushShader::new(
991                        "brush_yuv_image",
992                        &yuv_features,
993                        &shader_list,
994                        false /* advanced blend */,
995                        false /* dual source */,
996                        &mut loader,
997                    )?;
998                    brush_yuv_image[index] = Some(brush_shader);
999                }
1000
1001                yuv_features.clear();
1002                rgba_features.clear();
1003                fast_path_features.clear();
1004            }
1005        }
1006
1007        let cs_line_decoration = loader.create_shader(
1008            ShaderKind::Cache(VertexArrayKind::LineDecoration),
1009            "cs_line_decoration",
1010            &[],
1011            &shader_list,
1012        )?;
1013
1014        let cs_fast_linear_gradient = loader.create_shader(
1015            ShaderKind::Cache(VertexArrayKind::FastLinearGradient),
1016            "cs_fast_linear_gradient",
1017            &[],
1018            &shader_list,
1019        )?;
1020
1021        let cs_linear_gradient = loader.create_shader(
1022            ShaderKind::Cache(VertexArrayKind::LinearGradient),
1023            "cs_linear_gradient",
1024            &[],
1025            &shader_list,
1026        )?;
1027
1028        let cs_radial_gradient = loader.create_shader(
1029            ShaderKind::Cache(VertexArrayKind::RadialGradient),
1030            "cs_radial_gradient",
1031            &[],
1032            &shader_list,
1033        )?;
1034
1035        let cs_conic_gradient = loader.create_shader(
1036            ShaderKind::Cache(VertexArrayKind::ConicGradient),
1037            "cs_conic_gradient",
1038            &[],
1039            &shader_list,
1040        )?;
1041
1042        let cs_border_segment = loader.create_shader(
1043            ShaderKind::Cache(VertexArrayKind::Border),
1044            "cs_border_segment",
1045             &[],
1046            &shader_list,
1047        )?;
1048
1049        let cs_border_solid = loader.create_shader(
1050            ShaderKind::Cache(VertexArrayKind::Border),
1051            "cs_border_solid",
1052            &[],
1053            &shader_list,
1054        )?;
1055
1056        let composite = CompositorShaders::new(device, gl_type, &mut loader)?;
1057
1058        Ok(Shaders {
1059            loader,
1060
1061            cs_blur_rgba8,
1062            cs_border_segment,
1063            cs_line_decoration,
1064            cs_fast_linear_gradient,
1065            cs_linear_gradient,
1066            cs_radial_gradient,
1067            cs_conic_gradient,
1068            cs_border_solid,
1069            cs_scale,
1070            cs_svg_filter,
1071            cs_svg_filter_node,
1072            brush_solid,
1073            brush_image,
1074            brush_fast_image,
1075            brush_blend,
1076            brush_mix_blend,
1077            brush_yuv_image,
1078            brush_linear_gradient,
1079            brush_opacity,
1080            brush_opacity_aa,
1081            cs_clip_rectangle_slow,
1082            cs_clip_rectangle_fast,
1083            cs_clip_box_shadow,
1084            ps_text_run,
1085            ps_text_run_dual_source,
1086            ps_quad_textured,
1087            ps_quad_radial_gradient,
1088            ps_quad_conic_gradient,
1089            ps_mask,
1090            ps_mask_fast,
1091            ps_split_composite,
1092            ps_clear,
1093            ps_copy,
1094            composite,
1095        })
1096    }
1097
1098    #[must_use]
1099    pub fn precache_all(
1100        &mut self,
1101        precache_flags: ShaderPrecacheFlags,
1102    ) -> PendingShadersToPrecache {
1103        PendingShadersToPrecache {
1104            precache_flags,
1105            remaining_shaders: self.loader.all_handles().into(),
1106        }
1107    }
1108
1109    /// Returns true if another call is needed, false if precaching is finished.
1110    pub fn resume_precache(
1111        &mut self,
1112        device: &mut Device,
1113        pending_shaders: &mut PendingShadersToPrecache,
1114    ) -> Result<bool, ShaderError> {
1115        let Some(next_shader) = pending_shaders.remaining_shaders.pop_front() else {
1116            return Ok(false)
1117        };
1118
1119        self.loader.precache(next_shader, device, pending_shaders.precache_flags)?;
1120        Ok(true)
1121    }
1122
1123    fn get_compositing_shader_index(buffer_kind: ImageBufferKind) -> usize {
1124        buffer_kind as usize
1125    }
1126
1127    pub fn get_composite_shader(
1128        &mut self,
1129        format: CompositeSurfaceFormat,
1130        buffer_kind: ImageBufferKind,
1131        features: CompositeFeatures,
1132    ) -> &mut LazilyCompiledShader {
1133        let shader_handle = self.composite.get_handle(format, buffer_kind, features);
1134        self.loader.get(shader_handle)
1135    }
1136
1137    pub fn get_scale_shader(
1138        &mut self,
1139        buffer_kind: ImageBufferKind,
1140    ) -> &mut LazilyCompiledShader {
1141        let shader_index = Self::get_compositing_shader_index(buffer_kind);
1142        let shader_handle = self.cs_scale[shader_index]
1143            .expect("bug: unsupported scale shader requested");
1144        self.loader.get(shader_handle)
1145    }
1146
1147    pub fn get_quad_shader(
1148        &mut self,
1149        pattern: PatternKind
1150    ) -> &mut LazilyCompiledShader {
1151        let shader_handle = match pattern {
1152            PatternKind::ColorOrTexture => self.ps_quad_textured,
1153            PatternKind::RadialGradient => self.ps_quad_radial_gradient,
1154            PatternKind::ConicGradient => self.ps_quad_conic_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::Mask) => {
1189                unreachable!();
1190            }
1191            BatchKind::SplitComposite => {
1192                self.ps_split_composite
1193            }
1194            BatchKind::Brush(brush_kind) => {
1195                // SWGL uses a native anti-aliasing implementation that bypasses the shader.
1196                // Don't consider it in that case when deciding whether or not to use
1197                // an alpha-pass shader.
1198                if device.get_capabilities().uses_native_antialiasing {
1199                    features.remove(BatchFeatures::ANTIALIASING);
1200                }
1201                let brush_shader = match brush_kind {
1202                    BrushBatchKind::Solid => {
1203                        &mut self.brush_solid
1204                    }
1205                    BrushBatchKind::Image(image_buffer_kind) => {
1206                        if features.contains(BatchFeatures::ANTIALIASING) ||
1207                            features.contains(BatchFeatures::REPETITION) {
1208
1209                            self.brush_image[image_buffer_kind as usize]
1210                                .as_mut()
1211                                .expect("Unsupported image shader kind")
1212                        } else {
1213                            self.brush_fast_image[image_buffer_kind as usize]
1214                            .as_mut()
1215                                .expect("Unsupported image shader kind")
1216                        }
1217                    }
1218                    BrushBatchKind::Blend => {
1219                        &mut self.brush_blend
1220                    }
1221                    BrushBatchKind::MixBlend { .. } => {
1222                        &mut self.brush_mix_blend
1223                    }
1224                    BrushBatchKind::LinearGradient => {
1225                        // SWGL uses a native clip mask implementation that bypasses the shader.
1226                        // Don't consider it in that case when deciding whether or not to use
1227                        // an alpha-pass shader.
1228                        if device.get_capabilities().uses_native_clip_mask {
1229                            features.remove(BatchFeatures::CLIP_MASK);
1230                        }
1231                        // Gradient brushes can optimistically use the opaque shader even
1232                        // with a blend mode if they don't require any features.
1233                        if !features.intersects(
1234                            BatchFeatures::ANTIALIASING
1235                                | BatchFeatures::REPETITION
1236                                | BatchFeatures::CLIP_MASK,
1237                        ) {
1238                            features.remove(BatchFeatures::ALPHA_PASS);
1239                        }
1240                        match brush_kind {
1241                            BrushBatchKind::LinearGradient => &mut self.brush_linear_gradient,
1242                            _ => panic!(),
1243                        }
1244                    }
1245                    BrushBatchKind::YuvImage(image_buffer_kind, ..) => {
1246                        let shader_index =
1247                            Self::get_compositing_shader_index(image_buffer_kind);
1248                        self.brush_yuv_image[shader_index]
1249                            .as_mut()
1250                            .expect("Unsupported YUV shader kind")
1251                    }
1252                    BrushBatchKind::Opacity => {
1253                        if features.contains(BatchFeatures::ANTIALIASING) {
1254                            &mut self.brush_opacity_aa
1255                        } else {
1256                            &mut self.brush_opacity
1257                        }
1258                    }
1259                };
1260                brush_shader.get_handle(key.blend_mode, features, debug_flags)
1261            }
1262            BatchKind::TextRun(glyph_format) => {
1263                let text_shader = match key.blend_mode {
1264                    BlendMode::SubpixelDualSource => self.ps_text_run_dual_source.as_mut().unwrap(),
1265                    _ => &mut self.ps_text_run,
1266                };
1267                text_shader.get_handle(glyph_format, debug_flags)
1268            }
1269        }
1270    }
1271
1272    pub fn cs_blur_rgba8(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_blur_rgba8) }
1273    pub fn cs_border_segment(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_segment) }
1274    pub fn cs_border_solid(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_solid) }
1275    pub fn cs_line_decoration(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_line_decoration) }
1276    pub fn cs_fast_linear_gradient(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_fast_linear_gradient) }
1277    pub fn cs_linear_gradient(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_linear_gradient) }
1278    pub fn cs_radial_gradient(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_radial_gradient) }
1279    pub fn cs_conic_gradient(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_conic_gradient) }
1280    pub fn cs_svg_filter(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_svg_filter) }
1281    pub fn cs_svg_filter_node(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_svg_filter_node) }
1282    pub fn cs_clip_rectangle_slow(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_clip_rectangle_slow) }
1283    pub fn cs_clip_rectangle_fast(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_clip_rectangle_fast) }
1284    pub fn cs_clip_box_shadow(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_clip_box_shadow) }
1285    pub fn ps_quad_textured(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_quad_textured) }
1286    pub fn ps_mask(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_mask) }
1287    pub fn ps_mask_fast(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_mask_fast) }
1288    pub fn ps_clear(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_clear) }
1289    pub fn ps_copy(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_copy) }
1290
1291    pub fn deinit(self, device: &mut Device) {
1292        self.loader.deinit(device);
1293    }
1294}
1295
1296pub type SharedShaders = Rc<RefCell<Shaders>>;
1297
1298pub struct CompositorShaders {
1299    // Composite shaders. These are very simple shaders used to composite
1300    // picture cache tiles into the framebuffer on platforms that do not have an
1301    // OS Compositor (or we cannot use it).  Such an OS Compositor (such as
1302    // DirectComposite or CoreAnimation) handles the composition of the picture
1303    // cache tiles at a lower level (e.g. in DWM for Windows); in that case we
1304    // directly hand the picture cache surfaces over to the OS Compositor, and
1305    // our own Composite shaders below never run.
1306    // To composite external (RGB) surfaces we need various permutations of
1307    // shaders with WR_FEATURE flags on or off based on the type of image
1308    // buffer we're sourcing from (see IMAGE_BUFFER_KINDS).
1309    rgba: Vec<Option<ShaderHandle>>,
1310    // A faster set of rgba composite shaders that do not support UV clamping
1311    // or color modulation.
1312    rgba_fast_path: Vec<Option<ShaderHandle>>,
1313    // The same set of composite shaders but with WR_FEATURE_YUV added.
1314    yuv_clip: Vec<Option<ShaderHandle>>,
1315    yuv_fast: Vec<Option<ShaderHandle>>,
1316}
1317
1318impl CompositorShaders {
1319    pub fn new(
1320        device: &mut Device,
1321        gl_type: GlType,
1322        loader: &mut ShaderLoader,
1323    )  -> Result<Self, ShaderError>  {
1324        let mut yuv_clip_features = Vec::new();
1325        let mut yuv_fast_features = Vec::new();
1326        let mut rgba_features = Vec::new();
1327        let mut fast_path_features = Vec::new();
1328        let mut rgba = Vec::new();
1329        let mut rgba_fast_path = Vec::new();
1330        let mut yuv_clip = Vec::new();
1331        let mut yuv_fast = Vec::new();
1332
1333        let texture_external_version = if device.get_capabilities().supports_image_external_essl3 {
1334            TextureExternalVersion::ESSL3
1335        } else {
1336            TextureExternalVersion::ESSL1
1337        };
1338
1339        let feature_flags = get_shader_feature_flags(gl_type, texture_external_version, device);
1340        let shader_list = get_shader_features(feature_flags);
1341
1342        for _ in 0..IMAGE_BUFFER_KINDS.len() {
1343            yuv_clip.push(None);
1344            yuv_fast.push(None);
1345            rgba.push(None);
1346            rgba_fast_path.push(None);
1347        }
1348
1349        for image_buffer_kind in &IMAGE_BUFFER_KINDS {
1350            if !has_platform_support(*image_buffer_kind, device) {
1351                continue;
1352            }
1353
1354            yuv_clip_features.push("YUV");
1355            yuv_fast_features.push("YUV");
1356            yuv_fast_features.push("FAST_PATH");
1357            fast_path_features.push("FAST_PATH");
1358    
1359            let index = Self::get_shader_index(*image_buffer_kind);
1360
1361            let feature_string = get_feature_string(
1362                *image_buffer_kind,
1363                texture_external_version,
1364            );
1365            if feature_string != "" {
1366                yuv_clip_features.push(feature_string);
1367                yuv_fast_features.push(feature_string);
1368                rgba_features.push(feature_string);
1369                fast_path_features.push(feature_string);
1370            }
1371
1372            // YUV shaders are not compatible with ESSL1
1373            if *image_buffer_kind != ImageBufferKind::TextureExternal ||
1374                texture_external_version == TextureExternalVersion::ESSL3 {
1375
1376                yuv_clip[index] = Some(loader.create_shader(
1377                    ShaderKind::Composite,
1378                    "composite",
1379                    &yuv_clip_features,
1380                    &shader_list,
1381                )?);
1382
1383                yuv_fast[index] = Some(loader.create_shader(
1384                    ShaderKind::Composite,
1385                    "composite",
1386                    &yuv_fast_features,
1387                    &shader_list,
1388                )?);
1389            }
1390
1391            rgba[index] = Some(loader.create_shader(
1392                ShaderKind::Composite,
1393                "composite",
1394                &rgba_features,
1395                &shader_list,
1396            )?);
1397
1398            rgba_fast_path[index] = Some(loader.create_shader(
1399                ShaderKind::Composite,
1400                "composite",
1401                &fast_path_features,
1402                &shader_list,
1403            )?);
1404
1405            yuv_fast_features.clear();
1406            yuv_clip_features.clear();
1407            rgba_features.clear();
1408            fast_path_features.clear();
1409        }
1410
1411        Ok(CompositorShaders {
1412            rgba,
1413            rgba_fast_path,
1414            yuv_clip,
1415            yuv_fast,
1416        })
1417    }
1418
1419    pub fn get_handle(
1420        &mut self,
1421        format: CompositeSurfaceFormat,
1422        buffer_kind: ImageBufferKind,
1423        features: CompositeFeatures,
1424    ) -> ShaderHandle {
1425        match format {
1426            CompositeSurfaceFormat::Rgba => {
1427                if features.contains(CompositeFeatures::NO_UV_CLAMP)
1428                    && features.contains(CompositeFeatures::NO_COLOR_MODULATION)
1429                    && features.contains(CompositeFeatures::NO_CLIP_MASK)
1430                {
1431                    let shader_index = Self::get_shader_index(buffer_kind);
1432                    self.rgba_fast_path[shader_index]
1433                        .expect("bug: unsupported rgba fast path shader requested")
1434                } else {
1435                    let shader_index = Self::get_shader_index(buffer_kind);
1436                    self.rgba[shader_index]
1437                        .expect("bug: unsupported rgba shader requested")
1438                }
1439            }
1440            CompositeSurfaceFormat::Yuv => {
1441                let shader_index = Self::get_shader_index(buffer_kind);
1442                if features.contains(CompositeFeatures::NO_CLIP_MASK) {
1443                    self.yuv_fast[shader_index]
1444                        .expect("bug: unsupported yuv shader requested")
1445                } else {
1446                    self.yuv_clip[shader_index]
1447                        .expect("bug: unsupported yuv shader requested")
1448                }
1449            }
1450        }
1451    }
1452
1453    fn get_shader_index(buffer_kind: ImageBufferKind) -> usize {
1454        buffer_kind as usize
1455    }
1456}
1457
1458fn get_shader_feature_flags(
1459    gl_type: GlType,
1460    texture_external_version: TextureExternalVersion,
1461    device: &Device
1462) -> ShaderFeatureFlags {
1463    match gl_type {
1464        GlType::Gl => ShaderFeatureFlags::GL,
1465        GlType::Gles => {
1466            let mut flags = ShaderFeatureFlags::GLES;
1467            flags |= match texture_external_version {
1468                TextureExternalVersion::ESSL3 => ShaderFeatureFlags::TEXTURE_EXTERNAL,
1469                TextureExternalVersion::ESSL1 => ShaderFeatureFlags::TEXTURE_EXTERNAL_ESSL1,
1470            };
1471            if device.supports_extension("GL_EXT_YUV_target") {
1472                flags |= ShaderFeatureFlags::TEXTURE_EXTERNAL_BT709;
1473            }
1474            flags
1475        }
1476    }
1477}