HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ShaderGraph.h
Go to the documentation of this file.
1 //
2 // Copyright Contributors to the MaterialX Project
3 // SPDX-License-Identifier: Apache-2.0
4 //
5 
6 #ifndef MATERIALX_SHADERGRAPH_H
7 #define MATERIALX_SHADERGRAPH_H
8 
9 /// @file
10 /// Shader graph class
11 
13 
19 
20 #include <MaterialXCore/Document.h>
21 #include <MaterialXCore/Node.h>
22 
24 
25 class Syntax;
26 class ShaderGraphEdge;
28 class GenOptions;
30 
31 /// An internal input socket in a shader graph,
32 /// used for connecting internal nodes to the outside
34 
35 /// An internal output socket in a shader graph,
36 /// used for connecting internal nodes to the outside
38 
39 /// A shared pointer to a shader graph
40 using ShaderGraphPtr = shared_ptr<class ShaderGraph>;
41 
42 /// @class ShaderGraph
43 /// Class representing a graph (DAG) for shader generation
45 {
46  public:
47  /// Constructor.
48  ShaderGraph(const ShaderGraph* parent, const string& name, ConstDocumentPtr document,
49  GenContext& context);
50 
51  /// Destructor.
52  virtual ~ShaderGraph() { }
53 
54  /// Create a new shader graph from an element.
55  /// Supported elements are outputs and shader nodes.
56  static ShaderGraphPtr create(const ShaderGraph* parent, const string& name, ElementPtr element,
57  GenContext& context);
58 
59  /// Create a new shader graph from a nodegraph.
60  static ShaderGraphPtr create(const ShaderGraph* parent, const NodeGraph& nodeGraph,
61  GenContext& context);
62 
63  /// Return true if this node is a graph.
64  bool isAGraph() const override { return true; }
65 
66  /// Get an internal node by its unique identifier.
67  ShaderNode* getNode(const string& uniqueId);
68 
69  /// Get an internal node by its unique identifier.
70  const ShaderNode* getNode(const string& uniqueId) const;
71 
72  /// Get a vector of all nodes in order
73  const vector<ShaderNode*>& getNodes() const { return _nodeOrder; }
74 
75  /// Get number of input sockets
76  size_t numInputSockets() const { return numOutputs(); }
77 
78  /// Get number of output sockets
79  size_t numOutputSockets() const { return numInputs(); }
80 
81  /// Get socket by index
84  const ShaderGraphInputSocket* getInputSocket(size_t index) const { return getOutput(index); }
85  const ShaderGraphOutputSocket* getOutputSocket(size_t index = 0) const { return getInput(index); }
86 
87  /// Get socket by name
88  ShaderGraphInputSocket* getInputSocket(const string& name) { return getOutput(name); }
89  ShaderGraphOutputSocket* getOutputSocket(const string& name) { return getInput(name); }
90  const ShaderGraphInputSocket* getInputSocket(const string& name) const { return getOutput(name); }
91  const ShaderGraphOutputSocket* getOutputSocket(const string& name) const { return getInput(name); }
92 
93  /// Get vector of sockets
94  const vector<ShaderGraphInputSocket*>& getInputSockets() const { return _outputOrder; }
95  const vector<ShaderGraphOutputSocket*>& getOutputSockets() const { return _inputOrder; }
96 
97  /// Apply color and unit transforms to each input of a node.
98  void applyInputTransforms(ConstNodePtr node, ShaderNode* shaderNode, GenContext& context);
99 
100  /// Create a new node in the graph
101  ShaderNode* createNode(ConstNodePtr node, GenContext& context);
102 
103  ShaderNode* inlineNodeBeforeOutput(ShaderGraphOutputSocket* output,
104  const std::string& newNodeName,
105  const std::string& nodeDefName,
106  const std::string& inputName,
107  const std::string& outputName,
108  GenContext& context);
109 
110  /// Add input sockets
111  ShaderGraphInputSocket* addInputSocket(const string& name, TypeDesc type);
112  [[deprecated]] ShaderGraphInputSocket* addInputSocket(const string& name, const TypeDesc* type) { return addInputSocket(name, *type); }
113 
114  /// Add output sockets
115  ShaderGraphOutputSocket* addOutputSocket(const string& name, TypeDesc type);
116  [[deprecated]] ShaderGraphOutputSocket* addOutputSocket(const string& name, const TypeDesc* type) { return addOutputSocket(name, *type); }
117 
118  /// Add a default geometric node and connect to the given input.
119  void addDefaultGeomNode(ShaderInput* input, const GeomPropDef& geomprop, GenContext& context);
120 
121  /// Sort the nodes in topological order.
122  void topologicalSort();
123 
124  /// Return an iterator for traversal upstream from the given output
125  static ShaderGraphEdgeIterator traverseUpstream(ShaderOutput* output);
126 
127  /// Return the map of unique identifiers used in the scope of this graph.
128  IdentifierMap& getIdentifierMap() { return _identifiers; }
129 
130  /// Return the document associated with this graph.
131  ConstDocumentPtr getDocument() const { return _document; }
132 
133  /// Create a new node in the graph from a node definition.
134  ShaderNode* createNode(const string& name, const string& uniqueId, ConstNodeDefPtr nodeDef, GenContext& context);
135 
136  /// Bypass a node for a particular input and output,
137  /// effectively connecting the input's upstream connection
138  /// with the output's downstream connections.
139  void bypass(ShaderNode* node, size_t inputIndex, size_t outputIndex = 0);
140 
141  /// Remove nodes that are no longer connected to any output.
142  void removeUnusedNodes();
143 
144  /// Rewire all downstream connections from one output to another.
145  void replaceOutput(ShaderOutput* oldOutput, ShaderOutput* newOutput);
146 
147  protected:
148  /// Create node connections corresponding to the connection between a pair of elements.
149  /// @param downstreamElement Element representing the node to connect to.
150  /// @param upstreamElement Element representing the node to connect from
151  /// @param connectingElement If non-null, specifies the element on on the downstream node to connect to.
152  /// @param context Context for generation.
153  void createConnectedNodes(const ElementPtr& downstreamElement,
154  const ElementPtr& upstreamElement,
155  ElementPtr connectingElement,
156  GenContext& context);
157 
158  /// Add a node to the graph, keyed by the node's unique identifier.
159  void addNode(ShaderNodePtr node);
160 
161  /// Add input sockets from an interface element (nodedef, nodegraph or node)
162  void addInputSockets(const InterfaceElement& elem, GenContext& context);
163 
164  /// Add output sockets from an interface element (nodedef, nodegraph or node)
165  void addOutputSockets(const InterfaceElement& elem, GenContext& context);
166 
167  /// Traverse from the given root element and add all dependencies upstream.
168  /// The traversal is done in the context of a material, if given, to include
169  /// bind input elements in the traversal.
170  void addUpstreamDependencies(const Element& root, GenContext& context);
171 
172  /// Add a color transform node and connect to the given input.
173  void addColorTransformNode(ShaderInput* input, const ColorSpaceTransform& transform, GenContext& context);
174 
175  /// Add a color transform node and connect to the given output.
176  void addColorTransformNode(ShaderOutput* output, const ColorSpaceTransform& transform, GenContext& context);
177 
178  /// Add a unit transform node and connect to the given input.
179  void addUnitTransformNode(ShaderInput* input, const UnitTransform& transform, GenContext& context);
180 
181  /// Add a unit transform node and connect to the given output.
182  void addUnitTransformNode(ShaderOutput* output, const UnitTransform& transform, GenContext& context);
183 
184  /// Perform all post-build operations on the graph.
185  void finalize(GenContext& context);
186 
187  /// For inputs and outputs in the graph set the variable names to be used
188  /// in generated code. Making sure variable names are valid and unique
189  /// to avoid name conflicts during shader generation.
190  void setVariableNames(GenContext& context);
191 
192  /// Populate the color transform map for the given shader port, if the provided combination of
193  /// source and target color spaces are supported for its data type.
194  void populateColorTransformMap(ColorManagementSystemPtr colorManagementSystem, ShaderPort* shaderPort,
195  const string& sourceColorSpace, const string& targetColorSpace, bool asInput);
196 
197  /// Populates the appropriate unit transform map if the provided input/parameter or output
198  /// has a unit attribute and is of the supported type
199  void populateUnitTransformMap(UnitSystemPtr unitSystem, ShaderPort* shaderPort, ValueElementPtr element, const string& targetUnitSpace, bool asInput);
200 
201  /// Break all connections on a node
202  void disconnect(ShaderNode* node) const;
203 
205  std::unordered_map<string, ShaderNodePtr> _nodeMap;
206  std::vector<ShaderNode*> _nodeOrder;
208 
209  // Temporary storage for inputs that require color transformations
210  std::vector<std::pair<ShaderInput*, ColorSpaceTransform>> _inputColorTransformMap;
211  // Temporary storage for inputs that require unit transformations
212  std::vector<std::pair<ShaderInput*, UnitTransform>> _inputUnitTransformMap;
213 
214  // Temporary storage for outputs that require color transformations
215  std::vector<std::pair<ShaderOutput*, ColorSpaceTransform>> _outputColorTransformMap;
216  // Temporary storage for outputs that require unit transformations
217  std::vector<std::pair<ShaderOutput*, UnitTransform>> _outputUnitTransformMap;
218 };
219 
220 /// @class ShaderGraphEdge
221 /// An edge returned during shader graph traversal.
223 {
224  public:
226  upstream(up),
227  downstream(down)
228  {
229  }
230 
231  bool operator==(const ShaderGraphEdge& rhs) const
232  {
233  return upstream == rhs.upstream && downstream == rhs.downstream;
234  }
235 
236  bool operator!=(const ShaderGraphEdge& rhs) const
237  {
238  return !(*this == rhs);
239  }
240 
241  bool operator<(const ShaderGraphEdge& rhs) const
242  {
243  return std::tie(upstream, downstream) < std::tie(rhs.upstream, rhs.downstream);
244  }
245 
248 };
249 
250 /// @class ShaderGraphEdgeIterator
251 /// Iterator class for traversing edges between nodes in a shader graph.
253 {
254  public:
256  ~ShaderGraphEdgeIterator() = default;
257 
258  bool operator==(const ShaderGraphEdgeIterator& rhs) const
259  {
260  return _upstream == rhs._upstream &&
261  _downstream == rhs._downstream &&
262  _stack == rhs._stack;
263  }
264  bool operator!=(const ShaderGraphEdgeIterator& rhs) const
265  {
266  return !(*this == rhs);
267  }
268 
269  /// Dereference this iterator, returning the current output in the traversal.
271  {
272  return ShaderGraphEdge(_upstream, _downstream);
273  }
274 
275  /// Iterate to the next edge in the traversal.
276  /// @throws ExceptionFoundCycle if a cycle is encountered.
277  ShaderGraphEdgeIterator& operator++();
278 
279  /// Return a reference to this iterator to begin traversal
281  {
282  return *this;
283  }
284 
285  /// Return the end iterator.
286  static const ShaderGraphEdgeIterator& end();
287 
288  private:
289  void extendPathUpstream(ShaderOutput* upstream, ShaderInput* downstream);
290  void returnPathDownstream(ShaderOutput* upstream);
291  bool skipOrMarkAsVisited(ShaderGraphEdge);
292 
293  ShaderOutput* _upstream;
294  ShaderInput* _downstream;
295  using StackFrame = std::pair<ShaderOutput*, size_t>;
296  std::vector<StackFrame> _stack;
297  std::set<ShaderOutput*> _path;
298  std::set<ShaderGraphEdge> _visitedEdges;
299 };
300 
302 
303 #endif
std::vector< std::pair< ShaderInput *, UnitTransform > > _inputUnitTransformMap
Definition: ShaderGraph.h:212
ShaderGraphOutputSocket * addOutputSocket(const string &name, const TypeDesc *type)
Definition: ShaderGraph.h:116
ShaderGraphEdge operator*() const
Dereference this iterator, returning the current output in the traversal.
Definition: ShaderGraph.h:270
ShaderGraphInputSocket * getInputSocket(size_t index)
Get socket by index.
Definition: ShaderGraph.h:82
friend class ShaderGraph
Definition: ShaderNode.h:518
vector< ShaderInput * > _inputOrder
Definition: ShaderNode.h:510
bool operator==(const ShaderGraphEdgeIterator &rhs) const
Definition: ShaderGraph.h:258
std::unordered_map< string, ShaderNodePtr > _nodeMap
Definition: ShaderGraph.h:205
#define MATERIALX_NAMESPACE_BEGIN
Definition: Generated.h:25
ShaderOutput * getOutput(size_t index=0)
Definition: ShaderNode.h:461
ShaderInput * getInput(size_t index)
Get inputs/outputs by index.
Definition: ShaderNode.h:460
shared_ptr< class UnitSystem > UnitSystemPtr
A shared pointer to a UnitSystem.
Definition: UnitSystem.h:26
vector< ShaderOutput * > _outputOrder
Definition: ShaderNode.h:513
ShaderGraphOutputSocket * getOutputSocket(const string &name)
Definition: ShaderGraph.h:89
shared_ptr< const Node > ConstNodePtr
A shared pointer to a const Node.
Definition: Node.h:26
size_t numOutputs() const
Definition: ShaderNode.h:457
#define MX_GENSHADER_API
Definition: Export.h:18
const vector< ShaderGraphOutputSocket * > & getOutputSockets() const
Definition: ShaderGraph.h:95
ShaderGraphOutputSocket * getOutputSocket(size_t index=0)
Definition: ShaderGraph.h:83
const ShaderGraphInputSocket * getInputSocket(size_t index) const
Definition: ShaderGraph.h:84
std::vector< ShaderNode * > _nodeOrder
Definition: ShaderGraph.h:206
bool operator!=(const ShaderGraphEdgeIterator &rhs) const
Definition: ShaderGraph.h:264
ShaderGraphEdgeIterator & begin()
Return a reference to this iterator to begin traversal.
Definition: ShaderGraph.h:280
std::vector< std::pair< ShaderOutput *, UnitTransform > > _outputUnitTransformMap
Definition: ShaderGraph.h:217
size_t numInputSockets() const
Get number of input sockets.
Definition: ShaderGraph.h:76
ShaderGraphInputSocket * addInputSocket(const string &name, const TypeDesc *type)
Definition: ShaderGraph.h:112
std::vector< std::pair< ShaderInput *, ColorSpaceTransform > > _inputColorTransformMap
Definition: ShaderGraph.h:210
ShaderGraphEdge(ShaderOutput *up, ShaderInput *down)
Definition: ShaderGraph.h:225
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
bool operator<(const ShaderGraphEdge &rhs) const
Definition: ShaderGraph.h:241
shared_ptr< class ColorManagementSystem > ColorManagementSystemPtr
A shared pointer to a ColorManagementSystem.
ShaderGraphInputSocket * getInputSocket(const string &name)
Get socket by name.
Definition: ShaderGraph.h:88
shared_ptr< class ShaderNode > ShaderNodePtr
Shared pointer to a ShaderNode.
Definition: ShaderNode.h:35
ShaderInput * downstream
Definition: ShaderGraph.h:247
GLuint GLuint end
Definition: glcorearb.h:475
bool operator==(const ShaderGraphEdge &rhs) const
Definition: ShaderGraph.h:231
static ShaderNodePtr create(const ShaderGraph *parent, const string &name, const NodeDef &nodeDef, GenContext &context)
Create a new node from a nodedef.
GLuint const GLchar * name
Definition: glcorearb.h:786
shared_ptr< class ShaderGraph > ShaderGraphPtr
A shared pointer to a shader graph.
Definition: ShaderGraph.h:40
bool operator!=(const ShaderGraphEdge &rhs) const
Definition: ShaderGraph.h:236
GA_API const UT_StringHolder transform
const ShaderGraphOutputSocket * getOutputSocket(size_t index=0) const
Definition: ShaderGraph.h:85
const ShaderGraphOutputSocket * getOutputSocket(const string &name) const
Definition: ShaderGraph.h:91
size_t numOutputSockets() const
Get number of output sockets.
Definition: ShaderGraph.h:79
virtual ~ShaderGraph()
Destructor.
Definition: ShaderGraph.h:52
ShaderOutput * upstream
Definition: ShaderGraph.h:246
bool isAGraph() const override
Return true if this node is a graph.
Definition: ShaderGraph.h:64
IdentifierMap _identifiers
Definition: ShaderGraph.h:207
const vector< ShaderNode * > & getNodes() const
Get a vector of all nodes in order.
Definition: ShaderGraph.h:73
std::unordered_map< string, size_t > IdentifierMap
Definition: Syntax.h:38
GLuint index
Definition: glcorearb.h:786
const ShaderGraphInputSocket * getInputSocket(const string &name) const
Definition: ShaderGraph.h:90
const vector< ShaderGraphInputSocket * > & getInputSockets() const
Get vector of sockets.
Definition: ShaderGraph.h:94
shared_ptr< Element > ElementPtr
A shared pointer to an Element.
Definition: Element.h:31
shared_ptr< ValueElement > ValueElementPtr
A shared pointer to a ValueElement.
Definition: Element.h:41
#define MATERIALX_NAMESPACE_END
Definition: Generated.h:26
shared_ptr< const NodeDef > ConstNodeDefPtr
A shared pointer to a const NodeDef.
Definition: Definition.h:34
size_t numInputs() const
Get number of inputs/outputs.
Definition: ShaderNode.h:456
Definition: Syntax.h:43
ConstDocumentPtr _document
Definition: ShaderGraph.h:204
shared_ptr< const Document > ConstDocumentPtr
A shared pointer to a const Document.
Definition: Document.h:24
ConstDocumentPtr getDocument() const
Return the document associated with this graph.
Definition: ShaderGraph.h:131
std::vector< std::pair< ShaderOutput *, ColorSpaceTransform > > _outputColorTransformMap
Definition: ShaderGraph.h:215
IdentifierMap & getIdentifierMap()
Return the map of unique identifiers used in the scope of this graph.
Definition: ShaderGraph.h:128