2
0

ShaderProgramCompilerMain.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. // Copyright (C) 2009-2022, 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 const char* USAGE = 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. HeapAllocator<U8> m_alloc = {allocAligned, nullptr};
  21. StringAuto m_inputFname = {m_alloc};
  22. StringAuto m_outFname = {m_alloc};
  23. StringAuto m_includePath = {m_alloc};
  24. U32 m_threadCount = getCpuCoresCount();
  25. Bool m_fullFpPrecision = false;
  26. Bool m_mobilePlatform = false;
  27. };
  28. static Error parseCommandLineArgs(int argc, char** argv, CmdLineArgs& info)
  29. {
  30. // Parse config
  31. if(argc < 2)
  32. {
  33. return Error::USER_DATA;
  34. }
  35. for(I i = 1; i < argc - 1; i++)
  36. {
  37. if(strcmp(argv[i], "-o") == 0)
  38. {
  39. ++i;
  40. if(i < argc)
  41. {
  42. if(std::strlen(argv[i]) > 0)
  43. {
  44. info.m_outFname.sprintf("%s", argv[i]);
  45. }
  46. else
  47. {
  48. return Error::USER_DATA;
  49. }
  50. }
  51. else
  52. {
  53. return Error::USER_DATA;
  54. }
  55. }
  56. else if(strcmp(argv[i], "-j") == 0)
  57. {
  58. ++i;
  59. if(i < argc)
  60. {
  61. ANKI_CHECK(CString(argv[i]).toNumber(info.m_threadCount));
  62. }
  63. else
  64. {
  65. return Error::USER_DATA;
  66. }
  67. }
  68. else if(strcmp(argv[i], "-I") == 0)
  69. {
  70. ++i;
  71. if(i < argc)
  72. {
  73. if(std::strlen(argv[i]) > 0)
  74. {
  75. info.m_includePath.sprintf("%s", argv[i]);
  76. }
  77. else
  78. {
  79. return Error::USER_DATA;
  80. }
  81. }
  82. else
  83. {
  84. return Error::USER_DATA;
  85. }
  86. }
  87. else if(strcmp(argv[i], "-force-full-fp") == 0)
  88. {
  89. info.m_fullFpPrecision = true;
  90. }
  91. else if(strcmp(argv[i], "-mobile-platform") == 0)
  92. {
  93. info.m_mobilePlatform = true;
  94. }
  95. else
  96. {
  97. return Error::USER_DATA;
  98. }
  99. }
  100. info.m_inputFname.create(argv[argc - 1]);
  101. return Error::NONE;
  102. }
  103. static Error work(const CmdLineArgs& info)
  104. {
  105. HeapAllocator<U8> alloc{allocAligned, nullptr};
  106. // Load interface
  107. class FSystem : public ShaderProgramFilesystemInterface
  108. {
  109. public:
  110. CString m_includePath;
  111. U32 m_fileReadCount = 0;
  112. Error readAllTextInternal(CString filename, StringAuto& txt)
  113. {
  114. StringAuto fname(txt.getAllocator());
  115. // The first file is the input file. Don't append the include path to it
  116. if(m_fileReadCount == 0)
  117. {
  118. fname.sprintf("%s", filename.cstr());
  119. }
  120. else
  121. {
  122. fname.sprintf("%s/%s", m_includePath.cstr(), filename.cstr());
  123. }
  124. ++m_fileReadCount;
  125. File file;
  126. ANKI_CHECK(file.open(fname, FileOpenFlag::READ));
  127. ANKI_CHECK(file.readAllText(txt));
  128. return Error::NONE;
  129. }
  130. Error readAllText(CString filename, StringAuto& txt) final
  131. {
  132. const Error err = readAllTextInternal(filename, txt);
  133. if(err)
  134. {
  135. ANKI_LOGE("Failed to read file: %s", filename.cstr());
  136. }
  137. return err;
  138. }
  139. } fsystem;
  140. fsystem.m_includePath = info.m_includePath;
  141. // Threading interface
  142. class TaskManager : public ShaderProgramAsyncTaskInterface
  143. {
  144. public:
  145. ThreadHive* m_hive = nullptr;
  146. HeapAllocator<U8> m_alloc;
  147. void enqueueTask(void (*callback)(void* userData), void* userData)
  148. {
  149. struct Ctx
  150. {
  151. void (*m_callback)(void* userData);
  152. void* m_userData;
  153. HeapAllocator<U8> m_alloc;
  154. };
  155. Ctx* ctx = m_alloc.newInstance<Ctx>();
  156. ctx->m_callback = callback;
  157. ctx->m_userData = userData;
  158. ctx->m_alloc = m_alloc;
  159. m_hive->submitTask(
  160. [](void* userData, U32 threadId, ThreadHive& hive, ThreadHiveSemaphore* signalSemaphore) {
  161. Ctx* ctx = static_cast<Ctx*>(userData);
  162. ctx->m_callback(ctx->m_userData);
  163. auto alloc = ctx->m_alloc;
  164. alloc.deleteInstance(ctx);
  165. },
  166. ctx);
  167. }
  168. Error joinTasks()
  169. {
  170. m_hive->waitAllTasks();
  171. return Error::NONE;
  172. }
  173. } taskManager;
  174. taskManager.m_hive =
  175. (info.m_threadCount) ? alloc.newInstance<ThreadHive>(info.m_threadCount, alloc, true) : nullptr;
  176. taskManager.m_alloc = alloc;
  177. // Compiler options
  178. ShaderCompilerOptions compilerOptions;
  179. compilerOptions.m_forceFullFloatingPointPrecision = info.m_fullFpPrecision;
  180. compilerOptions.m_mobilePlatform = info.m_mobilePlatform;
  181. // Compile
  182. ShaderProgramBinaryWrapper binary(alloc);
  183. ANKI_CHECK(compileShaderProgram(info.m_inputFname, fsystem, nullptr, (info.m_threadCount) ? &taskManager : nullptr,
  184. alloc, compilerOptions, binary));
  185. // Store the binary
  186. ANKI_CHECK(binary.serializeToFile(info.m_outFname));
  187. // Cleanup
  188. alloc.deleteInstance(taskManager.m_hive);
  189. return Error::NONE;
  190. }
  191. int main(int argc, char** argv)
  192. {
  193. CmdLineArgs info;
  194. if(parseCommandLineArgs(argc, argv, info))
  195. {
  196. ANKI_LOGE(USAGE, argv[0]);
  197. return 1;
  198. }
  199. if(info.m_outFname.isEmpty())
  200. {
  201. getFilepathFilename(info.m_inputFname, info.m_outFname);
  202. info.m_outFname.append("bin");
  203. }
  204. if(info.m_includePath.isEmpty())
  205. {
  206. info.m_includePath.create("./");
  207. }
  208. if(work(info))
  209. {
  210. ANKI_LOGE("Failed");
  211. return 1;
  212. }
  213. return 0;
  214. }