PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Graphics/Basics/Shader.cs

#
C# | 208 lines | 113 code | 21 blank | 74 comment | 21 complexity | 2f890bfa168e653cc0559071d7b56923 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using Delta.ContentSystem.Rendering;
  4. using Delta.Engine.Dynamic;
  5. using Delta.Utilities;
  6. using Delta.Utilities.Graphics.ShaderFeatures;
  7. namespace Delta.Graphics.Basics
  8. {
  9. /// <summary>
  10. /// Shader base class, defines all the public methods we can call from the
  11. /// outside, mostly done from the material class or some render classes.
  12. /// Most importantly each platform implements all the platform dependant
  13. /// render code (which can be both fixed function or shader based if the
  14. /// hardware supports it).
  15. /// <para />
  16. /// You can use this class to extend shader functionality for all platforms.
  17. /// If you just change OpenTKShader, your game will not be able to use that
  18. /// changes on any other graphic platform.
  19. /// <para />
  20. /// Note: Please check the wiki for help and ask in the forum on how to
  21. /// extend the Shader class and add more uniforms and features.
  22. /// </summary>
  23. public abstract class Shader : BaseShader
  24. {
  25. #region Create (Static)
  26. /// <summary>
  27. /// Create shader from the shader content name if that is known. Note that
  28. /// there is also a Create overload just from the shader feature flags.
  29. /// </summary>
  30. /// <param name="shaderName">Shader content name</param>
  31. /// <returns>Shader</returns>
  32. public static Shader Create(string shaderName)
  33. {
  34. if (String.IsNullOrEmpty(shaderName))
  35. {
  36. // Use the flags Create method instead!
  37. return Create(ShaderFeatureFlags.Basic);
  38. }
  39. if (shaderCache == null)
  40. {
  41. shaderCache = new Dictionary<string, Shader>(
  42. StringComparer.InvariantCultureIgnoreCase);
  43. shaderFlagsCache = new Dictionary<ShaderFeatureFlags, Shader>();
  44. // Make sure that every shader gets reloaded with the new internal
  45. // graphics device handle), every time that the device is reseted.
  46. Graphic.DeviceReset += shaderCache.Clear;
  47. Graphic.DeviceReset += shaderFlagsCache.Clear;
  48. }
  49. // Before we try to load the new shader, we look at first if we have it
  50. // already in the shader cache
  51. if (shaderCache.ContainsKey(shaderName))
  52. {
  53. // if we already have it, then just return the shader from the cache
  54. return shaderCache[shaderName];
  55. }
  56. // Else if we haven't it loaded yet, then do it now
  57. Shader loadedShader = Factory.Create<Shader>(shaderName);
  58. if (loadedShader == null)
  59. {
  60. Log.Warning("Graphic.CreateShader: The shader '" + shaderName +
  61. "' couldn't be loaded, the shader type was not found.");
  62. return null;
  63. }
  64. // Add it to the (global) shader cache
  65. if (shaderCache.ContainsKey(shaderName) == false)
  66. {
  67. shaderCache.Add(shaderName, loadedShader);
  68. if (shaderCache.Count > 75)
  69. {
  70. Log.Warning("The shader cache got bigger than 75 entries! " +
  71. "Please dispose some unused shaders (make sure to dispose " +
  72. "scenes as well to get rid of content).");
  73. }
  74. }
  75. // And make sure it exists in the shader flags cache as well
  76. if (shaderFlagsCache.ContainsKey(loadedShader.Flags) == false)
  77. {
  78. shaderFlagsCache.Add(loadedShader.Flags, loadedShader);
  79. if (shaderFlagsCache.Count > 75)
  80. {
  81. Log.Warning("The shader flags cache got bigger than 75 entries! " +
  82. "Please dispose some unused shaders (make sure to dispose " +
  83. "scenes as well to get rid of content).");
  84. }
  85. }
  86. // And return it finally
  87. return loadedShader;
  88. }
  89. #endregion
  90. #region Private
  91. #region shaderCache (Private)
  92. /// <summary>
  93. /// Global shader cache, makes sure that every shader is only loaded once.
  94. /// </summary>
  95. private static Dictionary<string, Shader> shaderCache;
  96. #endregion
  97. #region shaderFlagsCache (Private)
  98. /// <summary>
  99. /// Global shader flags cache, makes sure that every dynamically requested
  100. /// shader via shader flags is only loaded once.
  101. /// </summary>
  102. private static Dictionary<ShaderFeatureFlags, Shader> shaderFlagsCache;
  103. #endregion
  104. #endregion
  105. #region Constructors
  106. /// <summary>
  107. /// Creates a base shader, this constructor will grab the ShaderData and
  108. /// then setup the native shader objects (the graphics device needs to be
  109. /// up). When the device is lost or the window gets resized the matrices
  110. /// are updated, we reload everything and grab the shader parameters again.
  111. /// The Load method also checks if we are loading the same shader again
  112. /// and caches the results, so we never create two instances of the same
  113. /// shader! If we do a warning is outputted to prevent bad performance
  114. /// of using multiple shaders with the exact same internal data.
  115. /// </summary>
  116. /// <param name="setShaderName">Set shader name for loading the ShaderData
  117. /// from the content system, which is used to create the shader</param>
  118. protected Shader(string setShaderName)
  119. : base(ShaderData.Get(setShaderName))
  120. {
  121. }
  122. /// <summary>
  123. /// Create shader from shader flags instead of the content name.
  124. /// </summary>
  125. /// <param name="setShaderFlags">Shader flags to search for a shader
  126. /// content entry with this flags</param>
  127. protected Shader(ShaderFeatureFlags setShaderFlags)
  128. : base(ShaderData.Get(setShaderFlags))
  129. {
  130. }
  131. #endregion
  132. #region Methods (Private)
  133. #region Create
  134. /// <summary>
  135. /// Create shader dynamically from shader flags. Will just return the
  136. /// first shader we can find from the content system that uses those flags.
  137. /// For more control use the Create method with the shader content name!
  138. /// Note: Only allowed internally for fallback, normally in applications
  139. /// shaders are created by the MaterialData.ShaderName string value!
  140. /// </summary>
  141. /// <param name="shaderFlags">Shader flags combination</param>
  142. /// <returns>Shader we found that matches this flags</returns>
  143. internal static Shader Create(ShaderFeatureFlags shaderFlags)
  144. {
  145. if (shaderCache == null)
  146. {
  147. shaderCache = new Dictionary<string, Shader>(
  148. StringComparer.InvariantCultureIgnoreCase);
  149. shaderFlagsCache = new Dictionary<ShaderFeatureFlags, Shader>();
  150. // Make sure that every shader gets reloaded with the new internal
  151. // graphics device handle), every time that the device is reseted.
  152. //wrong: Graphic.DeviceReset += shaderCache.Clear;
  153. //wrong: Graphic.DeviceReset += shaderFlagsCache.Clear;
  154. }
  155. // Before we try to load the new shader, we look at first if we have it
  156. // already in the shader cache
  157. if (shaderFlagsCache.ContainsKey(shaderFlags))
  158. {
  159. // if we already have it, then just return the shader from the cache
  160. return shaderFlagsCache[shaderFlags];
  161. }
  162. // Else if we haven't it loaded yet, then do it now
  163. Shader loadedShader = Factory.Create<Shader>(shaderFlags);
  164. if (loadedShader == null)
  165. {
  166. Log.Warning("Shader.Create: The shader with the flags '" +
  167. shaderFlags + "' couldn't be loaded, it was not found.");
  168. return null;
  169. }
  170. // Add it the shader flags cache
  171. if (shaderFlagsCache.ContainsKey(shaderFlags) == false)
  172. {
  173. shaderFlagsCache.Add(shaderFlags, loadedShader);
  174. }
  175. // Add it to the global shader name cache as well
  176. string shaderKey = loadedShader.Name;
  177. if (shaderCache.ContainsKey(shaderKey) == false)
  178. {
  179. shaderCache.Add(shaderKey, loadedShader);
  180. }
  181. // And return it finally
  182. return loadedShader;
  183. }
  184. #endregion
  185. #endregion
  186. }
  187. }