OGLShaderVariation.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. #include "../../Precompiled.h"
  4. #include "../../Graphics/Graphics.h"
  5. #include "../../GraphicsAPI/GraphicsImpl.h"
  6. #include "../../GraphicsAPI/OpenGL/OGLShaderProgram.h"
  7. #include "../../GraphicsAPI/Shader.h"
  8. #include "../../GraphicsAPI/ShaderVariation.h"
  9. #include "../../IO/Log.h"
  10. #include "../../DebugNew.h"
  11. namespace Urho3D
  12. {
  13. const char* ShaderVariation::elementSemanticNames_OGL[] =
  14. {
  15. "POS",
  16. "NORMAL",
  17. "BINORMAL",
  18. "TANGENT",
  19. "TEXCOORD",
  20. "COLOR",
  21. "BLENDWEIGHT",
  22. "BLENDINDICES",
  23. "OBJECTINDEX"
  24. };
  25. void ShaderVariation::OnDeviceLost_OGL()
  26. {
  27. if (object_.name_ && !graphics_->IsDeviceLost())
  28. glDeleteShader(object_.name_);
  29. GPUObject::OnDeviceLost();
  30. compilerOutput_.Clear();
  31. }
  32. void ShaderVariation::Release_OGL()
  33. {
  34. if (object_.name_)
  35. {
  36. if (!graphics_)
  37. return;
  38. if (!graphics_->IsDeviceLost())
  39. {
  40. if (type_ == VS)
  41. {
  42. if (graphics_->GetVertexShader() == this)
  43. graphics_->SetShaders(nullptr, nullptr);
  44. }
  45. else
  46. {
  47. if (graphics_->GetPixelShader() == this)
  48. graphics_->SetShaders(nullptr, nullptr);
  49. }
  50. glDeleteShader(object_.name_);
  51. }
  52. object_.name_ = 0;
  53. graphics_->CleanupShaderPrograms_OGL(this);
  54. }
  55. compilerOutput_.Clear();
  56. }
  57. bool ShaderVariation::Create_OGL()
  58. {
  59. Release_OGL();
  60. if (!owner_)
  61. {
  62. compilerOutput_ = "Owner shader has expired";
  63. return false;
  64. }
  65. object_.name_ = glCreateShader(type_ == VS ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER);
  66. if (!object_.name_)
  67. {
  68. compilerOutput_ = "Could not create shader object";
  69. return false;
  70. }
  71. const String& originalShaderCode = owner_->GetSourceCode(type_);
  72. String shaderCode;
  73. // Check if the shader code contains a version define
  74. i32 verStart = originalShaderCode.Find('#');
  75. i32 verEnd = 0;
  76. if (verStart != String::NPOS)
  77. {
  78. if (originalShaderCode.Substring(verStart + 1, 7) == "version")
  79. {
  80. verEnd = verStart + 9;
  81. while (verEnd < originalShaderCode.Length())
  82. {
  83. if (IsDigit((unsigned)originalShaderCode[verEnd]))
  84. ++verEnd;
  85. else
  86. break;
  87. }
  88. // If version define found, insert it first
  89. String versionDefine = originalShaderCode.Substring(verStart, verEnd - verStart);
  90. shaderCode += versionDefine + "\n";
  91. }
  92. }
  93. // Force GLSL version 150 if no version define and GL3 is being used
  94. if (!verEnd && Graphics::GetGL3Support())
  95. {
  96. #if defined(MOBILE_GRAPHICS) || URHO3D_GLES3
  97. shaderCode += "#version 300 es\n";
  98. #else
  99. shaderCode += "#version 150\n";
  100. #endif
  101. }
  102. #if defined(DESKTOP_GRAPHICS)
  103. shaderCode += "#define DESKTOP_GRAPHICS\n";
  104. #elif defined(MOBILE_GRAPHICS)
  105. shaderCode += "#define MOBILE_GRAPHICS\n";
  106. #endif
  107. // Distinguish between VS and PS compile in case the shader code wants to include/omit different things
  108. shaderCode += type_ == VS ? "#define COMPILEVS\n" : "#define COMPILEPS\n";
  109. // Add define for the maximum number of supported bones
  110. shaderCode += "#define MAXBONES " + String(Graphics::GetMaxBones()) + "\n";
  111. // Prepend the defines to the shader code
  112. Vector<String> defineVec = defines_.Split(' ');
  113. for (unsigned i = 0; i < defineVec.Size(); ++i)
  114. {
  115. // Add extra space for the checking code below
  116. String defineString = "#define " + defineVec[i].Replaced('=', ' ') + " \n";
  117. shaderCode += defineString;
  118. // In debug mode, check that all defines are referenced by the shader code
  119. #ifdef _DEBUG
  120. String defineCheck = defineString.Substring(8, defineString.Find(' ', 8) - 8);
  121. if (originalShaderCode.Find(defineCheck) == String::NPOS)
  122. URHO3D_LOGWARNING("Shader " + GetFullName() + " does not use the define " + defineCheck);
  123. #endif
  124. }
  125. #ifdef RPI
  126. if (type_ == VS)
  127. shaderCode += "#define RPI\n";
  128. #endif
  129. #ifdef __EMSCRIPTEN__
  130. shaderCode += "#define WEBGL\n";
  131. #endif
  132. if (Graphics::GetGL3Support())
  133. shaderCode += "#define GL3\n";
  134. // When version define found, do not insert it a second time
  135. if (verEnd > 0)
  136. shaderCode += (originalShaderCode.CString() + verEnd);
  137. else
  138. shaderCode += originalShaderCode;
  139. const char* shaderCStr = shaderCode.CString();
  140. glShaderSource(object_.name_, 1, &shaderCStr, nullptr);
  141. glCompileShader(object_.name_);
  142. int compiled, length;
  143. glGetShaderiv(object_.name_, GL_COMPILE_STATUS, &compiled);
  144. if (!compiled)
  145. {
  146. glGetShaderiv(object_.name_, GL_INFO_LOG_LENGTH, &length);
  147. compilerOutput_.Resize((unsigned)length);
  148. int outLength;
  149. glGetShaderInfoLog(object_.name_, length, &outLength, &compilerOutput_[0]);
  150. glDeleteShader(object_.name_);
  151. object_.name_ = 0;
  152. }
  153. else
  154. compilerOutput_.Clear();
  155. return object_.name_ != 0;
  156. }
  157. void ShaderVariation::SetDefines_OGL(const String& defines)
  158. {
  159. defines_ = defines;
  160. }
  161. }