tor-browser

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

lib.rs (127389B)


      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 #![allow(unknown_lints, mismatched_lifetime_syntaxes)]
      6 
      7 extern crate glsl;
      8 
      9 mod hir;
     10 
     11 use glsl::parser::Parse;
     12 use glsl::syntax;
     13 use glsl::syntax::{TranslationUnit, UnaryOp};
     14 use hir::{Statement, Type};
     15 use std::cell::{Cell, RefCell};
     16 use std::collections::{BTreeMap, HashMap};
     17 use std::io::Read;
     18 use std::mem;
     19 
     20 #[derive(PartialEq, Eq)]
     21 enum ShaderKind {
     22    Fragment,
     23    Vertex,
     24 }
     25 
     26 type UniformIndices = BTreeMap<String, (i32, hir::TypeKind, hir::StorageClass)>;
     27 
     28 fn build_uniform_indices(indices: &mut UniformIndices, state: &hir::State) {
     29    for u in state.used_globals.borrow().iter() {
     30        let sym = state.sym(*u);
     31        match &sym.decl {
     32            hir::SymDecl::Global(storage, _, ty, _) => match storage {
     33                hir::StorageClass::Uniform | hir::StorageClass::Sampler(..) => {
     34                    let next_index = indices.len() as i32 + 1;
     35                    indices.entry(sym.name.clone()).or_insert((
     36                        next_index,
     37                        ty.kind.clone(),
     38                        *storage,
     39                    ));
     40                }
     41                _ => {}
     42            },
     43            _ => {}
     44        }
     45    }
     46 }
     47 
     48 pub fn translate(args: &mut dyn Iterator<Item = String>) -> String {
     49    let _cmd_name = args.next();
     50    let vertex_file = args.next().unwrap();
     51 
     52    let vs_name = std::path::Path::new(&vertex_file)
     53        .file_stem()
     54        .unwrap()
     55        .to_string_lossy()
     56        .to_string();
     57 
     58    let frag_file = args.next().unwrap();
     59 
     60    let fs_name = std::path::Path::new(&frag_file)
     61        .file_stem()
     62        .unwrap()
     63        .to_string_lossy()
     64        .to_string();
     65 
     66    let (vs_state, vs_hir, vs_is_frag) = parse_shader(vertex_file);
     67    let (fs_state, fs_hir, fs_is_frag) = parse_shader(frag_file);
     68 
     69    // we use a BTree so that iteration is stable
     70    let mut uniform_indices = BTreeMap::new();
     71    build_uniform_indices(&mut uniform_indices, &vs_state);
     72    build_uniform_indices(&mut uniform_indices, &fs_state);
     73 
     74    assert_eq!(fs_name, vs_name);
     75 
     76    let mut result = translate_shader(
     77        vs_name,
     78        vs_state,
     79        vs_hir,
     80        vs_is_frag,
     81        &uniform_indices,
     82    );
     83    result += "\n";
     84    result += &translate_shader(
     85        fs_name,
     86        fs_state,
     87        fs_hir,
     88        fs_is_frag,
     89        &uniform_indices,
     90    );
     91    result
     92 }
     93 
     94 fn parse_shader(file: String) -> (hir::State, hir::TranslationUnit, bool) {
     95    let mut contents = String::new();
     96    let is_frag = file.contains("frag");
     97    std::fs::File::open(&file)
     98        .unwrap()
     99        .read_to_string(&mut contents)
    100        .unwrap();
    101    let r = TranslationUnit::parse(contents);
    102 
    103    //println!("{:#?}", r);
    104    let mut ast_glsl = String::new();
    105    let r = match r {
    106        Ok(ok) => ok,
    107        Err(e) => panic!("failed to parse {:?}: {:?}", file, e),
    108    };
    109    glsl::transpiler::glsl::show_translation_unit(&mut ast_glsl, &r);
    110    //let mut fast = std::fs::File::create("ast").unwrap();
    111    //fast.write(ast_glsl.as_bytes());
    112 
    113    let mut state = hir::State::new();
    114    let hir = hir::ast_to_hir(&mut state, &r);
    115    (state, hir, is_frag)
    116 }
    117 
    118 fn translate_shader(
    119    name: String,
    120    mut state: hir::State,
    121    hir: hir::TranslationUnit,
    122    is_frag: bool,
    123    uniform_indices: &UniformIndices,
    124 ) -> String {
    125    //println!("{:#?}", state);
    126 
    127    hir::infer_run_class(&mut state, &hir);
    128 
    129    let mut uniforms = Vec::new();
    130    let mut inputs = Vec::new();
    131    let mut outputs = Vec::new();
    132 
    133    for i in &hir {
    134        match i {
    135            hir::ExternalDeclaration::Declaration(hir::Declaration::InitDeclaratorList(ref d)) => {
    136                match &state.sym(d.head.name).decl {
    137                    hir::SymDecl::Global(storage, ..)
    138                        if state.used_globals.borrow().contains(&d.head.name) =>
    139                    {
    140                        match storage {
    141                            hir::StorageClass::Uniform | hir::StorageClass::Sampler(..) => {
    142                                uniforms.push(d.head.name);
    143                            }
    144                            hir::StorageClass::In => {
    145                                inputs.push(d.head.name);
    146                            }
    147                            hir::StorageClass::Out | hir::StorageClass::FragColor(_) => {
    148                                outputs.push(d.head.name);
    149                            }
    150                            _ => {}
    151                        }
    152                    }
    153                    _ => {}
    154                }
    155            }
    156            _ => {}
    157        }
    158    }
    159 
    160    //println!("{:#?}", hir);
    161 
    162    let mut state = OutputState {
    163        hir: state,
    164        output: String::new(),
    165        buffer: RefCell::new(String::new()),
    166        indent: 0,
    167        should_indent: false,
    168        output_cxx: false,
    169        mask: None,
    170        cond_index: 0,
    171        return_type: None,
    172        return_declared: false,
    173        return_vector: false,
    174        is_scalar: Cell::new(false),
    175        is_lval: Cell::new(false),
    176        name: name.clone(),
    177        kind: if is_frag {
    178            ShaderKind::Fragment
    179        } else {
    180            ShaderKind::Vertex
    181        },
    182        functions: HashMap::new(),
    183        deps: RefCell::new(Vec::new()),
    184        vector_mask: 0,
    185        uses_discard: false,
    186        used_fragcoord: Cell::new(0),
    187        use_perspective: false,
    188        used_globals: RefCell::new(Vec::new()),
    189        texel_fetches: RefCell::new(Vec::new()),
    190    };
    191 
    192    show_translation_unit(&mut state, &hir);
    193    let _output_glsl = state.finish_output();
    194 
    195    state.should_indent = true;
    196    state.output_cxx = true;
    197 
    198    if state.output_cxx {
    199        let part_name = name.to_owned()
    200            + match state.kind {
    201                ShaderKind::Vertex => "_vert",
    202                ShaderKind::Fragment => "_frag",
    203            };
    204 
    205        if state.kind == ShaderKind::Vertex {
    206            write_common_globals(&mut state, &inputs, &outputs, uniform_indices);
    207            write!(state, "struct {0}_vert : VertexShaderImpl, {0}_common {{\nprivate:\n", name);
    208        } else {
    209            write!(state, "struct {0}_frag : FragmentShaderImpl, {0}_vert {{\nprivate:\n", name);
    210        }
    211 
    212        write!(state, "typedef {} Self;\n", part_name);
    213 
    214        show_translation_unit(&mut state, &hir);
    215 
    216        let pruned_inputs: Vec<_> = inputs
    217            .iter()
    218            .filter(|i| state.used_globals.borrow().contains(i))
    219            .cloned()
    220            .collect();
    221 
    222        if state.kind == ShaderKind::Vertex {
    223            write_set_uniform_1i(&mut state, uniform_indices);
    224            write_set_uniform_4fv(&mut state, uniform_indices);
    225            write_set_uniform_matrix4fv(&mut state, uniform_indices);
    226            write_load_attribs(&mut state, &pruned_inputs);
    227            write_store_outputs(&mut state, &outputs);
    228        } else {
    229            write_read_inputs(&mut state, &pruned_inputs);
    230        }
    231 
    232        write_abi(&mut state);
    233        write!(state, "}};\n\n");
    234 
    235        if state.kind == ShaderKind::Fragment {
    236            write!(state, "struct {0}_program : ProgramImpl, {0}_frag {{\n", name);
    237            write_get_uniform_index(&mut state, uniform_indices);
    238            write!(state, "void bind_attrib(const char* name, int index) override {{\n");
    239            write!(state, " attrib_locations.bind_loc(name, index);\n}}\n");
    240            write!(state, "int get_attrib(const char* name) const override {{\n");
    241            write!(state, " return attrib_locations.get_loc(name);\n}}\n");
    242            write!(state, "size_t interpolants_size() const override {{ return sizeof(InterpOutputs); }}\n");
    243            write!(state, "VertexShaderImpl* get_vertex_shader() override {{\n");
    244            write!(state, " return this;\n}}\n");
    245            write!(state, "FragmentShaderImpl* get_fragment_shader() override {{\n");
    246            write!(state, " return this;\n}}\n");
    247            write!(state, "const char* get_name() const override {{ return \"{}\"; }}\n", name);
    248            write!(state, "static ProgramImpl* loader() {{ return new {}_program; }}\n", name);
    249            write!(state, "}};\n\n");
    250        }
    251 
    252        define_global_consts(&mut state, &hir, &part_name);
    253    } else {
    254        show_translation_unit(&mut state, &hir);
    255    }
    256    let output_cxx = state.finish_output();
    257 
    258    //let mut hir = std::fs::File::create("hir").unwrap();
    259    //hir.write(output_glsl.as_bytes());
    260 
    261    output_cxx
    262 }
    263 
    264 fn write_get_uniform_index(state: &mut OutputState, uniform_indices: &UniformIndices) {
    265    write!(
    266        state,
    267        "int get_uniform(const char *name) const override {{\n"
    268    );
    269    for (uniform_name, (index, _, _)) in uniform_indices.iter() {
    270        write!(
    271            state,
    272            " if (strcmp(\"{}\", name) == 0) {{ return {}; }}\n",
    273            uniform_name, index
    274        );
    275    }
    276    write!(state, " return -1;\n");
    277    write!(state, "}}\n");
    278 }
    279 
    280 fn float4_compatible(ty: hir::TypeKind) -> bool {
    281    match ty {
    282        hir::TypeKind::Vec4 => true,
    283        _ => false,
    284    }
    285 }
    286 
    287 fn matrix4_compatible(ty: hir::TypeKind) -> bool {
    288    match ty {
    289        hir::TypeKind::Mat4 => true,
    290        _ => false,
    291    }
    292 }
    293 
    294 fn write_program_samplers(state: &mut OutputState, uniform_indices: &UniformIndices) {
    295    write!(state, "struct Samplers {{\n");
    296    for (name, (_, tk, storage)) in uniform_indices.iter() {
    297        match tk {
    298            hir::TypeKind::Sampler2D
    299            | hir::TypeKind::Sampler2DRect
    300            | hir::TypeKind::ISampler2D => {
    301                write!(state, " ");
    302                show_type_kind(state, &tk);
    303                let suffix = if let hir::StorageClass::Sampler(format) = storage {
    304                    format.type_suffix()
    305                } else {
    306                    None
    307                };
    308                write!(state, "{}_impl {}_impl;\n", suffix.unwrap_or(""), name);
    309                write!(state, " int {}_slot;\n", name);
    310            }
    311            _ => {}
    312        }
    313    }
    314    write!(
    315        state,
    316        " bool set_slot(int index, int value) {{\n"
    317    );
    318    write!(state, "  switch (index) {{\n");
    319    for (name, (index, tk, _)) in uniform_indices.iter() {
    320        match tk {
    321            hir::TypeKind::Sampler2D
    322            | hir::TypeKind::Sampler2DRect
    323            | hir::TypeKind::ISampler2D => {
    324                write!(state, "  case {}:\n", index);
    325                write!(state, "   {}_slot = value;\n", name);
    326                write!(state, "   return true;\n");
    327            }
    328            _ => {}
    329        }
    330    }
    331    write!(state, "  }}\n");
    332    write!(state, "  return false;\n");
    333    write!(state, " }}\n");
    334    write!(state, "}} samplers;\n");
    335 
    336 }
    337 
    338 fn write_bind_textures(state: &mut OutputState, uniforms: &UniformIndices) {
    339    write!(state, "void bind_textures() {{\n");
    340    for (name, (_, tk, storage)) in uniforms {
    341        match storage {
    342            hir::StorageClass::Sampler(_format) => {
    343                match tk {
    344                    hir::TypeKind::Sampler2D
    345                    | hir::TypeKind::Sampler2DRect => write!(state,
    346                        " {0} = lookup_sampler(&samplers.{0}_impl, samplers.{0}_slot);\n",
    347                        name),
    348                    hir::TypeKind::ISampler2D => write!(state,
    349                        " {0} = lookup_isampler(&samplers.{0}_impl, samplers.{0}_slot);\n",
    350                        name),
    351                    _ => {}
    352                };
    353            }
    354            _ => {}
    355        }
    356    }
    357    write!(state, "}}\n");
    358 }
    359 
    360 fn write_set_uniform_1i(
    361    state: &mut OutputState,
    362    uniforms: &UniformIndices,
    363 ) {
    364    write!(
    365        state,
    366        "static void set_uniform_1i(VertexShaderImpl* impl, int index, int value) {{\n"
    367    );
    368    write!(state, " Self* self = (Self*)impl;\n");
    369    write!(state, " if (self->samplers.set_slot(index, value)) return;\n");
    370    write!(state, " switch (index) {{\n");
    371    for (name, (index, tk, _)) in uniforms {
    372        write!(state, " case {}:\n", index);
    373        match tk {
    374            hir::TypeKind::Int => write!(
    375                state,
    376                "  self->{} = {}(value);\n",
    377                name,
    378                tk.cxx_primitive_scalar_type_name().unwrap(),
    379            ),
    380            _ => write!(state, "  assert(0); // {}\n", name),
    381        };
    382        write!(state, "  break;\n");
    383    }
    384    write!(state, " }}\n");
    385    write!(state, "}}\n");
    386 }
    387 
    388 fn write_set_uniform_4fv(
    389    state: &mut OutputState,
    390    uniforms: &UniformIndices,
    391 ) {
    392    write!(
    393        state,
    394        "static void set_uniform_4fv(VertexShaderImpl* impl, int index, const float *value) {{\n"
    395    );
    396    write!(state, " Self* self = (Self*)impl;\n");
    397    write!(state, " switch (index) {{\n");
    398    for (name, (index, tk, _)) in uniforms {
    399        write!(state, " case {}:\n", index);
    400        if float4_compatible(tk.clone()) {
    401            write!(
    402                state,
    403                "  self->{} = vec4_scalar::load_from_ptr(value);\n",
    404                name
    405            );
    406        } else {
    407            write!(state, "  assert(0); // {}\n", name);
    408        }
    409        write!(state, "  break;\n");
    410    }
    411    write!(state, " }}\n");
    412    write!(state, "}}\n");
    413 }
    414 
    415 fn write_set_uniform_matrix4fv(
    416    state: &mut OutputState,
    417    uniforms: &UniformIndices,
    418 ) {
    419    write!(
    420        state,
    421        "static void set_uniform_matrix4fv(VertexShaderImpl* impl, int index, const float *value) {{\n"
    422    );
    423    write!(state, " Self* self = (Self*)impl;\n");
    424    write!(state, " switch (index) {{\n");
    425    for (name, (index, tk, _)) in uniforms {
    426        write!(state, " case {}:\n", index);
    427        if matrix4_compatible(tk.clone()) {
    428            write!(
    429                state,
    430                "  self->{} = mat4_scalar::load_from_ptr(value);\n",
    431                name
    432            );
    433        } else {
    434            write!(state, "  assert(0); // {}\n", name);
    435        }
    436        write!(state, "  break;\n");
    437    }
    438    write!(state, " }}\n");
    439    write!(state, "}}\n");
    440 }
    441 
    442 fn write_bind_attrib_location(state: &mut OutputState, attribs: &[hir::SymRef]) {
    443    write!(state, "struct AttribLocations {{\n");
    444    for i in attribs {
    445        let sym = state.hir.sym(*i);
    446        write!(state, " int {} = NULL_ATTRIB;\n", sym.name.as_str());
    447    }
    448    write!(state, " void bind_loc(const char* name, int index) {{\n");
    449    for i in attribs {
    450        let sym = state.hir.sym(*i);
    451        write!(
    452            state,
    453            "  if (strcmp(\"{0}\", name) == 0) {{ {0} = index; return; }}\n",
    454            sym.name.as_str()
    455        );
    456    }
    457    write!(state, " }}\n");
    458    write!(state, " int get_loc(const char* name) const {{\n");
    459    for i in attribs {
    460        let sym = state.hir.sym(*i);
    461        write!(state,
    462            "  if (strcmp(\"{0}\", name) == 0) {{ \
    463                return {0} != NULL_ATTRIB ? {0} : -1; \
    464              }}\n",
    465            sym.name.as_str());
    466    }
    467    write!(state, "  return -1;\n");
    468    write!(state, " }}\n");
    469    write!(state, "}} attrib_locations;\n");
    470 }
    471 
    472 fn write_common_globals(state: &mut OutputState, attribs: &[hir::SymRef],
    473                        outputs: &[hir::SymRef], uniforms: &UniformIndices) {
    474    write!(state, "struct {}_common {{\n", state.name);
    475 
    476    write_program_samplers(state, uniforms);
    477    write_bind_attrib_location(state, attribs);
    478 
    479    let is_scalar = state.is_scalar.replace(true);
    480    for i in outputs {
    481        let sym = state.hir.sym(*i);
    482        match &sym.decl {
    483            hir::SymDecl::Global(hir::StorageClass::Out, _, ty, hir::RunClass::Scalar) => {
    484                show_type(state, ty);
    485                write!(state, " {};\n", sym.name.as_str());
    486            }
    487            _ => {}
    488        }
    489    }
    490    for (name, (_, tk, storage)) in uniforms {
    491        match storage {
    492            hir::StorageClass::Sampler(format) => {
    493                write!(state,
    494                       "{}{} {};\n",
    495                       tk.cxx_primitive_type_name().unwrap(),
    496                       format.type_suffix().unwrap_or(""),
    497                       name,
    498                );
    499            }
    500            _ => {
    501                show_type_kind(state, tk);
    502                write!(state, " {};\n", name);
    503            }
    504        }
    505    }
    506    state.is_scalar.set(is_scalar);
    507 
    508    write_bind_textures(state, uniforms);
    509 
    510    write!(state, "}};\n");
    511 }
    512 
    513 //fn type_name(state: &OutputState, ty: &Type) -> String {
    514 //  let buffer = state.push_buffer();
    515 //  show_type(state, ty);
    516 //  state.pop_buffer(buffer)
    517 //}
    518 
    519 fn write_load_attribs(state: &mut OutputState, attribs: &[hir::SymRef]) {
    520    write!(state, "static void load_attribs(\
    521                   VertexShaderImpl* impl, VertexAttrib *attribs, \
    522                   uint32_t start, int instance, int count) {{\
    523                     Self* self = (Self*)impl;\n");
    524    for i in attribs {
    525        let sym = state.hir.sym(*i);
    526        match &sym.decl {
    527            hir::SymDecl::Global(_, _interpolation, _ty, run_class) => {
    528                let name = sym.name.as_str();
    529                let func = if *run_class == hir::RunClass::Scalar {
    530                    "load_flat_attrib"
    531                } else {
    532                    "load_attrib"
    533                };
    534                write!(state,
    535                    " {0}(self->{1}, attribs[self->attrib_locations.{1}], start, instance, count);\n",
    536                    func, name);
    537            }
    538            _ => panic!(),
    539        }
    540    }
    541    write!(state, "}}\n");
    542 }
    543 
    544 fn write_store_outputs(state: &mut OutputState, outputs: &[hir::SymRef]) {
    545    let is_scalar = state.is_scalar.replace(true);
    546    write!(state, "public:\nstruct InterpOutputs {{\n");
    547    if state.hir.used_clip_dist != 0 {
    548       state.write(" Float swgl_ClipDistance;\n");
    549    }
    550    for i in outputs {
    551        let sym = state.hir.sym(*i);
    552        match &sym.decl {
    553            hir::SymDecl::Global(_, _, ty, run_class) => {
    554                if *run_class != hir::RunClass::Scalar {
    555                    show_type(state, ty);
    556                    write!(state, " {};\n", sym.name.as_str());
    557                }
    558            }
    559            _ => panic!(),
    560        }
    561    }
    562 
    563    write!(state, "}};\nprivate:\n");
    564    state.is_scalar.set(is_scalar);
    565 
    566    write!(
    567        state,
    568        "ALWAYS_INLINE void store_interp_outputs(char* dest_ptr, size_t stride) {{\n"
    569    );
    570    write!(state, "  for(int n = 0; n < 4; n++) {{\n");
    571    write!(
    572        state,
    573        "    auto* dest = reinterpret_cast<InterpOutputs*>(dest_ptr);\n"
    574    );
    575    if state.hir.used_clip_dist != 0 {
    576        for (i, comp) in "xyzw".chars().enumerate() {
    577            if (state.hir.used_clip_dist & (1 << i)) != 0 {
    578                write!(state, "    dest->swgl_ClipDistance.{} = get_nth(gl_ClipDistance[{}], n);\n", comp, i);
    579            } else {
    580                write!(state, "    dest->swgl_ClipDistance.{} = 0.0f;\n", comp);
    581            }
    582        }
    583    }
    584    for i in outputs {
    585        let sym = state.hir.sym(*i);
    586        match &sym.decl {
    587            hir::SymDecl::Global(_, _, _, run_class) => {
    588                if *run_class != hir::RunClass::Scalar {
    589                    let name = sym.name.as_str();
    590                    write!(state, "    dest->{} = get_nth({}, n);\n", name, name);
    591                }
    592            }
    593            _ => panic!(),
    594        }
    595    }
    596    write!(state, "    dest_ptr += stride;\n");
    597    write!(state, "  }}\n");
    598    write!(state, "}}\n");
    599 }
    600 
    601 fn write_read_inputs(state: &mut OutputState, inputs: &[hir::SymRef]) {
    602    write!(
    603        state,
    604        "typedef {}_vert::InterpOutputs InterpInputs;\n",
    605        state.name
    606    );
    607 
    608    write!(state, "InterpInputs interp_step;\n");
    609 
    610    let mut has_varying = false;
    611    for i in inputs {
    612        let sym = state.hir.sym(*i);
    613        match &sym.decl {
    614            hir::SymDecl::Global(_, _, ty, run_class) => {
    615                if *run_class != hir::RunClass::Scalar {
    616                    if !has_varying {
    617                        has_varying = true;
    618                        write!(state, "struct InterpPerspective {{\n");
    619                    }
    620                    show_type(state, ty);
    621                    write!(state, " {};\n", sym.name.as_str());
    622                }
    623            }
    624            _ => panic!(),
    625        }
    626    }
    627    if has_varying {
    628        write!(state, "}};\n");
    629        write!(state, "InterpPerspective interp_perspective;\n");
    630    }
    631 
    632    write!(state,
    633        "static void read_interp_inputs(\
    634            FragmentShaderImpl* impl, const void* init_, const void* step_) {{\
    635            Self* self = (Self*)impl;\
    636            const InterpInputs* init = (const InterpInputs*)init_;\
    637            const InterpInputs* step = (const InterpInputs*)step_;\n");
    638    for i in inputs {
    639        let sym = state.hir.sym(*i);
    640        match &sym.decl {
    641            hir::SymDecl::Global(_, _, _, run_class) => {
    642                if *run_class != hir::RunClass::Scalar {
    643                    let name = sym.name.as_str();
    644                    write!(
    645                        state,
    646                        "  self->{0} = init_interp(init->{0}, step->{0});\n",
    647                        name
    648                    );
    649                    write!(
    650                        state,
    651                        "  self->interp_step.{0} = step->{0} * 4.0f;\n",
    652                        name
    653                    );
    654                }
    655            }
    656            _ => panic!(),
    657        }
    658    }
    659    write!(state, "}}\n");
    660 
    661    let used_fragcoord = state.used_fragcoord.get();
    662    if has_varying || (used_fragcoord & (4 | 8)) != 0 {
    663        state.use_perspective = true;
    664    }
    665    if state.use_perspective {
    666        write!(state,
    667            "static void read_perspective_inputs(\
    668                FragmentShaderImpl* impl, const void* init_, const void* step_) {{\
    669                Self* self = (Self*)impl;\
    670                const InterpInputs* init = (const InterpInputs*)init_;\
    671                const InterpInputs* step = (const InterpInputs*)step_;\n");
    672        if has_varying {
    673            write!(state, "  Float w = 1.0f / self->gl_FragCoord.w;\n");
    674        }
    675        for i in inputs {
    676            let sym = state.hir.sym(*i);
    677            match &sym.decl {
    678                hir::SymDecl::Global(_, _, _, run_class) => {
    679                    if *run_class != hir::RunClass::Scalar {
    680                        let name = sym.name.as_str();
    681                        write!(
    682                            state,
    683                            "  self->interp_perspective.{0} = init_interp(init->{0}, step->{0});\n",
    684                            name
    685                        );
    686                        write!(state, "  self->{0} = self->interp_perspective.{0} * w;\n", name);
    687                        write!(
    688                            state,
    689                            "  self->interp_step.{0} = step->{0} * 4.0f;\n",
    690                            name
    691                        );
    692                    }
    693                }
    694                _ => panic!(),
    695            }
    696        }
    697        write!(state, "}}\n");
    698    }
    699 
    700    write!(state, "ALWAYS_INLINE void step_interp_inputs(int steps = 4) {{\n");
    701    if (used_fragcoord & 1) != 0 {
    702        write!(state, "  step_fragcoord(steps);\n");
    703    }
    704    if !inputs.is_empty() {
    705        write!(state, "  float chunks = steps * 0.25f;\n");
    706    }
    707    for i in inputs {
    708        let sym = state.hir.sym(*i);
    709        match &sym.decl {
    710            hir::SymDecl::Global(_, _, _, run_class) => {
    711                if *run_class != hir::RunClass::Scalar {
    712                    let name = sym.name.as_str();
    713                    write!(state, "  {0} += interp_step.{0} * chunks;\n", name);
    714                }
    715            }
    716            _ => panic!(),
    717        }
    718    }
    719    write!(state, "}}\n");
    720 
    721    if state.use_perspective {
    722        write!(state, "ALWAYS_INLINE void step_perspective_inputs(int steps = 4) {{\n");
    723        if (used_fragcoord & 1) != 0 {
    724            write!(state, "  step_fragcoord(steps);\n");
    725        }
    726        write!(state, "  step_perspective(steps);\n");
    727        if !inputs.is_empty() {
    728            write!(state, "  float chunks = steps * 0.25f;\n");
    729        }
    730        if has_varying {
    731            write!(state, "  Float w = 1.0f / gl_FragCoord.w;\n");
    732        }
    733        for i in inputs {
    734            let sym = state.hir.sym(*i);
    735            match &sym.decl {
    736                hir::SymDecl::Global(_, _, _, run_class) => {
    737                    if *run_class != hir::RunClass::Scalar {
    738                        let name = sym.name.as_str();
    739                        write!(state, "  interp_perspective.{0} += interp_step.{0} * chunks;\n", name);
    740                        write!(state, "  {0} = w * interp_perspective.{0};\n", name);
    741                    }
    742                }
    743                _ => panic!(),
    744            }
    745        }
    746        write!(state, "}}\n");
    747    }
    748 }
    749 
    750 pub struct OutputState {
    751    hir: hir::State,
    752    output: String,
    753    buffer: RefCell<String>,
    754    should_indent: bool,
    755    output_cxx: bool,
    756    indent: i32,
    757    mask: Option<Box<hir::Expr>>,
    758    cond_index: usize,
    759    return_type: Option<Box<hir::Type>>,
    760    return_declared: bool,
    761    return_vector: bool,
    762    is_scalar: Cell<bool>,
    763    is_lval: Cell<bool>,
    764    name: String,
    765    kind: ShaderKind,
    766    functions: HashMap<(hir::SymRef, u32), bool>,
    767    deps: RefCell<Vec<(hir::SymRef, u32)>>,
    768    vector_mask: u32,
    769    uses_discard: bool,
    770    used_fragcoord: Cell<i32>,
    771    use_perspective: bool,
    772    used_globals: RefCell<Vec<hir::SymRef>>,
    773    texel_fetches: RefCell<Vec<(hir::SymRef, hir::SymRef, hir::TexelFetchOffsets)>>,
    774 }
    775 
    776 use std::fmt::{Arguments, Write};
    777 
    778 impl OutputState {
    779    fn indent(&mut self) {
    780        if self.should_indent {
    781            self.indent += 1
    782        }
    783    }
    784    fn outdent(&mut self) {
    785        if self.should_indent {
    786            self.indent -= 1
    787        }
    788    }
    789 
    790    fn write(&self, s: &str) {
    791        self.buffer.borrow_mut().push_str(s);
    792    }
    793 
    794    fn flush_buffer(&mut self) {
    795        self.output.push_str(&self.buffer.borrow());
    796        self.buffer.borrow_mut().clear();
    797    }
    798 
    799    fn finish_output(&mut self) -> String {
    800        self.flush_buffer();
    801 
    802        let mut s = String::new();
    803        mem::swap(&mut self.output, &mut s);
    804        s
    805    }
    806 
    807    fn push_buffer(&self) -> String {
    808        self.buffer.replace(String::new())
    809    }
    810 
    811    fn pop_buffer(&self, s: String) -> String {
    812        self.buffer.replace(s)
    813    }
    814 
    815    fn write_fmt(&self, args: Arguments) {
    816        let _ = self.buffer.borrow_mut().write_fmt(args);
    817    }
    818 }
    819 
    820 pub fn show_identifier(state: &OutputState, i: &syntax::Identifier) {
    821    state.write(&i.0);
    822 }
    823 
    824 fn glsl_primitive_type_name_to_cxx(glsl_name: &str) -> &str {
    825    hir::TypeKind::from_glsl_primitive_type_name(glsl_name)
    826        .and_then(|kind| kind.cxx_primitive_type_name())
    827        .unwrap_or(glsl_name)
    828 }
    829 
    830 fn add_used_global(state: &OutputState, i: &hir::SymRef) {
    831    let mut globals = state.used_globals.borrow_mut();
    832    if !globals.contains(i) {
    833        globals.push(*i);
    834    }
    835 }
    836 
    837 pub fn show_sym(state: &OutputState, i: &hir::SymRef) {
    838    let sym = state.hir.sym(*i);
    839    match &sym.decl {
    840        hir::SymDecl::NativeFunction(_, ref cxx_name, _) => {
    841            let mut name = sym.name.as_str();
    842            if state.output_cxx {
    843                name = cxx_name.unwrap_or(name);
    844            }
    845            state.write(name);
    846        }
    847        hir::SymDecl::Global(..) => {
    848            if state.output_cxx {
    849                add_used_global(state, i);
    850            }
    851            let mut name = sym.name.as_str();
    852            if state.output_cxx {
    853                name = glsl_primitive_type_name_to_cxx(name);
    854            }
    855            state.write(name);
    856        }
    857        hir::SymDecl::UserFunction(..) | hir::SymDecl::Local(..) | hir::SymDecl::Struct(..) => {
    858            let mut name = sym.name.as_str();
    859            // we want to replace constructor names
    860            if state.output_cxx {
    861                name = glsl_primitive_type_name_to_cxx(name);
    862            }
    863            state.write(name);
    864        }
    865    }
    866 }
    867 
    868 pub fn show_variable(state: &OutputState, i: &hir::SymRef) {
    869    let sym = state.hir.sym(*i);
    870    match &sym.decl {
    871        hir::SymDecl::Global(_, _, ty, _) => {
    872            show_type(state, ty);
    873            state.write(" ");
    874            let mut name = sym.name.as_str();
    875            if state.output_cxx {
    876                name = glsl_primitive_type_name_to_cxx(name);
    877            }
    878            state.write(name);
    879        }
    880        _ => panic!(),
    881    }
    882 }
    883 
    884 pub fn write_default_constructor(state: &OutputState, name: &str) {
    885    // write default constructor
    886    let _ = write!(state, "{}() = default;\n", name);
    887 }
    888 
    889 pub fn write_constructor(state: &OutputState, name: &str, s: &hir::StructFields) {
    890    if s.fields.len() == 1 {
    891        state.write("explicit ");
    892    }
    893    let _ = write!(state, "{}(", name);
    894    let mut first_field = true;
    895    for field in &s.fields {
    896        if !first_field {
    897            state.write(", ");
    898        }
    899        show_type(state, &field.ty);
    900        state.write(" ");
    901        show_identifier_and_type(state, &field.name, &field.ty);
    902        first_field = false;
    903    }
    904    state.write(") : ");
    905 
    906    let mut first_field = true;
    907    for field in &s.fields {
    908        if !first_field {
    909            state.write(", ");
    910        }
    911        let _ = write!(state, "{}({})", field.name, field.name);
    912        first_field = false;
    913    }
    914    state.write("{}\n");
    915 }
    916 
    917 pub fn write_convert_constructor(state: &OutputState, name: &str, s: &hir::StructFields) {
    918    if s.fields.len() == 1 {
    919        state.write("explicit ");
    920    }
    921    let _ = write!(state, "{}(", name);
    922    let mut first_field = true;
    923    for field in &s.fields {
    924        if !first_field {
    925            state.write(", ");
    926        }
    927 
    928        let is_scalar = state.is_scalar.replace(true);
    929        show_type(state, &field.ty);
    930        state.is_scalar.set(is_scalar);
    931 
    932        state.write(" ");
    933 
    934        show_identifier_and_type(state, &field.name, &field.ty);
    935        first_field = false;
    936    }
    937    state.write(")");
    938 
    939    let mut first_field = true;
    940    for hir::StructField { ty, name } in &s.fields {
    941        if ty.array_sizes.is_none() {
    942            if first_field {
    943                state.write(":");
    944            } else {
    945                state.write(",");
    946            }
    947            let _ = write!(state, "{}({})", name, name);
    948            first_field = false;
    949        }
    950    }
    951    state.write("{\n");
    952    for hir::StructField { ty, name } in &s.fields {
    953        if ty.array_sizes.is_some() {
    954            let _ = write!(state, "this->{}.convert({});\n", name, name);
    955        }
    956    }
    957    state.write("}\n");
    958 
    959    let _ = write!(state, "IMPLICIT {}({}_scalar s)", name, name);
    960    let mut first_field = true;
    961    for hir::StructField { ty, name } in &s.fields {
    962        if ty.array_sizes.is_none() {
    963            if first_field {
    964                state.write(":");
    965            } else {
    966                state.write(",");
    967            }
    968            let _ = write!(state, "{}(s.{})", name, name);
    969            first_field = false;
    970        }
    971    }
    972    state.write("{\n");
    973    for hir::StructField { ty, name } in &s.fields {
    974        if ty.array_sizes.is_some() {
    975            let _ = write!(state, "{}.convert(s.{});\n", name, name);
    976        }
    977    }
    978    state.write("}\n");
    979 }
    980 
    981 pub fn write_if_then_else(state: &OutputState, name: &str, s: &hir::StructFields) {
    982    let _ = write!(
    983        state,
    984        "friend {} if_then_else(I32 c, {} t, {} e) {{ return {}(\n",
    985        name, name, name, name
    986    );
    987    let mut first_field = true;
    988    for field in &s.fields {
    989        if !first_field {
    990            state.write(", ");
    991        }
    992        let _ = write!(state, "if_then_else(c, t.{}, e.{})", field.name, field.name);
    993        first_field = false;
    994    }
    995    state.write(");\n}");
    996 }
    997 
    998 pub fn show_storage_class(state: &OutputState, q: &hir::StorageClass) {
    999    match *q {
   1000        hir::StorageClass::None => {}
   1001        hir::StorageClass::Const => {
   1002            state.write("const ");
   1003        }
   1004        hir::StorageClass::In => {
   1005            state.write("in ");
   1006        }
   1007        hir::StorageClass::Out => {
   1008            state.write("out ");
   1009        }
   1010        hir::StorageClass::FragColor(index) => {
   1011            write!(state, "layout(location = 0, index = {}) out ", index);
   1012        }
   1013        hir::StorageClass::Uniform | hir::StorageClass::Sampler(..) => {
   1014            state.write("uniform ");
   1015        }
   1016    }
   1017 }
   1018 
   1019 pub fn show_sym_decl(state: &OutputState, i: &hir::SymRef) {
   1020    let sym = state.hir.sym(*i);
   1021    match &sym.decl {
   1022        hir::SymDecl::Global(storage, ..) => {
   1023            if !state.output_cxx {
   1024                show_storage_class(state, storage)
   1025            }
   1026            if storage == &hir::StorageClass::Const {
   1027                state.write("static constexpr ");
   1028            }
   1029            let mut name = sym.name.as_str();
   1030            if state.output_cxx {
   1031                name = glsl_primitive_type_name_to_cxx(name);
   1032            }
   1033            state.write(name);
   1034        }
   1035        hir::SymDecl::Local(storage, ..) => {
   1036            if !state.output_cxx {
   1037                show_storage_class(state, storage)
   1038            }
   1039            if storage == &hir::StorageClass::Const {
   1040                state.write("const ");
   1041            }
   1042            let mut name = sym.name.as_str();
   1043            if state.output_cxx {
   1044                name = glsl_primitive_type_name_to_cxx(name);
   1045            }
   1046            state.write(name);
   1047        }
   1048        hir::SymDecl::Struct(s) => {
   1049            let name = sym.name.as_str();
   1050 
   1051            if state.output_cxx {
   1052                let name_scalar = format!("{}_scalar", name);
   1053                write!(state, "struct {} {{\n", name_scalar);
   1054                let is_scalar = state.is_scalar.replace(true);
   1055                for field in &s.fields {
   1056                    show_struct_field(state, field);
   1057                }
   1058                write_default_constructor(state, &name_scalar);
   1059                write_constructor(state, &name_scalar, s);
   1060                state.is_scalar.set(is_scalar);
   1061                state.write("};\n");
   1062            }
   1063 
   1064            write!(state, "struct {} {{\n", name);
   1065            for field in &s.fields {
   1066                show_struct_field(state, field);
   1067            }
   1068 
   1069            // write if_then_else
   1070            if state.output_cxx {
   1071                write_default_constructor(state, name);
   1072                write_constructor(state, name, s);
   1073                write_convert_constructor(state, name, s);
   1074                write_if_then_else(state, name, s);
   1075            }
   1076            state.write("}");
   1077        }
   1078        _ => panic!(),
   1079    }
   1080 }
   1081 
   1082 pub fn show_type_name(state: &OutputState, t: &syntax::TypeName) {
   1083    state.write(&t.0);
   1084 }
   1085 
   1086 pub fn show_type_specifier_non_array(state: &mut OutputState, t: &syntax::TypeSpecifierNonArray) {
   1087    if let Some(kind) = hir::TypeKind::from_primitive_type_specifier(t) {
   1088        show_type_kind(state, &kind);
   1089    } else {
   1090        match t {
   1091            syntax::TypeSpecifierNonArray::Struct(ref _s) => panic!(), //show_struct_non_declaration(state, s),
   1092            syntax::TypeSpecifierNonArray::TypeName(ref tn) => show_type_name(state, tn),
   1093            _ => unreachable!(),
   1094        }
   1095    }
   1096 }
   1097 
   1098 pub fn show_type_kind(state: &OutputState, t: &hir::TypeKind) {
   1099    if state.output_cxx {
   1100        if state.is_scalar.get() {
   1101            if let Some(name) = t.cxx_primitive_scalar_type_name() {
   1102                state.write(name);
   1103            } else if let Some(name) = t.cxx_primitive_type_name() {
   1104                let mut scalar_name = String::from(name);
   1105                scalar_name.push_str("_scalar");
   1106                state.write(scalar_name.as_str());
   1107            } else {
   1108                match t {
   1109                    hir::TypeKind::Struct(ref s) => {
   1110                        let mut scalar_name = String::from(state.hir.sym(*s).name.as_str());
   1111                        scalar_name.push_str("_scalar");
   1112                        state.write(scalar_name.as_str());
   1113                    }
   1114                    _ => unreachable!(),
   1115                }
   1116            }
   1117        } else if let Some(name) = t.cxx_primitive_type_name() {
   1118            state.write(name);
   1119        } else {
   1120            match t {
   1121                hir::TypeKind::Struct(ref s) => {
   1122                    state.write(state.hir.sym(*s).name.as_str());
   1123                }
   1124                _ => unreachable!(),
   1125            }
   1126        }
   1127    } else if let Some(name) = t.glsl_primitive_type_name() {
   1128        state.write(name);
   1129    } else {
   1130        match t {
   1131            hir::TypeKind::Struct(ref s) => {
   1132                state.write(state.hir.sym(*s).name.as_str());
   1133            }
   1134            _ => unreachable!(),
   1135        }
   1136    }
   1137 }
   1138 
   1139 pub fn show_type_specifier(state: &mut OutputState, t: &syntax::TypeSpecifier) {
   1140    show_type_specifier_non_array(state, &t.ty);
   1141 
   1142    if let Some(ref arr_spec) = t.array_specifier {
   1143        show_array_spec(state, arr_spec);
   1144    }
   1145 }
   1146 
   1147 pub fn show_type(state: &OutputState, t: &Type) {
   1148    if !state.output_cxx {
   1149        if let Some(ref precision) = t.precision {
   1150            show_precision_qualifier(state, precision);
   1151            state.write(" ");
   1152        }
   1153    }
   1154 
   1155    if state.output_cxx {
   1156        if let Some(ref array) = t.array_sizes {
   1157            state.write("Array<");
   1158            show_type_kind(state, &t.kind);
   1159            let size = match &array.sizes[..] {
   1160                [size] => size,
   1161                _ => panic!(),
   1162            };
   1163            state.write(",");
   1164            show_hir_expr(state, size);
   1165            state.write(">");
   1166        } else {
   1167            show_type_kind(state, &t.kind);
   1168        }
   1169    } else {
   1170        show_type_kind(state, &t.kind);
   1171    }
   1172 
   1173    /*if let Some(ref arr_spec) = t.array_sizes {
   1174      panic!();
   1175    }*/
   1176 }
   1177 
   1178 /*pub fn show_fully_specified_type(state: &mut OutputState, t: &FullySpecifiedType) {
   1179  state.flat = false;
   1180  if let Some(ref qual) = t.qualifier {
   1181    if !state.output_cxx {
   1182      show_type_qualifier(state, &qual);
   1183    } else {
   1184      state.flat =
   1185        qual.qualifiers.0.iter()
   1186            .flat_map(|q| match q { syntax::TypeQualifierSpec::Interpolation(Flat) => Some(()), _ => None})
   1187            .next().is_some();
   1188    }
   1189    state.write(" ");
   1190  }
   1191 
   1192  show_type_specifier(state, &t.ty);
   1193 }*/
   1194 
   1195 /*pub fn show_struct_non_declaration(state: &mut OutputState, s: &syntax::StructSpecifier) {
   1196  state.write("struct ");
   1197 
   1198  if let Some(ref name) = s.name {
   1199    let _ = write!(state, "{} ", name);
   1200  }
   1201 
   1202  state.write("{\n");
   1203 
   1204  for field in &s.fields.0 {
   1205    show_struct_field(state, field);
   1206  }
   1207 
   1208  state.write("}");
   1209 }*/
   1210 
   1211 pub fn show_struct(_state: &OutputState, _s: &syntax::StructSpecifier) {
   1212    panic!();
   1213    //show_struct_non_declaration(state, s);
   1214    //state.write(";\n");
   1215 }
   1216 
   1217 pub fn show_struct_field(state: &OutputState, field: &hir::StructField) {
   1218    show_type(state, &field.ty);
   1219    state.write(" ");
   1220 
   1221    show_identifier_and_type(state, &field.name, &field.ty);
   1222 
   1223    state.write(";\n");
   1224 }
   1225 
   1226 pub fn show_array_spec(state: &OutputState, a: &syntax::ArraySpecifier) {
   1227    for dimension in &a.dimensions {
   1228        match dimension {
   1229            syntax::ArraySpecifierDimension::Unsized => {
   1230                state.write("[]");
   1231            }
   1232            syntax::ArraySpecifierDimension::ExplicitlySized(ref e) => {
   1233                state.write("[");
   1234                show_expr(state, &e);
   1235                state.write("]");
   1236            }
   1237        }
   1238    }
   1239 }
   1240 
   1241 pub fn show_identifier_and_type(state: &OutputState, ident: &syntax::Identifier, ty: &hir::Type) {
   1242    let _ = write!(state, "{}", ident);
   1243 
   1244    if !state.output_cxx {
   1245        if let Some(ref arr_spec) = ty.array_sizes {
   1246            show_array_sizes(state, &arr_spec);
   1247        }
   1248    }
   1249 }
   1250 
   1251 pub fn show_arrayed_identifier(state: &OutputState, ident: &syntax::ArrayedIdentifier) {
   1252    let _ = write!(state, "{}", ident.ident);
   1253 
   1254    if let Some(ref arr_spec) = ident.array_spec {
   1255        show_array_spec(state, &arr_spec);
   1256    }
   1257 }
   1258 
   1259 pub fn show_array_sizes(state: &OutputState, a: &hir::ArraySizes) {
   1260    state.write("[");
   1261    match &a.sizes[..] {
   1262        [a] => show_hir_expr(state, a),
   1263        _ => panic!(),
   1264    }
   1265 
   1266    state.write("]");
   1267    /*
   1268    match *a {
   1269      syntax::ArraySpecifier::Unsized => { state.write("[]"); }
   1270      syntax::ArraySpecifier::ExplicitlySized(ref e) => {
   1271        state.write("[");
   1272        show_expr(state, &e);
   1273        state.write("]");
   1274      }
   1275    }*/
   1276 }
   1277 
   1278 pub fn show_type_qualifier(state: &OutputState, q: &hir::TypeQualifier) {
   1279    let mut qualifiers = q.qualifiers.0.iter();
   1280    let first = qualifiers.next().unwrap();
   1281 
   1282    show_type_qualifier_spec(state, first);
   1283 
   1284    for qual_spec in qualifiers {
   1285        state.write(" ");
   1286        show_type_qualifier_spec(state, qual_spec)
   1287    }
   1288 }
   1289 
   1290 pub fn show_type_qualifier_spec(state: &OutputState, q: &hir::TypeQualifierSpec) {
   1291    match *q {
   1292        hir::TypeQualifierSpec::Layout(ref l) => show_layout_qualifier(state, &l),
   1293        hir::TypeQualifierSpec::Parameter(ref _p) => panic!(),
   1294        hir::TypeQualifierSpec::Memory(ref _m) => panic!(),
   1295        hir::TypeQualifierSpec::Invariant => {
   1296            state.write("invariant");
   1297        }
   1298        hir::TypeQualifierSpec::Precise => {
   1299            state.write("precise");
   1300        }
   1301    }
   1302 }
   1303 
   1304 pub fn show_syntax_storage_qualifier(state: &OutputState, q: &syntax::StorageQualifier) {
   1305    match *q {
   1306        syntax::StorageQualifier::Const => {
   1307            state.write("const");
   1308        }
   1309        syntax::StorageQualifier::InOut => {
   1310            state.write("inout");
   1311        }
   1312        syntax::StorageQualifier::In => {
   1313            state.write("in");
   1314        }
   1315        syntax::StorageQualifier::Out => {
   1316            state.write("out");
   1317        }
   1318        syntax::StorageQualifier::Centroid => {
   1319            state.write("centroid");
   1320        }
   1321        syntax::StorageQualifier::Patch => {
   1322            state.write("patch");
   1323        }
   1324        syntax::StorageQualifier::Sample => {
   1325            state.write("sample");
   1326        }
   1327        syntax::StorageQualifier::Uniform => {
   1328            state.write("uniform");
   1329        }
   1330        syntax::StorageQualifier::Attribute => {
   1331            state.write("attribute");
   1332        }
   1333        syntax::StorageQualifier::Varying => {
   1334            state.write("varying");
   1335        }
   1336        syntax::StorageQualifier::Buffer => {
   1337            state.write("buffer");
   1338        }
   1339        syntax::StorageQualifier::Shared => {
   1340            state.write("shared");
   1341        }
   1342        syntax::StorageQualifier::Coherent => {
   1343            state.write("coherent");
   1344        }
   1345        syntax::StorageQualifier::Volatile => {
   1346            state.write("volatile");
   1347        }
   1348        syntax::StorageQualifier::Restrict => {
   1349            state.write("restrict");
   1350        }
   1351        syntax::StorageQualifier::ReadOnly => {
   1352            state.write("readonly");
   1353        }
   1354        syntax::StorageQualifier::WriteOnly => {
   1355            state.write("writeonly");
   1356        }
   1357        syntax::StorageQualifier::Subroutine(ref n) => show_subroutine(state, &n),
   1358    }
   1359 }
   1360 
   1361 pub fn show_subroutine(state: &OutputState, types: &[syntax::TypeName]) {
   1362    state.write("subroutine");
   1363 
   1364    if !types.is_empty() {
   1365        state.write("(");
   1366 
   1367        let mut types_iter = types.iter();
   1368        let first = types_iter.next().unwrap();
   1369 
   1370        show_type_name(state, first);
   1371 
   1372        for type_name in types_iter {
   1373            state.write(", ");
   1374            show_type_name(state, type_name);
   1375        }
   1376 
   1377        state.write(")");
   1378    }
   1379 }
   1380 
   1381 pub fn show_layout_qualifier(state: &OutputState, l: &syntax::LayoutQualifier) {
   1382    let mut qualifiers = l.ids.0.iter();
   1383    let first = qualifiers.next().unwrap();
   1384 
   1385    state.write("layout (");
   1386    show_layout_qualifier_spec(state, first);
   1387 
   1388    for qual_spec in qualifiers {
   1389        state.write(", ");
   1390        show_layout_qualifier_spec(state, qual_spec);
   1391    }
   1392 
   1393    state.write(")");
   1394 }
   1395 
   1396 pub fn show_layout_qualifier_spec(state: &OutputState, l: &syntax::LayoutQualifierSpec) {
   1397    match *l {
   1398        syntax::LayoutQualifierSpec::Identifier(ref i, Some(ref e)) => {
   1399            let _ = write!(state, "{} = ", i);
   1400            show_expr(state, &e);
   1401        }
   1402        syntax::LayoutQualifierSpec::Identifier(ref i, None) => show_identifier(state, &i),
   1403        syntax::LayoutQualifierSpec::Shared => {
   1404            state.write("shared");
   1405        }
   1406    }
   1407 }
   1408 
   1409 pub fn show_precision_qualifier(state: &OutputState, p: &syntax::PrecisionQualifier) {
   1410    match *p {
   1411        syntax::PrecisionQualifier::High => {
   1412            state.write("highp");
   1413        }
   1414        syntax::PrecisionQualifier::Medium => {
   1415            state.write("mediump");
   1416        }
   1417        syntax::PrecisionQualifier::Low => {
   1418            state.write("low");
   1419        }
   1420    }
   1421 }
   1422 
   1423 pub fn show_interpolation_qualifier(state: &OutputState, i: &syntax::InterpolationQualifier) {
   1424    match *i {
   1425        syntax::InterpolationQualifier::Smooth => {
   1426            state.write("smooth");
   1427        }
   1428        syntax::InterpolationQualifier::Flat => {
   1429            state.write("flat");
   1430        }
   1431        syntax::InterpolationQualifier::NoPerspective => {
   1432            state.write("noperspective");
   1433        }
   1434    }
   1435 }
   1436 
   1437 pub fn show_parameter_qualifier(state: &mut OutputState, i: &Option<hir::ParameterQualifier>) {
   1438    if let Some(i) = i {
   1439        if state.output_cxx {
   1440            match *i {
   1441                hir::ParameterQualifier::Out => {
   1442                    state.write("&");
   1443                }
   1444                hir::ParameterQualifier::InOut => {
   1445                    state.write("&");
   1446                }
   1447                _ => {}
   1448            }
   1449        } else {
   1450            match *i {
   1451                hir::ParameterQualifier::Const => {
   1452                    state.write("const");
   1453                }
   1454                hir::ParameterQualifier::In => {
   1455                    state.write("in");
   1456                }
   1457                hir::ParameterQualifier::Out => {
   1458                    state.write("out");
   1459                }
   1460                hir::ParameterQualifier::InOut => {
   1461                    state.write("inout");
   1462                }
   1463            }
   1464        }
   1465    }
   1466 }
   1467 
   1468 pub fn show_float(state: &OutputState, x: f32) {
   1469    if x.fract() == 0. {
   1470        write!(state, "{}.f", x);
   1471    } else {
   1472        write!(state, "{}f", x);
   1473    }
   1474 }
   1475 
   1476 pub fn show_double(state: &OutputState, x: f64) {
   1477    // force doubles to print as floats
   1478    if x.fract() == 0. {
   1479        write!(state, "{}.f", x);
   1480    } else {
   1481        write!(state, "{}f", x);
   1482    }
   1483 }
   1484 
   1485 fn expr_run_class(state: &OutputState, expr: &hir::Expr) -> hir::RunClass {
   1486    match &expr.kind {
   1487        hir::ExprKind::Variable(i) => symbol_run_class(&state.hir.sym(*i).decl, state.vector_mask),
   1488        hir::ExprKind::IntConst(_)
   1489        | hir::ExprKind::UIntConst(_)
   1490        | hir::ExprKind::BoolConst(_)
   1491        | hir::ExprKind::FloatConst(_)
   1492        | hir::ExprKind::DoubleConst(_) => hir::RunClass::Scalar,
   1493        hir::ExprKind::Unary(_, ref e) => expr_run_class(state, e),
   1494        hir::ExprKind::Binary(_, ref l, ref r) => {
   1495            expr_run_class(state, l).merge(expr_run_class(state, r))
   1496        }
   1497        hir::ExprKind::Ternary(ref c, ref s, ref e) => expr_run_class(state, c)
   1498            .merge(expr_run_class(state, s))
   1499            .merge(expr_run_class(state, e)),
   1500        hir::ExprKind::Assignment(ref v, _, ref e) => {
   1501            expr_run_class(state, v).merge(expr_run_class(state, e))
   1502        }
   1503        hir::ExprKind::Bracket(ref e, ref indx) => {
   1504            indx.iter().fold(
   1505                expr_run_class(state, e),
   1506                |run_class, indx| run_class.merge(expr_run_class(state, indx)),
   1507            )
   1508        }
   1509        hir::ExprKind::FunCall(ref fun, ref args) => {
   1510            let arg_mask: u32 = args.iter().enumerate().fold(0, |mask, (idx, e)| {
   1511                if expr_run_class(state, e) == hir::RunClass::Vector {
   1512                    mask | (1 << idx)
   1513                } else {
   1514                    mask
   1515                }
   1516            });
   1517            match fun {
   1518                hir::FunIdentifier::Identifier(ref sym) => match &state.hir.sym(*sym).decl {
   1519                    hir::SymDecl::NativeFunction(_, _, ref ret_class) => {
   1520                        if *ret_class != hir::RunClass::Unknown {
   1521                            *ret_class
   1522                        } else if arg_mask != 0 {
   1523                            hir::RunClass::Vector
   1524                        } else {
   1525                            hir::RunClass::Scalar
   1526                        }
   1527                    }
   1528                    hir::SymDecl::UserFunction(ref fd, ref run_class) => {
   1529                        let param_mask: u32 = fd.prototype.parameters.iter().enumerate().fold(
   1530                            arg_mask,
   1531                            |mask, (idx, param)| {
   1532                                if let hir::FunctionParameterDeclaration::Named(Some(qual), p) =
   1533                                    param
   1534                                {
   1535                                    match qual {
   1536                                        hir::ParameterQualifier::InOut
   1537                                        | hir::ParameterQualifier::Out => {
   1538                                            if symbol_run_class(
   1539                                                &state.hir.sym(p.sym).decl,
   1540                                                arg_mask,
   1541                                            ) == hir::RunClass::Vector
   1542                                            {
   1543                                                mask | (1 << idx)
   1544                                            } else {
   1545                                                mask
   1546                                            }
   1547                                        }
   1548                                        _ => mask,
   1549                                    }
   1550                                } else {
   1551                                    mask
   1552                                }
   1553                            },
   1554                        );
   1555                        match *run_class {
   1556                            hir::RunClass::Scalar => hir::RunClass::Scalar,
   1557                            hir::RunClass::Dependent(mask) => {
   1558                                if (mask & param_mask) != 0 {
   1559                                    hir::RunClass::Vector
   1560                                } else {
   1561                                    hir::RunClass::Scalar
   1562                                }
   1563                            }
   1564                            _ => hir::RunClass::Vector,
   1565                        }
   1566                    }
   1567                    hir::SymDecl::Struct(..) => {
   1568                        if arg_mask != 0 {
   1569                            hir::RunClass::Vector
   1570                        } else {
   1571                            hir::RunClass::Scalar
   1572                        }
   1573                    }
   1574                    _ => panic!(),
   1575                },
   1576                hir::FunIdentifier::Constructor(..) => {
   1577                    if arg_mask != 0 {
   1578                        hir::RunClass::Vector
   1579                    } else {
   1580                        hir::RunClass::Scalar
   1581                    }
   1582                }
   1583            }
   1584        }
   1585        hir::ExprKind::Dot(ref e, _) => expr_run_class(state, e),
   1586        hir::ExprKind::SwizzleSelector(ref e, _) => expr_run_class(state, e),
   1587        hir::ExprKind::PostInc(ref e) => expr_run_class(state, e),
   1588        hir::ExprKind::PostDec(ref e) => expr_run_class(state, e),
   1589        hir::ExprKind::Comma(_, ref e) => expr_run_class(state, e),
   1590        hir::ExprKind::Cond(_, ref e) => expr_run_class(state, e),
   1591        hir::ExprKind::CondMask => hir::RunClass::Vector,
   1592    }
   1593 }
   1594 
   1595 pub fn show_hir_expr(state: &OutputState, expr: &hir::Expr) {
   1596    show_hir_expr_inner(state, expr, false);
   1597 }
   1598 
   1599 pub fn show_hir_expr_inner(state: &OutputState, expr: &hir::Expr, top_level: bool) {
   1600    match expr.kind {
   1601        hir::ExprKind::Variable(ref i) => show_sym(state, i),
   1602        hir::ExprKind::IntConst(ref x) => {
   1603            let _ = write!(state, "{}", x);
   1604        }
   1605        hir::ExprKind::UIntConst(ref x) => {
   1606            let _ = write!(state, "{}u", x);
   1607        }
   1608        hir::ExprKind::BoolConst(ref x) => {
   1609            let _ = write!(state, "{}", x);
   1610        }
   1611        hir::ExprKind::FloatConst(ref x) => show_float(state, *x),
   1612        hir::ExprKind::DoubleConst(ref x) => show_double(state, *x),
   1613        hir::ExprKind::Unary(ref op, ref e) => {
   1614            show_unary_op(state, &op);
   1615            state.write("(");
   1616            show_hir_expr(state, &e);
   1617            state.write(")");
   1618        }
   1619        hir::ExprKind::Binary(ref op, ref l, ref r) => {
   1620            state.write("(");
   1621            show_hir_expr(state, &l);
   1622            state.write(")");
   1623            show_binary_op(state, &op);
   1624            state.write("(");
   1625            show_hir_expr(state, &r);
   1626            state.write(")");
   1627        }
   1628        hir::ExprKind::Ternary(ref c, ref s, ref e) => {
   1629            if state.output_cxx && expr_run_class(state, c) != hir::RunClass::Scalar {
   1630                state.write("if_then_else(");
   1631                show_hir_expr(state, &c);
   1632                state.write(", ");
   1633                show_hir_expr(state, &s);
   1634                state.write(", ");
   1635                show_hir_expr(state, &e);
   1636                state.write(")");
   1637            } else {
   1638                show_hir_expr(state, &c);
   1639                state.write(" ? ");
   1640                show_hir_expr(state, &s);
   1641                state.write(" : ");
   1642                show_hir_expr(state, &e);
   1643            }
   1644        }
   1645        hir::ExprKind::Assignment(ref v, ref op, ref e) => {
   1646            let is_output = hir::is_output(v, &state.hir).is_some();
   1647            let is_scalar_var = expr_run_class(state, v) == hir::RunClass::Scalar;
   1648            let is_scalar_expr = expr_run_class(state, e) == hir::RunClass::Scalar;
   1649            let force_scalar = is_scalar_var && !is_scalar_expr;
   1650 
   1651            if let Some(mask) = &state.mask {
   1652                let is_scalar_mask = expr_run_class(state, mask) == hir::RunClass::Scalar;
   1653                let force_scalar_mask = is_scalar_var && is_scalar_expr && !is_scalar_mask;
   1654 
   1655                if force_scalar || force_scalar_mask {
   1656                    if top_level {
   1657                        state.write("if (");
   1658                    } else {
   1659                        state.write("(");
   1660                    }
   1661                } else {
   1662                    state.is_lval.set(true);
   1663                    show_hir_expr(state, &v);
   1664                    state.is_lval.set(false);
   1665                    state.write(" = if_then_else(");
   1666                }
   1667 
   1668                if is_output && state.return_declared {
   1669                    state.write("((");
   1670                    show_hir_expr(state, mask);
   1671                    state.write(")&ret_mask)");
   1672                } else {
   1673                    show_hir_expr(state, mask);
   1674                }
   1675                if force_scalar || force_scalar_mask {
   1676                    if top_level {
   1677                        state.write("[0]) { ");
   1678                    } else {
   1679                        state.write("[0] ? ");
   1680                    }
   1681                    state.is_lval.set(true);
   1682                    show_hir_expr(state, &v);
   1683                    state.is_lval.set(false);
   1684                    state.write(" = ");
   1685                } else {
   1686                    state.write(",");
   1687                }
   1688 
   1689                if op != &syntax::AssignmentOp::Equal {
   1690                    show_hir_expr(state, &v);
   1691                }
   1692 
   1693                match *op {
   1694                    syntax::AssignmentOp::Equal => {}
   1695                    syntax::AssignmentOp::Mult => {
   1696                        state.write("*");
   1697                    }
   1698                    syntax::AssignmentOp::Div => {
   1699                        state.write("/");
   1700                    }
   1701                    syntax::AssignmentOp::Mod => {
   1702                        state.write("%");
   1703                    }
   1704                    syntax::AssignmentOp::Add => {
   1705                        state.write("+");
   1706                    }
   1707                    syntax::AssignmentOp::Sub => {
   1708                        state.write("-");
   1709                    }
   1710                    syntax::AssignmentOp::LShift => {
   1711                        state.write("<<");
   1712                    }
   1713                    syntax::AssignmentOp::RShift => {
   1714                        state.write(">>");
   1715                    }
   1716                    syntax::AssignmentOp::And => {
   1717                        state.write("&");
   1718                    }
   1719                    syntax::AssignmentOp::Xor => {
   1720                        state.write("^");
   1721                    }
   1722                    syntax::AssignmentOp::Or => {
   1723                        state.write("|");
   1724                    }
   1725                }
   1726                if force_scalar {
   1727                    state.write("force_scalar(");
   1728                }
   1729                show_hir_expr(state, &e);
   1730                if force_scalar {
   1731                    state.write(")");
   1732                }
   1733                if force_scalar || force_scalar_mask {
   1734                    if top_level {
   1735                        state.write("; }");
   1736                    } else {
   1737                        state.write(" : ");
   1738                        show_hir_expr(state, &v);
   1739                        state.write(")");
   1740                    }
   1741                } else {
   1742                    state.write(",");
   1743                    show_hir_expr(state, &v);
   1744                    state.write(")");
   1745                }
   1746            } else {
   1747                state.is_lval.set(true);
   1748                show_hir_expr(state, &v);
   1749                state.is_lval.set(false);
   1750                state.write(" ");
   1751 
   1752                if is_output && state.return_declared {
   1753                    state.write("= ");
   1754                    if force_scalar {
   1755                        state.write("force_scalar(");
   1756                    }
   1757                    state.write("if_then_else(ret_mask,");
   1758 
   1759                    if op != &syntax::AssignmentOp::Equal {
   1760                        show_hir_expr(state, &v);
   1761                    }
   1762 
   1763                    match *op {
   1764                        syntax::AssignmentOp::Equal => {}
   1765                        syntax::AssignmentOp::Mult => {
   1766                            state.write("*");
   1767                        }
   1768                        syntax::AssignmentOp::Div => {
   1769                            state.write("/");
   1770                        }
   1771                        syntax::AssignmentOp::Mod => {
   1772                            state.write("%");
   1773                        }
   1774                        syntax::AssignmentOp::Add => {
   1775                            state.write("+");
   1776                        }
   1777                        syntax::AssignmentOp::Sub => {
   1778                            state.write("-");
   1779                        }
   1780                        syntax::AssignmentOp::LShift => {
   1781                            state.write("<<");
   1782                        }
   1783                        syntax::AssignmentOp::RShift => {
   1784                            state.write(">>");
   1785                        }
   1786                        syntax::AssignmentOp::And => {
   1787                            state.write("&");
   1788                        }
   1789                        syntax::AssignmentOp::Xor => {
   1790                            state.write("^");
   1791                        }
   1792                        syntax::AssignmentOp::Or => {
   1793                            state.write("|");
   1794                        }
   1795                    }
   1796                    show_hir_expr(state, &e);
   1797                    state.write(",");
   1798                    show_hir_expr(state, &v);
   1799                    state.write(")");
   1800                } else {
   1801                    show_assignment_op(state, &op);
   1802                    state.write(" ");
   1803                    if force_scalar {
   1804                        state.write("force_scalar(");
   1805                    }
   1806                    show_hir_expr(state, &e);
   1807                }
   1808 
   1809                if force_scalar {
   1810                    state.write(")");
   1811                }
   1812            }
   1813        }
   1814        hir::ExprKind::Bracket(ref e, ref indx) => {
   1815            show_hir_expr(state, &e);
   1816            state.write("[");
   1817            for dimension in indx {
   1818                show_hir_expr(state, dimension);
   1819            }
   1820            state.write("]");
   1821        }
   1822        hir::ExprKind::FunCall(ref fun, ref args) => {
   1823            let mut cond_mask: u32 = 0;
   1824            let mut adapt_mask: u32 = 0;
   1825            let mut has_ret = false;
   1826            let mut array_constructor = false;
   1827 
   1828            let mut arg_mask: u32 = 0;
   1829            for (idx, e) in args.iter().enumerate() {
   1830                if expr_run_class(state, e) == hir::RunClass::Vector {
   1831                    arg_mask |= 1 << idx;
   1832                }
   1833            }
   1834 
   1835            match fun {
   1836                hir::FunIdentifier::Constructor(t) => {
   1837                    let is_scalar = state.is_scalar.replace(arg_mask == 0);
   1838                    show_type(state, t);
   1839                    state.is_scalar.set(is_scalar);
   1840                    array_constructor = t.array_sizes.is_some();
   1841                }
   1842                hir::FunIdentifier::Identifier(name) => {
   1843                    if state.output_cxx {
   1844                        let sym = state.hir.sym(*name);
   1845                        match &sym.decl {
   1846                            hir::SymDecl::NativeFunction(..) => {
   1847                                if sym.name == "texelFetchOffset" && args.len() >= 4 {
   1848                                    if let Some((sampler, base, x, y)) = hir::get_texel_fetch_offset(
   1849                                        &state.hir, &args[0], &args[1], &args[3],
   1850                                    ) {
   1851                                        let base_sym = state.hir.sym(base);
   1852                                        let sampler_sym = state.hir.sym(sampler);
   1853                                        add_used_global(state, &sampler);
   1854                                        if let hir::SymDecl::Global(..) = &base_sym.decl {
   1855                                            add_used_global(state, &base);
   1856                                        }
   1857                                        write!(
   1858                                            state,
   1859                                            "texelFetchUnchecked({}, {}_{}_fetch, {}, {})",
   1860                                            sampler_sym.name,
   1861                                            sampler_sym.name,
   1862                                            base_sym.name,
   1863                                            x,
   1864                                            y,
   1865                                        );
   1866                                        return;
   1867                                    }
   1868                                } else if sym.name.starts_with("swgl_commitDithered") {
   1869                                    state.used_fragcoord.set(
   1870                                        state.used_fragcoord.get() | 1 | 2);
   1871                                }
   1872                                show_sym(state, name)
   1873                            }
   1874                            hir::SymDecl::UserFunction(ref fd, ref _run_class) => {
   1875                                if (state.mask.is_some() || state.return_declared) &&
   1876                                    !fd.globals.is_empty()
   1877                                {
   1878                                    cond_mask |= 1 << 31;
   1879                                }
   1880                                let mut param_mask: u32 = 0;
   1881                                for (idx, (param, e)) in
   1882                                    fd.prototype.parameters.iter().zip(args.iter()).enumerate()
   1883                                {
   1884                                    if let hir::FunctionParameterDeclaration::Named(qual, p) = param
   1885                                    {
   1886                                        if symbol_run_class(&state.hir.sym(p.sym).decl, arg_mask)
   1887                                            == hir::RunClass::Vector
   1888                                        {
   1889                                            param_mask |= 1 << idx;
   1890                                        }
   1891                                        match qual {
   1892                                            Some(hir::ParameterQualifier::InOut)
   1893                                            | Some(hir::ParameterQualifier::Out) => {
   1894                                                if state.mask.is_some() || state.return_declared {
   1895                                                    cond_mask |= 1 << idx;
   1896                                                }
   1897                                                if (!arg_mask & param_mask & (1 << idx)) != 0 {
   1898                                                    if adapt_mask == 0 {
   1899                                                        state.write(if top_level {
   1900                                                            "{ "
   1901                                                        } else {
   1902                                                            "({ "
   1903                                                        });
   1904                                                    }
   1905                                                    show_type(state, &p.ty);
   1906                                                    write!(state, " _arg{}_ = ", idx);
   1907                                                    show_hir_expr(state, e);
   1908                                                    state.write("; ");
   1909                                                    adapt_mask |= 1 << idx;
   1910                                                }
   1911                                            }
   1912                                            _ => {}
   1913                                        }
   1914                                    }
   1915                                }
   1916                                if adapt_mask != 0 &&
   1917                                    fd.prototype.ty.kind != hir::TypeKind::Void &&
   1918                                    !top_level
   1919                                {
   1920                                    state.write("auto _ret_ = ");
   1921                                    has_ret = true;
   1922                                }
   1923                                show_sym(state, name);
   1924                                let mut deps = state.deps.borrow_mut();
   1925                                let dep_key = (
   1926                                    *name,
   1927                                    if cond_mask != 0 {
   1928                                        param_mask | (1 << 31)
   1929                                    } else {
   1930                                        param_mask
   1931                                    },
   1932                                );
   1933                                if !deps.contains(&dep_key) {
   1934                                    deps.push(dep_key);
   1935                                }
   1936                            }
   1937                            hir::SymDecl::Struct(..) => {
   1938                                show_sym(state, name);
   1939                                if arg_mask == 0 {
   1940                                    state.write("_scalar");
   1941                                }
   1942                            }
   1943                            _ => panic!("bad identifier to function call"),
   1944                        }
   1945                    }
   1946                }
   1947            }
   1948 
   1949            if array_constructor {
   1950                state.write("{{");
   1951            } else {
   1952                state.write("(");
   1953            }
   1954 
   1955            for (idx, e) in args.iter().enumerate() {
   1956                if idx != 0 {
   1957                    state.write(", ");
   1958                }
   1959                if (adapt_mask & (1 << idx)) != 0 {
   1960                    write!(state, "_arg{}_", idx);
   1961                } else {
   1962                    show_hir_expr(state, e);
   1963                }
   1964            }
   1965 
   1966            if cond_mask != 0 {
   1967                if !args.is_empty() {
   1968                    state.write(", ");
   1969                }
   1970                if let Some(mask) = &state.mask {
   1971                    if state.return_declared {
   1972                        state.write("(");
   1973                        show_hir_expr(state, mask);
   1974                        state.write(")&ret_mask");
   1975                    } else {
   1976                        show_hir_expr(state, mask);
   1977                    }
   1978                } else if state.return_declared {
   1979                    state.write("ret_mask");
   1980                } else {
   1981                    state.write("~0");
   1982                }
   1983            }
   1984 
   1985            if array_constructor {
   1986                state.write("}}");
   1987            } else {
   1988                state.write(")");
   1989            }
   1990 
   1991            if adapt_mask != 0 {
   1992                state.write("; ");
   1993                for (idx, e) in args.iter().enumerate() {
   1994                    if (adapt_mask & (1 << idx)) != 0 {
   1995                        state.is_lval.set(true);
   1996                        show_hir_expr(state, e);
   1997                        state.is_lval.set(false);
   1998                        write!(state, " = force_scalar(_arg{}_); ", idx);
   1999                    }
   2000                }
   2001                if has_ret {
   2002                    state.write("_ret_; })");
   2003                } else {
   2004                    state.write(if top_level { "}" } else { "})" });
   2005                }
   2006            }
   2007        }
   2008        hir::ExprKind::Dot(ref e, ref i) => {
   2009            state.write("(");
   2010            show_hir_expr(state, &e);
   2011            state.write(")");
   2012            state.write(".");
   2013            show_identifier(state, i);
   2014        }
   2015        hir::ExprKind::SwizzleSelector(ref e, ref s) => {
   2016            if state.output_cxx {
   2017                if let hir::ExprKind::Variable(ref sym) = &e.kind {
   2018                    if state.hir.sym(*sym).name == "gl_FragCoord" {
   2019                        state.used_fragcoord.set(
   2020                            s.components.iter().fold(
   2021                                state.used_fragcoord.get(),
   2022                                |used, c| used | (1 << c)));
   2023                    }
   2024                }
   2025                state.write("(");
   2026                show_hir_expr(state, &e);
   2027                state.write(").");
   2028                if s.components.len() == 1 {
   2029                    // For single component swizzles, output a field access to
   2030                    // avoid stressing inlining of sel().
   2031                    state.write(&s.to_field_set(hir::FieldSet::Xyzw));
   2032                } else {
   2033                    if state.is_lval.get() && s.components.len() > 1 {
   2034                        state.write("lsel(");
   2035                    } else {
   2036                        state.write("sel(");
   2037                    }
   2038                    for (i, c) in s.to_string().chars().enumerate() {
   2039                        if i > 0 {
   2040                            state.write(",");
   2041                        }
   2042                        write!(state, "{}", c.to_uppercase());
   2043                    }
   2044                    state.write(")");
   2045                }
   2046            } else {
   2047                state.write("(");
   2048                show_hir_expr(state, &e);
   2049                state.write(")");
   2050                state.write(".");
   2051                state.write(&s.to_string());
   2052            }
   2053        }
   2054        hir::ExprKind::PostInc(ref e) => {
   2055            show_hir_expr(state, &e);
   2056            state.write("++");
   2057        }
   2058        hir::ExprKind::PostDec(ref e) => {
   2059            show_hir_expr(state, &e);
   2060            state.write("--");
   2061        }
   2062        hir::ExprKind::Comma(ref a, ref b) => {
   2063            show_hir_expr(state, &a);
   2064            state.write(", ");
   2065            show_hir_expr(state, &b);
   2066        }
   2067        hir::ExprKind::Cond(index, _) => {
   2068            write!(state, "_c{}_", index);
   2069        }
   2070        hir::ExprKind::CondMask => {
   2071            state.write("_cond_mask_");
   2072        }
   2073    }
   2074 }
   2075 
   2076 pub fn show_expr(state: &OutputState, expr: &syntax::Expr) {
   2077    match *expr {
   2078        syntax::Expr::Variable(ref i) => show_identifier(state, &i),
   2079        syntax::Expr::IntConst(ref x) => {
   2080            let _ = write!(state, "{}", x);
   2081        }
   2082        syntax::Expr::UIntConst(ref x) => {
   2083            let _ = write!(state, "{}u", x);
   2084        }
   2085        syntax::Expr::BoolConst(ref x) => {
   2086            let _ = write!(state, "{}", x);
   2087        }
   2088        syntax::Expr::FloatConst(ref x) => show_float(state, *x),
   2089        syntax::Expr::DoubleConst(ref x) => show_double(state, *x),
   2090        syntax::Expr::Unary(ref op, ref e) => {
   2091            show_unary_op(state, &op);
   2092            state.write("(");
   2093            show_expr(state, &e);
   2094            state.write(")");
   2095        }
   2096        syntax::Expr::Binary(ref op, ref l, ref r) => {
   2097            state.write("(");
   2098            show_expr(state, &l);
   2099            state.write(")");
   2100            show_binary_op(state, &op);
   2101            state.write("(");
   2102            show_expr(state, &r);
   2103            state.write(")");
   2104        }
   2105        syntax::Expr::Ternary(ref c, ref s, ref e) => {
   2106            show_expr(state, &c);
   2107            state.write(" ? ");
   2108            show_expr(state, &s);
   2109            state.write(" : ");
   2110            show_expr(state, &e);
   2111        }
   2112        syntax::Expr::Assignment(ref v, ref op, ref e) => {
   2113            show_expr(state, &v);
   2114            state.write(" ");
   2115            show_assignment_op(state, &op);
   2116            state.write(" ");
   2117            show_expr(state, &e);
   2118        }
   2119        syntax::Expr::Bracket(ref e, ref a) => {
   2120            show_expr(state, &e);
   2121            show_array_spec(state, &a);
   2122        }
   2123        syntax::Expr::FunCall(ref fun, ref args) => {
   2124            show_function_identifier(state, &fun);
   2125            state.write("(");
   2126 
   2127            if !args.is_empty() {
   2128                let mut args_iter = args.iter();
   2129                let first = args_iter.next().unwrap();
   2130                show_expr(state, first);
   2131 
   2132                for e in args_iter {
   2133                    state.write(", ");
   2134                    show_expr(state, e);
   2135                }
   2136            }
   2137 
   2138            state.write(")");
   2139        }
   2140        syntax::Expr::Dot(ref e, ref i) => {
   2141            state.write("(");
   2142            show_expr(state, &e);
   2143            state.write(")");
   2144            state.write(".");
   2145            show_identifier(state, &i);
   2146        }
   2147        syntax::Expr::PostInc(ref e) => {
   2148            show_expr(state, &e);
   2149            state.write("++");
   2150        }
   2151        syntax::Expr::PostDec(ref e) => {
   2152            show_expr(state, &e);
   2153            state.write("--");
   2154        }
   2155        syntax::Expr::Comma(ref a, ref b) => {
   2156            show_expr(state, &a);
   2157            state.write(", ");
   2158            show_expr(state, &b);
   2159        }
   2160    }
   2161 }
   2162 
   2163 pub fn show_unary_op(state: &OutputState, op: &syntax::UnaryOp) {
   2164    match *op {
   2165        syntax::UnaryOp::Inc => {
   2166            state.write("++");
   2167        }
   2168        syntax::UnaryOp::Dec => {
   2169            state.write("--");
   2170        }
   2171        syntax::UnaryOp::Add => {
   2172            state.write("+");
   2173        }
   2174        syntax::UnaryOp::Minus => {
   2175            state.write("-");
   2176        }
   2177        syntax::UnaryOp::Not => {
   2178            state.write("!");
   2179        }
   2180        syntax::UnaryOp::Complement => {
   2181            state.write("~");
   2182        }
   2183    }
   2184 }
   2185 
   2186 pub fn show_binary_op(state: &OutputState, op: &syntax::BinaryOp) {
   2187    match *op {
   2188        syntax::BinaryOp::Or => {
   2189            state.write("||");
   2190        }
   2191        syntax::BinaryOp::Xor => {
   2192            state.write("^^");
   2193        }
   2194        syntax::BinaryOp::And => {
   2195            state.write("&&");
   2196        }
   2197        syntax::BinaryOp::BitOr => {
   2198            state.write("|");
   2199        }
   2200        syntax::BinaryOp::BitXor => {
   2201            state.write("^");
   2202        }
   2203        syntax::BinaryOp::BitAnd => {
   2204            state.write("&");
   2205        }
   2206        syntax::BinaryOp::Equal => {
   2207            state.write("==");
   2208        }
   2209        syntax::BinaryOp::NonEqual => {
   2210            state.write("!=");
   2211        }
   2212        syntax::BinaryOp::LT => {
   2213            state.write("<");
   2214        }
   2215        syntax::BinaryOp::GT => {
   2216            state.write(">");
   2217        }
   2218        syntax::BinaryOp::LTE => {
   2219            state.write("<=");
   2220        }
   2221        syntax::BinaryOp::GTE => {
   2222            state.write(">=");
   2223        }
   2224        syntax::BinaryOp::LShift => {
   2225            state.write("<<");
   2226        }
   2227        syntax::BinaryOp::RShift => {
   2228            state.write(">>");
   2229        }
   2230        syntax::BinaryOp::Add => {
   2231            state.write("+");
   2232        }
   2233        syntax::BinaryOp::Sub => {
   2234            state.write("-");
   2235        }
   2236        syntax::BinaryOp::Mult => {
   2237            state.write("*");
   2238        }
   2239        syntax::BinaryOp::Div => {
   2240            state.write("/");
   2241        }
   2242        syntax::BinaryOp::Mod => {
   2243            state.write("%");
   2244        }
   2245    }
   2246 }
   2247 
   2248 pub fn show_assignment_op(state: &OutputState, op: &syntax::AssignmentOp) {
   2249    match *op {
   2250        syntax::AssignmentOp::Equal => {
   2251            state.write("=");
   2252        }
   2253        syntax::AssignmentOp::Mult => {
   2254            state.write("*=");
   2255        }
   2256        syntax::AssignmentOp::Div => {
   2257            state.write("/=");
   2258        }
   2259        syntax::AssignmentOp::Mod => {
   2260            state.write("%=");
   2261        }
   2262        syntax::AssignmentOp::Add => {
   2263            state.write("+=");
   2264        }
   2265        syntax::AssignmentOp::Sub => {
   2266            state.write("-=");
   2267        }
   2268        syntax::AssignmentOp::LShift => {
   2269            state.write("<<=");
   2270        }
   2271        syntax::AssignmentOp::RShift => {
   2272            state.write(">>=");
   2273        }
   2274        syntax::AssignmentOp::And => {
   2275            state.write("&=");
   2276        }
   2277        syntax::AssignmentOp::Xor => {
   2278            state.write("^=");
   2279        }
   2280        syntax::AssignmentOp::Or => {
   2281            state.write("|=");
   2282        }
   2283    }
   2284 }
   2285 
   2286 pub fn show_function_identifier(state: &OutputState, i: &syntax::FunIdentifier) {
   2287    match *i {
   2288        syntax::FunIdentifier::Identifier(ref n) => show_identifier(state, &n),
   2289        syntax::FunIdentifier::Expr(ref e) => show_expr(state, &*e),
   2290    }
   2291 }
   2292 
   2293 pub fn show_hir_function_identifier(state: &OutputState, i: &hir::FunIdentifier) {
   2294    match *i {
   2295        hir::FunIdentifier::Identifier(ref n) => show_sym(state, n),
   2296        hir::FunIdentifier::Constructor(ref t) => show_type(state, &*t),
   2297    }
   2298 }
   2299 
   2300 pub fn show_declaration(state: &mut OutputState, d: &hir::Declaration) {
   2301    show_indent(state);
   2302    match *d {
   2303        hir::Declaration::FunctionPrototype(ref proto) => {
   2304            if !state.output_cxx {
   2305                show_function_prototype(state, &proto);
   2306                state.write(";\n");
   2307            }
   2308        }
   2309        hir::Declaration::InitDeclaratorList(ref list) => {
   2310            show_init_declarator_list(state, &list);
   2311            state.write(";\n");
   2312 
   2313            if state.output_cxx {
   2314                let base = list.head.name;
   2315                let base_sym = state.hir.sym(base);
   2316                if let hir::SymDecl::Local(..) = &base_sym.decl {
   2317                    let mut texel_fetches = state.texel_fetches.borrow_mut();
   2318                    while let Some(idx) = texel_fetches.iter().position(|&(_, b, _)| b == base)
   2319                    {
   2320                        let (sampler, _, offsets) = texel_fetches.remove(idx);
   2321                        let sampler_sym = state.hir.sym(sampler);
   2322                        define_texel_fetch_ptr(state, &base_sym, &sampler_sym, &offsets);
   2323                    }
   2324                }
   2325            }
   2326        }
   2327        hir::Declaration::Precision(ref qual, ref ty) => {
   2328            if !state.output_cxx {
   2329                show_precision_qualifier(state, &qual);
   2330                show_type_specifier(state, &ty);
   2331                state.write(";\n");
   2332            }
   2333        }
   2334        hir::Declaration::Block(ref _block) => {
   2335            panic!();
   2336            //show_block(state, &block);
   2337            //state.write(";\n");
   2338        }
   2339        hir::Declaration::Global(ref qual, ref identifiers) => {
   2340            // We only want to output GLSL layout qualifiers if not C++
   2341            if !state.output_cxx {
   2342                show_type_qualifier(state, &qual);
   2343 
   2344                if !identifiers.is_empty() {
   2345                    let mut iter = identifiers.iter();
   2346                    let first = iter.next().unwrap();
   2347                    show_identifier(state, first);
   2348 
   2349                    for identifier in iter {
   2350                        let _ = write!(state, ", {}", identifier);
   2351                    }
   2352                }
   2353 
   2354                state.write(";\n");
   2355            }
   2356        }
   2357        hir::Declaration::StructDefinition(ref sym) => {
   2358            show_sym_decl(state, sym);
   2359 
   2360            state.write(";\n");
   2361        }
   2362    }
   2363 }
   2364 
   2365 pub fn show_function_prototype(state: &mut OutputState, fp: &hir::FunctionPrototype) {
   2366    let is_scalar = state.is_scalar.replace(!state.return_vector);
   2367    show_type(state, &fp.ty);
   2368    state.is_scalar.set(is_scalar);
   2369 
   2370    state.write(" ");
   2371    show_identifier(state, &fp.name);
   2372 
   2373    state.write("(");
   2374 
   2375    if !fp.parameters.is_empty() {
   2376        let mut iter = fp.parameters.iter();
   2377        let first = iter.next().unwrap();
   2378        show_function_parameter_declaration(state, first);
   2379 
   2380        for param in iter {
   2381            state.write(", ");
   2382            show_function_parameter_declaration(state, param);
   2383        }
   2384    }
   2385 
   2386    if state.output_cxx && (state.vector_mask & (1 << 31)) != 0 {
   2387        if !fp.parameters.is_empty() {
   2388            state.write(", ");
   2389        }
   2390        state.write("I32 _cond_mask_");
   2391    }
   2392 
   2393    state.write(")");
   2394 }
   2395 
   2396 pub fn show_function_parameter_declaration(
   2397    state: &mut OutputState,
   2398    p: &hir::FunctionParameterDeclaration,
   2399 ) {
   2400    match *p {
   2401        hir::FunctionParameterDeclaration::Named(ref qual, ref fpd) => {
   2402            if state.output_cxx {
   2403                let is_scalar = state.is_scalar.replace(
   2404                    symbol_run_class(&state.hir.sym(fpd.sym).decl, state.vector_mask)
   2405                        == hir::RunClass::Scalar,
   2406                );
   2407                show_type(state, &fpd.ty);
   2408                state.is_scalar.set(is_scalar);
   2409                show_parameter_qualifier(state, qual);
   2410            } else {
   2411                show_parameter_qualifier(state, qual);
   2412                state.write(" ");
   2413                show_type(state, &fpd.ty);
   2414            }
   2415            state.write(" ");
   2416            show_identifier_and_type(state, &fpd.name, &fpd.ty);
   2417        }
   2418        hir::FunctionParameterDeclaration::Unnamed(ref qual, ref ty) => {
   2419            if state.output_cxx {
   2420                show_type_specifier(state, ty);
   2421                show_parameter_qualifier(state, qual);
   2422            } else {
   2423                show_parameter_qualifier(state, qual);
   2424                state.write(" ");
   2425                show_type_specifier(state, ty);
   2426            }
   2427        }
   2428    }
   2429 }
   2430 
   2431 pub fn show_init_declarator_list(state: &mut OutputState, i: &hir::InitDeclaratorList) {
   2432    show_single_declaration(state, &i.head);
   2433 
   2434    for decl in &i.tail {
   2435        state.write(", ");
   2436        show_single_declaration_no_type(state, decl);
   2437    }
   2438 }
   2439 
   2440 pub fn show_single_declaration(state: &mut OutputState, d: &hir::SingleDeclaration) {
   2441    if state.output_cxx {
   2442        show_single_declaration_cxx(state, d)
   2443    } else {
   2444        show_single_declaration_glsl(state, d)
   2445    }
   2446 }
   2447 
   2448 pub fn show_single_declaration_glsl(state: &mut OutputState, d: &hir::SingleDeclaration) {
   2449    if let Some(ref qual) = d.qualifier {
   2450        show_type_qualifier(state, &qual);
   2451        state.write(" ");
   2452    }
   2453 
   2454    let sym = state.hir.sym(d.name);
   2455    match &sym.decl {
   2456        hir::SymDecl::Global(storage, interpolation, ..) => {
   2457            show_storage_class(state, storage);
   2458            if let Some(i) = interpolation {
   2459                show_interpolation_qualifier(state, i);
   2460            }
   2461        }
   2462        hir::SymDecl::Local(storage, ..) => show_storage_class(state, storage),
   2463        _ => panic!("should be variable"),
   2464    }
   2465 
   2466    if let Some(ty_def) = d.ty_def {
   2467        show_sym_decl(state, &ty_def);
   2468    } else {
   2469        show_type(state, &d.ty);
   2470    }
   2471 
   2472    state.write(" ");
   2473    state.write(sym.name.as_str());
   2474 
   2475    if let Some(ref arr_spec) = d.ty.array_sizes {
   2476        show_array_sizes(state, &arr_spec);
   2477    }
   2478 
   2479    if let Some(ref initializer) = d.initializer {
   2480        state.write(" = ");
   2481        show_initializer(state, initializer);
   2482    }
   2483 }
   2484 
   2485 fn symbol_run_class(decl: &hir::SymDecl, vector_mask: u32) -> hir::RunClass {
   2486    let run_class = match decl {
   2487        hir::SymDecl::Global(_, _, _, run_class) => *run_class,
   2488        hir::SymDecl::Local(_, _, run_class) => *run_class,
   2489        _ => hir::RunClass::Vector,
   2490    };
   2491    match run_class {
   2492        hir::RunClass::Scalar => hir::RunClass::Scalar,
   2493        hir::RunClass::Dependent(mask) => {
   2494            if (mask & vector_mask) != 0 {
   2495                hir::RunClass::Vector
   2496            } else {
   2497                hir::RunClass::Scalar
   2498            }
   2499        }
   2500        _ => hir::RunClass::Vector,
   2501    }
   2502 }
   2503 
   2504 pub fn show_single_declaration_cxx(state: &mut OutputState, d: &hir::SingleDeclaration) {
   2505    let sym = state.hir.sym(d.name);
   2506    if state.kind == ShaderKind::Vertex {
   2507        match &sym.decl {
   2508            hir::SymDecl::Global(hir::StorageClass::Uniform, ..) |
   2509            hir::SymDecl::Global(hir::StorageClass::Sampler(_), ..) |
   2510            hir::SymDecl::Global(hir::StorageClass::Out, _, _, hir::RunClass::Scalar) => {
   2511                state.write("// ");
   2512            }
   2513            _ => {}
   2514        }
   2515    } else {
   2516        match &sym.decl {
   2517            hir::SymDecl::Global(hir::StorageClass::FragColor(index), ..) => {
   2518                let fragcolor = match index {
   2519                    0 => "gl_FragColor",
   2520                    1 => "gl_SecondaryFragColor",
   2521                    _ => panic!(),
   2522                };
   2523                write!(state, "#define {} {}\n", sym.name, fragcolor);
   2524                show_indent(state);
   2525                state.write("// ");
   2526            }
   2527            hir::SymDecl::Global(hir::StorageClass::Out, ..) => {
   2528                write!(state, "#define {} gl_FragColor\n", sym.name);
   2529                show_indent(state);
   2530                state.write("// ");
   2531            }
   2532            hir::SymDecl::Global(hir::StorageClass::Uniform, ..) |
   2533            hir::SymDecl::Global(hir::StorageClass::Sampler(_), ..) |
   2534            hir::SymDecl::Global(hir::StorageClass::In, _, _, hir::RunClass::Scalar) => {
   2535                state.write("// ");
   2536            }
   2537            _ => {}
   2538        }
   2539    }
   2540    let is_scalar = state
   2541        .is_scalar
   2542        .replace(symbol_run_class(&sym.decl, state.vector_mask) == hir::RunClass::Scalar);
   2543 
   2544    if let Some(ref _array) = d.ty.array_sizes {
   2545        show_type(state, &d.ty);
   2546    } else {
   2547        if let Some(ty_def) = d.ty_def {
   2548            show_sym_decl(state, &ty_def);
   2549        } else {
   2550            show_type(state, &d.ty);
   2551        }
   2552    }
   2553 
   2554    // XXX: this is pretty grotty
   2555    state.write(" ");
   2556    show_sym_decl(state, &d.name);
   2557 
   2558    state.is_scalar.set(is_scalar);
   2559 
   2560    if let Some(ref initializer) = d.initializer {
   2561        state.write(" = ");
   2562        show_initializer(state, initializer);
   2563    }
   2564 }
   2565 
   2566 pub fn show_single_declaration_no_type(state: &OutputState, d: &hir::SingleDeclarationNoType) {
   2567    show_arrayed_identifier(state, &d.ident);
   2568 
   2569    if let Some(ref initializer) = d.initializer {
   2570        state.write(" = ");
   2571        show_initializer(state, initializer);
   2572    }
   2573 }
   2574 
   2575 pub fn show_initializer(state: &OutputState, i: &hir::Initializer) {
   2576    match *i {
   2577        hir::Initializer::Simple(ref e) => show_hir_expr(state, e),
   2578        hir::Initializer::List(ref list) => {
   2579            let mut iter = list.0.iter();
   2580            let first = iter.next().unwrap();
   2581 
   2582            state.write("{ ");
   2583            show_initializer(state, first);
   2584 
   2585            for ini in iter {
   2586                state.write(", ");
   2587                show_initializer(state, ini);
   2588            }
   2589 
   2590            state.write(" }");
   2591        }
   2592    }
   2593 }
   2594 
   2595 /*
   2596 pub fn show_block(state: &mut OutputState, b: &hir::Block) {
   2597  show_type_qualifier(state, &b.qualifier);
   2598  state.write(" ");
   2599  show_identifier(state, &b.name);
   2600  state.write(" {");
   2601 
   2602  for field in &b.fields {
   2603    show_struct_field(state, field);
   2604    state.write("\n");
   2605  }
   2606  state.write("}");
   2607 
   2608  if let Some(ref ident) = b.identifier {
   2609    show_arrayed_identifier(state, ident);
   2610  }
   2611 }
   2612 */
   2613 
   2614 // This is a hack to run through the first time with an empty writter to find if 'return' is declared.
   2615 pub fn has_conditional_return(state: &mut OutputState, cst: &hir::CompoundStatement) -> bool {
   2616    let buffer = state.push_buffer();
   2617    show_compound_statement(state, cst);
   2618    state.pop_buffer(buffer);
   2619    let result = state.return_declared;
   2620    state.return_declared = false;
   2621    result
   2622 }
   2623 
   2624 fn define_texel_fetch_ptr(
   2625    state: &OutputState,
   2626    base_sym: &hir::Symbol,
   2627    sampler_sym: &hir::Symbol,
   2628    offsets: &hir::TexelFetchOffsets,
   2629 ) {
   2630    show_indent(state);
   2631    write!(
   2632        state,
   2633        "auto {}_{}_fetch = texelFetchPtr({}, {}, {}, {}, {}, {});\n",
   2634        sampler_sym.name,
   2635        base_sym.name,
   2636        sampler_sym.name,
   2637        base_sym.name,
   2638        offsets.min_x,
   2639        offsets.max_x,
   2640        offsets.min_y,
   2641        offsets.max_y,
   2642    );
   2643 }
   2644 
   2645 pub fn show_function_definition(
   2646    state: &mut OutputState,
   2647    fd: &hir::FunctionDefinition,
   2648    vector_mask: u32,
   2649 ) {
   2650    //  println!("start {:?} {:?}", fd.prototype.name, vector_mask);
   2651    if state.output_cxx && fd.prototype.name.as_str() == "main" {
   2652        state.write("ALWAYS_INLINE ");
   2653    }
   2654    show_function_prototype(state, &fd.prototype);
   2655    state.write(" ");
   2656    state.return_type = Some(Box::new(fd.prototype.ty.clone()));
   2657 
   2658    if state.output_cxx && (vector_mask & (1 << 31)) != 0 {
   2659        state.mask = Some(Box::new(hir::Expr {
   2660            kind: hir::ExprKind::CondMask,
   2661            ty: hir::Type::new(hir::TypeKind::Bool),
   2662        }));
   2663    }
   2664 
   2665    show_indent(state);
   2666    state.write("{\n");
   2667 
   2668    state.indent();
   2669    if has_conditional_return(state, &fd.body) {
   2670        show_indent(state);
   2671        state.write(if state.return_vector {
   2672            "I32"
   2673        } else {
   2674            "int32_t"
   2675        });
   2676        state.write(" ret_mask = ");
   2677        if let Some(mask) = &state.mask {
   2678            show_hir_expr(state, mask);
   2679        } else {
   2680            state.write("~0");
   2681        }
   2682        state.write(";\n");
   2683        // XXX: the cloning here is bad
   2684        show_indent(state);
   2685        if fd.prototype.ty != Type::new(hir::TypeKind::Void) {
   2686            let is_scalar = state.is_scalar.replace(!state.return_vector);
   2687            show_type(state, &state.return_type.clone().unwrap());
   2688            state.write(" ret;\n");
   2689            state.is_scalar.set(is_scalar);
   2690        }
   2691    }
   2692 
   2693    if state.output_cxx {
   2694        match fd.prototype.name.as_str() {
   2695            "swgl_drawSpanRGBA8" |
   2696            "swgl_drawSpanR8" => {
   2697                // Partial spans are not drawn using span shaders, but rather drawn with a fragment shader
   2698                // where the span shader left off. We need to undo any changes to the interpolants made by
   2699                // the span shaders so that we can reset the interpolants to where the fragment shader
   2700                // expects them. We do this by saving them in an _Undo_ struct on entry to the span shader,
   2701                // and then restore them in the _Undo_ struct destructor.
   2702                let mut needs_undo = vec![];
   2703                for global in &fd.globals {
   2704                    let sym = state.hir.sym(*global);
   2705                    match &sym.decl {
   2706                        hir::SymDecl::Global(hir::StorageClass::In, _, ty, hir::RunClass::Vector) => {
   2707                            if needs_undo.is_empty() {
   2708                                state.write("struct _Undo_ {\nSelf* self;\n");
   2709                            }
   2710                            show_type(state, ty);
   2711                            write!(state, " {};\n", sym.name);
   2712                            needs_undo.push(sym.name.clone());
   2713                        }
   2714                        _ => {}
   2715                    }
   2716                }
   2717                if !needs_undo.is_empty() {
   2718                    state.write("explicit _Undo_(Self* self) : self(self)");
   2719                    for name in &needs_undo {
   2720                        write!(state, ", {0}(self->{0})", name);
   2721                    }
   2722                    state.write(" {}\n");
   2723                    state.write("~_Undo_() {\n");
   2724                    for name in &needs_undo {
   2725                        write!(state, "self->{0} = {0};\n", name);
   2726                    }
   2727                    state.write("}} _undo_(this);\n");
   2728                }
   2729            }
   2730            _ => {}
   2731        }
   2732 
   2733        let mut texel_fetches = state.texel_fetches.borrow_mut();
   2734        texel_fetches.clear();
   2735        for ((sampler, base), offsets) in fd.texel_fetches.iter() {
   2736            add_used_global(state, sampler);
   2737            let sampler_sym = state.hir.sym(*sampler);
   2738            let base_sym = state.hir.sym(*base);
   2739            match &base_sym.decl {
   2740                hir::SymDecl::Global(..) => {
   2741                    add_used_global(state, base);
   2742                    define_texel_fetch_ptr(state, &base_sym, &sampler_sym, &offsets);
   2743                }
   2744                hir::SymDecl::Local(..) => {
   2745                    if fd.prototype.has_parameter(*base) {
   2746                        define_texel_fetch_ptr(state, &base_sym, &sampler_sym, &offsets);
   2747                    } else {
   2748                        texel_fetches.push((*sampler, *base, offsets.clone()));
   2749                    }
   2750                }
   2751                _ => panic!(),
   2752            }
   2753        }
   2754    }
   2755 
   2756    for st in &fd.body.statement_list {
   2757        show_statement(state, st);
   2758    }
   2759 
   2760    if state.return_declared {
   2761        show_indent(state);
   2762        if fd.prototype.ty == Type::new(hir::TypeKind::Void) {
   2763            state.write("return;\n");
   2764        } else {
   2765            state.write("return ret;\n");
   2766        }
   2767    }
   2768    state.outdent();
   2769 
   2770    show_indent(state);
   2771    state.write("}\n");
   2772    // println!("end {:?}", fd.prototype.name);
   2773 
   2774    state.return_type = None;
   2775    state.return_declared = false;
   2776    state.mask = None;
   2777 }
   2778 
   2779 pub fn show_compound_statement(state: &mut OutputState, cst: &hir::CompoundStatement) {
   2780    show_indent(state);
   2781    state.write("{\n");
   2782 
   2783    state.indent();
   2784    for st in &cst.statement_list {
   2785        show_statement(state, st);
   2786    }
   2787    state.outdent();
   2788 
   2789    show_indent(state);
   2790    state.write("}\n");
   2791 }
   2792 
   2793 pub fn show_statement(state: &mut OutputState, st: &hir::Statement) {
   2794    match *st {
   2795        hir::Statement::Compound(ref cst) => show_compound_statement(state, cst),
   2796        hir::Statement::Simple(ref sst) => show_simple_statement(state, sst),
   2797    }
   2798 }
   2799 
   2800 pub fn show_simple_statement(state: &mut OutputState, sst: &hir::SimpleStatement) {
   2801    match *sst {
   2802        hir::SimpleStatement::Declaration(ref d) => show_declaration(state, d),
   2803        hir::SimpleStatement::Expression(ref e) => show_expression_statement(state, e),
   2804        hir::SimpleStatement::Selection(ref s) => show_selection_statement(state, s),
   2805        hir::SimpleStatement::Switch(ref s) => show_switch_statement(state, s),
   2806        hir::SimpleStatement::Iteration(ref i) => show_iteration_statement(state, i),
   2807        hir::SimpleStatement::Jump(ref j) => show_jump_statement(state, j),
   2808    }
   2809 }
   2810 
   2811 pub fn show_indent(state: &OutputState) {
   2812    for _ in 0 .. state.indent {
   2813        state.write(" ");
   2814    }
   2815 }
   2816 
   2817 pub fn show_expression_statement(state: &mut OutputState, est: &hir::ExprStatement) {
   2818    show_indent(state);
   2819 
   2820    if let Some(ref e) = *est {
   2821        show_hir_expr_inner(state, e, true);
   2822    }
   2823 
   2824    state.write(";\n");
   2825 }
   2826 
   2827 pub fn show_selection_statement(state: &mut OutputState, sst: &hir::SelectionStatement) {
   2828    show_indent(state);
   2829 
   2830    if state.output_cxx &&
   2831        (state.return_declared || expr_run_class(state, &sst.cond) != hir::RunClass::Scalar)
   2832    {
   2833        let (cond_index, mask) = if state.mask.is_none() || sst.else_stmt.is_some() {
   2834            let cond = sst.cond.clone();
   2835            state.cond_index += 1;
   2836            let cond_index = state.cond_index;
   2837            write!(state, "auto _c{}_ = ", cond_index);
   2838            show_hir_expr(state, &cond);
   2839            state.write(";\n");
   2840            (
   2841                cond_index,
   2842                Box::new(hir::Expr {
   2843                    kind: hir::ExprKind::Cond(cond_index, cond),
   2844                    ty: hir::Type::new(hir::TypeKind::Bool),
   2845                }),
   2846            )
   2847        } else {
   2848            (0, sst.cond.clone())
   2849        };
   2850 
   2851        let previous = mem::replace(&mut state.mask, None);
   2852        state.mask = Some(match previous.clone() {
   2853            Some(e) => {
   2854                let cond = Box::new(hir::Expr {
   2855                    kind: hir::ExprKind::Binary(syntax::BinaryOp::BitAnd, e, mask.clone()),
   2856                    ty: hir::Type::new(hir::TypeKind::Bool),
   2857                });
   2858                state.cond_index += 1;
   2859                let nested_cond_index = state.cond_index;
   2860                show_indent(state);
   2861                write!(state, "auto _c{}_ = ", nested_cond_index);
   2862                show_hir_expr(state, &cond);
   2863                state.write(";\n");
   2864                Box::new(hir::Expr {
   2865                    kind: hir::ExprKind::Cond(nested_cond_index, cond),
   2866                    ty: hir::Type::new(hir::TypeKind::Bool),
   2867                })
   2868            }
   2869            None => mask.clone(),
   2870        });
   2871 
   2872        show_statement(state, &sst.body);
   2873        state.mask = previous;
   2874 
   2875        if let Some(rest) = &sst.else_stmt {
   2876            // invert the condition
   2877            let inverted_cond = Box::new(hir::Expr {
   2878                kind: hir::ExprKind::Unary(UnaryOp::Complement, mask),
   2879                ty: hir::Type::new(hir::TypeKind::Bool),
   2880            });
   2881            let previous = mem::replace(&mut state.mask, None);
   2882            state.mask = Some(match previous.clone() {
   2883                Some(e) => {
   2884                    let cond = Box::new(hir::Expr {
   2885                        kind: hir::ExprKind::Binary(syntax::BinaryOp::BitAnd, e, inverted_cond),
   2886                        ty: hir::Type::new(hir::TypeKind::Bool),
   2887                    });
   2888                    show_indent(state);
   2889                    write!(state, "_c{}_ = ", cond_index);
   2890                    show_hir_expr(state, &cond);
   2891                    state.write(";\n");
   2892                    Box::new(hir::Expr {
   2893                        kind: hir::ExprKind::Cond(cond_index, cond),
   2894                        ty: hir::Type::new(hir::TypeKind::Bool),
   2895                    })
   2896                }
   2897                None => inverted_cond,
   2898            });
   2899 
   2900            show_statement(state, rest);
   2901            state.mask = previous;
   2902        }
   2903    } else {
   2904        state.write("if (");
   2905        show_hir_expr(state, &sst.cond);
   2906        state.write(") {\n");
   2907 
   2908        state.indent();
   2909        show_statement(state, &sst.body);
   2910        state.outdent();
   2911 
   2912        show_indent(state);
   2913        if let Some(rest) = &sst.else_stmt {
   2914            state.write("} else ");
   2915            show_statement(state, rest);
   2916        } else {
   2917            state.write("}\n");
   2918        }
   2919    }
   2920 }
   2921 
   2922 fn case_stmts_to_if_stmts(stmts: &[Statement], last: bool) -> (Option<Box<Statement>>, bool) {
   2923    // Look for jump statements and remove them
   2924    // We currently are pretty strict on the form that the statement
   2925    // list needs to be in. This can be loosened as needed.
   2926    let mut fallthrough = false;
   2927    let cstmt = match &stmts[..] {
   2928        [hir::Statement::Compound(c)] => match c.statement_list.split_last() {
   2929            Some((hir::Statement::Simple(s), rest)) => match **s {
   2930                hir::SimpleStatement::Jump(hir::JumpStatement::Break) => hir::CompoundStatement {
   2931                    statement_list: rest.to_owned(),
   2932                },
   2933                _ => panic!("fall through not supported"),
   2934            },
   2935            _ => panic!("empty compound"),
   2936        },
   2937        [hir::Statement::Simple(s)] => {
   2938            match **s {
   2939                hir::SimpleStatement::Jump(hir::JumpStatement::Break) => hir::CompoundStatement {
   2940                    statement_list: Vec::new(),
   2941                },
   2942                _ => {
   2943                    if last {
   2944                        // we don't need a break at the end
   2945                        hir::CompoundStatement {
   2946                            statement_list: vec![hir::Statement::Simple(s.clone())],
   2947                        }
   2948                    } else {
   2949                        panic!("fall through not supported {:?}", s)
   2950                    }
   2951                }
   2952            }
   2953        }
   2954        [] => return (None, true),
   2955        stmts => match stmts.split_last() {
   2956            Some((hir::Statement::Simple(s), rest)) => match **s {
   2957                hir::SimpleStatement::Jump(hir::JumpStatement::Break) => hir::CompoundStatement {
   2958                    statement_list: rest.to_owned(),
   2959                },
   2960                _ => {
   2961                    if !last {
   2962                        fallthrough = true;
   2963                    }
   2964                    hir::CompoundStatement {
   2965                        statement_list: stmts.to_owned(),
   2966                    }
   2967                }
   2968            },
   2969            _ => panic!("unexpected empty"),
   2970        },
   2971    };
   2972    let stmts = Box::new(hir::Statement::Compound(Box::new(cstmt)));
   2973    (Some(stmts), fallthrough)
   2974 }
   2975 
   2976 fn build_selection<'a, I: Iterator<Item = &'a hir::Case>>(
   2977    head: &Box<hir::Expr>,
   2978    case: &hir::Case,
   2979    mut cases: I,
   2980    default: Option<&hir::Case>,
   2981    previous_condition: Option<Box<hir::Expr>>,
   2982    previous_stmts: Option<Box<hir::Statement>>,
   2983 ) -> hir::SelectionStatement {
   2984    let cond = match &case.label {
   2985        hir::CaseLabel::Case(e) => Some(Box::new(hir::Expr {
   2986            kind: hir::ExprKind::Binary(syntax::BinaryOp::Equal, head.clone(), e.clone()),
   2987            ty: hir::Type::new(hir::TypeKind::Bool),
   2988        })),
   2989        hir::CaseLabel::Def => None,
   2990    };
   2991 
   2992    // if we have two conditions join them
   2993    let cond = match (&previous_condition, &cond) {
   2994        (Some(prev), Some(cond)) => Some(Box::new(hir::Expr {
   2995            kind: hir::ExprKind::Binary(syntax::BinaryOp::Or, prev.clone(), cond.clone()),
   2996            ty: hir::Type::new(hir::TypeKind::Bool),
   2997        })),
   2998        (_, cond) => cond.clone(),
   2999    };
   3000 
   3001    /*
   3002 
   3003    // find the next case that's not a default
   3004    let next_case = loop {
   3005      match cases.next() {
   3006        Some(hir::Case { label: hir::CaseLabel::Def, ..}) => { },
   3007        case => break case,
   3008      }
   3009    };*/
   3010 
   3011    let (cond, body, else_stmt) = match (cond, cases.next()) {
   3012        (None, Some(next_case)) => {
   3013            assert!(previous_stmts.is_none());
   3014            // default so just move on to the next
   3015            return build_selection(head, next_case, cases, default, None, None);
   3016        }
   3017        (Some(cond), Some(next_case)) => {
   3018            assert!(previous_stmts.is_none());
   3019            let (stmts, fallthrough) = case_stmts_to_if_stmts(&case.stmts, false);
   3020            if !fallthrough && stmts.is_some() {
   3021                (
   3022                    cond,
   3023                    stmts.unwrap(),
   3024                    Some(Box::new(hir::Statement::Simple(Box::new(
   3025                        hir::SimpleStatement::Selection(build_selection(
   3026                            head, next_case, cases, default, None, None,
   3027                        )),
   3028                    )))),
   3029                )
   3030            } else {
   3031                // empty so fall through to the next
   3032                return build_selection(head, next_case, cases, default, Some(cond), stmts);
   3033            }
   3034        }
   3035        (Some(cond), None) => {
   3036            // non-default last
   3037            assert!(previous_stmts.is_none());
   3038            let (stmts, _) = case_stmts_to_if_stmts(&case.stmts, default.is_none());
   3039            let stmts = stmts.expect("empty case labels unsupported at the end");
   3040            // add the default case at the end if we have one
   3041            (
   3042                cond,
   3043                stmts,
   3044                match default {
   3045                    Some(default) => {
   3046                        let (default_stmts, fallthrough) =
   3047                            case_stmts_to_if_stmts(&default.stmts, true);
   3048                        assert!(!fallthrough);
   3049                        Some(default_stmts.expect("empty default unsupported"))
   3050                    }
   3051                    None => None,
   3052                },
   3053            )
   3054        }
   3055        (None, None) => {
   3056            // default, last
   3057 
   3058            assert!(default.is_some());
   3059 
   3060            let (stmts, fallthrough) = case_stmts_to_if_stmts(&case.stmts, true);
   3061            let stmts = stmts.expect("empty default unsupported");
   3062            assert!(!fallthrough);
   3063 
   3064            match previous_stmts {
   3065                Some(previous_stmts) => {
   3066                    let cond = previous_condition.expect("must have previous condition");
   3067                    (cond, previous_stmts, Some(stmts))
   3068                }
   3069                None => {
   3070                    let cond = Box::new(hir::Expr {
   3071                        kind: hir::ExprKind::BoolConst(true),
   3072                        ty: hir::Type::new(hir::TypeKind::Bool),
   3073                    });
   3074                    (cond, stmts, None)
   3075                }
   3076            }
   3077        }
   3078    };
   3079 
   3080    hir::SelectionStatement {
   3081        cond,
   3082        body,
   3083        else_stmt,
   3084    }
   3085 }
   3086 
   3087 pub fn lower_switch_to_ifs(sst: &hir::SwitchStatement) -> hir::SelectionStatement {
   3088    let default = sst.cases.iter().find(|x| x.label == hir::CaseLabel::Def);
   3089    let mut cases = sst.cases.iter();
   3090    let r = build_selection(&sst.head, cases.next().unwrap(), cases, default, None, None);
   3091    r
   3092 }
   3093 
   3094 fn is_declaration(stmt: &hir::Statement) -> bool {
   3095    if let hir::Statement::Simple(s) = stmt {
   3096        if let hir::SimpleStatement::Declaration(..) = **s {
   3097            return true;
   3098        }
   3099    }
   3100    return false;
   3101 }
   3102 
   3103 pub fn show_switch_statement(state: &mut OutputState, sst: &hir::SwitchStatement) {
   3104    if state.output_cxx && expr_run_class(state, &sst.head) != hir::RunClass::Scalar {
   3105        // XXX: when lowering switches we end up with a mask that has
   3106        // a bunch of mutually exclusive conditions.
   3107        // It would be nice if we could fold them together.
   3108        let ifs = lower_switch_to_ifs(sst);
   3109        return show_selection_statement(state, &ifs);
   3110    }
   3111 
   3112    show_indent(state);
   3113    state.write("switch (");
   3114    show_hir_expr(state, &sst.head);
   3115    state.write(") {\n");
   3116    state.indent();
   3117 
   3118    for case in &sst.cases {
   3119        show_case_label(state, &case.label);
   3120        state.indent();
   3121 
   3122        let has_declaration = case.stmts.iter().any(|x| is_declaration(x));
   3123        // glsl allows declarations in switch statements while C requires them to be
   3124        // in a compound statement. If we have a declaration wrap the statements in an block.
   3125        // This will break some glsl shaders but keeps the saner ones working
   3126        if has_declaration {
   3127            show_indent(state);
   3128            state.write("{\n");
   3129            state.indent();
   3130        }
   3131        for st in &case.stmts {
   3132            show_statement(state, st);
   3133        }
   3134 
   3135        if has_declaration {
   3136            show_indent(state);
   3137            state.write("}\n");
   3138            state.outdent();
   3139        }
   3140 
   3141        state.outdent();
   3142    }
   3143    state.outdent();
   3144    show_indent(state);
   3145    state.write("}\n");
   3146 }
   3147 
   3148 pub fn show_case_label(state: &mut OutputState, cl: &hir::CaseLabel) {
   3149    show_indent(state);
   3150    match *cl {
   3151        hir::CaseLabel::Case(ref e) => {
   3152            state.write("case ");
   3153            show_hir_expr(state, e);
   3154            state.write(":\n");
   3155        }
   3156        hir::CaseLabel::Def => {
   3157            state.write("default:\n");
   3158        }
   3159    }
   3160 }
   3161 
   3162 pub fn show_iteration_statement(state: &mut OutputState, ist: &hir::IterationStatement) {
   3163    show_indent(state);
   3164    match *ist {
   3165        hir::IterationStatement::While(ref cond, ref body) => {
   3166            state.write("while (");
   3167            show_condition(state, cond);
   3168            state.write(") ");
   3169            show_statement(state, body);
   3170        }
   3171        hir::IterationStatement::DoWhile(ref body, ref cond) => {
   3172            state.write("do ");
   3173            show_statement(state, body);
   3174            state.write(" while (");
   3175            show_hir_expr(state, cond);
   3176            state.write(");\n");
   3177        }
   3178        hir::IterationStatement::For(ref init, ref rest, ref body) => {
   3179            state.write("for (");
   3180            show_for_init_statement(state, init);
   3181            show_for_rest_statement(state, rest);
   3182            state.write(") ");
   3183            show_statement(state, body);
   3184        }
   3185    }
   3186 }
   3187 
   3188 pub fn show_condition(state: &mut OutputState, c: &hir::Condition) {
   3189    match *c {
   3190        hir::Condition::Expr(ref e) => show_hir_expr(state, e),
   3191        /*hir::Condition::Assignment(ref ty, ref name, ref initializer) => {
   3192          show_type(state, ty);
   3193          state.write(" ");
   3194          show_identifier(f, name);
   3195          state.write(" = ");
   3196          show_initializer(state, initializer);
   3197        }*/
   3198    }
   3199 }
   3200 
   3201 pub fn show_for_init_statement(state: &mut OutputState, i: &hir::ForInitStatement) {
   3202    match *i {
   3203        hir::ForInitStatement::Expression(ref expr) => {
   3204            if let Some(ref e) = *expr {
   3205                show_hir_expr(state, e);
   3206            }
   3207        }
   3208        hir::ForInitStatement::Declaration(ref d) => {
   3209            show_declaration(state, d);
   3210        }
   3211    }
   3212 }
   3213 
   3214 pub fn show_for_rest_statement(state: &mut OutputState, r: &hir::ForRestStatement) {
   3215    if let Some(ref cond) = r.condition {
   3216        show_condition(state, cond);
   3217    }
   3218 
   3219    state.write("; ");
   3220 
   3221    if let Some(ref e) = r.post_expr {
   3222        show_hir_expr(state, e);
   3223    }
   3224 }
   3225 
   3226 fn use_return_mask(state: &OutputState) -> bool {
   3227    if let Some(mask) = &state.mask {
   3228        mask.kind != hir::ExprKind::CondMask
   3229    } else {
   3230        false
   3231    }
   3232 }
   3233 
   3234 pub fn show_jump_statement(state: &mut OutputState, j: &hir::JumpStatement) {
   3235    show_indent(state);
   3236    match *j {
   3237        hir::JumpStatement::Continue => {
   3238            state.write("continue;\n");
   3239        }
   3240        hir::JumpStatement::Break => {
   3241            state.write("break;\n");
   3242        }
   3243        hir::JumpStatement::Discard => {
   3244            if state.output_cxx {
   3245                state.uses_discard = true;
   3246                if let Some(mask) = &state.mask {
   3247                    state.write("swgl_IsPixelDiscarded |= (");
   3248                    show_hir_expr(state, mask);
   3249                    state.write(")");
   3250                    if state.return_declared {
   3251                        state.write("&ret_mask");
   3252                    }
   3253                    state.write(";\n");
   3254                } else {
   3255                    state.write("swgl_IsPixelDiscarded = true;\n");
   3256                }
   3257            } else {
   3258                state.write("discard;\n");
   3259            }
   3260        }
   3261        hir::JumpStatement::Return(ref e) => {
   3262            if let Some(e) = e {
   3263                if state.output_cxx {
   3264                    if use_return_mask(state) {
   3265                        // We cast any conditions by `ret_mask_type` so that scalars nicely
   3266                        // convert to -1. i.e. I32 &= bool will give the wrong result. while I32 &= I32(bool) works
   3267                        let ret_mask_type = if state.return_vector {
   3268                            "I32"
   3269                        } else {
   3270                            "int32_t"
   3271                        };
   3272                        if state.return_declared {
   3273                            // XXX: the cloning here is bad
   3274                            write!(state, "ret = if_then_else(ret_mask & {}(", ret_mask_type);
   3275                            show_hir_expr(state, &state.mask.clone().unwrap());
   3276                            state.write("), ");
   3277                            show_hir_expr(state, e);
   3278                            state.write(", ret);\n");
   3279                        } else {
   3280                            state.write("ret = ");
   3281                            show_hir_expr(state, e);
   3282                            state.write(";\n");
   3283                        }
   3284 
   3285                        show_indent(state);
   3286 
   3287                        if state.return_declared {
   3288                            write!(state, "ret_mask &= ~{}(", ret_mask_type);
   3289                        } else {
   3290                            write!(state, "ret_mask = ~{}(", ret_mask_type);
   3291                        }
   3292                        show_hir_expr(state, &state.mask.clone().unwrap());
   3293                        state.write(");\n");
   3294                        state.return_declared = true;
   3295                    } else {
   3296                        if state.return_declared {
   3297                            state.write("ret = if_then_else(ret_mask, ");
   3298                            show_hir_expr(state, e);
   3299                            state.write(", ret);\n");
   3300                        } else {
   3301                            state.write("return ");
   3302                            show_hir_expr(state, e);
   3303                            state.write(";\n");
   3304                        }
   3305                    }
   3306                } else {
   3307                    state.write("return ");
   3308                    show_hir_expr(state, e);
   3309                    state.write(";\n");
   3310                }
   3311            } else {
   3312                if state.output_cxx {
   3313                    if use_return_mask(state) {
   3314                        show_indent(state);
   3315                        let ret_mask_type = if state.return_vector {
   3316                            "I32"
   3317                        } else {
   3318                            "int32_t"
   3319                        };
   3320                        if state.return_declared {
   3321                            write!(state, "ret_mask &= ~{}(", ret_mask_type);
   3322                        } else {
   3323                            write!(state, "ret_mask = ~{}(", ret_mask_type);
   3324                        }
   3325                        show_hir_expr(state, &state.mask.clone().unwrap());
   3326                        state.write(");\n");
   3327                        state.return_declared = true;
   3328                    } else {
   3329                        state.write("return;\n");
   3330                    }
   3331                } else {
   3332                    state.write("return;\n");
   3333                }
   3334            }
   3335        }
   3336    }
   3337 }
   3338 
   3339 pub fn show_path(state: &OutputState, path: &syntax::Path) {
   3340    match path {
   3341        syntax::Path::Absolute(s) => {
   3342            let _ = write!(state, "<{}>", s);
   3343        }
   3344        syntax::Path::Relative(s) => {
   3345            let _ = write!(state, "\"{}\"", s);
   3346        }
   3347    }
   3348 }
   3349 
   3350 pub fn show_preprocessor(state: &OutputState, pp: &syntax::Preprocessor) {
   3351    match *pp {
   3352        syntax::Preprocessor::Define(ref pd) => show_preprocessor_define(state, pd),
   3353        syntax::Preprocessor::Else => show_preprocessor_else(state),
   3354        syntax::Preprocessor::ElseIf(ref pei) => show_preprocessor_elseif(state, pei),
   3355        syntax::Preprocessor::EndIf => show_preprocessor_endif(state),
   3356        syntax::Preprocessor::Error(ref pe) => show_preprocessor_error(state, pe),
   3357        syntax::Preprocessor::If(ref pi) => show_preprocessor_if(state, pi),
   3358        syntax::Preprocessor::IfDef(ref pid) => show_preprocessor_ifdef(state, pid),
   3359        syntax::Preprocessor::IfNDef(ref pind) => show_preprocessor_ifndef(state, pind),
   3360        syntax::Preprocessor::Include(ref pi) => show_preprocessor_include(state, pi),
   3361        syntax::Preprocessor::Line(ref pl) => show_preprocessor_line(state, pl),
   3362        syntax::Preprocessor::Pragma(ref pp) => show_preprocessor_pragma(state, pp),
   3363        syntax::Preprocessor::Undef(ref pu) => show_preprocessor_undef(state, pu),
   3364        syntax::Preprocessor::Version(ref pv) => show_preprocessor_version(state, pv),
   3365        syntax::Preprocessor::Extension(ref pe) => show_preprocessor_extension(state, pe),
   3366    }
   3367 }
   3368 
   3369 pub fn show_preprocessor_define(state: &OutputState, pd: &syntax::PreprocessorDefine) {
   3370    match *pd {
   3371        syntax::PreprocessorDefine::ObjectLike {
   3372            ref ident,
   3373            ref value,
   3374        } => {
   3375            let _ = write!(state, "#define {} {}\n", ident, value);
   3376        }
   3377 
   3378        syntax::PreprocessorDefine::FunctionLike {
   3379            ref ident,
   3380            ref args,
   3381            ref value,
   3382        } => {
   3383            let _ = write!(state, "#define {}(", ident);
   3384 
   3385            if !args.is_empty() {
   3386                let _ = write!(state, "{}", &args[0]);
   3387 
   3388                for arg in &args[1 .. args.len()] {
   3389                    let _ = write!(state, ", {}", arg);
   3390                }
   3391            }
   3392 
   3393            let _ = write!(state, ") {}\n", value);
   3394        }
   3395    }
   3396 }
   3397 
   3398 pub fn show_preprocessor_else(state: &OutputState) {
   3399    state.write("#else\n");
   3400 }
   3401 
   3402 pub fn show_preprocessor_elseif(state: &OutputState, pei: &syntax::PreprocessorElseIf) {
   3403    let _ = write!(state, "#elseif {}\n", pei.condition);
   3404 }
   3405 
   3406 pub fn show_preprocessor_error(state: &OutputState, pe: &syntax::PreprocessorError) {
   3407    let _ = writeln!(state, "#error {}", pe.message);
   3408 }
   3409 
   3410 pub fn show_preprocessor_endif(state: &OutputState) {
   3411    state.write("#endif\n");
   3412 }
   3413 
   3414 pub fn show_preprocessor_if(state: &OutputState, pi: &syntax::PreprocessorIf) {
   3415    let _ = write!(state, "#if {}\n", pi.condition);
   3416 }
   3417 
   3418 pub fn show_preprocessor_ifdef(state: &OutputState, pid: &syntax::PreprocessorIfDef) {
   3419    state.write("#ifdef ");
   3420    show_identifier(state, &pid.ident);
   3421    state.write("\n");
   3422 }
   3423 
   3424 pub fn show_preprocessor_ifndef(state: &OutputState, pind: &syntax::PreprocessorIfNDef) {
   3425    state.write("#ifndef ");
   3426    show_identifier(state, &pind.ident);
   3427    state.write("\n");
   3428 }
   3429 
   3430 pub fn show_preprocessor_include(state: &OutputState, pi: &syntax::PreprocessorInclude) {
   3431    state.write("#include ");
   3432    show_path(state, &pi.path);
   3433    state.write("\n");
   3434 }
   3435 
   3436 pub fn show_preprocessor_line(state: &OutputState, pl: &syntax::PreprocessorLine) {
   3437    let _ = write!(state, "#line {}", pl.line);
   3438    if let Some(source_string_number) = pl.source_string_number {
   3439        let _ = write!(state, " {}", source_string_number);
   3440    }
   3441    state.write("\n");
   3442 }
   3443 
   3444 pub fn show_preprocessor_pragma(state: &OutputState, pp: &syntax::PreprocessorPragma) {
   3445    let _ = writeln!(state, "#pragma {}", pp.command);
   3446 }
   3447 
   3448 pub fn show_preprocessor_undef(state: &OutputState, pud: &syntax::PreprocessorUndef) {
   3449    state.write("#undef ");
   3450    show_identifier(state, &pud.name);
   3451    state.write("\n");
   3452 }
   3453 
   3454 pub fn show_preprocessor_version(state: &OutputState, pv: &syntax::PreprocessorVersion) {
   3455    let _ = write!(state, "#version {}", pv.version);
   3456 
   3457    if let Some(ref profile) = pv.profile {
   3458        match *profile {
   3459            syntax::PreprocessorVersionProfile::Core => {
   3460                state.write(" core");
   3461            }
   3462            syntax::PreprocessorVersionProfile::Compatibility => {
   3463                state.write(" compatibility");
   3464            }
   3465            syntax::PreprocessorVersionProfile::ES => {
   3466                state.write(" es");
   3467            }
   3468        }
   3469    }
   3470 
   3471    state.write("\n");
   3472 }
   3473 
   3474 pub fn show_preprocessor_extension(state: &OutputState, pe: &syntax::PreprocessorExtension) {
   3475    state.write("#extension ");
   3476 
   3477    match pe.name {
   3478        syntax::PreprocessorExtensionName::All => {
   3479            state.write("all");
   3480        }
   3481        syntax::PreprocessorExtensionName::Specific(ref n) => {
   3482            state.write(n);
   3483        }
   3484    }
   3485 
   3486    if let Some(ref behavior) = pe.behavior {
   3487        match *behavior {
   3488            syntax::PreprocessorExtensionBehavior::Require => {
   3489                state.write(" : require");
   3490            }
   3491            syntax::PreprocessorExtensionBehavior::Enable => {
   3492                state.write(" : enable");
   3493            }
   3494            syntax::PreprocessorExtensionBehavior::Warn => {
   3495                state.write(" : warn");
   3496            }
   3497            syntax::PreprocessorExtensionBehavior::Disable => {
   3498                state.write(" : disable");
   3499            }
   3500        }
   3501    }
   3502 
   3503    state.write("\n");
   3504 }
   3505 
   3506 pub fn show_external_declaration(state: &mut OutputState, ed: &hir::ExternalDeclaration) {
   3507    match *ed {
   3508        hir::ExternalDeclaration::Preprocessor(ref pp) => {
   3509            if !state.output_cxx {
   3510                show_preprocessor(state, pp)
   3511            }
   3512        }
   3513        hir::ExternalDeclaration::FunctionDefinition(ref fd) => {
   3514            if !state.output_cxx {
   3515                show_function_definition(state, fd, !0)
   3516            }
   3517        }
   3518        hir::ExternalDeclaration::Declaration(ref d) => show_declaration(state, d),
   3519    }
   3520 }
   3521 
   3522 pub fn show_cxx_function_definition(state: &mut OutputState, name: hir::SymRef, vector_mask: u32) {
   3523    if let Some((ref fd, run_class)) = state.hir.function_definition(name) {
   3524        state.vector_mask = vector_mask;
   3525        state.return_vector = (vector_mask & (1 << 31)) != 0
   3526            || match run_class {
   3527                hir::RunClass::Scalar => false,
   3528                hir::RunClass::Dependent(mask) => (mask & vector_mask) != 0,
   3529                _ => true,
   3530            };
   3531        match state.functions.get(&(name, vector_mask)) {
   3532            Some(true) => {}
   3533            Some(false) => {
   3534                show_function_prototype(state, &fd.prototype);
   3535                state.functions.insert((name, vector_mask), true);
   3536            }
   3537            None => {
   3538                state.functions.insert((name, vector_mask), false);
   3539                let buffer = state.push_buffer();
   3540                show_function_definition(state, fd, vector_mask);
   3541                for (name, vector_mask) in state.deps.replace(Vec::new()) {
   3542                    show_cxx_function_definition(state, name, vector_mask);
   3543                }
   3544                state.flush_buffer();
   3545                state.pop_buffer(buffer);
   3546                state.functions.insert((name, vector_mask), true);
   3547            }
   3548        }
   3549    }
   3550 }
   3551 
   3552 pub fn show_translation_unit(state: &mut OutputState, tu: &hir::TranslationUnit) {
   3553    state.flush_buffer();
   3554 
   3555    for ed in &(tu.0).0 {
   3556        show_external_declaration(state, ed);
   3557        state.flush_buffer();
   3558    }
   3559    if state.output_cxx {
   3560        for name in &["main", "swgl_drawSpanRGBA8", "swgl_drawSpanR8"] {
   3561            if let Some(sym) = state.hir.lookup(name) {
   3562                show_cxx_function_definition(state, sym, 0);
   3563                state.flush_buffer();
   3564            }
   3565        }
   3566    }
   3567 }
   3568 
   3569 fn write_abi(state: &mut OutputState) {
   3570    match state.kind {
   3571        ShaderKind::Fragment => {
   3572            state.write("static void run(FragmentShaderImpl* impl) {\n");
   3573            state.write(" Self* self = (Self*)impl;\n");
   3574            if state.uses_discard {
   3575                state.write(" self->swgl_IsPixelDiscarded = false;\n");
   3576            }
   3577            state.write(" self->main();\n");
   3578            state.write(" self->step_interp_inputs();\n");
   3579            state.write("}\n");
   3580            state.write("static void skip(FragmentShaderImpl* impl, int steps) {\n");
   3581            state.write(" Self* self = (Self*)impl;\n");
   3582            state.write(" self->step_interp_inputs(steps);\n");
   3583            state.write("}\n");
   3584            if state.use_perspective {
   3585                state.write("static void run_perspective(FragmentShaderImpl* impl) {\n");
   3586                state.write(" Self* self = (Self*)impl;\n");
   3587                if state.uses_discard {
   3588                    state.write(" self->swgl_IsPixelDiscarded = false;\n");
   3589                }
   3590                state.write(" self->main();\n");
   3591                state.write(" self->step_perspective_inputs();\n");
   3592                state.write("}\n");
   3593                state.write("static void skip_perspective(FragmentShaderImpl* impl, int steps) {\n");
   3594                state.write(" Self* self = (Self*)impl;\n");
   3595                state.write(" self->step_perspective_inputs(steps);\n");
   3596                state.write("}\n");
   3597            }
   3598            if state.hir.lookup("swgl_drawSpanRGBA8").is_some() {
   3599                state.write("static int draw_span_RGBA8(FragmentShaderImpl* impl) {\n");
   3600                state.write(" Self* self = (Self*)impl; DISPATCH_DRAW_SPAN(self, RGBA8); }\n");
   3601            }
   3602            if state.hir.lookup("swgl_drawSpanR8").is_some() {
   3603                state.write("static int draw_span_R8(FragmentShaderImpl* impl) {\n");
   3604                state.write(" Self* self = (Self*)impl; DISPATCH_DRAW_SPAN(self, R8); }\n");
   3605            }
   3606 
   3607            write!(state, "public:\n{}_frag() {{\n", state.name);
   3608        }
   3609        ShaderKind::Vertex => {
   3610            state.write("static void run(VertexShaderImpl* impl, char* interps, size_t interp_stride) {\n");
   3611            state.write(" Self* self = (Self*)impl;\n");
   3612            state.write(" self->main();\n");
   3613            state.write(" self->store_interp_outputs(interps, interp_stride);\n");
   3614            state.write("}\n");
   3615            state.write("static void init_batch(VertexShaderImpl* impl) {\n");
   3616            state.write(" Self* self = (Self*)impl; self->bind_textures(); }\n");
   3617 
   3618            write!(state, "public:\n{}_vert() {{\n", state.name);
   3619        }
   3620    }
   3621    match state.kind {
   3622        ShaderKind::Fragment => {
   3623            state.write(" init_span_func = &read_interp_inputs;\n");
   3624            state.write(" run_func = &run;\n");
   3625            state.write(" skip_func = &skip;\n");
   3626            if state.hir.lookup("swgl_drawSpanRGBA8").is_some() {
   3627                state.write(" draw_span_RGBA8_func = &draw_span_RGBA8;\n");
   3628            }
   3629            if state.hir.lookup("swgl_drawSpanR8").is_some() {
   3630                state.write(" draw_span_R8_func = &draw_span_R8;\n");
   3631            }
   3632            if state.uses_discard {
   3633                state.write(" enable_discard();\n");
   3634            }
   3635            if state.use_perspective {
   3636                state.write(" enable_perspective();\n");
   3637                state.write(" init_span_w_func = &read_perspective_inputs;\n");
   3638                state.write(" run_w_func = &run_perspective;\n");
   3639                state.write(" skip_w_func = &skip_perspective;\n");
   3640            } else {
   3641                state.write(" init_span_w_func = &read_interp_inputs;\n");
   3642                state.write(" run_w_func = &run;\n");
   3643                state.write(" skip_w_func = &skip;\n");
   3644            }
   3645        }
   3646        ShaderKind::Vertex => {
   3647            state.write(" set_uniform_1i_func = &set_uniform_1i;\n");
   3648            state.write(" set_uniform_4fv_func = &set_uniform_4fv;\n");
   3649            state.write(" set_uniform_matrix4fv_func = &set_uniform_matrix4fv;\n");
   3650            state.write(" init_batch_func = &init_batch;\n");
   3651            state.write(" load_attribs_func = &load_attribs;\n");
   3652            state.write(" run_primitive_func = &run;\n");
   3653            if state.hir.used_clip_dist != 0 {
   3654                state.write(" enable_clip_distance();\n");
   3655            }
   3656        }
   3657    }
   3658    state.write("}\n");
   3659 }
   3660 
   3661 pub fn define_global_consts(state: &mut OutputState, tu: &hir::TranslationUnit, part_name: &str) {
   3662    for i in tu {
   3663        match i {
   3664            hir::ExternalDeclaration::Declaration(hir::Declaration::InitDeclaratorList(ref d)) => {
   3665                let sym = state.hir.sym(d.head.name);
   3666                match &sym.decl {
   3667                    hir::SymDecl::Global(hir::StorageClass::Const, ..) => {
   3668                        let is_scalar = state.is_scalar.replace(
   3669                            symbol_run_class(&sym.decl, state.vector_mask) == hir::RunClass::Scalar,
   3670                        );
   3671                        if let Some(ref _array) = d.head.ty.array_sizes {
   3672                            show_type(state, &d.head.ty);
   3673                        } else {
   3674                            if let Some(ty_def) = d.head.ty_def {
   3675                                show_sym_decl(state, &ty_def);
   3676                            } else {
   3677                                show_type(state, &d.head.ty);
   3678                            }
   3679                        }
   3680                        write!(state, " constexpr {}::{};\n", part_name, sym.name);
   3681                        state.is_scalar.set(is_scalar);
   3682                    }
   3683                    _ => {}
   3684                }
   3685            }
   3686            _ => {}
   3687        }
   3688    }
   3689 }