AcademySoftwareFoundation / AcademySoftwareFoundation/MaterialX
Enhance shader interface options (draft)
- Dominant language
- C++
- Stars
- 2.3k
- Forks
- 451
- Avg merge
- 6d 6h
- Merged PRs (30d)
- 5
Description
# MaterialX Shader Optimizations
## 1. Background
This document provides some insights into possible shader optimizations for code generated through MaterialX shader / code generators.
## 2. Constant Folding Optimization
The first optimization to consider is "constant folding" which reduces the number of bindable **uniform** inputs arguments which are exposed in a shader.
In general **varying** inputs must be bound as they represent geometric inputs
and are not considered any further in this document.
This can reduce both time to discover these uniforms, to bind as well as render time.
## 3. MaterialX Data Model Information Hiding
Reduction of bindable inputs can be performed by the creator of MaterialX node graphs.
(In the following diagrams, items in green are bindable or have bindable inputs)
### 3.1 Default Exposure
The greatest "exposure" of inputs is with graphs which are created at the top (Document) level. Any input on any node is considered to be a bindable input.
For example provided shading model nodes such as "standard surface" has more than 50 bindable inputs. Attaching more upstream nodes can increase that number so that a graph with a few texture mapped inputs could for instance have 100 or more inputs.
```mermaid
graph LR
node1-->node2
node2-->node3
node5
node4-->node5
style node1 fill:#1b1,color:#fff
style node2 fill:#1b1,color:#fff
style node3 fill:#1b1,color:#fff
style node4 fill:#1b1,color:#fff
style node5 fill:#1b1,color:#fff
```
----------------
### 3.2 Node Graph Interface Exposure
One option is to "hide" the one or more sets of nodes within nodegraphs. Nodegraphs allow for the instantiation of inputs which act as the "public" interface. The smaller the interface the smaller the number of possible bindable inputs.
```mermaid
graph LR
subgraph nodegraph[Node Graph]
input1(Diffuse Color)-->node1
node1-->node2
node2-->node3
node4-->node3
node5
node4-->node5
node3-->output(Output Alpha)
node5-->output2(Output Color)
end
style input1 fill:#1b1,color:#fff
style output fill:#0bb,color:#fff
style output fill:#0bb,color:#fff
style output2 fill:#0bb,color:#fff
```
----------------
### 3.1 Definition Interface Exposure
Further interface hiding can occur by creating new definitions from nodegraphs and replacing the nodegraphs with instances of these new definitions.
```mermaid
graph LR
subgraph myNode[Node Definition]
m_input1(Diffuse Color)
m_output(Output Alpha)
m_output2(Output Color)
subgraph myNodeGraph[Functioal Graph Implementation]
input1(Diffuse Color)-->node1
node1-->node2
node2-->node3
node4-->node3
node5
node4-->node5
node3-->output(Output Alpha)
node5-->output2(Output Color)
end
end
style input1 fill:#1b1,color:#fff
style output fill:#0bb,color:#fff
style output2 fill:#0bb,color:#fff
style m_input1 fill:#1b1,color:#fff
style m_output fill:#0bb,color:#fff
style m_output2 fill:#0bb,color:#fff
```
----------------
### 3.3 Data Model Caveats
Some tradeoffs for this approach include:
* The original authored graphs must be transformed into another graph to perform reduction.
* If this is a replacement than this changes the user facing interface.
* Any new nodes, definitions can "pollute" the original document and would need to be filtered out for interop as desired.
* This can introduce graphs which may not be handled by certain integrations. For example inclusion of shading model nodes into definitions may not be supported.
## 4. Shader Generation Options
By default a "full" set of bindable inputs is exposed. That is any unconnected inputs on nodes internal to a graph are treated the same as nodes which do not reside in a graph.
For example, the following graph would have in1 to in9 be bindable
```mermaid
graph BT
subgraph nodegraph[Node Graph]
input1(in1)-->node1
node1-->node2
input2(in2)-->node4
node2-->node3
input3(in3)-->node4
node4-->node3
input4(in4)-->node2
node4 --> node5
node5 --> output1
end
node6
input5(in5) --> node6
input6(in6) --> node6
input7(in7) --> node6
input8(in8) --> node6
input9(in9) --> node6
output1 --> node6
style input1 fill:#1b1,color:#fff
style input2 fill:#555,color:#fff
style input3 fill:#555,color:#fff
style input4 fill:#555,color:#fff
style input5 fill:#1b1,color:#fff
style input6 fill:#1b1,color:#fff
style input7 fill:#1b1,color:#fff
style input8 fill:#1b1,color:#fff
style input9 fill:#1b1,color:#fff
```
A second option is to reduce this by not exposing inputs on these internal nodes. For the above example only in5-in9 and in1 are bindable.
If a definition was created from this graph then by default none of in1-in9 would be bindable. Any interfaces were added then they would be bindable.
### 4.1 Possible Extensions
The reasoning for this first set of options is that the author has intentionally specified / created what is accessible to a user so code generation should not expose any other inputs:
* Only expose inputs which are explicitly definition on a node instance. This is a variation on reduction such that both top level nodes and graph inputs are considered.
For instance, the example "Jade" shader only sets this inputs. All others would not be exposed / made bindable.
```xml
```
* Only expose inputs which set non-default values.
In this example, no inputs would be bindable
```xml
```
* Only expose inputs which are set to be visible in the ui ("ui visible").
Note that this is defined on the definition and not per instance.
For example, "default" is not bindable.
```xml
```
* Only expose inputs which are no "advanced" in the ui. Note that this is defined on the definition and not per instance.
* Allow for custom meta-data tagging on inputs. TBD if this is desirable and what this might look like.
Additional variations include:
* Expose no inputs. This results in an "immutable shader" and is useful for read-only deployments such as viewers. This is roughly equivalent to
creating a definition and exposing no inputs.
Reconfiguring the example in 3.1, this graph would have no bindable inputs:
```mermaid
graph LR
subgraph myNode[Node Definition]
m_output(Output Alpha)
m_output2(Output Color)
subgraph myNodeGraph[Functioal Graph Implementation]
node1-->node2
node2-->node3
node4-->node3
node5
node4-->node5
node3-->output(Output Alpha)
node5-->output2(Output Color)
end
end
style output fill:#0bb,color:#FFF
style output2 fill:#0bb,color:#FFF
style m_output fill:#0bb,color:#FFF
style m_output2 fill:#0bb,color:#FFF
```
* Handle uniform blocks versus just individual uniforms. This could include allow for custom (named) uniform block creation.
### 4.2 Code Generation Caveats
* For each optimization a different shader may be created.
* This can cause an increase in the number of unique shaders. If a unique shader library is being kept then the input signature of the shader must be considered in addition to the MaterialX graph input signature.
* This runs counter to keeping less shaders (uber shaders) which can have a fixed set of inputs to handle shader variants.
# 5. Code Branch Optimization
Conditional node inputs are tested and only a single branch is emitted.
These is however no general detection that an arbitrary input value would result in a particular graph or code branch to have no effect. (e.g. multiplication of a result by 0).
This could be an additional option for value checking. For example if `specular` is 0, then all code for specular computation need not be emitted.
Again this has the caveat that code generation would need to be performed again when such a value no longer results in a "no-op".
Contributor guide
Research direction
The issue is a draft design document and names no files, tests, or entry points. Start by resolving which shader-generation optimization is in scope, then identify the affected MaterialX shader/code-generator entry point and agree on observable bindable-input or branch-output behavior; done requires a decided, testable scope.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- computer-graphics
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 15/100