1use std::collections::{HashMap, HashSet, VecDeque};
6
7#[allow(dead_code)]
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum GlslBlockLayout {
11 Std140,
12 Std430,
13 Shared,
14}
15impl GlslBlockLayout {
16 pub fn qualifier_str(self) -> &'static str {
18 match self {
19 GlslBlockLayout::Std140 => "std140",
20 GlslBlockLayout::Std430 => "std430",
21 GlslBlockLayout::Shared => "shared",
22 }
23 }
24}
25#[allow(dead_code)]
27#[derive(Debug, Clone, Default)]
28pub struct GLSLExtPassStats {
29 pub iterations: usize,
30 pub changed: bool,
31 pub nodes_visited: usize,
32 pub nodes_modified: usize,
33 pub time_ms: u64,
34 pub memory_bytes: usize,
35 pub errors: usize,
36}
37impl GLSLExtPassStats {
38 #[allow(dead_code)]
39 pub fn new() -> Self {
40 Self::default()
41 }
42 #[allow(dead_code)]
43 pub fn visit(&mut self) {
44 self.nodes_visited += 1;
45 }
46 #[allow(dead_code)]
47 pub fn modify(&mut self) {
48 self.nodes_modified += 1;
49 self.changed = true;
50 }
51 #[allow(dead_code)]
52 pub fn iterate(&mut self) {
53 self.iterations += 1;
54 }
55 #[allow(dead_code)]
56 pub fn error(&mut self) {
57 self.errors += 1;
58 }
59 #[allow(dead_code)]
60 pub fn efficiency(&self) -> f64 {
61 if self.nodes_visited == 0 {
62 0.0
63 } else {
64 self.nodes_modified as f64 / self.nodes_visited as f64
65 }
66 }
67 #[allow(dead_code)]
68 pub fn merge(&mut self, o: &GLSLExtPassStats) {
69 self.iterations += o.iterations;
70 self.changed |= o.changed;
71 self.nodes_visited += o.nodes_visited;
72 self.nodes_modified += o.nodes_modified;
73 self.time_ms += o.time_ms;
74 self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
75 self.errors += o.errors;
76 }
77}
78#[allow(dead_code)]
79pub struct GLSLConstantFoldingHelper;
80impl GLSLConstantFoldingHelper {
81 #[allow(dead_code)]
82 pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
83 a.checked_add(b)
84 }
85 #[allow(dead_code)]
86 pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
87 a.checked_sub(b)
88 }
89 #[allow(dead_code)]
90 pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
91 a.checked_mul(b)
92 }
93 #[allow(dead_code)]
94 pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
95 if b == 0 {
96 None
97 } else {
98 a.checked_div(b)
99 }
100 }
101 #[allow(dead_code)]
102 pub fn fold_add_f64(a: f64, b: f64) -> f64 {
103 a + b
104 }
105 #[allow(dead_code)]
106 pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
107 a * b
108 }
109 #[allow(dead_code)]
110 pub fn fold_neg_i64(a: i64) -> Option<i64> {
111 a.checked_neg()
112 }
113 #[allow(dead_code)]
114 pub fn fold_not_bool(a: bool) -> bool {
115 !a
116 }
117 #[allow(dead_code)]
118 pub fn fold_and_bool(a: bool, b: bool) -> bool {
119 a && b
120 }
121 #[allow(dead_code)]
122 pub fn fold_or_bool(a: bool, b: bool) -> bool {
123 a || b
124 }
125 #[allow(dead_code)]
126 pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
127 a.checked_shl(b)
128 }
129 #[allow(dead_code)]
130 pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
131 a.checked_shr(b)
132 }
133 #[allow(dead_code)]
134 pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
135 if b == 0 {
136 None
137 } else {
138 Some(a % b)
139 }
140 }
141 #[allow(dead_code)]
142 pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
143 a & b
144 }
145 #[allow(dead_code)]
146 pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
147 a | b
148 }
149 #[allow(dead_code)]
150 pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
151 a ^ b
152 }
153 #[allow(dead_code)]
154 pub fn fold_bitnot_i64(a: i64) -> i64 {
155 !a
156 }
157}
158#[allow(dead_code)]
160#[derive(Debug, Clone)]
161pub struct GlslBlockMember {
162 pub name: String,
163 pub ty: GLSLType,
164 pub array_size: Option<usize>,
165}
166#[allow(dead_code)]
167impl GlslBlockMember {
168 pub fn new(name: impl Into<String>, ty: GLSLType) -> Self {
169 GlslBlockMember {
170 name: name.into(),
171 ty,
172 array_size: None,
173 }
174 }
175 pub fn array(name: impl Into<String>, ty: GLSLType, size: usize) -> Self {
176 GlslBlockMember {
177 name: name.into(),
178 ty,
179 array_size: Some(size),
180 }
181 }
182}
183#[allow(dead_code)]
184pub struct GLSLPassRegistry {
185 pub(super) configs: Vec<GLSLPassConfig>,
186 pub(super) stats: std::collections::HashMap<String, GLSLPassStats>,
187}
188impl GLSLPassRegistry {
189 #[allow(dead_code)]
190 pub fn new() -> Self {
191 GLSLPassRegistry {
192 configs: Vec::new(),
193 stats: std::collections::HashMap::new(),
194 }
195 }
196 #[allow(dead_code)]
197 pub fn register(&mut self, config: GLSLPassConfig) {
198 self.stats
199 .insert(config.pass_name.clone(), GLSLPassStats::new());
200 self.configs.push(config);
201 }
202 #[allow(dead_code)]
203 pub fn enabled_passes(&self) -> Vec<&GLSLPassConfig> {
204 self.configs.iter().filter(|c| c.enabled).collect()
205 }
206 #[allow(dead_code)]
207 pub fn get_stats(&self, name: &str) -> Option<&GLSLPassStats> {
208 self.stats.get(name)
209 }
210 #[allow(dead_code)]
211 pub fn total_passes(&self) -> usize {
212 self.configs.len()
213 }
214 #[allow(dead_code)]
215 pub fn enabled_count(&self) -> usize {
216 self.enabled_passes().len()
217 }
218 #[allow(dead_code)]
219 pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
220 if let Some(stats) = self.stats.get_mut(name) {
221 stats.record_run(changes, time_ms, iter);
222 }
223 }
224}
225#[allow(dead_code)]
226#[derive(Debug, Clone)]
227pub struct GLSLDominatorTree {
228 pub idom: Vec<Option<u32>>,
229 pub dom_children: Vec<Vec<u32>>,
230 pub dom_depth: Vec<u32>,
231}
232impl GLSLDominatorTree {
233 #[allow(dead_code)]
234 pub fn new(size: usize) -> Self {
235 GLSLDominatorTree {
236 idom: vec![None; size],
237 dom_children: vec![Vec::new(); size],
238 dom_depth: vec![0; size],
239 }
240 }
241 #[allow(dead_code)]
242 pub fn set_idom(&mut self, node: usize, idom: u32) {
243 self.idom[node] = Some(idom);
244 }
245 #[allow(dead_code)]
246 pub fn dominates(&self, a: usize, b: usize) -> bool {
247 if a == b {
248 return true;
249 }
250 let mut cur = b;
251 loop {
252 match self.idom[cur] {
253 Some(parent) if parent as usize == a => return true,
254 Some(parent) if parent as usize == cur => return false,
255 Some(parent) => cur = parent as usize,
256 None => return false,
257 }
258 }
259 }
260 #[allow(dead_code)]
261 pub fn depth(&self, node: usize) -> u32 {
262 self.dom_depth.get(node).copied().unwrap_or(0)
263 }
264}
265#[derive(Debug, Clone)]
267pub struct GLSLStructField {
268 pub name: String,
270 pub ty: GLSLType,
272}
273impl GLSLStructField {
274 pub fn new(name: impl Into<String>, ty: GLSLType) -> Self {
276 GLSLStructField {
277 name: name.into(),
278 ty,
279 }
280 }
281}
282#[derive(Debug, Clone, PartialEq, Eq, Hash)]
284pub enum GLSLType {
285 Void,
287 Bool,
289 Int,
291 Uint,
293 Float,
295 Double,
297 Vec2,
299 Vec3,
301 Vec4,
303 IVec2,
305 IVec3,
307 IVec4,
309 UVec2,
311 UVec3,
313 UVec4,
315 BVec2,
317 BVec3,
319 BVec4,
321 Mat2,
323 Mat3,
325 Mat4,
327 Mat2x3,
329 Mat2x4,
331 Mat3x2,
333 Mat3x4,
335 Mat4x2,
337 Mat4x3,
339 DMat4,
341 Sampler2D,
343 Sampler3D,
345 SamplerCube,
347 Sampler2DArray,
349 Sampler2DShadow,
351 ISampler2D,
353 USampler2D,
355 Image2D,
357 UImage2D,
359 Struct(String),
361 Array(Box<GLSLType>, u32),
363}
364impl GLSLType {
365 pub fn keyword(&self) -> String {
367 match self {
368 GLSLType::Void => "void".into(),
369 GLSLType::Bool => "bool".into(),
370 GLSLType::Int => "int".into(),
371 GLSLType::Uint => "uint".into(),
372 GLSLType::Float => "float".into(),
373 GLSLType::Double => "double".into(),
374 GLSLType::Vec2 => "vec2".into(),
375 GLSLType::Vec3 => "vec3".into(),
376 GLSLType::Vec4 => "vec4".into(),
377 GLSLType::IVec2 => "ivec2".into(),
378 GLSLType::IVec3 => "ivec3".into(),
379 GLSLType::IVec4 => "ivec4".into(),
380 GLSLType::UVec2 => "uvec2".into(),
381 GLSLType::UVec3 => "uvec3".into(),
382 GLSLType::UVec4 => "uvec4".into(),
383 GLSLType::BVec2 => "bvec2".into(),
384 GLSLType::BVec3 => "bvec3".into(),
385 GLSLType::BVec4 => "bvec4".into(),
386 GLSLType::Mat2 => "mat2".into(),
387 GLSLType::Mat3 => "mat3".into(),
388 GLSLType::Mat4 => "mat4".into(),
389 GLSLType::Mat2x3 => "mat2x3".into(),
390 GLSLType::Mat2x4 => "mat2x4".into(),
391 GLSLType::Mat3x2 => "mat3x2".into(),
392 GLSLType::Mat3x4 => "mat3x4".into(),
393 GLSLType::Mat4x2 => "mat4x2".into(),
394 GLSLType::Mat4x3 => "mat4x3".into(),
395 GLSLType::DMat4 => "dmat4".into(),
396 GLSLType::Sampler2D => "sampler2D".into(),
397 GLSLType::Sampler3D => "sampler3D".into(),
398 GLSLType::SamplerCube => "samplerCube".into(),
399 GLSLType::Sampler2DArray => "sampler2DArray".into(),
400 GLSLType::Sampler2DShadow => "sampler2DShadow".into(),
401 GLSLType::ISampler2D => "isampler2D".into(),
402 GLSLType::USampler2D => "usampler2D".into(),
403 GLSLType::Image2D => "image2D".into(),
404 GLSLType::UImage2D => "uimage2D".into(),
405 GLSLType::Struct(name) => name.clone(),
406 GLSLType::Array(elem, _) => elem.keyword(),
407 }
408 }
409 pub fn component_count(&self) -> u32 {
411 match self {
412 GLSLType::Vec2 | GLSLType::IVec2 | GLSLType::UVec2 | GLSLType::BVec2 => 2,
413 GLSLType::Vec3 | GLSLType::IVec3 | GLSLType::UVec3 | GLSLType::BVec3 => 3,
414 GLSLType::Vec4 | GLSLType::IVec4 | GLSLType::UVec4 | GLSLType::BVec4 => 4,
415 GLSLType::Mat2 | GLSLType::Mat2x3 | GLSLType::Mat2x4 => 2,
416 GLSLType::Mat3 | GLSLType::Mat3x2 | GLSLType::Mat3x4 => 3,
417 GLSLType::Mat4 | GLSLType::Mat4x2 | GLSLType::Mat4x3 | GLSLType::DMat4 => 4,
418 _ => 1,
419 }
420 }
421 pub fn is_opaque(&self) -> bool {
423 matches!(
424 self,
425 GLSLType::Sampler2D
426 | GLSLType::Sampler3D
427 | GLSLType::SamplerCube
428 | GLSLType::Sampler2DArray
429 | GLSLType::Sampler2DShadow
430 | GLSLType::ISampler2D
431 | GLSLType::USampler2D
432 | GLSLType::Image2D
433 | GLSLType::UImage2D
434 )
435 }
436 pub fn is_float_like(&self) -> bool {
438 matches!(
439 self,
440 GLSLType::Float | GLSLType::Double | GLSLType::Vec2 | GLSLType::Vec3 | GLSLType::Vec4
441 )
442 }
443}
444#[allow(dead_code)]
446pub struct GlslTypeInference {
447 pub(super) bindings: std::collections::HashMap<String, GLSLType>,
448 pub(super) version: GLSLVersion,
449}
450#[allow(dead_code)]
451impl GlslTypeInference {
452 pub fn new(version: GLSLVersion) -> Self {
454 GlslTypeInference {
455 bindings: std::collections::HashMap::new(),
456 version,
457 }
458 }
459 pub fn bind(&mut self, name: impl Into<String>, ty: GLSLType) {
461 self.bindings.insert(name.into(), ty);
462 }
463 pub fn lookup(&self, name: &str) -> Option<&GLSLType> {
465 self.bindings.get(name)
466 }
467 pub fn num_components(ty: &GLSLType) -> usize {
469 match ty {
470 GLSLType::Vec2 | GLSLType::IVec2 | GLSLType::BVec2 => 2,
471 GLSLType::Vec3 | GLSLType::IVec3 | GLSLType::BVec3 => 3,
472 GLSLType::Vec4 | GLSLType::IVec4 | GLSLType::BVec4 => 4,
473 GLSLType::Mat2 => 4,
474 GLSLType::Mat3 => 9,
475 GLSLType::Mat4 => 16,
476 _ => 1,
477 }
478 }
479 pub fn type_available(&self, ty: &GLSLType) -> bool {
481 match ty {
482 GLSLType::Uint => self.version.supports_uint(),
483 _ => true,
484 }
485 }
486 pub fn version(&self) -> GLSLVersion {
488 self.version
489 }
490 pub fn num_bindings(&self) -> usize {
492 self.bindings.len()
493 }
494}
495#[allow(dead_code)]
496#[derive(Debug, Clone, PartialEq)]
497pub enum GLSLPassPhase {
498 Analysis,
499 Transformation,
500 Verification,
501 Cleanup,
502}
503impl GLSLPassPhase {
504 #[allow(dead_code)]
505 pub fn name(&self) -> &str {
506 match self {
507 GLSLPassPhase::Analysis => "analysis",
508 GLSLPassPhase::Transformation => "transformation",
509 GLSLPassPhase::Verification => "verification",
510 GLSLPassPhase::Cleanup => "cleanup",
511 }
512 }
513 #[allow(dead_code)]
514 pub fn is_modifying(&self) -> bool {
515 matches!(self, GLSLPassPhase::Transformation | GLSLPassPhase::Cleanup)
516 }
517}
518#[allow(dead_code)]
520#[derive(Debug, Clone)]
521pub struct GLSLExtWorklist {
522 pub(super) items: std::collections::VecDeque<usize>,
523 pub(super) present: Vec<bool>,
524}
525impl GLSLExtWorklist {
526 #[allow(dead_code)]
527 pub fn new(capacity: usize) -> Self {
528 Self {
529 items: std::collections::VecDeque::new(),
530 present: vec![false; capacity],
531 }
532 }
533 #[allow(dead_code)]
534 pub fn push(&mut self, id: usize) {
535 if id < self.present.len() && !self.present[id] {
536 self.present[id] = true;
537 self.items.push_back(id);
538 }
539 }
540 #[allow(dead_code)]
541 pub fn push_front(&mut self, id: usize) {
542 if id < self.present.len() && !self.present[id] {
543 self.present[id] = true;
544 self.items.push_front(id);
545 }
546 }
547 #[allow(dead_code)]
548 pub fn pop(&mut self) -> Option<usize> {
549 let id = self.items.pop_front()?;
550 if id < self.present.len() {
551 self.present[id] = false;
552 }
553 Some(id)
554 }
555 #[allow(dead_code)]
556 pub fn is_empty(&self) -> bool {
557 self.items.is_empty()
558 }
559 #[allow(dead_code)]
560 pub fn len(&self) -> usize {
561 self.items.len()
562 }
563 #[allow(dead_code)]
564 pub fn contains(&self, id: usize) -> bool {
565 id < self.present.len() && self.present[id]
566 }
567 #[allow(dead_code)]
568 pub fn drain_all(&mut self) -> Vec<usize> {
569 let v: Vec<usize> = self.items.drain(..).collect();
570 for &id in &v {
571 if id < self.present.len() {
572 self.present[id] = false;
573 }
574 }
575 v
576 }
577}
578#[allow(dead_code)]
580#[derive(Debug, Clone, Default)]
581pub struct GLSLExtConstFolder {
582 pub(super) folds: usize,
583 pub(super) failures: usize,
584 pub(super) enabled: bool,
585}
586impl GLSLExtConstFolder {
587 #[allow(dead_code)]
588 pub fn new() -> Self {
589 Self {
590 folds: 0,
591 failures: 0,
592 enabled: true,
593 }
594 }
595 #[allow(dead_code)]
596 pub fn add_i64(&mut self, a: i64, b: i64) -> Option<i64> {
597 self.folds += 1;
598 a.checked_add(b)
599 }
600 #[allow(dead_code)]
601 pub fn sub_i64(&mut self, a: i64, b: i64) -> Option<i64> {
602 self.folds += 1;
603 a.checked_sub(b)
604 }
605 #[allow(dead_code)]
606 pub fn mul_i64(&mut self, a: i64, b: i64) -> Option<i64> {
607 self.folds += 1;
608 a.checked_mul(b)
609 }
610 #[allow(dead_code)]
611 pub fn div_i64(&mut self, a: i64, b: i64) -> Option<i64> {
612 if b == 0 {
613 self.failures += 1;
614 None
615 } else {
616 self.folds += 1;
617 a.checked_div(b)
618 }
619 }
620 #[allow(dead_code)]
621 pub fn rem_i64(&mut self, a: i64, b: i64) -> Option<i64> {
622 if b == 0 {
623 self.failures += 1;
624 None
625 } else {
626 self.folds += 1;
627 a.checked_rem(b)
628 }
629 }
630 #[allow(dead_code)]
631 pub fn neg_i64(&mut self, a: i64) -> Option<i64> {
632 self.folds += 1;
633 a.checked_neg()
634 }
635 #[allow(dead_code)]
636 pub fn shl_i64(&mut self, a: i64, s: u32) -> Option<i64> {
637 if s >= 64 {
638 self.failures += 1;
639 None
640 } else {
641 self.folds += 1;
642 a.checked_shl(s)
643 }
644 }
645 #[allow(dead_code)]
646 pub fn shr_i64(&mut self, a: i64, s: u32) -> Option<i64> {
647 if s >= 64 {
648 self.failures += 1;
649 None
650 } else {
651 self.folds += 1;
652 a.checked_shr(s)
653 }
654 }
655 #[allow(dead_code)]
656 pub fn and_i64(&mut self, a: i64, b: i64) -> i64 {
657 self.folds += 1;
658 a & b
659 }
660 #[allow(dead_code)]
661 pub fn or_i64(&mut self, a: i64, b: i64) -> i64 {
662 self.folds += 1;
663 a | b
664 }
665 #[allow(dead_code)]
666 pub fn xor_i64(&mut self, a: i64, b: i64) -> i64 {
667 self.folds += 1;
668 a ^ b
669 }
670 #[allow(dead_code)]
671 pub fn not_i64(&mut self, a: i64) -> i64 {
672 self.folds += 1;
673 !a
674 }
675 #[allow(dead_code)]
676 pub fn fold_count(&self) -> usize {
677 self.folds
678 }
679 #[allow(dead_code)]
680 pub fn failure_count(&self) -> usize {
681 self.failures
682 }
683 #[allow(dead_code)]
684 pub fn enable(&mut self) {
685 self.enabled = true;
686 }
687 #[allow(dead_code)]
688 pub fn disable(&mut self) {
689 self.enabled = false;
690 }
691 #[allow(dead_code)]
692 pub fn is_enabled(&self) -> bool {
693 self.enabled
694 }
695}
696#[allow(dead_code)]
698#[derive(Debug, Clone, Default)]
699pub struct GlslMacroExpander {
700 pub(super) defines: std::collections::HashMap<String, String>,
701}
702#[allow(dead_code)]
703impl GlslMacroExpander {
704 pub fn new() -> Self {
705 GlslMacroExpander {
706 defines: std::collections::HashMap::new(),
707 }
708 }
709 pub fn define(&mut self, name: impl Into<String>, value: impl Into<String>) {
710 self.defines.insert(name.into(), value.into());
711 }
712 pub fn undef(&mut self, name: &str) {
713 self.defines.remove(name);
714 }
715 pub fn is_defined(&self, name: &str) -> bool {
716 self.defines.contains_key(name)
717 }
718 pub fn value(&self, name: &str) -> Option<&str> {
719 self.defines.get(name).map(|s| s.as_str())
720 }
721 pub fn emit_defines(&self) -> String {
722 let mut names: Vec<&String> = self.defines.keys().collect();
723 names.sort();
724 names
725 .iter()
726 .map(|name| {
727 let val = &self.defines[*name];
728 if val.is_empty() {
729 format!("#define {}\n", name)
730 } else {
731 format!("#define {} {}\n", name, val)
732 }
733 })
734 .collect()
735 }
736 pub fn num_defines(&self) -> usize {
737 self.defines.len()
738 }
739}
740#[derive(Debug, Clone)]
742pub struct GLSLStruct {
743 pub name: String,
745 pub fields: Vec<GLSLStructField>,
747}
748impl GLSLStruct {
749 pub fn new(name: impl Into<String>) -> Self {
751 GLSLStruct {
752 name: name.into(),
753 fields: Vec::new(),
754 }
755 }
756 pub fn add_field(&mut self, name: impl Into<String>, ty: GLSLType) {
758 self.fields.push(GLSLStructField::new(name, ty));
759 }
760 pub fn emit(&self) -> String {
762 let mut out = format!("struct {} {{\n", self.name);
763 for f in &self.fields {
764 out.push_str(&format!(" {} {};\n", f.ty, f.name));
765 }
766 out.push_str("};");
767 out
768 }
769}
770#[derive(Debug, Clone)]
772pub struct GLSLFunction {
773 pub name: String,
775 pub return_type: GLSLType,
777 pub params: Vec<GLSLVariable>,
779 pub body: Vec<String>,
781}
782impl GLSLFunction {
783 pub fn new(name: impl Into<String>, return_type: GLSLType) -> Self {
785 GLSLFunction {
786 name: name.into(),
787 return_type,
788 params: Vec::new(),
789 body: Vec::new(),
790 }
791 }
792 pub fn add_param(&mut self, var: GLSLVariable) {
794 self.params.push(var);
795 }
796 pub fn add_statement(&mut self, stmt: impl Into<String>) {
798 self.body.push(stmt.into());
799 }
800 pub fn emit(&self) -> String {
802 let params: Vec<String> = self.params.iter().map(|p| p.emit_param()).collect();
803 let mut out = format!(
804 "{} {}({}) {{\n",
805 self.return_type,
806 self.name,
807 params.join(", ")
808 );
809 for stmt in &self.body {
810 out.push_str(&format!(" {};\n", stmt));
811 }
812 out.push('}');
813 out
814 }
815 pub fn emit_prototype(&self) -> String {
817 let params: Vec<String> = self.params.iter().map(|p| p.emit_param()).collect();
818 format!("{} {}({});", self.return_type, self.name, params.join(", "))
819 }
820}
821#[allow(dead_code)]
823#[derive(Debug, Clone, PartialEq)]
824pub enum GlslConstant {
825 Float(f64),
826 Int(i64),
827 Bool(bool),
828 Vec(Vec<f64>),
829}
830#[allow(dead_code)]
831impl GlslConstant {
832 pub fn to_glsl_literal(&self) -> String {
834 match self {
835 GlslConstant::Float(v) => {
836 if v.fract() == 0.0 {
837 format!("{:.1}", v)
838 } else {
839 format!("{}", v)
840 }
841 }
842 GlslConstant::Int(v) => format!("{}", v),
843 GlslConstant::Bool(b) => {
844 if *b {
845 "true".to_string()
846 } else {
847 "false".to_string()
848 }
849 }
850 GlslConstant::Vec(c) => {
851 let inner: Vec<String> = c
852 .iter()
853 .map(|v| {
854 if v.fract() == 0.0 {
855 format!("{:.1}", v)
856 } else {
857 format!("{}", v)
858 }
859 })
860 .collect();
861 format!("vec{}({})", c.len(), inner.join(", "))
862 }
863 }
864 }
865 pub fn is_zero(&self) -> bool {
867 match self {
868 GlslConstant::Float(v) => *v == 0.0,
869 GlslConstant::Int(v) => *v == 0,
870 GlslConstant::Bool(b) => !b,
871 GlslConstant::Vec(c) => c.iter().all(|x| *x == 0.0),
872 }
873 }
874 pub fn is_one(&self) -> bool {
876 match self {
877 GlslConstant::Float(v) => *v == 1.0,
878 GlslConstant::Int(v) => *v == 1,
879 _ => false,
880 }
881 }
882 pub fn add(&self, other: &GlslConstant) -> Option<GlslConstant> {
884 match (self, other) {
885 (GlslConstant::Float(a), GlslConstant::Float(b)) => Some(GlslConstant::Float(a + b)),
886 (GlslConstant::Int(a), GlslConstant::Int(b)) => Some(GlslConstant::Int(a + b)),
887 _ => None,
888 }
889 }
890}
891#[allow(dead_code)]
893#[derive(Debug, Clone, Default)]
894pub struct GlslOutputVariableSet {
895 pub(super) vars: Vec<(String, GLSLType, Option<u32>)>,
896}
897#[allow(dead_code)]
898impl GlslOutputVariableSet {
899 pub fn new() -> Self {
900 GlslOutputVariableSet { vars: Vec::new() }
901 }
902 pub fn add(&mut self, name: impl Into<String>, ty: GLSLType, location: Option<u32>) {
903 self.vars.push((name.into(), ty, location));
904 }
905 pub fn len(&self) -> usize {
906 self.vars.len()
907 }
908 pub fn is_empty(&self) -> bool {
909 self.vars.is_empty()
910 }
911 pub fn emit(&self, version: GLSLVersion) -> String {
912 let mut out = String::new();
913 for (name, ty, loc) in &self.vars {
914 if let Some(l) = loc {
915 if version.supports_layout_location() {
916 out.push_str(&format!("layout(location = {}) ", l));
917 }
918 }
919 out.push_str(&format!("out {} {};\n", ty.keyword(), name));
920 }
921 out
922 }
923}
924#[allow(dead_code)]
926#[derive(Debug, Clone, PartialEq, Eq, Hash)]
927pub enum GLSLExtPassPhase {
928 Early,
929 Middle,
930 Late,
931 Finalize,
932}
933impl GLSLExtPassPhase {
934 #[allow(dead_code)]
935 pub fn is_early(&self) -> bool {
936 matches!(self, Self::Early)
937 }
938 #[allow(dead_code)]
939 pub fn is_middle(&self) -> bool {
940 matches!(self, Self::Middle)
941 }
942 #[allow(dead_code)]
943 pub fn is_late(&self) -> bool {
944 matches!(self, Self::Late)
945 }
946 #[allow(dead_code)]
947 pub fn is_finalize(&self) -> bool {
948 matches!(self, Self::Finalize)
949 }
950 #[allow(dead_code)]
951 pub fn order(&self) -> u32 {
952 match self {
953 Self::Early => 0,
954 Self::Middle => 1,
955 Self::Late => 2,
956 Self::Finalize => 3,
957 }
958 }
959 #[allow(dead_code)]
960 pub fn from_order(n: u32) -> Option<Self> {
961 match n {
962 0 => Some(Self::Early),
963 1 => Some(Self::Middle),
964 2 => Some(Self::Late),
965 3 => Some(Self::Finalize),
966 _ => None,
967 }
968 }
969}
970#[allow(dead_code)]
971#[derive(Debug, Clone)]
972pub struct GLSLCacheEntry {
973 pub key: String,
974 pub data: Vec<u8>,
975 pub timestamp: u64,
976 pub valid: bool,
977}
978#[allow(dead_code)]
980#[derive(Debug, Clone, Default)]
981pub struct GLSLExtLiveness {
982 pub live_in: Vec<Vec<usize>>,
983 pub live_out: Vec<Vec<usize>>,
984 pub defs: Vec<Vec<usize>>,
985 pub uses: Vec<Vec<usize>>,
986}
987impl GLSLExtLiveness {
988 #[allow(dead_code)]
989 pub fn new(n: usize) -> Self {
990 Self {
991 live_in: vec![Vec::new(); n],
992 live_out: vec![Vec::new(); n],
993 defs: vec![Vec::new(); n],
994 uses: vec![Vec::new(); n],
995 }
996 }
997 #[allow(dead_code)]
998 pub fn live_in(&self, b: usize, v: usize) -> bool {
999 self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1000 }
1001 #[allow(dead_code)]
1002 pub fn live_out(&self, b: usize, v: usize) -> bool {
1003 self.live_out
1004 .get(b)
1005 .map(|s| s.contains(&v))
1006 .unwrap_or(false)
1007 }
1008 #[allow(dead_code)]
1009 pub fn add_def(&mut self, b: usize, v: usize) {
1010 if let Some(s) = self.defs.get_mut(b) {
1011 if !s.contains(&v) {
1012 s.push(v);
1013 }
1014 }
1015 }
1016 #[allow(dead_code)]
1017 pub fn add_use(&mut self, b: usize, v: usize) {
1018 if let Some(s) = self.uses.get_mut(b) {
1019 if !s.contains(&v) {
1020 s.push(v);
1021 }
1022 }
1023 }
1024 #[allow(dead_code)]
1025 pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
1026 self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1027 }
1028 #[allow(dead_code)]
1029 pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
1030 self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1031 }
1032}
1033#[allow(dead_code)]
1034#[derive(Debug, Clone, Default)]
1035pub struct GLSLPassStats {
1036 pub total_runs: u32,
1037 pub successful_runs: u32,
1038 pub total_changes: u64,
1039 pub time_ms: u64,
1040 pub iterations_used: u32,
1041}
1042impl GLSLPassStats {
1043 #[allow(dead_code)]
1044 pub fn new() -> Self {
1045 Self::default()
1046 }
1047 #[allow(dead_code)]
1048 pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
1049 self.total_runs += 1;
1050 self.successful_runs += 1;
1051 self.total_changes += changes;
1052 self.time_ms += time_ms;
1053 self.iterations_used = iterations;
1054 }
1055 #[allow(dead_code)]
1056 pub fn average_changes_per_run(&self) -> f64 {
1057 if self.total_runs == 0 {
1058 return 0.0;
1059 }
1060 self.total_changes as f64 / self.total_runs as f64
1061 }
1062 #[allow(dead_code)]
1063 pub fn success_rate(&self) -> f64 {
1064 if self.total_runs == 0 {
1065 return 0.0;
1066 }
1067 self.successful_runs as f64 / self.total_runs as f64
1068 }
1069 #[allow(dead_code)]
1070 pub fn format_summary(&self) -> String {
1071 format!(
1072 "Runs: {}/{}, Changes: {}, Time: {}ms",
1073 self.successful_runs, self.total_runs, self.total_changes, self.time_ms
1074 )
1075 }
1076}
1077#[allow(dead_code)]
1078#[derive(Debug, Clone)]
1079pub struct GLSLWorklist {
1080 pub(super) items: std::collections::VecDeque<u32>,
1081 pub(super) in_worklist: std::collections::HashSet<u32>,
1082}
1083impl GLSLWorklist {
1084 #[allow(dead_code)]
1085 pub fn new() -> Self {
1086 GLSLWorklist {
1087 items: std::collections::VecDeque::new(),
1088 in_worklist: std::collections::HashSet::new(),
1089 }
1090 }
1091 #[allow(dead_code)]
1092 pub fn push(&mut self, item: u32) -> bool {
1093 if self.in_worklist.insert(item) {
1094 self.items.push_back(item);
1095 true
1096 } else {
1097 false
1098 }
1099 }
1100 #[allow(dead_code)]
1101 pub fn pop(&mut self) -> Option<u32> {
1102 let item = self.items.pop_front()?;
1103 self.in_worklist.remove(&item);
1104 Some(item)
1105 }
1106 #[allow(dead_code)]
1107 pub fn is_empty(&self) -> bool {
1108 self.items.is_empty()
1109 }
1110 #[allow(dead_code)]
1111 pub fn len(&self) -> usize {
1112 self.items.len()
1113 }
1114 #[allow(dead_code)]
1115 pub fn contains(&self, item: u32) -> bool {
1116 self.in_worklist.contains(&item)
1117 }
1118}
1119#[allow(dead_code)]
1120#[derive(Debug, Clone)]
1121pub struct GLSLDepGraph {
1122 pub(super) nodes: Vec<u32>,
1123 pub(super) edges: Vec<(u32, u32)>,
1124}
1125impl GLSLDepGraph {
1126 #[allow(dead_code)]
1127 pub fn new() -> Self {
1128 GLSLDepGraph {
1129 nodes: Vec::new(),
1130 edges: Vec::new(),
1131 }
1132 }
1133 #[allow(dead_code)]
1134 pub fn add_node(&mut self, id: u32) {
1135 if !self.nodes.contains(&id) {
1136 self.nodes.push(id);
1137 }
1138 }
1139 #[allow(dead_code)]
1140 pub fn add_dep(&mut self, dep: u32, dependent: u32) {
1141 self.add_node(dep);
1142 self.add_node(dependent);
1143 self.edges.push((dep, dependent));
1144 }
1145 #[allow(dead_code)]
1146 pub fn dependents_of(&self, node: u32) -> Vec<u32> {
1147 self.edges
1148 .iter()
1149 .filter(|(d, _)| *d == node)
1150 .map(|(_, dep)| *dep)
1151 .collect()
1152 }
1153 #[allow(dead_code)]
1154 pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
1155 self.edges
1156 .iter()
1157 .filter(|(_, dep)| *dep == node)
1158 .map(|(d, _)| *d)
1159 .collect()
1160 }
1161 #[allow(dead_code)]
1162 pub fn topological_sort(&self) -> Vec<u32> {
1163 let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
1164 for &n in &self.nodes {
1165 in_degree.insert(n, 0);
1166 }
1167 for (_, dep) in &self.edges {
1168 *in_degree.entry(*dep).or_insert(0) += 1;
1169 }
1170 let mut queue: std::collections::VecDeque<u32> = self
1171 .nodes
1172 .iter()
1173 .filter(|&&n| in_degree[&n] == 0)
1174 .copied()
1175 .collect();
1176 let mut result = Vec::new();
1177 while let Some(node) = queue.pop_front() {
1178 result.push(node);
1179 for dep in self.dependents_of(node) {
1180 let cnt = in_degree.entry(dep).or_insert(0);
1181 *cnt = cnt.saturating_sub(1);
1182 if *cnt == 0 {
1183 queue.push_back(dep);
1184 }
1185 }
1186 }
1187 result
1188 }
1189 #[allow(dead_code)]
1190 pub fn has_cycle(&self) -> bool {
1191 self.topological_sort().len() < self.nodes.len()
1192 }
1193}
1194#[allow(dead_code)]
1196#[derive(Debug, Clone)]
1197pub struct GlslBuiltinFn {
1198 pub name: &'static str,
1199 pub category: GlslBuiltinCategory,
1200 pub min_version: u32,
1201}
1202impl GlslBuiltinFn {
1203 pub(super) const fn new(name: &'static str, cat: GlslBuiltinCategory, ver: u32) -> Self {
1204 GlslBuiltinFn {
1205 name,
1206 category: cat,
1207 min_version: ver,
1208 }
1209 }
1210}
1211#[derive(Debug, Clone)]
1213pub struct GLSLShader {
1214 pub version: GLSLVersion,
1216 pub stage: GLSLShaderStage,
1218 pub extensions: Vec<String>,
1220 pub defines: Vec<(String, Option<String>)>,
1222 pub structs: Vec<GLSLStruct>,
1224 pub inputs: Vec<GLSLVariable>,
1226 pub outputs: Vec<GLSLVariable>,
1228 pub uniforms: Vec<GLSLVariable>,
1230 pub globals: Vec<GLSLVariable>,
1232 pub functions: Vec<GLSLFunction>,
1234 pub main_body: Vec<String>,
1236}
1237impl GLSLShader {
1238 pub fn new(version: GLSLVersion, stage: GLSLShaderStage) -> Self {
1240 GLSLShader {
1241 version,
1242 stage,
1243 extensions: Vec::new(),
1244 defines: Vec::new(),
1245 structs: Vec::new(),
1246 inputs: Vec::new(),
1247 outputs: Vec::new(),
1248 uniforms: Vec::new(),
1249 globals: Vec::new(),
1250 functions: Vec::new(),
1251 main_body: Vec::new(),
1252 }
1253 }
1254 pub fn add_extension(&mut self, ext: impl Into<String>) {
1256 self.extensions.push(ext.into());
1257 }
1258 pub fn add_define(&mut self, name: impl Into<String>) {
1260 self.defines.push((name.into(), None));
1261 }
1262 pub fn add_define_value(&mut self, name: impl Into<String>, value: impl Into<String>) {
1264 self.defines.push((name.into(), Some(value.into())));
1265 }
1266 pub fn add_struct(&mut self, s: GLSLStruct) {
1268 self.structs.push(s);
1269 }
1270 pub fn add_input(&mut self, v: GLSLVariable) {
1272 self.inputs.push(v);
1273 }
1274 pub fn add_output(&mut self, v: GLSLVariable) {
1276 self.outputs.push(v);
1277 }
1278 pub fn add_uniform(&mut self, v: GLSLVariable) {
1280 self.uniforms.push(v);
1281 }
1282 pub fn add_global(&mut self, v: GLSLVariable) {
1284 self.globals.push(v);
1285 }
1286 pub fn add_function(&mut self, f: GLSLFunction) {
1288 self.functions.push(f);
1289 }
1290 pub fn add_main_statement(&mut self, stmt: impl Into<String>) {
1292 self.main_body.push(stmt.into());
1293 }
1294}
1295#[allow(dead_code)]
1297#[derive(Debug)]
1298pub struct GLSLExtCache {
1299 pub(super) entries: Vec<(u64, Vec<u8>, bool, u32)>,
1300 pub(super) cap: usize,
1301 pub(super) total_hits: u64,
1302 pub(super) total_misses: u64,
1303}
1304impl GLSLExtCache {
1305 #[allow(dead_code)]
1306 pub fn new(cap: usize) -> Self {
1307 Self {
1308 entries: Vec::new(),
1309 cap,
1310 total_hits: 0,
1311 total_misses: 0,
1312 }
1313 }
1314 #[allow(dead_code)]
1315 pub fn get(&mut self, key: u64) -> Option<&[u8]> {
1316 for e in self.entries.iter_mut() {
1317 if e.0 == key && e.2 {
1318 e.3 += 1;
1319 self.total_hits += 1;
1320 return Some(&e.1);
1321 }
1322 }
1323 self.total_misses += 1;
1324 None
1325 }
1326 #[allow(dead_code)]
1327 pub fn put(&mut self, key: u64, data: Vec<u8>) {
1328 if self.entries.len() >= self.cap {
1329 self.entries.retain(|e| e.2);
1330 if self.entries.len() >= self.cap {
1331 self.entries.remove(0);
1332 }
1333 }
1334 self.entries.push((key, data, true, 0));
1335 }
1336 #[allow(dead_code)]
1337 pub fn invalidate(&mut self) {
1338 for e in self.entries.iter_mut() {
1339 e.2 = false;
1340 }
1341 }
1342 #[allow(dead_code)]
1343 pub fn hit_rate(&self) -> f64 {
1344 let t = self.total_hits + self.total_misses;
1345 if t == 0 {
1346 0.0
1347 } else {
1348 self.total_hits as f64 / t as f64
1349 }
1350 }
1351 #[allow(dead_code)]
1352 pub fn live_count(&self) -> usize {
1353 self.entries.iter().filter(|e| e.2).count()
1354 }
1355}
1356#[allow(dead_code)]
1357#[derive(Debug, Clone)]
1358pub struct GLSLPassConfig {
1359 pub phase: GLSLPassPhase,
1360 pub enabled: bool,
1361 pub max_iterations: u32,
1362 pub debug_output: bool,
1363 pub pass_name: String,
1364}
1365impl GLSLPassConfig {
1366 #[allow(dead_code)]
1367 pub fn new(name: impl Into<String>, phase: GLSLPassPhase) -> Self {
1368 GLSLPassConfig {
1369 phase,
1370 enabled: true,
1371 max_iterations: 10,
1372 debug_output: false,
1373 pass_name: name.into(),
1374 }
1375 }
1376 #[allow(dead_code)]
1377 pub fn disabled(mut self) -> Self {
1378 self.enabled = false;
1379 self
1380 }
1381 #[allow(dead_code)]
1382 pub fn with_debug(mut self) -> Self {
1383 self.debug_output = true;
1384 self
1385 }
1386 #[allow(dead_code)]
1387 pub fn max_iter(mut self, n: u32) -> Self {
1388 self.max_iterations = n;
1389 self
1390 }
1391}
1392#[allow(dead_code)]
1393#[derive(Debug, Clone)]
1394pub struct GLSLLivenessInfo {
1395 pub live_in: Vec<std::collections::HashSet<u32>>,
1396 pub live_out: Vec<std::collections::HashSet<u32>>,
1397 pub defs: Vec<std::collections::HashSet<u32>>,
1398 pub uses: Vec<std::collections::HashSet<u32>>,
1399}
1400impl GLSLLivenessInfo {
1401 #[allow(dead_code)]
1402 pub fn new(block_count: usize) -> Self {
1403 GLSLLivenessInfo {
1404 live_in: vec![std::collections::HashSet::new(); block_count],
1405 live_out: vec![std::collections::HashSet::new(); block_count],
1406 defs: vec![std::collections::HashSet::new(); block_count],
1407 uses: vec![std::collections::HashSet::new(); block_count],
1408 }
1409 }
1410 #[allow(dead_code)]
1411 pub fn add_def(&mut self, block: usize, var: u32) {
1412 if block < self.defs.len() {
1413 self.defs[block].insert(var);
1414 }
1415 }
1416 #[allow(dead_code)]
1417 pub fn add_use(&mut self, block: usize, var: u32) {
1418 if block < self.uses.len() {
1419 self.uses[block].insert(var);
1420 }
1421 }
1422 #[allow(dead_code)]
1423 pub fn is_live_in(&self, block: usize, var: u32) -> bool {
1424 self.live_in
1425 .get(block)
1426 .map(|s| s.contains(&var))
1427 .unwrap_or(false)
1428 }
1429 #[allow(dead_code)]
1430 pub fn is_live_out(&self, block: usize, var: u32) -> bool {
1431 self.live_out
1432 .get(block)
1433 .map(|s| s.contains(&var))
1434 .unwrap_or(false)
1435 }
1436}
1437pub struct GLSLBackend {
1439 pub version: GLSLVersion,
1441}
1442impl GLSLBackend {
1443 pub fn new(version: GLSLVersion) -> Self {
1445 GLSLBackend { version }
1446 }
1447 pub fn emit_type(&self, ty: &GLSLType) -> String {
1449 ty.keyword()
1450 }
1451 pub fn emit_shader(&self, shader: &GLSLShader) -> String {
1453 let mut out = String::new();
1454 out.push_str(&shader.version.version_line());
1455 out.push('\n');
1456 for ext in &shader.extensions {
1457 out.push_str(&format!("#extension {} : enable\n", ext));
1458 }
1459 if !shader.extensions.is_empty() {
1460 out.push('\n');
1461 }
1462 for (name, val) in &shader.defines {
1463 match val {
1464 Some(v) => out.push_str(&format!("#define {} {}\n", name, v)),
1465 None => out.push_str(&format!("#define {}\n", name)),
1466 }
1467 }
1468 if !shader.defines.is_empty() {
1469 out.push('\n');
1470 }
1471 for s in &shader.structs {
1472 out.push_str(&s.emit());
1473 out.push_str("\n\n");
1474 }
1475 for v in &shader.inputs {
1476 out.push_str(&v.emit_global());
1477 out.push('\n');
1478 }
1479 if !shader.inputs.is_empty() {
1480 out.push('\n');
1481 }
1482 for v in &shader.outputs {
1483 out.push_str(&v.emit_global());
1484 out.push('\n');
1485 }
1486 if !shader.outputs.is_empty() {
1487 out.push('\n');
1488 }
1489 for v in &shader.uniforms {
1490 out.push_str(&v.emit_global());
1491 out.push('\n');
1492 }
1493 if !shader.uniforms.is_empty() {
1494 out.push('\n');
1495 }
1496 for v in &shader.globals {
1497 out.push_str(&v.emit_global());
1498 out.push('\n');
1499 }
1500 if !shader.globals.is_empty() {
1501 out.push('\n');
1502 }
1503 for f in &shader.functions {
1504 out.push_str(&f.emit());
1505 out.push_str("\n\n");
1506 }
1507 out.push_str("void main() {\n");
1508 for stmt in &shader.main_body {
1509 out.push_str(&format!(" {};\n", stmt));
1510 }
1511 out.push_str("}\n");
1512 out
1513 }
1514 pub fn vertex_shader_template(&self) -> String {
1516 let mut shader = GLSLShader::new(self.version, GLSLShaderStage::Vertex);
1517 if self.version.supports_layout_location() {
1518 shader.add_input(GLSLVariable::layout_input("aPosition", GLSLType::Vec3, 0));
1519 shader.add_input(GLSLVariable::layout_input("aTexCoord", GLSLType::Vec2, 1));
1520 shader.add_output(GLSLVariable::layout_output("vTexCoord", GLSLType::Vec2, 0));
1521 } else {
1522 shader.add_input(GLSLVariable::input("aPosition", GLSLType::Vec3));
1523 shader.add_input(GLSLVariable::input("aTexCoord", GLSLType::Vec2));
1524 shader.add_output(GLSLVariable::output("vTexCoord", GLSLType::Vec2));
1525 }
1526 shader.add_uniform(GLSLVariable::uniform("uMVP", GLSLType::Mat4));
1527 shader.add_main_statement("gl_Position = uMVP * vec4(aPosition, 1.0)");
1528 shader.add_main_statement("vTexCoord = aTexCoord");
1529 self.emit_shader(&shader)
1530 }
1531 pub fn fragment_shader_template(&self) -> String {
1533 let mut shader = GLSLShader::new(self.version, GLSLShaderStage::Fragment);
1534 if self.version.supports_layout_location() {
1535 shader.add_input(GLSLVariable::layout_input("vTexCoord", GLSLType::Vec2, 0));
1536 shader.add_output(GLSLVariable::layout_output("fragColor", GLSLType::Vec4, 0));
1537 } else {
1538 shader.add_input(GLSLVariable::input("vTexCoord", GLSLType::Vec2));
1539 shader.add_output(GLSLVariable::output("fragColor", GLSLType::Vec4));
1540 }
1541 shader.add_uniform(GLSLVariable::uniform("uTexture", GLSLType::Sampler2D));
1542 shader.add_main_statement("fragColor = texture(uTexture, vTexCoord)");
1543 self.emit_shader(&shader)
1544 }
1545 pub fn phong_vertex_template(&self) -> String {
1547 let mut shader = GLSLShader::new(self.version, GLSLShaderStage::Vertex);
1548 shader.add_input(GLSLVariable::layout_input("aPosition", GLSLType::Vec3, 0));
1549 shader.add_input(GLSLVariable::layout_input("aNormal", GLSLType::Vec3, 1));
1550 shader.add_output(GLSLVariable::layout_output("vNormal", GLSLType::Vec3, 0));
1551 shader.add_output(GLSLVariable::layout_output("vFragPos", GLSLType::Vec3, 1));
1552 shader.add_uniform(GLSLVariable::uniform("uModel", GLSLType::Mat4));
1553 shader.add_uniform(GLSLVariable::uniform("uView", GLSLType::Mat4));
1554 shader.add_uniform(GLSLVariable::uniform("uProjection", GLSLType::Mat4));
1555 shader.add_main_statement("vFragPos = vec3(uModel * vec4(aPosition, 1.0))");
1556 shader.add_main_statement("vNormal = mat3(transpose(inverse(uModel))) * aNormal");
1557 shader.add_main_statement("gl_Position = uProjection * uView * vec4(vFragPos, 1.0)");
1558 self.emit_shader(&shader)
1559 }
1560 pub fn phong_fragment_template(&self) -> String {
1562 let mut shader = GLSLShader::new(self.version, GLSLShaderStage::Fragment);
1563 shader.add_input(GLSLVariable::layout_input("vNormal", GLSLType::Vec3, 0));
1564 shader.add_input(GLSLVariable::layout_input("vFragPos", GLSLType::Vec3, 1));
1565 shader.add_output(GLSLVariable::layout_output("fragColor", GLSLType::Vec4, 0));
1566 shader.add_uniform(GLSLVariable::uniform("uLightPos", GLSLType::Vec3));
1567 shader.add_uniform(GLSLVariable::uniform("uViewPos", GLSLType::Vec3));
1568 shader.add_uniform(GLSLVariable::uniform("uLightColor", GLSLType::Vec3));
1569 shader.add_uniform(GLSLVariable::uniform("uObjectColor", GLSLType::Vec3));
1570 shader.add_main_statement("float ambientStrength = 0.1");
1571 shader.add_main_statement("vec3 ambient = ambientStrength * uLightColor");
1572 shader.add_main_statement("vec3 norm = normalize(vNormal)");
1573 shader.add_main_statement("vec3 lightDir = normalize(uLightPos - vFragPos)");
1574 shader.add_main_statement("float diff = max(dot(norm, lightDir), 0.0)");
1575 shader.add_main_statement("vec3 diffuse = diff * uLightColor");
1576 shader.add_main_statement("float specularStrength = 0.5");
1577 shader.add_main_statement("vec3 viewDir = normalize(uViewPos - vFragPos)");
1578 shader.add_main_statement("vec3 reflectDir = reflect(-lightDir, norm)");
1579 shader.add_main_statement("float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0)");
1580 shader.add_main_statement("vec3 specular = specularStrength * spec * uLightColor");
1581 shader.add_main_statement("vec3 result = (ambient + diffuse + specular) * uObjectColor");
1582 shader.add_main_statement("fragColor = vec4(result, 1.0)");
1583 self.emit_shader(&shader)
1584 }
1585 pub fn compute_shader_template(&self, local_x: u32, local_y: u32, local_z: u32) -> String {
1587 let mut shader = GLSLShader::new(self.version, GLSLShaderStage::Compute);
1588 shader.add_extension("GL_ARB_compute_shader");
1589 shader.add_main_statement("uint idx = gl_GlobalInvocationID.x");
1590 shader.add_main_statement("// TODO: compute work here");
1591 let mut out = self.emit_shader(&shader);
1592 let layout_line = format!(
1593 "layout(local_size_x = {}, local_size_y = {}, local_size_z = {}) in;\n",
1594 local_x, local_y, local_z
1595 );
1596 if let Some(pos) = out.find('\n') {
1597 out.insert_str(pos + 1, &layout_line);
1598 }
1599 out
1600 }
1601}
1602#[allow(dead_code)]
1604#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1605pub struct GlslComputeWorkgroup {
1606 pub local_size_x: u32,
1607 pub local_size_y: u32,
1608 pub local_size_z: u32,
1609}
1610#[allow(dead_code)]
1611impl GlslComputeWorkgroup {
1612 pub fn linear(x: u32) -> Self {
1613 GlslComputeWorkgroup {
1614 local_size_x: x,
1615 local_size_y: 1,
1616 local_size_z: 1,
1617 }
1618 }
1619 pub fn planar(x: u32, y: u32) -> Self {
1620 GlslComputeWorkgroup {
1621 local_size_x: x,
1622 local_size_y: y,
1623 local_size_z: 1,
1624 }
1625 }
1626 pub fn volumetric(x: u32, y: u32, z: u32) -> Self {
1627 GlslComputeWorkgroup {
1628 local_size_x: x,
1629 local_size_y: y,
1630 local_size_z: z,
1631 }
1632 }
1633 pub fn total_threads(&self) -> u32 {
1634 self.local_size_x * self.local_size_y * self.local_size_z
1635 }
1636 pub fn emit_layout(&self) -> String {
1637 format!(
1638 "layout(local_size_x = {}, local_size_y = {}, local_size_z = {}) in;\n",
1639 self.local_size_x, self.local_size_y, self.local_size_z
1640 )
1641 }
1642}
1643#[allow(dead_code)]
1645#[derive(Debug, Clone)]
1646pub struct GLSLExtDomTree {
1647 pub(super) idom: Vec<Option<usize>>,
1648 pub(super) children: Vec<Vec<usize>>,
1649 pub(super) depth: Vec<usize>,
1650}
1651impl GLSLExtDomTree {
1652 #[allow(dead_code)]
1653 pub fn new(n: usize) -> Self {
1654 Self {
1655 idom: vec![None; n],
1656 children: vec![Vec::new(); n],
1657 depth: vec![0; n],
1658 }
1659 }
1660 #[allow(dead_code)]
1661 pub fn set_idom(&mut self, node: usize, dom: usize) {
1662 if node < self.idom.len() {
1663 self.idom[node] = Some(dom);
1664 if dom < self.children.len() {
1665 self.children[dom].push(node);
1666 }
1667 self.depth[node] = if dom < self.depth.len() {
1668 self.depth[dom] + 1
1669 } else {
1670 1
1671 };
1672 }
1673 }
1674 #[allow(dead_code)]
1675 pub fn dominates(&self, a: usize, mut b: usize) -> bool {
1676 if a == b {
1677 return true;
1678 }
1679 let n = self.idom.len();
1680 for _ in 0..n {
1681 match self.idom.get(b).copied().flatten() {
1682 None => return false,
1683 Some(p) if p == a => return true,
1684 Some(p) if p == b => return false,
1685 Some(p) => b = p,
1686 }
1687 }
1688 false
1689 }
1690 #[allow(dead_code)]
1691 pub fn children_of(&self, n: usize) -> &[usize] {
1692 self.children.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1693 }
1694 #[allow(dead_code)]
1695 pub fn depth_of(&self, n: usize) -> usize {
1696 self.depth.get(n).copied().unwrap_or(0)
1697 }
1698 #[allow(dead_code)]
1699 pub fn lca(&self, mut a: usize, mut b: usize) -> usize {
1700 let n = self.idom.len();
1701 for _ in 0..(2 * n) {
1702 if a == b {
1703 return a;
1704 }
1705 if self.depth_of(a) > self.depth_of(b) {
1706 a = self.idom.get(a).and_then(|x| *x).unwrap_or(a);
1707 } else {
1708 b = self.idom.get(b).and_then(|x| *x).unwrap_or(b);
1709 }
1710 }
1711 0
1712 }
1713}
1714#[allow(dead_code)]
1716#[derive(Debug, Clone)]
1717pub struct GlslIncludeGuard {
1718 pub macro_name: String,
1719}
1720#[allow(dead_code)]
1721impl GlslIncludeGuard {
1722 pub fn from_filename(filename: &str) -> Self {
1723 let macro_name = filename
1724 .replace('.', "_")
1725 .replace('/', "_")
1726 .replace('-', "_")
1727 .to_uppercase();
1728 GlslIncludeGuard {
1729 macro_name: format!("{}_GUARD", macro_name),
1730 }
1731 }
1732 pub fn open(&self) -> String {
1733 format!("#ifndef {0}\n#define {0}\n", self.macro_name)
1734 }
1735 pub fn close(&self) -> String {
1736 format!("#endif // {}\n", self.macro_name)
1737 }
1738}
1739#[allow(dead_code)]
1741#[derive(Debug, Clone)]
1742pub struct GLSLExtDepGraph {
1743 pub(super) n: usize,
1744 pub(super) adj: Vec<Vec<usize>>,
1745 pub(super) rev: Vec<Vec<usize>>,
1746 pub(super) edge_count: usize,
1747}
1748impl GLSLExtDepGraph {
1749 #[allow(dead_code)]
1750 pub fn new(n: usize) -> Self {
1751 Self {
1752 n,
1753 adj: vec![Vec::new(); n],
1754 rev: vec![Vec::new(); n],
1755 edge_count: 0,
1756 }
1757 }
1758 #[allow(dead_code)]
1759 pub fn add_edge(&mut self, from: usize, to: usize) {
1760 if from < self.n && to < self.n {
1761 if !self.adj[from].contains(&to) {
1762 self.adj[from].push(to);
1763 self.rev[to].push(from);
1764 self.edge_count += 1;
1765 }
1766 }
1767 }
1768 #[allow(dead_code)]
1769 pub fn succs(&self, n: usize) -> &[usize] {
1770 self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1771 }
1772 #[allow(dead_code)]
1773 pub fn preds(&self, n: usize) -> &[usize] {
1774 self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1775 }
1776 #[allow(dead_code)]
1777 pub fn topo_sort(&self) -> Option<Vec<usize>> {
1778 let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
1779 let mut q: std::collections::VecDeque<usize> =
1780 (0..self.n).filter(|&i| deg[i] == 0).collect();
1781 let mut out = Vec::with_capacity(self.n);
1782 while let Some(u) = q.pop_front() {
1783 out.push(u);
1784 for &v in &self.adj[u] {
1785 deg[v] -= 1;
1786 if deg[v] == 0 {
1787 q.push_back(v);
1788 }
1789 }
1790 }
1791 if out.len() == self.n {
1792 Some(out)
1793 } else {
1794 None
1795 }
1796 }
1797 #[allow(dead_code)]
1798 pub fn has_cycle(&self) -> bool {
1799 self.topo_sort().is_none()
1800 }
1801 #[allow(dead_code)]
1802 pub fn reachable(&self, start: usize) -> Vec<usize> {
1803 let mut vis = vec![false; self.n];
1804 let mut stk = vec![start];
1805 let mut out = Vec::new();
1806 while let Some(u) = stk.pop() {
1807 if u < self.n && !vis[u] {
1808 vis[u] = true;
1809 out.push(u);
1810 for &v in &self.adj[u] {
1811 if !vis[v] {
1812 stk.push(v);
1813 }
1814 }
1815 }
1816 }
1817 out
1818 }
1819 #[allow(dead_code)]
1820 pub fn scc(&self) -> Vec<Vec<usize>> {
1821 let mut visited = vec![false; self.n];
1822 let mut order = Vec::new();
1823 for i in 0..self.n {
1824 if !visited[i] {
1825 let mut stk = vec![(i, 0usize)];
1826 while let Some((u, idx)) = stk.last_mut() {
1827 if !visited[*u] {
1828 visited[*u] = true;
1829 }
1830 if *idx < self.adj[*u].len() {
1831 let v = self.adj[*u][*idx];
1832 *idx += 1;
1833 if !visited[v] {
1834 stk.push((v, 0));
1835 }
1836 } else {
1837 order.push(*u);
1838 stk.pop();
1839 }
1840 }
1841 }
1842 }
1843 let mut comp = vec![usize::MAX; self.n];
1844 let mut components: Vec<Vec<usize>> = Vec::new();
1845 for &start in order.iter().rev() {
1846 if comp[start] == usize::MAX {
1847 let cid = components.len();
1848 let mut component = Vec::new();
1849 let mut stk = vec![start];
1850 while let Some(u) = stk.pop() {
1851 if comp[u] == usize::MAX {
1852 comp[u] = cid;
1853 component.push(u);
1854 for &v in &self.rev[u] {
1855 if comp[v] == usize::MAX {
1856 stk.push(v);
1857 }
1858 }
1859 }
1860 }
1861 components.push(component);
1862 }
1863 }
1864 components
1865 }
1866 #[allow(dead_code)]
1867 pub fn node_count(&self) -> usize {
1868 self.n
1869 }
1870 #[allow(dead_code)]
1871 pub fn edge_count(&self) -> usize {
1872 self.edge_count
1873 }
1874}
1875#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1877pub enum GLSLShaderStage {
1878 Vertex,
1880 Fragment,
1882 Geometry,
1884 TessControl,
1886 TessEval,
1888 Compute,
1890}
1891#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1893pub enum GLSLQualifier {
1894 None,
1896 In,
1898 Out,
1900 InOut,
1902 Uniform,
1904 Const,
1906 Flat,
1908 CentroidIn,
1910 CentroidOut,
1912 LayoutIn(String),
1914 LayoutOut(String),
1916 LayoutUniform(String),
1918}
1919impl GLSLQualifier {
1920 pub fn prefix(&self) -> String {
1922 match self {
1923 GLSLQualifier::None => String::new(),
1924 GLSLQualifier::In => "in ".into(),
1925 GLSLQualifier::Out => "out ".into(),
1926 GLSLQualifier::InOut => "inout ".into(),
1927 GLSLQualifier::Uniform => "uniform ".into(),
1928 GLSLQualifier::Const => "const ".into(),
1929 GLSLQualifier::Flat => "flat in ".into(),
1930 GLSLQualifier::CentroidIn => "centroid in ".into(),
1931 GLSLQualifier::CentroidOut => "centroid out ".into(),
1932 GLSLQualifier::LayoutIn(l) => format!("layout({}) in ", l),
1933 GLSLQualifier::LayoutOut(l) => format!("layout({}) out ", l),
1934 GLSLQualifier::LayoutUniform(l) => format!("layout({}) uniform ", l),
1935 }
1936 }
1937}
1938#[allow(dead_code)]
1940#[derive(Debug, Clone)]
1941pub struct GlslUniformBlock {
1942 pub block_name: String,
1943 pub instance_name: Option<String>,
1944 pub layout: GlslBlockLayout,
1945 pub binding: Option<u32>,
1946 pub members: Vec<GlslBlockMember>,
1947 pub is_ssbo: bool,
1948}
1949#[allow(dead_code)]
1950impl GlslUniformBlock {
1951 pub fn ubo(block_name: impl Into<String>) -> Self {
1952 GlslUniformBlock {
1953 block_name: block_name.into(),
1954 instance_name: None,
1955 layout: GlslBlockLayout::Std140,
1956 binding: None,
1957 members: Vec::new(),
1958 is_ssbo: false,
1959 }
1960 }
1961 pub fn with_binding(mut self, b: u32) -> Self {
1962 self.binding = Some(b);
1963 self
1964 }
1965 pub fn add_member(&mut self, m: GlslBlockMember) {
1966 self.members.push(m);
1967 }
1968 pub fn num_members(&self) -> usize {
1969 self.members.len()
1970 }
1971 pub fn emit(&self) -> String {
1972 let layout_str = self.layout.qualifier_str();
1973 let mut out = if let Some(b) = self.binding {
1974 format!("layout({}, binding = {}) ", layout_str, b)
1975 } else {
1976 format!("layout({}) ", layout_str)
1977 };
1978 let kw = if self.is_ssbo { "buffer" } else { "uniform" };
1979 out.push_str(&format!("{} {} {{\n", kw, self.block_name));
1980 for m in &self.members {
1981 let ty_str = m.ty.keyword();
1982 if let Some(sz) = m.array_size {
1983 out.push_str(&format!(" {} {}[{}];\n", ty_str, m.name, sz));
1984 } else {
1985 out.push_str(&format!(" {} {};\n", ty_str, m.name));
1986 }
1987 }
1988 if let Some(ref inst) = self.instance_name {
1989 out.push_str(&format!("}} {};\n", inst));
1990 } else {
1991 out.push_str("};\n");
1992 }
1993 out
1994 }
1995}
1996#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1998pub enum GLSLVersion {
1999 V120,
2001 V330,
2003 V450,
2005 V460,
2007}
2008impl GLSLVersion {
2009 pub fn number(self) -> u32 {
2011 match self {
2012 GLSLVersion::V120 => 120,
2013 GLSLVersion::V330 => 330,
2014 GLSLVersion::V450 => 450,
2015 GLSLVersion::V460 => 460,
2016 }
2017 }
2018 pub fn profile(self) -> &'static str {
2023 match self {
2024 GLSLVersion::V120 => "",
2025 _ => " core",
2026 }
2027 }
2028 pub fn version_line(self) -> String {
2030 format!("#version {}{}", self.number(), self.profile())
2031 }
2032 pub fn supports_layout_location(self) -> bool {
2034 self.number() >= 330
2035 }
2036 pub fn supports_compute(self) -> bool {
2038 self.number() >= 430
2039 }
2040 pub fn supports_uint(self) -> bool {
2042 self.number() >= 130
2043 }
2044}
2045#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2047pub enum GLSLPrecision {
2048 Low,
2049 Medium,
2050 High,
2051}
2052#[allow(dead_code)]
2054#[derive(Debug, Default)]
2055pub struct GLSLExtPassRegistry {
2056 pub(super) configs: Vec<GLSLExtPassConfig>,
2057 pub(super) stats: Vec<GLSLExtPassStats>,
2058}
2059impl GLSLExtPassRegistry {
2060 #[allow(dead_code)]
2061 pub fn new() -> Self {
2062 Self::default()
2063 }
2064 #[allow(dead_code)]
2065 pub fn register(&mut self, c: GLSLExtPassConfig) {
2066 self.stats.push(GLSLExtPassStats::new());
2067 self.configs.push(c);
2068 }
2069 #[allow(dead_code)]
2070 pub fn len(&self) -> usize {
2071 self.configs.len()
2072 }
2073 #[allow(dead_code)]
2074 pub fn is_empty(&self) -> bool {
2075 self.configs.is_empty()
2076 }
2077 #[allow(dead_code)]
2078 pub fn get(&self, i: usize) -> Option<&GLSLExtPassConfig> {
2079 self.configs.get(i)
2080 }
2081 #[allow(dead_code)]
2082 pub fn get_stats(&self, i: usize) -> Option<&GLSLExtPassStats> {
2083 self.stats.get(i)
2084 }
2085 #[allow(dead_code)]
2086 pub fn enabled_passes(&self) -> Vec<&GLSLExtPassConfig> {
2087 self.configs.iter().filter(|c| c.enabled).collect()
2088 }
2089 #[allow(dead_code)]
2090 pub fn passes_in_phase(&self, ph: &GLSLExtPassPhase) -> Vec<&GLSLExtPassConfig> {
2091 self.configs
2092 .iter()
2093 .filter(|c| c.enabled && &c.phase == ph)
2094 .collect()
2095 }
2096 #[allow(dead_code)]
2097 pub fn total_nodes_visited(&self) -> usize {
2098 self.stats.iter().map(|s| s.nodes_visited).sum()
2099 }
2100 #[allow(dead_code)]
2101 pub fn any_changed(&self) -> bool {
2102 self.stats.iter().any(|s| s.changed)
2103 }
2104}
2105#[allow(dead_code)]
2107#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2108pub enum GlslBuiltinCategory {
2109 Trigonometric,
2110 Exponential,
2111 Common,
2112 GeometricVector,
2113 MatrixOp,
2114 TextureSampling,
2115 Atomic,
2116}
2117#[derive(Debug, Clone)]
2119pub enum GLSLExpr {
2120 Literal(String),
2122 Var(String),
2124 BinOp {
2126 op: String,
2127 lhs: Box<GLSLExpr>,
2128 rhs: Box<GLSLExpr>,
2129 },
2130 UnaryOp { op: String, operand: Box<GLSLExpr> },
2132 Call { func: String, args: Vec<GLSLExpr> },
2134 Field { base: Box<GLSLExpr>, field: String },
2136 Index {
2138 base: Box<GLSLExpr>,
2139 index: Box<GLSLExpr>,
2140 },
2141 Ternary {
2143 cond: Box<GLSLExpr>,
2144 then_expr: Box<GLSLExpr>,
2145 else_expr: Box<GLSLExpr>,
2146 },
2147}
2148impl GLSLExpr {
2149 pub fn emit(&self) -> String {
2151 match self {
2152 GLSLExpr::Literal(s) => s.clone(),
2153 GLSLExpr::Var(name) => name.clone(),
2154 GLSLExpr::BinOp { op, lhs, rhs } => {
2155 format!("({} {} {})", lhs.emit(), op, rhs.emit())
2156 }
2157 GLSLExpr::UnaryOp { op, operand } => format!("({}{})", op, operand.emit()),
2158 GLSLExpr::Call { func, args } => {
2159 let arg_strs: Vec<String> = args.iter().map(|a| a.emit()).collect();
2160 format!("{}({})", func, arg_strs.join(", "))
2161 }
2162 GLSLExpr::Field { base, field } => format!("{}.{}", base.emit(), field),
2163 GLSLExpr::Index { base, index } => {
2164 format!("{}[{}]", base.emit(), index.emit())
2165 }
2166 GLSLExpr::Ternary {
2167 cond,
2168 then_expr,
2169 else_expr,
2170 } => {
2171 format!(
2172 "({} ? {} : {})",
2173 cond.emit(),
2174 then_expr.emit(),
2175 else_expr.emit()
2176 )
2177 }
2178 }
2179 }
2180 pub fn binop(op: impl Into<String>, lhs: GLSLExpr, rhs: GLSLExpr) -> Self {
2182 GLSLExpr::BinOp {
2183 op: op.into(),
2184 lhs: Box::new(lhs),
2185 rhs: Box::new(rhs),
2186 }
2187 }
2188 pub fn call(func: impl Into<String>, args: Vec<GLSLExpr>) -> Self {
2190 GLSLExpr::Call {
2191 func: func.into(),
2192 args,
2193 }
2194 }
2195 pub fn var(name: impl Into<String>) -> Self {
2197 GLSLExpr::Var(name.into())
2198 }
2199 pub fn float(v: f32) -> Self {
2201 GLSLExpr::Literal(format!("{:.6}", v))
2202 }
2203}
2204#[allow(dead_code)]
2205#[derive(Debug, Clone)]
2206pub struct GLSLAnalysisCache {
2207 pub(super) entries: std::collections::HashMap<String, GLSLCacheEntry>,
2208 pub(super) max_size: usize,
2209 pub(super) hits: u64,
2210 pub(super) misses: u64,
2211}
2212impl GLSLAnalysisCache {
2213 #[allow(dead_code)]
2214 pub fn new(max_size: usize) -> Self {
2215 GLSLAnalysisCache {
2216 entries: std::collections::HashMap::new(),
2217 max_size,
2218 hits: 0,
2219 misses: 0,
2220 }
2221 }
2222 #[allow(dead_code)]
2223 pub fn get(&mut self, key: &str) -> Option<&GLSLCacheEntry> {
2224 if self.entries.contains_key(key) {
2225 self.hits += 1;
2226 self.entries.get(key)
2227 } else {
2228 self.misses += 1;
2229 None
2230 }
2231 }
2232 #[allow(dead_code)]
2233 pub fn insert(&mut self, key: String, data: Vec<u8>) {
2234 if self.entries.len() >= self.max_size {
2235 if let Some(oldest) = self.entries.keys().next().cloned() {
2236 self.entries.remove(&oldest);
2237 }
2238 }
2239 self.entries.insert(
2240 key.clone(),
2241 GLSLCacheEntry {
2242 key,
2243 data,
2244 timestamp: 0,
2245 valid: true,
2246 },
2247 );
2248 }
2249 #[allow(dead_code)]
2250 pub fn invalidate(&mut self, key: &str) {
2251 if let Some(entry) = self.entries.get_mut(key) {
2252 entry.valid = false;
2253 }
2254 }
2255 #[allow(dead_code)]
2256 pub fn clear(&mut self) {
2257 self.entries.clear();
2258 }
2259 #[allow(dead_code)]
2260 pub fn hit_rate(&self) -> f64 {
2261 let total = self.hits + self.misses;
2262 if total == 0 {
2263 return 0.0;
2264 }
2265 self.hits as f64 / total as f64
2266 }
2267 #[allow(dead_code)]
2268 pub fn size(&self) -> usize {
2269 self.entries.len()
2270 }
2271}
2272#[derive(Debug, Clone)]
2274pub struct GLSLVariable {
2275 pub name: String,
2277 pub ty: GLSLType,
2279 pub qualifier: GLSLQualifier,
2281 pub initializer: Option<String>,
2283}
2284impl GLSLVariable {
2285 pub fn new(name: impl Into<String>, ty: GLSLType, qualifier: GLSLQualifier) -> Self {
2287 GLSLVariable {
2288 name: name.into(),
2289 ty,
2290 qualifier,
2291 initializer: None,
2292 }
2293 }
2294 pub fn uniform(name: impl Into<String>, ty: GLSLType) -> Self {
2296 Self::new(name, ty, GLSLQualifier::Uniform)
2297 }
2298 pub fn input(name: impl Into<String>, ty: GLSLType) -> Self {
2300 Self::new(name, ty, GLSLQualifier::In)
2301 }
2302 pub fn output(name: impl Into<String>, ty: GLSLType) -> Self {
2304 Self::new(name, ty, GLSLQualifier::Out)
2305 }
2306 pub fn layout_input(name: impl Into<String>, ty: GLSLType, location: u32) -> Self {
2308 Self::new(
2309 name,
2310 ty,
2311 GLSLQualifier::LayoutIn(format!("location = {}", location)),
2312 )
2313 }
2314 pub fn layout_output(name: impl Into<String>, ty: GLSLType, location: u32) -> Self {
2316 Self::new(
2317 name,
2318 ty,
2319 GLSLQualifier::LayoutOut(format!("location = {}", location)),
2320 )
2321 }
2322 pub fn emit_global(&self) -> String {
2324 match &self.initializer {
2325 Some(init) => {
2326 format!(
2327 "{}{} {} = {};",
2328 self.qualifier.prefix(),
2329 self.ty,
2330 self.name,
2331 init
2332 )
2333 }
2334 None => format!("{}{} {};", self.qualifier.prefix(), self.ty, self.name),
2335 }
2336 }
2337 pub fn emit_param(&self) -> String {
2339 format!("{}{} {}", self.qualifier.prefix(), self.ty, self.name)
2340 }
2341}
2342#[allow(dead_code)]
2344pub struct GlslSwizzleValidator;
2345impl GlslSwizzleValidator {
2346 pub fn validate(mask: &str, components: usize) -> Result<usize, String> {
2348 if mask.is_empty() || mask.len() > 4 {
2349 return Err(format!(
2350 "swizzle mask length {} is not in [1,4]",
2351 mask.len()
2352 ));
2353 }
2354 let xyzw = ['x', 'y', 'z', 'w'];
2355 let rgba = ['r', 'g', 'b', 'a'];
2356 let stpq = ['s', 't', 'p', 'q'];
2357 let first = mask
2358 .chars()
2359 .next()
2360 .expect("mask is non-empty; checked at function entry");
2361 let set: &[char] = if xyzw.contains(&first) {
2362 &xyzw[..components]
2363 } else if rgba.contains(&first) {
2364 &rgba[..components]
2365 } else if stpq.contains(&first) {
2366 &stpq[..components]
2367 } else {
2368 return Err(format!("unknown swizzle character '{}'", first));
2369 };
2370 for ch in mask.chars() {
2371 if !set.contains(&ch) {
2372 return Err(format!(
2373 "swizzle char '{}' out of range for {}-component vector",
2374 ch, components
2375 ));
2376 }
2377 }
2378 Ok(mask.len())
2379 }
2380}
2381#[allow(dead_code)]
2383#[derive(Debug, Clone)]
2384pub struct GLSLExtPassConfig {
2385 pub name: String,
2386 pub phase: GLSLExtPassPhase,
2387 pub enabled: bool,
2388 pub max_iterations: usize,
2389 pub debug: u32,
2390 pub timeout_ms: Option<u64>,
2391}
2392impl GLSLExtPassConfig {
2393 #[allow(dead_code)]
2394 pub fn new(name: impl Into<String>) -> Self {
2395 Self {
2396 name: name.into(),
2397 phase: GLSLExtPassPhase::Middle,
2398 enabled: true,
2399 max_iterations: 100,
2400 debug: 0,
2401 timeout_ms: None,
2402 }
2403 }
2404 #[allow(dead_code)]
2405 pub fn with_phase(mut self, phase: GLSLExtPassPhase) -> Self {
2406 self.phase = phase;
2407 self
2408 }
2409 #[allow(dead_code)]
2410 pub fn with_max_iter(mut self, n: usize) -> Self {
2411 self.max_iterations = n;
2412 self
2413 }
2414 #[allow(dead_code)]
2415 pub fn with_debug(mut self, d: u32) -> Self {
2416 self.debug = d;
2417 self
2418 }
2419 #[allow(dead_code)]
2420 pub fn disabled(mut self) -> Self {
2421 self.enabled = false;
2422 self
2423 }
2424 #[allow(dead_code)]
2425 pub fn with_timeout(mut self, ms: u64) -> Self {
2426 self.timeout_ms = Some(ms);
2427 self
2428 }
2429 #[allow(dead_code)]
2430 pub fn is_debug_enabled(&self) -> bool {
2431 self.debug > 0
2432 }
2433}