shaderc.cpp 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307
  1. /*
  2. * Copyright 2011-2012 Branimir Karadzic. All rights reserved.
  3. * License: http://www.opensource.org/licenses/BSD-2-Clause
  4. */
  5. #define NOMINMAX
  6. #include <stdio.h>
  7. #include <stdint.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <string>
  11. #include <vector>
  12. #include "glsl_optimizer.h"
  13. #define MAX_TAGS 256
  14. extern "C" {
  15. # include <fpp.h>
  16. } // extern "C"
  17. #if 1
  18. # define BX_TRACE(_format, ...) fprintf(stderr, "" _format "\n", ##__VA_ARGS__)
  19. #endif // DEBUG
  20. #define BX_NAMESPACE 1
  21. #include <bx/bx.h>
  22. #if BX_PLATFORM_LINUX
  23. # define _stricmp strcasecmp
  24. #endif // BX_PLATFORM_LINUX
  25. #include <bx/commandline.h>
  26. #include <bx/countof.h>
  27. #include <bx/endian.h>
  28. #include <bx/uint32_t.h>
  29. #if BX_PLATFORM_WINDOWS
  30. # include <d3dx9.h>
  31. # include <d3dcompiler.h>
  32. #endif // BX_PLATFORM_WINDOWS
  33. long int fsize(FILE* _file)
  34. {
  35. long int pos = ftell(_file);
  36. fseek(_file, 0L, SEEK_END);
  37. long int size = ftell(_file);
  38. fseek(_file, pos, SEEK_SET);
  39. return size;
  40. }
  41. struct ConstantType
  42. {
  43. enum Enum
  44. {
  45. Uniform1i,
  46. Uniform1f,
  47. End,
  48. Uniform1iv,
  49. Uniform1fv,
  50. Uniform2fv,
  51. Uniform3fv,
  52. Uniform4fv,
  53. Uniform3x3fv,
  54. Uniform4x4fv,
  55. Count,
  56. TypeMask = 0x7f,
  57. FragmentBit = 0x80
  58. };
  59. };
  60. static const char* s_constantTypeName[ConstantType::Count] =
  61. {
  62. "int",
  63. "float",
  64. NULL,
  65. "int",
  66. "float",
  67. "float2",
  68. "float3",
  69. "float4",
  70. "float3x3",
  71. "float4x4",
  72. };
  73. struct Uniform
  74. {
  75. std::string name;
  76. ConstantType::Enum type;
  77. uint8_t num;
  78. uint16_t regIndex;
  79. uint16_t regCount;
  80. };
  81. typedef std::vector<Uniform> UniformArray;
  82. #if BX_PLATFORM_WINDOWS
  83. struct ConstRemapDx9
  84. {
  85. ConstantType::Enum id;
  86. D3DXPARAMETER_CLASS paramClass;
  87. D3DXPARAMETER_TYPE paramType;
  88. uint32_t paramBytes;
  89. };
  90. static const ConstRemapDx9 s_constRemapDx9[7] =
  91. {
  92. { ConstantType::Uniform1iv, D3DXPC_SCALAR, D3DXPT_INT, 4 },
  93. { ConstantType::Uniform1fv, D3DXPC_SCALAR, D3DXPT_FLOAT, 4 },
  94. { ConstantType::Uniform2fv, D3DXPC_VECTOR, D3DXPT_FLOAT, 8 },
  95. { ConstantType::Uniform3fv, D3DXPC_VECTOR, D3DXPT_FLOAT, 12 },
  96. { ConstantType::Uniform4fv, D3DXPC_VECTOR, D3DXPT_FLOAT, 16 },
  97. { ConstantType::Uniform3x3fv, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 36 },
  98. { ConstantType::Uniform4x4fv, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 64 },
  99. };
  100. ConstantType::Enum findConstantTypeDx9(const D3DXCONSTANT_DESC& constDesc)
  101. {
  102. uint32_t count = sizeof(s_constRemapDx9)/sizeof(ConstRemapDx9);
  103. for (uint32_t ii = 0; ii < count; ++ii)
  104. {
  105. const ConstRemapDx9& remap = s_constRemapDx9[ii];
  106. if (remap.paramClass == constDesc.Class
  107. && remap.paramType == constDesc.Type
  108. && (constDesc.Bytes%remap.paramBytes) == 0)
  109. {
  110. return remap.id;
  111. }
  112. }
  113. return ConstantType::Count;
  114. }
  115. static uint32_t s_optimizationLevelDx9[4] =
  116. {
  117. D3DXSHADER_OPTIMIZATION_LEVEL0,
  118. D3DXSHADER_OPTIMIZATION_LEVEL1,
  119. D3DXSHADER_OPTIMIZATION_LEVEL2,
  120. D3DXSHADER_OPTIMIZATION_LEVEL3,
  121. };
  122. struct ConstRemapDx11
  123. {
  124. ConstantType::Enum id;
  125. D3D_SHADER_VARIABLE_CLASS paramClass;
  126. D3D_SHADER_VARIABLE_TYPE paramType;
  127. uint32_t paramBytes;
  128. };
  129. static const ConstRemapDx11 s_constRemapDx11[7] =
  130. {
  131. { ConstantType::Uniform1iv, D3D_SVC_SCALAR, D3D_SVT_INT, 4 },
  132. { ConstantType::Uniform1fv, D3D_SVC_SCALAR, D3D_SVT_FLOAT, 4 },
  133. { ConstantType::Uniform2fv, D3D_SVC_VECTOR, D3D_SVT_FLOAT, 8 },
  134. { ConstantType::Uniform3fv, D3D_SVC_VECTOR, D3D_SVT_FLOAT, 12 },
  135. { ConstantType::Uniform4fv, D3D_SVC_VECTOR, D3D_SVT_FLOAT, 16 },
  136. { ConstantType::Uniform3x3fv, D3D_SVC_MATRIX_COLUMNS, D3D_SVT_FLOAT, 36 },
  137. { ConstantType::Uniform4x4fv, D3D_SVC_MATRIX_COLUMNS, D3D_SVT_FLOAT, 64 },
  138. };
  139. ConstantType::Enum findConstantTypeDx11(const D3D11_SHADER_TYPE_DESC& constDesc, uint32_t _size)
  140. {
  141. uint32_t count = sizeof(s_constRemapDx11)/sizeof(ConstRemapDx9);
  142. for (uint32_t ii = 0; ii < count; ++ii)
  143. {
  144. const ConstRemapDx11& remap = s_constRemapDx11[ii];
  145. if (remap.paramClass == constDesc.Class
  146. && remap.paramType == constDesc.Type
  147. && remap.paramBytes == _size)
  148. {
  149. return remap.id;
  150. }
  151. }
  152. return ConstantType::Count;
  153. }
  154. static uint32_t s_optimizationLevelDx11[4] =
  155. {
  156. D3DCOMPILE_OPTIMIZATION_LEVEL0,
  157. D3DCOMPILE_OPTIMIZATION_LEVEL1,
  158. D3DCOMPILE_OPTIMIZATION_LEVEL2,
  159. D3DCOMPILE_OPTIMIZATION_LEVEL3,
  160. };
  161. #endif // BX_PLATFORM_WINDOWS
  162. class IStreamWriter
  163. {
  164. public:
  165. virtual ~IStreamWriter() = 0;
  166. virtual bool open() = 0;
  167. virtual void close() = 0;
  168. virtual void writef(const char* _format, ...) = 0;
  169. virtual void write(const char* _str) = 0;
  170. virtual void write(const void* _data, size_t _size) = 0;
  171. template<typename Ty>
  172. void write(Ty _value)
  173. {
  174. write(&_value, sizeof(Ty) );
  175. }
  176. // template<typename Ty>
  177. // void write(Ty _value)
  178. // {
  179. // Ty temp = m_bigEndian ? bx::bigEndian<Ty>(_value) : _value;
  180. // write(&temp, sizeof(Ty) );
  181. // }
  182. };
  183. IStreamWriter::~IStreamWriter()
  184. {
  185. }
  186. class FileWriter : public IStreamWriter
  187. {
  188. public:
  189. FileWriter(const char* _filePath, bool _bigEndian = false)
  190. : m_filePath(_filePath)
  191. , m_file(NULL)
  192. , m_bigEndian(_bigEndian)
  193. {
  194. }
  195. ~FileWriter()
  196. {
  197. }
  198. bool open()
  199. {
  200. BX_CHECK(NULL == m_file, "Still open!");
  201. m_file = fopen(m_filePath.c_str(), "wb");
  202. return NULL != m_file;
  203. }
  204. void close()
  205. {
  206. if (NULL != m_file)
  207. {
  208. fclose(m_file);
  209. m_file = NULL;
  210. }
  211. }
  212. void writef(const char* _format, ...)
  213. {
  214. if (NULL != m_file)
  215. {
  216. va_list argList;
  217. va_start(argList, _format);
  218. char temp[2048];
  219. int len = vsnprintf(temp, sizeof(temp), _format, argList);
  220. fwrite(temp, len, 1, m_file);
  221. va_end(argList);
  222. }
  223. }
  224. void write(const char* _str)
  225. {
  226. if (NULL != m_file)
  227. {
  228. fwrite(_str, strlen(_str), 1, m_file);
  229. }
  230. }
  231. void write(const void* _data, size_t _size)
  232. {
  233. if (NULL != m_file)
  234. {
  235. fwrite(_data, _size, 1, m_file);
  236. }
  237. }
  238. private:
  239. std::string m_filePath;
  240. FILE* m_file;
  241. bool m_bigEndian;
  242. };
  243. class Bin2cStream : public IStreamWriter
  244. {
  245. public:
  246. Bin2cStream(const char* _filePath, const char* _name)
  247. : m_filePath(_filePath)
  248. , m_name(_name)
  249. , m_file(NULL)
  250. {
  251. }
  252. ~Bin2cStream()
  253. {
  254. }
  255. bool open()
  256. {
  257. BX_CHECK(NULL == m_file, "Still open!");
  258. m_file = fopen(m_filePath.c_str(), "wb");
  259. return NULL != m_file;
  260. }
  261. void close()
  262. {
  263. if (NULL != m_file)
  264. {
  265. #define HEX_DUMP_WIDTH 16
  266. #define HEX_DUMP_SPACE_WIDTH 96
  267. #define HEX_DUMP_FORMAT "%-" BX_STRINGIZE(HEX_DUMP_SPACE_WIDTH) "." BX_STRINGIZE(HEX_DUMP_SPACE_WIDTH) "s"
  268. const uint8_t* data = &m_buffer[0];
  269. uint32_t size = m_buffer.size();
  270. fprintf(m_file, "static const uint8_t %s[%d] =\n{\n", m_name.c_str(), size);
  271. if (NULL != data)
  272. {
  273. char hex[HEX_DUMP_SPACE_WIDTH+1];
  274. char ascii[HEX_DUMP_WIDTH+1];
  275. uint32_t hexPos = 0;
  276. uint32_t asciiPos = 0;
  277. for (uint32_t ii = 0; ii < size; ++ii)
  278. {
  279. _snprintf(&hex[hexPos], sizeof(hex)-hexPos, "0x%02x, ", data[asciiPos]);
  280. hexPos += 6;
  281. ascii[asciiPos] = isprint(data[asciiPos]) && data[asciiPos] != '\\' ? data[asciiPos] : '.';
  282. asciiPos++;
  283. if (HEX_DUMP_WIDTH == asciiPos)
  284. {
  285. ascii[asciiPos] = '\0';
  286. fprintf(m_file, "\t" HEX_DUMP_FORMAT "// %s\n", hex, ascii);
  287. data += asciiPos;
  288. hexPos = 0;
  289. asciiPos = 0;
  290. }
  291. }
  292. if (0 != asciiPos)
  293. {
  294. ascii[asciiPos] = '\0';
  295. fprintf(m_file, "\t" HEX_DUMP_FORMAT "// %s\n", hex, ascii);
  296. }
  297. }
  298. fprintf(m_file, "};\n");
  299. #undef HEX_DUMP_WIDTH
  300. #undef HEX_DUMP_SPACE_WIDTH
  301. #undef HEX_DUMP_FORMAT
  302. fclose(m_file);
  303. m_file = NULL;
  304. }
  305. }
  306. void writef(const char* _format, ...)
  307. {
  308. va_list argList;
  309. va_start(argList, _format);
  310. char temp[2048];
  311. int len = vsnprintf(temp, sizeof(temp), _format, argList);
  312. m_buffer.insert(m_buffer.end(), temp, temp+len);
  313. va_end(argList);
  314. }
  315. void write(const char* _str)
  316. {
  317. m_buffer.insert(m_buffer.end(), _str, _str+strlen(_str) );
  318. }
  319. void write(const void* _data, size_t _size)
  320. {
  321. const char* data = (const char*)_data;
  322. m_buffer.insert(m_buffer.end(), data, data+_size);
  323. }
  324. private:
  325. std::string m_filePath;
  326. std::string m_name;
  327. typedef std::vector<uint8_t> Buffer;
  328. Buffer m_buffer;
  329. FILE* m_file;
  330. };
  331. class LineReader
  332. {
  333. public:
  334. LineReader(const char* _str)
  335. : m_str(_str)
  336. , m_pos(0)
  337. , m_size( (uint32_t)strlen(_str) )
  338. {
  339. }
  340. std::string getLine()
  341. {
  342. const char* str = &m_str[m_pos];
  343. skipLine();
  344. const char* eol = &m_str[m_pos];
  345. std::string tmp;
  346. tmp.assign(str, eol-str);
  347. return tmp;
  348. }
  349. bool isEof() const
  350. {
  351. return m_str[m_pos] == '\0';
  352. }
  353. private:
  354. void skipLine()
  355. {
  356. const char* str = &m_str[m_pos];
  357. const char* eol = strstr(str, "\n\r");
  358. if (NULL != eol)
  359. {
  360. m_pos += eol-str+2;
  361. return;
  362. }
  363. eol = strstr(str, "\n");
  364. if (NULL != eol)
  365. {
  366. m_pos += eol-str+1;
  367. return;
  368. }
  369. m_pos += (uint32_t)strlen(str);
  370. }
  371. const char* m_str;
  372. uint32_t m_pos;
  373. uint32_t m_size;
  374. };
  375. void printCode(const char* _code)
  376. {
  377. fprintf(stderr, "Code:\n---\n");
  378. LineReader lr(_code);
  379. for (uint32_t line = 1; !lr.isEof(); ++line)
  380. {
  381. fprintf(stderr, "%3d: %s", line, lr.getLine().c_str() );
  382. }
  383. fprintf(stderr, "---\n");
  384. }
  385. bool compileGLSLShader(CommandLine& _cmdLine, const std::string& _code, IStreamWriter& _stream)
  386. {
  387. const glslopt_shader_type type = tolower(_cmdLine.findOption('\0', "type")[0]) == 'f' ? kGlslOptShaderFragment : kGlslOptShaderVertex;
  388. glslopt_ctx* ctx = glslopt_initialize(false);
  389. glslopt_shader* shader = glslopt_optimize(ctx, type, _code.c_str(), 0);
  390. if( !glslopt_get_status(shader) )
  391. {
  392. printCode(_code.c_str() );
  393. fprintf(stderr, "Error: %s\n", glslopt_get_log(shader) );
  394. glslopt_cleanup(ctx);
  395. return false;
  396. }
  397. const char* optimizedShader = glslopt_get_output(shader);
  398. const char* profile = _cmdLine.findOption('p');
  399. if (NULL == profile)
  400. {
  401. _stream.write("#ifdef GL_ES\n");
  402. _stream.write("precision highp float;\n");
  403. _stream.write("#endif // GL_ES\n\n");
  404. }
  405. else
  406. {
  407. _stream.writef("#version %s\n\n", profile);
  408. }
  409. _stream.write(optimizedShader, strlen(optimizedShader) );
  410. uint8_t nul = 0;
  411. _stream.write(nul);
  412. glslopt_cleanup(ctx);
  413. return true;
  414. }
  415. bool compileHLSLShaderDx9(CommandLine& _cmdLine, const std::string& _code, IStreamWriter& _stream)
  416. {
  417. #if BX_PLATFORM_WINDOWS
  418. const char* profile = _cmdLine.findOption('p');
  419. if (NULL == profile)
  420. {
  421. printf("Shader profile must be specified.\n");
  422. return false;
  423. }
  424. bool bigEndian = _cmdLine.hasArg('\0', "xbox360");
  425. uint32_t flags = 0;
  426. flags |= _cmdLine.hasArg('\0', "debug") ? D3DXSHADER_DEBUG : 0;
  427. flags |= _cmdLine.hasArg('\0', "avoid-flow-control") ? D3DXSHADER_AVOID_FLOW_CONTROL : 0;
  428. flags |= _cmdLine.hasArg('\0', "no-preshader") ? D3DXSHADER_NO_PRESHADER : 0;
  429. flags |= _cmdLine.hasArg('\0', "partial-precision") ? D3DXSHADER_PARTIALPRECISION : 0;
  430. flags |= _cmdLine.hasArg('\0', "prefer-flow-control") ? D3DXSHADER_PREFER_FLOW_CONTROL : 0;
  431. flags |= _cmdLine.hasArg('\0', "backwards-compatibility") ? D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY : 0;
  432. bool werror = _cmdLine.hasArg('\0', "Werror");
  433. uint32_t optimization = 3;
  434. if (_cmdLine.hasArg(optimization, 'O') )
  435. {
  436. optimization = bx::uint32_min(optimization, countof(s_optimizationLevelDx9)-1);
  437. flags |= s_optimizationLevelDx9[optimization];
  438. }
  439. else
  440. {
  441. flags |= D3DXSHADER_SKIPOPTIMIZATION;
  442. }
  443. BX_TRACE("Profile: %s", profile);
  444. BX_TRACE("Flags: 0x%08x", flags);
  445. BX_TRACE("Big Endian: %s", bigEndian?"true":"false");
  446. LPD3DXBUFFER code;
  447. LPD3DXBUFFER errorMsg;
  448. LPD3DXCONSTANTTABLE constantTable;
  449. HRESULT hr = D3DXCompileShader(_code.c_str()
  450. , _code.size()
  451. , NULL
  452. , NULL
  453. , "main"
  454. , profile
  455. , flags
  456. , &code
  457. , &errorMsg
  458. , &constantTable
  459. );
  460. if (FAILED(hr)
  461. || werror && NULL != errorMsg)
  462. {
  463. printCode(_code.c_str() );
  464. fprintf(stderr, "Error: 0x%08x %s\n", hr, errorMsg->GetBufferPointer() );
  465. return false;
  466. }
  467. D3DXCONSTANTTABLE_DESC desc;
  468. hr = constantTable->GetDesc(&desc);
  469. if (FAILED(hr) )
  470. {
  471. fprintf(stderr, "Error 0x%08x\n", hr);
  472. return false;
  473. }
  474. BX_TRACE("Creator: %s 0x%08x", desc.Creator, desc.Version);
  475. BX_TRACE("Num constants: %d", desc.Constants);
  476. BX_TRACE("# cl ty RxC S By Name");
  477. UniformArray uniforms;
  478. for (uint32_t ii = 0; ii < desc.Constants; ++ii)
  479. {
  480. D3DXHANDLE handle = constantTable->GetConstant(NULL, ii);
  481. D3DXCONSTANT_DESC constDesc;
  482. uint32_t count;
  483. constantTable->GetConstantDesc(handle, &constDesc, &count);
  484. BX_TRACE("%3d %2d %2d [%dx%d] %d %3d %s[%d] c%d (%d)"
  485. , ii
  486. , constDesc.Class
  487. , constDesc.Type
  488. , constDesc.Rows
  489. , constDesc.Columns
  490. , constDesc.StructMembers
  491. , constDesc.Bytes
  492. , constDesc.Name
  493. , constDesc.Elements
  494. , constDesc.RegisterIndex
  495. , constDesc.RegisterCount
  496. );
  497. ConstantType::Enum type = findConstantTypeDx9(constDesc);
  498. if (ConstantType::Count != type)
  499. {
  500. Uniform un;
  501. un.name = '$' == constDesc.Name[0] ? constDesc.Name+1 : constDesc.Name;
  502. un.type = type;
  503. un.num = constDesc.Elements;
  504. un.regIndex = constDesc.RegisterIndex;
  505. un.regCount = constDesc.RegisterCount;
  506. uniforms.push_back(un);
  507. }
  508. }
  509. uint16_t count = (uint16_t)uniforms.size();
  510. _stream.write(count);
  511. uint32_t fragmentBit = profile[0] == 'p' ? ConstantType::FragmentBit : 0;
  512. for (UniformArray::const_iterator it = uniforms.begin(); it != uniforms.end(); ++it)
  513. {
  514. const Uniform& un = *it;
  515. uint8_t nameSize = (uint8_t)un.name.size();
  516. _stream.write(nameSize);
  517. _stream.write(un.name.c_str(), nameSize);
  518. _stream.write<uint8_t>(un.type|fragmentBit);
  519. _stream.write(un.num);
  520. _stream.write(un.regIndex);
  521. _stream.write(un.regCount);
  522. BX_TRACE("%s, %s, %d, %d, %d"
  523. , un.name.c_str()
  524. , s_constantTypeName[un.type]
  525. , un.num
  526. , un.regIndex
  527. , un.regCount
  528. );
  529. }
  530. uint16_t shaderSize = (uint16_t)code->GetBufferSize();
  531. _stream.write(shaderSize);
  532. _stream.write(code->GetBufferPointer(), shaderSize);
  533. uint8_t nul = 0;
  534. _stream.write(nul);
  535. if (NULL != code)
  536. {
  537. code->Release();
  538. }
  539. if (NULL != errorMsg)
  540. {
  541. errorMsg->Release();
  542. }
  543. if (NULL != constantTable)
  544. {
  545. constantTable->Release();
  546. }
  547. return true;
  548. #else
  549. fprintf(stderr, "HLSL compiler is not supported on this platform.\n");
  550. return false;
  551. #endif // BX_PLATFORM_WINDOWS
  552. }
  553. bool compileHLSLShaderDx11(CommandLine& _cmdLine, const std::string& _code, IStreamWriter& _stream)
  554. {
  555. #if BX_PLATFORM_WINDOWS
  556. const char* profile = _cmdLine.findOption('p');
  557. if (NULL == profile)
  558. {
  559. printf("Shader profile must be specified.\n");
  560. return false;
  561. }
  562. bool bigEndian = _cmdLine.hasArg('\0', "xbox360");
  563. uint32_t flags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY;
  564. flags |= _cmdLine.hasArg('\0', "debug") ? D3DCOMPILE_DEBUG : 0;
  565. flags |= _cmdLine.hasArg('\0', "avoid-flow-control") ? D3DCOMPILE_AVOID_FLOW_CONTROL : 0;
  566. flags |= _cmdLine.hasArg('\0', "no-preshader") ? D3DCOMPILE_NO_PRESHADER : 0;
  567. flags |= _cmdLine.hasArg('\0', "partial-precision") ? D3DCOMPILE_PARTIAL_PRECISION : 0;
  568. flags |= _cmdLine.hasArg('\0', "prefer-flow-control") ? D3DCOMPILE_PREFER_FLOW_CONTROL : 0;
  569. flags |= _cmdLine.hasArg('\0', "backwards-compatibility") ? D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY : 0;
  570. bool werror = _cmdLine.hasArg('\0', "Werror");
  571. if (werror)
  572. {
  573. flags |= D3DCOMPILE_WARNINGS_ARE_ERRORS;
  574. }
  575. uint32_t optimization = 3;
  576. if (_cmdLine.hasArg(optimization, 'O') )
  577. {
  578. optimization = bx::uint32_min(optimization, countof(s_optimizationLevelDx11)-1);
  579. flags |= s_optimizationLevelDx11[optimization];
  580. }
  581. else
  582. {
  583. flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
  584. }
  585. BX_TRACE("Profile: %s", profile);
  586. BX_TRACE("Flags: 0x%08x", flags);
  587. BX_TRACE("Big Endian: %s", bigEndian?"true":"false");
  588. ID3DBlob* code;
  589. ID3DBlob* errorMsg;
  590. HRESULT hr = D3DCompile(_code.c_str()
  591. , _code.size()
  592. , NULL
  593. , NULL
  594. , NULL
  595. , "main"
  596. , profile
  597. , flags
  598. , 0
  599. , &code
  600. , &errorMsg
  601. );
  602. if (FAILED(hr)
  603. || werror && NULL != errorMsg)
  604. {
  605. printCode(_code.c_str() );
  606. fprintf(stderr, BX_FILE_LINE_LITERAL "Error: 0x%08x %s\n", hr, errorMsg->GetBufferPointer() );
  607. return false;
  608. }
  609. UniformArray uniforms;
  610. ID3D11ShaderReflection* reflect = NULL;
  611. hr = D3DReflect(code->GetBufferPointer()
  612. , code->GetBufferSize()
  613. , IID_ID3D11ShaderReflection
  614. , (void**)&reflect
  615. );
  616. if (FAILED(hr) )
  617. {
  618. fprintf(stderr, BX_FILE_LINE_LITERAL "Error: 0x%08x\n", hr);
  619. return false;
  620. }
  621. D3D11_SHADER_DESC desc;
  622. hr = reflect->GetDesc(&desc);
  623. if (FAILED(hr) )
  624. {
  625. fprintf(stderr, BX_FILE_LINE_LITERAL "Error: 0x%08x\n", hr);
  626. return false;
  627. }
  628. BX_TRACE("Creator: %s 0x%08x", desc.Creator, desc.Version);
  629. BX_TRACE("Num constant buffers: %d", desc.ConstantBuffers);
  630. BX_TRACE("# cl ty RxC S By Name");
  631. // bx::HashMurmur2A hash;
  632. // hash.begin();
  633. BX_TRACE("Input:");
  634. for (uint32_t ii = 0; ii < desc.InputParameters; ++ii)
  635. {
  636. D3D11_SIGNATURE_PARAMETER_DESC spd;
  637. reflect->GetInputParameterDesc(ii, &spd);
  638. BX_TRACE("\t%2d: %s%d, %d, %d", ii, spd.SemanticName, spd.SemanticIndex, spd.SystemValueType, spd.ComponentType);
  639. // hash.add(inputSignature->GetBufferPointer(), inputSignature->GetBufferSize() );
  640. }
  641. BX_TRACE("Output:");
  642. for (uint32_t ii = 0; ii < desc.OutputParameters; ++ii)
  643. {
  644. D3D11_SIGNATURE_PARAMETER_DESC spd;
  645. reflect->GetOutputParameterDesc(ii, &spd);
  646. BX_TRACE("\t%2d: %s%d, %d, %d", ii, spd.SemanticName, spd.SemanticIndex, spd.SystemValueType, spd.ComponentType);
  647. // hash.add(inputSignature->GetBufferPointer(), inputSignature->GetBufferSize() );
  648. }
  649. // uint32_t inputSignatureHash = hash.end();
  650. uint16_t size = 0;
  651. for (uint32_t ii = 0; ii < bx::uint32_min(1, desc.ConstantBuffers); ++ii)
  652. {
  653. ID3D11ShaderReflectionConstantBuffer* cbuffer = reflect->GetConstantBufferByIndex(ii);
  654. D3D11_SHADER_BUFFER_DESC bufferDesc;
  655. hr = cbuffer->GetDesc(&bufferDesc);
  656. size = (uint16_t)bufferDesc.Size;
  657. if (SUCCEEDED(hr) )
  658. {
  659. BX_TRACE("%s, %d, vars %d, size %d"
  660. , bufferDesc.Name
  661. , bufferDesc.Type
  662. , bufferDesc.Variables
  663. , bufferDesc.Size
  664. );
  665. for (uint32_t jj = 0; jj < bufferDesc.Variables; ++jj)
  666. {
  667. ID3D11ShaderReflectionVariable* var = cbuffer->GetVariableByIndex(jj);
  668. ID3D11ShaderReflectionType* type = var->GetType();
  669. D3D11_SHADER_VARIABLE_DESC varDesc;
  670. hr = var->GetDesc(&varDesc);
  671. if (SUCCEEDED(hr) )
  672. {
  673. D3D11_SHADER_TYPE_DESC constDesc;
  674. hr = type->GetDesc(&constDesc);
  675. if (SUCCEEDED(hr) )
  676. {
  677. ConstantType::Enum type = findConstantTypeDx11(constDesc, varDesc.Size);
  678. if (ConstantType::Count != type
  679. && 0 != (varDesc.uFlags & D3D10_SVF_USED) )
  680. {
  681. Uniform un;
  682. un.name = varDesc.Name;
  683. un.type = type;
  684. un.num = constDesc.Elements;
  685. un.regIndex = varDesc.StartOffset;
  686. un.regCount = varDesc.Size;
  687. uniforms.push_back(un);
  688. BX_TRACE("\t%s, %d, size %d, flags 0x%08x, %d"
  689. , varDesc.Name
  690. , varDesc.StartOffset
  691. , varDesc.Size
  692. , varDesc.uFlags
  693. , type
  694. );
  695. }
  696. }
  697. }
  698. }
  699. }
  700. }
  701. uint16_t count = (uint16_t)uniforms.size();
  702. _stream.write(count);
  703. _stream.write(size);
  704. uint32_t fragmentBit = profile[0] == 'p' ? ConstantType::FragmentBit : 0;
  705. for (UniformArray::const_iterator it = uniforms.begin(); it != uniforms.end(); ++it)
  706. {
  707. const Uniform& un = *it;
  708. uint8_t nameSize = (uint8_t)un.name.size();
  709. _stream.write(nameSize);
  710. _stream.write(un.name.c_str(), nameSize);
  711. _stream.write<uint8_t>(un.type|fragmentBit);
  712. _stream.write(un.num);
  713. _stream.write(un.regIndex);
  714. _stream.write(un.regCount);
  715. BX_TRACE("%s, %s, %d, %d, %d"
  716. , un.name.c_str()
  717. , s_constantTypeName[un.type]
  718. , un.num
  719. , un.regIndex
  720. , un.regCount
  721. );
  722. }
  723. uint16_t shaderSize = (uint16_t)code->GetBufferSize();
  724. _stream.write(shaderSize);
  725. _stream.write(code->GetBufferPointer(), shaderSize);
  726. uint8_t nul = 0;
  727. _stream.write(nul);
  728. if (NULL != reflect)
  729. {
  730. reflect->Release();
  731. }
  732. if (NULL != code)
  733. {
  734. code->Release();
  735. }
  736. if (NULL != errorMsg)
  737. {
  738. errorMsg->Release();
  739. }
  740. return true;
  741. #else
  742. fprintf(stderr, "HLSL compiler is not supported on this platform.\n");
  743. return false;
  744. #endif // BX_PLATFORM_WINDOWS
  745. }
  746. struct Preprocessor
  747. {
  748. Preprocessor(const char* _filePath)
  749. : m_tagptr(m_tags)
  750. , m_scratchPos(0)
  751. , m_fgetsPos(0)
  752. {
  753. m_filePath = scratch(_filePath);
  754. m_tagptr->tag = FPPTAG_USERDATA;
  755. m_tagptr->data = this;
  756. m_tagptr++;
  757. m_tagptr->tag = FPPTAG_DEPENDS;
  758. m_tagptr->data = (void*)fppDepends;
  759. m_tagptr++;
  760. m_tagptr->tag = FPPTAG_INPUT;
  761. m_tagptr->data = (void*)fppInput;
  762. m_tagptr++;
  763. m_tagptr->tag = FPPTAG_OUTPUT;
  764. m_tagptr->data = (void*)fppOutput;
  765. m_tagptr++;
  766. m_tagptr->tag = FPPTAG_ERROR;
  767. m_tagptr->data = (void*)fppError;
  768. m_tagptr++;
  769. m_tagptr->tag = FPPTAG_IGNOREVERSION;
  770. m_tagptr->data = (void*)0;
  771. m_tagptr++;
  772. m_tagptr->tag = FPPTAG_LINE;
  773. m_tagptr->data = (void*)0;
  774. m_tagptr++;
  775. m_tagptr->tag = FPPTAG_INPUT_NAME;
  776. m_tagptr->data = m_filePath;
  777. m_tagptr++;
  778. m_default = "#define lowp\n#define mediump\n#define highp\n";
  779. }
  780. void setDefine(const char* _define)
  781. {
  782. m_tagptr->tag = FPPTAG_DEFINE;
  783. m_tagptr->data = scratch(_define);
  784. m_tagptr++;
  785. }
  786. void setDefaultDefine(const char* _name)
  787. {
  788. char temp[1024];
  789. _snprintf(temp, countof(temp)
  790. , "#ifndef %s\n"
  791. "# define %s 0\n"
  792. "#endif // %s\n"
  793. "\n"
  794. , _name
  795. , _name
  796. , _name
  797. );
  798. m_default += temp;
  799. }
  800. void addDependency(const char* _fileName)
  801. {
  802. m_depends += " \\\n ";
  803. m_depends += _fileName;
  804. }
  805. bool run()
  806. {
  807. m_fgetsPos = 0;
  808. FILE* file = fopen(m_filePath, "r");
  809. if (NULL == file)
  810. {
  811. return false;
  812. }
  813. long int size = fsize(file);
  814. char* input = new char[size+1];
  815. size = fread(input, 1, size, file);
  816. input[size] = '\0';
  817. fclose(file);
  818. m_input = m_default;
  819. m_input += input;
  820. fppTag* tagptr = m_tagptr;
  821. tagptr->tag = FPPTAG_END;
  822. tagptr->data = 0;
  823. tagptr++;
  824. int result = fppPreProcess(m_tags);
  825. return 0 == result;
  826. }
  827. char* fgets(char* _buffer, int _size)
  828. {
  829. int ii = 0;
  830. for (char ch = m_input[m_fgetsPos]; m_fgetsPos < m_input.size() && ii < _size-1; ch = m_input[++m_fgetsPos])
  831. {
  832. _buffer[ii++] = ch;
  833. if (ch == '\n' || ii == _size)
  834. {
  835. _buffer[ii] = '\0';
  836. m_fgetsPos++;
  837. return _buffer;
  838. }
  839. }
  840. return NULL;
  841. }
  842. static void fppDepends(char* _fileName, void* _userData)
  843. {
  844. Preprocessor* thisClass = (Preprocessor*)_userData;
  845. thisClass->addDependency(_fileName);
  846. }
  847. static char* fppInput(char* _buffer, int _size, void* _userData)
  848. {
  849. Preprocessor* thisClass = (Preprocessor*)_userData;
  850. return thisClass->fgets(_buffer, _size);
  851. }
  852. static void fppOutput(int _ch, void* _userData)
  853. {
  854. Preprocessor* thisClass = (Preprocessor*)_userData;
  855. thisClass->m_preprocessed += _ch;
  856. }
  857. static void fppError(void* _userData, char* _format, va_list _vargs)
  858. {
  859. vfprintf(stderr, _format, _vargs);
  860. }
  861. char* scratch(const char* _str)
  862. {
  863. char* result = &m_scratch[m_scratchPos];
  864. strcpy(result, _str);
  865. m_scratchPos += strlen(_str)+1;
  866. return result;
  867. }
  868. fppTag m_tags[MAX_TAGS];
  869. fppTag* m_tagptr;
  870. char* m_filePath;
  871. std::string m_depends;
  872. std::string m_default;
  873. std::string m_input;
  874. std::string m_preprocessed;
  875. char m_scratch[16<<10];
  876. uint32_t m_scratchPos;
  877. uint32_t m_fgetsPos;
  878. };
  879. const char* baseName(const char* _filePath)
  880. {
  881. const char* bs = strrchr(_filePath, '\\');
  882. const char* fs = strrchr(_filePath, '/');
  883. const char* column = strrchr(_filePath, ':');
  884. const char* basename = std::max(std::max(bs, fs), column);
  885. if (NULL != basename)
  886. {
  887. return basename+1;
  888. }
  889. return _filePath;
  890. }
  891. // OpenGL #version Features Direct3D Features Shader Model
  892. // 2.1 120 vf 9.0 vf 2.0
  893. // 3.0 130
  894. // 3.1 140
  895. // 3.2 150 vgf
  896. // 3.3 330 10.0 vgf 4.0
  897. // 4.0 400 vhdgf
  898. // 4.1 410
  899. // 4.2 420 11.0 vhdgf 5.0
  900. int main(int _argc, const char* _argv[])
  901. {
  902. CommandLine cmdLine(_argc, _argv);
  903. const char* filePath = cmdLine.findOption('f');
  904. if (NULL == filePath)
  905. {
  906. fprintf(stderr, "Shader file name must be specified.\n");
  907. return EXIT_FAILURE;
  908. }
  909. const char* outFilePath = cmdLine.findOption('o');
  910. if (NULL == outFilePath)
  911. {
  912. fprintf(stderr, "Output file name must be specified.\n");
  913. return EXIT_FAILURE;
  914. }
  915. const char* type = cmdLine.findOption('\0', "type");
  916. if (NULL == type)
  917. {
  918. fprintf(stderr, "Must specify shader type.");
  919. return EXIT_FAILURE;
  920. }
  921. const char* platform = cmdLine.findOption('\0', "platform");
  922. if (NULL == platform)
  923. {
  924. fprintf(stderr, "Must specify platform.\n");
  925. return EXIT_FAILURE;
  926. }
  927. const char* bin2c = NULL;
  928. if (cmdLine.hasArg("bin2c") )
  929. {
  930. bin2c = cmdLine.findOption("bin2c");
  931. if (NULL == bin2c)
  932. {
  933. bin2c = baseName(outFilePath);
  934. uint32_t len = strlen(bin2c);
  935. char* temp = (char*)alloca(len+1);
  936. for (char *out = temp; *bin2c != '\0';)
  937. {
  938. char ch = *bin2c++;
  939. if (isalnum(ch) )
  940. {
  941. *out++ = ch;
  942. }
  943. else
  944. {
  945. *out++ = '_';
  946. }
  947. }
  948. temp[len] = '\0';
  949. bin2c = temp;
  950. }
  951. }
  952. bool depends = cmdLine.hasArg("depends");
  953. bool preprocessOnly = cmdLine.hasArg("preprocess");
  954. Preprocessor preprocessor(filePath);
  955. preprocessor.setDefaultDefine("BX_PLATFORM_ANDROID");
  956. preprocessor.setDefaultDefine("BX_PLATFORM_IOS");
  957. preprocessor.setDefaultDefine("BX_PLATFORM_LINUX");
  958. preprocessor.setDefaultDefine("BX_PLATFORM_NACL");
  959. preprocessor.setDefaultDefine("BX_PLATFORM_OSX");
  960. preprocessor.setDefaultDefine("BX_PLATFORM_WINDOWS");
  961. preprocessor.setDefaultDefine("BX_PLATFORM_XBOX360");
  962. preprocessor.setDefaultDefine("BGFX_SHADER_LANGUAGE_GLSL");
  963. preprocessor.setDefaultDefine("BGFX_SHADER_LANGUAGE_HLSL");
  964. preprocessor.setDefaultDefine("BGFX_SHADER_TYPE_FRAGMENT");
  965. preprocessor.setDefaultDefine("BGFX_SHADER_TYPE_VERTEX");
  966. bool glsl = false;
  967. if (0 == _stricmp(platform, "android") )
  968. {
  969. preprocessor.setDefine("BX_PLATFORM_ANDROID=1");
  970. preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1");
  971. glsl = true;
  972. }
  973. else if (0 == _stricmp(platform, "ios") )
  974. {
  975. preprocessor.setDefine("BX_PLATFORM_IOS=1");
  976. preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1");
  977. glsl = true;
  978. }
  979. else if (0 == _stricmp(platform, "linux") )
  980. {
  981. preprocessor.setDefine("BX_PLATFORM_IOS=1");
  982. preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1");
  983. glsl = true;
  984. }
  985. else if (0 == _stricmp(platform, "nacl") )
  986. {
  987. preprocessor.setDefine("BX_PLATFORM_NACL=1");
  988. preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1");
  989. glsl = true;
  990. }
  991. else if (0 == _stricmp(platform, "osx") )
  992. {
  993. preprocessor.setDefine("BX_PLATFORM_OSX=1");
  994. preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1");
  995. glsl = true;
  996. }
  997. else if (0 == _stricmp(platform, "windows") )
  998. {
  999. preprocessor.setDefine("BX_PLATFORM_WINDOWS=1");
  1000. preprocessor.setDefine("BGFX_SHADER_LANGUAGE_HLSL=1");
  1001. }
  1002. else if (0 == _stricmp(platform, "xbox360") )
  1003. {
  1004. preprocessor.setDefine("BX_PLATFORM_XBOX360=1");
  1005. preprocessor.setDefine("BGFX_SHADER_LANGUAGE_HLSL=1");
  1006. }
  1007. else
  1008. {
  1009. fprintf(stderr, "Unknown platform %s?!", platform);
  1010. return EXIT_FAILURE;
  1011. }
  1012. switch (tolower(type[0]) )
  1013. {
  1014. case 'f':
  1015. preprocessor.setDefine("BGFX_SHADER_TYPE_FRAGMENT=1");
  1016. break;
  1017. case 'v':
  1018. preprocessor.setDefine("BGFX_SHADER_TYPE_VERTEX=1");
  1019. break;
  1020. default:
  1021. fprintf(stderr, "Unknown type: %s?!", type);
  1022. return EXIT_FAILURE;
  1023. }
  1024. if (preprocessor.run() )
  1025. {
  1026. BX_TRACE("Input file: %s", filePath);
  1027. BX_TRACE("Output file: %s", outFilePath);
  1028. if (preprocessOnly)
  1029. {
  1030. FileWriter stream(outFilePath);
  1031. if (!stream.open() )
  1032. {
  1033. fprintf(stderr, "Unable to open output file '%s'.", outFilePath);
  1034. return false;
  1035. }
  1036. if (glsl)
  1037. {
  1038. const char* profile = cmdLine.findOption('p');
  1039. if (NULL == profile)
  1040. {
  1041. stream.write("#ifdef GL_ES\n");
  1042. stream.write("precision highp float;\n");
  1043. stream.write("#endif // GL_ES\n\n");
  1044. }
  1045. else
  1046. {
  1047. stream.writef("#version %s\n\n", profile);
  1048. }
  1049. }
  1050. stream.write(preprocessor.m_preprocessed.c_str(), preprocessor.m_preprocessed.size() );
  1051. stream.close();
  1052. return EXIT_SUCCESS;
  1053. }
  1054. bool compiled = false;
  1055. {
  1056. IStreamWriter* stream = NULL;
  1057. if (NULL != bin2c)
  1058. {
  1059. stream = new Bin2cStream(outFilePath, bin2c);
  1060. }
  1061. else
  1062. {
  1063. stream = new FileWriter(outFilePath);
  1064. }
  1065. if (!stream->open() )
  1066. {
  1067. fprintf(stderr, "Unable to open output file '%s'.", outFilePath);
  1068. return false;
  1069. }
  1070. if (glsl)
  1071. {
  1072. compiled = compileGLSLShader(cmdLine, preprocessor.m_preprocessed, *stream);
  1073. }
  1074. else
  1075. {
  1076. const char* profile = cmdLine.findOption('p');
  1077. if (0 == strncmp(&profile[1], "s_4", 3)
  1078. || 0 == strncmp(&profile[1], "s_5", 3) )
  1079. {
  1080. compiled = compileHLSLShaderDx11(cmdLine, preprocessor.m_preprocessed, *stream);
  1081. }
  1082. else
  1083. {
  1084. compiled = compileHLSLShaderDx9(cmdLine, preprocessor.m_preprocessed, *stream);
  1085. }
  1086. }
  1087. stream->close();
  1088. delete stream;
  1089. }
  1090. if (compiled
  1091. && depends)
  1092. {
  1093. std::string ofp = outFilePath;
  1094. ofp += ".d";
  1095. FileWriter stream(ofp.c_str() );
  1096. if (stream.open() )
  1097. {
  1098. stream.write(outFilePath);
  1099. stream.write(":");
  1100. stream.write(preprocessor.m_depends.c_str() );
  1101. stream.write("\n");
  1102. stream.close();
  1103. }
  1104. }
  1105. return EXIT_SUCCESS;
  1106. }
  1107. fprintf(stderr, "Failed to build shader.\n");
  1108. return EXIT_FAILURE;
  1109. }