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