Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ShaderSourceManager.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.Collections.Generic;
4 using System.IO;
5 using System.Net.Configuration;
6 using System.Text;
7 
8 using SiliconStudio.Core.IO;
9 using SiliconStudio.Core.Serialization.Assets;
10 using SiliconStudio.Core.Storage;
11 
12 namespace SiliconStudio.Paradox.Shaders.Parser.Mixins
13 {
14  /// <summary>
15  /// Class ShaderSourceManager
16  /// </summary>
17  public class ShaderSourceManager
18  {
19  private readonly object locker = new object();
20  private readonly Dictionary<string, ShaderSourceWithHash> loadedShaderSources = new Dictionary<string, ShaderSourceWithHash>();
21  private readonly Dictionary<string, string> classNameToPath = new Dictionary<string, string>();
22 
23  private const string DefaultEffectFileExtension = ".pdxsl";
24 
25  /// <summary>
26  /// Gets the directory list.
27  /// </summary>
28  /// <value>The directory list.</value>
29  public List<string> LookupDirectoryList { get; set; }
30 
31  /// <summary>
32  /// Gets or sets the URL mapping to file path.
33  /// </summary>
34  /// <value>The URL automatic file path.</value>
35  public Dictionary<string, string> UrlToFilePath { get; set; }
36 
37  /// <summary>
38  /// Initializes a new instance of the <see cref="ShaderSourceManager"/> class.
39  /// </summary>
41  {
42  LookupDirectoryList = new List<string>();
43  UrlToFilePath = new Dictionary<string, string>();
44  }
45 
46  /// <summary>
47  /// Deletes the shader cache for the specified shaders.
48  /// </summary>
49  /// <param name="modifiedShaders">The modified shaders.</param>
50  public void DeleteObsoleteCache(HashSet<string> modifiedShaders)
51  {
52  foreach (var shaderName in modifiedShaders)
53  {
54  loadedShaderSources.Remove(shaderName);
55  //classNameToPath.Remove(shaderName); // is it really useful?
56  }
57  }
58 
59  public ObjectId GetShaderSourceHash(string type)
60  {
61  return LoadShaderSource(type).Hash;
62  }
63 
64  /// <summary>
65  /// Loads the shader source with the specified type name.
66  /// </summary>
67  /// <param name="type">The typeName.</param>
68  /// <param name="modifiedShaders">The list of modified shaders.</param>
69  /// <returns>ShaderSourceWithHash.</returns>
70  /// <exception cref="System.IO.FileNotFoundException">If the file was not found</exception>
71  public ShaderSourceWithHash LoadShaderSource(string type, HashSet<string> modifiedShaders = null)
72  {
73  lock (locker)
74  {
75  // Load file
76  ShaderSourceWithHash shaderSource;
77  if (!loadedShaderSources.TryGetValue(type, out shaderSource))
78  {
79  var sourceUrl = FindFilePath(type);
80  if (sourceUrl != null)
81  {
82  shaderSource = new ShaderSourceWithHash();
83 
84  if (modifiedShaders != null && modifiedShaders.Contains(sourceUrl))
85  {
86  using (var fileStream = AssetManager.FileProvider.OpenStream(sourceUrl + "/path", VirtualFileMode.Open, VirtualFileAccess.Read, VirtualFileShare.Read))
87  {
88  string shaderSourcePath;
89  using (var sr = new StreamReader(fileStream, Encoding.UTF8))
90  shaderSourcePath = sr.ReadToEnd();
91 
92  try
93  {
94  using (var sourceStream = File.Open(shaderSourcePath, FileMode.Open, FileAccess.Read))
95  {
96  using (var sr = new StreamReader(sourceStream))
97  shaderSource.Source = sr.ReadToEnd();
98  }
99  }
100  catch (FileNotFoundException)
101  {
102  throw new FileNotFoundException(string.Format("Unable to find shader [{0}] on disk", type), string.Format("{0}.pdxsl", type));
103  }
104  }
105  }
106  else
107  {
108  using (var fileStream = AssetManager.FileProvider.OpenStream(sourceUrl, VirtualFileMode.Open, VirtualFileAccess.Read, VirtualFileShare.Read))
109  {
110  using (var sr = new StreamReader(fileStream))
111  shaderSource.Source = sr.ReadToEnd();
112 
113  var databaseStream = fileStream as IDatabaseStream;
114  if (databaseStream != null)
115  {
116  shaderSource.Hash = databaseStream.ObjectId;
117  }
118  }
119  }
120 
121  // If the file was loaded from the database, use the ObjectId returned by the database, otherwise compute it directly
122  if (shaderSource.Hash == ObjectId.Empty)
123  {
124  shaderSource.Hash = ObjectId.FromBytes(Encoding.UTF8.GetBytes(shaderSource.Source));
125  }
126 
127  // Convert URL to absolute file path
128  // TODO can we handle path differently? Current code is just a hack
129  UrlToFilePath.TryGetValue(sourceUrl, out shaderSource.Path);
130 
131  // If Path is null, set it to type at least to be able to have more information
132  if (shaderSource.Path == null)
133  {
134  shaderSource.Path = type;
135  }
136  loadedShaderSources[type] = shaderSource;
137  }
138  else
139  {
140  throw new FileNotFoundException(string.Format("Unable to find shader [{0}]", type), string.Format("{0}.pdxsl", type));
141  }
142  }
143  return shaderSource;
144  }
145  }
146 
147  /// <summary>
148  /// Determines whether a class with the specified type name exists.
149  /// </summary>
150  /// <param name="typeName">The typeName.</param>
151  /// <returns><c>true</c> if a class with the specified type name exists; otherwise, <c>false</c>.</returns>
152  public bool IsClassExists(string typeName)
153  {
154  return FindFilePath(typeName) != null;
155  }
156 
157  public string FindFilePath(string type)
158  {
159  lock (locker)
160  {
161  if (LookupDirectoryList == null)
162  return null;
163 
164  string path;
165  if (classNameToPath.TryGetValue(type, out path))
166  return path;
167 
168  foreach (var directory in LookupDirectoryList)
169  {
170  var fileName = Path.ChangeExtension(type, DefaultEffectFileExtension);
171  var testPath = string.IsNullOrEmpty(directory) || directory == "/" || directory == "\\" ? string.Format("/{0}", fileName) : string.Format("{0}/{1}", directory.TrimEnd('/'), fileName);
172  if (AssetManager.FileProvider.FileExists(testPath))
173  {
174  path = testPath;
175  break;
176  }
177  }
178 
179  classNameToPath.Add(type, path);
180 
181  return path;
182  }
183  }
184 
185  public struct ShaderSourceWithHash
186  {
187  public string Path;
188  public string Source;
189  public ObjectId Hash;
190  }
191  }
192 }
System.Text.Encoding Encoding
override bool FileExists(string url)
Determines whether the specified path points to an existing file. The path.
void DeleteObsoleteCache(HashSet< string > modifiedShaders)
Deletes the shader cache for the specified shaders.
static readonly ObjectId Empty
Definition: ObjectId.cs:15
A hash to uniquely identify data.
Definition: ObjectId.cs:13
ShaderSourceWithHash LoadShaderSource(string type, HashSet< string > modifiedShaders=null)
Loads the shader source with the specified type name.
ShaderSourceManager()
Initializes a new instance of the ShaderSourceManager class.
bool IsClassExists(string typeName)
Determines whether a class with the specified type name exists.