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