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 
5 use api::{ImageBufferKind, units::DeviceSize};
6 use crate::batch::{BatchKey, BatchKind, BrushBatchKind, BatchFeatures};
7 use crate::composite::{CompositeFeatures, CompositeSurfaceFormat};
8 use crate::device::{Device, Program, ShaderError};
9 use euclid::default::Transform3D;
10 use crate::glyph_rasterizer::GlyphFormat;
11 use crate::renderer::{
12     desc,
13     BlendMode, DebugFlags, RendererError, RendererOptions,
14     TextureSampler, VertexArrayKind, ShaderPrecacheFlags,
15 };
16 
17 use gleam::gl::GlType;
18 use time::precise_time_ns;
19 
20 use std::cell::RefCell;
21 use std::rc::Rc;
22 
23 use 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)]
27 enum 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 
get_feature_string(kind: ImageBufferKind, texture_external_version: TextureExternalVersion) -> &'static str35 fn 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 
has_platform_support(kind: ImageBufferKind, gl_type: &GlType) -> bool44 fn 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 
54 pub const IMAGE_BUFFER_KINDS: [ImageBufferKind; 3] = [
55     ImageBufferKind::Texture2D,
56     ImageBufferKind::TextureRect,
57     ImageBufferKind::TextureExternal,
58 ];
59 
60 const ADVANCED_BLEND_FEATURE: &str = "ADVANCED_BLEND";
61 const ALPHA_FEATURE: &str = "ALPHA_PASS";
62 const DEBUG_OVERDRAW_FEATURE: &str = "DEBUG_OVERDRAW";
63 const DITHERING_FEATURE: &str = "DITHERING";
64 const DUAL_SOURCE_FEATURE: &str = "DUAL_SOURCE_BLENDING";
65 const FAST_PATH_FEATURE: &str = "FAST_PATH";
66 
67 pub(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 
83 pub 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 
91 impl LazilyCompiledShader {
new( kind: ShaderKind, name: &'static str, unsorted_features: &[&'static str], device: &mut Device, precache_flags: ShaderPrecacheFlags, shader_list: &ShaderFeatures, ) -> Result<Self, ShaderError>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 
bind( &mut self, device: &mut Device, projection: &Transform3D<f32>, texture_size: Option<DeviceSize>, renderer_errors: &mut Vec<RendererError>, )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 
get_internal( &mut self, device: &mut Device, precache_flags: ShaderPrecacheFlags, ) -> Result<&mut Program, ShaderError>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 
deinit(self, device: &mut Device)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.
310 struct BrushShader {
311     opaque: LazilyCompiledShader,
312     alpha: LazilyCompiledShader,
313     advanced_blend: Option<LazilyCompiledShader>,
314     dual_source: Option<LazilyCompiledShader>,
315     debug_overdraw: LazilyCompiledShader,
316 }
317 
318 impl BrushShader {
new( name: &'static str, device: &mut Device, features: &[&'static str], precache_flags: ShaderPrecacheFlags, shader_list: &ShaderFeatures, use_advanced_blend: bool, use_dual_source: bool, ) -> Result<Self, ShaderError>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 
get(&mut self, blend_mode: BlendMode, features: BatchFeatures, debug_flags: DebugFlags) -> &mut LazilyCompiledShader407     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 
deinit(self, device: &mut Device)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 
452 pub struct TextShader {
453     simple: LazilyCompiledShader,
454     glyph_transform: LazilyCompiledShader,
455     debug_overdraw: LazilyCompiledShader,
456 }
457 
458 impl TextShader {
new( name: &'static str, device: &mut Device, features: &[&'static str], precache_flags: ShaderPrecacheFlags, shader_list: &ShaderFeatures, ) -> Result<Self, ShaderError>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 
get( &mut self, glyph_format: GlyphFormat, debug_flags: DebugFlags, ) -> &mut LazilyCompiledShader509     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 
deinit(self, device: &mut Device)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 
create_prim_shader( name: &'static str, device: &mut Device, features: &[&'static str], ) -> Result<Program, ShaderError>532 fn 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 
create_clip_shader( name: &'static str, device: &mut Device, features: &[&'static str], ) -> Result<Program, ShaderError>542 fn 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.
554 pub 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 
620 impl Shaders {
new( device: &mut Device, gl_type: GlType, options: &RendererOptions, ) -> Result<Self, ShaderError>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 
get_compositing_shader_index(buffer_kind: ImageBufferKind) -> usize1095     fn get_compositing_shader_index(buffer_kind: ImageBufferKind) -> usize {
1096         buffer_kind as usize
1097     }
1098 
get_composite_shader( &mut self, format: CompositeSurfaceFormat, buffer_kind: ImageBufferKind, features: CompositeFeatures, ) -> &mut LazilyCompiledShader1099     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 
get_scale_shader( &mut self, buffer_kind: ImageBufferKind, ) -> &mut LazilyCompiledShader1130     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 
get(& mut self, key: &BatchKey, mut features: BatchFeatures, debug_flags: DebugFlags, device: &Device, ) -> &mut LazilyCompiledShader1140     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 
deinit(self, device: &mut Device)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 
1295 pub type SharedShaders = Rc<RefCell<Shaders>>;
1296