1use api::{ImageBufferKind, units::DeviceSize};
6use crate::batch::{BatchKey, BatchKind, BrushBatchKind, BatchFeatures};
7use crate::composite::{CompositeFeatures, CompositeSurfaceFormat};
8use crate::device::{Device, Program, ShaderError};
9use crate::pattern::PatternKind;
10use crate::telemetry::Telemetry;
11use euclid::default::Transform3D;
12use glyph_rasterizer::GlyphFormat;
13use crate::renderer::{
14 desc,
15 BlendMode, DebugFlags, RendererError, WebRenderOptions,
16 TextureSampler, VertexArrayKind, ShaderPrecacheFlags,
17};
18use crate::profiler::{self, RenderCommandLog, TransactionProfile, ns_to_ms};
19
20use gleam::gl::GlType;
21
22use std::cell::RefCell;
23use std::collections::VecDeque;
24use std::rc::Rc;
25
26use webrender_build::shader::{ShaderFeatures, ShaderFeatureFlags, get_shader_features};
27
28#[derive(Clone, Copy, Debug, PartialEq)]
30enum TextureExternalVersion {
31 ESSL3,
34 ESSL1,
36}
37
38fn get_feature_string(kind: ImageBufferKind, texture_external_version: TextureExternalVersion) -> &'static str {
39 match (kind, texture_external_version) {
40 (ImageBufferKind::Texture2D, _) => "TEXTURE_2D",
41 (ImageBufferKind::TextureRect, _) => "TEXTURE_RECT",
42 (ImageBufferKind::TextureExternal, TextureExternalVersion::ESSL3) => "TEXTURE_EXTERNAL",
43 (ImageBufferKind::TextureExternal, TextureExternalVersion::ESSL1) => "TEXTURE_EXTERNAL_ESSL1",
44 (ImageBufferKind::TextureExternalBT709, _) => "TEXTURE_EXTERNAL_BT709",
45 }
46}
47
48fn has_platform_support(kind: ImageBufferKind, device: &Device) -> bool {
49 match (kind, device.gl().get_type()) {
50 (ImageBufferKind::Texture2D, _) => true,
51 (ImageBufferKind::TextureRect, GlType::Gles) => false,
52 (ImageBufferKind::TextureRect, GlType::Gl) => true,
53 (ImageBufferKind::TextureExternal, GlType::Gles) => true,
54 (ImageBufferKind::TextureExternal, GlType::Gl) => false,
55 (ImageBufferKind::TextureExternalBT709, GlType::Gles) => device.supports_extension("GL_EXT_YUV_target"),
56 (ImageBufferKind::TextureExternalBT709, GlType::Gl) => false,
57 }
58}
59
60pub const IMAGE_BUFFER_KINDS: [ImageBufferKind; 4] = [
61 ImageBufferKind::Texture2D,
62 ImageBufferKind::TextureRect,
63 ImageBufferKind::TextureExternal,
64 ImageBufferKind::TextureExternalBT709,
65];
66
67const ADVANCED_BLEND_FEATURE: &str = "ADVANCED_BLEND";
68const ALPHA_FEATURE: &str = "ALPHA_PASS";
69const DEBUG_OVERDRAW_FEATURE: &str = "DEBUG_OVERDRAW";
70const DITHERING_FEATURE: &str = "DITHERING";
71const DUAL_SOURCE_FEATURE: &str = "DUAL_SOURCE_BLENDING";
72const FAST_PATH_FEATURE: &str = "FAST_PATH";
73
74pub(crate) enum ShaderKind {
75 Primitive,
76 Cache(VertexArrayKind),
77 ClipCache(VertexArrayKind),
78 Brush,
79 Text,
80 Composite,
81 Clear,
82 Copy,
83}
84
85pub struct LazilyCompiledShader {
86 program: Option<Program>,
87 name: &'static str,
88 kind: ShaderKind,
89 cached_projection: Transform3D<f32>,
90 features: Vec<&'static str>,
91}
92
93impl LazilyCompiledShader {
94 pub(crate) fn new(
95 kind: ShaderKind,
96 name: &'static str,
97 unsorted_features: &[&'static str],
98 shader_list: &ShaderFeatures,
99 ) -> Result<Self, ShaderError> {
100
101 let mut features = unsorted_features.to_vec();
102 features.sort();
103
104 let config = features.join(",");
107 assert!(
108 shader_list.get(name).map_or(false, |f| f.contains(&config)),
109 "shader \"{}\" with features \"{}\" not in available shader list",
110 name,
111 config,
112 );
113
114 let shader = LazilyCompiledShader {
115 program: None,
116 name,
117 kind,
118 cached_projection: Transform3D::identity(),
121 features,
122 };
123
124 Ok(shader)
125 }
126
127 pub fn precache(
128 &mut self,
129 device: &mut Device,
130 flags: ShaderPrecacheFlags,
131 ) -> Result<(), ShaderError> {
132 let t0 = zeitstempel::now();
133 let timer_id = Telemetry::start_shaderload_time();
134 self.get_internal(device, flags, None)?;
135 Telemetry::stop_and_accumulate_shaderload_time(timer_id);
136 let t1 = zeitstempel::now();
137 debug!("[C: {:.1} ms ] Precache {} {:?}",
138 (t1 - t0) as f64 / 1000000.0,
139 self.name,
140 self.features
141 );
142 Ok(())
143 }
144
145 pub fn bind(
146 &mut self,
147 device: &mut Device,
148 projection: &Transform3D<f32>,
149 texture_size: Option<DeviceSize>,
150 renderer_errors: &mut Vec<RendererError>,
151 profile: &mut TransactionProfile,
152 history: &mut Option<RenderCommandLog>,
153 ) {
154 if let Some(history) = history {
155 history.set_shader(self.name);
156 }
157 let update_projection = self.cached_projection != *projection;
158 let program = match self.get_internal(device, ShaderPrecacheFlags::FULL_COMPILE, Some(profile)) {
159 Ok(program) => program,
160 Err(e) => {
161 renderer_errors.push(RendererError::from(e));
162 return;
163 }
164 };
165 device.bind_program(program);
166 if let Some(texture_size) = texture_size {
167 device.set_shader_texture_size(program, texture_size);
168 }
169 if update_projection {
170 device.set_uniforms(program, projection);
171 self.cached_projection = *projection;
173 }
174 }
175
176 fn get_internal(
177 &mut self,
178 device: &mut Device,
179 precache_flags: ShaderPrecacheFlags,
180 mut profile: Option<&mut TransactionProfile>,
181 ) -> Result<&mut Program, ShaderError> {
182 if self.program.is_none() {
183 let start_time = zeitstempel::now();
184 let program = match self.kind {
185 ShaderKind::Primitive | ShaderKind::Brush | ShaderKind::Text | ShaderKind::Clear | ShaderKind::Copy => {
186 create_prim_shader(
187 self.name,
188 device,
189 &self.features,
190 )
191 }
192 ShaderKind::Cache(..) => {
193 create_prim_shader(
194 self.name,
195 device,
196 &self.features,
197 )
198 }
199 ShaderKind::Composite => {
200 create_prim_shader(
201 self.name,
202 device,
203 &self.features,
204 )
205 }
206 ShaderKind::ClipCache(..) => {
207 create_clip_shader(
208 self.name,
209 device,
210 &self.features,
211 )
212 }
213 };
214 self.program = Some(program?);
215
216 if let Some(profile) = &mut profile {
217 let end_time = zeitstempel::now();
218 profile.add(profiler::SHADER_BUILD_TIME, ns_to_ms(end_time - start_time));
219 }
220 }
221
222 let program = self.program.as_mut().unwrap();
223
224 if precache_flags.contains(ShaderPrecacheFlags::FULL_COMPILE) && !program.is_initialized() {
225 let start_time = zeitstempel::now();
226
227 let vertex_format = match self.kind {
228 ShaderKind::Primitive |
229 ShaderKind::Brush |
230 ShaderKind::Text => VertexArrayKind::Primitive,
231 ShaderKind::Cache(format) => format,
232 ShaderKind::ClipCache(format) => format,
233 ShaderKind::Composite => VertexArrayKind::Composite,
234 ShaderKind::Clear => VertexArrayKind::Clear,
235 ShaderKind::Copy => VertexArrayKind::Copy,
236 };
237
238 let vertex_descriptor = match vertex_format {
239 VertexArrayKind::Primitive => &desc::PRIM_INSTANCES,
240 VertexArrayKind::LineDecoration => &desc::LINE,
241 VertexArrayKind::Blur => &desc::BLUR,
242 VertexArrayKind::ClipRect => &desc::CLIP_RECT,
243 VertexArrayKind::Border => &desc::BORDER,
244 VertexArrayKind::Scale => &desc::SCALE,
245 VertexArrayKind::SvgFilterNode => &desc::SVG_FILTER_NODE,
246 VertexArrayKind::Composite => &desc::COMPOSITE,
247 VertexArrayKind::Clear => &desc::CLEAR,
248 VertexArrayKind::Copy => &desc::COPY,
249 VertexArrayKind::Mask => &desc::MASK,
250 };
251
252 device.link_program(program, vertex_descriptor)?;
253 device.bind_program(program);
254 match self.kind {
255 ShaderKind::ClipCache(..) => {
256 device.bind_shader_samplers(
257 &program,
258 &[
259 ("sColor0", TextureSampler::Color0),
260 ("sTransformPalette", TextureSampler::TransformPalette),
261 ("sRenderTasks", TextureSampler::RenderTasks),
262 ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF),
263 ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI),
264 ("sGpuBufferF", TextureSampler::GpuBufferF),
265 ("sGpuBufferI", TextureSampler::GpuBufferI),
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 ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF),
280 ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI),
281 ("sClipMask", TextureSampler::ClipMask),
282 ("sGpuBufferF", TextureSampler::GpuBufferF),
283 ("sGpuBufferI", TextureSampler::GpuBufferI),
284 ],
285 );
286 }
287 }
288
289 if let Some(profile) = &mut profile {
290 let end_time = zeitstempel::now();
291 profile.add(profiler::SHADER_BUILD_TIME, ns_to_ms(end_time - start_time));
292 }
293 }
294
295 Ok(program)
296 }
297
298 fn deinit(self, device: &mut Device) {
299 if let Some(program) = self.program {
300 device.delete_program(program);
301 }
302 }
303}
304
305struct BrushShader {
317 opaque: ShaderHandle,
318 alpha: ShaderHandle,
319 advanced_blend: Option<ShaderHandle>,
320 dual_source: Option<ShaderHandle>,
321 debug_overdraw: ShaderHandle,
322}
323
324impl BrushShader {
325 fn new(
326 name: &'static str,
327 features: &[&'static str],
328 shader_list: &ShaderFeatures,
329 use_advanced_blend: bool,
330 use_dual_source: bool,
331 loader: &mut ShaderLoader,
332 ) -> Result<Self, ShaderError> {
333 let opaque_features = features.to_vec();
334 let opaque = loader.create_shader(
335 ShaderKind::Brush,
336 name,
337 &opaque_features,
338 &shader_list,
339 )?;
340
341 let mut alpha_features = opaque_features.to_vec();
342 alpha_features.push(ALPHA_FEATURE);
343
344 let alpha = loader.create_shader(
345 ShaderKind::Brush,
346 name,
347 &alpha_features,
348 &shader_list,
349 )?;
350
351 let advanced_blend = if use_advanced_blend {
352 let mut advanced_blend_features = alpha_features.to_vec();
353 advanced_blend_features.push(ADVANCED_BLEND_FEATURE);
354
355 let shader = loader.create_shader(
356 ShaderKind::Brush,
357 name,
358 &advanced_blend_features,
359 &shader_list,
360 )?;
361
362 Some(shader)
363 } else {
364 None
365 };
366
367 let dual_source = if use_dual_source {
368 let mut dual_source_features = alpha_features.to_vec();
369 dual_source_features.push(DUAL_SOURCE_FEATURE);
370
371 let shader = loader.create_shader(
372 ShaderKind::Brush,
373 name,
374 &dual_source_features,
375 &shader_list,
376 )?;
377
378 Some(shader)
379 } else {
380 None
381 };
382
383 let mut debug_overdraw_features = features.to_vec();
384 debug_overdraw_features.push(DEBUG_OVERDRAW_FEATURE);
385
386 let debug_overdraw = loader.create_shader(
387 ShaderKind::Brush,
388 name,
389 &debug_overdraw_features,
390 &shader_list,
391 )?;
392
393 Ok(BrushShader {
394 opaque,
395 alpha,
396 advanced_blend,
397 dual_source,
398 debug_overdraw,
399 })
400 }
401
402 fn get_handle(
403 &mut self,
404 blend_mode: BlendMode,
405 features: BatchFeatures,
406 debug_flags: DebugFlags,
407 ) -> ShaderHandle {
408 match blend_mode {
409 _ if debug_flags.contains(DebugFlags::SHOW_OVERDRAW) => self.debug_overdraw,
410 BlendMode::None => self.opaque,
411 BlendMode::Alpha |
412 BlendMode::PremultipliedAlpha |
413 BlendMode::PremultipliedDestOut |
414 BlendMode::Screen |
415 BlendMode::PlusLighter |
416 BlendMode::Exclusion => {
417 if features.contains(BatchFeatures::ALPHA_PASS) {
418 self.alpha
419 } else {
420 self.opaque
421 }
422 }
423 BlendMode::Advanced(_) => {
424 self.advanced_blend.expect("bug: no advanced blend shader loaded")
425 }
426 BlendMode::SubpixelDualSource |
427 BlendMode::MultiplyDualSource => {
428 self.dual_source.expect("bug: no dual source shader loaded")
429 }
430 }
431 }
432}
433
434pub struct TextShader {
435 simple: ShaderHandle,
436 glyph_transform: ShaderHandle,
437 debug_overdraw: ShaderHandle,
438}
439
440impl TextShader {
441 fn new(
442 name: &'static str,
443 features: &[&'static str],
444 shader_list: &ShaderFeatures,
445 loader: &mut ShaderLoader,
446 ) -> Result<Self, ShaderError> {
447 let mut simple_features = features.to_vec();
448 simple_features.push("ALPHA_PASS");
449 simple_features.push("TEXTURE_2D");
450
451 let simple = loader.create_shader(
452 ShaderKind::Text,
453 name,
454 &simple_features,
455 &shader_list,
456 )?;
457
458 let mut glyph_transform_features = features.to_vec();
459 glyph_transform_features.push("GLYPH_TRANSFORM");
460 glyph_transform_features.push("ALPHA_PASS");
461 glyph_transform_features.push("TEXTURE_2D");
462
463 let glyph_transform = loader.create_shader(
464 ShaderKind::Text,
465 name,
466 &glyph_transform_features,
467 &shader_list,
468 )?;
469
470 let mut debug_overdraw_features = features.to_vec();
471 debug_overdraw_features.push("DEBUG_OVERDRAW");
472 debug_overdraw_features.push("TEXTURE_2D");
473
474 let debug_overdraw = loader.create_shader(
475 ShaderKind::Text,
476 name,
477 &debug_overdraw_features,
478 &shader_list,
479 )?;
480
481 Ok(TextShader { simple, glyph_transform, debug_overdraw })
482 }
483
484 pub fn get_handle(
485 &mut self,
486 glyph_format: GlyphFormat,
487 debug_flags: DebugFlags,
488 ) -> ShaderHandle {
489 match glyph_format {
490 _ if debug_flags.contains(DebugFlags::SHOW_OVERDRAW) => self.debug_overdraw,
491 GlyphFormat::Alpha |
492 GlyphFormat::Subpixel |
493 GlyphFormat::Bitmap |
494 GlyphFormat::ColorBitmap => self.simple,
495 GlyphFormat::TransformedAlpha |
496 GlyphFormat::TransformedSubpixel => self.glyph_transform,
497 }
498 }
499}
500
501fn create_prim_shader(
502 name: &'static str,
503 device: &mut Device,
504 features: &[&'static str],
505) -> Result<Program, ShaderError> {
506 debug!("PrimShader {}", name);
507
508 device.create_program(name, features)
509}
510
511fn create_clip_shader(
512 name: &'static str,
513 device: &mut Device,
514 features: &[&'static str],
515) -> Result<Program, ShaderError> {
516 debug!("ClipShader {}", name);
517
518 device.create_program(name, features)
519}
520
521#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
522pub struct ShaderHandle(usize);
523
524#[derive(Default)]
525pub struct ShaderLoader {
526 shaders: Vec<LazilyCompiledShader>,
527}
528
529impl ShaderLoader {
530 pub fn new() -> Self {
531 Default::default()
532 }
533
534 pub fn create_shader(
535 &mut self,
536 kind: ShaderKind,
537 name: &'static str,
538 unsorted_features: &[&'static str],
539 shader_list: &ShaderFeatures,
540 ) -> Result<ShaderHandle, ShaderError> {
541 let index = self.shaders.len();
542 let shader = LazilyCompiledShader::new(
543 kind,
544 name,
545 unsorted_features,
546 shader_list,
547 )?;
548 self.shaders.push(shader);
549 Ok(ShaderHandle(index))
550 }
551
552 pub fn precache(
553 &mut self,
554 shader: ShaderHandle,
555 device: &mut Device,
556 flags: ShaderPrecacheFlags,
557 ) -> Result<(), ShaderError> {
558 if !flags.intersects(ShaderPrecacheFlags::ASYNC_COMPILE | ShaderPrecacheFlags::FULL_COMPILE) {
559 return Ok(());
560 }
561
562 self.shaders[shader.0].precache(device, flags)
563 }
564
565 pub fn all_handles(&self) -> Vec<ShaderHandle> {
566 self.shaders.iter().enumerate().map(|(index, _)| ShaderHandle(index)).collect()
567 }
568
569 pub fn get(&mut self, handle: ShaderHandle) -> &mut LazilyCompiledShader {
570 &mut self.shaders[handle.0]
571 }
572
573 pub fn deinit(self, device: &mut Device) {
574 for shader in self.shaders {
575 shader.deinit(device);
576 }
577 }
578}
579
580pub struct Shaders {
581 loader: ShaderLoader,
582
583 cs_blur_rgba8: ShaderHandle,
587 cs_border_segment: ShaderHandle,
588 cs_border_solid: ShaderHandle,
589 cs_scale: Vec<Option<ShaderHandle>>,
590 cs_line_decoration: ShaderHandle,
591 cs_svg_filter_node: ShaderHandle,
592
593 brush_solid: BrushShader,
595 brush_image: Vec<Option<BrushShader>>,
596 brush_fast_image: Vec<Option<BrushShader>>,
597 brush_blend: BrushShader,
598 brush_mix_blend: BrushShader,
599 brush_yuv_image: Vec<Option<BrushShader>>,
600 brush_opacity: BrushShader,
601 brush_opacity_aa: BrushShader,
602
603 cs_clip_rectangle_slow: ShaderHandle,
607 cs_clip_rectangle_fast: ShaderHandle,
608
609 ps_text_run: TextShader,
617 ps_text_run_dual_source: Option<TextShader>,
618
619 ps_split_composite: ShaderHandle,
620 ps_quad_textured: ShaderHandle,
624 ps_quad_textured_external: Option<ShaderHandle>,
625 ps_quad_textured_external_bt709: Option<ShaderHandle>,
626 ps_quad_textured_rect: Option<ShaderHandle>,
627 ps_quad_repeat: ShaderHandle,
628 ps_quad_gradient: ShaderHandle,
629 ps_quad_box_shadow: ShaderHandle,
630 ps_mask: ShaderHandle,
631 ps_mask_fast: ShaderHandle,
632 ps_clear: ShaderHandle,
633 ps_copy: ShaderHandle,
634
635 composite: CompositorShaders,
636}
637
638pub struct PendingShadersToPrecache {
639 precache_flags: ShaderPrecacheFlags,
640 remaining_shaders: VecDeque<ShaderHandle>,
641}
642
643impl Shaders {
644 pub fn new(
645 device: &mut Device,
646 gl_type: GlType,
647 options: &WebRenderOptions,
648 ) -> Result<Self, ShaderError> {
649 let use_dual_source_blending =
650 device.get_capabilities().supports_dual_source_blending &&
651 options.allow_dual_source_blending;
652 let use_advanced_blend_equation =
653 device.get_capabilities().supports_advanced_blend_equation &&
654 options.allow_advanced_blend_equation;
655
656 let texture_external_version = if device.get_capabilities().supports_image_external_essl3 {
657 TextureExternalVersion::ESSL3
658 } else {
659 TextureExternalVersion::ESSL1
660 };
661 let mut shader_flags = get_shader_feature_flags(gl_type, texture_external_version, device);
662 shader_flags.set(ShaderFeatureFlags::ADVANCED_BLEND_EQUATION, use_advanced_blend_equation);
663 shader_flags.set(ShaderFeatureFlags::DUAL_SOURCE_BLENDING, use_dual_source_blending);
664 shader_flags.set(ShaderFeatureFlags::DITHERING, options.enable_dithering);
665 let shader_list = get_shader_features(shader_flags);
666
667 let mut loader = ShaderLoader::new();
668
669 let brush_solid = BrushShader::new(
670 "brush_solid",
671 &[],
672 &shader_list,
673 false ,
674 false ,
675 &mut loader,
676 )?;
677
678 let brush_blend = BrushShader::new(
679 "brush_blend",
680 &[],
681 &shader_list,
682 false ,
683 false ,
684 &mut loader,
685 )?;
686
687 let brush_mix_blend = BrushShader::new(
688 "brush_mix_blend",
689 &[],
690 &shader_list,
691 false ,
692 false ,
693 &mut loader,
694 )?;
695
696 let brush_opacity_aa = BrushShader::new(
697 "brush_opacity",
698 &["ANTIALIASING"],
699 &shader_list,
700 false ,
701 false ,
702 &mut loader,
703 )?;
704
705 let brush_opacity = BrushShader::new(
706 "brush_opacity",
707 &[],
708 &shader_list,
709 false ,
710 false ,
711 &mut loader,
712 )?;
713
714 let cs_blur_rgba8 = loader.create_shader(
715 ShaderKind::Cache(VertexArrayKind::Blur),
716 "cs_blur",
717 &["COLOR_TARGET"],
718 &shader_list,
719 )?;
720
721 let cs_svg_filter_node = loader.create_shader(
722 ShaderKind::Cache(VertexArrayKind::SvgFilterNode),
723 "cs_svg_filter_node",
724 &[],
725 &shader_list,
726 )?;
727
728 let ps_mask = loader.create_shader(
729 ShaderKind::Cache(VertexArrayKind::Mask),
730 "ps_quad_mask",
731 &[],
732 &shader_list,
733 )?;
734
735 let ps_mask_fast = loader.create_shader(
736 ShaderKind::Cache(VertexArrayKind::Mask),
737 "ps_quad_mask",
738 &[FAST_PATH_FEATURE],
739 &shader_list,
740 )?;
741
742 let cs_clip_rectangle_slow = loader.create_shader(
743 ShaderKind::ClipCache(VertexArrayKind::ClipRect),
744 "cs_clip_rectangle",
745 &[],
746 &shader_list,
747 )?;
748
749 let cs_clip_rectangle_fast = loader.create_shader(
750 ShaderKind::ClipCache(VertexArrayKind::ClipRect),
751 "cs_clip_rectangle",
752 &[FAST_PATH_FEATURE],
753 &shader_list,
754 )?;
755
756 let mut cs_scale = Vec::new();
757 let scale_shader_num = IMAGE_BUFFER_KINDS.len();
758 for _ in 0 .. scale_shader_num {
760 cs_scale.push(None);
761 }
762 for image_buffer_kind in &IMAGE_BUFFER_KINDS {
763 if has_platform_support(*image_buffer_kind, device) {
764 let feature_string = get_feature_string(
765 *image_buffer_kind,
766 texture_external_version,
767 );
768
769 let mut features = Vec::new();
770 if feature_string != "" {
771 features.push(feature_string);
772 }
773
774 let shader = loader.create_shader(
775 ShaderKind::Cache(VertexArrayKind::Scale),
776 "cs_scale",
777 &features,
778 &shader_list,
779 )?;
780
781 let index = Self::get_compositing_shader_index(
782 *image_buffer_kind,
783 );
784 cs_scale[index] = Some(shader);
785 }
786 }
787
788 let ps_text_run = TextShader::new("ps_text_run",
793 &[],
794 &shader_list,
795 &mut loader,
796 )?;
797
798 let ps_text_run_dual_source = if use_dual_source_blending {
799 let dual_source_features = vec![DUAL_SOURCE_FEATURE];
800 Some(TextShader::new("ps_text_run",
801 &dual_source_features,
802 &shader_list,
803 &mut loader,
804 )?)
805 } else {
806 None
807 };
808
809 let ps_quad_textured = loader.create_shader(
810 ShaderKind::Primitive,
811 "ps_quad_textured",
812 &["TEXTURE_2D"],
813 &shader_list,
814 )?;
815
816 let ps_quad_textured_external = if has_platform_support(
820 ImageBufferKind::TextureExternal, device,
821 ) && texture_external_version == TextureExternalVersion::ESSL3
822 {
823 Some(loader.create_shader(
824 ShaderKind::Primitive,
825 "ps_quad_textured",
826 &["TEXTURE_EXTERNAL"],
827 &shader_list,
828 )?)
829 } else {
830 None
831 };
832
833 let ps_quad_textured_external_bt709 = if has_platform_support(
834 ImageBufferKind::TextureExternalBT709, device,
835 ) {
836 Some(loader.create_shader(
837 ShaderKind::Primitive,
838 "ps_quad_textured",
839 &["TEXTURE_EXTERNAL_BT709"],
840 &shader_list,
841 )?)
842 } else {
843 None
844 };
845
846 let ps_quad_textured_rect = if has_platform_support(
847 ImageBufferKind::TextureRect, device,
848 ) {
849 Some(loader.create_shader(
850 ShaderKind::Primitive,
851 "ps_quad_textured",
852 &["TEXTURE_RECT"],
853 &shader_list,
854 )?)
855 } else {
856 None
857 };
858
859 let ps_quad_repeat = loader.create_shader(
860 ShaderKind::Primitive,
861 "ps_quad_repeat",
862 &[],
863 &shader_list,
864 )?;
865
866 let ps_quad_gradient = loader.create_shader(
867 ShaderKind::Primitive,
868 "ps_quad_gradient",
869 if options.enable_dithering {
870 &[DITHERING_FEATURE]
871 } else {
872 &[]
873 },
874 &shader_list,
875 )?;
876
877 let ps_quad_box_shadow = loader.create_shader(
878 ShaderKind::Primitive,
879 "ps_quad_box_shadow",
880 &[],
881 &shader_list,
882 )?;
883
884 let ps_split_composite = loader.create_shader(
885 ShaderKind::Primitive,
886 "ps_split_composite",
887 &[],
888 &shader_list,
889 )?;
890
891 let ps_clear = loader.create_shader(
892 ShaderKind::Clear,
893 "ps_clear",
894 &[],
895 &shader_list,
896 )?;
897
898 let ps_copy = loader.create_shader(
899 ShaderKind::Copy,
900 "ps_copy",
901 &[],
902 &shader_list,
903 )?;
904
905 let mut image_features = Vec::new();
907 let mut brush_image = Vec::new();
908 let mut brush_fast_image = Vec::new();
909 for _ in 0 .. IMAGE_BUFFER_KINDS.len() {
911 brush_image.push(None);
912 brush_fast_image.push(None);
913 }
914 for buffer_kind in 0 .. IMAGE_BUFFER_KINDS.len() {
915 if !has_platform_support(IMAGE_BUFFER_KINDS[buffer_kind], device)
916 || (IMAGE_BUFFER_KINDS[buffer_kind] == ImageBufferKind::TextureExternal
918 && texture_external_version == TextureExternalVersion::ESSL1)
919 {
920 continue;
921 }
922
923 let feature_string = get_feature_string(
924 IMAGE_BUFFER_KINDS[buffer_kind],
925 texture_external_version,
926 );
927 if feature_string != "" {
928 image_features.push(feature_string);
929 }
930
931 brush_fast_image[buffer_kind] = Some(BrushShader::new(
932 "brush_image",
933 &image_features,
934 &shader_list,
935 use_advanced_blend_equation,
936 use_dual_source_blending,
937 &mut loader,
938 )?);
939
940 image_features.push("REPETITION");
941 image_features.push("ANTIALIASING");
942
943 brush_image[buffer_kind] = Some(BrushShader::new(
944 "brush_image",
945 &image_features,
946 &shader_list,
947 use_advanced_blend_equation,
948 use_dual_source_blending,
949 &mut loader,
950 )?);
951
952 image_features.clear();
953 }
954
955 let mut yuv_features = Vec::new();
957 let mut rgba_features = Vec::new();
958 let mut fast_path_features = Vec::new();
959 let yuv_shader_num = IMAGE_BUFFER_KINDS.len();
960 let mut brush_yuv_image = Vec::new();
961 for _ in 0 .. yuv_shader_num {
963 brush_yuv_image.push(None);
964 }
965 for image_buffer_kind in &IMAGE_BUFFER_KINDS {
966 if has_platform_support(*image_buffer_kind, device) {
967 yuv_features.push("YUV");
968 fast_path_features.push("FAST_PATH");
969
970 let index = Self::get_compositing_shader_index(
971 *image_buffer_kind,
972 );
973
974 let feature_string = get_feature_string(
975 *image_buffer_kind,
976 texture_external_version,
977 );
978 if feature_string != "" {
979 yuv_features.push(feature_string);
980 rgba_features.push(feature_string);
981 fast_path_features.push(feature_string);
982 }
983
984 if *image_buffer_kind != ImageBufferKind::TextureExternal ||
986 texture_external_version == TextureExternalVersion::ESSL3 {
987 let brush_shader = BrushShader::new(
988 "brush_yuv_image",
989 &yuv_features,
990 &shader_list,
991 false ,
992 false ,
993 &mut loader,
994 )?;
995 brush_yuv_image[index] = Some(brush_shader);
996 }
997
998 yuv_features.clear();
999 rgba_features.clear();
1000 fast_path_features.clear();
1001 }
1002 }
1003
1004 let cs_line_decoration = loader.create_shader(
1005 ShaderKind::Cache(VertexArrayKind::LineDecoration),
1006 "cs_line_decoration",
1007 &[],
1008 &shader_list,
1009 )?;
1010
1011
1012 let cs_border_segment = loader.create_shader(
1013 ShaderKind::Cache(VertexArrayKind::Border),
1014 "cs_border_segment",
1015 &[],
1016 &shader_list,
1017 )?;
1018
1019 let cs_border_solid = loader.create_shader(
1020 ShaderKind::Cache(VertexArrayKind::Border),
1021 "cs_border_solid",
1022 &[],
1023 &shader_list,
1024 )?;
1025
1026 let composite = CompositorShaders::new(device, gl_type, &mut loader)?;
1027
1028 Ok(Shaders {
1029 loader,
1030
1031 cs_blur_rgba8,
1032 cs_border_segment,
1033 cs_line_decoration,
1034 cs_border_solid,
1035 cs_scale,
1036 cs_svg_filter_node,
1037 brush_solid,
1038 brush_image,
1039 brush_fast_image,
1040 brush_blend,
1041 brush_mix_blend,
1042 brush_yuv_image,
1043 brush_opacity,
1044 brush_opacity_aa,
1045 cs_clip_rectangle_slow,
1046 cs_clip_rectangle_fast,
1047 ps_text_run,
1048 ps_text_run_dual_source,
1049 ps_quad_textured,
1050 ps_quad_textured_external,
1051 ps_quad_textured_external_bt709,
1052 ps_quad_textured_rect,
1053 ps_quad_repeat,
1054 ps_quad_gradient,
1055 ps_quad_box_shadow,
1056 ps_mask,
1057 ps_mask_fast,
1058 ps_split_composite,
1059 ps_clear,
1060 ps_copy,
1061 composite,
1062 })
1063 }
1064
1065 #[must_use]
1066 pub fn precache_all(
1067 &mut self,
1068 precache_flags: ShaderPrecacheFlags,
1069 ) -> PendingShadersToPrecache {
1070 PendingShadersToPrecache {
1071 precache_flags,
1072 remaining_shaders: self.loader.all_handles().into(),
1073 }
1074 }
1075
1076 pub fn resume_precache(
1078 &mut self,
1079 device: &mut Device,
1080 pending_shaders: &mut PendingShadersToPrecache,
1081 ) -> Result<bool, ShaderError> {
1082 let Some(next_shader) = pending_shaders.remaining_shaders.pop_front() else {
1083 return Ok(false)
1084 };
1085
1086 self.loader.precache(next_shader, device, pending_shaders.precache_flags)?;
1087 Ok(true)
1088 }
1089
1090 fn get_compositing_shader_index(buffer_kind: ImageBufferKind) -> usize {
1091 buffer_kind as usize
1092 }
1093
1094 pub fn get_composite_shader(
1095 &mut self,
1096 format: CompositeSurfaceFormat,
1097 buffer_kind: ImageBufferKind,
1098 features: CompositeFeatures,
1099 ) -> &mut LazilyCompiledShader {
1100 let shader_handle = self.composite.get_handle(format, buffer_kind, features);
1101 self.loader.get(shader_handle)
1102 }
1103
1104 pub fn get_scale_shader(
1105 &mut self,
1106 buffer_kind: ImageBufferKind,
1107 ) -> &mut LazilyCompiledShader {
1108 let shader_index = Self::get_compositing_shader_index(buffer_kind);
1109 let shader_handle = self.cs_scale[shader_index]
1110 .expect("bug: unsupported scale shader requested");
1111 self.loader.get(shader_handle)
1112 }
1113
1114 pub fn get_quad_shader(
1115 &mut self,
1116 pattern: PatternKind,
1117 ) -> &mut LazilyCompiledShader {
1118 let shader_handle = match pattern {
1119 PatternKind::ColorOrTexture => self.ps_quad_textured,
1120 PatternKind::TextureExternal => self.ps_quad_textured_external
1121 .expect("bug: ps_quad_textured TEXTURE_EXTERNAL variant not loaded"),
1122 PatternKind::TextureExternalBT709 => self.ps_quad_textured_external_bt709
1123 .expect("bug: ps_quad_textured TEXTURE_EXTERNAL_BT709 variant not loaded"),
1124 PatternKind::TextureRect => self.ps_quad_textured_rect
1125 .expect("bug: ps_quad_textured TEXTURE_RECT variant not loaded"),
1126 PatternKind::Gradient => self.ps_quad_gradient,
1127 PatternKind::Repeat => self.ps_quad_repeat,
1128 PatternKind::BoxShadow => self.ps_quad_box_shadow,
1129 PatternKind::Mask => unreachable!(),
1130 };
1131 self.loader.get(shader_handle)
1132 }
1133
1134 pub fn get(
1135 &mut self,
1136 key: &BatchKey,
1137 features: BatchFeatures,
1138 debug_flags: DebugFlags,
1139 device: &Device,
1140 ) -> &mut LazilyCompiledShader {
1141 let shader_handle = self.get_handle(key, features, debug_flags, device);
1142 self.loader.get(shader_handle)
1143 }
1144
1145 pub fn get_handle(
1146 &mut self,
1147 key: &BatchKey,
1148 mut features: BatchFeatures,
1149 debug_flags: DebugFlags,
1150 device: &Device,
1151 ) -> ShaderHandle {
1152 match key.kind {
1153 BatchKind::Quad(PatternKind::ColorOrTexture) => {
1154 self.ps_quad_textured
1155 }
1156 BatchKind::Quad(PatternKind::TextureExternal) => {
1157 self.ps_quad_textured_external
1158 .expect("bug: ps_quad_textured TEXTURE_EXTERNAL variant not loaded")
1159 }
1160 BatchKind::Quad(PatternKind::TextureExternalBT709) => {
1161 self.ps_quad_textured_external_bt709
1162 .expect("bug: ps_quad_textured TEXTURE_EXTERNAL_BT709 variant not loaded")
1163 }
1164 BatchKind::Quad(PatternKind::TextureRect) => {
1165 self.ps_quad_textured_rect
1166 .expect("bug: ps_quad_textured TEXTURE_RECT variant not loaded")
1167 }
1168 BatchKind::Quad(PatternKind::Gradient) => {
1169 self.ps_quad_gradient
1170 }
1171 BatchKind::Quad(PatternKind::Repeat) => {
1172 self.ps_quad_repeat
1173 }
1174 BatchKind::Quad(PatternKind::BoxShadow) => {
1175 self.ps_quad_box_shadow
1176 }
1177 BatchKind::Quad(PatternKind::Mask) => {
1178 unreachable!();
1179 }
1180 BatchKind::SplitComposite => {
1181 self.ps_split_composite
1182 }
1183 BatchKind::Brush(brush_kind) => {
1184 if device.get_capabilities().uses_native_antialiasing {
1188 features.remove(BatchFeatures::ANTIALIASING);
1189 }
1190 let brush_shader = match brush_kind {
1191 BrushBatchKind::Solid => {
1192 &mut self.brush_solid
1193 }
1194 BrushBatchKind::Image(image_buffer_kind) => {
1195 if features.contains(BatchFeatures::ANTIALIASING) ||
1196 features.contains(BatchFeatures::REPETITION) {
1197
1198 self.brush_image[image_buffer_kind as usize]
1199 .as_mut()
1200 .expect("Unsupported image shader kind")
1201 } else {
1202 self.brush_fast_image[image_buffer_kind as usize]
1203 .as_mut()
1204 .expect("Unsupported image shader kind")
1205 }
1206 }
1207 BrushBatchKind::Blend => {
1208 &mut self.brush_blend
1209 }
1210 BrushBatchKind::MixBlend { .. } => {
1211 &mut self.brush_mix_blend
1212 }
1213 BrushBatchKind::YuvImage(image_buffer_kind, ..) => {
1214 let shader_index =
1215 Self::get_compositing_shader_index(image_buffer_kind);
1216 self.brush_yuv_image[shader_index]
1217 .as_mut()
1218 .expect("Unsupported YUV shader kind")
1219 }
1220 BrushBatchKind::Opacity => {
1221 if features.contains(BatchFeatures::ANTIALIASING) {
1222 &mut self.brush_opacity_aa
1223 } else {
1224 &mut self.brush_opacity
1225 }
1226 }
1227 };
1228 brush_shader.get_handle(key.blend_mode, features, debug_flags)
1229 }
1230 BatchKind::TextRun(glyph_format) => {
1231 let text_shader = match key.blend_mode {
1232 BlendMode::SubpixelDualSource => self.ps_text_run_dual_source.as_mut().unwrap(),
1233 _ => &mut self.ps_text_run,
1234 };
1235 text_shader.get_handle(glyph_format, debug_flags)
1236 }
1237 }
1238 }
1239
1240 pub fn cs_blur_rgba8(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_blur_rgba8) }
1241 pub fn cs_border_segment(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_segment) }
1242 pub fn cs_border_solid(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_solid) }
1243 pub fn cs_line_decoration(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_line_decoration) }
1244 pub fn cs_svg_filter_node(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_svg_filter_node) }
1245 pub fn cs_clip_rectangle_slow(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_clip_rectangle_slow) }
1246 pub fn cs_clip_rectangle_fast(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_clip_rectangle_fast) }
1247 pub fn ps_quad_textured(&mut self) -> &mut LazilyCompiledShader {
1248 self.loader.get(self.ps_quad_textured)
1249 }
1250 pub fn ps_mask(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_mask) }
1251 pub fn ps_mask_fast(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_mask_fast) }
1252 pub fn ps_clear(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_clear) }
1253 pub fn ps_copy(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_copy) }
1254
1255 pub fn deinit(self, device: &mut Device) {
1256 self.loader.deinit(device);
1257 }
1258}
1259
1260pub type SharedShaders = Rc<RefCell<Shaders>>;
1261
1262pub struct CompositorShaders {
1263 rgba: Vec<Option<ShaderHandle>>,
1274 rgba_fast_path: Vec<Option<ShaderHandle>>,
1277 yuv_clip: Vec<Option<ShaderHandle>>,
1279 yuv_fast: Vec<Option<ShaderHandle>>,
1280}
1281
1282impl CompositorShaders {
1283 pub fn new(
1284 device: &mut Device,
1285 gl_type: GlType,
1286 loader: &mut ShaderLoader,
1287 ) -> Result<Self, ShaderError> {
1288 let mut yuv_clip_features = Vec::new();
1289 let mut yuv_fast_features = Vec::new();
1290 let mut rgba_features = Vec::new();
1291 let mut fast_path_features = Vec::new();
1292 let mut rgba = Vec::new();
1293 let mut rgba_fast_path = Vec::new();
1294 let mut yuv_clip = Vec::new();
1295 let mut yuv_fast = Vec::new();
1296
1297 let texture_external_version = if device.get_capabilities().supports_image_external_essl3 {
1298 TextureExternalVersion::ESSL3
1299 } else {
1300 TextureExternalVersion::ESSL1
1301 };
1302
1303 let feature_flags = get_shader_feature_flags(gl_type, texture_external_version, device);
1304 let shader_list = get_shader_features(feature_flags);
1305
1306 for _ in 0..IMAGE_BUFFER_KINDS.len() {
1307 yuv_clip.push(None);
1308 yuv_fast.push(None);
1309 rgba.push(None);
1310 rgba_fast_path.push(None);
1311 }
1312
1313 for image_buffer_kind in &IMAGE_BUFFER_KINDS {
1314 if !has_platform_support(*image_buffer_kind, device) {
1315 continue;
1316 }
1317
1318 yuv_clip_features.push("YUV");
1319 yuv_fast_features.push("YUV");
1320 yuv_fast_features.push("FAST_PATH");
1321 fast_path_features.push("FAST_PATH");
1322
1323 let index = Self::get_shader_index(*image_buffer_kind);
1324
1325 let feature_string = get_feature_string(
1326 *image_buffer_kind,
1327 texture_external_version,
1328 );
1329 if feature_string != "" {
1330 yuv_clip_features.push(feature_string);
1331 yuv_fast_features.push(feature_string);
1332 rgba_features.push(feature_string);
1333 fast_path_features.push(feature_string);
1334 }
1335
1336 if *image_buffer_kind != ImageBufferKind::TextureExternal ||
1338 texture_external_version == TextureExternalVersion::ESSL3 {
1339
1340 yuv_clip[index] = Some(loader.create_shader(
1341 ShaderKind::Composite,
1342 "composite",
1343 &yuv_clip_features,
1344 &shader_list,
1345 )?);
1346
1347 yuv_fast[index] = Some(loader.create_shader(
1348 ShaderKind::Composite,
1349 "composite",
1350 &yuv_fast_features,
1351 &shader_list,
1352 )?);
1353 }
1354
1355 rgba[index] = Some(loader.create_shader(
1356 ShaderKind::Composite,
1357 "composite",
1358 &rgba_features,
1359 &shader_list,
1360 )?);
1361
1362 rgba_fast_path[index] = Some(loader.create_shader(
1363 ShaderKind::Composite,
1364 "composite",
1365 &fast_path_features,
1366 &shader_list,
1367 )?);
1368
1369 yuv_fast_features.clear();
1370 yuv_clip_features.clear();
1371 rgba_features.clear();
1372 fast_path_features.clear();
1373 }
1374
1375 Ok(CompositorShaders {
1376 rgba,
1377 rgba_fast_path,
1378 yuv_clip,
1379 yuv_fast,
1380 })
1381 }
1382
1383 pub fn get_handle(
1384 &mut self,
1385 format: CompositeSurfaceFormat,
1386 buffer_kind: ImageBufferKind,
1387 features: CompositeFeatures,
1388 ) -> ShaderHandle {
1389 match format {
1390 CompositeSurfaceFormat::Rgba => {
1391 if features.contains(CompositeFeatures::NO_UV_CLAMP)
1392 && features.contains(CompositeFeatures::NO_COLOR_MODULATION)
1393 && features.contains(CompositeFeatures::NO_CLIP_MASK)
1394 {
1395 let shader_index = Self::get_shader_index(buffer_kind);
1396 self.rgba_fast_path[shader_index]
1397 .expect("bug: unsupported rgba fast path shader requested")
1398 } else {
1399 let shader_index = Self::get_shader_index(buffer_kind);
1400 self.rgba[shader_index]
1401 .expect("bug: unsupported rgba shader requested")
1402 }
1403 }
1404 CompositeSurfaceFormat::Yuv => {
1405 let shader_index = Self::get_shader_index(buffer_kind);
1406 if features.contains(CompositeFeatures::NO_CLIP_MASK) {
1407 self.yuv_fast[shader_index]
1408 .expect("bug: unsupported yuv shader requested")
1409 } else {
1410 self.yuv_clip[shader_index]
1411 .expect("bug: unsupported yuv shader requested")
1412 }
1413 }
1414 }
1415 }
1416
1417 fn get_shader_index(buffer_kind: ImageBufferKind) -> usize {
1418 buffer_kind as usize
1419 }
1420}
1421
1422fn get_shader_feature_flags(
1423 gl_type: GlType,
1424 texture_external_version: TextureExternalVersion,
1425 device: &Device
1426) -> ShaderFeatureFlags {
1427 match gl_type {
1428 GlType::Gl => ShaderFeatureFlags::GL,
1429 GlType::Gles => {
1430 let mut flags = ShaderFeatureFlags::GLES;
1431 flags |= match texture_external_version {
1432 TextureExternalVersion::ESSL3 => ShaderFeatureFlags::TEXTURE_EXTERNAL,
1433 TextureExternalVersion::ESSL1 => ShaderFeatureFlags::TEXTURE_EXTERNAL_ESSL1,
1434 };
1435 if device.supports_extension("GL_EXT_YUV_target") {
1436 flags |= ShaderFeatureFlags::TEXTURE_EXTERNAL_BT709;
1437 }
1438 flags
1439 }
1440 }
1441}