Skip to main content

glsl_to_cxx/
lib.rs

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
7extern crate glsl;
8
9mod hir;
10
11use glsl::parser::Parse;
12use glsl::syntax;
13use glsl::syntax::{TranslationUnit, UnaryOp};
14use hir::{Statement, Type};
15use std::cell::{Cell, RefCell};
16use std::collections::{BTreeMap, HashMap};
17use std::io::Read;
18use std::mem;
19
20#[derive(PartialEq, Eq)]
21enum ShaderKind {
22    Fragment,
23    Vertex,
24}
25
26type UniformIndices = BTreeMap<String, (i32, hir::TypeKind, hir::StorageClass)>;
27
28fn 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
48pub 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
94fn 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
118fn 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
264fn 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
280fn float4_compatible(ty: hir::TypeKind) -> bool {
281    match ty {
282        hir::TypeKind::Vec4 => true,
283        _ => false,
284    }
285}
286
287fn matrix4_compatible(ty: hir::TypeKind) -> bool {
288    match ty {
289        hir::TypeKind::Mat4 => true,
290        _ => false,
291    }
292}
293
294fn 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
338fn 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
360fn 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
388fn 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
415fn 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
442fn 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
472fn 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
519fn 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
544fn 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
601fn 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
750pub 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
776use std::fmt::{Arguments, Write};
777
778impl 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
820pub fn show_identifier(state: &OutputState, i: &syntax::Identifier) {
821    state.write(&i.0);
822}
823
824fn 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
830fn 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
837pub 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
868pub 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
884pub fn write_default_constructor(state: &OutputState, name: &str) {
885    // write default constructor
886    let _ = write!(state, "{}() = default;\n", name);
887}
888
889pub 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
917pub 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
981pub 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
998pub 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
1019pub 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
1082pub fn show_type_name(state: &OutputState, t: &syntax::TypeName) {
1083    state.write(&t.0);
1084}
1085
1086pub 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
1098pub 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
1139pub 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
1147pub 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
1211pub fn show_struct(_state: &OutputState, _s: &syntax::StructSpecifier) {
1212    panic!();
1213    //show_struct_non_declaration(state, s);
1214    //state.write(";\n");
1215}
1216
1217pub 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
1226pub 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
1241pub 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
1251pub 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
1259pub 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
1278pub 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
1290pub 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
1304pub 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
1361pub 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
1381pub 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
1396pub 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
1409pub 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
1423pub 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
1437pub 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
1468pub 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
1476pub 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
1485fn 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
1595pub fn show_hir_expr(state: &OutputState, expr: &hir::Expr) {
1596    show_hir_expr_inner(state, expr, false);
1597}
1598
1599pub 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
2076pub 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
2163pub 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
2186pub 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
2248pub 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
2286pub 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
2293pub 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
2300pub 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
2365pub 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
2396pub 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
2431pub 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
2440pub 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
2448pub 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
2485fn 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
2504pub 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
2566pub 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
2575pub 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/*
2596pub 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.
2615pub 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
2624fn 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
2645pub 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
2779pub 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
2793pub 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
2800pub 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
2811pub fn show_indent(state: &OutputState) {
2812    for _ in 0 .. state.indent {
2813        state.write(" ");
2814    }
2815}
2816
2817pub 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
2827pub 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
2922fn 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
2976fn 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
3087pub 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
3094fn 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
3103pub 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
3148pub 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
3162pub 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
3188pub 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
3201pub 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
3214pub 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
3226fn 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
3234pub 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
3339pub 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
3350pub 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
3369pub 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
3398pub fn show_preprocessor_else(state: &OutputState) {
3399    state.write("#else\n");
3400}
3401
3402pub fn show_preprocessor_elseif(state: &OutputState, pei: &syntax::PreprocessorElseIf) {
3403    let _ = write!(state, "#elseif {}\n", pei.condition);
3404}
3405
3406pub fn show_preprocessor_error(state: &OutputState, pe: &syntax::PreprocessorError) {
3407    let _ = writeln!(state, "#error {}", pe.message);
3408}
3409
3410pub fn show_preprocessor_endif(state: &OutputState) {
3411    state.write("#endif\n");
3412}
3413
3414pub fn show_preprocessor_if(state: &OutputState, pi: &syntax::PreprocessorIf) {
3415    let _ = write!(state, "#if {}\n", pi.condition);
3416}
3417
3418pub 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
3424pub 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
3430pub 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
3436pub 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
3444pub fn show_preprocessor_pragma(state: &OutputState, pp: &syntax::PreprocessorPragma) {
3445    let _ = writeln!(state, "#pragma {}", pp.command);
3446}
3447
3448pub 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
3454pub 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
3474pub 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
3506pub 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
3522pub 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
3552pub 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
3569fn 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
3661pub 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}