Skip to main content

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