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