ShaderProgramCompilerMain.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. // Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/ShaderCompiler/ShaderProgramCompiler.h>
  6. #include <AnKi/Util.h>
  7. using namespace anki;
  8. static constexpr const char* kUsage = R"(Compile an AnKi shader program
  9. Usage: %s [options] input_shader_program_file
  10. Options:
  11. -o <name of output> : The name of the output binary
  12. -j <thread count> : Number of threads. Defaults to system's max
  13. -I <include path> : The path of the #include files
  14. -force-full-fp : Force full floating point precision
  15. -mobile-platform : Build for mobile
  16. )";
  17. class CmdLineArgs
  18. {
  19. public:
  20. String m_inputFname;
  21. String m_outFname;
  22. String m_includePath;
  23. U32 m_threadCount = getCpuCoresCount();
  24. Bool m_fullFpPrecision = false;
  25. Bool m_mobilePlatform = false;
  26. };
  27. static Error parseCommandLineArgs(int argc, char** argv, CmdLineArgs& info)
  28. {
  29. // Parse config
  30. if(argc < 2)
  31. {
  32. return Error::kUserData;
  33. }
  34. for(I i = 1; i < argc - 1; i++)
  35. {
  36. if(strcmp(argv[i], "-o") == 0)
  37. {
  38. ++i;
  39. if(i < argc)
  40. {
  41. if(std::strlen(argv[i]) > 0)
  42. {
  43. info.m_outFname.sprintf("%s", argv[i]);
  44. }
  45. else
  46. {
  47. return Error::kUserData;
  48. }
  49. }
  50. else
  51. {
  52. return Error::kUserData;
  53. }
  54. }
  55. else if(strcmp(argv[i], "-j") == 0)
  56. {
  57. ++i;
  58. if(i < argc)
  59. {
  60. ANKI_CHECK(CString(argv[i]).toNumber(info.m_threadCount));
  61. }
  62. else
  63. {
  64. return Error::kUserData;
  65. }
  66. }
  67. else if(strcmp(argv[i], "-I") == 0)
  68. {
  69. ++i;
  70. if(i < argc)
  71. {
  72. if(std::strlen(argv[i]) > 0)
  73. {
  74. info.m_includePath.sprintf("%s", argv[i]);
  75. }
  76. else
  77. {
  78. return Error::kUserData;
  79. }
  80. }
  81. else
  82. {
  83. return Error::kUserData;
  84. }
  85. }
  86. else if(strcmp(argv[i], "-force-full-fp") == 0)
  87. {
  88. info.m_fullFpPrecision = true;
  89. }
  90. else if(strcmp(argv[i], "-mobile-platform") == 0)
  91. {
  92. info.m_mobilePlatform = true;
  93. }
  94. else
  95. {
  96. return Error::kUserData;
  97. }
  98. }
  99. info.m_inputFname = argv[argc - 1];
  100. return Error::kNone;
  101. }
  102. static Error work(const CmdLineArgs& info)
  103. {
  104. HeapMemoryPool pool(allocAligned, nullptr, "ProgramPool");
  105. // Load interface
  106. class FSystem : public ShaderProgramFilesystemInterface
  107. {
  108. public:
  109. CString m_includePath;
  110. U32 m_fileReadCount = 0;
  111. Error readAllTextInternal(CString filename, String& txt)
  112. {
  113. String fname;
  114. // The first file is the input file. Don't append the include path to it
  115. if(m_fileReadCount == 0)
  116. {
  117. fname.sprintf("%s", filename.cstr());
  118. }
  119. else
  120. {
  121. fname.sprintf("%s/%s", m_includePath.cstr(), filename.cstr());
  122. }
  123. ++m_fileReadCount;
  124. File file;
  125. ANKI_CHECK(file.open(fname, FileOpenFlag::kRead));
  126. ANKI_CHECK(file.readAllText(txt));
  127. return Error::kNone;
  128. }
  129. Error readAllText(CString filename, String& txt) final
  130. {
  131. const Error err = readAllTextInternal(filename, txt);
  132. if(err)
  133. {
  134. ANKI_LOGE("Failed to read file: %s", filename.cstr());
  135. }
  136. return err;
  137. }
  138. } fsystem;
  139. fsystem.m_includePath = info.m_includePath;
  140. // Threading interface
  141. class TaskManager : public ShaderProgramAsyncTaskInterface
  142. {
  143. public:
  144. UniquePtr<ThreadJobManager, SingletonMemoryPoolDeleter<DefaultMemoryPool>> m_jobManager;
  145. void enqueueTask(void (*callback)(void* userData), void* userData) final
  146. {
  147. m_jobManager->dispatchTask([callback, userData]([[maybe_unused]] U32 threadIdx) {
  148. callback(userData);
  149. });
  150. }
  151. Error joinTasks()
  152. {
  153. m_jobManager->waitForAllTasksToFinish();
  154. return Error::kNone;
  155. }
  156. } taskManager;
  157. taskManager.m_jobManager.reset((info.m_threadCount) ? newInstance<ThreadJobManager>(DefaultMemoryPool::getSingleton(), info.m_threadCount, true)
  158. : nullptr);
  159. // Compiler options
  160. ShaderCompilerOptions compilerOptions;
  161. compilerOptions.m_forceFullFloatingPointPrecision = info.m_fullFpPrecision;
  162. compilerOptions.m_mobilePlatform = info.m_mobilePlatform;
  163. // Compile
  164. ShaderProgramBinaryWrapper binary(&pool);
  165. ANKI_CHECK(compileShaderProgram(info.m_inputFname, fsystem, nullptr, (info.m_threadCount) ? &taskManager : nullptr, compilerOptions, binary));
  166. // Store the binary
  167. ANKI_CHECK(binary.serializeToFile(info.m_outFname));
  168. return Error::kNone;
  169. }
  170. ANKI_MAIN_FUNCTION(myMain)
  171. int myMain(int argc, char** argv)
  172. {
  173. class Dummy
  174. {
  175. public:
  176. ~Dummy()
  177. {
  178. DefaultMemoryPool::freeSingleton();
  179. }
  180. } dummy;
  181. DefaultMemoryPool::allocateSingleton(allocAligned, nullptr);
  182. CmdLineArgs info;
  183. if(parseCommandLineArgs(argc, argv, info))
  184. {
  185. ANKI_LOGE(kUsage, argv[0]);
  186. return 1;
  187. }
  188. if(info.m_outFname.isEmpty())
  189. {
  190. getFilepathFilename(info.m_inputFname, info.m_outFname);
  191. info.m_outFname += "bin";
  192. }
  193. if(info.m_includePath.isEmpty())
  194. {
  195. info.m_includePath = "./";
  196. }
  197. if(work(info))
  198. {
  199. ANKI_LOGE("Compilation failed");
  200. return 1;
  201. }
  202. return 0;
  203. }