Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
PostEffectGraphPlugin.cs
Go to the documentation of this file.
1 using System.Collections.Generic;
2 using System.Linq;
3 
4 using SiliconStudio.Paradox.Graphics;
5 
6 using QuickGraph;
7 using QuickGraph.Algorithms;
8 
9 namespace SiliconStudio.Paradox.Effects
10 {
11  /// <summary>
12  /// Posteffect manager.
13  /// </summary>
15  {
16  BidirectionalGraph<EffectMesh, PostEffectEdge> graph = new BidirectionalGraph<EffectMesh, PostEffectEdge>();
17  private Dictionary<TextureDescription, List<RenderTarget>> textures = new Dictionary<TextureDescription, List<RenderTarget>>();
18 
19  public PostEffectGraphPlugin() : this(null)
20  {
21  }
22 
23  public PostEffectGraphPlugin(string name) : base(name)
24  {
25  }
26 
27  public IEnumerable<EffectMesh> Meshes
28  {
29  get
30  {
31  return graph.Vertices;
32  }
33  }
34 
35  public void AddMesh(EffectMesh mesh)
36  {
37  if (!graph.ContainsVertex(mesh))
38  graph.AddVertex(mesh);
39  }
40 
41  public void AddLink(EffectMesh source, ParameterKey<RenderTarget> sourceKey, EffectMesh target, ParameterKey<Texture> targetKey, RenderTarget texture)
42  {
43  if (!graph.ContainsVertex(source))
44  graph.AddVertex(source);
45 
46  if (!graph.ContainsVertex(target))
47  graph.AddVertex(target);
48 
49  graph.AddEdge(new PostEffectEdge(source, sourceKey, target, targetKey, texture));
50  }
51 
52  public void AddLink(EffectMesh source, ParameterKey<RenderTarget> sourceKey, EffectMesh target, ParameterKey<Texture> targetKey, TextureDescription? textureDescription = null)
53  {
54  if (!graph.ContainsVertex(source))
55  graph.AddVertex(source);
56 
57  if (!graph.ContainsVertex(target))
58  graph.AddVertex(target);
59 
60  graph.AddEdge(new PostEffectEdge(source, sourceKey, target, targetKey, textureDescription));
61  }
62 
63  /// <summary>
64  /// Resolve the dependency graph for the resources and create the necessary RenderTarget2D.
65  /// It will take care of reusing resources (if possible) and creating them if more are necessaries.
66  /// </summary>
67  public void Resolve()
68  {
69  var currentTextures = new Dictionary<RenderTarget, int>();
70 
71  // Topological sort in order to have nodes in their dependency order
72  foreach (var node in graph.TopologicalSort())
73  {
74  var inEdges = graph.InEdges(node);
75 
76  // Plug the effect pass into the render pass
77  node.EffectPass.RenderPass = RenderPass;
78 
79  // Group nodes by source key, because each (Source,SourceKey) will be a single output of the current node and
80  // will correspond to one shared resource.
81  foreach (var outEdges in graph.OutEdges(node).GroupBy(x => x.SourceKey))
82  {
83  // TODO: First, execute action stored in EffectMesh to compute required resource type
84 
85  // Otherwise, just try to instantiate a render target same size as first texture input.
86  var resource = outEdges.Where(x => x.ProvidedTexture != null).Select(x => x.ProvidedTexture).FirstOrDefault();
87 
88  if (resource == null)
89  {
90  TextureDescription? textureDescription = null;
91 
92  // 1/ First, try to check if user forced texture description
93  var forcedTextureDescriptions = outEdges.Where(x => x.TextureDescription != null).Select(x => x.TextureDescription);
94 
95  // TODO: Warning if more than one forcedTextureDescriptions
96  var forcedTextureDescription = forcedTextureDescriptions.FirstOrDefault();
97 
98  if (forcedTextureDescription != null)
99  {
100  textureDescription = forcedTextureDescription;
101  }
102 
103  // 2/ Otherwise, try to resolve using input textures
104  // TODO: More advanced logic (allowing use of customizable lambda functions)
105  if (textureDescription == null)
106  {
107  foreach (var inEdge in inEdges)
108  {
109  textureDescription = ((Texture) node.Parameters.GetObject(inEdge.TargetKey)).Description;
110  if (textureDescription != null) break;
111  }
112  }
113 
114  // 3/ Otherwise, default texture
115  if (textureDescription == null)
116  {
117  // If nothing found, try to create a default render target.
118  // TODO add parameters for Width, Height, Format
119  textureDescription = new TextureDescription {Width = 1024, Height = 768, Format = PixelFormat.R8G8B8A8_UNorm};
120  }
121 
122  // Either try to find a currently unused resources that matches this description
123  List<RenderTarget> matchingTextureList;
124  if (!textures.TryGetValue(textureDescription.Value, out matchingTextureList))
125  textures[textureDescription.Value] = matchingTextureList = new List<RenderTarget>();
126 
127  resource = matchingTextureList.FirstOrDefault(x => !currentTextures.ContainsKey(x));
128 
129  // If no available resource was found, create a new one.
130  if (resource == null)
131  {
132  resource = Texture2D.New(GraphicsDevice, textureDescription.Value).ToRenderTarget();
133  matchingTextureList.Add(resource);
134  }
135  }
136 
137  // Add the resource as output of current node
138  node.Parameters.SetObject(outEdges.Key, resource);
139 
140  foreach (var outEdge in outEdges)
141  {
142  // Add the resources as input of next nodes
143  outEdge.Target.Parameters.SetObject(outEdge.TargetKey, resource.Texture);
144  outEdge.Texture = resource;
145  }
146  if (!currentTextures.ContainsKey(resource))
147  currentTextures[resource] = outEdges.Count();
148  else
149  currentTextures[resource] += outEdges.Count();
150  }
151 
152  foreach (var inEdge in inEdges)
153  {
154  var resource = inEdge.Texture;
155  if (--currentTextures[resource] == 0)
156  currentTextures.Remove(resource);
157  }
158  }
159  }
160 
161  private class PostEffectEdge : IEdge<EffectMesh>
162  {
163  public PostEffectEdge(EffectMesh source, ParameterKey<RenderTarget> sourceKey, EffectMesh target, ParameterKey<Texture> targetKey, RenderTarget texture)
164  {
165  Source = source;
166  Target = target;
167  SourceKey = sourceKey;
168  TargetKey = targetKey;
169  ProvidedTexture = texture;
170  }
171 
172  public PostEffectEdge(EffectMesh source, ParameterKey<RenderTarget> sourceKey, EffectMesh target, ParameterKey<Texture> targetKey, TextureDescription? textureDescription = null)
173  {
174  Source = source;
175  Target = target;
176  SourceKey = sourceKey;
177  TargetKey = targetKey;
178  TextureDescription = textureDescription;
179  }
180 
181  public EffectMesh Source { get; private set; }
182 
183  public EffectMesh Target { get; private set; }
184 
185  public ParameterKey SourceKey { get; private set; }
186 
187  public ParameterKey TargetKey { get; private set; }
188 
189  public RenderTarget Texture { get; set; }
190 
191  public RenderTarget ProvidedTexture { get; set; }
192 
193  public TextureDescription? TextureDescription { get; set; }
194  }
195  }
196 }
void AddMesh(EffectMesh mesh)
Key of an effect parameter.
Definition: ParameterKey.cs:15
Performs primitive-based rendering, creates resources, handles system-level variables, adjusts gamma ramp levels, and creates shaders. See The+GraphicsDevice+class to learn more about the class.
A Common description for all textures.
void AddLink(EffectMesh source, ParameterKey< RenderTarget > sourceKey, EffectMesh target, ParameterKey< Texture > targetKey, RenderTarget texture)
PostEffectGraphPlugin()
void Resolve()
Resolve the dependency graph for the resources and create the necessary RenderTarget2D. It will take care of reusing resources (if possible) and creating them if more are necessaries.
PostEffectGraphPlugin(string name)
Posteffect manager.
RenderPass is a hierarchy that defines how to collect and render meshes.
Definition: RenderPass.cs:19
void AddLink(EffectMesh source, ParameterKey< RenderTarget > sourceKey, EffectMesh target, ParameterKey< Texture > targetKey, TextureDescription?textureDescription=null)
Base class for texture resources.
Definition: Texture.cs:38