HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ShaderStage.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_SHADERSTAGE_H
7 #define MATERIALX_SHADERSTAGE_H
8 
9 /// @file
10 /// Class related to holding information for shader stages
11 
13 
17 
18 #include <MaterialXFormat/File.h>
19 
20 #include <MaterialXCore/Node.h>
21 
22 #include <map>
23 #include <sstream>
24 
25 // Restrict a scoped block of statements to a specific shader stage, as
26 // is required for multi-stage shading languages. Statements within
27 // the block will only be emitted when processing the given stage.
28 #define DEFINE_SHADER_STAGE(stage, name) if (stage.getName() == name)
29 
30 // These macros are deprecated, and should be replaced with DEFINE_SHADER_STAGE.
31 #define BEGIN_SHADER_STAGE(stage, name) \
32  if (stage.getName() == name) \
33  {
34 #define END_SHADER_STAGE(stage, name) }
35 
37 
38 namespace Stage
39 {
40 
41 /// Identifier for pixel stage.
42 /// This is the main stage used by all shader targets.
43 /// For single stage shader targets this is the one
44 /// and only stage.
45 /// Shader targets with multiple stages can add additional
46 /// stage identifiers to the Stage namespace.
47 extern MX_GENSHADER_API const string PIXEL;
48 // technically this might only be needed in MaterialXGenHW, but including it here
49 // now for simplicity - refactoring code in MaterialXGenShader may be possible
50 // in the future
51 extern MX_GENSHADER_API const string VERTEX;
52 
53 } // namespace Stage
54 
55 class VariableBlock;
56 /// Shared pointer to a VariableBlock
57 using VariableBlockPtr = std::shared_ptr<VariableBlock>;
58 /// Shared pointer to a map between string identifiers and VariableBlocks.
59 /// The order may affect the order of the respective definitions in the generated code.
60 using VariableBlockMap = std::map<string, VariableBlockPtr>;
61 /// A standard function predicate taking an ShaderPort pointer and returning a boolean.
62 using ShaderPortPredicate = std::function<bool(ShaderPort*)>;
63 
64 /// @class VariableBlock
65 /// A block of variables in a shader stage
67 {
68  public:
69  VariableBlock(const string& name, const string& instance) :
70  _name(name),
71  _instance(instance)
72  {
73  }
74 
75  /// Get the name of this block.
76  const string& getName() const { return _name; }
77 
78  /// Set the name of this block.
79  void setName(const string& name) { _name = name; }
80 
81  /// Get the instance name of this block.
82  const string& getInstance() const { return _instance; }
83 
84  /// Set the instance name of this block.
85  void setInstance(const string& instance) { _instance = instance; }
86 
87  /// Return true if the block has no variables.
88  bool empty() const { return _variableOrder.empty(); }
89 
90  /// Return the number of variables in this block.
91  size_t size() const { return _variableOrder.size(); }
92 
93  /// Return a variable by index.
94  ShaderPort* operator[](size_t index) { return _variableOrder[index]; }
95 
96  /// Return a variable by index.
97  const ShaderPort* operator[](size_t index) const { return _variableOrder[index]; }
98 
99  /// Return a const reference to our variable order vector.
100  const vector<ShaderPort*>& getVariableOrder() const { return _variableOrder; }
101 
102  /// Return a variable by name. Throws exception if
103  /// no variable is found by the given name.
104  ShaderPort* operator[](const string& name);
105 
106  /// Return a variable by name. Throws exception if
107  /// no variable is found by the given name.
108  const ShaderPort* operator[](const string& name) const;
109 
110  /// Return a variable by name. Returns nullptr if
111  /// no variable is found by the given name.
112  ShaderPort* find(const string& name);
113 
114  /// Return a variable by name. Returns nullptr if
115  /// no variable is found by the given name.
116  const ShaderPort* find(const string& name) const;
117 
118  /// Find a port based on a predicate
119  ShaderPort* find(const ShaderPortPredicate& predicate);
120 
121  /// Add a new shader port to this block.
122  /// @param type The desired shader port type
123  /// @param name The shader port name
124  /// @param value The value to attach to the shader port
125  /// @param shouldWiden When false, an exception is thrown if the type of the existing port with
126  /// the same name does not match the requested type. When true, the types can mismatch, and the
127  /// type of any existing port is widened to match the requested type when necessary.
128  /// @return A new shader port, or a pre-existing shader port with the same name.
129  ShaderPort* add(TypeDesc type, const string& name, ValuePtr value = nullptr, bool shouldWiden = false);
130 
131  /// Add an existing shader port to this block.
132  void add(ShaderPortPtr port);
133 
134  private:
135  string _name;
136  string _instance;
137  std::unordered_map<string, ShaderPortPtr> _variableMap;
138  vector<ShaderPort*> _variableOrder;
139 };
140 
141 /// @class ShaderStage
142 /// A shader stage, containing the state and
143 /// resulting source code for the stage.
145 {
146  public:
147  using FunctionCallId = const ShaderNode*;
148  struct Scope
149  {
151  std::set<FunctionCallId> functions;
153  punctuation(p) { }
154  };
155 
156  public:
157  /// Constructor.
158  ShaderStage(const string& name, ConstSyntaxPtr syntax);
159 
160  /// Return the stage name.
161  const string& getName() const { return _name; }
162 
163  /// Return the stage function name.
164  const string& getFunctionName() const { return _functionName; }
165 
166  /// Set the stage source code.
167  void setSourceCode(const string& code) { _code = code; }
168 
169  /// Return the stage source code.
170  const string& getSourceCode() const { return _code; }
171 
172  /// Create a new uniform variable block.
173  VariableBlockPtr createUniformBlock(const string& name, const string& instance = EMPTY_STRING);
174 
175  /// Create a new input variable block.
176  VariableBlockPtr createInputBlock(const string& name, const string& instance = EMPTY_STRING);
177 
178  /// Create a new output variable block.
179  VariableBlockPtr createOutputBlock(const string& name, const string& instance = EMPTY_STRING);
180 
181  /// Return the uniform variable block with given name.
182  VariableBlock& getUniformBlock(const string& name);
183 
184  /// Return the uniform variable block with given name.
185  const VariableBlock& getUniformBlock(const string& name) const;
186 
187  /// Return the input variable block with given name.
188  VariableBlock& getInputBlock(const string& name);
189 
190  /// Return the input variable block with given name.
191  const VariableBlock& getInputBlock(const string& name) const;
192 
193  /// Return the output variable block with given name.
194  VariableBlock& getOutputBlock(const string& name);
195 
196  /// Return the output variable block with given name.
197  const VariableBlock& getOutputBlock(const string& name) const;
198 
199  /// Return the constant variable block.
200  VariableBlock& getConstantBlock();
201 
202  /// Return the constant variable block.
203  const VariableBlock& getConstantBlock() const;
204 
205  /// Return a map of all uniform blocks.
207  {
208  return _uniforms;
209  }
210 
211  /// Return a map of all input blocks.
213  {
214  return _inputs;
215  }
216 
217  /// Return a map of all output blocks.
219  {
220  return _outputs;
221  }
222 
223  /// Return a set of all include files
224  const StringSet& getIncludes() const
225  {
226  return _includes;
227  }
228 
229  /// Return a set of all source dependencies
231  {
232  return _sourceDependencies;
233  }
234 
235  /// Start a new scope using the given bracket type.
236  void beginScope(Syntax::Punctuation punc = Syntax::CURLY_BRACKETS);
237 
238  /// End the current scope.
239  void endScope(bool semicolon = false, bool newline = true);
240 
241  /// Start a new line.
242  void beginLine();
243 
244  /// End the current line.
245  void endLine(bool semicolon = true);
246 
247  /// Add a newline character.
248  void newLine();
249 
250  /// Add a string.
251  void addString(const string& str);
252 
253  /// Add a single line of code, optionally appending a semicolon.
254  void addLine(const string& str, bool semicolon = true);
255 
256  /// Add a single line code comment.
257  void addComment(const string& str);
258 
259  /// Add a block of code.
260  void addBlock(const string& str, const FilePath& sourceFilename, GenContext& context);
261 
262  /// Add the contents of an include file if not already present.
263  void addInclude(const FilePath& includeFilename, const FilePath& sourceFilename, GenContext& context);
264 
265  /// Return true if this stage depends on the given source file.
266  bool hasSourceDependency(const FilePath& file);
267 
268  /// Mark the given source file as a dependency of this stage.
269  void addSourceDependency(const FilePath& file);
270 
271  /// Add a value.
272  template <typename T>
273  void addValue(const T& value)
274  {
275  StringStream str;
276  str << value;
277  _code += str.str();
278  }
279 
280  /// Add the function definition for a node's implementation.
281  void addFunctionDefinition(const ShaderNode& node, GenContext& context);
282 
283  /// Add the function call for the given node.
284  /// This will register the function as being called in the current scope, and code for the
285  /// function call will be added to the stage. If emitCode is set to false the code for the
286  /// function call will be omitted.
287  void addFunctionCall(const ShaderNode& node, GenContext& context, bool emitCode = true);
288 
289  /// Return true if the function for the given node has been emitted in the current scope.
290  bool isEmitted(const ShaderNode& node, GenContext& context) const;
291 
292  /// Set stage function name.
293  void setFunctionName(const string& functionName)
294  {
295  _functionName = functionName;
296  }
297 
298  private:
299  /// Name of the stage
300  const string _name;
301 
302  /// Name of the stage main function
303  string _functionName;
304 
305  /// Syntax for the type of shader to generate.
306  ConstSyntaxPtr _syntax;
307 
308  /// Current indentation level.
309  int _indentations;
310 
311  /// Current scope.
312  vector<Scope> _scopes;
313 
314  /// Set of include files that has been included.
315  StringSet _includes;
316 
317  /// Set of source file dependencies from source code nodes
318  StringSet _sourceDependencies;
319 
320  /// Set of hash ID's for functions that has been defined.
321  std::set<size_t> _definedFunctions;
322 
323  /// Block holding constant variables for this stage.
324  VariableBlock _constants;
325 
326  /// Map of blocks holding uniform variables for this stage.
327  VariableBlockMap _uniforms;
328 
329  /// Map of blocks holding input variables for this stage.
330  VariableBlockMap _inputs;
331 
332  /// Map of blocks holding output variables for this stage.
333  VariableBlockMap _outputs;
334 
335  /// Resulting source code for this stage.
336  string _code;
337 
338  friend class ShaderGenerator;
339 };
340 
341 /// Shared pointer to a ShaderStage
342 using ShaderStagePtr = std::shared_ptr<ShaderStage>;
343 
344 /// Utility function for adding a new shader port to a uniform block.
345 inline ShaderPort* addStageUniform(const string& block,
346  TypeDesc type,
347  const string& name,
348  ShaderStage& stage)
349 {
350  VariableBlock& uniforms = stage.getUniformBlock(block);
351  return uniforms.add(type, name);
352 }
353 [[deprecated]] inline ShaderPort* addStageUniform(const string& block,
354  const TypeDesc* type,
355  const string& name,
356  ShaderStage& stage)
357 {
358  return addStageUniform(block, *type, name, stage);
359 }
360 
361 /// Utility function for adding a new shader port to an input block.
362 inline ShaderPort* addStageInput(const string& block,
363  TypeDesc type,
364  const string& name,
365  ShaderStage& stage,
366  bool shouldWiden = false)
367 {
368  VariableBlock& inputs = stage.getInputBlock(block);
369  return inputs.add(type, name, {}, shouldWiden);
370 }
371 [[deprecated]] inline ShaderPort* addStageInput(const string& block,
372  const TypeDesc* type,
373  const string& name,
374  ShaderStage& stage,
375  bool shouldWiden = false)
376 {
377  return addStageInput(block, *type, name, stage, shouldWiden);
378 }
379 
380 /// Utility function for adding a new shader port to an output block.
381 inline ShaderPort* addStageOutput(const string& block,
382  TypeDesc type,
383  const string& name,
384  ShaderStage& stage,
385  bool shouldWiden = false)
386 {
387  VariableBlock& outputs = stage.getOutputBlock(block);
388  return outputs.add(type, name, {}, shouldWiden);
389 }
390 [[deprecated]] inline ShaderPort* addStageOutput(const string& block,
391  const TypeDesc* type,
392  const string& name,
393  ShaderStage& stage,
394  bool shouldWiden = false)
395 {
396  return addStageOutput(block, *type, name, stage, shouldWiden);
397 }
398 
399 /// Utility function for adding a connector block between stages.
400 inline void addStageConnectorBlock(const string& block,
401  const string& instance,
402  ShaderStage& from,
403  ShaderStage& to)
404 {
405  from.createOutputBlock(block, instance);
406  to.createInputBlock(block, instance);
407 }
408 
409 /// Utility function for adding a variable to a stage connector block.
410 inline void addStageConnector(const string& block,
411  TypeDesc type,
412  const string& name,
413  ShaderStage& from,
414  ShaderStage& to,
415  bool shouldWiden = false)
416 {
417  addStageOutput(block, type, name, from, shouldWiden);
418  addStageInput(block, type, name, to, shouldWiden);
419 }
420 [[deprecated]] inline void addStageConnector(const string& block,
421  const TypeDesc* type,
422  const string& name,
423  ShaderStage& from,
424  ShaderStage& to,
425  bool shouldWiden = false)
426 {
427  addStageConnector(block, *type, name, from, to, shouldWiden);
428 }
429 
431 
432 #endif
ShaderPort * addStageOutput(const string &block, TypeDesc type, const string &name, ShaderStage &stage, bool shouldWiden=false)
Utility function for adding a new shader port to an output block.
Definition: ShaderStage.h:381
void addStageConnectorBlock(const string &block, const string &instance, ShaderStage &from, ShaderStage &to)
Utility function for adding a connector block between stages.
Definition: ShaderStage.h:400
Definition: File.h:26
void addValue(const T &value)
Add a value.
Definition: ShaderStage.h:273
#define MATERIALX_NAMESPACE_BEGIN
Definition: Generated.h:25
GLsizei const GLfloat * value
Definition: glcorearb.h:824
bool empty() const
Return true if the block has no variables.
Definition: ShaderStage.h:88
ShaderPort * add(TypeDesc type, const string &name, ValuePtr value=nullptr, bool shouldWiden=false)
Uses the stage's time code range.
std::map< string, VariableBlockPtr > VariableBlockMap
Definition: ShaderStage.h:60
MATERIALX_NAMESPACE_BEGIN MX_CORE_API const string EMPTY_STRING
VariableBlockPtr createOutputBlock(const string &name, const string &instance=EMPTY_STRING)
Create a new output variable block.
shared_ptr< const Syntax > ConstSyntaxPtr
Shared pointer to a constant Syntax.
Definition: Syntax.h:30
const VariableBlockMap & getOutputBlocks() const
Return a map of all output blocks.
Definition: ShaderStage.h:218
#define MX_GENSHADER_API
Definition: Export.h:18
const VariableBlockMap & getInputBlocks() const
Return a map of all input blocks.
Definition: ShaderStage.h:212
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2138
const string & getName() const
Return the stage name.
Definition: ShaderStage.h:161
void setSourceCode(const string &code)
Set the stage source code.
Definition: ShaderStage.h:167
std::shared_ptr< VariableBlock > VariableBlockPtr
Shared pointer to a VariableBlock.
Definition: ShaderStage.h:57
void addStageConnector(const string &block, TypeDesc type, const string &name, ShaderStage &from, ShaderStage &to, bool shouldWiden=false)
Utility function for adding a variable to a stage connector block.
Definition: ShaderStage.h:410
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
const string & getName() const
Get the name of this block.
Definition: ShaderStage.h:76
std::function< bool(ShaderPort *)> ShaderPortPredicate
A standard function predicate taking an ShaderPort pointer and returning a boolean.
Definition: ShaderStage.h:62
Scope(Syntax::Punctuation p)
Definition: ShaderStage.h:152
MX_GENSHADER_API const string VERTEX
VariableBlock & getInputBlock(const string &name)
Return the input variable block with given name.
ShaderPort * operator[](size_t index)
Return a variable by index.
Definition: ShaderStage.h:94
const StringSet & getIncludes() const
Return a set of all include files.
Definition: ShaderStage.h:224
GLuint const GLchar * name
Definition: glcorearb.h:786
void setFunctionName(const string &functionName)
Set stage function name.
Definition: ShaderStage.h:293
ShaderPort * addStageInput(const string &block, TypeDesc type, const string &name, ShaderStage &stage, bool shouldWiden=false)
Utility function for adding a new shader port to an input block.
Definition: ShaderStage.h:362
MX_GENSHADER_API const string PIXEL
Syntax::Punctuation punctuation
Definition: ShaderStage.h:150
const vector< ShaderPort * > & getVariableOrder() const
Return a const reference to our variable order vector.
Definition: ShaderStage.h:100
std::set< FunctionCallId > functions
Definition: ShaderStage.h:151
size_t size() const
Return the number of variables in this block.
Definition: ShaderStage.h:91
void setInstance(const string &instance)
Set the instance name of this block.
Definition: ShaderStage.h:85
shared_ptr< ShaderStage > ShaderStagePtr
Shared pointer to a ShaderStage.
Definition: Library.h:35
Punctuation
Punctuation types.
Definition: Syntax.h:47
const VariableBlockMap & getUniformBlocks() const
Return a map of all uniform blocks.
Definition: ShaderStage.h:206
void setName(const string &name)
Set the name of this block.
Definition: ShaderStage.h:79
GLuint index
Definition: glcorearb.h:786
shared_ptr< class ShaderPort > ShaderPortPtr
Shared pointer to a ShaderPort.
Definition: ShaderNode.h:29
VariableBlock & getUniformBlock(const string &name)
Return the uniform variable block with given name.
const ShaderPort * operator[](size_t index) const
Return a variable by index.
Definition: ShaderStage.h:97
std::set< string > StringSet
A set of strings.
Definition: Library.h:65
#define MATERIALX_NAMESPACE_END
Definition: Generated.h:26
ShaderPort * addStageUniform(const string &block, TypeDesc type, const string &name, ShaderStage &stage)
Utility function for adding a new shader port to a uniform block.
Definition: ShaderStage.h:345
VariableBlock & getOutputBlock(const string &name)
Return the output variable block with given name.
ImageBuf OIIO_API add(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
const string & getFunctionName() const
Return the stage function name.
Definition: ShaderStage.h:164
std::stringstream StringStream
A string stream.
Definition: Library.h:30
const string & getInstance() const
Get the instance name of this block.
Definition: ShaderStage.h:82
shared_ptr< Value > ValuePtr
A shared pointer to a Value.
Definition: Value.h:30
const StringSet & getSourceDependencies() const
Return a set of all source dependencies.
Definition: ShaderStage.h:230
VariableBlockPtr createInputBlock(const string &name, const string &instance=EMPTY_STRING)
Create a new input variable block.
const string & getSourceCode() const
Return the stage source code.
Definition: ShaderStage.h:170
VariableBlock(const string &name, const string &instance)
Definition: ShaderStage.h:69