shaderc_spirv.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. /*
  2. * Copyright 2011-2016 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  4. */
  5. #include "shaderc.h"
  6. BX_PRAGMA_DIAGNOSTIC_PUSH()
  7. BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4265) // error C4265: 'spv::spirvbin_t': class has virtual functions, but destructor is not virtual
  8. #include <ShaderLang.h>
  9. #include <ResourceLimits.h>
  10. #include <SPIRV/SPVRemapper.h>
  11. //#include <spirv-tools/libspirv.hpp>
  12. //#include <spirv-tools/optimizer.hpp>
  13. BX_PRAGMA_DIAGNOSTIC_POP()
  14. namespace bgfx
  15. {
  16. static bx::CrtAllocator s_allocator;
  17. bx::AllocatorI* g_allocator = &s_allocator;
  18. struct TinyStlAllocator
  19. {
  20. static void* static_allocate(size_t _bytes);
  21. static void static_deallocate(void* _ptr, size_t /*_bytes*/);
  22. };
  23. void* TinyStlAllocator::static_allocate(size_t _bytes)
  24. {
  25. return BX_ALLOC(g_allocator, _bytes);
  26. }
  27. void TinyStlAllocator::static_deallocate(void* _ptr, size_t /*_bytes*/)
  28. {
  29. if (NULL != _ptr)
  30. {
  31. BX_FREE(g_allocator, _ptr);
  32. }
  33. }
  34. } // namespace bgfx
  35. #define TINYSTL_ALLOCATOR bgfx::TinyStlAllocator
  36. #include <tinystl/allocator.h>
  37. #include <tinystl/string.h>
  38. #include <tinystl/unordered_map.h>
  39. #include <tinystl/vector.h>
  40. namespace stl = tinystl;
  41. #include "../../src/shader_spirv.h"
  42. namespace glslang
  43. {
  44. void GlslangToSpv(const glslang::TIntermediate& _intermediate, std::vector<uint32_t>& _spirv);
  45. } // namespace glslang
  46. namespace bgfx { namespace spirv
  47. {
  48. const TBuiltInResource resourceLimits =
  49. {
  50. 32, // MaxLights
  51. 6, // MaxClipPlanes
  52. 32, // MaxTextureUnits
  53. 32, // MaxTextureCoords
  54. 64, // MaxVertexAttribs
  55. 4096, // MaxVertexUniformComponents
  56. 64, // MaxVaryingFloats
  57. 32, // MaxVertexTextureImageUnits
  58. 80, // MaxCombinedTextureImageUnits
  59. 32, // MaxTextureImageUnits
  60. 4096, // MaxFragmentUniformComponents
  61. 32, // MaxDrawBuffers
  62. 128, // MaxVertexUniformVectors
  63. 8, // MaxVaryingVectors
  64. 16, // MaxFragmentUniformVectors
  65. 16, // MaxVertexOutputVectors
  66. 15, // MaxFragmentInputVectors
  67. -8, // MinProgramTexelOffset
  68. 7, // MaxProgramTexelOffset
  69. 8, // MaxClipDistances
  70. 65535, // MaxComputeWorkGroupCountX
  71. 65535, // MaxComputeWorkGroupCountY
  72. 65535, // MaxComputeWorkGroupCountZ
  73. 1024, // MaxComputeWorkGroupSizeX
  74. 1024, // MaxComputeWorkGroupSizeY
  75. 64, // MaxComputeWorkGroupSizeZ
  76. 1024, // MaxComputeUniformComponents
  77. 16, // MaxComputeTextureImageUnits
  78. 8, // MaxComputeImageUniforms
  79. 8, // MaxComputeAtomicCounters
  80. 1, // MaxComputeAtomicCounterBuffers
  81. 60, // MaxVaryingComponents
  82. 64, // MaxVertexOutputComponents
  83. 64, // MaxGeometryInputComponents
  84. 128, // MaxGeometryOutputComponents
  85. 128, // MaxFragmentInputComponents
  86. 8, // MaxImageUnits
  87. 8, // MaxCombinedImageUnitsAndFragmentOutputs
  88. 8, // MaxCombinedShaderOutputResources
  89. 0, // MaxImageSamples
  90. 0, // MaxVertexImageUniforms
  91. 0, // MaxTessControlImageUniforms
  92. 0, // MaxTessEvaluationImageUniforms
  93. 0, // MaxGeometryImageUniforms
  94. 8, // MaxFragmentImageUniforms
  95. 8, // MaxCombinedImageUniforms
  96. 16, // MaxGeometryTextureImageUnits
  97. 256, // MaxGeometryOutputVertices
  98. 1024, // MaxGeometryTotalOutputComponents
  99. 1024, // MaxGeometryUniformComponents
  100. 64, // MaxGeometryVaryingComponents
  101. 128, // MaxTessControlInputComponents
  102. 128, // MaxTessControlOutputComponents
  103. 16, // MaxTessControlTextureImageUnits
  104. 1024, // MaxTessControlUniformComponents
  105. 4096, // MaxTessControlTotalOutputComponents
  106. 128, // MaxTessEvaluationInputComponents
  107. 128, // MaxTessEvaluationOutputComponents
  108. 16, // MaxTessEvaluationTextureImageUnits
  109. 1024, // MaxTessEvaluationUniformComponents
  110. 120, // MaxTessPatchComponents
  111. 32, // MaxPatchVertices
  112. 64, // MaxTessGenLevel
  113. 16, // MaxViewports
  114. 0, // MaxVertexAtomicCounters
  115. 0, // MaxTessControlAtomicCounters
  116. 0, // MaxTessEvaluationAtomicCounters
  117. 0, // MaxGeometryAtomicCounters
  118. 8, // MaxFragmentAtomicCounters
  119. 8, // MaxCombinedAtomicCounters
  120. 1, // MaxAtomicCounterBindings
  121. 0, // MaxVertexAtomicCounterBuffers
  122. 0, // MaxTessControlAtomicCounterBuffers
  123. 0, // MaxTessEvaluationAtomicCounterBuffers
  124. 0, // MaxGeometryAtomicCounterBuffers
  125. 1, // MaxFragmentAtomicCounterBuffers
  126. 1, // MaxCombinedAtomicCounterBuffers
  127. 16384, // MaxAtomicCounterBufferSize
  128. 4, // MaxTransformFeedbackBuffers
  129. 64, // MaxTransformFeedbackInterleavedComponents
  130. 8, // MaxCullDistances
  131. 8, // MaxCombinedClipAndCullDistances
  132. 4, // MaxSamples
  133. { // limits
  134. 1, // nonInductiveForLoops
  135. 1, // whileLoops
  136. 1, // doWhileLoops
  137. 1, // generalUniformIndexing
  138. 1, // generalAttributeMatrixVectorIndexing
  139. 1, // generalVaryingIndexing
  140. 1, // generalSamplerIndexing
  141. 1, // generalVariableIndexing
  142. 1, // generalConstantMatrixVectorIndexing
  143. },
  144. };
  145. bool printAsm(uint32_t _offset, const SpvInstruction& _instruction, void* _userData)
  146. {
  147. BX_UNUSED(_userData);
  148. char temp[512];
  149. toString(temp, sizeof(temp), _instruction);
  150. BX_TRACE("%5d: %s", _offset, temp);
  151. return true;
  152. }
  153. struct SpvReflection
  154. {
  155. struct TypeId
  156. {
  157. enum Enum
  158. {
  159. Void,
  160. Bool,
  161. Int32,
  162. Int64,
  163. Uint32,
  164. Uint64,
  165. Float,
  166. Double,
  167. Vector,
  168. Matrix,
  169. Count
  170. };
  171. TypeId()
  172. : baseType(Enum::Count)
  173. , type(Enum::Count)
  174. , numComponents(0)
  175. {
  176. }
  177. Enum baseType;
  178. Enum type;
  179. uint32_t numComponents;
  180. stl::string toString()
  181. {
  182. stl::string result;
  183. switch (type)
  184. {
  185. case Float:
  186. result.append("float");
  187. break;
  188. case Vector:
  189. bx::stringPrintf(result, "vec%d"
  190. , numComponents
  191. );
  192. break;
  193. case Matrix:
  194. bx::stringPrintf(result, "mat%d"
  195. , numComponents
  196. );
  197. default:
  198. break;
  199. }
  200. return result;
  201. }
  202. };
  203. struct Id
  204. {
  205. struct Variable
  206. {
  207. Variable()
  208. : decoration(SpvDecoration::Count)
  209. , builtin(SpvBuiltin::Count)
  210. , storageClass(SpvStorageClass::Count)
  211. , location(UINT32_MAX)
  212. , offset(UINT32_MAX)
  213. , type(UINT32_MAX)
  214. {
  215. }
  216. stl::string name;
  217. SpvDecoration::Enum decoration;
  218. SpvBuiltin::Enum builtin;
  219. SpvStorageClass::Enum storageClass;
  220. uint32_t location;
  221. uint32_t offset;
  222. uint32_t type;
  223. };
  224. typedef stl::vector<Variable> MemberArray;
  225. Variable var;
  226. MemberArray members;
  227. };
  228. typedef stl::unordered_map<uint32_t, TypeId> TypeIdMap;
  229. typedef stl::unordered_map<uint32_t, Id> IdMap;
  230. TypeIdMap typeIdMap;
  231. IdMap idMap;
  232. stl::string getTypeName(uint32_t _typeId)
  233. {
  234. return getTypeId(_typeId).toString();
  235. }
  236. Id& getId(uint32_t _id)
  237. {
  238. IdMap::iterator it = idMap.find(_id);
  239. if (it == idMap.end() )
  240. {
  241. Id id;
  242. stl::pair<IdMap::iterator, bool> result = idMap.insert(stl::make_pair(_id, id) );
  243. it = result.first;
  244. }
  245. return it->second;
  246. }
  247. Id::Variable& get(uint32_t _id, uint32_t _idx)
  248. {
  249. Id& id = getId(_id);
  250. id.members.resize(bx::uint32_max(_idx+1, uint32_t(id.members.size() ) ) );
  251. return id.members[_idx];
  252. }
  253. TypeId& getTypeId(uint32_t _id)
  254. {
  255. TypeIdMap::iterator it = typeIdMap.find(_id);
  256. if (it == typeIdMap.end() )
  257. {
  258. TypeId id;
  259. stl::pair<TypeIdMap::iterator, bool> result = typeIdMap.insert(stl::make_pair(_id, id) );
  260. it = result.first;
  261. }
  262. return it->second;
  263. }
  264. void update(uint32_t _id, const stl::string& _name)
  265. {
  266. getId(_id).var.name = _name;
  267. }
  268. BX_NO_INLINE void update(Id::Variable& _variable, SpvDecoration::Enum _decoration, uint32_t _literal)
  269. {
  270. _variable.decoration = _decoration;
  271. switch (_decoration)
  272. {
  273. case SpvDecoration::Location:
  274. _variable.location = _literal;
  275. break;
  276. case SpvDecoration::Offset:
  277. _variable.offset = _literal;
  278. break;
  279. case SpvDecoration::BuiltIn:
  280. _variable.builtin = SpvBuiltin::Enum(_literal);
  281. break;
  282. default:
  283. break;
  284. }
  285. }
  286. BX_NO_INLINE void update(Id::Variable& _variable, uint32_t _type, SpvStorageClass::Enum _storageClass)
  287. {
  288. _variable.type = _type;
  289. _variable.storageClass = _storageClass;
  290. }
  291. void update(uint32_t _id, SpvDecoration::Enum _decoration, uint32_t _literal)
  292. {
  293. update(getId(_id).var, _decoration, _literal);
  294. }
  295. void update(uint32_t _id, uint32_t _type, SpvStorageClass::Enum _storageClass)
  296. {
  297. update(getId(_id).var, _type, _storageClass);
  298. }
  299. void update(uint32_t _id, uint32_t _idx, const stl::string& _name)
  300. {
  301. Id::Variable& var = get(_id, _idx);
  302. var.name = _name;
  303. }
  304. BX_NO_INLINE void update(uint32_t _id, uint32_t _idx, SpvDecoration::Enum _decoration, uint32_t _literal)
  305. {
  306. update(get(_id, _idx), _decoration, _literal);
  307. }
  308. void update(uint32_t _id, TypeId::Enum _type)
  309. {
  310. TypeId& type = getTypeId(_id);
  311. type.type = _type;
  312. }
  313. void update(uint32_t _id, TypeId::Enum _type, uint32_t _baseTypeId, uint32_t _numComonents)
  314. {
  315. TypeId& type = getTypeId(_id);
  316. type.type = _type;
  317. type.baseType = getTypeId(_baseTypeId).type;
  318. type.numComponents = _numComonents;
  319. }
  320. };
  321. bool spvParse(uint32_t _offset, const SpvInstruction& _instruction, void* _userData)
  322. {
  323. BX_UNUSED(_offset);
  324. SpvReflection* spv = (SpvReflection*)_userData;
  325. switch (_instruction.opcode)
  326. {
  327. case SpvOpcode::Name:
  328. spv->update(_instruction.result
  329. , _instruction.operand[0].literalString
  330. );
  331. break;
  332. case SpvOpcode::Decorate:
  333. spv->update(_instruction.operand[0].data
  334. , SpvDecoration::Enum(_instruction.operand[1].data)
  335. , _instruction.operand[2].data
  336. );
  337. break;
  338. case SpvOpcode::MemberName:
  339. spv->update(_instruction.result
  340. , _instruction.operand[0].data
  341. , _instruction.operand[1].literalString
  342. );
  343. break;
  344. case SpvOpcode::MemberDecorate:
  345. spv->update(_instruction.operand[0].data
  346. , _instruction.operand[1].data
  347. , SpvDecoration::Enum(_instruction.operand[2].data)
  348. , _instruction.operand[3].data
  349. );
  350. break;
  351. case SpvOpcode::Variable:
  352. spv->update(_instruction.result
  353. , _instruction.type
  354. , SpvStorageClass::Enum(_instruction.operand[0].data)
  355. );
  356. break;
  357. case SpvOpcode::TypeVoid:
  358. spv->update(_instruction.result, SpvReflection::TypeId::Void);
  359. break;
  360. case SpvOpcode::TypeBool:
  361. spv->update(_instruction.result, SpvReflection::TypeId::Bool);
  362. break;
  363. case SpvOpcode::TypeInt:
  364. spv->update(_instruction.result
  365. , 32 == _instruction.operand[0].data
  366. ? 0 == _instruction.operand[1].data
  367. ? SpvReflection::TypeId::Uint32
  368. : SpvReflection::TypeId::Int32
  369. : 0 == _instruction.operand[1].data
  370. ? SpvReflection::TypeId::Uint64
  371. : SpvReflection::TypeId::Int64
  372. );
  373. break;
  374. case SpvOpcode::TypeFloat:
  375. spv->update(_instruction.result
  376. , 32 == _instruction.operand[0].data
  377. ? SpvReflection::TypeId::Float
  378. : SpvReflection::TypeId::Double
  379. );
  380. break;
  381. case SpvOpcode::TypeVector:
  382. spv->update(_instruction.result
  383. , SpvReflection::TypeId::Vector
  384. , _instruction.operand[0].data
  385. , _instruction.operand[1].data
  386. );
  387. break;
  388. case SpvOpcode::TypeMatrix:
  389. spv->update(_instruction.result
  390. , SpvReflection::TypeId::Matrix
  391. , _instruction.operand[0].data
  392. , _instruction.operand[1].data
  393. );
  394. break;
  395. case SpvOpcode::TypeImage:
  396. case SpvOpcode::TypeSampler:
  397. case SpvOpcode::TypeSampledImage:
  398. break;
  399. case SpvOpcode::TypeStruct:
  400. for (uint32_t ii = 0, num = _instruction.numOperands; ii < num; ++ii)
  401. {
  402. SpvReflection::Id::Variable& var = spv->get(_instruction.result, ii);
  403. var.type = _instruction.operand[ii].data;
  404. }
  405. break;
  406. default:
  407. break;
  408. }
  409. return true;
  410. }
  411. void disassemble(bx::WriterI* _writer, bx::ReaderSeekerI* _reader, bx::Error* _err)
  412. {
  413. BX_UNUSED(_writer);
  414. uint32_t magic;
  415. bx::peek(_reader, magic);
  416. SpvReflection spvx;
  417. if (magic == SPV_CHUNK_HEADER)
  418. {
  419. SpirV spirv;
  420. read(_reader, spirv, _err);
  421. parse(spirv.shader, spvParse, &spvx, _err);
  422. for (SpvReflection::IdMap::const_iterator it = spvx.idMap.begin(), itEnd = spvx.idMap.end(); it != itEnd; ++it)
  423. {
  424. const SpvReflection::Id& id = it->second;
  425. uint32_t num = uint32_t(id.members.size() );
  426. if (0 < num
  427. && 0 != strcmp(id.var.name.c_str(), "gl_PerVertex") )
  428. {
  429. printf("%3d: %s %d %s\n"
  430. , it->first
  431. , id.var.name.c_str()
  432. , id.var.location
  433. , getName(id.var.storageClass)
  434. );
  435. printf("{\n");
  436. for (uint32_t ii = 0; ii < num; ++ii)
  437. {
  438. const SpvReflection::Id::Variable& var = id.members[ii];
  439. printf("\t\t%s %s %d %s\n"
  440. , spvx.getTypeName(var.type).c_str()
  441. , var.name.c_str()
  442. , var.offset
  443. , getName(var.storageClass)
  444. );
  445. }
  446. printf("}\n");
  447. }
  448. }
  449. }
  450. }
  451. struct DebugOutputWriter : public bx::WriterI
  452. {
  453. virtual int32_t write(const void* _data, int32_t _size, bx::Error*) BX_OVERRIDE
  454. {
  455. char* out = (char*)alloca(_size + 1);
  456. memcpy(out, _data, _size);
  457. out[_size] = '\0';
  458. printf("%s", out);
  459. return _size;
  460. }
  461. };
  462. static EShLanguage getLang(char _p)
  463. {
  464. switch (_p)
  465. {
  466. case 'c': return EShLangCompute;
  467. case 'f': return EShLangFragment;
  468. default: break;
  469. }
  470. return EShLangVertex;
  471. }
  472. // static void printError(spv_message_level_t, const char*, const spv_position_t&, const char* _message)
  473. // {
  474. // fprintf(stderr, "%s\n", _message);
  475. // }
  476. static bool compile(bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer)
  477. {
  478. BX_UNUSED(_cmdLine, _version, _code, _writer);
  479. const char* profile = _cmdLine.findOption('p', "profile");
  480. if (NULL == profile)
  481. {
  482. fprintf(stderr, "Error: Shader profile must be specified.\n");
  483. return false;
  484. }
  485. glslang::InitializeProcess();
  486. glslang::TProgram* program = new glslang::TProgram;
  487. EShLanguage stage = getLang(profile[0]);
  488. glslang::TShader* shader = new glslang::TShader(stage);
  489. EShMessages messages = EShMessages(0
  490. | EShMsgDefault
  491. | EShMsgReadHlsl
  492. | EShMsgVulkanRules
  493. | EShMsgSpvRules
  494. );
  495. const char* shaderStrings[] = { _code.c_str() };
  496. const char* shaderNames[] = { "" };
  497. shader->setStringsWithLengthsAndNames(
  498. shaderStrings
  499. , NULL
  500. , shaderNames
  501. , BX_COUNTOF(shaderNames)
  502. );
  503. bool compiled = shader->parse(&resourceLimits
  504. , 110
  505. , false
  506. , messages
  507. );
  508. bool linked = false;
  509. bool validated = true;
  510. bool optimized = true;
  511. if (!compiled)
  512. {
  513. const char* log = shader->getInfoLog();
  514. if (NULL != log)
  515. {
  516. int32_t source = 0;
  517. int32_t line = 0;
  518. int32_t column = 0;
  519. int32_t start = 0;
  520. int32_t end = INT32_MAX;
  521. const char* err = strstr(log, "ERROR:");
  522. bool found = false;
  523. if (NULL != err)
  524. {
  525. found = 2 == sscanf(err, "ERROR: %u:%u: '", &source, &line);
  526. if (found)
  527. {
  528. ++line;
  529. }
  530. }
  531. if (found)
  532. {
  533. start = bx::uint32_imax(1, line-10);
  534. end = start + 20;
  535. }
  536. printCode(_code.c_str(), line, start, end, column);
  537. fprintf(stderr, "%s\n", log);
  538. }
  539. }
  540. else
  541. {
  542. program->addShader(shader);
  543. linked = true
  544. && program->link(messages)
  545. && program->mapIO()
  546. ;
  547. if (!linked)
  548. {
  549. const char* log = program->getInfoLog();
  550. if (NULL != log)
  551. {
  552. fprintf(stderr, "%s\n", log);
  553. }
  554. }
  555. else
  556. {
  557. // program->buildReflection();
  558. // fprintf(stderr, "attributes %d, uniforms %d\n"
  559. // , program->getNumLiveAttributes()
  560. // , program->getNumLiveUniformVariables()
  561. // );
  562. // program->dumpReflection();
  563. BX_UNUSED(spv::MemorySemanticsAllMemory);
  564. glslang::TIntermediate* intermediate = program->getIntermediate(stage);
  565. std::vector<uint32_t> spirv;
  566. glslang::GlslangToSpv(*intermediate, spirv);
  567. spv::spirvbin_t spvBin;
  568. spvBin.remap(
  569. spirv
  570. , 0
  571. | spv::spirvbin_t::DCE_ALL
  572. | spv::spirvbin_t::OPT_ALL
  573. | spv::spirvbin_t::MAP_ALL
  574. // | spv::spirvbin_t::STRIP
  575. );
  576. bx::Error err;
  577. DebugOutputWriter writer;
  578. bx::MemoryReader reader(spirv.data(), uint32_t(spirv.size()*4) );
  579. disassemble(&writer, &reader, &err);
  580. #if 0
  581. spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
  582. tools.SetMessageConsumer(printError);
  583. validated = tools.Validate(spirv);
  584. if (!validated)
  585. {
  586. std::string out;
  587. tools.Disassemble(spirv, &out);
  588. printf("%s\n", out.c_str());
  589. }
  590. if (validated)
  591. {
  592. spvtools::Optimizer optm(SPV_ENV_VULKAN_1_0);
  593. optm.SetMessageConsumer(printError);
  594. optm
  595. .RegisterPass(spvtools::CreateStripDebugInfoPass() )
  596. // .RegisterPass(spvtools::CreateSetSpecConstantDefaultValuePass({ {1, "42" } }) )
  597. .RegisterPass(spvtools::CreateFreezeSpecConstantValuePass() )
  598. .RegisterPass(spvtools::CreateFoldSpecConstantOpAndCompositePass() )
  599. .RegisterPass(spvtools::CreateEliminateDeadConstantPass() )
  600. .RegisterPass(spvtools::CreateUnifyConstantPass() )
  601. ;
  602. optimized = optm.Run(spirv.data(), spirv.size(), &spirv);
  603. }
  604. #endif // 0
  605. if (optimized)
  606. {
  607. uint16_t shaderSize = (uint16_t)spirv.size()*sizeof(uint32_t);
  608. bx::write(_writer, shaderSize);
  609. bx::write(_writer, spirv.data(), shaderSize);
  610. uint8_t nul = 0;
  611. bx::write(_writer, nul);
  612. }
  613. }
  614. }
  615. delete program;
  616. delete shader;
  617. glslang::FinalizeProcess();
  618. return compiled && linked && validated && optimized;
  619. }
  620. } // namespace spirv
  621. bool compileSPIRVShader(bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer)
  622. {
  623. return spirv::compile(_cmdLine, _version, _code, _writer);
  624. }
  625. } // namespace bgfx