diff --git a/examples/convert.rs b/examples/convert.rs index f3919ee892..01522b1f37 100644 --- a/examples/convert.rs +++ b/examples/convert.rs @@ -249,15 +249,13 @@ fn main() { let name = args.get(4).map_or("main", |p| p.as_str()).to_string(); let options = glsl::Options { version, - entry_point: ( - match stage { - "vert" => naga::ShaderStage::Vertex, - "frag" => naga::ShaderStage::Fragment, - "comp" => naga::ShaderStage::Compute, - _ => unreachable!(), - }, - name, - ), + shader_stage: match stage { + "vert" => naga::ShaderStage::Vertex, + "frag" => naga::ShaderStage::Fragment, + "comp" => naga::ShaderStage::Compute, + _ => unreachable!(), + }, + entry_point: name, }; let file = fs::OpenOptions::new() diff --git a/src/back/glsl/features.rs b/src/back/glsl/features.rs index 4f75cbd097..283c2ac7d5 100644 --- a/src/back/glsl/features.rs +++ b/src/back/glsl/features.rs @@ -175,8 +175,6 @@ impl<'a, W> Writer<'a, W> { /// If the version doesn't support any of the needed [`Features`](Features) a /// [`Error::MissingFeatures`](super::Error::MissingFeatures) will be returned pub(super) fn collect_required_features(&mut self) -> BackendResult { - let stage = self.options.entry_point.0; - if let Some(depth_test) = self.entry_point.early_depth_test { self.features.request(Features::IMAGE_LOAD_STORE); @@ -185,7 +183,7 @@ impl<'a, W> Writer<'a, W> { } } - if let ShaderStage::Compute = stage { + if let ShaderStage::Compute = self.options.shader_stage { self.features.request(Features::COMPUTE_SHADER) } diff --git a/src/back/glsl/mod.rs b/src/back/glsl/mod.rs index 58a46287f8..50d238eb87 100644 --- a/src/back/glsl/mod.rs +++ b/src/back/glsl/mod.rs @@ -44,10 +44,7 @@ pub use features::Features; use crate::{ - proc::{ - analyzer::Analysis, CallGraph, CallGraphBuilder, NameKey, Namer, ResolveContext, - ResolveError, Typifier, - }, + proc::{analyzer::Analysis, NameKey, Namer, ResolveContext, ResolveError, Typifier}, Arena, ArraySize, BinaryOperator, Binding, BuiltIn, Bytes, ConservativeDepth, Constant, ConstantInner, DerivativeAxis, Expression, FastHashMap, Function, GlobalVariable, Handle, ImageClass, Interpolation, LocalVariable, Module, RelationalFunction, ScalarKind, ScalarValue, @@ -129,11 +126,13 @@ impl fmt::Display for Version { pub struct Options { /// The glsl version to be used pub version: Version, - /// The name and stage of the entry point + /// The stage of the entry point + pub shader_stage: ShaderStage, + /// The name of the entry point /// /// If no entry point that matches is found a error will be thrown while creating a new instance /// of [`Writer`](struct.Writer.html) - pub entry_point: (ShaderStage, String), + pub entry_point: String, } /// Structure that connects a texture to a sampler or not @@ -275,8 +274,6 @@ pub struct Writer<'a, W> { entry_point: &'a crate::EntryPoint, /// The index of the selected entry point entry_point_idx: crate::proc::EntryPointIndex, - /// The current entry point call_graph (doesn't contain the entry point) - call_graph: CallGraph, /// Used to generate a unique number for blocks block_id: IdGenerator, } @@ -301,12 +298,12 @@ impl<'a, W: Write> Writer<'a, W> { } // Try to find the entry point and corresponding index - let (ep_idx, ep) = module + let (ep_idx, (_, ep)) = module .entry_points .iter() .enumerate() - .find_map(|(i, (key, entry_point))| { - Some((i as u16, entry_point)).filter(|_| &options.entry_point == key) + .find(|(_, ((stage, name), _))| { + options.shader_stage == *stage && &options.entry_point == name }) .ok_or(Error::EntryPointNotFound)?; @@ -314,12 +311,6 @@ impl<'a, W: Write> Writer<'a, W> { let mut names = FastHashMap::default(); Namer::default().reset(module, keywords::RESERVED_KEYWORDS, &mut names); - // Generate a call graph for the entry point - let call_graph = CallGraphBuilder { - functions: &module.functions, - } - .process(&ep.function); - // Build the instance let mut this = Self { module, @@ -330,8 +321,7 @@ impl<'a, W: Write> Writer<'a, W> { features: FeaturesManager::new(), names, entry_point: ep, - entry_point_idx: ep_idx, - call_graph, + entry_point_idx: ep_idx as u16, block_id: IdGenerator::default(), }; @@ -407,7 +397,7 @@ impl<'a, W: Write> Writer<'a, W> { let ep_info = self .analysis - .get_entry_point(self.options.entry_point.0, &self.options.entry_point.1); + .get_entry_point(self.options.shader_stage, &self.options.entry_point); // Write the globals // @@ -475,25 +465,19 @@ impl<'a, W: Write> Writer<'a, W> { _ => self.write_global(handle, global)?, } } + // Write all regular functions + for (handle, function) in self.module.functions.iter() { + // Check that the function doesn't use globals that aren't supported + // by the current entry point + if !ep_info.dominates_global_use(&self.analysis[handle]) { + continue; + } - // Sort the graph topologically so that functions calls are valid - // It's impossible for this to panic because the IR forbids cycles - let functions = petgraph::algo::toposort(&self.call_graph, None).unwrap(); - - // Write all regular functions that are in the call graph this is important - // because other functions might require for example globals that weren't written - for node in functions { - // We do this inside the loop instead of using `map` to satisfy the borrow checker - let handle = self.call_graph[node]; // We also `clone` to satisfy the borrow checker let name = self.names[&NameKey::Function(handle)].clone(); // Write the function - self.write_function( - FunctionType::Function(handle), - &self.module.functions[handle], - name, - )?; + self.write_function(FunctionType::Function(handle), function, name)?; writeln!(self.out)?; } @@ -692,7 +676,7 @@ impl<'a, W: Write> Writer<'a, W> { // // TODO: Should this throw an error? if let Some(interpolation) = global.interpolation { - match (self.options.entry_point.0, global.class) { + match (self.options.shader_stage, global.class) { (ShaderStage::Fragment, StorageClass::Input) | (ShaderStage::Vertex, StorageClass::Output) => { write!(self.out, "{} ", glsl_interpolation(interpolation)?)?; @@ -731,7 +715,7 @@ impl<'a, W: Write> Writer<'a, W> { format!( "_location_{}{}", location, - match (self.options.entry_point.0, global.class) { + match (self.options.shader_stage, global.class) { (ShaderStage::Fragment, StorageClass::Input) => "_vs", (ShaderStage::Vertex, StorageClass::Output) => "_vs", _ => "", @@ -1755,7 +1739,7 @@ impl<'a, W: Write> Writer<'a, W> { use std::collections::hash_map::Entry; let info = self .analysis - .get_entry_point(self.options.entry_point.0, &self.options.entry_point.1); + .get_entry_point(self.options.shader_stage, &self.options.entry_point); let mut mappings = FastHashMap::default(); for sampling in info.sampling_set.iter() { diff --git a/src/proc/analyzer.rs b/src/proc/analyzer.rs index 04081d6468..805d344f50 100644 --- a/src/proc/analyzer.rs +++ b/src/proc/analyzer.rs @@ -99,6 +99,16 @@ impl FunctionInfo { pub fn expression_count(&self) -> usize { self.expressions.len() } + pub fn dominates_global_use(&self, other: &Self) -> bool { + for (self_global_uses, other_global_uses) in + self.global_uses.iter().zip(other.global_uses.iter()) + { + if !self_global_uses.contains(*other_global_uses) { + return false; + } + } + true + } } impl ops::Index> for FunctionInfo { diff --git a/src/proc/call_graph.rs b/src/proc/call_graph.rs deleted file mode 100644 index 9c604bfe9b..0000000000 --- a/src/proc/call_graph.rs +++ /dev/null @@ -1,85 +0,0 @@ -use crate::{ - arena::{Arena, Handle}, - proc::{Interface, Visitor}, - Function, -}; -use bit_set::BitSet; -use petgraph::{ - graph::{DefaultIx, NodeIndex}, - Graph, -}; - -pub type CallGraph = Graph, ()>; - -pub struct CallGraphBuilder<'a> { - pub functions: &'a Arena, -} - -impl<'a> CallGraphBuilder<'a> { - pub fn process(&self, func: &Function) -> CallGraph { - let mut graph = Graph::new(); - let mut children = Vec::new(); - let mut mask = BitSet::with_capacity(func.expressions.len()); - - let visitor = CallGraphVisitor { - children: &mut children, - }; - - let mut interface = Interface { - expressions: &func.expressions, - local_variables: &func.local_variables, - visitor, - mask: &mut mask, - }; - - interface.traverse(&func.body); - - for handle in children { - let id = graph.add_node(handle); - self.collect(handle, id, &mut graph, &mut mask); - } - - graph - } - - fn collect( - &self, - handle: Handle, - id: NodeIndex, - graph: &mut CallGraph, - mask: &mut BitSet, - ) { - let mut children = Vec::new(); - let visitor = CallGraphVisitor { - children: &mut children, - }; - let func = &self.functions[handle]; - mask.clear(); - - let mut interface = Interface { - expressions: &func.expressions, - local_variables: &func.local_variables, - visitor, - mask, - }; - - interface.traverse(&func.body); - - for handle in children { - let child_id = graph.add_node(handle); - graph.add_edge(id, child_id, ()); - - self.collect(handle, child_id, graph, mask); - } - } -} - -struct CallGraphVisitor<'a> { - children: &'a mut Vec>, -} - -impl<'a> Visitor for CallGraphVisitor<'a> { - fn visit_fun(&mut self, func: Handle) { - self.children.push(func) - } -} diff --git a/src/proc/mod.rs b/src/proc/mod.rs index 4e111aa937..3f545fb278 100644 --- a/src/proc/mod.rs +++ b/src/proc/mod.rs @@ -1,8 +1,6 @@ //! Module processing functionality. pub mod analyzer; -#[cfg(feature = "petgraph")] -mod call_graph; mod interface; mod layouter; mod namer; @@ -10,8 +8,6 @@ mod terminator; mod typifier; mod validator; -#[cfg(feature = "petgraph")] -pub use call_graph::{CallGraph, CallGraphBuilder}; pub use interface::{Interface, Visitor}; pub use layouter::{Alignment, Layouter}; pub use namer::{EntryPointIndex, NameKey, Namer}; diff --git a/tests/snapshots.rs b/tests/snapshots.rs index f5148c7dba..f68f4d6afc 100644 --- a/tests/snapshots.rs +++ b/tests/snapshots.rs @@ -187,7 +187,8 @@ fn check_output_glsl( let options = glsl::Options { version: glsl::Version::Embedded(310), - entry_point: (stage, ep_name.to_string()), + shader_stage: stage, + entry_point: ep_name.to_string(), }; let mut buffer = Vec::new();