From 520e0fc0660627c8b8007459ebc4a477dda2a9fd Mon Sep 17 00:00:00 2001 From: Bert Peers Date: Wed, 25 Mar 2020 03:49:38 +0000 Subject: [PATCH 1/9] Bug 1605283 - Improve support for invalidation debugging and testing r=gw Support hiding slices to better understand what's on which layer, and to hide UI when not relevant. Requires using a HTTP server due to cross-scripting. Differential Revision: https://phabricator.services.mozilla.com/D67963 [ghsync] From https://hg.mozilla.org/mozilla-central/rev/c034bb22ce039bd90289c6ca972b00206b069dfa --- tileview/src/main.rs | 46 ++++++++++++++++++++++++++++++++++++--- tileview/src/tilecache.js | 30 +++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/tileview/src/main.rs b/tileview/src/main.rs index 20758185b4..7011ca35c4 100644 --- a/tileview/src/main.rs +++ b/tileview/src/main.rs @@ -12,6 +12,20 @@ /// 2nd: /// cargo run --release -- /foo/bar/wr-capture/tilecache /tmp/tilecache /// 4. open /tmp/tilecache/index.html +/// +/// Note: accurate interning info requires that the circular buffer doesn't wrap around. +/// So for best results, use this workflow: +/// a. start up blank browser; in about:config enable logging; close browser +/// b. start new browser, quickly load the repro +/// c. capture. +/// +/// If that's tricky, you can also just throw more memory at it: in render_backend.rs, +/// increase the buffer size here: 'TileCacheLogger::new(500usize)' +/// +/// Note: some features don't work when opening index.html directly due to cross-scripting +/// protections. Instead use a HTTP server: +/// python -m SimpleHTTPServer 8000 + use webrender::{TileNode, TileNodeKind, InvalidationReason, TileOffset}; use webrender::{TileSerializer, TileCacheInstanceSerializer, TileCacheLoggerUpdateLists}; @@ -353,6 +367,8 @@ fn slices_to_svg(slices: &[Slice], prev_slices: Option>, let prim_class = format!("tile_slice{}", tile_cache.slice); + svg.push_str(&format!("\n", tile_cache.slice)); + //println!("slice {}", tile_cache.slice); svg.push_str(&format!("\n\n", tile_cache.slice)); @@ -382,6 +398,8 @@ fn slices_to_svg(slices: &[Slice], prev_slices: Option>, &mut invalidation_report, svg_width, svg_height, svg_settings)); } + + svg.push_str("\n"); } ( @@ -398,7 +416,7 @@ fn slices_to_svg(slices: &[Slice], prev_slices: Option>, ) } -fn write_html(output_dir: &Path, svg_files: &[String], intern_files: &[String]) { +fn write_html(output_dir: &Path, max_slice_index: usize, svg_files: &[String], intern_files: &[String]) { let html_head = "\n\ \n\ \n\ @@ -433,6 +451,26 @@ fn write_html(output_dir: &Path, svg_files: &[String], intern_files: &[String]) \n" .to_string(); + let mut html_slices_form = + "\n
\n\ + Slice\n".to_string(); + + for ix in 0..max_slice_index + 1 { + html_slices_form += + &format!( + "\n\ + \n", + ix, + max_slice_index + 1, + ix, + ix ); + } + + html_slices_form += "\n"; + let html_body = format!( "{}\n\
\n\ @@ -451,13 +489,15 @@ fn write_html(output_dir: &Path, svg_files: &[String], intern_files: &[String])
Spacebar to Play
\n\
Use Left/Right to Step
\n\ + {}
", html_body, svg_files[0], svg_files[0], intern_files[0], svg_files[0], - svg_files.len() ); + svg_files.len(), + html_slices_form ); let html = format!("{}{}{}{}", html_head, html_body, script, html_end); @@ -649,7 +689,7 @@ fn main() { prev_slices = Some(slices); } - write_html(output_dir, &svg_files, &intern_files); + write_html(output_dir, max_slice_index, &svg_files, &intern_files); write_css(output_dir, max_slice_index, &svg_settings); std::fs::write(output_dir.join("tilecache.js"), RES_JAVASCRIPT).unwrap(); diff --git a/tileview/src/tilecache.js b/tileview/src/tilecache.js index 36a9fd0aee..5b4f9627d0 100644 --- a/tileview/src/tilecache.js +++ b/tileview/src/tilecache.js @@ -42,6 +42,33 @@ function toggle_quadtree() { } } +function update_slice_visibility(max_slice) { + let content = frontbuffer.contentDocument; + update_slice_visibility_for_content(content, max_slice); +} + +function update_slice_visibility_for_content(content, max_slice) { + + if( !content ) // might happen due to cross-scripting -- use SimpleHTTPServer + return; + + for (let slice = 0; slice != max_slice; ++slice) { + var cbox_name = "slice_toggle" + slice; + let cbox = document.getElementById(cbox_name); + if( !cbox ) + continue; + let checked = cbox.checked; + var id = "tile_slice" + slice + "_everything"; + var group = content.getElementById(id); + if( !group ) + continue; + if( checked ) + group.style.display = "block"; + else + group.style.display = "none"; + } +} + // try to block repeated keypressed from causing flickering // when they land between go_to_svg returning and onload // firing. @@ -66,6 +93,9 @@ function go_to_svg(index) { document.getElementById("text_frame_counter").innerHTML = svg_files[svg_index]; + let content = backbuffer.contentDocument; + update_slice_visibility_for_content(content, 20); + backbuffer.style.display = ''; frontbuffer.style.display = 'none'; From 63e30b259fae37a31773b2bca2768c30693cb336 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 25 Mar 2020 03:49:47 +0000 Subject: [PATCH 2/9] Bug 1624396 - implement centralized shader features list management for WebRender. r=gw,jrmuizel,jnicol Differential Revision: https://phabricator.services.mozilla.com/D67958 [ghsync] From https://hg.mozilla.org/mozilla-central/rev/178ba8ef059cb90937f458692617a660bc961562 --- Cargo.lock | 1 + webrender/src/device/gl.rs | 12 +- webrender/src/renderer.rs | 11 +- webrender/src/shade.rs | 170 ++++++++++++++++++------- webrender_build/Cargo.toml | 1 + webrender_build/src/lib.rs | 4 + webrender_build/src/shader.rs | 2 + webrender_build/src/shader_features.rs | 146 +++++++++++++++++++++ 8 files changed, 291 insertions(+), 56 deletions(-) create mode 100644 webrender_build/src/shader_features.rs diff --git a/Cargo.lock b/Cargo.lock index 21e269c4af..41bbabbb42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1868,6 +1868,7 @@ dependencies = [ name = "webrender_build" version = "0.0.1" dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/webrender/src/device/gl.rs b/webrender/src/device/gl.rs index 68f1bb644f..4bd97420c4 100644 --- a/webrender/src/device/gl.rs +++ b/webrender/src/device/gl.rs @@ -32,8 +32,7 @@ use std::{ thread, time::Duration, }; -use webrender_build::shader::ProgramSourceDigest; -use webrender_build::shader::{ShaderSourceParser, shader_source_from_file}; +use webrender_build::shader::{ProgramSourceDigest, ShaderSourceParser, shader_source_from_file}; /// Sequence number for frames, as tracked by the device layer. #[derive(Debug, Copy, Clone, PartialEq, Ord, Eq, PartialOrd)] @@ -988,6 +987,8 @@ pub struct Capabilities { pub supports_pixel_local_storage: bool, /// Whether advanced blend equations are supported. pub supports_advanced_blend_equation: bool, + /// Whether dual-source blending is supported. + pub supports_dual_source_blending: bool, /// Whether KHR_debug is supported for getting debug messages from /// the driver. pub supports_khr_debug: bool, @@ -1509,6 +1510,12 @@ impl Device { supports_extension(&extensions, "GL_KHR_blend_equation_advanced") && !is_adreno; + let supports_dual_source_blending = match gl.get_type() { + gl::GlType::Gl => supports_extension(&extensions,"GL_ARB_blend_func_extended") && + supports_extension(&extensions,"GL_ARB_explicit_attrib_location"), + gl::GlType::Gles => supports_extension(&extensions,"GL_EXT_blend_func_extended"), + }; + // On the android emulator, glShaderSource can crash if the source // strings are not null-terminated. See bug 1591945. let requires_null_terminated_shader_source = is_emulator; @@ -1542,6 +1549,7 @@ impl Device { supports_blit_to_texture_array, supports_pixel_local_storage, supports_advanced_blend_equation, + supports_dual_source_blending, supports_khr_debug, supports_texture_swizzle, supports_nonzero_pbo_offsets, diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 1f40e5218f..6e482d7fc8 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -2071,13 +2071,8 @@ impl Renderer { let color_cache_formats = device.preferred_color_formats(); let swizzle_settings = device.swizzle_settings(); - let supports_dual_source_blending = match gl_type { - gl::GlType::Gl => device.supports_extension("GL_ARB_blend_func_extended") && - device.supports_extension("GL_ARB_explicit_attrib_location"), - gl::GlType::Gles => device.supports_extension("GL_EXT_blend_func_extended"), - }; let use_dual_source_blending = - supports_dual_source_blending && + device.get_capabilities().supports_dual_source_blending && options.allow_dual_source_blending && // If using pixel local storage, subpixel AA isn't supported (we disable it on all // mobile devices explicitly anyway). @@ -5882,6 +5877,8 @@ impl Renderer { self.shaders .borrow_mut() .pls_init + .as_mut() + .unwrap() .bind( &mut self.device, projection, @@ -5910,6 +5907,8 @@ impl Renderer { self.shaders .borrow_mut() .pls_resolve + .as_mut() + .unwrap() .bind( &mut self.device, projection, diff --git a/webrender/src/shade.rs b/webrender/src/shade.rs index 585917b14f..df646d5a33 100644 --- a/webrender/src/shade.rs +++ b/webrender/src/shade.rs @@ -20,6 +20,8 @@ use time::precise_time_ns; use std::cell::RefCell; use std::rc::Rc; +use webrender_build::shader::{ShaderFeatures, ShaderFeatureFlags, get_shader_features}; + impl ImageBufferKind { pub(crate) fn get_feature_string(&self) -> &'static str { match *self { @@ -34,7 +36,8 @@ impl ImageBufferKind { match (*self, gl_type) { (ImageBufferKind::Texture2D, _) => true, (ImageBufferKind::Texture2DArray, _) => true, - (ImageBufferKind::TextureRect, _) => true, + (ImageBufferKind::TextureRect, &GlType::Gles) => false, + (ImageBufferKind::TextureRect, &GlType::Gl) => true, (ImageBufferKind::TextureExternal, &GlType::Gles) => true, (ImageBufferKind::TextureExternal, &GlType::Gl) => false, } @@ -85,6 +88,7 @@ impl LazilyCompiledShader { features: &[&'static str], device: &mut Device, precache_flags: ShaderPrecacheFlags, + shader_list: &ShaderFeatures, ) -> Result { let mut shader = LazilyCompiledShader { program: None, @@ -96,6 +100,16 @@ impl LazilyCompiledShader { features: features.to_vec(), }; + // Ensure this shader config is in the available shader list so that we get + // alerted if the list gets out-of-date when shaders or features are added. + let config = features.join(","); + assert!( + shader_list.get(name).map_or(false, |f| f.contains(&config)), + "shader \"{}\" with features \"{}\" not in available shader list", + name, + config, + ); + if precache_flags.intersects(ShaderPrecacheFlags::ASYNC_COMPILE | ShaderPrecacheFlags::FULL_COMPILE) { let t0 = precise_time_ns(); shader.get_internal(device, precache_flags)?; @@ -287,8 +301,9 @@ impl BrushShader { device: &mut Device, features: &[&'static str], precache_flags: ShaderPrecacheFlags, - advanced_blend: bool, - dual_source: bool, + shader_list: &ShaderFeatures, + use_advanced_blend: bool, + use_dual_source: bool, use_pixel_local_storage: bool, ) -> Result { let opaque = LazilyCompiledShader::new( @@ -297,6 +312,7 @@ impl BrushShader { features, device, precache_flags, + &shader_list, )?; let mut alpha_features = features.to_vec(); @@ -311,11 +327,10 @@ impl BrushShader { &alpha_features, device, precache_flags, + &shader_list, )?; - let advanced_blend = if advanced_blend && - device.get_capabilities().supports_advanced_blend_equation - { + let advanced_blend = if use_advanced_blend { let mut advanced_blend_features = alpha_features.to_vec(); advanced_blend_features.push(ADVANCED_BLEND_FEATURE); @@ -325,6 +340,7 @@ impl BrushShader { &advanced_blend_features, device, precache_flags, + &shader_list, )?; Some(shader) @@ -332,10 +348,7 @@ impl BrushShader { None }; - // If using PLS, we disable all subpixel AA implicitly. Subpixel AA is always - // disabled on mobile devices anyway, due to uncertainty over the subpixel - // layout configuration. - let dual_source = if dual_source && !use_pixel_local_storage { + let dual_source = if use_dual_source { let mut dual_source_features = alpha_features.to_vec(); dual_source_features.push(DUAL_SOURCE_FEATURE); @@ -345,6 +358,7 @@ impl BrushShader { &dual_source_features, device, precache_flags, + &shader_list, )?; Some(shader) @@ -361,6 +375,7 @@ impl BrushShader { &debug_overdraw_features, device, precache_flags, + &shader_list, )?; Ok(BrushShader { @@ -420,6 +435,7 @@ impl TextShader { device: &mut Device, features: &[&'static str], precache_flags: ShaderPrecacheFlags, + shader_list: &ShaderFeatures, ) -> Result { let mut simple_features = features.to_vec(); simple_features.push("ALPHA_PASS"); @@ -430,6 +446,7 @@ impl TextShader { &simple_features, device, precache_flags, + &shader_list, )?; let mut glyph_transform_features = features.to_vec(); @@ -442,6 +459,7 @@ impl TextShader { &glyph_transform_features, device, precache_flags, + &shader_list, )?; let mut debug_overdraw_features = features.to_vec(); @@ -453,6 +471,7 @@ impl TextShader { &debug_overdraw_features, device, precache_flags, + &shader_list, )?; Ok(TextShader { simple, glyph_transform, debug_overdraw }) @@ -562,13 +581,13 @@ pub struct Shaders { // output, and the cache_image shader blits the results of // a cache shader (e.g. blur) to the screen. pub ps_text_run: TextShader, - pub ps_text_run_dual_source: TextShader, + pub ps_text_run_dual_source: Option, // Helper shaders for pixel local storage render paths. // pls_init: Initialize pixel local storage, based on current framebuffer value. // pls_resolve: Convert pixel local storage, writing out to fragment value. - pub pls_init: LazilyCompiledShader, - pub pls_resolve: LazilyCompiledShader, + pub pls_init: Option, + pub pls_resolve: Option, ps_split_composite: LazilyCompiledShader, @@ -592,12 +611,33 @@ impl Shaders { let use_pixel_local_storage = device .get_capabilities() .supports_pixel_local_storage; + // If using PLS, we disable all subpixel AA implicitly. Subpixel AA is always + // disabled on mobile devices anyway, due to uncertainty over the subpixel + // layout configuration. + let use_dual_source_blending = + device.get_capabilities().supports_dual_source_blending && + options.allow_dual_source_blending && + !use_pixel_local_storage; + let use_advanced_blend_equation = + device.get_capabilities().supports_advanced_blend_equation && + options.allow_advanced_blend_equation; + + let mut shader_flags = match gl_type { + GlType::Gl => ShaderFeatureFlags::GL, + GlType::Gles => ShaderFeatureFlags::GLES | ShaderFeatureFlags::TEXTURE_EXTERNAL, + }; + shader_flags.set(ShaderFeatureFlags::PIXEL_LOCAL_STORAGE, use_pixel_local_storage); + shader_flags.set(ShaderFeatureFlags::ADVANCED_BLEND_EQUATION, use_advanced_blend_equation); + shader_flags.set(ShaderFeatureFlags::DUAL_SOURCE_BLENDING, use_dual_source_blending); + shader_flags.set(ShaderFeatureFlags::DITHERING, options.enable_dithering); + let shader_list = get_shader_features(shader_flags); let brush_solid = BrushShader::new( "brush_solid", device, &[], options.precache_flags, + &shader_list, false /* advanced blend */, false /* dual source */, use_pixel_local_storage, @@ -608,6 +648,7 @@ impl Shaders { device, &[], options.precache_flags, + &shader_list, false /* advanced blend */, false /* dual source */, use_pixel_local_storage, @@ -618,6 +659,7 @@ impl Shaders { device, &[], options.precache_flags, + &shader_list, false /* advanced blend */, false /* dual source */, use_pixel_local_storage, @@ -632,6 +674,7 @@ impl Shaders { &[] }, options.precache_flags, + &shader_list, false /* advanced blend */, false /* dual source */, use_pixel_local_storage, @@ -646,6 +689,7 @@ impl Shaders { &[] }, options.precache_flags, + &shader_list, false /* advanced blend */, false /* dual source */, use_pixel_local_storage, @@ -660,6 +704,7 @@ impl Shaders { &[] }, options.precache_flags, + &shader_list, false /* advanced blend */, false /* dual source */, use_pixel_local_storage, @@ -670,6 +715,7 @@ impl Shaders { device, &[], options.precache_flags, + &shader_list, false /* advanced blend */, false /* dual source */, use_pixel_local_storage, @@ -681,6 +727,7 @@ impl Shaders { &["ALPHA_TARGET"], device, options.precache_flags, + &shader_list, )?; let cs_blur_rgba8 = LazilyCompiledShader::new( @@ -689,6 +736,7 @@ impl Shaders { &["COLOR_TARGET"], device, options.precache_flags, + &shader_list, )?; let cs_svg_filter = LazilyCompiledShader::new( @@ -697,6 +745,7 @@ impl Shaders { &[], device, options.precache_flags, + &shader_list, )?; let cs_clip_rectangle_slow = LazilyCompiledShader::new( @@ -705,6 +754,7 @@ impl Shaders { &[], device, options.precache_flags, + &shader_list, )?; let cs_clip_rectangle_fast = LazilyCompiledShader::new( @@ -713,6 +763,7 @@ impl Shaders { &[FAST_PATH_FEATURE], device, options.precache_flags, + &shader_list, )?; let cs_clip_box_shadow = LazilyCompiledShader::new( @@ -721,6 +772,7 @@ impl Shaders { &[], device, options.precache_flags, + &shader_list, )?; let cs_clip_image = LazilyCompiledShader::new( @@ -729,29 +781,34 @@ impl Shaders { &[], device, options.precache_flags, + &shader_list, )?; - let pls_precache_flags = if use_pixel_local_storage { - options.precache_flags + let pls_init = if use_pixel_local_storage { + Some(LazilyCompiledShader::new( + ShaderKind::Resolve, + "pls_init", + &[PIXEL_LOCAL_STORAGE_FEATURE], + device, + options.precache_flags, + &shader_list, + )?) } else { - ShaderPrecacheFlags::empty() + None }; - let pls_init = LazilyCompiledShader::new( - ShaderKind::Resolve, - "pls_init", - &[PIXEL_LOCAL_STORAGE_FEATURE], - device, - pls_precache_flags, - )?; - - let pls_resolve = LazilyCompiledShader::new( - ShaderKind::Resolve, - "pls_resolve", - &[PIXEL_LOCAL_STORAGE_FEATURE], - device, - pls_precache_flags, - )?; + let pls_resolve = if use_pixel_local_storage { + Some(LazilyCompiledShader::new( + ShaderKind::Resolve, + "pls_resolve", + &[PIXEL_LOCAL_STORAGE_FEATURE], + device, + options.precache_flags, + &shader_list, + )?) + } else { + None + }; let cs_scale = LazilyCompiledShader::new( ShaderKind::Cache(VertexArrayKind::Scale), @@ -759,6 +816,7 @@ impl Shaders { &[], device, options.precache_flags, + &shader_list, )?; // TODO(gw): The split composite + text shader are special cases - the only @@ -773,26 +831,27 @@ impl Shaders { device, &extra_features, options.precache_flags, + &shader_list, )?; - let dual_source_precache_flags = if options.allow_dual_source_blending { - options.precache_flags + let ps_text_run_dual_source = if use_dual_source_blending { + Some(TextShader::new("ps_text_run", + device, + &[DUAL_SOURCE_FEATURE], + options.precache_flags, + &shader_list, + )?) } else { - ShaderPrecacheFlags::empty() + None }; - let ps_text_run_dual_source = TextShader::new("ps_text_run", - device, - &[DUAL_SOURCE_FEATURE], - dual_source_precache_flags, - )?; - let ps_split_composite = LazilyCompiledShader::new( ShaderKind::Primitive, "ps_split_composite", &extra_features, device, options.precache_flags, + &shader_list, )?; // All image configuration. @@ -819,8 +878,9 @@ impl Shaders { device, &image_features, options.precache_flags, - options.allow_advanced_blend_equation, - options.allow_dual_source_blending, + &shader_list, + use_advanced_blend_equation, + use_dual_source_blending, use_pixel_local_storage, )?); @@ -832,8 +892,9 @@ impl Shaders { device, &image_features, options.precache_flags, - options.allow_advanced_blend_equation, - options.allow_dual_source_blending, + &shader_list, + use_advanced_blend_equation, + use_dual_source_blending, use_pixel_local_storage, )?); @@ -864,6 +925,7 @@ impl Shaders { device, &yuv_features, options.precache_flags, + &shader_list, false /* advanced blend */, false /* dual source */, use_pixel_local_storage, @@ -875,6 +937,7 @@ impl Shaders { &yuv_features, device, options.precache_flags, + &shader_list, )?; let index = Self::get_yuv_shader_index( @@ -893,6 +956,7 @@ impl Shaders { &[], device, options.precache_flags, + &shader_list, )?; let cs_gradient = LazilyCompiledShader::new( @@ -901,6 +965,7 @@ impl Shaders { &[], device, options.precache_flags, + &shader_list, )?; let cs_border_segment = LazilyCompiledShader::new( @@ -909,6 +974,7 @@ impl Shaders { &[], device, options.precache_flags, + &shader_list, )?; let cs_border_solid = LazilyCompiledShader::new( @@ -917,6 +983,7 @@ impl Shaders { &[], device, options.precache_flags, + &shader_list, )?; let composite_rgba = LazilyCompiledShader::new( @@ -925,6 +992,7 @@ impl Shaders { &[], device, options.precache_flags, + &shader_list, )?; Ok(Shaders { @@ -1036,7 +1104,7 @@ impl Shaders { } BatchKind::TextRun(glyph_format) => { let text_shader = match key.blend_mode { - BlendMode::SubpixelDualSource => &mut self.ps_text_run_dual_source, + BlendMode::SubpixelDualSource => self.ps_text_run_dual_source.as_mut().unwrap(), _ => &mut self.ps_text_run, }; text_shader.get(glyph_format, debug_flags) @@ -1060,10 +1128,16 @@ impl Shaders { self.cs_clip_rectangle_fast.deinit(device); self.cs_clip_box_shadow.deinit(device); self.cs_clip_image.deinit(device); - self.pls_init.deinit(device); - self.pls_resolve.deinit(device); + if let Some(shader) = self.pls_init { + shader.deinit(device); + } + if let Some(shader) = self.pls_resolve { + shader.deinit(device); + } self.ps_text_run.deinit(device); - self.ps_text_run_dual_source.deinit(device); + if let Some(shader) = self.ps_text_run_dual_source { + shader.deinit(device); + } for shader in self.brush_image { if let Some(shader) = shader { shader.deinit(device); diff --git a/webrender_build/Cargo.toml b/webrender_build/Cargo.toml index 411118dc3f..e8637996b1 100644 --- a/webrender_build/Cargo.toml +++ b/webrender_build/Cargo.toml @@ -11,4 +11,5 @@ edition = "2018" serialize_program = ["serde"] [dependencies] +bitflags = "1.2" serde = { optional = true, version = "1.0", features = ["serde_derive"] } diff --git a/webrender_build/src/lib.rs b/webrender_build/src/lib.rs index 0abd144725..1d6f19797e 100644 --- a/webrender_build/src/lib.rs +++ b/webrender_build/src/lib.rs @@ -2,8 +2,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#[macro_use] +extern crate bitflags; + #[cfg(any(feature = "serde"))] #[macro_use] extern crate serde; pub mod shader; +mod shader_features; diff --git a/webrender_build/src/shader.rs b/webrender_build/src/shader.rs index 48367f3658..a564ef2591 100644 --- a/webrender_build/src/shader.rs +++ b/webrender_build/src/shader.rs @@ -14,6 +14,8 @@ use std::path::Path; use std::collections::HashSet; use std::collections::hash_map::DefaultHasher; +pub use crate::shader_features::*; + #[derive(PartialEq, Eq, Hash, Debug, Clone, Default)] #[cfg_attr(feature = "serialize_program", derive(Deserialize, Serialize))] pub struct ProgramSourceDigest(u64); diff --git a/webrender_build/src/shader_features.rs b/webrender_build/src/shader_features.rs new file mode 100644 index 0000000000..997616b0f4 --- /dev/null +++ b/webrender_build/src/shader_features.rs @@ -0,0 +1,146 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::collections::HashMap; + +bitflags! { + #[derive(Default)] + pub struct ShaderFeatureFlags: u32 { + const GL = 1 << 0; + const GLES = 1 << 1; + + const ADVANCED_BLEND_EQUATION = 1 << 8; + const DUAL_SOURCE_BLENDING = 1 << 9; + const PIXEL_LOCAL_STORAGE = 1 << 10; + const DITHERING = 1 << 11; + const TEXTURE_EXTERNAL = 1 << 12; + } +} + +pub type ShaderFeatures = HashMap<&'static str, Vec>; + +macro_rules! features { + ($($str:expr),*) => { vec![$(String::from($str),)*] as Vec }; +} + +fn concat_features(a: &str, b: &str) -> String { + if a.is_empty() { + b.to_string() + } else if b.is_empty() { + a.to_string() + } else { + [a, b].join(",") + } +} + +/// Computes available shaders and their features for the given feature flags. +pub fn get_shader_features(flags: ShaderFeatureFlags) -> ShaderFeatures { + let mut shaders = ShaderFeatures::new(); + + // Clip shaders + shaders.insert("cs_clip_rectangle", features!["", "FAST_PATH"]); + for name in &["cs_clip_image", "cs_clip_box_shadow"] { + shaders.insert(name, features![""]); + } + + // Cache shaders + shaders.insert("cs_blur", features!["ALPHA_TARGET", "COLOR_TARGET"]); + + for name in &["cs_line_decoration", "cs_gradient", "cs_border_segment", "cs_border_solid", "cs_svg_filter"] { + shaders.insert(name, features![""]); + } + + shaders.insert("cs_scale", features![""]); + + // Pixel local storage shaders + let pls_feature = if flags.contains(ShaderFeatureFlags::PIXEL_LOCAL_STORAGE) { + for name in &["pls_init", "pls_resolve"] { + shaders.insert(name, features!["PIXEL_LOCAL_STORAGE"]); + } + + "PIXEL_LOCAL_STORAGE" + } else { + "" + }; + + // Brush shaders + let brush_alpha_features = concat_features("ALPHA_PASS", pls_feature); + for name in &["brush_solid", "brush_blend", "brush_mix_blend", "brush_opacity"] { + shaders.insert(name, features!["", &brush_alpha_features, "DEBUG_OVERDRAW"]); + } + for name in &["brush_conic_gradient", "brush_radial_gradient", "brush_linear_gradient"] { + let mut features: Vec = Vec::new(); + let base = if flags.contains(ShaderFeatureFlags::DITHERING) { + "DITHERING" + } else { + "" + }; + features.push(base.to_string()); + features.push(concat_features(base, &brush_alpha_features)); + features.push(concat_features(base, "DEBUG_OVERDRAW")); + shaders.insert(name, features); + } + + // Image brush shaders + let mut texture_types = vec!["", "TEXTURE_2D"]; + if flags.contains(ShaderFeatureFlags::GL) { + texture_types.push("TEXTURE_RECT"); + } + if flags.contains(ShaderFeatureFlags::TEXTURE_EXTERNAL) { + texture_types.push("TEXTURE_EXTERNAL"); + } + let mut image_features: Vec = Vec::new(); + for texture_type in &texture_types { + let fast = texture_type.to_string(); + image_features.push(fast.clone()); + image_features.push(concat_features(&fast, &brush_alpha_features)); + image_features.push(concat_features(&fast, "DEBUG_OVERDRAW")); + let slow = concat_features(texture_type, "REPETITION,ANTIALIASING"); + image_features.push(slow.clone()); + image_features.push(concat_features(&slow, &brush_alpha_features)); + image_features.push(concat_features(&slow, "DEBUG_OVERDRAW")); + if flags.contains(ShaderFeatureFlags::ADVANCED_BLEND_EQUATION) { + let advanced_blend_features = concat_features(&brush_alpha_features, "ADVANCED_BLEND"); + image_features.push(concat_features(&fast, &advanced_blend_features)); + image_features.push(concat_features(&slow, &advanced_blend_features)); + } + if flags.contains(ShaderFeatureFlags::DUAL_SOURCE_BLENDING) { + let dual_source_features = concat_features(&brush_alpha_features, "DUAL_SOURCE_BLENDING"); + image_features.push(concat_features(&fast, &dual_source_features)); + image_features.push(concat_features(&slow, &dual_source_features)); + } + } + shaders.insert("brush_image", image_features); + + // YUV image brush shaders + let mut composite_features: Vec = vec!["".to_string()]; + let mut yuv_features: Vec = Vec::new(); + for texture_type in &texture_types { + let base = concat_features("YUV", texture_type); + composite_features.push(base.clone()); + yuv_features.push(base.clone()); + yuv_features.push(concat_features(&base, &brush_alpha_features)); + yuv_features.push(concat_features(&base, "DEBUG_OVERDRAW")); + } + shaders.insert("composite", composite_features); + shaders.insert("brush_yuv_image", yuv_features); + + // Prim shaders + let mut text_types = vec![pls_feature]; + if flags.contains(ShaderFeatureFlags::DUAL_SOURCE_BLENDING) { + text_types.push("DUAL_SOURCE_BLENDING"); + } + let mut text_features: Vec = Vec::new(); + for text_type in &text_types { + text_features.push(concat_features(text_type, "ALPHA_PASS")); + text_features.push(concat_features(text_type, "GLYPH_TRANSFORM,ALPHA_PASS")); + text_features.push(concat_features(text_type, "DEBUG_OVERDRAW")); + } + shaders.insert("ps_text_run", text_features); + + shaders.insert("ps_split_composite", features![pls_feature]); + + shaders +} + From 691473189c385b02670cbc0930ffa9ee8e71747f Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 25 Mar 2020 03:49:57 +0000 Subject: [PATCH 3/9] Bug 1624396 - update SWGL to use the centralized WR shader list. r=jrmuizel Depends on D67958 Differential Revision: https://phabricator.services.mozilla.com/D67959 [ghsync] From https://hg.mozilla.org/mozilla-central/rev/72cbbe719b5d526b950d77691d36c234d21395fe --- Cargo.lock | 1 + swgl/Cargo.toml | 1 + swgl/build.rs | 75 ++++++++++++------------------------------------- 3 files changed, 20 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41bbabbb42..7758842697 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1542,6 +1542,7 @@ dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "glsl-to-cxx 0.1.0", + "webrender_build 0.0.1", ] [[package]] diff --git a/swgl/Cargo.toml b/swgl/Cargo.toml index 55df40ccba..eaed858855 100644 --- a/swgl/Cargo.toml +++ b/swgl/Cargo.toml @@ -9,6 +9,7 @@ description = "Software OpenGL implementation for WebRender." [build-dependencies] cc = "1.0.46" glsl-to-cxx = { path = "../glsl-to-cxx" } +webrender_build = { path = "../webrender_build" } [dependencies] gleam = "0.10.0" diff --git a/swgl/build.rs b/swgl/build.rs index 82050e6e6c..4174a1769b 100644 --- a/swgl/build.rs +++ b/swgl/build.rs @@ -4,12 +4,14 @@ extern crate cc; extern crate glsl_to_cxx; +extern crate webrender_build; use std::collections::HashSet; use std::fmt::Write; +use webrender_build::shader::{ShaderFeatureFlags, get_shader_features}; -fn write_load_shader(shader_keys: &[&str]) { - let shaders: Vec<_> = shader_keys.iter().map(|s| s.replace(':', "_")).collect(); +fn write_load_shader(shader_keys: &[String]) { + let shaders: Vec<_> = shader_keys.iter().map(|s| s.replace(',', "_")).collect(); let mut load_shader = String::new(); for s in &shaders { let _ = write!(load_shader, "#include \"{}.h\"\n", s); @@ -48,7 +50,7 @@ fn translate_shader(shader_key: &str, shader_dir: &str) { imported.push_str("#define SWGL 1\n"); imported.push_str("#define WR_MAX_VERTEX_TEXTURE_WIDTH 1024U\n"); - let mut features = shader_key.split(':'); + let mut features = shader_key.split(','); let basename = features.next().unwrap(); for feature in features { let _ = write!(imported, "#define WR_FEATURE_{}\n", feature); @@ -56,7 +58,7 @@ fn translate_shader(shader_key: &str, shader_dir: &str) { process_imports(shader_dir, basename, &mut HashSet::new(), &mut imported); - let shader = shader_key.replace(':', "_"); + let shader = shader_key.replace(',', "_"); let out_dir = std::env::var("OUT_DIR").unwrap(); let imp_name = format!("{}/{}.c", out_dir, shader); @@ -94,68 +96,27 @@ fn translate_shader(shader_key: &str, shader_dir: &str) { std::fs::write(format!("{}/{}.h", out_dir, shader), result).unwrap(); } -const WR_SHADERS: &'static [&'static str] = &[ - "brush_blend:ALPHA_PASS", - "brush_blend", - "brush_image:ALPHA_PASS", - "brush_image", - "brush_image:REPETITION:ANTIALIASING:ALPHA_PASS", - "brush_image:REPETITION:ANTIALIASING", - "brush_linear_gradient:ALPHA_PASS", - "brush_linear_gradient:DITHERING:ALPHA_PASS", - "brush_linear_gradient:DITHERING", - "brush_linear_gradient", - "brush_mix_blend:ALPHA_PASS", - "brush_mix_blend", - "brush_opacity:ALPHA_PASS", - "brush_radial_gradient:ALPHA_PASS", - "brush_radial_gradient:DITHERING:ALPHA_PASS", - "brush_radial_gradient:DITHERING", - "brush_radial_gradient", - "brush_solid:ALPHA_PASS", - "brush_solid", - "brush_yuv_image", - "brush_yuv_image:TEXTURE_2D:YUV:NV12", - "brush_yuv_image:YUV", - "brush_yuv_image:YUV:ALPHA_PASS", - "brush_yuv_image:YUV:INTERLEAVED", - "brush_yuv_image:YUV:NV12:ALPHA_PASS", - "brush_yuv_image:YUV:NV12", - "brush_yuv_image:YUV:PLANAR", - "composite", - "composite:YUV", - "cs_blur:ALPHA_TARGET", - "cs_blur:COLOR_TARGET", - "cs_border_segment", - "cs_border_solid", - "cs_clip_box_shadow", - "cs_clip_image", - "cs_clip_rectangle:FAST_PATH", - "cs_clip_rectangle", - "cs_gradient", - "cs_line_decoration", - "cs_scale", - "cs_svg_filter", - "debug_color", - "debug_font", - "ps_split_composite", - "ps_text_run:DUAL_SOURCE_BLENDING:ALPHA_PASS", - "ps_text_run:GLYPH_TRANSFORM:ALPHA_PASS", - "ps_text_run:DUAL_SOURCE_BLENDING:GLYPH_TRANSFORM:ALPHA_PASS", - "ps_text_run:ALPHA_PASS", -]; - fn main() { let shader_dir = match std::env::var("MOZ_SRC") { Ok(dir) => dir + "/gfx/wr/webrender/res", Err(_) => std::env::var("CARGO_MANIFEST_DIR").unwrap() + "/../webrender/res", }; - for shader in WR_SHADERS { + let shader_flags = + ShaderFeatureFlags::GL | + ShaderFeatureFlags::DUAL_SOURCE_BLENDING; + let mut shaders: Vec = Vec::new(); + for (name, features) in get_shader_features(shader_flags) { + shaders.extend(features.iter().map(|f| { + if f.is_empty() { name.to_owned() } else { format!("{},{}", name, f) } + })); + } + + for shader in &shaders { translate_shader(shader, &shader_dir); } - write_load_shader(WR_SHADERS); + write_load_shader(&shaders); println!("cargo:rerun-if-changed=src/gl_defs.h"); println!("cargo:rerun-if-changed=src/glsl.h"); From d32f52f09cc00d20c4e0969370dd40931bff9c78 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 25 Mar 2020 03:50:06 +0000 Subject: [PATCH 4/9] Bug 1624396 - add missing texture rectangle support to SWGL. r=jrmuizel Depends on D67959 Differential Revision: https://phabricator.services.mozilla.com/D67960 [ghsync] From https://hg.mozilla.org/mozilla-central/rev/86954fd812617a5b7e5d3e4182184c44b3bb0a33 --- glsl-to-cxx/src/hir.rs | 11 +++++++++-- glsl-to-cxx/src/lib.rs | 8 ++++++-- swgl/src/glsl.h | 29 +++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/glsl-to-cxx/src/hir.rs b/glsl-to-cxx/src/hir.rs index f668c585bb..4c5bdba91a 100644 --- a/glsl-to-cxx/src/hir.rs +++ b/glsl-to-cxx/src/hir.rs @@ -3374,14 +3374,14 @@ pub fn ast_to_hir(state: &mut State, tu: &syntax::TranslationUnit) -> Translatio "texture", None, Type::new(Vec4), - vec![Type::new(Sampler2D), Type::new(Vec3)], + vec![Type::new(Sampler2D), Type::new(Vec2)], ); declare_function( state, "texture", None, Type::new(Vec4), - vec![Type::new(Sampler2D), Type::new(Vec2)], + vec![Type::new(Sampler2DRect), Type::new(Vec2)], ); declare_function( state, @@ -3411,6 +3411,13 @@ pub fn ast_to_hir(state: &mut State, tu: &syntax::TranslationUnit) -> Translatio Type::new(IVec2), vec![Type::new(Sampler2D), Type::new(Int)], ); + declare_function( + state, + "textureSize", + None, + Type::new(IVec2), + vec![Type::new(Sampler2DRect), Type::new(Int)], + ); declare_function( state, diff --git a/glsl-to-cxx/src/lib.rs b/glsl-to-cxx/src/lib.rs index 7ce461abf0..a4b2873380 100644 --- a/glsl-to-cxx/src/lib.rs +++ b/glsl-to-cxx/src/lib.rs @@ -319,6 +319,7 @@ fn write_program_samplers(state: &mut OutputState, uniform_indices: &UniformIndi for (name, (_, tk, storage)) in uniform_indices.iter() { match tk { hir::TypeKind::Sampler2D + | hir::TypeKind::Sampler2DRect | hir::TypeKind::ISampler2D | hir::TypeKind::Sampler2DArray => { write!(state, " "); @@ -344,6 +345,7 @@ fn write_program_samplers(state: &mut OutputState, uniform_indices: &UniformIndi for (name, (index, tk, _)) in uniform_indices.iter() { match tk { hir::TypeKind::Sampler2D + | hir::TypeKind::Sampler2DRect | hir::TypeKind::ISampler2D | hir::TypeKind::Sampler2DArray => { write!(state, " case {}:\n", index); @@ -370,7 +372,8 @@ fn write_bind_textures(state: &mut OutputState, uniforms: &[hir::SymRef]) { hir::SymDecl::Global(hir::StorageClass::Sampler(_format), _, ty, _) => { let name = sym.name.as_str(); match ty.kind { - hir::TypeKind::Sampler2D => write!(state, + hir::TypeKind::Sampler2D + | hir::TypeKind::Sampler2DRect => write!(state, " self->{0} = lookup_sampler(&prog->samplers.{0}_impl, prog->samplers.{0}_slot);\n", name), hir::TypeKind::ISampler2D => write!(state, @@ -2678,7 +2681,8 @@ fn define_texel_fetch_ptr( show_indent(state); if let hir::SymDecl::Global(_, _, ty, _) = &sampler_sym.decl { match ty.kind { - hir::TypeKind::Sampler2D => { + hir::TypeKind::Sampler2D + | hir::TypeKind::Sampler2DRect => { write!( state, "vec4_scalar* {}_{}_fetch = ", diff --git a/swgl/src/glsl.h b/swgl/src/glsl.h index cc94aa3d2d..4de3a12019 100644 --- a/swgl/src/glsl.h +++ b/swgl/src/glsl.h @@ -427,6 +427,10 @@ vec2_scalar make_vec2(float n) { return vec2_scalar{n, n}; } vec2_scalar make_vec2(float x, float y) { return vec2_scalar{x, y}; } +vec2_scalar make_vec2(int32_t x, int32_t y) { + return vec2_scalar{float(x), float(y)}; +} + template vec2 make_vec2(const N& n) { return vec2(n); @@ -1763,6 +1767,9 @@ typedef isampler2D_impl* isampler2D; struct isampler2DRGBA32I_impl : isampler2D_impl {}; typedef isampler2DRGBA32I_impl* isampler2DRGBA32I; +struct sampler2DRect_impl : samplerCommon, samplerFilter {}; +typedef sampler2DRect_impl* sampler2DRect; + struct mat4_scalar; struct mat2_scalar { @@ -2270,6 +2277,13 @@ vec4_scalar texelFetch(sampler2DR8 sampler, ivec2_scalar P, int lod) { 0.0f, 0.0f}; } +vec4 texelFetch(sampler2DRect sampler, ivec2 P) { + P = clamp2D(P, sampler); + assert(sampler->format == TextureFormat::RGBA8); + I32 offset = P.x + P.y * sampler->stride; + return fetchOffsetsRGBA8(sampler, offset); +} + vec4 texelFetch(sampler2DArray sampler, ivec3 P, int lod) { P = clamp2DArray(P, sampler); if (sampler->format == TextureFormat::RGBA32F) { @@ -2643,6 +2657,17 @@ vec4 texture(sampler2D sampler, vec2 P) { } } +vec4 texture(sampler2DRect sampler, vec2 P) { + assert(sampler->format == TextureFormat::RGBA8); + if (sampler->filter == TextureFilter::LINEAR) { + return textureLinearRGBA8(sampler, + P * vec2_scalar{1.0f / sampler->width, 1.0f / sampler->height}); + } else { + ivec2 coord(roundto(P.x, 1.0f), roundto(P.y, 1.0f)); + return texelFetch(sampler, coord); + } +} + vec4 texture(sampler2DArray sampler, vec3 P, Float layer) { assert(0); return vec4(); @@ -2682,6 +2707,10 @@ ivec2_scalar textureSize(sampler2D sampler, int) { return ivec2_scalar{int32_t(sampler->width), int32_t(sampler->height)}; } +ivec2_scalar textureSize(sampler2DRect sampler) { + return ivec2_scalar{int32_t(sampler->width), int32_t(sampler->height)}; +} + ivec4 ivec2::sel(XYZW c1, XYZW c2, XYZW c3, XYZW c4) { return ivec4(select(c1), select(c2), select(c3), select(c4)); } From d64bf045adc538cacb3ec0057db7d0271b4e8dad Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 25 Mar 2020 03:50:15 +0000 Subject: [PATCH 5/9] Bug 1624396 - add necessary trigonometry intrinsics for conic gradients in SWGL. r=jrmuizel Depends on D67960 Differential Revision: https://phabricator.services.mozilla.com/D67961 [ghsync] From https://hg.mozilla.org/mozilla-central/rev/a6414fe1b3ecc526b2c524ae13a00467264bb07b --- glsl-to-cxx/src/hir.rs | 3 +++ swgl/src/glsl.h | 21 ++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/glsl-to-cxx/src/hir.rs b/glsl-to-cxx/src/hir.rs index 4c5bdba91a..e1511e613d 100644 --- a/glsl-to-cxx/src/hir.rs +++ b/glsl-to-cxx/src/hir.rs @@ -3164,6 +3164,9 @@ pub fn ast_to_hir(state: &mut State, tu: &syntax::TranslationUnit) -> Translatio ); declare_function(state, "cos", None, Type::new(Float), vec![Type::new(Float)]); declare_function(state, "sin", None, Type::new(Float), vec![Type::new(Float)]); + declare_function(state, "tan", None, Type::new(Float), vec![Type::new(Float)]); + declare_function(state, "atan", None, Type::new(Float), vec![Type::new(Float)]); + declare_function(state, "atan", None, Type::new(Float), vec![Type::new(Float), Type::new(Float)]); declare_function( state, "clamp", diff --git a/swgl/src/glsl.h b/swgl/src/glsl.h index 4de3a12019..52528adb0b 100644 --- a/swgl/src/glsl.h +++ b/swgl/src/glsl.h @@ -2793,16 +2793,35 @@ float dot(vec2_scalar a, vec2_scalar b) { return a.x * b.x + a.y * b.y; } Float dot(vec2 a, vec2 b) { return a.x * b.x + a.y * b.y; } #define sin __glsl_sin -#define cos __glsl_cos float sin(float x) { return sinf(x); } Float sin(Float v) { return {sinf(v.x), sinf(v.y), sinf(v.z), sinf(v.w)}; } +#define cos __glsl_cos + float cos(float x) { return cosf(x); } Float cos(Float v) { return {cosf(v.x), cosf(v.y), cosf(v.z), cosf(v.w)}; } +#define tan __glsl_tan + +float tan(float x) { return tanf(x); } + +Float tan(Float v) { return {tanf(v.x), tanf(v.y), tanf(v.z), tanf(v.w)}; } + +#define atan __glsl_atan + +float atan(float x) { return atanf(x); } + +Float atan(Float v) { return {atanf(v.x), atanf(v.y), atanf(v.z), atanf(v.w)}; } + +float atan(float a, float b) { return atan2f(a, b); } + +Float atan(Float a, Float b) { + return {atan2f(a.x, b.x), atan2f(a.y, b.y), atan2f(a.z, b.z), atan2f(a.w, b.w)}; +} + bvec4 notEqual(ivec4 a, ivec4 b) { return bvec4(a.x != b.x, a.y != b.y, a.z != b.z, a.w != b.w); } From 6e3a95557bb5fa72790c5b39d252e3e4d7c71957 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 25 Mar 2020 03:50:25 +0000 Subject: [PATCH 6/9] Bug 1624396 - update ANGLE shader validation tests to use centralized WR shader list. r=gw Depends on D67961 Differential Revision: https://phabricator.services.mozilla.com/D67962 [ghsync] From https://hg.mozilla.org/mozilla-central/rev/86555508bdba0ca56663ca9b6ec92079cf06ac21 --- webrender/tests/angle_shader_validation.rs | 122 ++------------------- 1 file changed, 7 insertions(+), 115 deletions(-) diff --git a/webrender/tests/angle_shader_validation.rs b/webrender/tests/angle_shader_validation.rs index 4fbac97209..69548e3766 100644 --- a/webrender/tests/angle_shader_validation.rs +++ b/webrender/tests/angle_shader_validation.rs @@ -4,125 +4,17 @@ extern crate mozangle; extern crate webrender; +extern crate webrender_build; use mozangle::shaders::{BuiltInResources, Output, ShaderSpec, ShaderValidator}; +use webrender_build::shader::{ShaderFeatureFlags, get_shader_features}; // from glslang const FRAGMENT_SHADER: u32 = 0x8B30; const VERTEX_SHADER: u32 = 0x8B31; -struct Shader { - name: &'static str, - features: &'static [&'static str], -} - const SHADER_PREFIX: &str = "#define WR_MAX_VERTEX_TEXTURE_WIDTH 1024U\n"; -const BRUSH_FEATURES: &[&str] = &["", "ALPHA_PASS"]; -const CLIP_FEATURES: &[&str] = &[""]; -const FAST_CLIP_FEATURES: &[&str] = &["FAST_PATH"]; -const CACHE_FEATURES: &[&str] = &[""]; -const GRADIENT_FEATURES: &[&str] = &[ "", "DITHERING", "ALPHA_PASS", "DITHERING,ALPHA_PASS" ]; -const PRIM_FEATURES: &[&str] = &[""]; - -const SHADERS: &[Shader] = &[ - // Clip mask shaders - Shader { - name: "cs_clip_rectangle", - features: CLIP_FEATURES, - }, - Shader { - name: "cs_clip_rectangle", - features: FAST_CLIP_FEATURES, - }, - Shader { - name: "cs_clip_image", - features: CLIP_FEATURES, - }, - Shader { - name: "cs_clip_box_shadow", - features: CLIP_FEATURES, - }, - // Cache shaders - Shader { - name: "cs_blur", - features: &[ "ALPHA_TARGET", "COLOR_TARGET" ], - }, - Shader { - name: "cs_border_segment", - features: CACHE_FEATURES, - }, - Shader { - name: "cs_line_decoration", - features: CACHE_FEATURES, - }, - Shader { - name: "cs_gradient", - features: CACHE_FEATURES, - }, - Shader { - name: "cs_border_solid", - features: CACHE_FEATURES, - }, - Shader { - name: "cs_svg_filter", - features: CACHE_FEATURES, - }, - // Prim shaders - Shader { - name: "ps_split_composite", - features: PRIM_FEATURES, - }, - Shader { - name: "ps_text_run", - features: &[ "", "GLYPH_TRANSFORM" ], - }, - // Brush shaders - Shader { - name: "brush_yuv_image", - features: &[ - "", - "YUV_NV12", - "YUV_PLANAR", - "YUV_INTERLEAVED", - "TEXTURE_2D,YUV_NV12", - "YUV_NV12,ALPHA_PASS", - ], - }, - Shader { - name: "brush_solid", - features: BRUSH_FEATURES, - }, - Shader { - name: "brush_image", - features: BRUSH_FEATURES, - }, - Shader { - name: "brush_blend", - features: BRUSH_FEATURES, - }, - Shader { - name: "brush_mix_blend", - features: BRUSH_FEATURES, - }, - Shader { - name: "brush_conic_gradient", - features: GRADIENT_FEATURES, - }, - Shader { - name: "brush_radial_gradient", - features: GRADIENT_FEATURES, - }, - Shader { - name: "brush_linear_gradient", - features: GRADIENT_FEATURES, - }, - Shader { - name: "brush_opacity", - features: BRUSH_FEATURES, - }, -]; - const VERSION_STRING: &str = "#version 300 es\n"; #[test] @@ -136,8 +28,8 @@ fn validate_shaders() { let fs_validator = ShaderValidator::new(FRAGMENT_SHADER, ShaderSpec::Gles3, Output::Essl, &resources).unwrap(); - for shader in SHADERS { - for config in shader.features { + for (shader, configs) in get_shader_features(ShaderFeatureFlags::GLES) { + for config in configs { let mut features = String::new(); features.push_str(SHADER_PREFIX); @@ -146,10 +38,10 @@ fn validate_shaders() { } let (vs, fs) = - webrender::build_shader_strings(VERSION_STRING, &features, shader.name, None); + webrender::build_shader_strings(VERSION_STRING, &features, shader, None); - validate(&vs_validator, shader.name, vs); - validate(&fs_validator, shader.name, fs); + validate(&vs_validator, shader, vs); + validate(&fs_validator, shader, fs); } } } From 6f2e8994c413743eb18bd90205fe465fba05047e Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 25 Mar 2020 03:50:34 +0000 Subject: [PATCH 7/9] Bug 1624565 - Eagerly deallocate empty texture arrays in the texture cache. r=gw We already have a cooldown from texture cache items being deallocated a certain amount of time and frames after their last use so we can deallocate texture arrays as soon as they are completely empty. We do this at the end of the frame to avoid deallocating and reallocating within the frame. It's better to reclaim texture memory this way than run into maybe_reclaim_shared_memory which will throw away everything and cause new allocations on the next frame. Differential Revision: https://phabricator.services.mozilla.com/D68050 [ghsync] From https://hg.mozilla.org/mozilla-central/rev/cb7a03e737951349193fb99410bb907991f7bc35 --- webrender/src/texture_cache.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/webrender/src/texture_cache.rs b/webrender/src/texture_cache.rs index 418383d997..fda8813d06 100644 --- a/webrender/src/texture_cache.rs +++ b/webrender/src/texture_cache.rs @@ -957,6 +957,11 @@ impl TextureCache { self.expire_old_entries(EntryKind::Standalone, threshold); self.expire_old_entries(EntryKind::Picture, threshold); + self.shared_textures.array_alpha8_linear.release_empty_textures(&mut self.pending_updates); + self.shared_textures.array_alpha16_linear.release_empty_textures(&mut self.pending_updates); + self.shared_textures.array_color8_linear.release_empty_textures(&mut self.pending_updates); + self.shared_textures.array_color8_nearest.release_empty_textures(&mut self.pending_updates); + self.shared_textures.array_alpha8_linear .update_profile(&mut texture_cache_profile.pages_alpha8_linear); self.shared_textures.array_alpha16_linear @@ -1731,6 +1736,10 @@ impl TextureArrayUnit { region.slab_size == slab_size && !region.free_slots.is_empty() }) } + + fn is_empty(&self) -> bool { + self.empty_regions == self.regions.len() + } } /// A texture array contains a number of textures, each with a number of @@ -1778,6 +1787,18 @@ impl TextureArray { } } + fn release_empty_textures(&mut self, updates: &mut TextureUpdateList) { + self.units.retain(|unit| { + if unit.is_empty() { + updates.push_free(unit.texture_id); + + false + } else { + true + } + }); + } + fn update_profile(&self, counter: &mut ResourceProfileCounter) { let num_regions: usize = self.units.iter().map(|u| u.regions.len()).sum(); counter.set(num_regions, self.size_in_bytes()); From 1d3ee1b263ccc325a8e47ea9e6b8549fe9cdbc4b Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 25 Mar 2020 03:50:44 +0000 Subject: [PATCH 8/9] Bug 1624565 - Avoid clearing the texture cache as often. r=gw The current heuristic in TextureCache::maybe_reclaim_shared_memory pretty much clears the cache every 5 seconds. Clearing the cache is prtty drastic though, because it causes us to re-upload data and reallocate several textures on the next frame. We really only want to do it when the savings are big, which happens less often now that texture array layer count is capped at 16 and that textures are released as soon as they are empty. This makes us clear the cache less often by augmenting the threshold to 16 megabytes and only considering texture regions that would not be reallocated right away (since we grow some texture arrays more than one region at a time). Differential Revision: https://phabricator.services.mozilla.com/D68051 [ghsync] From https://hg.mozilla.org/mozilla-central/rev/61582f6d817a401e12c32340873d3d781e6cfaf2 --- webrender/src/texture_cache.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/webrender/src/texture_cache.rs b/webrender/src/texture_cache.rs index fda8813d06..d1d52c0664 100644 --- a/webrender/src/texture_cache.rs +++ b/webrender/src/texture_cache.rs @@ -41,7 +41,7 @@ const TEXTURE_REGION_PIXELS: usize = // The minimum number of bytes that we must be able to reclaim in order // to justify clearing the entire shared cache in order to shrink it. -const RECLAIM_THRESHOLD_BYTES: usize = 5 * 1024 * 1024; +const RECLAIM_THRESHOLD_BYTES: usize = 16 * 512 * 512 * 4; /// Items in the texture cache can either be standalone textures, /// or a sub-rect inside the shared cache. @@ -315,11 +315,11 @@ impl SharedTextures { } /// Returns the cumulative number of GPU bytes consumed by empty regions. - fn empty_region_bytes(&self) -> usize { - self.array_alpha8_linear.empty_region_bytes() + - self.array_alpha16_linear.empty_region_bytes() + - self.array_color8_linear.empty_region_bytes() + - self.array_color8_nearest.empty_region_bytes() + fn reclaimable_region_bytes(&self) -> usize { + self.array_alpha8_linear.reclaimable_region_bytes() + + self.array_alpha16_linear.reclaimable_region_bytes() + + self.array_color8_linear.reclaimable_region_bytes() + + self.array_color8_nearest.reclaimable_region_bytes() } /// Clears each texture in the set, with the given set of pending updates. @@ -904,7 +904,7 @@ impl TextureCache { // self.require_frame_build flag which is set if we end up calling // clear_shared. debug_assert!(!self.now.is_valid()); - if self.shared_textures.empty_region_bytes() >= RECLAIM_THRESHOLD_BYTES { + if self.shared_textures.reclaimable_region_bytes() >= RECLAIM_THRESHOLD_BYTES { self.reached_reclaim_threshold.get_or_insert(time); } else { self.reached_reclaim_threshold = None; @@ -912,6 +912,7 @@ impl TextureCache { if let Some(t) = self.reached_reclaim_threshold { let dur = time.duration_since(t).unwrap_or_default(); if dur >= Duration::from_secs(5) { + println!("#n !! reclaim shared memory"); self.clear_shared(); self.reached_reclaim_threshold = None; } @@ -935,6 +936,7 @@ impl TextureCache { let do_periodic_gc = time_since_last_gc >= Duration::from_secs(5) && self.shared_textures.size_in_bytes() >= RECLAIM_THRESHOLD_BYTES * 2; if do_periodic_gc { + println!("#n ######## periodic GC"); let threshold = EvictionThresholdBuilder::new(self.now) .max_frames(1) .max_time_s(10) @@ -1775,7 +1777,7 @@ impl TextureArray { } /// Returns the number of GPU bytes consumed by empty regions. - fn empty_region_bytes(&self) -> usize { + fn reclaimable_region_bytes(&self) -> usize { let bpp = self.formats.internal.bytes_per_pixel() as usize; let empty_regions: usize = self.units.iter().map(|u| u.empty_regions).sum(); empty_regions * TEXTURE_REGION_PIXELS * bpp From 031268a9e0fbf8fd5d56d6676727df85c195a85e Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 25 Mar 2020 03:50:55 +0000 Subject: [PATCH 9/9] Bug 1624640 - Grow the alpha8 texture array four layers at a time. r=jrmuizel The texture array is currently grown layer by layer and we typically get to 3 or 4 layers over several frames by the time we are done loading a simple wikipedia page. Differential Revision: https://phabricator.services.mozilla.com/D68056 [ghsync] From https://hg.mozilla.org/mozilla-central/rev/167562affb96a1777609f6c6bb6f0a1dab520309 --- webrender/src/texture_cache.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrender/src/texture_cache.rs b/webrender/src/texture_cache.rs index d1d52c0664..f9ee1f6179 100644 --- a/webrender/src/texture_cache.rs +++ b/webrender/src/texture_cache.rs @@ -280,7 +280,7 @@ impl SharedTextures { array_alpha8_linear: TextureArray::new( TextureFormatPair::from(ImageFormat::R8), TextureFilter::Linear, - 1, + 4, ), // Used for experimental hdr yuv texture support, but not used in // production Firefox.