Source code

Revision control

Other Tools

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