Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ShaderParameterUpdater.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 using System.Text;
7 using SiliconStudio.Core.Collections;
8 using SiliconStudio.Paradox.Effects;
9 
10 namespace SiliconStudio.Paradox.Graphics.Internals
11 {
13  {
14  public int Destination;
15  public int[] Sources;
17  //public ParameterCollection.InternalValueReference[] Parameters;
18  }
19 
21  {
25 
26  public override string ToString()
27  {
28  var builder = new StringBuilder();
29  builder
30  .Append("(")
31  .Append(Destination.Name)
32  .Append(")");
33 
34  foreach (var source in Sources)
35  {
36  builder
37  .Append(" ")
38  .Append(source.Name);
39  }
40 
41  return builder.ToString();
42  }
43  }
44 
45  struct UpdaterKey
46  {
47  public ParameterKey Key;
48  public bool IsDynamic;
49  }
50 
51  class ShaderParameterUpdaterDefinition : ParameterUpdaterDefinition
52  {
53  internal ParameterDependencyIndex[] Dependencies;
54  internal ParameterCollection.InternalValue[][] ThreadLocalDynamicValues;
55 
57  {
58  SortedKeys = keys.OrderBy(x => x.HashCode).ToArray();
59  SortedKeyHashes = SortedKeys.Select(x => x.HashCode).ToArray();
60 
61  // Sort dependencies
62  dependencies = BuildDependencies(dependencies).ToArray();
63 
64  // Build dependencies (with indices instead of keys)
65  var dependenciesIndex = new List<ParameterDependencyIndex>();
66  foreach (var dependency in dependencies)
67  {
68  var destinationIndex = Array.IndexOf(SortedKeys, dependency.Destination);
69  if (destinationIndex == -1)
70  throw new InvalidOperationException();
71  var sourceIndices = dependency.Sources.Select(x => Array.IndexOf(SortedKeys, x)).ToArray();
72  if (sourceIndices.Any(x => x == -1))
73  throw new InvalidOperationException();
74  dependenciesIndex.Add(new ParameterDependencyIndex
75  {
76  Destination = destinationIndex,
77  Sources = sourceIndices,
78  Dynamic = dependency.Dynamic,
79  //Parameters = new ParameterCollection.InternalValueReference[dependency.Sources.Length],
80  });
81  }
82 
83  this.Dependencies = dependenciesIndex.ToArray();
84 
85  ThreadLocalDynamicValues = new ParameterCollection.InternalValue[GraphicsDevice.ThreadCount][];
86  for (int i = 0; i < ThreadLocalDynamicValues.Length; ++i)
87  {
88  ThreadLocalDynamicValues[i] = Dependencies.Select(x => ParameterCollection.CreateInternalValue(SortedKeys[x.Destination])).ToArray();
89  }
90  }
91 
92  /// <summary>
93  /// Builds list of dynamic dependencies.
94  /// </summary>
95  private static void VisitDependencies(Dictionary<ParameterDependency, List<ParameterDependency>> graph, HashSet<ParameterDependency> processedVertices, List<ParameterDependency> result, ParameterDependency vertex)
96  {
97  if (!processedVertices.Contains(vertex))
98  {
99  processedVertices.Add(vertex);
100  List<ParameterDependency> outEdges;
101  if (graph.TryGetValue(vertex, out outEdges))
102  {
103  foreach (var outVertex in outEdges)
104  {
105  VisitDependencies(graph, processedVertices, result, outVertex);
106  }
107  }
108 
109  // Complexity is not so good, but should be sufficient for small n.
110  if (!result.Contains(vertex))
111  result.Add(vertex);
112  }
113  }
114 
115  /// <summary>
116  /// Builds dependency graph and generates update ordering.
117  /// </summary>
118  /// <param name="edges"></param>
119  /// <param name="start"></param>
120  /// <returns></returns>
121  private static IEnumerable<ParameterDependency> BuildDependencies(IEnumerable<ParameterDependency> dependencies)
122  {
123  var processedVertices = new HashSet<ParameterDependency>();
124  var result = new List<ParameterDependency>();
125  var keyToDependencies = new Dictionary<ParameterKey, ParameterDependency>();
126  foreach (var dependency in dependencies)
127  {
128  keyToDependencies[dependency.Destination] = dependency;
129  }
130 
131  var graph = new Dictionary<ParameterDependency, List<ParameterDependency>>();
132  foreach (var dependency in dependencies)
133  {
134  foreach (var sourceKey in dependency.Sources)
135  {
136  ParameterDependency source;
137  if (!keyToDependencies.TryGetValue(sourceKey, out source))
138  continue;
139 
140  List<ParameterDependency> outEdges;
141  if (!graph.TryGetValue(dependency, out outEdges))
142  {
143  graph[dependency] = outEdges = new List<ParameterDependency>();
144  }
145  outEdges.Add(source);
146  }
147  }
148 
149  foreach (var dependency in dependencies)
150  {
151  VisitDependencies(graph, processedVertices, result, dependency);
152  }
153 
154  return result;
155  }
156  }
157 
158  struct FastListStruct<T>
159  {
160  public int Count;
161  public T[] Items;
162 
163  public FastListStruct(FastList<T> fastList)
164  {
165  Count = fastList.Count;
166  Items = fastList.Items;
167  }
168 
169  public FastListStruct(T[] array)
170  {
171  Count = array.Length;
172  Items = array;
173  }
174 
175  public static implicit operator FastListStruct<T>(FastList<T> fastList)
176  {
177  return new FastListStruct<T>(fastList);
178  }
179 
180  public static implicit operator FastListStruct<T>(T[] array)
181  {
182  return new FastListStruct<T>(array);
183  }
184  }
185 
186  /// <summary>
187  /// Updates ParameterCollection for rendering, including dynamic parameters.
188  /// </summary>
189  internal class ShaderParameterUpdater : ParameterUpdater
190  {
191  internal int InternalValueBinarySearch(int[] values, int keyHash)
192  {
193  int start = 0;
194  int end = values.Length - 1;
195  while (start <= end)
196  {
197  int middle = start + ((end - start) >> 1);
198  var hash1 = values[middle];
199  var hash2 = keyHash;
200 
201  if (hash1 == hash2)
202  {
203  return middle;
204  }
205  if (hash1 < hash2)
206  {
207  start = middle + 1;
208  }
209  else
210  {
211  end = middle - 1;
212  }
213  }
214  return ~start;
215  }
216 
217  public void Update(GraphicsDevice graphicsDevice, ShaderParameterUpdaterDefinition definition, ParameterCollection[] parameterCollections, int levelCount)
218  {
219  Update(definition, parameterCollections, levelCount);
220 
221  // ----------------------------------------------------------------
222  // Update dynamic values
223  // Definitions based on Default+Pass lists
224  // ----------------------------------------------------------------
225  var dependencies = definition.Dependencies;
226  for (int dependencyIndex = 0; dependencyIndex < dependencies.Length; ++dependencyIndex)
227  {
228  var dependency = dependencies[dependencyIndex];
229  int highestLevel = 0;
230  int destinationLevel = InternalValues[dependency.Destination].Key;
231 
232  var destination = InternalValues[dependency.Destination];
233  bool needUpdate = false;
234  for (int i = 0; i < dependency.Sources.Length; ++i)
235  {
236  var source = InternalValues[dependency.Sources[i]];
237  var sourceLevel = source.Key;
238 
239  if (highestLevel < sourceLevel)
240  highestLevel = sourceLevel;
241  }
242 
243  if (destinationLevel < highestLevel)
244  {
245  // Dynamic value: the sources of this dynamic value are defined in a most derived collection than its destination collection
246  // as a result, we need to create or use a new dynamic value at the appropriate level.
247 
248  // Find last collection index (excluding parameterOverrides)
249  int maxLevelNoOverride = levelCount - 1;
250  if (highestLevel <= maxLevelNoOverride)
251  {
252  // TODO: Choose target level more properly (i.e. mesh*pass => meshpass)
253  // Sources all comes from normal collections => override in the most derived collection
254  // For now, use maxLevelNoOverride instead of highestLevel just to be safe.
255  var bestCollectionForDynamicValue = parameterCollections[maxLevelNoOverride];
256  var key = definition.SortedKeys[dependency.Destination];
257  bestCollectionForDynamicValue.SetDefault(key, true);
258  InternalValues[dependency.Destination] = destination = new KeyValuePair<int, ParameterCollection.InternalValue>(highestLevel, bestCollectionForDynamicValue.GetInternalValue(key));
259  }
260  else
261  {
262  // At least one source comes from TLS override, so use dynamic from TLS dynamic storage as well.
263  InternalValues[dependency.Destination] = destination = new KeyValuePair<int, ParameterCollection.InternalValue>(parameterCollections.Length, definition.ThreadLocalDynamicValues[graphicsDevice.ThreadIndex][dependencyIndex]);
264  }
265 
266  needUpdate = true;
267  }
268 
269  // Force updating (even if no parameters has been updated)
270  if (!dependency.Dynamic.AutoCheckDependencies)
271  needUpdate = true;
272 
273  if (destination.Value.Dependencies == null || destination.Value.Dependencies.Length < dependency.Sources.Length)
274  destination.Value.Dependencies = new ParameterCollection.InternalValueReference[dependency.Sources.Length];
275 
276  var dependencyParameters = destination.Value.Dependencies;
277  for (int i = 0; i < dependency.Sources.Length; ++i)
278  {
279  var source = InternalValues[dependency.Sources[i]];
280  var internalValue = source.Value;
281 
282  if (dependencyParameters[i].Entry != internalValue)
283  {
284  needUpdate = true;
285  dependencyParameters[i].Entry = internalValue;
286  dependencyParameters[i].Counter = internalValue.Counter;
287  }
288  else if (dependencyParameters[i].Counter != internalValue.Counter)
289  {
290  needUpdate = true;
291  dependencyParameters[i].Counter = internalValue.Counter;
292  }
293  }
294 
295  if (needUpdate)
296  {
297  // At least one source was updated
298  dependency.Dynamic.GetValue(destination.Value);
299  destination.Value.Counter++;
300  }
301  }
302  }
303 
304  internal ParameterCollection.InternalValue GetInternalValue(int index)
305  {
306  return InternalValues[index].Value;
307  }
308 
309  public T GetValue<T>(int index)
310  {
311  return ((ParameterCollection.InternalValueBase<T>)InternalValues[index].Value).Value;
312  }
313  }
314 }
A resource that is accessible by both the GPU (read only) and the CPU (write only). A dynamic resource is a good choice for a resource that will be updated by the CPU at least once per frame. To update a dynamic resource, use a Map method.
Key of an effect parameter.
Definition: ParameterKey.cs:15
Similar to List{T}, with direct access to underlying array.
Definition: FastList.cs:19
Base class for ParameterDynamicValue{T}.
ShaderParameterUpdaterDefinition(IEnumerable< ParameterKey > keys, IEnumerable< ParameterDependency > dependencies)
A container to handle a hierarchical collection of effect variables.