A question on how much shadergraph optimizes unused code

Two similar questions:

First, let’s say I have some nodes in a graph that aren’t actually plugged into the Master output node. Do those nodes end up having any impact on the performance cost of the shader? Or are they ignored if they’re not connected to the output node?

Second, let’s say I have a subgraph like this:

If I end up using only one component of the output of this subgraph (that is, if I only use the “x” component of this subgraph in my shader), does shadergraph still compute the y and z components, even though they aren’t used? Or does shadergraph need to perform the “combine” node in entirety before passing the full Vector3 to the output node? I’m trying to decide how general or specific my subgraphs should be. The more general, the more reusable, but that might not be worth it if it’s computing a bunch of stuff it doesn’t need.

If nodes are not connected to the output of the master node, they aren’t compiled into the final shader at all. They only live inside of the graph window, but not the shader in the scene. That being said, for the most part, all nodes are calculated even if only one of their output ports are connected. The only exception to this would be nodes with parameters (drop down menus, etc) inside of the node. Only the selected drop down option gets compiled.

Specifically your question about the combine node, yes, all of the components are being calculated even you’re only using the X or Y etc.

5 Likes

This will increase compile times, but generally not increase the cost of the shader vs. a node with only one output that does only the work required to produce that value.* That’s because shader compilers are generally smart about removing unused code.

There’s a big asterisk there because it’s possible that “one output” could be calculated another way that would produce the same results more cheaply. Shader compilers generally won’t fix that.

2 Likes

is there a way to see the cost of each node? or the overall cost of the shader in number vertex and pixel instructions and texture reads? this used to visible in compiled shaders in unit 4 and 5, but I can’t find any performance info in shadergraph, or by exporting the compiled shader and searching in the code.

Nope.

Not in the UI, no.

Still exists for Unity 2019 and 2020, assuming you’re compiling to a platform that shows that data.

If by “exporting” you mean right click on a node in the Shader Graph and click on “Show Generated Code”, then no. That’s the uncompiled shader that the Shader Graph generates. That can be pasted into a .shader file and it’d work like any “regular” vertex fragment shader, because that’s what it is. If you want to see the compiled shader, which shows the stats, you can copy the generated shader code into a .shader file and click on the “Compile and show code” button in the inspector for that … or just select your Shader Graph asset in the project view and click on the same inspector button. It exists for Shader Graph shaders and .shader vertex fragment shaders alike.

1 Like

Thanks much !
I have tried right clicking, and pasting into a new shader file, then clicking compile and show on that shader, I also tried adding #pragma debug into that shader… but I don’t see anything that looks like the output it used to show…
for example…a simple list of… Vertex shader instructions :20 texture reads:3. etc…
I am currently on a mac, in build target PC, Mac and standalone… maybe I should switch to iOS and try that ? or maybe the data is there, but described in a different way?
thanks again !
Possibly it just lists things differently since changing to hlsl.

I tried build target as pc/mac and iOS… but the compiled output looks the same.

They changed to HLSL over 5 years ago and deleted everything actually Cg based shortly afterward, they just didn’t bother renaming all of the files that ended in “.cginc” to “.hlsl” or change CGPROGRAM to HLSLPROGRAM until the SRPs. You could of done that 5 years ago though and it would have worked.

What you’re describing sounds to me like the old OpenGL compiled shader output. I’m guessing you’re now seeing the Metal output, which is what Unity now defaults to on the Mac. But I honestly have no idea because I’m not a MacOS dev and I only recently even found out that compiling shaders for OpenGL on Macs shows similar stat values as Direct3D does on Windows. There’s no such stats for OpenGL on Windows.

1 Like

thanks for the info bgolus

I have an additional question on the matter : let’s say I would like to have to make a modular shader where I use booleans to choose whether I want to use a detail map, whether I want to height blend some vertex painting etc.

Is there a way to set up the graph so that if the boolean is false in the material, part of the graph is excluded from the code, to optimize it ? Or is that just not how shaders work ? Because I can see how I could use the booleans node and a Lerp to disable features, but it would still take the whole graph into account.

On a related matter : is it heavier to to use the channel of a map that’s used ? What I mean is let’s say I have a detail map in the alpha channel of my albedo, would a shader that doesn’t use it be faster, or does the renderer have to load every channel, even unused ?

I’m very much a beginner and have a lot to learn, thanks a lot !

You can use keywords for this. Add keywords in the blackboard and set them to ‘shader feature’. This will result in ‘shader variants’ though and so increased compile times. There is also a limit of 128 variants but you can increase this in the shader graph preferences.

Does it still compute everything before the boolean keyword in this case?

No. Keywords generate completely different versions of the shader internally with only that code which is on the active side of the Keyword Node.