1use 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 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 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
264struct 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 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
517pub struct Shaders {
520 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_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 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 pub ps_text_run: TextShader,
559 pub ps_text_run_dual_source: TextShader,
560
561 pub pls_init: LazilyCompiledShader,
565 pub pls_resolve: LazilyCompiledShader,
566
567 ps_split_composite: LazilyCompiledShader,
568
569 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 ,
593 false ,
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 ,
603 false ,
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 ,
613 false ,
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 ,
627 false ,
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 ,
641 false ,
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 ,
651 false ,
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 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 let mut image_features = Vec::new();
777 let mut brush_image = Vec::new();
778 let mut brush_fast_image = Vec::new();
779 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 let mut yuv_features = Vec::new();
822 let yuv_shader_num = IMAGE_BUFFER_KINDS.len();
823 let mut brush_yuv_image = Vec::new();
824 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 ,
841 false ,
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
1029pub struct WrShaders {
1034 pub shaders: Rc<RefCell<Shaders>>,
1035}