OGLShader.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2012 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Context.h"
  25. #include "Deserializer.h"
  26. #include "FileSystem.h"
  27. #include "Graphics.h"
  28. #include "Log.h"
  29. #include "Profiler.h"
  30. #include "ResourceCache.h"
  31. #include "Shader.h"
  32. #include "ShaderParser.h"
  33. #include "ShaderVariation.h"
  34. #include "XMLFile.h"
  35. #include "DebugNew.h"
  36. OBJECTTYPESTATIC(Shader);
  37. Shader::Shader(Context* context) :
  38. Resource(context),
  39. vsSourceCodeLength_(0),
  40. psSourceCodeLength_(0)
  41. {
  42. }
  43. Shader::~Shader()
  44. {
  45. }
  46. void Shader::RegisterObject(Context* context)
  47. {
  48. context->RegisterFactory<Shader>();
  49. }
  50. bool Shader::Load(Deserializer& source)
  51. {
  52. PROFILE(LoadShader);
  53. Graphics* graphics = GetSubsystem<Graphics>();
  54. if (!graphics)
  55. return false;
  56. unsigned memoryUse = sizeof(Shader);
  57. vsSourceCodeLength_ = 0;
  58. psSourceCodeLength_ = 0;
  59. SharedPtr<XMLFile> xml(new XMLFile(context_));
  60. if (!xml->Load(source))
  61. return false;
  62. ShaderParser vsParser;
  63. ShaderParser psParser;
  64. Vector<String> globalDefines;
  65. Vector<String> globalDefineValues;
  66. if (!vsParser.Parse(VS, xml->GetRoot("shaders"), globalDefines, globalDefineValues))
  67. {
  68. LOGERROR("VS: " + vsParser.GetErrorMessage());
  69. return false;
  70. }
  71. if (!psParser.Parse(PS, xml->GetRoot("shaders"), globalDefines, globalDefineValues))
  72. {
  73. LOGERROR("PS: " + psParser.GetErrorMessage());
  74. return false;
  75. }
  76. String path, fileName, extension;
  77. SplitPath(GetName(), path, fileName, extension);
  78. if (!ProcessSource(vsSourceCode_, vsSourceCodeLength_, path + fileName + ".vert"))
  79. return false;
  80. if (!ProcessSource(psSourceCode_, psSourceCodeLength_, path + fileName + ".frag"))
  81. return false;
  82. const Vector<ShaderCombination>& vsCombinations = vsParser.GetCombinations();
  83. for (Vector<ShaderCombination>::ConstIterator i = vsCombinations.Begin(); i != vsCombinations.End(); ++i)
  84. {
  85. StringHash nameHash(i->name_);
  86. HashMap<StringHash, SharedPtr<ShaderVariation> >::Iterator j = vsVariations_.Find(nameHash);
  87. if (j == vsVariations_.End())
  88. j = vsVariations_.Insert(MakePair(nameHash, SharedPtr<ShaderVariation>(new ShaderVariation(this, VS))));
  89. else
  90. {
  91. // If shader variation already exists, release
  92. j->second_->Release();
  93. }
  94. String shaderName = path + fileName + "_" + i->name_;
  95. if (shaderName.EndsWith("_"))
  96. shaderName.Resize(shaderName.Length() - 1);
  97. j->second_->SetName(shaderName);
  98. j->second_->SetSourceCode(vsSourceCode_, vsSourceCodeLength_);
  99. j->second_->SetDefines(i->defines_, i->defineValues_);
  100. }
  101. const Vector<ShaderCombination>& psCombinations = psParser.GetCombinations();
  102. for (Vector<ShaderCombination>::ConstIterator i = psCombinations.Begin(); i != psCombinations.End(); ++i)
  103. {
  104. StringHash nameHash(i->name_);
  105. HashMap<StringHash, SharedPtr<ShaderVariation> >::Iterator j = psVariations_.Find(nameHash);
  106. if (j == psVariations_.End())
  107. j = psVariations_.Insert(MakePair(nameHash, SharedPtr<ShaderVariation>(new ShaderVariation(this, PS))));
  108. else
  109. {
  110. // If shader variation already exists, release
  111. j->second_->Release();
  112. }
  113. String shaderName = path + fileName + "_" + i->name_;
  114. if (shaderName.EndsWith("_"))
  115. shaderName.Resize(shaderName.Length() - 1);
  116. j->second_->SetName(shaderName);
  117. j->second_->SetSourceCode(psSourceCode_, psSourceCodeLength_);
  118. j->second_->SetDefines(i->defines_, i->defineValues_);
  119. }
  120. memoryUse += (vsVariations_.Size() + psVariations_.Size()) * sizeof(ShaderVariation);
  121. memoryUse += vsSourceCodeLength_;
  122. memoryUse += psSourceCodeLength_;
  123. SetMemoryUse(memoryUse);
  124. return true;
  125. }
  126. ShaderVariation* Shader::GetVariation(ShaderType type, const String& name)
  127. {
  128. StringHash nameHash(name);
  129. if (type == VS)
  130. {
  131. HashMap<StringHash, SharedPtr<ShaderVariation> >::Iterator i = vsVariations_.Find(nameHash);
  132. if (i != vsVariations_.End())
  133. return i->second_;
  134. else
  135. return 0;
  136. }
  137. else
  138. {
  139. HashMap<StringHash, SharedPtr<ShaderVariation> >::Iterator i = psVariations_.Find(nameHash);
  140. if (i != psVariations_.End())
  141. return i->second_;
  142. else
  143. return 0;
  144. }
  145. }
  146. bool Shader::ProcessSource(SharedArrayPtr<char>& dest, unsigned& length, const String& fileName)
  147. {
  148. ResourceCache* cache = GetSubsystem<ResourceCache>();
  149. if (!cache)
  150. return false;
  151. Vector<String> glslCode;
  152. // Load the shader source code
  153. SharedPtr<File> glslFile = cache->GetFile(fileName);
  154. if (!glslFile)
  155. return false;
  156. while (!glslFile->IsEof())
  157. glslCode.Push(glslFile->ReadLine());
  158. // Process the code for includes
  159. for (unsigned i = 0; i < glslCode.Size(); ++i)
  160. {
  161. if (glslCode[i].StartsWith("#include"))
  162. {
  163. String includeFileName = GetPath(fileName) + glslCode[i].Substring(9).Replaced("\"", "").Trimmed();
  164. SharedPtr<File> glslIncludeFile = cache->GetFile(includeFileName);
  165. if (!glslIncludeFile)
  166. return false;
  167. // Remove the #include line, then include the code
  168. glslCode.Erase(i);
  169. unsigned pos = i;
  170. while (!glslIncludeFile->IsEof())
  171. {
  172. glslCode.Insert(pos, glslIncludeFile->ReadLine());
  173. ++pos;
  174. }
  175. // Finally insert an empty line to mark the space between files
  176. glslCode.Insert(pos, "");
  177. }
  178. }
  179. // Copy the final code into one memory block
  180. length = 0;
  181. for (unsigned i = 0; i < glslCode.Size(); ++i)
  182. length += glslCode[i].Length() + 1;
  183. dest = new char[length];
  184. char* destPtr = dest.Get();
  185. for (unsigned i = 0; i < glslCode.Size(); ++i)
  186. {
  187. memcpy(destPtr, glslCode[i].CString(), glslCode[i].Length());
  188. destPtr += glslCode[i].Length();
  189. *destPtr++ = '\n';
  190. }
  191. return true;
  192. }