webrender/
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 crate::batch::{BatchKey, BatchKind, BrushBatchKind, BatchFeatures};
6use crate::device::{Device, Program, ShaderError};
7use euclid::default::Transform3D;
8use crate::glyph_rasterizer::GlyphFormat;
9use crate::renderer::{
10    desc,
11    MAX_VERTEX_TEXTURE_WIDTH,
12    BlendMode, DebugFlags, ImageBufferKind, RendererError, RendererOptions,
13    TextureSampler, VertexArrayKind, ShaderPrecacheFlags,
14};
15
16use gleam::gl::GlType;
17use time::precise_time_ns;
18
19use std::cell::RefCell;
20use std::rc::Rc;
21
22impl ImageBufferKind {
23    pub(crate) fn get_feature_string(&self) -> &'static str {
24        match *self {
25            ImageBufferKind::Texture2D => "TEXTURE_2D",
26            ImageBufferKind::Texture2DArray => "",
27            ImageBufferKind::TextureRect => "TEXTURE_RECT",
28            ImageBufferKind::TextureExternal => "TEXTURE_EXTERNAL",
29        }
30    }
31
32    fn has_platform_support(&self, gl_type: &GlType) -> bool {
33        match (*self, gl_type) {
34            (ImageBufferKind::Texture2D, _) => true,
35            (ImageBufferKind::Texture2DArray, _) => true,
36            (ImageBufferKind::TextureRect, _) => true,
37            (ImageBufferKind::TextureExternal, &GlType::Gles) => true,
38            (ImageBufferKind::TextureExternal, &GlType::Gl) => false,
39        }
40    }
41}
42
43pub const IMAGE_BUFFER_KINDS: [ImageBufferKind; 4] = [
44    ImageBufferKind::Texture2D,
45    ImageBufferKind::TextureRect,
46    ImageBufferKind::TextureExternal,
47    ImageBufferKind::Texture2DArray,
48];
49
50const ADVANCED_BLEND_FEATURE: &str = "ADVANCED_BLEND";
51const ALPHA_FEATURE: &str = "ALPHA_PASS";
52const DEBUG_OVERDRAW_FEATURE: &str = "DEBUG_OVERDRAW";
53const DITHERING_FEATURE: &str = "DITHERING";
54const DUAL_SOURCE_FEATURE: &str = "DUAL_SOURCE_BLENDING";
55const FAST_PATH_FEATURE: &str = "FAST_PATH";
56const PIXEL_LOCAL_STORAGE_FEATURE: &str = "PIXEL_LOCAL_STORAGE";
57
58pub(crate) enum ShaderKind {
59    Primitive,
60    Cache(VertexArrayKind),
61    ClipCache,
62    Brush,
63    Text,
64    #[allow(dead_code)]
65    VectorStencil,
66    #[allow(dead_code)]
67    VectorCover,
68    Resolve,
69    Composite,
70}
71
72pub struct LazilyCompiledShader {
73    program: Option<Program>,
74    name: &'static str,
75    kind: ShaderKind,
76    cached_projection: Transform3D<f32>,
77    features: Vec<&'static str>,
78}
79
80impl LazilyCompiledShader {
81    pub(crate) fn new(
82        kind: ShaderKind,
83        name: &'static str,
84        features: &[&'static str],
85        device: &mut Device,
86        precache_flags: ShaderPrecacheFlags,
87    ) -> Result<Self, ShaderError> {
88        let mut shader = LazilyCompiledShader {
89            program: None,
90            name,
91            kind,
92            //Note: this isn't really the default state, but there is no chance
93            // an actual projection passed here would accidentally match.
94            cached_projection: Transform3D::identity(),
95            features: features.to_vec(),
96        };
97
98        if precache_flags.intersects(ShaderPrecacheFlags::ASYNC_COMPILE | ShaderPrecacheFlags::FULL_COMPILE) {
99            let t0 = precise_time_ns();
100            shader.get_internal(device, precache_flags)?;
101            let t1 = precise_time_ns();
102            debug!("[C: {:.1} ms ] Precache {} {:?}",
103                (t1 - t0) as f64 / 1000000.0,
104                name,
105                features
106            );
107        }
108
109        Ok(shader)
110    }
111
112    pub fn bind(
113        &mut self,
114        device: &mut Device,
115        projection: &Transform3D<f32>,
116        renderer_errors: &mut Vec<RendererError>,
117    ) {
118        let update_projection = self.cached_projection != *projection;
119        let program = match self.get_internal(device, ShaderPrecacheFlags::FULL_COMPILE) {
120            Ok(program) => program,
121            Err(e) => {
122                renderer_errors.push(RendererError::from(e));
123                return;
124            }
125        };
126        device.bind_program(program);
127        if update_projection {
128            device.set_uniforms(program, projection);
129            // thanks NLL for this (`program` technically borrows `self`)
130            self.cached_projection = *projection;
131        }
132    }
133
134    fn get_internal(
135        &mut self,
136        device: &mut Device,
137        precache_flags: ShaderPrecacheFlags,
138    ) -> Result<&mut Program, ShaderError> {
139        if self.program.is_none() {
140            let program = match self.kind {
141                ShaderKind::Primitive | ShaderKind::Brush | ShaderKind::Text | ShaderKind::Resolve => {
142                    create_prim_shader(
143                        self.name,
144                        device,
145                        &self.features,
146                    )
147                }
148                ShaderKind::Cache(..) => {
149                    create_prim_shader(
150                        self.name,
151                        device,
152                        &self.features,
153                    )
154                }
155                ShaderKind::VectorStencil => {
156                    create_prim_shader(
157                        self.name,
158                        device,
159                        &self.features,
160                    )
161                }
162                ShaderKind::VectorCover => {
163                    create_prim_shader(
164                        self.name,
165                        device,
166                        &self.features,
167                    )
168                }
169                ShaderKind::Composite => {
170                    create_prim_shader(
171                        self.name,
172                        device,
173                        &self.features,
174                    )
175                }
176                ShaderKind::ClipCache => {
177                    create_clip_shader(
178                        self.name,
179                        device,
180                        &self.features,
181                    )
182                }
183            };
184            self.program = Some(program?);
185        }
186
187        let program = self.program.as_mut().unwrap();
188
189        if precache_flags.contains(ShaderPrecacheFlags::FULL_COMPILE) && !program.is_initialized() {
190            let vertex_format = match self.kind {
191                ShaderKind::Primitive |
192                ShaderKind::Brush |
193                ShaderKind::Text => VertexArrayKind::Primitive,
194                ShaderKind::Cache(format) => format,
195                ShaderKind::VectorStencil => VertexArrayKind::VectorStencil,
196                ShaderKind::VectorCover => VertexArrayKind::VectorCover,
197                ShaderKind::ClipCache => VertexArrayKind::Clip,
198                ShaderKind::Resolve => VertexArrayKind::Resolve,
199                ShaderKind::Composite => VertexArrayKind::Composite,
200            };
201
202            let vertex_descriptor = match vertex_format {
203                VertexArrayKind::Primitive => &desc::PRIM_INSTANCES,
204                VertexArrayKind::LineDecoration => &desc::LINE,
205                VertexArrayKind::Gradient => &desc::GRADIENT,
206                VertexArrayKind::Blur => &desc::BLUR,
207                VertexArrayKind::Clip => &desc::CLIP,
208                VertexArrayKind::VectorStencil => &desc::VECTOR_STENCIL,
209                VertexArrayKind::VectorCover => &desc::VECTOR_COVER,
210                VertexArrayKind::Border => &desc::BORDER,
211                VertexArrayKind::Scale => &desc::SCALE,
212                VertexArrayKind::Resolve => &desc::RESOLVE,
213                VertexArrayKind::SvgFilter => &desc::SVG_FILTER,
214                VertexArrayKind::Composite => &desc::COMPOSITE,
215            };
216
217            device.link_program(program, vertex_descriptor)?;
218            device.bind_program(program);
219            match self.kind {
220                ShaderKind::ClipCache => {
221                    device.bind_shader_samplers(
222                        &program,
223                        &[
224                            ("sColor0", TextureSampler::Color0),
225                            ("sTransformPalette", TextureSampler::TransformPalette),
226                            ("sRenderTasks", TextureSampler::RenderTasks),
227                            ("sGpuCache", TextureSampler::GpuCache),
228                            ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF),
229                            ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI),
230                        ],
231                    );
232                }
233                _ => {
234                    device.bind_shader_samplers(
235                        &program,
236                        &[
237                            ("sColor0", TextureSampler::Color0),
238                            ("sColor1", TextureSampler::Color1),
239                            ("sColor2", TextureSampler::Color2),
240                            ("sDither", TextureSampler::Dither),
241                            ("sPrevPassAlpha", TextureSampler::PrevPassAlpha),
242                            ("sPrevPassColor", TextureSampler::PrevPassColor),
243                            ("sTransformPalette", TextureSampler::TransformPalette),
244                            ("sRenderTasks", TextureSampler::RenderTasks),
245                            ("sGpuCache", TextureSampler::GpuCache),
246                            ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF),
247                            ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI),
248                        ],
249                    );
250                }
251            }
252        }
253
254        Ok(program)
255    }
256
257    fn deinit(self, device: &mut Device) {
258        if let Some(program) = self.program {
259            device.delete_program(program);
260        }
261    }
262}
263
264// A brush shader supports two modes:
265// opaque:
266//   Used for completely opaque primitives,
267//   or inside segments of partially
268//   opaque primitives. Assumes no need
269//   for clip masks, AA etc.
270// alpha:
271//   Used for brush primitives in the alpha
272//   pass. Assumes that AA should be applied
273//   along the primitive edge, and also that
274//   clip mask is present.
275struct BrushShader {
276    opaque: LazilyCompiledShader,
277    alpha: LazilyCompiledShader,
278    advanced_blend: Option<LazilyCompiledShader>,
279    dual_source: Option<LazilyCompiledShader>,
280    debug_overdraw: LazilyCompiledShader,
281}
282
283impl BrushShader {
284    fn new(
285        name: &'static str,
286        device: &mut Device,
287        features: &[&'static str],
288        precache_flags: ShaderPrecacheFlags,
289        advanced_blend: bool,
290        dual_source: bool,
291        use_pixel_local_storage: bool,
292    ) -> Result<Self, ShaderError> {
293        let opaque = LazilyCompiledShader::new(
294            ShaderKind::Brush,
295            name,
296            features,
297            device,
298            precache_flags,
299        )?;
300
301        let mut alpha_features = features.to_vec();
302        alpha_features.push(ALPHA_FEATURE);
303        if use_pixel_local_storage {
304            alpha_features.push(PIXEL_LOCAL_STORAGE_FEATURE);
305        }
306
307        let alpha = LazilyCompiledShader::new(
308            ShaderKind::Brush,
309            name,
310            &alpha_features,
311            device,
312            precache_flags,
313        )?;
314
315        let advanced_blend = if advanced_blend &&
316            device.get_capabilities().supports_advanced_blend_equation
317        {
318            let mut advanced_blend_features = alpha_features.to_vec();
319            advanced_blend_features.push(ADVANCED_BLEND_FEATURE);
320
321            let shader = LazilyCompiledShader::new(
322                ShaderKind::Brush,
323                name,
324                &advanced_blend_features,
325                device,
326                precache_flags,
327            )?;
328
329            Some(shader)
330        } else {
331            None
332        };
333
334        // If using PLS, we disable all subpixel AA implicitly. Subpixel AA is always
335        // disabled on mobile devices anyway, due to uncertainty over the subpixel
336        // layout configuration.
337        let dual_source = if dual_source && !use_pixel_local_storage {
338            let mut dual_source_features = alpha_features.to_vec();
339            dual_source_features.push(DUAL_SOURCE_FEATURE);
340
341            let shader = LazilyCompiledShader::new(
342                ShaderKind::Brush,
343                name,
344                &dual_source_features,
345                device,
346                precache_flags,
347            )?;
348
349            Some(shader)
350        } else {
351            None
352        };
353
354        let mut debug_overdraw_features = features.to_vec();
355        debug_overdraw_features.push(DEBUG_OVERDRAW_FEATURE);
356
357        let debug_overdraw = LazilyCompiledShader::new(
358            ShaderKind::Brush,
359            name,
360            &debug_overdraw_features,
361            device,
362            precache_flags,
363        )?;
364
365        Ok(BrushShader {
366            opaque,
367            alpha,
368            advanced_blend,
369            dual_source,
370            debug_overdraw,
371        })
372    }
373
374    fn get(&mut self, blend_mode: BlendMode, debug_flags: DebugFlags)
375           -> &mut LazilyCompiledShader {
376        match blend_mode {
377            _ if debug_flags.contains(DebugFlags::SHOW_OVERDRAW) => &mut self.debug_overdraw,
378            BlendMode::None => &mut self.opaque,
379            BlendMode::Alpha |
380            BlendMode::PremultipliedAlpha |
381            BlendMode::PremultipliedDestOut |
382            BlendMode::SubpixelConstantTextColor(..) |
383            BlendMode::SubpixelWithBgColor => &mut self.alpha,
384            BlendMode::Advanced(_) => {
385                self.advanced_blend
386                    .as_mut()
387                    .expect("bug: no advanced blend shader loaded")
388            }
389            BlendMode::SubpixelDualSource => {
390                self.dual_source
391                    .as_mut()
392                    .expect("bug: no dual source shader loaded")
393            }
394        }
395    }
396
397    fn deinit(self, device: &mut Device) {
398        self.opaque.deinit(device);
399        self.alpha.deinit(device);
400        if let Some(advanced_blend) = self.advanced_blend {
401            advanced_blend.deinit(device);
402        }
403        if let Some(dual_source) = self.dual_source {
404            dual_source.deinit(device);
405        }
406        self.debug_overdraw.deinit(device);
407    }
408}
409
410pub struct TextShader {
411    simple: LazilyCompiledShader,
412    glyph_transform: LazilyCompiledShader,
413    debug_overdraw: LazilyCompiledShader,
414}
415
416impl TextShader {
417    fn new(
418        name: &'static str,
419        device: &mut Device,
420        features: &[&'static str],
421        precache_flags: ShaderPrecacheFlags,
422    ) -> Result<Self, ShaderError> {
423        let simple = LazilyCompiledShader::new(
424            ShaderKind::Text,
425            name,
426            features,
427            device,
428            precache_flags,
429        )?;
430
431        let mut glyph_transform_features = features.to_vec();
432        glyph_transform_features.push("GLYPH_TRANSFORM");
433
434        let glyph_transform = LazilyCompiledShader::new(
435            ShaderKind::Text,
436            name,
437            &glyph_transform_features,
438            device,
439            precache_flags,
440        )?;
441
442        let mut debug_overdraw_features = features.to_vec();
443        debug_overdraw_features.push("DEBUG_OVERDRAW");
444
445        let debug_overdraw = LazilyCompiledShader::new(
446            ShaderKind::Text,
447            name,
448            &debug_overdraw_features,
449            device,
450            precache_flags,
451        )?;
452
453        Ok(TextShader { simple, glyph_transform, debug_overdraw })
454    }
455
456    pub fn get(
457        &mut self,
458        glyph_format: GlyphFormat,
459        debug_flags: DebugFlags,
460    ) -> &mut LazilyCompiledShader {
461        match glyph_format {
462            _ if debug_flags.contains(DebugFlags::SHOW_OVERDRAW) => &mut self.debug_overdraw,
463            GlyphFormat::Alpha |
464            GlyphFormat::Subpixel |
465            GlyphFormat::Bitmap |
466            GlyphFormat::ColorBitmap => &mut self.simple,
467            GlyphFormat::TransformedAlpha |
468            GlyphFormat::TransformedSubpixel => &mut self.glyph_transform,
469        }
470    }
471
472    fn deinit(self, device: &mut Device) {
473        self.simple.deinit(device);
474        self.glyph_transform.deinit(device);
475        self.debug_overdraw.deinit(device);
476    }
477}
478
479fn create_prim_shader(
480    name: &'static str,
481    device: &mut Device,
482    features: &[&'static str],
483) -> Result<Program, ShaderError> {
484    let mut prefix = format!(
485        "#define WR_MAX_VERTEX_TEXTURE_WIDTH {}U\n",
486        MAX_VERTEX_TEXTURE_WIDTH
487    );
488
489    for feature in features {
490        prefix.push_str(&format!("#define WR_FEATURE_{}\n", feature));
491    }
492
493    debug!("PrimShader {}", name);
494
495    device.create_program(name, prefix)
496}
497
498fn create_clip_shader(
499    name: &'static str,
500    device: &mut Device,
501    features: &[&'static str],
502) -> Result<Program, ShaderError> {
503    let mut prefix = format!(
504        "#define WR_MAX_VERTEX_TEXTURE_WIDTH {}U\n",
505        MAX_VERTEX_TEXTURE_WIDTH
506    );
507
508    for feature in features {
509        prefix.push_str(&format!("#define WR_FEATURE_{}\n", feature));
510    }
511
512    debug!("ClipShader {}", name);
513
514    device.create_program(name, prefix)
515}
516
517// NB: If you add a new shader here, make sure to deinitialize it
518// in `Shaders::deinit()` below.
519pub struct Shaders {
520    // These are "cache shaders". These shaders are used to
521    // draw intermediate results to cache targets. The results
522    // of these shaders are then used by the primitive shaders.
523    pub cs_blur_a8: LazilyCompiledShader,
524    pub cs_blur_rgba8: LazilyCompiledShader,
525    pub cs_border_segment: LazilyCompiledShader,
526    pub cs_border_solid: LazilyCompiledShader,
527    pub cs_scale: LazilyCompiledShader,
528    pub cs_line_decoration: LazilyCompiledShader,
529    pub cs_gradient: LazilyCompiledShader,
530    pub cs_svg_filter: LazilyCompiledShader,
531
532    // Brush shaders
533    brush_solid: BrushShader,
534    brush_image: Vec<Option<BrushShader>>,
535    brush_fast_image: Vec<Option<BrushShader>>,
536    brush_blend: BrushShader,
537    brush_mix_blend: BrushShader,
538    brush_yuv_image: Vec<Option<BrushShader>>,
539    brush_radial_gradient: BrushShader,
540    brush_linear_gradient: BrushShader,
541    brush_opacity: BrushShader,
542
543    /// These are "cache clip shaders". These shaders are used to
544    /// draw clip instances into the cached clip mask. The results
545    /// of these shaders are also used by the primitive shaders.
546    pub cs_clip_rectangle_slow: LazilyCompiledShader,
547    pub cs_clip_rectangle_fast: LazilyCompiledShader,
548    pub cs_clip_box_shadow: LazilyCompiledShader,
549    pub cs_clip_image: LazilyCompiledShader,
550
551    // The are "primitive shaders". These shaders draw and blend
552    // final results on screen. They are aware of tile boundaries.
553    // Most draw directly to the framebuffer, but some use inputs
554    // from the cache shaders to draw. Specifically, the box
555    // shadow primitive shader stretches the box shadow cache
556    // output, and the cache_image shader blits the results of
557    // a cache shader (e.g. blur) to the screen.
558    pub ps_text_run: TextShader,
559    pub ps_text_run_dual_source: TextShader,
560
561    // Helper shaders for pixel local storage render paths.
562    // pls_init: Initialize pixel local storage, based on current framebuffer value.
563    // pls_resolve: Convert pixel local storage, writing out to fragment value.
564    pub pls_init: LazilyCompiledShader,
565    pub pls_resolve: LazilyCompiledShader,
566
567    ps_split_composite: LazilyCompiledShader,
568
569    // Composite shader. This is a very simple shader used to composite
570    // picture cache tiles into the framebuffer. In future, this will
571    // only be used on platforms that aren't directly handing picture
572    // cache surfaces to an OS compositor, such as DirectComposite or
573    // CoreAnimation.
574    pub composite: LazilyCompiledShader,
575}
576
577impl Shaders {
578    pub fn new(
579        device: &mut Device,
580        gl_type: GlType,
581        options: &RendererOptions,
582    ) -> Result<Self, ShaderError> {
583        let use_pixel_local_storage = device
584            .get_capabilities()
585            .supports_pixel_local_storage;
586
587        let brush_solid = BrushShader::new(
588            "brush_solid",
589            device,
590            &[],
591            options.precache_flags,
592            false /* advanced blend */,
593            false /* dual source */,
594            use_pixel_local_storage,
595        )?;
596
597        let brush_blend = BrushShader::new(
598            "brush_blend",
599            device,
600            &[],
601            options.precache_flags,
602            false /* advanced blend */,
603            false /* dual source */,
604            use_pixel_local_storage,
605        )?;
606
607        let brush_mix_blend = BrushShader::new(
608            "brush_mix_blend",
609            device,
610            &[],
611            options.precache_flags,
612            false /* advanced blend */,
613            false /* dual source */,
614            use_pixel_local_storage,
615        )?;
616
617        let brush_radial_gradient = BrushShader::new(
618            "brush_radial_gradient",
619            device,
620            if options.enable_dithering {
621               &[DITHERING_FEATURE]
622            } else {
623               &[]
624            },
625            options.precache_flags,
626            false /* advanced blend */,
627            false /* dual source */,
628            use_pixel_local_storage,
629        )?;
630
631        let brush_linear_gradient = BrushShader::new(
632            "brush_linear_gradient",
633            device,
634            if options.enable_dithering {
635               &[DITHERING_FEATURE]
636            } else {
637               &[]
638            },
639            options.precache_flags,
640            false /* advanced blend */,
641            false /* dual source */,
642            use_pixel_local_storage,
643        )?;
644
645        let brush_opacity = BrushShader::new(
646            "brush_opacity",
647            device,
648            &[],
649            options.precache_flags,
650            false /* advanced blend */,
651            false /* dual source */,
652            use_pixel_local_storage,
653        )?;
654
655        let cs_blur_a8 = LazilyCompiledShader::new(
656            ShaderKind::Cache(VertexArrayKind::Blur),
657            "cs_blur",
658            &["ALPHA_TARGET"],
659            device,
660            options.precache_flags,
661        )?;
662
663        let cs_blur_rgba8 = LazilyCompiledShader::new(
664            ShaderKind::Cache(VertexArrayKind::Blur),
665            "cs_blur",
666            &["COLOR_TARGET"],
667            device,
668            options.precache_flags,
669        )?;
670
671        let cs_svg_filter = LazilyCompiledShader::new(
672            ShaderKind::Cache(VertexArrayKind::SvgFilter),
673            "cs_svg_filter",
674            &[],
675            device,
676            options.precache_flags,
677        )?;
678
679        let cs_clip_rectangle_slow = LazilyCompiledShader::new(
680            ShaderKind::ClipCache,
681            "cs_clip_rectangle",
682            &[],
683            device,
684            options.precache_flags,
685        )?;
686
687        let cs_clip_rectangle_fast = LazilyCompiledShader::new(
688            ShaderKind::ClipCache,
689            "cs_clip_rectangle",
690            &[FAST_PATH_FEATURE],
691            device,
692            options.precache_flags,
693        )?;
694
695        let cs_clip_box_shadow = LazilyCompiledShader::new(
696            ShaderKind::ClipCache,
697            "cs_clip_box_shadow",
698            &[],
699            device,
700            options.precache_flags,
701        )?;
702
703        let cs_clip_image = LazilyCompiledShader::new(
704            ShaderKind::ClipCache,
705            "cs_clip_image",
706            &[],
707            device,
708            options.precache_flags,
709        )?;
710
711        let pls_precache_flags = if use_pixel_local_storage {
712            options.precache_flags
713        } else {
714            ShaderPrecacheFlags::empty()
715        };
716
717        let pls_init = LazilyCompiledShader::new(
718            ShaderKind::Resolve,
719            "pls_init",
720            &[PIXEL_LOCAL_STORAGE_FEATURE],
721            device,
722            pls_precache_flags,
723        )?;
724
725        let pls_resolve = LazilyCompiledShader::new(
726            ShaderKind::Resolve,
727            "pls_resolve",
728            &[PIXEL_LOCAL_STORAGE_FEATURE],
729            device,
730            pls_precache_flags,
731        )?;
732
733        let cs_scale = LazilyCompiledShader::new(
734            ShaderKind::Cache(VertexArrayKind::Scale),
735            "cs_scale",
736            &[],
737            device,
738            options.precache_flags,
739        )?;
740
741        // TODO(gw): The split composite + text shader are special cases - the only
742        //           shaders used during normal scene rendering that aren't a brush
743        //           shader. Perhaps we can unify these in future?
744        let mut extra_features = Vec::new();
745        if use_pixel_local_storage {
746            extra_features.push(PIXEL_LOCAL_STORAGE_FEATURE);
747        }
748
749        let ps_text_run = TextShader::new("ps_text_run",
750            device,
751            &extra_features,
752            options.precache_flags,
753        )?;
754
755        let dual_source_precache_flags = if options.allow_dual_source_blending {
756            options.precache_flags
757        } else {
758            ShaderPrecacheFlags::empty()
759        };
760
761        let ps_text_run_dual_source = TextShader::new("ps_text_run",
762            device,
763            &[DUAL_SOURCE_FEATURE],
764            dual_source_precache_flags,
765        )?;
766
767        let ps_split_composite = LazilyCompiledShader::new(
768            ShaderKind::Primitive,
769            "ps_split_composite",
770            &extra_features,
771            device,
772            options.precache_flags,
773        )?;
774
775        // All image configuration.
776        let mut image_features = Vec::new();
777        let mut brush_image = Vec::new();
778        let mut brush_fast_image = Vec::new();
779        // PrimitiveShader is not clonable. Use push() to initialize the vec.
780        for _ in 0 .. IMAGE_BUFFER_KINDS.len() {
781            brush_image.push(None);
782            brush_fast_image.push(None);
783        }
784        for buffer_kind in 0 .. IMAGE_BUFFER_KINDS.len() {
785            if !IMAGE_BUFFER_KINDS[buffer_kind].has_platform_support(&gl_type) {
786                continue;
787            }
788
789            let feature_string = IMAGE_BUFFER_KINDS[buffer_kind].get_feature_string();
790            if feature_string != "" {
791                image_features.push(feature_string);
792            }
793
794            brush_fast_image[buffer_kind] = Some(BrushShader::new(
795                "brush_image",
796                device,
797                &image_features,
798                options.precache_flags,
799                options.allow_advanced_blend_equation,
800                options.allow_dual_source_blending,
801                use_pixel_local_storage,
802            )?);
803
804            image_features.push("REPETITION");
805            image_features.push("ANTIALIASING");
806
807            brush_image[buffer_kind] = Some(BrushShader::new(
808                "brush_image",
809                device,
810                &image_features,
811                options.precache_flags,
812                options.allow_advanced_blend_equation,
813                options.allow_dual_source_blending,
814                use_pixel_local_storage,
815            )?);
816
817            image_features.clear();
818        }
819
820        // All yuv_image configuration.
821        let mut yuv_features = Vec::new();
822        let yuv_shader_num = IMAGE_BUFFER_KINDS.len();
823        let mut brush_yuv_image = Vec::new();
824        // PrimitiveShader is not clonable. Use push() to initialize the vec.
825        for _ in 0 .. yuv_shader_num {
826            brush_yuv_image.push(None);
827        }
828        for image_buffer_kind in &IMAGE_BUFFER_KINDS {
829            if image_buffer_kind.has_platform_support(&gl_type) {
830                let feature_string = image_buffer_kind.get_feature_string();
831                if feature_string != "" {
832                    yuv_features.push(feature_string);
833                }
834
835                let shader = BrushShader::new(
836                    "brush_yuv_image",
837                    device,
838                    &yuv_features,
839                    options.precache_flags,
840                    false /* advanced blend */,
841                    false /* dual source */,
842                    use_pixel_local_storage,
843                )?;
844                let index = Self::get_yuv_shader_index(
845                    *image_buffer_kind,
846                );
847                brush_yuv_image[index] = Some(shader);
848                yuv_features.clear();
849            }
850        }
851
852        let cs_line_decoration = LazilyCompiledShader::new(
853            ShaderKind::Cache(VertexArrayKind::LineDecoration),
854            "cs_line_decoration",
855            &[],
856            device,
857            options.precache_flags,
858        )?;
859
860        let cs_gradient = LazilyCompiledShader::new(
861            ShaderKind::Cache(VertexArrayKind::Gradient),
862            "cs_gradient",
863            &[],
864            device,
865            options.precache_flags,
866        )?;
867
868        let cs_border_segment = LazilyCompiledShader::new(
869            ShaderKind::Cache(VertexArrayKind::Border),
870            "cs_border_segment",
871             &[],
872             device,
873             options.precache_flags,
874        )?;
875
876        let cs_border_solid = LazilyCompiledShader::new(
877            ShaderKind::Cache(VertexArrayKind::Border),
878            "cs_border_solid",
879            &[],
880            device,
881            options.precache_flags,
882        )?;
883
884        let composite = LazilyCompiledShader::new(
885            ShaderKind::Composite,
886            "composite",
887            &[],
888            device,
889            options.precache_flags,
890        )?;
891
892        Ok(Shaders {
893            cs_blur_a8,
894            cs_blur_rgba8,
895            cs_border_segment,
896            cs_line_decoration,
897            cs_gradient,
898            cs_border_solid,
899            cs_scale,
900            cs_svg_filter,
901            brush_solid,
902            brush_image,
903            brush_fast_image,
904            brush_blend,
905            brush_mix_blend,
906            brush_yuv_image,
907            brush_radial_gradient,
908            brush_linear_gradient,
909            brush_opacity,
910            cs_clip_rectangle_slow,
911            cs_clip_rectangle_fast,
912            cs_clip_box_shadow,
913            cs_clip_image,
914            pls_init,
915            pls_resolve,
916            ps_text_run,
917            ps_text_run_dual_source,
918            ps_split_composite,
919            composite,
920        })
921    }
922
923    fn get_yuv_shader_index(buffer_kind: ImageBufferKind) -> usize {
924        (buffer_kind as usize)
925    }
926
927    pub fn get(&mut self, key: &BatchKey, features: BatchFeatures, debug_flags: DebugFlags) -> &mut LazilyCompiledShader {
928        match key.kind {
929            BatchKind::SplitComposite => {
930                &mut self.ps_split_composite
931            }
932            BatchKind::Brush(brush_kind) => {
933                let brush_shader = match brush_kind {
934                    BrushBatchKind::Solid => {
935                        &mut self.brush_solid
936                    }
937                    BrushBatchKind::Image(image_buffer_kind) => {
938                        if features.contains(BatchFeatures::ANTIALIASING) ||
939                            features.contains(BatchFeatures::REPETITION) ||
940                            !features.contains(BatchFeatures::ALPHA_PASS) {
941
942                            self.brush_image[image_buffer_kind as usize]
943                                .as_mut()
944                                .expect("Unsupported image shader kind")
945                        } else {
946                            self.brush_fast_image[image_buffer_kind as usize]
947                                .as_mut()
948                                .expect("Unsupported image shader kind")
949                        }
950                    }
951                    BrushBatchKind::Blend => {
952                        &mut self.brush_blend
953                    }
954                    BrushBatchKind::MixBlend { .. } => {
955                        &mut self.brush_mix_blend
956                    }
957                    BrushBatchKind::RadialGradient => {
958                        &mut self.brush_radial_gradient
959                    }
960                    BrushBatchKind::LinearGradient => {
961                        &mut self.brush_linear_gradient
962                    }
963                    BrushBatchKind::YuvImage(image_buffer_kind, ..) => {
964                        let shader_index =
965                            Self::get_yuv_shader_index(image_buffer_kind);
966                        self.brush_yuv_image[shader_index]
967                            .as_mut()
968                            .expect("Unsupported YUV shader kind")
969                    }
970                    BrushBatchKind::Opacity => {
971                        &mut self.brush_opacity
972                    }
973                };
974                brush_shader.get(key.blend_mode, debug_flags)
975            }
976            BatchKind::TextRun(glyph_format) => {
977                let text_shader = match key.blend_mode {
978                    BlendMode::SubpixelDualSource => &mut self.ps_text_run_dual_source,
979                    _ => &mut self.ps_text_run,
980                };
981                text_shader.get(glyph_format, debug_flags)
982            }
983        }
984    }
985
986    pub fn deinit(self, device: &mut Device) {
987        self.cs_scale.deinit(device);
988        self.cs_blur_a8.deinit(device);
989        self.cs_blur_rgba8.deinit(device);
990        self.cs_svg_filter.deinit(device);
991        self.brush_solid.deinit(device);
992        self.brush_blend.deinit(device);
993        self.brush_mix_blend.deinit(device);
994        self.brush_radial_gradient.deinit(device);
995        self.brush_linear_gradient.deinit(device);
996        self.brush_opacity.deinit(device);
997        self.cs_clip_rectangle_slow.deinit(device);
998        self.cs_clip_rectangle_fast.deinit(device);
999        self.cs_clip_box_shadow.deinit(device);
1000        self.cs_clip_image.deinit(device);
1001        self.pls_init.deinit(device);
1002        self.pls_resolve.deinit(device);
1003        self.ps_text_run.deinit(device);
1004        self.ps_text_run_dual_source.deinit(device);
1005        for shader in self.brush_image {
1006            if let Some(shader) = shader {
1007                shader.deinit(device);
1008            }
1009        }
1010        for shader in self.brush_fast_image {
1011            if let Some(shader) = shader {
1012                shader.deinit(device);
1013            }
1014        }
1015        for shader in self.brush_yuv_image {
1016            if let Some(shader) = shader {
1017                shader.deinit(device);
1018            }
1019        }
1020        self.cs_border_solid.deinit(device);
1021        self.cs_gradient.deinit(device);
1022        self.cs_line_decoration.deinit(device);
1023        self.cs_border_segment.deinit(device);
1024        self.ps_split_composite.deinit(device);
1025        self.composite.deinit(device);
1026    }
1027}
1028
1029// A wrapper around a strong reference to a Shaders
1030// object. We have this so that external (ffi)
1031// consumers can own a reference to a shared Shaders
1032// instance without understanding rust's refcounting.
1033pub struct WrShaders {
1034    pub shaders: Rc<RefCell<Shaders>>,
1035}