diff --git a/gfx/wr/Cargo.lock b/gfx/wr/Cargo.lock index 4c97e824fdc4..4e9eef45e805 100644 --- a/gfx/wr/Cargo.lock +++ b/gfx/wr/Cargo.lock @@ -1848,6 +1848,7 @@ dependencies = [ "env_logger", "font-loader", "gleam 0.13.1", + "glsl", "glutin", "image", "log", diff --git a/gfx/wr/ci-scripts/linux-release-tests.sh b/gfx/wr/ci-scripts/linux-release-tests.sh index 665fc88b5fe1..3a14cee3cb6e 100755 --- a/gfx/wr/ci-scripts/linux-release-tests.sh +++ b/gfx/wr/ci-scripts/linux-release-tests.sh @@ -16,9 +16,10 @@ set -o xtrace CARGOFLAGS=${CARGOFLAGS:-""} # default to empty if not set pushd wrench -# Test that all shaders compile successfully. +# Test that all shaders compile successfully and pass tests. python script/headless.py --precache test_init python script/headless.py --precache --use-unoptimized-shaders test_init +python script/headless.py test_shaders python script/headless.py reftest python script/headless.py rawtest diff --git a/gfx/wr/ci-scripts/macos-release-tests.sh b/gfx/wr/ci-scripts/macos-release-tests.sh index 5eb22c9f8890..c92fe4377f90 100755 --- a/gfx/wr/ci-scripts/macos-release-tests.sh +++ b/gfx/wr/ci-scripts/macos-release-tests.sh @@ -20,9 +20,10 @@ WRENCH_BINARY=${WRENCH_BINARY:-""} pushd wrench -# Test that all shaders compile successfully. +# Test that all shaders compile successfully and pass tests. python script/headless.py --precache test_init python script/headless.py --precache --use-unoptimized-shaders test_init +python script/headless.py test_shaders python script/headless.py reftest python script/headless.py test_invalidation diff --git a/gfx/wr/ci-scripts/windows-tests.cmd b/gfx/wr/ci-scripts/windows-tests.cmd index cf3997b11b7e..fcafcf2b902a 100755 --- a/gfx/wr/ci-scripts/windows-tests.cmd +++ b/gfx/wr/ci-scripts/windows-tests.cmd @@ -21,12 +21,15 @@ popd pushd wrench cargo test --verbose if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL% -:: Test that all shaders compile successfully. --precache compiles all shaders -:: during initialization, therefore if init is successful then the shaders compile. +:: Test that all shaders compile successfully and pass tests. +:: --precache compiles all shaders during initialization, therefore if init +:: is successful then the shaders compile. cargo run --release -- --angle --precache test_init if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL% cargo run --release -- --angle --precache --use-unoptimized-shaders test_init if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL% +cargo run --release -- --angle test_shaders +if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL% cargo run --release -- --angle reftest if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL% diff --git a/gfx/wr/webrender/src/lib.rs b/gfx/wr/webrender/src/lib.rs index 492bf249e1ea..2c9a63b24552 100644 --- a/gfx/wr/webrender/src/lib.rs +++ b/gfx/wr/webrender/src/lib.rs @@ -137,7 +137,7 @@ pub mod intern; /// pub mod render_api; -mod shader_source { +pub mod shader_source { include!(concat!(env!("OUT_DIR"), "/shaders.rs")); } diff --git a/gfx/wr/wrench/Cargo.toml b/gfx/wr/wrench/Cargo.toml index 7d2345be43bd..31d02c9a9a26 100644 --- a/gfx/wr/wrench/Cargo.toml +++ b/gfx/wr/wrench/Cargo.toml @@ -12,6 +12,7 @@ env_logger = { version = "0.5", optional = true } gleam = "0.13" glutin = "0.21" clap = { version = "2", features = ["yaml"] } +glsl = "4.0" log = "0.4" yaml-rust = "0.4" serde_json = "1.0" diff --git a/gfx/wr/wrench/src/args.yaml b/gfx/wr/wrench/src/args.yaml index 469bba889ce2..f55a4195718a 100644 --- a/gfx/wr/wrench/src/args.yaml +++ b/gfx/wr/wrench/src/args.yaml @@ -184,3 +184,5 @@ subcommands: index: 2 - test_init: about: Test for successful initialization then exit immediately + - test_shaders: + about: run shader tests diff --git a/gfx/wr/wrench/src/main.rs b/gfx/wr/wrench/src/main.rs index 5481e3c6965c..bd477f15828a 100644 --- a/gfx/wr/wrench/src/main.rs +++ b/gfx/wr/wrench/src/main.rs @@ -21,6 +21,7 @@ mod premultiply; mod rawtest; mod reftest; mod test_invalidation; +mod test_shaders; mod wrench; mod yaml_frame_reader; mod yaml_helper; @@ -757,6 +758,8 @@ fn main() { // Wrench::new() unwraps the Renderer initialization, so if // we reach this point then we have initialized successfully. println!("Initialization successful"); + } else if let Some(_) = args.subcommand_matches("test_shaders") { + test_shaders::test_shaders(); } else { panic!("Should never have gotten here! {:?}", args); }; diff --git a/gfx/wr/wrench/src/test_shaders.rs b/gfx/wr/wrench/src/test_shaders.rs new file mode 100644 index 000000000000..fad6a23b0595 --- /dev/null +++ b/gfx/wr/wrench/src/test_shaders.rs @@ -0,0 +1,67 @@ +/* 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 webrender::shader_source::OPTIMIZED_SHADERS; +use glsl::parser::Parse as _; +use glsl::syntax::{InterpolationQualifier, ShaderStage, SingleDeclaration}; +use glsl::syntax::{TypeSpecifierNonArray, TypeQualifierSpec}; +use glsl::visitor::{Host, Visit, Visitor}; + +/// Tests that a shader contains no flat scalar varyings. +/// These must be avoided on Adreno 3xx devices due to bug 1630356. +fn test_no_flat_scalar_varyings(name: &str, shader: &mut ShaderStage) { + struct FlatScalarVaryingsVisitor { + shader_name: String, + } + + impl Visitor for FlatScalarVaryingsVisitor { + fn visit_single_declaration(&mut self, declaration: &mut SingleDeclaration) -> Visit { + let is_scalar = match declaration.ty.ty.ty { + TypeSpecifierNonArray::Bool + | TypeSpecifierNonArray::Int + | TypeSpecifierNonArray::UInt + | TypeSpecifierNonArray::Float + | TypeSpecifierNonArray::Double => true, + _ => false, + }; + + let qualifiers = declaration + .ty + .qualifier + .as_ref() + .map(|q| q.qualifiers.0.as_slice()) + .unwrap_or(&[]); + + let is_flat = qualifiers.contains(&TypeQualifierSpec::Interpolation( + InterpolationQualifier::Flat, + )); + + assert!( + !(is_scalar && is_flat), + "{}: {} is a flat scalar varying", + self.shader_name, + &declaration.name.as_ref().unwrap() + ); + + Visit::Parent + } + } + + let mut visitor = FlatScalarVaryingsVisitor { + shader_name: name.to_string(), + }; + shader.visit(&mut visitor); +} + +pub fn test_shaders() { + for ((_version, name), shader) in OPTIMIZED_SHADERS.iter() { + let mut vert = ShaderStage::parse(shader.vert_source).unwrap(); + let mut frag = ShaderStage::parse(shader.frag_source).unwrap(); + + if cfg!(target_os = "android") { + test_no_flat_scalar_varyings(&format!("{}.vert", name), &mut vert); + test_no_flat_scalar_varyings(&format!("{}.frag", name), &mut frag); + } + } +} diff --git a/testing/mozharness/scripts/android_wrench.py b/testing/mozharness/scripts/android_wrench.py index 51996c706709..e8f97f57f84e 100644 --- a/testing/mozharness/scripts/android_wrench.py +++ b/testing/mozharness/scripts/android_wrench.py @@ -29,7 +29,8 @@ from mozharness.mozilla.testing.testbase import TestingMixin class TestMode(enum.Enum): OPTIMIZED_SHADER_COMPILATION = 0 UNOPTIMIZED_SHADER_COMPILATION = 1 - REFTEST = 2 + SHADER_TEST = 2 + REFTEST = 3 class AndroidWrench(TestingMixin, BaseScript, MozbaseMixin, AndroidMixin): @@ -171,6 +172,8 @@ class AndroidWrench(TestingMixin, BaseScript, MozbaseMixin, AndroidMixin): argfile.write("--precache test_init") elif test_mode == TestMode.UNOPTIMIZED_SHADER_COMPILATION: argfile.write("--precache --use-unoptimized-shaders test_init") + elif test_mode == TestMode.SHADER_TEST: + argfile.write("--precache test_shaders") elif test_mode == TestMode.REFTEST: argfile.write("reftest") self.device.push(args_file, "/sdcard/wrench/args") @@ -272,6 +275,12 @@ class AndroidWrench(TestingMixin, BaseScript, MozbaseMixin, AndroidMixin): self.info("Running unoptimized shader compilation tests...") self.run_tests(60) + if not self._errored: + self.info("Setting up SD card...") + self.setup_sdcard(TestMode.SHADER_TEST) + self.info("Running shader tests...") + self.run_tests(60) + if not self._errored: self.info("Setting up SD card...") self.setup_sdcard(TestMode.REFTEST)