shade.rs (52260B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use api::{ImageBufferKind, units::DeviceSize}; 6 use crate::batch::{BatchKey, BatchKind, BrushBatchKind, BatchFeatures}; 7 use crate::composite::{CompositeFeatures, CompositeSurfaceFormat}; 8 use crate::device::{Device, Program, ShaderError}; 9 use crate::pattern::PatternKind; 10 use crate::telemetry::Telemetry; 11 use euclid::default::Transform3D; 12 use glyph_rasterizer::GlyphFormat; 13 use crate::renderer::{ 14 desc, 15 BlendMode, DebugFlags, RendererError, WebRenderOptions, 16 TextureSampler, VertexArrayKind, ShaderPrecacheFlags, 17 }; 18 use crate::profiler::{self, RenderCommandLog, TransactionProfile, ns_to_ms}; 19 20 use gleam::gl::GlType; 21 22 use std::cell::RefCell; 23 use std::collections::VecDeque; 24 use std::rc::Rc; 25 26 use webrender_build::shader::{ShaderFeatures, ShaderFeatureFlags, get_shader_features}; 27 28 /// Which extension version to use for texture external support. 29 #[derive(Clone, Copy, Debug, PartialEq)] 30 enum TextureExternalVersion { 31 // GL_OES_EGL_image_external_essl3 (Compatible with ESSL 3.0 and 32 // later shaders, but not supported on all GLES 3 devices.) 33 ESSL3, 34 // GL_OES_EGL_image_external (Compatible with ESSL 1.0 shaders) 35 ESSL1, 36 } 37 38 fn 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 48 fn 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 60 pub const IMAGE_BUFFER_KINDS: [ImageBufferKind; 4] = [ 61 ImageBufferKind::Texture2D, 62 ImageBufferKind::TextureRect, 63 ImageBufferKind::TextureExternal, 64 ImageBufferKind::TextureExternalBT709, 65 ]; 66 67 const ADVANCED_BLEND_FEATURE: &str = "ADVANCED_BLEND"; 68 const ALPHA_FEATURE: &str = "ALPHA_PASS"; 69 const DEBUG_OVERDRAW_FEATURE: &str = "DEBUG_OVERDRAW"; 70 const DITHERING_FEATURE: &str = "DITHERING"; 71 const DUAL_SOURCE_FEATURE: &str = "DUAL_SOURCE_BLENDING"; 72 const FAST_PATH_FEATURE: &str = "FAST_PATH"; 73 74 pub(crate) enum ShaderKind { 75 Primitive, 76 Cache(VertexArrayKind), 77 ClipCache(VertexArrayKind), 78 Brush, 79 Text, 80 Composite, 81 Clear, 82 Copy, 83 } 84 85 pub 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 93 impl 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 // Ensure this shader config is in the available shader list so that we get 105 // alerted if the list gets out-of-date when shaders or features are added. 106 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 //Note: this isn't really the default state, but there is no chance 119 // an actual projection passed here would accidentally match. 120 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 // thanks NLL for this (`program` technically borrows `self`) 172 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::FastLinearGradient => &desc::FAST_LINEAR_GRADIENT, 242 VertexArrayKind::LinearGradient => &desc::LINEAR_GRADIENT, 243 VertexArrayKind::RadialGradient => &desc::RADIAL_GRADIENT, 244 VertexArrayKind::ConicGradient => &desc::CONIC_GRADIENT, 245 VertexArrayKind::Blur => &desc::BLUR, 246 VertexArrayKind::ClipRect => &desc::CLIP_RECT, 247 VertexArrayKind::ClipBoxShadow => &desc::CLIP_BOX_SHADOW, 248 VertexArrayKind::Border => &desc::BORDER, 249 VertexArrayKind::Scale => &desc::SCALE, 250 VertexArrayKind::SvgFilterNode => &desc::SVG_FILTER_NODE, 251 VertexArrayKind::Composite => &desc::COMPOSITE, 252 VertexArrayKind::Clear => &desc::CLEAR, 253 VertexArrayKind::Copy => &desc::COPY, 254 VertexArrayKind::Mask => &desc::MASK, 255 }; 256 257 device.link_program(program, vertex_descriptor)?; 258 device.bind_program(program); 259 match self.kind { 260 ShaderKind::ClipCache(..) => { 261 device.bind_shader_samplers( 262 &program, 263 &[ 264 ("sColor0", TextureSampler::Color0), 265 ("sTransformPalette", TextureSampler::TransformPalette), 266 ("sRenderTasks", TextureSampler::RenderTasks), 267 ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF), 268 ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI), 269 ("sGpuBufferF", TextureSampler::GpuBufferF), 270 ("sGpuBufferI", TextureSampler::GpuBufferI), 271 ], 272 ); 273 } 274 _ => { 275 device.bind_shader_samplers( 276 &program, 277 &[ 278 ("sColor0", TextureSampler::Color0), 279 ("sColor1", TextureSampler::Color1), 280 ("sColor2", TextureSampler::Color2), 281 ("sDither", TextureSampler::Dither), 282 ("sTransformPalette", TextureSampler::TransformPalette), 283 ("sRenderTasks", TextureSampler::RenderTasks), 284 ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF), 285 ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI), 286 ("sClipMask", TextureSampler::ClipMask), 287 ("sGpuBufferF", TextureSampler::GpuBufferF), 288 ("sGpuBufferI", TextureSampler::GpuBufferI), 289 ], 290 ); 291 } 292 } 293 294 if let Some(profile) = &mut profile { 295 let end_time = zeitstempel::now(); 296 profile.add(profiler::SHADER_BUILD_TIME, ns_to_ms(end_time - start_time)); 297 } 298 } 299 300 Ok(program) 301 } 302 303 fn deinit(self, device: &mut Device) { 304 if let Some(program) = self.program { 305 device.delete_program(program); 306 } 307 } 308 } 309 310 // A brush shader supports two modes: 311 // opaque: 312 // Used for completely opaque primitives, 313 // or inside segments of partially 314 // opaque primitives. Assumes no need 315 // for clip masks, AA etc. 316 // alpha: 317 // Used for brush primitives in the alpha 318 // pass. Assumes that AA should be applied 319 // along the primitive edge, and also that 320 // clip mask is present. 321 struct BrushShader { 322 opaque: ShaderHandle, 323 alpha: ShaderHandle, 324 advanced_blend: Option<ShaderHandle>, 325 dual_source: Option<ShaderHandle>, 326 debug_overdraw: ShaderHandle, 327 } 328 329 impl BrushShader { 330 fn new( 331 name: &'static str, 332 features: &[&'static str], 333 shader_list: &ShaderFeatures, 334 use_advanced_blend: bool, 335 use_dual_source: bool, 336 loader: &mut ShaderLoader, 337 ) -> Result<Self, ShaderError> { 338 let opaque_features = features.to_vec(); 339 let opaque = loader.create_shader( 340 ShaderKind::Brush, 341 name, 342 &opaque_features, 343 &shader_list, 344 )?; 345 346 let mut alpha_features = opaque_features.to_vec(); 347 alpha_features.push(ALPHA_FEATURE); 348 349 let alpha = loader.create_shader( 350 ShaderKind::Brush, 351 name, 352 &alpha_features, 353 &shader_list, 354 )?; 355 356 let advanced_blend = if use_advanced_blend { 357 let mut advanced_blend_features = alpha_features.to_vec(); 358 advanced_blend_features.push(ADVANCED_BLEND_FEATURE); 359 360 let shader = loader.create_shader( 361 ShaderKind::Brush, 362 name, 363 &advanced_blend_features, 364 &shader_list, 365 )?; 366 367 Some(shader) 368 } else { 369 None 370 }; 371 372 let dual_source = if use_dual_source { 373 let mut dual_source_features = alpha_features.to_vec(); 374 dual_source_features.push(DUAL_SOURCE_FEATURE); 375 376 let shader = loader.create_shader( 377 ShaderKind::Brush, 378 name, 379 &dual_source_features, 380 &shader_list, 381 )?; 382 383 Some(shader) 384 } else { 385 None 386 }; 387 388 let mut debug_overdraw_features = features.to_vec(); 389 debug_overdraw_features.push(DEBUG_OVERDRAW_FEATURE); 390 391 let debug_overdraw = loader.create_shader( 392 ShaderKind::Brush, 393 name, 394 &debug_overdraw_features, 395 &shader_list, 396 )?; 397 398 Ok(BrushShader { 399 opaque, 400 alpha, 401 advanced_blend, 402 dual_source, 403 debug_overdraw, 404 }) 405 } 406 407 fn get_handle( 408 &mut self, 409 blend_mode: BlendMode, 410 features: BatchFeatures, 411 debug_flags: DebugFlags, 412 ) -> ShaderHandle { 413 match blend_mode { 414 _ if debug_flags.contains(DebugFlags::SHOW_OVERDRAW) => self.debug_overdraw, 415 BlendMode::None => self.opaque, 416 BlendMode::Alpha | 417 BlendMode::PremultipliedAlpha | 418 BlendMode::PremultipliedDestOut | 419 BlendMode::Screen | 420 BlendMode::PlusLighter | 421 BlendMode::Exclusion => { 422 if features.contains(BatchFeatures::ALPHA_PASS) { 423 self.alpha 424 } else { 425 self.opaque 426 } 427 } 428 BlendMode::Advanced(_) => { 429 self.advanced_blend.expect("bug: no advanced blend shader loaded") 430 } 431 BlendMode::SubpixelDualSource | 432 BlendMode::MultiplyDualSource => { 433 self.dual_source.expect("bug: no dual source shader loaded") 434 } 435 } 436 } 437 } 438 439 pub struct TextShader { 440 simple: ShaderHandle, 441 glyph_transform: ShaderHandle, 442 debug_overdraw: ShaderHandle, 443 } 444 445 impl TextShader { 446 fn new( 447 name: &'static str, 448 features: &[&'static str], 449 shader_list: &ShaderFeatures, 450 loader: &mut ShaderLoader, 451 ) -> Result<Self, ShaderError> { 452 let mut simple_features = features.to_vec(); 453 simple_features.push("ALPHA_PASS"); 454 simple_features.push("TEXTURE_2D"); 455 456 let simple = loader.create_shader( 457 ShaderKind::Text, 458 name, 459 &simple_features, 460 &shader_list, 461 )?; 462 463 let mut glyph_transform_features = features.to_vec(); 464 glyph_transform_features.push("GLYPH_TRANSFORM"); 465 glyph_transform_features.push("ALPHA_PASS"); 466 glyph_transform_features.push("TEXTURE_2D"); 467 468 let glyph_transform = loader.create_shader( 469 ShaderKind::Text, 470 name, 471 &glyph_transform_features, 472 &shader_list, 473 )?; 474 475 let mut debug_overdraw_features = features.to_vec(); 476 debug_overdraw_features.push("DEBUG_OVERDRAW"); 477 debug_overdraw_features.push("TEXTURE_2D"); 478 479 let debug_overdraw = loader.create_shader( 480 ShaderKind::Text, 481 name, 482 &debug_overdraw_features, 483 &shader_list, 484 )?; 485 486 Ok(TextShader { simple, glyph_transform, debug_overdraw }) 487 } 488 489 pub fn get_handle( 490 &mut self, 491 glyph_format: GlyphFormat, 492 debug_flags: DebugFlags, 493 ) -> ShaderHandle { 494 match glyph_format { 495 _ if debug_flags.contains(DebugFlags::SHOW_OVERDRAW) => self.debug_overdraw, 496 GlyphFormat::Alpha | 497 GlyphFormat::Subpixel | 498 GlyphFormat::Bitmap | 499 GlyphFormat::ColorBitmap => self.simple, 500 GlyphFormat::TransformedAlpha | 501 GlyphFormat::TransformedSubpixel => self.glyph_transform, 502 } 503 } 504 } 505 506 fn create_prim_shader( 507 name: &'static str, 508 device: &mut Device, 509 features: &[&'static str], 510 ) -> Result<Program, ShaderError> { 511 debug!("PrimShader {}", name); 512 513 device.create_program(name, features) 514 } 515 516 fn create_clip_shader( 517 name: &'static str, 518 device: &mut Device, 519 features: &[&'static str], 520 ) -> Result<Program, ShaderError> { 521 debug!("ClipShader {}", name); 522 523 device.create_program(name, features) 524 } 525 526 #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)] 527 pub struct ShaderHandle(usize); 528 529 #[derive(Default)] 530 pub struct ShaderLoader { 531 shaders: Vec<LazilyCompiledShader>, 532 } 533 534 impl ShaderLoader { 535 pub fn new() -> Self { 536 Default::default() 537 } 538 539 pub fn create_shader( 540 &mut self, 541 kind: ShaderKind, 542 name: &'static str, 543 unsorted_features: &[&'static str], 544 shader_list: &ShaderFeatures, 545 ) -> Result<ShaderHandle, ShaderError> { 546 let index = self.shaders.len(); 547 let shader = LazilyCompiledShader::new( 548 kind, 549 name, 550 unsorted_features, 551 shader_list, 552 )?; 553 self.shaders.push(shader); 554 Ok(ShaderHandle(index)) 555 } 556 557 pub fn precache( 558 &mut self, 559 shader: ShaderHandle, 560 device: &mut Device, 561 flags: ShaderPrecacheFlags, 562 ) -> Result<(), ShaderError> { 563 if !flags.intersects(ShaderPrecacheFlags::ASYNC_COMPILE | ShaderPrecacheFlags::FULL_COMPILE) { 564 return Ok(()); 565 } 566 567 self.shaders[shader.0].precache(device, flags) 568 } 569 570 pub fn all_handles(&self) -> Vec<ShaderHandle> { 571 self.shaders.iter().enumerate().map(|(index, _)| ShaderHandle(index)).collect() 572 } 573 574 pub fn get(&mut self, handle: ShaderHandle) -> &mut LazilyCompiledShader { 575 &mut self.shaders[handle.0] 576 } 577 578 pub fn deinit(self, device: &mut Device) { 579 for shader in self.shaders { 580 shader.deinit(device); 581 } 582 } 583 } 584 585 pub struct Shaders { 586 loader: ShaderLoader, 587 588 // These are "cache shaders". These shaders are used to 589 // draw intermediate results to cache targets. The results 590 // of these shaders are then used by the primitive shaders. 591 cs_blur_rgba8: ShaderHandle, 592 cs_border_segment: ShaderHandle, 593 cs_border_solid: ShaderHandle, 594 cs_scale: Vec<Option<ShaderHandle>>, 595 cs_line_decoration: ShaderHandle, 596 cs_fast_linear_gradient: ShaderHandle, 597 cs_linear_gradient: ShaderHandle, 598 cs_radial_gradient: ShaderHandle, 599 cs_conic_gradient: ShaderHandle, 600 cs_svg_filter_node: ShaderHandle, 601 602 // Brush shaders 603 brush_solid: BrushShader, 604 brush_image: Vec<Option<BrushShader>>, 605 brush_fast_image: Vec<Option<BrushShader>>, 606 brush_blend: BrushShader, 607 brush_mix_blend: BrushShader, 608 brush_yuv_image: Vec<Option<BrushShader>>, 609 brush_linear_gradient: BrushShader, 610 brush_opacity: BrushShader, 611 brush_opacity_aa: BrushShader, 612 613 /// These are "cache clip shaders". These shaders are used to 614 /// draw clip instances into the cached clip mask. The results 615 /// of these shaders are also used by the primitive shaders. 616 cs_clip_rectangle_slow: ShaderHandle, 617 cs_clip_rectangle_fast: ShaderHandle, 618 cs_clip_box_shadow: ShaderHandle, 619 620 // The are "primitive shaders". These shaders draw and blend 621 // final results on screen. They are aware of tile boundaries. 622 // Most draw directly to the framebuffer, but some use inputs 623 // from the cache shaders to draw. Specifically, the box 624 // shadow primitive shader stretches the box shadow cache 625 // output, and the cache_image shader blits the results of 626 // a cache shader (e.g. blur) to the screen. 627 ps_text_run: TextShader, 628 ps_text_run_dual_source: Option<TextShader>, 629 630 ps_split_composite: ShaderHandle, 631 ps_quad_textured: ShaderHandle, 632 ps_quad_gradient: ShaderHandle, 633 #[allow(unused)] ps_quad_radial_gradient: ShaderHandle, 634 #[allow(unused)] ps_quad_conic_gradient: ShaderHandle, 635 ps_mask: ShaderHandle, 636 ps_mask_fast: ShaderHandle, 637 ps_clear: ShaderHandle, 638 ps_copy: ShaderHandle, 639 640 composite: CompositorShaders, 641 } 642 643 pub struct PendingShadersToPrecache { 644 precache_flags: ShaderPrecacheFlags, 645 remaining_shaders: VecDeque<ShaderHandle>, 646 } 647 648 impl Shaders { 649 pub fn new( 650 device: &mut Device, 651 gl_type: GlType, 652 options: &WebRenderOptions, 653 ) -> Result<Self, ShaderError> { 654 let use_dual_source_blending = 655 device.get_capabilities().supports_dual_source_blending && 656 options.allow_dual_source_blending; 657 let use_advanced_blend_equation = 658 device.get_capabilities().supports_advanced_blend_equation && 659 options.allow_advanced_blend_equation; 660 661 let texture_external_version = if device.get_capabilities().supports_image_external_essl3 { 662 TextureExternalVersion::ESSL3 663 } else { 664 TextureExternalVersion::ESSL1 665 }; 666 let mut shader_flags = get_shader_feature_flags(gl_type, texture_external_version, device); 667 shader_flags.set(ShaderFeatureFlags::ADVANCED_BLEND_EQUATION, use_advanced_blend_equation); 668 shader_flags.set(ShaderFeatureFlags::DUAL_SOURCE_BLENDING, use_dual_source_blending); 669 shader_flags.set(ShaderFeatureFlags::DITHERING, options.enable_dithering); 670 let shader_list = get_shader_features(shader_flags); 671 672 let mut loader = ShaderLoader::new(); 673 674 let brush_solid = BrushShader::new( 675 "brush_solid", 676 &[], 677 &shader_list, 678 false /* advanced blend */, 679 false /* dual source */, 680 &mut loader, 681 )?; 682 683 let brush_blend = BrushShader::new( 684 "brush_blend", 685 &[], 686 &shader_list, 687 false /* advanced blend */, 688 false /* dual source */, 689 &mut loader, 690 )?; 691 692 let brush_mix_blend = BrushShader::new( 693 "brush_mix_blend", 694 &[], 695 &shader_list, 696 false /* advanced blend */, 697 false /* dual source */, 698 &mut loader, 699 )?; 700 701 let brush_linear_gradient = BrushShader::new( 702 "brush_linear_gradient", 703 if options.enable_dithering { 704 &[DITHERING_FEATURE] 705 } else { 706 &[] 707 }, 708 &shader_list, 709 false /* advanced blend */, 710 false /* dual source */, 711 &mut loader, 712 )?; 713 714 let brush_opacity_aa = BrushShader::new( 715 "brush_opacity", 716 &["ANTIALIASING"], 717 &shader_list, 718 false /* advanced blend */, 719 false /* dual source */, 720 &mut loader, 721 )?; 722 723 let brush_opacity = BrushShader::new( 724 "brush_opacity", 725 &[], 726 &shader_list, 727 false /* advanced blend */, 728 false /* dual source */, 729 &mut loader, 730 )?; 731 732 let cs_blur_rgba8 = loader.create_shader( 733 ShaderKind::Cache(VertexArrayKind::Blur), 734 "cs_blur", 735 &["COLOR_TARGET"], 736 &shader_list, 737 )?; 738 739 let cs_svg_filter_node = loader.create_shader( 740 ShaderKind::Cache(VertexArrayKind::SvgFilterNode), 741 "cs_svg_filter_node", 742 &[], 743 &shader_list, 744 )?; 745 746 let ps_mask = loader.create_shader( 747 ShaderKind::Cache(VertexArrayKind::Mask), 748 "ps_quad_mask", 749 &[], 750 &shader_list, 751 )?; 752 753 let ps_mask_fast = loader.create_shader( 754 ShaderKind::Cache(VertexArrayKind::Mask), 755 "ps_quad_mask", 756 &[FAST_PATH_FEATURE], 757 &shader_list, 758 )?; 759 760 let cs_clip_rectangle_slow = loader.create_shader( 761 ShaderKind::ClipCache(VertexArrayKind::ClipRect), 762 "cs_clip_rectangle", 763 &[], 764 &shader_list, 765 )?; 766 767 let cs_clip_rectangle_fast = loader.create_shader( 768 ShaderKind::ClipCache(VertexArrayKind::ClipRect), 769 "cs_clip_rectangle", 770 &[FAST_PATH_FEATURE], 771 &shader_list, 772 )?; 773 774 let cs_clip_box_shadow = loader.create_shader( 775 ShaderKind::ClipCache(VertexArrayKind::ClipBoxShadow), 776 "cs_clip_box_shadow", 777 &["TEXTURE_2D"], 778 &shader_list, 779 )?; 780 781 let mut cs_scale = Vec::new(); 782 let scale_shader_num = IMAGE_BUFFER_KINDS.len(); 783 // PrimitiveShader is not clonable. Use push() to initialize the vec. 784 for _ in 0 .. scale_shader_num { 785 cs_scale.push(None); 786 } 787 for image_buffer_kind in &IMAGE_BUFFER_KINDS { 788 if has_platform_support(*image_buffer_kind, device) { 789 let feature_string = get_feature_string( 790 *image_buffer_kind, 791 texture_external_version, 792 ); 793 794 let mut features = Vec::new(); 795 if feature_string != "" { 796 features.push(feature_string); 797 } 798 799 let shader = loader.create_shader( 800 ShaderKind::Cache(VertexArrayKind::Scale), 801 "cs_scale", 802 &features, 803 &shader_list, 804 )?; 805 806 let index = Self::get_compositing_shader_index( 807 *image_buffer_kind, 808 ); 809 cs_scale[index] = Some(shader); 810 } 811 } 812 813 // TODO(gw): The split composite + text shader are special cases - the only 814 // shaders used during normal scene rendering that aren't a brush 815 // shader. Perhaps we can unify these in future? 816 817 let ps_text_run = TextShader::new("ps_text_run", 818 &[], 819 &shader_list, 820 &mut loader, 821 )?; 822 823 let ps_text_run_dual_source = if use_dual_source_blending { 824 let dual_source_features = vec![DUAL_SOURCE_FEATURE]; 825 Some(TextShader::new("ps_text_run", 826 &dual_source_features, 827 &shader_list, 828 &mut loader, 829 )?) 830 } else { 831 None 832 }; 833 834 let ps_quad_textured = loader.create_shader( 835 ShaderKind::Primitive, 836 "ps_quad_textured", 837 &[], 838 &shader_list, 839 )?; 840 841 let ps_quad_gradient = loader.create_shader( 842 ShaderKind::Primitive, 843 "ps_quad_gradient", 844 if options.enable_dithering { 845 &[DITHERING_FEATURE] 846 } else { 847 &[] 848 }, 849 &shader_list, 850 )?; 851 852 let ps_quad_radial_gradient = loader.create_shader( 853 ShaderKind::Primitive, 854 "ps_quad_radial_gradient", 855 if options.enable_dithering { 856 &[DITHERING_FEATURE] 857 } else { 858 &[] 859 }, 860 &shader_list, 861 )?; 862 863 let ps_quad_conic_gradient = loader.create_shader( 864 ShaderKind::Primitive, 865 "ps_quad_conic_gradient", 866 if options.enable_dithering { 867 &[DITHERING_FEATURE] 868 } else { 869 &[] 870 }, 871 &shader_list, 872 )?; 873 874 let ps_split_composite = loader.create_shader( 875 ShaderKind::Primitive, 876 "ps_split_composite", 877 &[], 878 &shader_list, 879 )?; 880 881 let ps_clear = loader.create_shader( 882 ShaderKind::Clear, 883 "ps_clear", 884 &[], 885 &shader_list, 886 )?; 887 888 let ps_copy = loader.create_shader( 889 ShaderKind::Copy, 890 "ps_copy", 891 &[], 892 &shader_list, 893 )?; 894 895 // All image configuration. 896 let mut image_features = Vec::new(); 897 let mut brush_image = Vec::new(); 898 let mut brush_fast_image = Vec::new(); 899 // PrimitiveShader is not clonable. Use push() to initialize the vec. 900 for _ in 0 .. IMAGE_BUFFER_KINDS.len() { 901 brush_image.push(None); 902 brush_fast_image.push(None); 903 } 904 for buffer_kind in 0 .. IMAGE_BUFFER_KINDS.len() { 905 if !has_platform_support(IMAGE_BUFFER_KINDS[buffer_kind], device) 906 // Brush shaders are not ESSL1 compatible 907 || (IMAGE_BUFFER_KINDS[buffer_kind] == ImageBufferKind::TextureExternal 908 && texture_external_version == TextureExternalVersion::ESSL1) 909 { 910 continue; 911 } 912 913 let feature_string = get_feature_string( 914 IMAGE_BUFFER_KINDS[buffer_kind], 915 texture_external_version, 916 ); 917 if feature_string != "" { 918 image_features.push(feature_string); 919 } 920 921 brush_fast_image[buffer_kind] = Some(BrushShader::new( 922 "brush_image", 923 &image_features, 924 &shader_list, 925 use_advanced_blend_equation, 926 use_dual_source_blending, 927 &mut loader, 928 )?); 929 930 image_features.push("REPETITION"); 931 image_features.push("ANTIALIASING"); 932 933 brush_image[buffer_kind] = Some(BrushShader::new( 934 "brush_image", 935 &image_features, 936 &shader_list, 937 use_advanced_blend_equation, 938 use_dual_source_blending, 939 &mut loader, 940 )?); 941 942 image_features.clear(); 943 } 944 945 // All yuv_image configuration. 946 let mut yuv_features = Vec::new(); 947 let mut rgba_features = Vec::new(); 948 let mut fast_path_features = Vec::new(); 949 let yuv_shader_num = IMAGE_BUFFER_KINDS.len(); 950 let mut brush_yuv_image = Vec::new(); 951 // PrimitiveShader is not clonable. Use push() to initialize the vec. 952 for _ in 0 .. yuv_shader_num { 953 brush_yuv_image.push(None); 954 } 955 for image_buffer_kind in &IMAGE_BUFFER_KINDS { 956 if has_platform_support(*image_buffer_kind, device) { 957 yuv_features.push("YUV"); 958 fast_path_features.push("FAST_PATH"); 959 960 let index = Self::get_compositing_shader_index( 961 *image_buffer_kind, 962 ); 963 964 let feature_string = get_feature_string( 965 *image_buffer_kind, 966 texture_external_version, 967 ); 968 if feature_string != "" { 969 yuv_features.push(feature_string); 970 rgba_features.push(feature_string); 971 fast_path_features.push(feature_string); 972 } 973 974 // YUV shaders are not compatible with ESSL1 975 if *image_buffer_kind != ImageBufferKind::TextureExternal || 976 texture_external_version == TextureExternalVersion::ESSL3 { 977 let brush_shader = BrushShader::new( 978 "brush_yuv_image", 979 &yuv_features, 980 &shader_list, 981 false /* advanced blend */, 982 false /* dual source */, 983 &mut loader, 984 )?; 985 brush_yuv_image[index] = Some(brush_shader); 986 } 987 988 yuv_features.clear(); 989 rgba_features.clear(); 990 fast_path_features.clear(); 991 } 992 } 993 994 let cs_line_decoration = loader.create_shader( 995 ShaderKind::Cache(VertexArrayKind::LineDecoration), 996 "cs_line_decoration", 997 &[], 998 &shader_list, 999 )?; 1000 1001 let cs_fast_linear_gradient = loader.create_shader( 1002 ShaderKind::Cache(VertexArrayKind::FastLinearGradient), 1003 "cs_fast_linear_gradient", 1004 &[], 1005 &shader_list, 1006 )?; 1007 1008 let cs_linear_gradient = loader.create_shader( 1009 ShaderKind::Cache(VertexArrayKind::LinearGradient), 1010 "cs_linear_gradient", 1011 if options.enable_dithering { 1012 &[DITHERING_FEATURE] 1013 } else { 1014 &[] 1015 }, 1016 &shader_list, 1017 )?; 1018 1019 let cs_radial_gradient = loader.create_shader( 1020 ShaderKind::Cache(VertexArrayKind::RadialGradient), 1021 "cs_radial_gradient", 1022 if options.enable_dithering { 1023 &[DITHERING_FEATURE] 1024 } else { 1025 &[] 1026 }, 1027 &shader_list, 1028 )?; 1029 1030 let cs_conic_gradient = loader.create_shader( 1031 ShaderKind::Cache(VertexArrayKind::ConicGradient), 1032 "cs_conic_gradient", 1033 if options.enable_dithering { 1034 &[DITHERING_FEATURE] 1035 } else { 1036 &[] 1037 }, 1038 &shader_list, 1039 )?; 1040 1041 let cs_border_segment = loader.create_shader( 1042 ShaderKind::Cache(VertexArrayKind::Border), 1043 "cs_border_segment", 1044 &[], 1045 &shader_list, 1046 )?; 1047 1048 let cs_border_solid = loader.create_shader( 1049 ShaderKind::Cache(VertexArrayKind::Border), 1050 "cs_border_solid", 1051 &[], 1052 &shader_list, 1053 )?; 1054 1055 let composite = CompositorShaders::new(device, gl_type, &mut loader)?; 1056 1057 Ok(Shaders { 1058 loader, 1059 1060 cs_blur_rgba8, 1061 cs_border_segment, 1062 cs_line_decoration, 1063 cs_fast_linear_gradient, 1064 cs_linear_gradient, 1065 cs_radial_gradient, 1066 cs_conic_gradient, 1067 cs_border_solid, 1068 cs_scale, 1069 cs_svg_filter_node, 1070 brush_solid, 1071 brush_image, 1072 brush_fast_image, 1073 brush_blend, 1074 brush_mix_blend, 1075 brush_yuv_image, 1076 brush_linear_gradient, 1077 brush_opacity, 1078 brush_opacity_aa, 1079 cs_clip_rectangle_slow, 1080 cs_clip_rectangle_fast, 1081 cs_clip_box_shadow, 1082 ps_text_run, 1083 ps_text_run_dual_source, 1084 ps_quad_textured, 1085 ps_quad_gradient, 1086 ps_quad_radial_gradient, 1087 ps_quad_conic_gradient, 1088 ps_mask, 1089 ps_mask_fast, 1090 ps_split_composite, 1091 ps_clear, 1092 ps_copy, 1093 composite, 1094 }) 1095 } 1096 1097 #[must_use] 1098 pub fn precache_all( 1099 &mut self, 1100 precache_flags: ShaderPrecacheFlags, 1101 ) -> PendingShadersToPrecache { 1102 PendingShadersToPrecache { 1103 precache_flags, 1104 remaining_shaders: self.loader.all_handles().into(), 1105 } 1106 } 1107 1108 /// Returns true if another call is needed, false if precaching is finished. 1109 pub fn resume_precache( 1110 &mut self, 1111 device: &mut Device, 1112 pending_shaders: &mut PendingShadersToPrecache, 1113 ) -> Result<bool, ShaderError> { 1114 let Some(next_shader) = pending_shaders.remaining_shaders.pop_front() else { 1115 return Ok(false) 1116 }; 1117 1118 self.loader.precache(next_shader, device, pending_shaders.precache_flags)?; 1119 Ok(true) 1120 } 1121 1122 fn get_compositing_shader_index(buffer_kind: ImageBufferKind) -> usize { 1123 buffer_kind as usize 1124 } 1125 1126 pub fn get_composite_shader( 1127 &mut self, 1128 format: CompositeSurfaceFormat, 1129 buffer_kind: ImageBufferKind, 1130 features: CompositeFeatures, 1131 ) -> &mut LazilyCompiledShader { 1132 let shader_handle = self.composite.get_handle(format, buffer_kind, features); 1133 self.loader.get(shader_handle) 1134 } 1135 1136 pub fn get_scale_shader( 1137 &mut self, 1138 buffer_kind: ImageBufferKind, 1139 ) -> &mut LazilyCompiledShader { 1140 let shader_index = Self::get_compositing_shader_index(buffer_kind); 1141 let shader_handle = self.cs_scale[shader_index] 1142 .expect("bug: unsupported scale shader requested"); 1143 self.loader.get(shader_handle) 1144 } 1145 1146 pub fn get_quad_shader( 1147 &mut self, 1148 pattern: PatternKind 1149 ) -> &mut LazilyCompiledShader { 1150 let shader_handle = match pattern { 1151 PatternKind::ColorOrTexture => self.ps_quad_textured, 1152 PatternKind::RadialGradient => self.ps_quad_radial_gradient, 1153 PatternKind::ConicGradient => self.ps_quad_conic_gradient, 1154 PatternKind::Gradient => self.ps_quad_gradient, 1155 PatternKind::Mask => unreachable!(), 1156 }; 1157 self.loader.get(shader_handle) 1158 } 1159 1160 pub fn get( 1161 &mut self, 1162 key: &BatchKey, 1163 features: BatchFeatures, 1164 debug_flags: DebugFlags, 1165 device: &Device, 1166 ) -> &mut LazilyCompiledShader { 1167 let shader_handle = self.get_handle(key, features, debug_flags, device); 1168 self.loader.get(shader_handle) 1169 } 1170 1171 pub fn get_handle( 1172 &mut self, 1173 key: &BatchKey, 1174 mut features: BatchFeatures, 1175 debug_flags: DebugFlags, 1176 device: &Device, 1177 ) -> ShaderHandle { 1178 match key.kind { 1179 BatchKind::Quad(PatternKind::ColorOrTexture) => { 1180 self.ps_quad_textured 1181 } 1182 BatchKind::Quad(PatternKind::RadialGradient) => { 1183 self.ps_quad_radial_gradient 1184 } 1185 BatchKind::Quad(PatternKind::ConicGradient) => { 1186 self.ps_quad_conic_gradient 1187 } 1188 BatchKind::Quad(PatternKind::Gradient) => { 1189 self.ps_quad_gradient 1190 } 1191 BatchKind::Quad(PatternKind::Mask) => { 1192 unreachable!(); 1193 } 1194 BatchKind::SplitComposite => { 1195 self.ps_split_composite 1196 } 1197 BatchKind::Brush(brush_kind) => { 1198 // SWGL uses a native anti-aliasing implementation that bypasses the shader. 1199 // Don't consider it in that case when deciding whether or not to use 1200 // an alpha-pass shader. 1201 if device.get_capabilities().uses_native_antialiasing { 1202 features.remove(BatchFeatures::ANTIALIASING); 1203 } 1204 let brush_shader = match brush_kind { 1205 BrushBatchKind::Solid => { 1206 &mut self.brush_solid 1207 } 1208 BrushBatchKind::Image(image_buffer_kind) => { 1209 if features.contains(BatchFeatures::ANTIALIASING) || 1210 features.contains(BatchFeatures::REPETITION) { 1211 1212 self.brush_image[image_buffer_kind as usize] 1213 .as_mut() 1214 .expect("Unsupported image shader kind") 1215 } else { 1216 self.brush_fast_image[image_buffer_kind as usize] 1217 .as_mut() 1218 .expect("Unsupported image shader kind") 1219 } 1220 } 1221 BrushBatchKind::Blend => { 1222 &mut self.brush_blend 1223 } 1224 BrushBatchKind::MixBlend { .. } => { 1225 &mut self.brush_mix_blend 1226 } 1227 BrushBatchKind::LinearGradient => { 1228 // SWGL uses a native clip mask implementation that bypasses the shader. 1229 // Don't consider it in that case when deciding whether or not to use 1230 // an alpha-pass shader. 1231 if device.get_capabilities().uses_native_clip_mask { 1232 features.remove(BatchFeatures::CLIP_MASK); 1233 } 1234 // Gradient brushes can optimistically use the opaque shader even 1235 // with a blend mode if they don't require any features. 1236 if !features.intersects( 1237 BatchFeatures::ANTIALIASING 1238 | BatchFeatures::REPETITION 1239 | BatchFeatures::CLIP_MASK, 1240 ) { 1241 features.remove(BatchFeatures::ALPHA_PASS); 1242 } 1243 match brush_kind { 1244 BrushBatchKind::LinearGradient => &mut self.brush_linear_gradient, 1245 _ => panic!(), 1246 } 1247 } 1248 BrushBatchKind::YuvImage(image_buffer_kind, ..) => { 1249 let shader_index = 1250 Self::get_compositing_shader_index(image_buffer_kind); 1251 self.brush_yuv_image[shader_index] 1252 .as_mut() 1253 .expect("Unsupported YUV shader kind") 1254 } 1255 BrushBatchKind::Opacity => { 1256 if features.contains(BatchFeatures::ANTIALIASING) { 1257 &mut self.brush_opacity_aa 1258 } else { 1259 &mut self.brush_opacity 1260 } 1261 } 1262 }; 1263 brush_shader.get_handle(key.blend_mode, features, debug_flags) 1264 } 1265 BatchKind::TextRun(glyph_format) => { 1266 let text_shader = match key.blend_mode { 1267 BlendMode::SubpixelDualSource => self.ps_text_run_dual_source.as_mut().unwrap(), 1268 _ => &mut self.ps_text_run, 1269 }; 1270 text_shader.get_handle(glyph_format, debug_flags) 1271 } 1272 } 1273 } 1274 1275 pub fn cs_blur_rgba8(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_blur_rgba8) } 1276 pub fn cs_border_segment(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_segment) } 1277 pub fn cs_border_solid(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_solid) } 1278 pub fn cs_line_decoration(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_line_decoration) } 1279 pub fn cs_fast_linear_gradient(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_fast_linear_gradient) } 1280 pub fn cs_linear_gradient(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_linear_gradient) } 1281 pub fn cs_radial_gradient(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_radial_gradient) } 1282 pub fn cs_conic_gradient(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_conic_gradient) } 1283 pub fn cs_svg_filter_node(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_svg_filter_node) } 1284 pub fn cs_clip_rectangle_slow(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_clip_rectangle_slow) } 1285 pub fn cs_clip_rectangle_fast(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_clip_rectangle_fast) } 1286 pub fn cs_clip_box_shadow(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_clip_box_shadow) } 1287 pub fn ps_quad_textured(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_quad_textured) } 1288 pub fn ps_mask(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_mask) } 1289 pub fn ps_mask_fast(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_mask_fast) } 1290 pub fn ps_clear(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_clear) } 1291 pub fn ps_copy(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_copy) } 1292 1293 pub fn deinit(self, device: &mut Device) { 1294 self.loader.deinit(device); 1295 } 1296 } 1297 1298 pub type SharedShaders = Rc<RefCell<Shaders>>; 1299 1300 pub struct CompositorShaders { 1301 // Composite shaders. These are very simple shaders used to composite 1302 // picture cache tiles into the framebuffer on platforms that do not have an 1303 // OS Compositor (or we cannot use it). Such an OS Compositor (such as 1304 // DirectComposite or CoreAnimation) handles the composition of the picture 1305 // cache tiles at a lower level (e.g. in DWM for Windows); in that case we 1306 // directly hand the picture cache surfaces over to the OS Compositor, and 1307 // our own Composite shaders below never run. 1308 // To composite external (RGB) surfaces we need various permutations of 1309 // shaders with WR_FEATURE flags on or off based on the type of image 1310 // buffer we're sourcing from (see IMAGE_BUFFER_KINDS). 1311 rgba: Vec<Option<ShaderHandle>>, 1312 // A faster set of rgba composite shaders that do not support UV clamping 1313 // or color modulation. 1314 rgba_fast_path: Vec<Option<ShaderHandle>>, 1315 // The same set of composite shaders but with WR_FEATURE_YUV added. 1316 yuv_clip: Vec<Option<ShaderHandle>>, 1317 yuv_fast: Vec<Option<ShaderHandle>>, 1318 } 1319 1320 impl CompositorShaders { 1321 pub fn new( 1322 device: &mut Device, 1323 gl_type: GlType, 1324 loader: &mut ShaderLoader, 1325 ) -> Result<Self, ShaderError> { 1326 let mut yuv_clip_features = Vec::new(); 1327 let mut yuv_fast_features = Vec::new(); 1328 let mut rgba_features = Vec::new(); 1329 let mut fast_path_features = Vec::new(); 1330 let mut rgba = Vec::new(); 1331 let mut rgba_fast_path = Vec::new(); 1332 let mut yuv_clip = Vec::new(); 1333 let mut yuv_fast = Vec::new(); 1334 1335 let texture_external_version = if device.get_capabilities().supports_image_external_essl3 { 1336 TextureExternalVersion::ESSL3 1337 } else { 1338 TextureExternalVersion::ESSL1 1339 }; 1340 1341 let feature_flags = get_shader_feature_flags(gl_type, texture_external_version, device); 1342 let shader_list = get_shader_features(feature_flags); 1343 1344 for _ in 0..IMAGE_BUFFER_KINDS.len() { 1345 yuv_clip.push(None); 1346 yuv_fast.push(None); 1347 rgba.push(None); 1348 rgba_fast_path.push(None); 1349 } 1350 1351 for image_buffer_kind in &IMAGE_BUFFER_KINDS { 1352 if !has_platform_support(*image_buffer_kind, device) { 1353 continue; 1354 } 1355 1356 yuv_clip_features.push("YUV"); 1357 yuv_fast_features.push("YUV"); 1358 yuv_fast_features.push("FAST_PATH"); 1359 fast_path_features.push("FAST_PATH"); 1360 1361 let index = Self::get_shader_index(*image_buffer_kind); 1362 1363 let feature_string = get_feature_string( 1364 *image_buffer_kind, 1365 texture_external_version, 1366 ); 1367 if feature_string != "" { 1368 yuv_clip_features.push(feature_string); 1369 yuv_fast_features.push(feature_string); 1370 rgba_features.push(feature_string); 1371 fast_path_features.push(feature_string); 1372 } 1373 1374 // YUV shaders are not compatible with ESSL1 1375 if *image_buffer_kind != ImageBufferKind::TextureExternal || 1376 texture_external_version == TextureExternalVersion::ESSL3 { 1377 1378 yuv_clip[index] = Some(loader.create_shader( 1379 ShaderKind::Composite, 1380 "composite", 1381 &yuv_clip_features, 1382 &shader_list, 1383 )?); 1384 1385 yuv_fast[index] = Some(loader.create_shader( 1386 ShaderKind::Composite, 1387 "composite", 1388 &yuv_fast_features, 1389 &shader_list, 1390 )?); 1391 } 1392 1393 rgba[index] = Some(loader.create_shader( 1394 ShaderKind::Composite, 1395 "composite", 1396 &rgba_features, 1397 &shader_list, 1398 )?); 1399 1400 rgba_fast_path[index] = Some(loader.create_shader( 1401 ShaderKind::Composite, 1402 "composite", 1403 &fast_path_features, 1404 &shader_list, 1405 )?); 1406 1407 yuv_fast_features.clear(); 1408 yuv_clip_features.clear(); 1409 rgba_features.clear(); 1410 fast_path_features.clear(); 1411 } 1412 1413 Ok(CompositorShaders { 1414 rgba, 1415 rgba_fast_path, 1416 yuv_clip, 1417 yuv_fast, 1418 }) 1419 } 1420 1421 pub fn get_handle( 1422 &mut self, 1423 format: CompositeSurfaceFormat, 1424 buffer_kind: ImageBufferKind, 1425 features: CompositeFeatures, 1426 ) -> ShaderHandle { 1427 match format { 1428 CompositeSurfaceFormat::Rgba => { 1429 if features.contains(CompositeFeatures::NO_UV_CLAMP) 1430 && features.contains(CompositeFeatures::NO_COLOR_MODULATION) 1431 && features.contains(CompositeFeatures::NO_CLIP_MASK) 1432 { 1433 let shader_index = Self::get_shader_index(buffer_kind); 1434 self.rgba_fast_path[shader_index] 1435 .expect("bug: unsupported rgba fast path shader requested") 1436 } else { 1437 let shader_index = Self::get_shader_index(buffer_kind); 1438 self.rgba[shader_index] 1439 .expect("bug: unsupported rgba shader requested") 1440 } 1441 } 1442 CompositeSurfaceFormat::Yuv => { 1443 let shader_index = Self::get_shader_index(buffer_kind); 1444 if features.contains(CompositeFeatures::NO_CLIP_MASK) { 1445 self.yuv_fast[shader_index] 1446 .expect("bug: unsupported yuv shader requested") 1447 } else { 1448 self.yuv_clip[shader_index] 1449 .expect("bug: unsupported yuv shader requested") 1450 } 1451 } 1452 } 1453 } 1454 1455 fn get_shader_index(buffer_kind: ImageBufferKind) -> usize { 1456 buffer_kind as usize 1457 } 1458 } 1459 1460 fn get_shader_feature_flags( 1461 gl_type: GlType, 1462 texture_external_version: TextureExternalVersion, 1463 device: &Device 1464 ) -> ShaderFeatureFlags { 1465 match gl_type { 1466 GlType::Gl => ShaderFeatureFlags::GL, 1467 GlType::Gles => { 1468 let mut flags = ShaderFeatureFlags::GLES; 1469 flags |= match texture_external_version { 1470 TextureExternalVersion::ESSL3 => ShaderFeatureFlags::TEXTURE_EXTERNAL, 1471 TextureExternalVersion::ESSL1 => ShaderFeatureFlags::TEXTURE_EXTERNAL_ESSL1, 1472 }; 1473 if device.supports_extension("GL_EXT_YUV_target") { 1474 flags |= ShaderFeatureFlags::TEXTURE_EXTERNAL_BT709; 1475 } 1476 flags 1477 } 1478 } 1479 }