A game about forced loneliness, made by TACStudios
at master 8.5 kB view raw
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using UnityEditor.Graphing; 5using UnityEditor.Graphing.Util; 6using UnityEditor.Rendering; 7using UnityEditor.ShaderGraph.Drawing; 8using UnityEditor.ShaderGraph.Internal; 9using UnityEngine; 10using UnityEngine.Rendering; 11using UnityEngine.UIElements; 12 13namespace UnityEditor.ShaderGraph 14{ 15 // TODO: rename this file to VirtualTexturingFeedbackUtils 16 static class VirtualTexturingFeedbackUtils 17 { 18 // TODO: could get rid of this if we could run a codegen prepass (with proper keyword #ifdef) 19 public static void GenerateVirtualTextureFeedback( 20 List<AbstractMaterialNode> downstreamNodesIncludingRoot, 21 List<int>[] keywordPermutationsPerNode, 22 ShaderStringBuilder surfaceDescriptionFunction, 23 KeywordCollector shaderKeywords) 24 { 25 // A note on how we handle vt feedback in combination with keywords: 26 // We essentially generate a fully separate feedback path for each permutation of keywords 27 // so per permutation we gather variables contribution to feedback and we generate 28 // feedback gathering for each permutation individually. 29 30 var feedbackVariablesPerPermutation = PooledList<PooledList<string>>.Get(); 31 try 32 { 33 if (shaderKeywords.permutations.Count >= 1) 34 { 35 for (int i = 0; i < shaderKeywords.permutations.Count; i++) 36 { 37 feedbackVariablesPerPermutation.Add(PooledList<string>.Get()); 38 } 39 } 40 else 41 { 42 // Create a dummy single permutation 43 feedbackVariablesPerPermutation.Add(PooledList<string>.Get()); 44 } 45 46 int index = 0; //for keywordPermutationsPerNode 47 foreach (var node in downstreamNodesIncludingRoot) 48 { 49 if (node is SampleVirtualTextureNode vtNode) 50 { 51 if (vtNode.noFeedback) continue; 52 if (keywordPermutationsPerNode[index] == null) 53 { 54 Debug.Assert(shaderKeywords.permutations.Count == 0, $"Shader has {shaderKeywords.permutations.Count} permutations but keywordPermutationsPerNode of some nodes are null."); 55 feedbackVariablesPerPermutation[0].Add(vtNode.GetFeedbackVariableName()); 56 } 57 else 58 { 59 foreach (int perm in keywordPermutationsPerNode[index]) 60 { 61 feedbackVariablesPerPermutation[perm].Add(vtNode.GetFeedbackVariableName()); 62 } 63 } 64 } 65 66 if (node is SubGraphNode sgNode) 67 { 68 if (sgNode.asset == null) continue; 69 if (keywordPermutationsPerNode[index] == null) 70 { 71 Debug.Assert(shaderKeywords.permutations.Count == 0, $"Shader has {shaderKeywords.permutations.Count} permutations but keywordPermutationsPerNode of some nodes are null."); 72 foreach (var feedbackSlot in sgNode.asset.vtFeedbackVariables) 73 { 74 feedbackVariablesPerPermutation[0].Add(node.GetVariableNameForNode() + "_" + feedbackSlot); 75 } 76 } 77 else 78 { 79 foreach (var feedbackSlot in sgNode.asset.vtFeedbackVariables) 80 { 81 foreach (int perm in keywordPermutationsPerNode[index]) 82 { 83 feedbackVariablesPerPermutation[perm].Add(node.GetVariableNameForNode() + "_" + feedbackSlot); 84 } 85 } 86 } 87 } 88 89 index++; 90 } 91 92 index = 0; 93 foreach (var feedbackVariables in feedbackVariablesPerPermutation) 94 { 95 // If it's a dummy single always-on permutation don't put an ifdef around the code 96 if (shaderKeywords.permutations.Count >= 1) 97 { 98 surfaceDescriptionFunction.AppendLine(KeywordUtil.GetKeywordPermutationConditional(index)); 99 } 100 101 using (surfaceDescriptionFunction.BlockScope()) 102 { 103 if (feedbackVariables.Count == 0) 104 { 105 string feedBackCode = "surface.VTPackedFeedback = float4(1.0f,1.0f,1.0f,1.0f);"; 106 surfaceDescriptionFunction.AppendLine(feedBackCode); 107 } 108 else if (feedbackVariables.Count == 1) 109 { 110 string feedBackCode = "surface.VTPackedFeedback = GetPackedVTFeedback(" + feedbackVariables[0] + ");"; 111 surfaceDescriptionFunction.AppendLine(feedBackCode); 112 } 113 else if (feedbackVariables.Count > 1) 114 { 115 surfaceDescriptionFunction.AppendLine("float4 VTFeedback_array[" + feedbackVariables.Count + "];"); 116 117 int arrayIndex = 0; 118 foreach (var variable in feedbackVariables) 119 { 120 surfaceDescriptionFunction.AppendLine("VTFeedback_array[" + arrayIndex + "] = " + variable + ";"); 121 arrayIndex++; 122 } 123 124 // TODO: should read from NDCPosition instead... 125 surfaceDescriptionFunction.AppendLine("uint pixelColumn = (IN.ScreenPosition.x / IN.ScreenPosition.w) * _ScreenParams.x;"); 126 surfaceDescriptionFunction.AppendLine( 127 "surface.VTPackedFeedback = GetPackedVTFeedback(VTFeedback_array[(pixelColumn + _FrameCount) % (uint)" + feedbackVariables.Count + "]);"); 128 } 129 } 130 131 if (shaderKeywords.permutations.Count >= 1) 132 { 133 surfaceDescriptionFunction.AppendLine("#endif"); 134 } 135 136 index++; 137 } 138 } 139 finally 140 { 141 foreach (var list in feedbackVariablesPerPermutation) 142 { 143 list.Dispose(); 144 } 145 feedbackVariablesPerPermutation.Dispose(); 146 } 147 } 148 149 // Automatically add a streaming feedback node and correctly connect it to stack samples are connected to it and it is connected to the master node output 150 public static List<string> GetFeedbackVariables(SubGraphOutputNode masterNode) 151 { 152 // TODO: make use a generic interface instead of hard-coding the node types that we need to look at here 153 var VTNodes = GraphUtil.FindDownStreamNodesOfType<SampleVirtualTextureNode>(masterNode); 154 var subGraphNodes = GraphUtil.FindDownStreamNodesOfType<SubGraphNode>(masterNode); 155 156 List<string> result = new List<string>(); 157 158 // Early out if there are no nodes we care about in the graph 159 if (subGraphNodes.Count <= 0 && VTNodes.Count <= 0) 160 { 161 return result; 162 } 163 164 // Add inputs to feedback node 165 foreach (var node in VTNodes) 166 { 167 if (node.noFeedback) continue; 168 result.Add(node.GetFeedbackVariableName()); 169 } 170 171 foreach (var node in subGraphNodes) 172 { 173 if (node.asset == null) continue; 174 // TODO: subgraph.GetFeedbackVariableNames(...) 175 foreach (var feedbackSlot in node.asset.vtFeedbackVariables) 176 { 177 result.Add(node.GetVariableNameForNode() + "_" + feedbackSlot); 178 } 179 } 180 181 return result; 182 } 183 } 184}