ShaderCompiler.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 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 "Context.h"
  24. #include "File.h"
  25. #include "FileSystem.h"
  26. #include "ProcessUtils.h"
  27. #include "StringUtils.h"
  28. #include "XMLFile.h"
  29. #include <cstdio>
  30. #include <cstring>
  31. #include "DebugNew.h"
  32. enum ShaderType
  33. {
  34. VS,
  35. PS,
  36. Both
  37. };
  38. struct Variation
  39. {
  40. Variation()
  41. {
  42. }
  43. Variation(const String& name, bool isOption) :
  44. name_(name),
  45. option_(isOption)
  46. {
  47. }
  48. void addDefine(const String& def)
  49. {
  50. defines_.Push(def);
  51. }
  52. void addExclude(const String& excl)
  53. {
  54. excludes_.Push(excl);
  55. }
  56. void addInclude(const String& incl)
  57. {
  58. includes_.Push(incl);
  59. }
  60. void addRequire(const String& req)
  61. {
  62. requires_.Push(req);
  63. }
  64. String name_;
  65. Vector<String> defines_;
  66. Vector<String> excludes_;
  67. Vector<String> includes_;
  68. Vector<String> requires_;
  69. bool option_;
  70. };
  71. struct Shader
  72. {
  73. Shader(const String& name, ShaderType type) :
  74. name_(name),
  75. type_(type)
  76. {
  77. }
  78. void addVariation(const Variation& var)
  79. {
  80. variations_.Push(var);
  81. }
  82. String name_;
  83. ShaderType type_;
  84. Vector<Variation> variations_;
  85. };
  86. struct Parameter
  87. {
  88. String name_;
  89. unsigned index_;
  90. };
  91. struct Parameters
  92. {
  93. void addVSParam(const String& name, unsigned index)
  94. {
  95. Parameter newParam;
  96. newParam.name_ = name;
  97. newParam.index_ = index;
  98. vsParams_.Push(newParam);
  99. }
  100. void addPSParam(const String& name, unsigned index)
  101. {
  102. Parameter newParam;
  103. newParam.name_ = name;
  104. newParam.index_ = index;
  105. psParams_.Push(newParam);
  106. }
  107. void addTextureUnit(const String& name, unsigned index)
  108. {
  109. Parameter newParam;
  110. newParam.name_ = name;
  111. newParam.index_ = index;
  112. textureUnits_.Push(newParam);
  113. }
  114. Vector<Parameter> vsParams_;
  115. Vector<Parameter> psParams_;
  116. Vector<Parameter> textureUnits_;
  117. };
  118. SharedPtr<Context> context_(new Context());
  119. SharedPtr<FileSystem> fileSystem_(new FileSystem(context_));
  120. String inDir_;
  121. String inFile_;
  122. String outDir_;
  123. Map<String, unsigned> vsParams_;
  124. Map<String, unsigned> psParams_;
  125. Map<String, unsigned> textureUnits_;
  126. Vector<String> defines_;
  127. bool useSM3_ = false;
  128. int main(int argc, char** argv);
  129. void Run(const Vector<String>& arguments);
  130. void CompileVariations(const Shader& baseShader, XMLElement& shaders);
  131. bool Compile(ShaderType type, const String& input, const String& output, const Vector<String>& defines, Parameters& params);
  132. int main(int argc, char** argv)
  133. {
  134. Vector<String> arguments;
  135. for (int i = 1; i < argc; ++i)
  136. {
  137. String argument(argv[i]);
  138. arguments.Push(argument.Replace('/', '\\'));
  139. }
  140. Run(arguments);
  141. return 0;
  142. }
  143. void Run(const Vector<String>& arguments)
  144. {
  145. if (arguments.Size() < 2)
  146. {
  147. ErrorExit(
  148. "Usage: ShaderCompiler <definitionfile> <outputpath> [SM3] [define1] [define2]\n\n"
  149. "HLSL files will be loaded from definition file directory, and binary code will\n"
  150. "be output to same directory as the output file.\n"
  151. );
  152. }
  153. unsigned pos = arguments[0].FindLast('\\');
  154. if (pos != String::NPOS)
  155. {
  156. inDir_ = arguments[0].Substring(0, pos);
  157. inFile_ = arguments[0].Substring(pos + 1);
  158. }
  159. else
  160. {
  161. inFile_ = arguments[0];
  162. }
  163. outDir_ = arguments[1];
  164. if (inDir_.Empty())
  165. inDir_ = ".\\";
  166. if (outDir_.Empty())
  167. outDir_ = ".\\";
  168. if (inDir_[inDir_.Length()-1] != '\\')
  169. inDir_ = inDir_ + "\\";
  170. if (outDir_[outDir_.Length()-1] != '\\')
  171. outDir_ = outDir_ + "\\";
  172. for (unsigned i = 2; i < arguments.Size(); ++i)
  173. {
  174. String arg = arguments[i].ToUpper();
  175. if (arg == "SM3")
  176. useSM3_ = true;
  177. else if (arg == "SM2")
  178. useSM3_ = false;
  179. defines_.Push(arg);
  180. }
  181. XMLFile doc(context_);
  182. File source(context_);
  183. source.Open(arguments[0]);
  184. if (!doc.Load(source))
  185. ErrorExit("Could not open input file " + arguments[0]);
  186. XMLElement shaders = doc.GetRootElement("shaders");
  187. if (!shaders)
  188. ErrorExit("No shaders element in " + source.GetName());
  189. XMLFile outDoc(context_);
  190. XMLElement outShaders = outDoc.CreateRootElement("shaders");
  191. XMLElement shader = shaders.GetChildElement("shader");
  192. while (shader)
  193. {
  194. bool WriteOutput = false;
  195. String source = shader.GetString("name");
  196. ShaderType compileType = Both;
  197. String type = shader.GetString("type");
  198. if ((type == "VS") || (type == "vs"))
  199. compileType = VS;
  200. if ((type == "PS") || (type == "ps"))
  201. compileType = PS;
  202. if ((compileType == Both) || (compileType == PS))
  203. WriteOutput = true;
  204. Shader baseShader(source, compileType);
  205. XMLElement variation = shader.GetChildElement("");
  206. while (variation)
  207. {
  208. String value = variation.GetName();
  209. if ((value == "variation") || (value == "option"))
  210. {
  211. String name = variation.GetString("name");
  212. Variation newVar(name, value == "option");
  213. String simpleDefine = variation.GetString("define");
  214. if (!simpleDefine.Empty())
  215. newVar.addDefine(simpleDefine);
  216. String simpleExclude = variation.GetString("exclude");
  217. if (!simpleExclude.Empty())
  218. newVar.addExclude(simpleExclude);
  219. String simpleInclude = variation.GetString("include");
  220. if (!simpleInclude.Empty())
  221. newVar.addInclude(simpleInclude);
  222. String simpleRequire = variation.GetString("require");
  223. if (!simpleRequire.Empty())
  224. newVar.addRequire(simpleRequire);
  225. XMLElement define = variation.GetChildElement("define");
  226. while (define)
  227. {
  228. String name = define.GetString("name");
  229. newVar.addDefine(name);
  230. define = define.GetNextElement("define");
  231. }
  232. XMLElement exclude = variation.GetChildElement("exclude");
  233. while (exclude)
  234. {
  235. String name = exclude.GetString("name");
  236. newVar.addExclude(name);
  237. exclude = exclude.GetNextElement("exclude");
  238. }
  239. XMLElement include = variation.GetChildElement("include");
  240. while (include)
  241. {
  242. String name = include.GetString("name");
  243. newVar.addInclude(name);
  244. include = include.GetNextElement("include");
  245. }
  246. XMLElement require = variation.GetChildElement("require");
  247. while (require)
  248. {
  249. String name = require.GetString("name");
  250. newVar.addRequire(name);
  251. require = require.GetNextElement("require");
  252. }
  253. baseShader.addVariation(newVar);
  254. }
  255. variation = variation.GetNextElement();
  256. }
  257. if (baseShader.type_ != Both)
  258. CompileVariations(baseShader, outShaders);
  259. else
  260. {
  261. baseShader.type_ = VS;
  262. CompileVariations(baseShader, outShaders);
  263. baseShader.type_ = PS;
  264. CompileVariations(baseShader, outShaders);
  265. }
  266. if (WriteOutput)
  267. {
  268. String outFileName = outDir_ + inDir_ + source + ".xml";
  269. remove(outFileName.CString());
  270. // Add global parameter & texture sampler definitions
  271. {
  272. XMLElement parameters = outShaders.CreateChildElement("vsparameters");
  273. Map<unsigned, Vector<String> > sorted;
  274. for (Map<String, unsigned>::ConstIterator i = vsParams_.Begin(); i != vsParams_.End(); ++i)
  275. sorted[i->second_].Push(i->first_);
  276. for (Map<unsigned, Vector<String> >::ConstIterator i = sorted.Begin(); i != sorted.End(); ++i)
  277. {
  278. for (unsigned j = 0; j < i->second_.Size(); ++j)
  279. {
  280. XMLElement param = parameters.CreateChildElement("parameter");
  281. param.SetString("name", i->second_[j]);
  282. param.SetInt("index", i->first_);
  283. }
  284. }
  285. }
  286. {
  287. XMLElement parameters = outShaders.CreateChildElement("psparameters");
  288. Map<unsigned, Vector<String> > sorted;
  289. for (Map<String, unsigned>::ConstIterator i = psParams_.Begin(); i != psParams_.End(); ++i)
  290. sorted[i->second_].Push(i->first_);
  291. for (Map<unsigned, Vector<String> >::ConstIterator i = sorted.Begin(); i != sorted.End(); ++i)
  292. {
  293. for (unsigned j = 0; j < i->second_.Size(); ++j)
  294. {
  295. XMLElement param = parameters.CreateChildElement("parameter");
  296. param.SetString("name", i->second_[j]);
  297. param.SetInt("index", i->first_);
  298. }
  299. }
  300. }
  301. {
  302. XMLElement parameters = outShaders.CreateChildElement("textureunits");
  303. Map<unsigned, Vector<String> > sorted;
  304. for (Map<String, unsigned>::ConstIterator i = textureUnits_.Begin(); i != textureUnits_.End(); ++i)
  305. sorted[i->second_].Push(i->first_);
  306. for (Map<unsigned, Vector<String> >::ConstIterator i = sorted.Begin(); i != sorted.End(); ++i)
  307. {
  308. for (unsigned j = 0; j < i->second_.Size(); ++j)
  309. {
  310. XMLElement param = parameters.CreateChildElement("parameter");
  311. param.SetString("name", i->second_[j]);
  312. param.SetInt("index", i->first_);
  313. }
  314. }
  315. }
  316. File outFile(context_);
  317. outFile.Open(outFileName, FILE_WRITE);
  318. if (!outDoc.Save(outFile))
  319. ErrorExit("Could not save output file " + outFileName);
  320. }
  321. shader = shader.GetNextElement("shader");
  322. }
  323. }
  324. void CompileVariations(const Shader& baseShader, XMLElement& shaders)
  325. {
  326. unsigned combinations = 1;
  327. PODVector<unsigned> compiled;
  328. bool hasVariations = false;
  329. const Vector<Variation>& variations = baseShader.variations_;
  330. Map<String, unsigned> nameToIndex;
  331. if (variations.Size() > 32)
  332. ErrorExit("Maximum amount of variations exceeded");
  333. for (unsigned i = 0; i < variations.Size(); ++i)
  334. {
  335. combinations *= 2;
  336. nameToIndex[variations[i].name_] = i;
  337. if (!variations[i].option_)
  338. hasVariations = true;
  339. }
  340. for (unsigned i = 0; i < combinations; ++i)
  341. {
  342. unsigned active = i; // Variations/options active on this particular combination
  343. bool variationActive = false;
  344. bool skipThis = false;
  345. // Check for excludes/includes/requires
  346. for (unsigned j = 0; j < variations.Size(); ++j)
  347. {
  348. if ((active >> j) & 1)
  349. {
  350. for (unsigned k = 0; k < variations[j].includes_.Size(); ++k)
  351. {
  352. if (nameToIndex.Find(variations[j].includes_[k]) != nameToIndex.End())
  353. active |= (1 << nameToIndex[variations[j].includes_[k]]);
  354. }
  355. for (unsigned k = 0; k < variations[j].excludes_.Size(); ++k)
  356. {
  357. if (nameToIndex.Find(variations[j].excludes_[k]) != nameToIndex.End())
  358. active &= ~(1 << nameToIndex[variations[j].excludes_[k]]);
  359. }
  360. // If it's a variation, exclude all other variations
  361. if (!variations[j].option_)
  362. {
  363. for (unsigned k = 0; k < variations.Size(); ++k)
  364. {
  365. if ((k != j) && (!variations[k].option_))
  366. active &= ~(1 << k);
  367. }
  368. variationActive = true;
  369. }
  370. for (unsigned k = 0; k < variations[j].requires_.Size(); ++k)
  371. {
  372. bool requireFound = false;
  373. for (unsigned l = 0; l < defines_.Size(); ++l)
  374. {
  375. if (defines_[l] == variations[j].requires_[k])
  376. {
  377. requireFound = true;
  378. break;
  379. }
  380. }
  381. for (unsigned l = 0; l < variations.Size(); ++l)
  382. {
  383. if (((active >> l) & 1) && (l != j))
  384. {
  385. if (variations[l].name_ == variations[j].requires_[k])
  386. {
  387. requireFound = true;
  388. break;
  389. }
  390. for (unsigned m = 0; m < variations[l].defines_.Size(); ++m)
  391. {
  392. if (variations[l].defines_[m] == variations[j].requires_[k])
  393. {
  394. requireFound = true;
  395. break;
  396. }
  397. }
  398. }
  399. if (requireFound)
  400. break;
  401. }
  402. if (!requireFound)
  403. skipThis = true;
  404. }
  405. }
  406. }
  407. // If variations are included, check that one of them is active
  408. if ((hasVariations) && (!variationActive))
  409. continue;
  410. if (skipThis)
  411. continue;
  412. // Check that this combination is unique
  413. bool unique = true;
  414. for (unsigned j = 0; j < compiled.Size(); ++j)
  415. {
  416. if (compiled[j] == active)
  417. {
  418. unique = false;
  419. break;
  420. }
  421. }
  422. if (unique)
  423. {
  424. bool firstSuffix = true;
  425. // Build output shader filename & defines from active variations
  426. String outName = baseShader.name_;
  427. Vector<String> defines;
  428. for (unsigned j = 0; j < variations.Size(); ++j)
  429. {
  430. if (active & (1 << j))
  431. {
  432. if (variations[j].name_.Length())
  433. {
  434. if (firstSuffix)
  435. {
  436. outName = outName + "_" + variations[j].name_;
  437. firstSuffix = false;
  438. }
  439. else
  440. outName = outName + variations[j].name_;
  441. }
  442. for (unsigned k = 0; k < variations[j].defines_.Size(); ++k)
  443. defines.Push(variations[j].defines_[k]);
  444. }
  445. }
  446. Parameters params;
  447. bool ok = Compile(baseShader.type_, baseShader.name_, outName, defines, params);
  448. // If shader was unnecessary (for example SM2 does not support HQ variations)
  449. // no output may have been produced. Skip in that case.
  450. if (ok)
  451. {
  452. XMLElement shader = shaders.CreateChildElement("shader");
  453. shader.SetString("name", outName);
  454. switch (baseShader.type_)
  455. {
  456. case VS:
  457. shader.SetString("type", "vs");
  458. for (unsigned j = 0; j < params.vsParams_.Size(); ++j)
  459. {
  460. XMLElement vsParam = shader.CreateChildElement("parameter");
  461. vsParam.SetString("name", params.vsParams_[j].name_);
  462. }
  463. break;
  464. case PS:
  465. shader.SetString("type", "ps");
  466. for (unsigned j = 0; j < params.psParams_.Size(); ++j)
  467. {
  468. XMLElement psParam = shader.CreateChildElement("parameter");
  469. psParam.SetString("name", params.psParams_[j].name_);
  470. }
  471. for (unsigned j = 0; j < params.textureUnits_.Size(); ++j)
  472. {
  473. XMLElement texture = shader.CreateChildElement("textureunit");
  474. texture.SetString("name", params.textureUnits_[j].name_);
  475. }
  476. break;
  477. }
  478. compiled.Push(active);
  479. }
  480. }
  481. }
  482. }
  483. bool Compile(ShaderType type, const String& input, const String& output, const Vector<String>& defines,
  484. Parameters& params)
  485. {
  486. bool compiled = false;
  487. String allDefines;
  488. for (unsigned i = 0; i < defines.Size(); ++i)
  489. allDefines += "/D" + defines[i] + " ";
  490. for (unsigned i = 0; i < defines_.Size(); ++i)
  491. allDefines += "/D" + defines_[i] + " ";
  492. if (type == VS)
  493. {
  494. if (!useSM3_)
  495. {
  496. String outFile = output + ".vs2";
  497. String command = "fxc /Tvs_2_0 /O3 /EVS /Fo" + outDir_ + inDir_ + outFile + " /Fcoutput.txt " + allDefines +
  498. inDir_ + input + ".hlsl";
  499. if (fileSystem_->SystemCommand(command))
  500. ErrorExit("Failed to compile shader " + outFile);
  501. compiled = true;
  502. }
  503. else
  504. {
  505. String outFile = output + ".vs3";
  506. String command = "fxc /Tvs_3_0 /O3 /EVS /Fo" + outDir_ + inDir_ + outFile + " /Fcoutput.txt " + allDefines +
  507. inDir_ + input + ".hlsl";
  508. if (fileSystem_->SystemCommand(command))
  509. ErrorExit("Failed to compile shader " + outFile);
  510. compiled = true;
  511. }
  512. }
  513. if (type == PS)
  514. {
  515. if (!useSM3_)
  516. {
  517. String outFile = output + ".ps2";
  518. String command = "fxc /Tps_2_0 /O3 /EPS /Fo" + outDir_ + inDir_ + outFile + " /Fcoutput.txt " + allDefines +
  519. inDir_ + input + ".hlsl";
  520. if (fileSystem_->SystemCommand(command))
  521. ErrorExit("Failed to compile shader " + outFile);
  522. compiled = true;
  523. }
  524. else
  525. {
  526. String outFile = output + ".ps3";
  527. String command = "fxc /Tps_3_0 /O3 /Gfp /EPS /Fo" + outDir_ + inDir_ + outFile + " /Fcoutput.txt " + allDefines +
  528. inDir_ + input + ".hlsl";
  529. if (fileSystem_->SystemCommand(command))
  530. ErrorExit("Failed to compile shader" + outFile);
  531. compiled = true;
  532. }
  533. }
  534. if (!compiled)
  535. return false;
  536. SharedPtr<File> dump(new File(context_, "output.txt"));
  537. if (!dump->IsOpen())
  538. ErrorExit("Could not open dump file");
  539. bool paramsStarted = false;
  540. while (!dump->IsEof())
  541. {
  542. String lineStr = dump->ReadLine();
  543. Vector<String> elements = lineStr.Split(' ');
  544. if (paramsStarted)
  545. {
  546. if ((!elements.Size()) || (elements[0] != "//"))
  547. break;
  548. if ((elements.Size() == 4) && (elements[0] == "//") && (elements[1][0] != '-'))
  549. {
  550. String name = elements[1];
  551. String reg = elements[2];
  552. bool isSampler = false;
  553. if (reg[0] == 's')
  554. isSampler = true;
  555. if ((name[0] == 'c') || (name[0] == 's'))
  556. name = name.Substring(1, name.Length() - 1);
  557. unsigned index = ToInt(reg.Substring(1, reg.Length() - 1));
  558. if (isSampler)
  559. {
  560. // Skip if it's a G-buffer sampler
  561. if (name.Find("Buffer") == String::NPOS)
  562. {
  563. params.addTextureUnit(name, index);
  564. if (textureUnits_.Find(name) != textureUnits_.End())
  565. {
  566. unsigned oldIndex = textureUnits_[name];
  567. if (oldIndex != index)
  568. ErrorExit("Texture " + name + " bound to several sampler registers");
  569. }
  570. textureUnits_[name] = index;
  571. }
  572. }
  573. else
  574. {
  575. if (type == VS)
  576. {
  577. params.addVSParam(name, index);
  578. if (vsParams_.Find(name) != vsParams_.End())
  579. {
  580. unsigned oldIndex = vsParams_[name];
  581. if (oldIndex != index)
  582. ErrorExit("Parameter " + name + " bound to several constant registers");
  583. }
  584. vsParams_[name] = index;
  585. }
  586. else
  587. {
  588. params.addPSParam(name, index);
  589. if (psParams_.Find(name) != psParams_.End())
  590. {
  591. unsigned oldIndex = psParams_[name];
  592. if (oldIndex != index)
  593. ErrorExit("Parameter " + name + " bound to several constant registers");
  594. }
  595. psParams_[name] = index;
  596. }
  597. }
  598. }
  599. }
  600. else
  601. {
  602. if ((elements.Size() == 4) && (elements[0] == "//") && (elements[1] == "Name"))
  603. paramsStarted = true;
  604. }
  605. }
  606. dump->Close();
  607. remove("output.txt");
  608. return true;
  609. }