tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_shaders.rs (6072B)


      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 webrender::ShaderKind;
      6 use webrender_build::shader::{ShaderFeatureFlags, ShaderVersion, build_shader_strings};
      7 use webrender_build::shader::get_shader_features;
      8 use glsl_lang::ast::{InterpolationQualifierData, NodeContent, SingleDeclaration};
      9 use glsl_lang::ast::{StorageQualifierData, TranslationUnit, TypeSpecifierNonArrayData};
     10 use glsl_lang::ast::TypeQualifierSpecData;
     11 use glsl_lang::parse::DefaultParse as _;
     12 use glsl_lang::visitor::{Host, Visit, Visitor};
     13 
     14 /// Tests that a shader contains no flat scalar varyings.
     15 /// These must be avoided on Adreno 3xx devices due to bug 1630356.
     16 fn test_no_flat_scalar_varyings(
     17    name: &str,
     18    shader: &mut TranslationUnit,
     19    _shader_kind: ShaderKind,
     20 ) {
     21    struct FlatScalarVaryingsVisitor {
     22        shader_name: String,
     23    }
     24 
     25    impl Visitor for FlatScalarVaryingsVisitor {
     26        fn visit_single_declaration(&mut self, declaration: &SingleDeclaration) -> Visit {
     27            let is_scalar = matches!(
     28                declaration.ty.ty.ty.content,
     29                TypeSpecifierNonArrayData::Bool
     30                    | TypeSpecifierNonArrayData::Int
     31                    | TypeSpecifierNonArrayData::UInt
     32                    | TypeSpecifierNonArrayData::Float
     33                    | TypeSpecifierNonArrayData::Double
     34            );
     35 
     36            let qualifiers = declaration
     37                .ty
     38                .qualifier
     39                .as_ref()
     40                .map(|q| q.qualifiers.as_slice())
     41                .unwrap_or(&[]);
     42 
     43            let is_flat = qualifiers.contains(
     44                &TypeQualifierSpecData::Interpolation(InterpolationQualifierData::Flat.into_node())
     45                    .into_node(),
     46            );
     47 
     48            assert!(
     49                !(is_scalar && is_flat),
     50                "{}: {} is a flat scalar varying",
     51                self.shader_name,
     52                &declaration.name.as_ref().unwrap()
     53            );
     54 
     55            Visit::Parent
     56        }
     57    }
     58 
     59    let mut visitor = FlatScalarVaryingsVisitor {
     60        shader_name: name.to_string(),
     61    };
     62    shader.visit(&mut visitor);
     63 }
     64 
     65 /// Tests that a shader's varyings have an explicit precision specifier.
     66 /// Mali vendor tooling shows us that we are often varying-iterpolation bound, so using mediump
     67 /// where possible helps alleviate this. By enforcing that varyings are given explicit precisions,
     68 /// we ensure that highp is only used when necessary rather than just by default.
     69 fn test_varying_explicit_precision(
     70    name: &str,
     71    shader: &mut TranslationUnit,
     72    shader_kind: ShaderKind,
     73 ) {
     74    struct VaryingExplicitPrecisionVisitor {
     75        shader_name: String,
     76        shader_kind: ShaderKind,
     77    }
     78 
     79    impl Visitor for VaryingExplicitPrecisionVisitor {
     80        fn visit_single_declaration(&mut self, declaration: &SingleDeclaration) -> Visit {
     81            let qualifiers = declaration
     82                .ty
     83                .qualifier
     84                .as_ref()
     85                .map(|q| q.qualifiers.as_slice())
     86                .unwrap_or(&[]);
     87 
     88            let is_varying = qualifiers.iter().any(|qualifier| {
     89                match &qualifier.content {
     90                    TypeQualifierSpecData::Storage(storage) => match self.shader_kind {
     91                        ShaderKind::Vertex => storage.content == StorageQualifierData::Out,
     92                        ShaderKind::Fragment => storage.content == StorageQualifierData::In,
     93                    }
     94                    _ => false,
     95                }
     96            });
     97 
     98            let has_explicit_precision = qualifiers
     99                .iter()
    100                .any(|qualifier| matches!(qualifier.content, TypeQualifierSpecData::Precision(_)));
    101 
    102            assert!(
    103                !is_varying || has_explicit_precision,
    104                "{}: {} is a varying without an explicit precision declared",
    105                self.shader_name,
    106                &declaration.name.as_ref().unwrap()
    107            );
    108 
    109            Visit::Parent
    110        }
    111    }
    112 
    113    let mut visitor = VaryingExplicitPrecisionVisitor {
    114        shader_name: name.to_string(),
    115        shader_kind,
    116    };
    117    shader.visit(&mut visitor);
    118 }
    119 
    120 pub fn test_shaders() {
    121    let mut flags = ShaderFeatureFlags::all();
    122    if cfg!(any(target_os = "windows", target_os = "android")) {
    123        flags.remove(ShaderFeatureFlags::GL);
    124    } else {
    125        flags.remove(ShaderFeatureFlags::GLES);
    126    }
    127    // glsl-lang crate fails to parse advanced blend shaders
    128    flags.remove(ShaderFeatureFlags::ADVANCED_BLEND_EQUATION);
    129    // glsl-lang crate fails to parse texture external BT709 shaders
    130    flags.remove(ShaderFeatureFlags::TEXTURE_EXTERNAL_BT709);
    131 
    132    for (shader, configs) in get_shader_features(flags) {
    133        for config in configs {
    134            let name = if config.is_empty() {
    135                shader.to_string()
    136            } else {
    137                format!("{}_{}", shader, config.replace(",", "_"))
    138            };
    139            let vert_name = format!("{}.vert", name);
    140            let frag_name = format!("{}.frag", name);
    141 
    142 
    143            let features = config
    144                .split(",")
    145                .filter(|f| !f.is_empty())
    146                .collect::<Vec<_>>();
    147 
    148            let (vert_src, frag_src) =
    149                build_shader_strings(ShaderVersion::Gles, &features, shader, &|f| {
    150                    webrender::get_unoptimized_shader_source(f, None)
    151                });
    152 
    153            let mut vert = TranslationUnit::parse(&vert_src).unwrap();
    154            let mut frag = TranslationUnit::parse(&frag_src).unwrap();
    155 
    156 
    157            test_no_flat_scalar_varyings(&vert_name, &mut vert, ShaderKind::Vertex);
    158            test_no_flat_scalar_varyings(&frag_name, &mut frag, ShaderKind::Fragment);
    159            test_varying_explicit_precision(&vert_name, &mut vert, ShaderKind::Vertex);
    160            test_varying_explicit_precision(&frag_name, &mut frag, ShaderKind::Fragment);
    161        }
    162    }
    163 }