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 euclid::default::Transform3D;
10 use crate::glyph_rasterizer::GlyphFormat;
11 use crate::renderer::{
12 desc,
13 BlendMode, DebugFlags, RendererError, RendererOptions,
14 TextureSampler, VertexArrayKind, ShaderPrecacheFlags,
15 };
16
17 use gleam::gl::GlType;
18 use time::precise_time_ns;
19
20 use std::cell::RefCell;
21 use std::rc::Rc;
22
23 use webrender_build::shader::{ShaderFeatures, ShaderFeatureFlags, get_shader_features};
24
25 /// Which extension version to use for texture external support.
26 #[derive(Clone, Copy, Debug, PartialEq)]
27 enum TextureExternalVersion {
28 // GL_OES_EGL_image_external_essl3 (Compatible with ESSL 3.0 and
29 // later shaders, but not supported on all GLES 3 devices.)
30 ESSL3,
31 // GL_OES_EGL_image_external (Compatible with ESSL 1.0 shaders)
32 ESSL1,
33 }
34
get_feature_string(kind: ImageBufferKind, texture_external_version: TextureExternalVersion) -> &'static str35 fn get_feature_string(kind: ImageBufferKind, texture_external_version: TextureExternalVersion) -> &'static str {
36 match (kind, texture_external_version) {
37 (ImageBufferKind::Texture2D, _) => "TEXTURE_2D",
38 (ImageBufferKind::TextureRect, _) => "TEXTURE_RECT",
39 (ImageBufferKind::TextureExternal, TextureExternalVersion::ESSL3) => "TEXTURE_EXTERNAL",
40 (ImageBufferKind::TextureExternal, TextureExternalVersion::ESSL1) => "TEXTURE_EXTERNAL_ESSL1",
41 }
42 }
43
has_platform_support(kind: ImageBufferKind, gl_type: &GlType) -> bool44 fn has_platform_support(kind: ImageBufferKind, gl_type: &GlType) -> bool {
45 match (kind, gl_type) {
46 (ImageBufferKind::Texture2D, _) => true,
47 (ImageBufferKind::TextureRect, &GlType::Gles) => false,
48 (ImageBufferKind::TextureRect, &GlType::Gl) => true,
49 (ImageBufferKind::TextureExternal, &GlType::Gles) => true,
50 (ImageBufferKind::TextureExternal, &GlType::Gl) => false,
51 }
52 }
53
54 pub const IMAGE_BUFFER_KINDS: [ImageBufferKind; 3] = [
55 ImageBufferKind::Texture2D,
56 ImageBufferKind::TextureRect,
57 ImageBufferKind::TextureExternal,
58 ];
59
60 const ADVANCED_BLEND_FEATURE: &str = "ADVANCED_BLEND";
61 const ALPHA_FEATURE: &str = "ALPHA_PASS";
62 const DEBUG_OVERDRAW_FEATURE: &str = "DEBUG_OVERDRAW";
63 const DITHERING_FEATURE: &str = "DITHERING";
64 const DUAL_SOURCE_FEATURE: &str = "DUAL_SOURCE_BLENDING";
65 const FAST_PATH_FEATURE: &str = "FAST_PATH";
66
67 pub(crate) enum ShaderKind {
68 Primitive,
69 Cache(VertexArrayKind),
70 ClipCache(VertexArrayKind),
71 Brush,
72 Text,
73 #[allow(dead_code)]
74 VectorStencil,
75 #[allow(dead_code)]
76 VectorCover,
77 #[allow(dead_code)]
78 Resolve,
79 Composite,
80 Clear,
81 }
82
83 pub struct LazilyCompiledShader {
84 program: Option<Program>,
85 name: &'static str,
86 kind: ShaderKind,
87 cached_projection: Transform3D<f32>,
88 features: Vec<&'static str>,
89 }
90
91 impl LazilyCompiledShader {
new( kind: ShaderKind, name: &'static str, unsorted_features: &[&'static str], device: &mut Device, precache_flags: ShaderPrecacheFlags, shader_list: &ShaderFeatures, ) -> Result<Self, ShaderError>92 pub(crate) fn new(
93 kind: ShaderKind,
94 name: &'static str,
95 unsorted_features: &[&'static str],
96 device: &mut Device,
97 precache_flags: ShaderPrecacheFlags,
98 shader_list: &ShaderFeatures,
99 ) -> Result<Self, ShaderError> {
100 let mut features = unsorted_features.to_vec();
101 features.sort();
102
103 // Ensure this shader config is in the available shader list so that we get
104 // alerted if the list gets out-of-date when shaders or features are added.
105 let config = features.join(",");
106 assert!(
107 shader_list.get(name).map_or(false, |f| f.contains(&config)),
108 "shader \"{}\" with features \"{}\" not in available shader list",
109 name,
110 config,
111 );
112
113 let mut shader = LazilyCompiledShader {
114 program: None,
115 name,
116 kind,
117 //Note: this isn't really the default state, but there is no chance
118 // an actual projection passed here would accidentally match.
119 cached_projection: Transform3D::identity(),
120 features,
121 };
122
123 if precache_flags.intersects(ShaderPrecacheFlags::ASYNC_COMPILE | ShaderPrecacheFlags::FULL_COMPILE) {
124 let t0 = precise_time_ns();
125 shader.get_internal(device, precache_flags)?;
126 let t1 = precise_time_ns();
127 debug!("[C: {:.1} ms ] Precache {} {:?}",
128 (t1 - t0) as f64 / 1000000.0,
129 name,
130 unsorted_features
131 );
132 }
133
134 Ok(shader)
135 }
136
bind( &mut self, device: &mut Device, projection: &Transform3D<f32>, texture_size: Option<DeviceSize>, renderer_errors: &mut Vec<RendererError>, )137 pub fn bind(
138 &mut self,
139 device: &mut Device,
140 projection: &Transform3D<f32>,
141 texture_size: Option<DeviceSize>,
142 renderer_errors: &mut Vec<RendererError>,
143 ) {
144 let update_projection = self.cached_projection != *projection;
145 let program = match self.get_internal(device, ShaderPrecacheFlags::FULL_COMPILE) {
146 Ok(program) => program,
147 Err(e) => {
148 renderer_errors.push(RendererError::from(e));
149 return;
150 }
151 };
152 device.bind_program(program);
153 if let Some(texture_size) = texture_size {
154 device.set_shader_texture_size(program, texture_size);
155 }
156 if update_projection {
157 device.set_uniforms(program, projection);
158 // thanks NLL for this (`program` technically borrows `self`)
159 self.cached_projection = *projection;
160 }
161 }
162
get_internal( &mut self, device: &mut Device, precache_flags: ShaderPrecacheFlags, ) -> Result<&mut Program, ShaderError>163 fn get_internal(
164 &mut self,
165 device: &mut Device,
166 precache_flags: ShaderPrecacheFlags,
167 ) -> Result<&mut Program, ShaderError> {
168 if self.program.is_none() {
169 let program = match self.kind {
170 ShaderKind::Primitive | ShaderKind::Brush | ShaderKind::Text | ShaderKind::Resolve | ShaderKind::Clear => {
171 create_prim_shader(
172 self.name,
173 device,
174 &self.features,
175 )
176 }
177 ShaderKind::Cache(..) => {
178 create_prim_shader(
179 self.name,
180 device,
181 &self.features,
182 )
183 }
184 ShaderKind::VectorStencil => {
185 create_prim_shader(
186 self.name,
187 device,
188 &self.features,
189 )
190 }
191 ShaderKind::VectorCover => {
192 create_prim_shader(
193 self.name,
194 device,
195 &self.features,
196 )
197 }
198 ShaderKind::Composite => {
199 create_prim_shader(
200 self.name,
201 device,
202 &self.features,
203 )
204 }
205 ShaderKind::ClipCache(..) => {
206 create_clip_shader(
207 self.name,
208 device,
209 &self.features,
210 )
211 }
212 };
213 self.program = Some(program?);
214 }
215
216 let program = self.program.as_mut().unwrap();
217
218 if precache_flags.contains(ShaderPrecacheFlags::FULL_COMPILE) && !program.is_initialized() {
219 let vertex_format = match self.kind {
220 ShaderKind::Primitive |
221 ShaderKind::Brush |
222 ShaderKind::Text => VertexArrayKind::Primitive,
223 ShaderKind::Cache(format) => format,
224 ShaderKind::VectorStencil => VertexArrayKind::VectorStencil,
225 ShaderKind::VectorCover => VertexArrayKind::VectorCover,
226 ShaderKind::ClipCache(format) => format,
227 ShaderKind::Resolve => VertexArrayKind::Resolve,
228 ShaderKind::Composite => VertexArrayKind::Composite,
229 ShaderKind::Clear => VertexArrayKind::Clear,
230 };
231
232 let vertex_descriptor = match vertex_format {
233 VertexArrayKind::Primitive => &desc::PRIM_INSTANCES,
234 VertexArrayKind::LineDecoration => &desc::LINE,
235 VertexArrayKind::FastLinearGradient => &desc::FAST_LINEAR_GRADIENT,
236 VertexArrayKind::LinearGradient => &desc::LINEAR_GRADIENT,
237 VertexArrayKind::RadialGradient => &desc::RADIAL_GRADIENT,
238 VertexArrayKind::ConicGradient => &desc::CONIC_GRADIENT,
239 VertexArrayKind::Blur => &desc::BLUR,
240 VertexArrayKind::ClipImage => &desc::CLIP_IMAGE,
241 VertexArrayKind::ClipRect => &desc::CLIP_RECT,
242 VertexArrayKind::ClipBoxShadow => &desc::CLIP_BOX_SHADOW,
243 VertexArrayKind::VectorStencil => &desc::VECTOR_STENCIL,
244 VertexArrayKind::VectorCover => &desc::VECTOR_COVER,
245 VertexArrayKind::Border => &desc::BORDER,
246 VertexArrayKind::Scale => &desc::SCALE,
247 VertexArrayKind::Resolve => &desc::RESOLVE,
248 VertexArrayKind::SvgFilter => &desc::SVG_FILTER,
249 VertexArrayKind::Composite => &desc::COMPOSITE,
250 VertexArrayKind::Clear => &desc::CLEAR,
251 };
252
253 device.link_program(program, vertex_descriptor)?;
254 device.bind_program(program);
255 match self.kind {
256 ShaderKind::ClipCache(..) => {
257 device.bind_shader_samplers(
258 &program,
259 &[
260 ("sColor0", TextureSampler::Color0),
261 ("sTransformPalette", TextureSampler::TransformPalette),
262 ("sRenderTasks", TextureSampler::RenderTasks),
263 ("sGpuCache", TextureSampler::GpuCache),
264 ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF),
265 ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI),
266 ],
267 );
268 }
269 _ => {
270 device.bind_shader_samplers(
271 &program,
272 &[
273 ("sColor0", TextureSampler::Color0),
274 ("sColor1", TextureSampler::Color1),
275 ("sColor2", TextureSampler::Color2),
276 ("sDither", TextureSampler::Dither),
277 ("sTransformPalette", TextureSampler::TransformPalette),
278 ("sRenderTasks", TextureSampler::RenderTasks),
279 ("sGpuCache", TextureSampler::GpuCache),
280 ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF),
281 ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI),
282 ("sClipMask", TextureSampler::ClipMask),
283 ],
284 );
285 }
286 }
287 }
288
289 Ok(program)
290 }
291
deinit(self, device: &mut Device)292 fn deinit(self, device: &mut Device) {
293 if let Some(program) = self.program {
294 device.delete_program(program);
295 }
296 }
297 }
298
299 // A brush shader supports two modes:
300 // opaque:
301 // Used for completely opaque primitives,
302 // or inside segments of partially
303 // opaque primitives. Assumes no need
304 // for clip masks, AA etc.
305 // alpha:
306 // Used for brush primitives in the alpha
307 // pass. Assumes that AA should be applied
308 // along the primitive edge, and also that
309 // clip mask is present.
310 struct BrushShader {
311 opaque: LazilyCompiledShader,
312 alpha: LazilyCompiledShader,
313 advanced_blend: Option<LazilyCompiledShader>,
314 dual_source: Option<LazilyCompiledShader>,
315 debug_overdraw: LazilyCompiledShader,
316 }
317
318 impl BrushShader {
new( name: &'static str, device: &mut Device, features: &[&'static str], precache_flags: ShaderPrecacheFlags, shader_list: &ShaderFeatures, use_advanced_blend: bool, use_dual_source: bool, ) -> Result<Self, ShaderError>319 fn new(
320 name: &'static str,
321 device: &mut Device,
322 features: &[&'static str],
323 precache_flags: ShaderPrecacheFlags,
324 shader_list: &ShaderFeatures,
325 use_advanced_blend: bool,
326 use_dual_source: bool,
327 ) -> Result<Self, ShaderError> {
328 let opaque_features = features.to_vec();
329 let opaque = LazilyCompiledShader::new(
330 ShaderKind::Brush,
331 name,
332 &opaque_features,
333 device,
334 precache_flags,
335 &shader_list,
336 )?;
337
338 let mut alpha_features = opaque_features.to_vec();
339 alpha_features.push(ALPHA_FEATURE);
340
341 let alpha = LazilyCompiledShader::new(
342 ShaderKind::Brush,
343 name,
344 &alpha_features,
345 device,
346 precache_flags,
347 &shader_list,
348 )?;
349
350 let advanced_blend = if use_advanced_blend {
351 let mut advanced_blend_features = alpha_features.to_vec();
352 advanced_blend_features.push(ADVANCED_BLEND_FEATURE);
353
354 let shader = LazilyCompiledShader::new(
355 ShaderKind::Brush,
356 name,
357 &advanced_blend_features,
358 device,
359 precache_flags,
360 &shader_list,
361 )?;
362
363 Some(shader)
364 } else {
365 None
366 };
367
368 let dual_source = if use_dual_source {
369 let mut dual_source_features = alpha_features.to_vec();
370 dual_source_features.push(DUAL_SOURCE_FEATURE);
371
372 let shader = LazilyCompiledShader::new(
373 ShaderKind::Brush,
374 name,
375 &dual_source_features,
376 device,
377 precache_flags,
378 &shader_list,
379 )?;
380
381 Some(shader)
382 } else {
383 None
384 };
385
386 let mut debug_overdraw_features = features.to_vec();
387 debug_overdraw_features.push(DEBUG_OVERDRAW_FEATURE);
388
389 let debug_overdraw = LazilyCompiledShader::new(
390 ShaderKind::Brush,
391 name,
392 &debug_overdraw_features,
393 device,
394 precache_flags,
395 &shader_list,
396 )?;
397
398 Ok(BrushShader {
399 opaque,
400 alpha,
401 advanced_blend,
402 dual_source,
403 debug_overdraw,
404 })
405 }
406
get(&mut self, blend_mode: BlendMode, features: BatchFeatures, debug_flags: DebugFlags) -> &mut LazilyCompiledShader407 fn get(&mut self, blend_mode: BlendMode, features: BatchFeatures, debug_flags: DebugFlags)
408 -> &mut LazilyCompiledShader {
409 match blend_mode {
410 _ if debug_flags.contains(DebugFlags::SHOW_OVERDRAW) => &mut self.debug_overdraw,
411 BlendMode::None => &mut self.opaque,
412 BlendMode::Alpha |
413 BlendMode::PremultipliedAlpha |
414 BlendMode::PremultipliedDestOut |
415 BlendMode::SubpixelConstantTextColor(..) |
416 BlendMode::SubpixelWithBgColor |
417 BlendMode::Screen |
418 BlendMode::Exclusion => {
419 if features.contains(BatchFeatures::ALPHA_PASS) {
420 &mut self.alpha
421 } else {
422 &mut self.opaque
423 }
424 }
425 BlendMode::Advanced(_) => {
426 self.advanced_blend
427 .as_mut()
428 .expect("bug: no advanced blend shader loaded")
429 }
430 BlendMode::SubpixelDualSource |
431 BlendMode::MultiplyDualSource => {
432 self.dual_source
433 .as_mut()
434 .expect("bug: no dual source shader loaded")
435 }
436 }
437 }
438
deinit(self, device: &mut Device)439 fn deinit(self, device: &mut Device) {
440 self.opaque.deinit(device);
441 self.alpha.deinit(device);
442 if let Some(advanced_blend) = self.advanced_blend {
443 advanced_blend.deinit(device);
444 }
445 if let Some(dual_source) = self.dual_source {
446 dual_source.deinit(device);
447 }
448 self.debug_overdraw.deinit(device);
449 }
450 }
451
452 pub struct TextShader {
453 simple: LazilyCompiledShader,
454 glyph_transform: LazilyCompiledShader,
455 debug_overdraw: LazilyCompiledShader,
456 }
457
458 impl TextShader {
new( name: &'static str, device: &mut Device, features: &[&'static str], precache_flags: ShaderPrecacheFlags, shader_list: &ShaderFeatures, ) -> Result<Self, ShaderError>459 fn new(
460 name: &'static str,
461 device: &mut Device,
462 features: &[&'static str],
463 precache_flags: ShaderPrecacheFlags,
464 shader_list: &ShaderFeatures,
465 ) -> Result<Self, ShaderError> {
466 let mut simple_features = features.to_vec();
467 simple_features.push("ALPHA_PASS");
468 simple_features.push("TEXTURE_2D");
469
470 let simple = LazilyCompiledShader::new(
471 ShaderKind::Text,
472 name,
473 &simple_features,
474 device,
475 precache_flags,
476 &shader_list,
477 )?;
478
479 let mut glyph_transform_features = features.to_vec();
480 glyph_transform_features.push("GLYPH_TRANSFORM");
481 glyph_transform_features.push("ALPHA_PASS");
482 glyph_transform_features.push("TEXTURE_2D");
483
484 let glyph_transform = LazilyCompiledShader::new(
485 ShaderKind::Text,
486 name,
487 &glyph_transform_features,
488 device,
489 precache_flags,
490 &shader_list,
491 )?;
492
493 let mut debug_overdraw_features = features.to_vec();
494 debug_overdraw_features.push("DEBUG_OVERDRAW");
495 debug_overdraw_features.push("TEXTURE_2D");
496
497 let debug_overdraw = LazilyCompiledShader::new(
498 ShaderKind::Text,
499 name,
500 &debug_overdraw_features,
501 device,
502 precache_flags,
503 &shader_list,
504 )?;
505
506 Ok(TextShader { simple, glyph_transform, debug_overdraw })
507 }
508
get( &mut self, glyph_format: GlyphFormat, debug_flags: DebugFlags, ) -> &mut LazilyCompiledShader509 pub fn get(
510 &mut self,
511 glyph_format: GlyphFormat,
512 debug_flags: DebugFlags,
513 ) -> &mut LazilyCompiledShader {
514 match glyph_format {
515 _ if debug_flags.contains(DebugFlags::SHOW_OVERDRAW) => &mut self.debug_overdraw,
516 GlyphFormat::Alpha |
517 GlyphFormat::Subpixel |
518 GlyphFormat::Bitmap |
519 GlyphFormat::ColorBitmap => &mut self.simple,
520 GlyphFormat::TransformedAlpha |
521 GlyphFormat::TransformedSubpixel => &mut self.glyph_transform,
522 }
523 }
524
deinit(self, device: &mut Device)525 fn deinit(self, device: &mut Device) {
526 self.simple.deinit(device);
527 self.glyph_transform.deinit(device);
528 self.debug_overdraw.deinit(device);
529 }
530 }
531
create_prim_shader( name: &'static str, device: &mut Device, features: &[&'static str], ) -> Result<Program, ShaderError>532 fn create_prim_shader(
533 name: &'static str,
534 device: &mut Device,
535 features: &[&'static str],
536 ) -> Result<Program, ShaderError> {
537 debug!("PrimShader {}", name);
538
539 device.create_program(name, features)
540 }
541
create_clip_shader( name: &'static str, device: &mut Device, features: &[&'static str], ) -> Result<Program, ShaderError>542 fn create_clip_shader(
543 name: &'static str,
544 device: &mut Device,
545 features: &[&'static str],
546 ) -> Result<Program, ShaderError> {
547 debug!("ClipShader {}", name);
548
549 device.create_program(name, features)
550 }
551
552 // NB: If you add a new shader here, make sure to deinitialize it
553 // in `Shaders::deinit()` below.
554 pub struct Shaders {
555 // These are "cache shaders". These shaders are used to
556 // draw intermediate results to cache targets. The results
557 // of these shaders are then used by the primitive shaders.
558 pub cs_blur_a8: LazilyCompiledShader,
559 pub cs_blur_rgba8: LazilyCompiledShader,
560 pub cs_border_segment: LazilyCompiledShader,
561 pub cs_border_solid: LazilyCompiledShader,
562 pub cs_scale: Vec<Option<LazilyCompiledShader>>,
563 pub cs_line_decoration: LazilyCompiledShader,
564 pub cs_fast_linear_gradient: LazilyCompiledShader,
565 pub cs_linear_gradient: LazilyCompiledShader,
566 pub cs_radial_gradient: LazilyCompiledShader,
567 pub cs_conic_gradient: LazilyCompiledShader,
568 pub cs_svg_filter: LazilyCompiledShader,
569
570 // Brush shaders
571 brush_solid: BrushShader,
572 brush_image: Vec<Option<BrushShader>>,
573 brush_fast_image: Vec<Option<BrushShader>>,
574 brush_blend: BrushShader,
575 brush_mix_blend: BrushShader,
576 brush_yuv_image: Vec<Option<BrushShader>>,
577 brush_linear_gradient: BrushShader,
578 brush_opacity: BrushShader,
579 brush_opacity_aa: BrushShader,
580
581 /// These are "cache clip shaders". These shaders are used to
582 /// draw clip instances into the cached clip mask. The results
583 /// of these shaders are also used by the primitive shaders.
584 pub cs_clip_rectangle_slow: LazilyCompiledShader,
585 pub cs_clip_rectangle_fast: LazilyCompiledShader,
586 pub cs_clip_box_shadow: LazilyCompiledShader,
587 pub cs_clip_image: LazilyCompiledShader,
588
589 // The are "primitive shaders". These shaders draw and blend
590 // final results on screen. They are aware of tile boundaries.
591 // Most draw directly to the framebuffer, but some use inputs
592 // from the cache shaders to draw. Specifically, the box
593 // shadow primitive shader stretches the box shadow cache
594 // output, and the cache_image shader blits the results of
595 // a cache shader (e.g. blur) to the screen.
596 pub ps_text_run: TextShader,
597 pub ps_text_run_dual_source: Option<TextShader>,
598
599 ps_split_composite: LazilyCompiledShader,
600 pub ps_clear: LazilyCompiledShader,
601
602 // Composite shaders. These are very simple shaders used to composite
603 // picture cache tiles into the framebuffer on platforms that do not have an
604 // OS Compositor (or we cannot use it). Such an OS Compositor (such as
605 // DirectComposite or CoreAnimation) handles the composition of the picture
606 // cache tiles at a lower level (e.g. in DWM for Windows); in that case we
607 // directly hand the picture cache surfaces over to the OS Compositor, and
608 // our own Composite shaders below never run.
609 // To composite external (RGB) surfaces we need various permutations of
610 // shaders with WR_FEATURE flags on or off based on the type of image
611 // buffer we're sourcing from (see IMAGE_BUFFER_KINDS).
612 pub composite_rgba: Vec<Option<LazilyCompiledShader>>,
613 // A faster set of rgba composite shaders that do not support UV clamping
614 // or color modulation.
615 pub composite_rgba_fast_path: Vec<Option<LazilyCompiledShader>>,
616 // The same set of composite shaders but with WR_FEATURE_YUV added.
617 pub composite_yuv: Vec<Option<LazilyCompiledShader>>,
618 }
619
620 impl Shaders {
new( device: &mut Device, gl_type: GlType, options: &RendererOptions, ) -> Result<Self, ShaderError>621 pub fn new(
622 device: &mut Device,
623 gl_type: GlType,
624 options: &RendererOptions,
625 ) -> Result<Self, ShaderError> {
626 let use_dual_source_blending =
627 device.get_capabilities().supports_dual_source_blending &&
628 options.allow_dual_source_blending;
629 let use_advanced_blend_equation =
630 device.get_capabilities().supports_advanced_blend_equation &&
631 options.allow_advanced_blend_equation;
632
633 let texture_external_version = if device.get_capabilities().supports_image_external_essl3 {
634 TextureExternalVersion::ESSL3
635 } else {
636 TextureExternalVersion::ESSL1
637 };
638 let mut shader_flags = match gl_type {
639 GlType::Gl => ShaderFeatureFlags::GL,
640 GlType::Gles => {
641 let texture_external_flag = match texture_external_version {
642 TextureExternalVersion::ESSL3 => ShaderFeatureFlags::TEXTURE_EXTERNAL,
643 TextureExternalVersion::ESSL1 => ShaderFeatureFlags::TEXTURE_EXTERNAL_ESSL1,
644 };
645 ShaderFeatureFlags::GLES | texture_external_flag
646 }
647 };
648 shader_flags.set(ShaderFeatureFlags::ADVANCED_BLEND_EQUATION, use_advanced_blend_equation);
649 shader_flags.set(ShaderFeatureFlags::DUAL_SOURCE_BLENDING, use_dual_source_blending);
650 shader_flags.set(ShaderFeatureFlags::DITHERING, options.enable_dithering);
651 let shader_list = get_shader_features(shader_flags);
652
653 let brush_solid = BrushShader::new(
654 "brush_solid",
655 device,
656 &[],
657 options.precache_flags,
658 &shader_list,
659 false /* advanced blend */,
660 false /* dual source */,
661 )?;
662
663 let brush_blend = BrushShader::new(
664 "brush_blend",
665 device,
666 &[],
667 options.precache_flags,
668 &shader_list,
669 false /* advanced blend */,
670 false /* dual source */,
671 )?;
672
673 let brush_mix_blend = BrushShader::new(
674 "brush_mix_blend",
675 device,
676 &[],
677 options.precache_flags,
678 &shader_list,
679 false /* advanced blend */,
680 false /* dual source */,
681 )?;
682
683 let brush_linear_gradient = BrushShader::new(
684 "brush_linear_gradient",
685 device,
686 if options.enable_dithering {
687 &[DITHERING_FEATURE]
688 } else {
689 &[]
690 },
691 options.precache_flags,
692 &shader_list,
693 false /* advanced blend */,
694 false /* dual source */,
695 )?;
696
697 let brush_opacity_aa = BrushShader::new(
698 "brush_opacity",
699 device,
700 &["ANTIALIASING"],
701 options.precache_flags,
702 &shader_list,
703 false /* advanced blend */,
704 false /* dual source */,
705 )?;
706
707 let brush_opacity = BrushShader::new(
708 "brush_opacity",
709 device,
710 &[],
711 options.precache_flags,
712 &shader_list,
713 false /* advanced blend */,
714 false /* dual source */,
715 )?;
716
717 let cs_blur_a8 = LazilyCompiledShader::new(
718 ShaderKind::Cache(VertexArrayKind::Blur),
719 "cs_blur",
720 &["ALPHA_TARGET"],
721 device,
722 options.precache_flags,
723 &shader_list,
724 )?;
725
726 let cs_blur_rgba8 = LazilyCompiledShader::new(
727 ShaderKind::Cache(VertexArrayKind::Blur),
728 "cs_blur",
729 &["COLOR_TARGET"],
730 device,
731 options.precache_flags,
732 &shader_list,
733 )?;
734
735 let cs_svg_filter = LazilyCompiledShader::new(
736 ShaderKind::Cache(VertexArrayKind::SvgFilter),
737 "cs_svg_filter",
738 &[],
739 device,
740 options.precache_flags,
741 &shader_list,
742 )?;
743
744 let cs_clip_rectangle_slow = LazilyCompiledShader::new(
745 ShaderKind::ClipCache(VertexArrayKind::ClipRect),
746 "cs_clip_rectangle",
747 &[],
748 device,
749 options.precache_flags,
750 &shader_list,
751 )?;
752
753 let cs_clip_rectangle_fast = LazilyCompiledShader::new(
754 ShaderKind::ClipCache(VertexArrayKind::ClipRect),
755 "cs_clip_rectangle",
756 &[FAST_PATH_FEATURE],
757 device,
758 options.precache_flags,
759 &shader_list,
760 )?;
761
762 let cs_clip_box_shadow = LazilyCompiledShader::new(
763 ShaderKind::ClipCache(VertexArrayKind::ClipBoxShadow),
764 "cs_clip_box_shadow",
765 &["TEXTURE_2D"],
766 device,
767 options.precache_flags,
768 &shader_list,
769 )?;
770
771 let cs_clip_image = LazilyCompiledShader::new(
772 ShaderKind::ClipCache(VertexArrayKind::ClipImage),
773 "cs_clip_image",
774 &["TEXTURE_2D"],
775 device,
776 options.precache_flags,
777 &shader_list,
778 )?;
779
780 let mut cs_scale = Vec::new();
781 let scale_shader_num = IMAGE_BUFFER_KINDS.len();
782 // PrimitiveShader is not clonable. Use push() to initialize the vec.
783 for _ in 0 .. scale_shader_num {
784 cs_scale.push(None);
785 }
786 for image_buffer_kind in &IMAGE_BUFFER_KINDS {
787 if has_platform_support(*image_buffer_kind, &gl_type) {
788 let feature_string = get_feature_string(
789 *image_buffer_kind,
790 texture_external_version,
791 );
792
793 let mut features = Vec::new();
794 if feature_string != "" {
795 features.push(feature_string);
796 }
797
798 let shader = LazilyCompiledShader::new(
799 ShaderKind::Cache(VertexArrayKind::Scale),
800 "cs_scale",
801 &features,
802 device,
803 options.precache_flags,
804 &shader_list,
805 )?;
806
807 let index = Self::get_compositing_shader_index(
808 *image_buffer_kind,
809 );
810 cs_scale[index] = Some(shader);
811 }
812 }
813
814 // TODO(gw): The split composite + text shader are special cases - the only
815 // shaders used during normal scene rendering that aren't a brush
816 // shader. Perhaps we can unify these in future?
817
818 let ps_text_run = TextShader::new("ps_text_run",
819 device,
820 &[],
821 options.precache_flags,
822 &shader_list,
823 )?;
824
825 let ps_text_run_dual_source = if use_dual_source_blending {
826 let dual_source_features = vec![DUAL_SOURCE_FEATURE];
827 Some(TextShader::new("ps_text_run",
828 device,
829 &dual_source_features,
830 options.precache_flags,
831 &shader_list,
832 )?)
833 } else {
834 None
835 };
836
837 let ps_split_composite = LazilyCompiledShader::new(
838 ShaderKind::Primitive,
839 "ps_split_composite",
840 &[],
841 device,
842 options.precache_flags,
843 &shader_list,
844 )?;
845
846 let ps_clear = LazilyCompiledShader::new(
847 ShaderKind::Clear,
848 "ps_clear",
849 &[],
850 device,
851 options.precache_flags,
852 &shader_list,
853 )?;
854
855 // All image configuration.
856 let mut image_features = Vec::new();
857 let mut brush_image = Vec::new();
858 let mut brush_fast_image = Vec::new();
859 // PrimitiveShader is not clonable. Use push() to initialize the vec.
860 for _ in 0 .. IMAGE_BUFFER_KINDS.len() {
861 brush_image.push(None);
862 brush_fast_image.push(None);
863 }
864 for buffer_kind in 0 .. IMAGE_BUFFER_KINDS.len() {
865 if !has_platform_support(IMAGE_BUFFER_KINDS[buffer_kind], &gl_type)
866 // Brush shaders are not ESSL1 compatible
867 || (IMAGE_BUFFER_KINDS[buffer_kind] == ImageBufferKind::TextureExternal
868 && texture_external_version == TextureExternalVersion::ESSL1)
869 {
870 continue;
871 }
872
873 let feature_string = get_feature_string(
874 IMAGE_BUFFER_KINDS[buffer_kind],
875 texture_external_version,
876 );
877 if feature_string != "" {
878 image_features.push(feature_string);
879 }
880
881 brush_fast_image[buffer_kind] = Some(BrushShader::new(
882 "brush_image",
883 device,
884 &image_features,
885 options.precache_flags,
886 &shader_list,
887 use_advanced_blend_equation,
888 use_dual_source_blending,
889 )?);
890
891 image_features.push("REPETITION");
892 image_features.push("ANTIALIASING");
893
894 brush_image[buffer_kind] = Some(BrushShader::new(
895 "brush_image",
896 device,
897 &image_features,
898 options.precache_flags,
899 &shader_list,
900 use_advanced_blend_equation,
901 use_dual_source_blending,
902 )?);
903
904 image_features.clear();
905 }
906
907 // All yuv_image configuration.
908 let mut yuv_features = Vec::new();
909 let mut rgba_features = Vec::new();
910 let mut fast_path_features = Vec::new();
911 let yuv_shader_num = IMAGE_BUFFER_KINDS.len();
912 let mut brush_yuv_image = Vec::new();
913 let mut composite_yuv = Vec::new();
914 let mut composite_rgba = Vec::new();
915 let mut composite_rgba_fast_path = Vec::new();
916 // PrimitiveShader is not clonable. Use push() to initialize the vec.
917 for _ in 0 .. yuv_shader_num {
918 brush_yuv_image.push(None);
919 composite_yuv.push(None);
920 composite_rgba.push(None);
921 composite_rgba_fast_path.push(None);
922 }
923 for image_buffer_kind in &IMAGE_BUFFER_KINDS {
924 if has_platform_support(*image_buffer_kind, &gl_type) {
925 yuv_features.push("YUV");
926 fast_path_features.push("FAST_PATH");
927
928 let index = Self::get_compositing_shader_index(
929 *image_buffer_kind,
930 );
931
932 let feature_string = get_feature_string(
933 *image_buffer_kind,
934 texture_external_version,
935 );
936 if feature_string != "" {
937 yuv_features.push(feature_string);
938 rgba_features.push(feature_string);
939 fast_path_features.push(feature_string);
940 }
941
942 // YUV shaders are not compatible with ESSL1
943 if *image_buffer_kind != ImageBufferKind::TextureExternal ||
944 texture_external_version == TextureExternalVersion::ESSL3 {
945 let brush_shader = BrushShader::new(
946 "brush_yuv_image",
947 device,
948 &yuv_features,
949 options.precache_flags,
950 &shader_list,
951 false /* advanced blend */,
952 false /* dual source */,
953 )?;
954 brush_yuv_image[index] = Some(brush_shader);
955
956 let composite_yuv_shader = LazilyCompiledShader::new(
957 ShaderKind::Composite,
958 "composite",
959 &yuv_features,
960 device,
961 options.precache_flags,
962 &shader_list,
963 )?;
964 composite_yuv[index] = Some(composite_yuv_shader);
965 }
966
967 let composite_rgba_shader = LazilyCompiledShader::new(
968 ShaderKind::Composite,
969 "composite",
970 &rgba_features,
971 device,
972 options.precache_flags,
973 &shader_list,
974 )?;
975
976 let composite_rgba_fast_path_shader = LazilyCompiledShader::new(
977 ShaderKind::Composite,
978 "composite",
979 &fast_path_features,
980 device,
981 options.precache_flags,
982 &shader_list,
983 )?;
984
985 let index = Self::get_compositing_shader_index(
986 *image_buffer_kind,
987 );
988 composite_rgba[index] = Some(composite_rgba_shader);
989 composite_rgba_fast_path[index] = Some(composite_rgba_fast_path_shader);
990
991 yuv_features.clear();
992 rgba_features.clear();
993 fast_path_features.clear();
994 }
995 }
996
997 let cs_line_decoration = LazilyCompiledShader::new(
998 ShaderKind::Cache(VertexArrayKind::LineDecoration),
999 "cs_line_decoration",
1000 &[],
1001 device,
1002 options.precache_flags,
1003 &shader_list,
1004 )?;
1005
1006 let cs_fast_linear_gradient = LazilyCompiledShader::new(
1007 ShaderKind::Cache(VertexArrayKind::FastLinearGradient),
1008 "cs_fast_linear_gradient",
1009 &[],
1010 device,
1011 options.precache_flags,
1012 &shader_list,
1013 )?;
1014
1015 let cs_linear_gradient = LazilyCompiledShader::new(
1016 ShaderKind::Cache(VertexArrayKind::LinearGradient),
1017 "cs_linear_gradient",
1018 &[],
1019 device,
1020 options.precache_flags,
1021 &shader_list,
1022 )?;
1023
1024 let cs_radial_gradient = LazilyCompiledShader::new(
1025 ShaderKind::Cache(VertexArrayKind::RadialGradient),
1026 "cs_radial_gradient",
1027 &[],
1028 device,
1029 options.precache_flags,
1030 &shader_list,
1031 )?;
1032
1033 let cs_conic_gradient = LazilyCompiledShader::new(
1034 ShaderKind::Cache(VertexArrayKind::ConicGradient),
1035 "cs_conic_gradient",
1036 &[],
1037 device,
1038 options.precache_flags,
1039 &shader_list,
1040 )?;
1041
1042 let cs_border_segment = LazilyCompiledShader::new(
1043 ShaderKind::Cache(VertexArrayKind::Border),
1044 "cs_border_segment",
1045 &[],
1046 device,
1047 options.precache_flags,
1048 &shader_list,
1049 )?;
1050
1051 let cs_border_solid = LazilyCompiledShader::new(
1052 ShaderKind::Cache(VertexArrayKind::Border),
1053 "cs_border_solid",
1054 &[],
1055 device,
1056 options.precache_flags,
1057 &shader_list,
1058 )?;
1059
1060 Ok(Shaders {
1061 cs_blur_a8,
1062 cs_blur_rgba8,
1063 cs_border_segment,
1064 cs_line_decoration,
1065 cs_fast_linear_gradient,
1066 cs_linear_gradient,
1067 cs_radial_gradient,
1068 cs_conic_gradient,
1069 cs_border_solid,
1070 cs_scale,
1071 cs_svg_filter,
1072 brush_solid,
1073 brush_image,
1074 brush_fast_image,
1075 brush_blend,
1076 brush_mix_blend,
1077 brush_yuv_image,
1078 brush_linear_gradient,
1079 brush_opacity,
1080 brush_opacity_aa,
1081 cs_clip_rectangle_slow,
1082 cs_clip_rectangle_fast,
1083 cs_clip_box_shadow,
1084 cs_clip_image,
1085 ps_text_run,
1086 ps_text_run_dual_source,
1087 ps_split_composite,
1088 ps_clear,
1089 composite_rgba,
1090 composite_rgba_fast_path,
1091 composite_yuv,
1092 })
1093 }
1094
get_compositing_shader_index(buffer_kind: ImageBufferKind) -> usize1095 fn get_compositing_shader_index(buffer_kind: ImageBufferKind) -> usize {
1096 buffer_kind as usize
1097 }
1098
get_composite_shader( &mut self, format: CompositeSurfaceFormat, buffer_kind: ImageBufferKind, features: CompositeFeatures, ) -> &mut LazilyCompiledShader1099 pub fn get_composite_shader(
1100 &mut self,
1101 format: CompositeSurfaceFormat,
1102 buffer_kind: ImageBufferKind,
1103 features: CompositeFeatures,
1104 ) -> &mut LazilyCompiledShader {
1105 match format {
1106 CompositeSurfaceFormat::Rgba => {
1107 if features.contains(CompositeFeatures::NO_UV_CLAMP)
1108 && features.contains(CompositeFeatures::NO_COLOR_MODULATION)
1109 {
1110 let shader_index = Self::get_compositing_shader_index(buffer_kind);
1111 self.composite_rgba_fast_path[shader_index]
1112 .as_mut()
1113 .expect("bug: unsupported rgba fast path shader requested")
1114 } else {
1115 let shader_index = Self::get_compositing_shader_index(buffer_kind);
1116 self.composite_rgba[shader_index]
1117 .as_mut()
1118 .expect("bug: unsupported rgba shader requested")
1119 }
1120 }
1121 CompositeSurfaceFormat::Yuv => {
1122 let shader_index = Self::get_compositing_shader_index(buffer_kind);
1123 self.composite_yuv[shader_index]
1124 .as_mut()
1125 .expect("bug: unsupported yuv shader requested")
1126 }
1127 }
1128 }
1129
get_scale_shader( &mut self, buffer_kind: ImageBufferKind, ) -> &mut LazilyCompiledShader1130 pub fn get_scale_shader(
1131 &mut self,
1132 buffer_kind: ImageBufferKind,
1133 ) -> &mut LazilyCompiledShader {
1134 let shader_index = Self::get_compositing_shader_index(buffer_kind);
1135 self.cs_scale[shader_index]
1136 .as_mut()
1137 .expect("bug: unsupported scale shader requested")
1138 }
1139
get(& mut self, key: &BatchKey, mut features: BatchFeatures, debug_flags: DebugFlags, device: &Device, ) -> &mut LazilyCompiledShader1140 pub fn get(&
1141 mut self,
1142 key: &BatchKey,
1143 mut features: BatchFeatures,
1144 debug_flags: DebugFlags,
1145 device: &Device,
1146 ) -> &mut LazilyCompiledShader {
1147 match key.kind {
1148 BatchKind::SplitComposite => {
1149 &mut self.ps_split_composite
1150 }
1151 BatchKind::Brush(brush_kind) => {
1152 // SWGL uses a native anti-aliasing implementation that bypasses the shader.
1153 // Don't consider it in that case when deciding whether or not to use
1154 // an alpha-pass shader.
1155 if device.get_capabilities().uses_native_antialiasing {
1156 features.remove(BatchFeatures::ANTIALIASING);
1157 }
1158 let brush_shader = match brush_kind {
1159 BrushBatchKind::Solid => {
1160 &mut self.brush_solid
1161 }
1162 BrushBatchKind::Image(image_buffer_kind) => {
1163 if features.contains(BatchFeatures::ANTIALIASING) ||
1164 features.contains(BatchFeatures::REPETITION) {
1165
1166 self.brush_image[image_buffer_kind as usize]
1167 .as_mut()
1168 .expect("Unsupported image shader kind")
1169 } else {
1170 self.brush_fast_image[image_buffer_kind as usize]
1171 .as_mut()
1172 .expect("Unsupported image shader kind")
1173 }
1174 }
1175 BrushBatchKind::Blend => {
1176 &mut self.brush_blend
1177 }
1178 BrushBatchKind::MixBlend { .. } => {
1179 &mut self.brush_mix_blend
1180 }
1181 BrushBatchKind::LinearGradient => {
1182 // SWGL uses a native clip mask implementation that bypasses the shader.
1183 // Don't consider it in that case when deciding whether or not to use
1184 // an alpha-pass shader.
1185 if device.get_capabilities().uses_native_clip_mask {
1186 features.remove(BatchFeatures::CLIP_MASK);
1187 }
1188 // Gradient brushes can optimistically use the opaque shader even
1189 // with a blend mode if they don't require any features.
1190 if !features.intersects(
1191 BatchFeatures::ANTIALIASING
1192 | BatchFeatures::REPETITION
1193 | BatchFeatures::CLIP_MASK,
1194 ) {
1195 features.remove(BatchFeatures::ALPHA_PASS);
1196 }
1197 match brush_kind {
1198 BrushBatchKind::LinearGradient => &mut self.brush_linear_gradient,
1199 _ => panic!(),
1200 }
1201 }
1202 BrushBatchKind::YuvImage(image_buffer_kind, ..) => {
1203 let shader_index =
1204 Self::get_compositing_shader_index(image_buffer_kind);
1205 self.brush_yuv_image[shader_index]
1206 .as_mut()
1207 .expect("Unsupported YUV shader kind")
1208 }
1209 BrushBatchKind::Opacity => {
1210 if features.contains(BatchFeatures::ANTIALIASING) {
1211 &mut self.brush_opacity_aa
1212 } else {
1213 &mut self.brush_opacity
1214 }
1215 }
1216 };
1217 brush_shader.get(key.blend_mode, features, debug_flags)
1218 }
1219 BatchKind::TextRun(glyph_format) => {
1220 let text_shader = match key.blend_mode {
1221 BlendMode::SubpixelDualSource => self.ps_text_run_dual_source.as_mut().unwrap(),
1222 _ => &mut self.ps_text_run,
1223 };
1224 text_shader.get(glyph_format, debug_flags)
1225 }
1226 }
1227 }
1228
deinit(self, device: &mut Device)1229 pub fn deinit(self, device: &mut Device) {
1230 for shader in self.cs_scale {
1231 if let Some(shader) = shader {
1232 shader.deinit(device);
1233 }
1234 }
1235 self.cs_blur_a8.deinit(device);
1236 self.cs_blur_rgba8.deinit(device);
1237 self.cs_svg_filter.deinit(device);
1238 self.brush_solid.deinit(device);
1239 self.brush_blend.deinit(device);
1240 self.brush_mix_blend.deinit(device);
1241 self.brush_linear_gradient.deinit(device);
1242 self.brush_opacity.deinit(device);
1243 self.brush_opacity_aa.deinit(device);
1244 self.cs_clip_rectangle_slow.deinit(device);
1245 self.cs_clip_rectangle_fast.deinit(device);
1246 self.cs_clip_box_shadow.deinit(device);
1247 self.cs_clip_image.deinit(device);
1248 self.ps_text_run.deinit(device);
1249 if let Some(shader) = self.ps_text_run_dual_source {
1250 shader.deinit(device);
1251 }
1252 for shader in self.brush_image {
1253 if let Some(shader) = shader {
1254 shader.deinit(device);
1255 }
1256 }
1257 for shader in self.brush_fast_image {
1258 if let Some(shader) = shader {
1259 shader.deinit(device);
1260 }
1261 }
1262 for shader in self.brush_yuv_image {
1263 if let Some(shader) = shader {
1264 shader.deinit(device);
1265 }
1266 }
1267 self.cs_border_solid.deinit(device);
1268 self.cs_fast_linear_gradient.deinit(device);
1269 self.cs_linear_gradient.deinit(device);
1270 self.cs_radial_gradient.deinit(device);
1271 self.cs_conic_gradient.deinit(device);
1272 self.cs_line_decoration.deinit(device);
1273 self.cs_border_segment.deinit(device);
1274 self.ps_split_composite.deinit(device);
1275 self.ps_clear.deinit(device);
1276
1277 for shader in self.composite_rgba {
1278 if let Some(shader) = shader {
1279 shader.deinit(device);
1280 }
1281 }
1282 for shader in self.composite_rgba_fast_path {
1283 if let Some(shader) = shader {
1284 shader.deinit(device);
1285 }
1286 }
1287 for shader in self.composite_yuv {
1288 if let Some(shader) = shader {
1289 shader.deinit(device);
1290 }
1291 }
1292 }
1293 }
1294
1295 pub type SharedShaders = Rc<RefCell<Shaders>>;
1296