1use 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#[derive(Clone, Copy, Debug, PartialEq)]
27enum TextureExternalVersion {
28 ESSL3,
31 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 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 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 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
299struct 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
552pub struct Shaders {
555 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_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 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 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 pub composite_rgba: Vec<Option<LazilyCompiledShader>>,
613 pub composite_rgba_fast_path: Vec<Option<LazilyCompiledShader>>,
616 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 ,
660 false ,
661 )?;
662
663 let brush_blend = BrushShader::new(
664 "brush_blend",
665 device,
666 &[],
667 options.precache_flags,
668 &shader_list,
669 false ,
670 false ,
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 ,
680 false ,
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 ,
694 false ,
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 ,
704 false ,
705 )?;
706
707 let brush_opacity = BrushShader::new(
708 "brush_opacity",
709 device,
710 &[],
711 options.precache_flags,
712 &shader_list,
713 false ,
714 false ,
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 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 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 let mut image_features = Vec::new();
857 let mut brush_image = Vec::new();
858 let mut brush_fast_image = Vec::new();
859 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 || (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 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 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 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 ,
952 false ,
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 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 if device.get_capabilities().uses_native_clip_mask {
1186 features.remove(BatchFeatures::CLIP_MASK);
1187 }
1188 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>>;