shaderc_spirv.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  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. {
  175. }
  176. Enum baseType;
  177. Enum type;
  178. uint32_t numComponents;
  179. stl::string toString()
  180. {
  181. stl::string result;
  182. switch (type)
  183. {
  184. case Float:
  185. result.append("float");
  186. break;
  187. case Vector:
  188. bx::stringPrintf(result, "vec%d"
  189. , numComponents
  190. );
  191. break;
  192. case Matrix:
  193. bx::stringPrintf(result, "mat%d"
  194. , numComponents
  195. );
  196. default:
  197. break;
  198. }
  199. return result;
  200. }
  201. };
  202. struct Id
  203. {
  204. struct Variable
  205. {
  206. Variable()
  207. : decoration(SpvDecoration::Count)
  208. , builtin(SpvBuiltin::Count)
  209. , storageClass(SpvStorageClass::Count)
  210. , location(UINT32_MAX)
  211. , offset(UINT32_MAX)
  212. , type(UINT32_MAX)
  213. {
  214. }
  215. stl::string name;
  216. SpvDecoration::Enum decoration;
  217. SpvBuiltin::Enum builtin;
  218. SpvStorageClass::Enum storageClass;
  219. uint32_t location;
  220. uint32_t offset;
  221. uint32_t type;
  222. };
  223. typedef stl::vector<Variable> MemberArray;
  224. Variable var;
  225. MemberArray members;
  226. };
  227. typedef stl::unordered_map<uint32_t, TypeId> TypeIdMap;
  228. typedef stl::unordered_map<uint32_t, Id> IdMap;
  229. TypeIdMap typeIdMap;
  230. IdMap idMap;
  231. stl::string getTypeName(uint32_t _typeId)
  232. {
  233. return getTypeId(_typeId).toString();
  234. }
  235. Id& getId(uint32_t _id)
  236. {
  237. IdMap::iterator it = idMap.find(_id);
  238. if (it == idMap.end() )
  239. {
  240. Id id;
  241. stl::pair<IdMap::iterator, bool> result = idMap.insert(stl::make_pair(_id, id) );
  242. it = result.first;
  243. }
  244. return it->second;
  245. }
  246. Id::Variable& get(uint32_t _id, uint32_t _idx)
  247. {
  248. Id& id = getId(_id);
  249. id.members.resize(bx::uint32_max(_idx+1, uint32_t(id.members.size() ) ) );
  250. return id.members[_idx];
  251. }
  252. TypeId& getTypeId(uint32_t _id)
  253. {
  254. TypeIdMap::iterator it = typeIdMap.find(_id);
  255. if (it == typeIdMap.end() )
  256. {
  257. TypeId id;
  258. stl::pair<TypeIdMap::iterator, bool> result = typeIdMap.insert(stl::make_pair(_id, id) );
  259. it = result.first;
  260. }
  261. return it->second;
  262. }
  263. void update(uint32_t _id, const stl::string& _name)
  264. {
  265. getId(_id).var.name = _name;
  266. }
  267. BX_NO_INLINE void update(Id::Variable& _variable, SpvDecoration::Enum _decoration, uint32_t _literal)
  268. {
  269. _variable.decoration = _decoration;
  270. switch (_decoration)
  271. {
  272. case SpvDecoration::Location:
  273. _variable.location = _literal;
  274. break;
  275. case SpvDecoration::Offset:
  276. _variable.offset = _literal;
  277. break;
  278. case SpvDecoration::BuiltIn:
  279. _variable.builtin = SpvBuiltin::Enum(_literal);
  280. break;
  281. default:
  282. break;
  283. }
  284. }
  285. BX_NO_INLINE void update(Id::Variable& _variable, uint32_t _type, SpvStorageClass::Enum _storageClass)
  286. {
  287. _variable.type = _type;
  288. _variable.storageClass = _storageClass;
  289. }
  290. void update(uint32_t _id, SpvDecoration::Enum _decoration, uint32_t _literal)
  291. {
  292. update(getId(_id).var, _decoration, _literal);
  293. }
  294. void update(uint32_t _id, uint32_t _type, SpvStorageClass::Enum _storageClass)
  295. {
  296. update(getId(_id).var, _type, _storageClass);
  297. }
  298. void update(uint32_t _id, uint32_t _idx, const stl::string& _name)
  299. {
  300. Id::Variable& var = get(_id, _idx);
  301. var.name = _name;
  302. }
  303. BX_NO_INLINE void update(uint32_t _id, uint32_t _idx, SpvDecoration::Enum _decoration, uint32_t _literal)
  304. {
  305. update(get(_id, _idx), _decoration, _literal);
  306. }
  307. void update(uint32_t _id, TypeId::Enum _type)
  308. {
  309. TypeId& type = getTypeId(_id);
  310. type.type = _type;
  311. }
  312. void update(uint32_t _id, TypeId::Enum _type, uint32_t _baseTypeId, uint32_t _numComonents)
  313. {
  314. TypeId& type = getTypeId(_id);
  315. type.type = _type;
  316. type.baseType = getTypeId(_baseTypeId).type;
  317. type.numComponents = _numComonents;
  318. }
  319. };
  320. bool spvParse(uint32_t _offset, const SpvInstruction& _instruction, void* _userData)
  321. {
  322. BX_UNUSED(_offset);
  323. SpvReflection* spv = (SpvReflection*)_userData;
  324. switch (_instruction.opcode)
  325. {
  326. case SpvOpcode::Name:
  327. spv->update(_instruction.result
  328. , _instruction.operand[0].literalString
  329. );
  330. break;
  331. case SpvOpcode::Decorate:
  332. spv->update(_instruction.operand[0].data
  333. , SpvDecoration::Enum(_instruction.operand[1].data)
  334. , _instruction.operand[2].data
  335. );
  336. break;
  337. case SpvOpcode::MemberName:
  338. spv->update(_instruction.result
  339. , _instruction.operand[0].data
  340. , _instruction.operand[1].literalString
  341. );
  342. break;
  343. case SpvOpcode::MemberDecorate:
  344. spv->update(_instruction.operand[0].data
  345. , _instruction.operand[1].data
  346. , SpvDecoration::Enum(_instruction.operand[2].data)
  347. , _instruction.operand[3].data
  348. );
  349. break;
  350. case SpvOpcode::Variable:
  351. spv->update(_instruction.result
  352. , _instruction.type
  353. , SpvStorageClass::Enum(_instruction.operand[0].data)
  354. );
  355. break;
  356. case SpvOpcode::TypeVoid:
  357. spv->update(_instruction.result, SpvReflection::TypeId::Void);
  358. break;
  359. case SpvOpcode::TypeBool:
  360. spv->update(_instruction.result, SpvReflection::TypeId::Bool);
  361. break;
  362. case SpvOpcode::TypeInt:
  363. spv->update(_instruction.result
  364. , 32 == _instruction.operand[0].data
  365. ? 0 == _instruction.operand[1].data
  366. ? SpvReflection::TypeId::Uint32
  367. : SpvReflection::TypeId::Int32
  368. : 0 == _instruction.operand[1].data
  369. ? SpvReflection::TypeId::Uint64
  370. : SpvReflection::TypeId::Int64
  371. );
  372. break;
  373. case SpvOpcode::TypeFloat:
  374. spv->update(_instruction.result
  375. , 32 == _instruction.operand[0].data
  376. ? SpvReflection::TypeId::Float
  377. : SpvReflection::TypeId::Double
  378. );
  379. break;
  380. case SpvOpcode::TypeVector:
  381. spv->update(_instruction.result
  382. , SpvReflection::TypeId::Vector
  383. , _instruction.operand[0].data
  384. , _instruction.operand[1].data
  385. );
  386. break;
  387. case SpvOpcode::TypeMatrix:
  388. spv->update(_instruction.result
  389. , SpvReflection::TypeId::Matrix
  390. , _instruction.operand[0].data
  391. , _instruction.operand[1].data
  392. );
  393. break;
  394. case SpvOpcode::TypeImage:
  395. case SpvOpcode::TypeSampler:
  396. case SpvOpcode::TypeSampledImage:
  397. break;
  398. case SpvOpcode::TypeStruct:
  399. for (uint32_t ii = 0, num = _instruction.numOperands; ii < num; ++ii)
  400. {
  401. SpvReflection::Id::Variable& var = spv->get(_instruction.result, ii);
  402. var.type = _instruction.operand[ii].data;
  403. }
  404. break;
  405. default:
  406. break;
  407. }
  408. return true;
  409. }
  410. void disassemble(bx::WriterI* _writer, bx::ReaderSeekerI* _reader, bx::Error* _err)
  411. {
  412. BX_UNUSED(_writer);
  413. uint32_t magic;
  414. bx::peek(_reader, magic);
  415. SpvReflection spvx;
  416. if (magic == SPV_CHUNK_HEADER)
  417. {
  418. SpirV spirv;
  419. read(_reader, spirv, _err);
  420. parse(spirv.shader, spvParse, &spvx, _err);
  421. for (SpvReflection::IdMap::const_iterator it = spvx.idMap.begin(), itEnd = spvx.idMap.end(); it != itEnd; ++it)
  422. {
  423. const SpvReflection::Id& id = it->second;
  424. uint32_t num = uint32_t(id.members.size() );
  425. if (0 < num
  426. && 0 != strcmp(id.var.name.c_str(), "gl_PerVertex") )
  427. {
  428. printf("%3d: %s %d %s\n"
  429. , it->first
  430. , id.var.name.c_str()
  431. , id.var.location
  432. , getName(id.var.storageClass)
  433. );
  434. printf("{\n");
  435. for (uint32_t ii = 0; ii < num; ++ii)
  436. {
  437. const SpvReflection::Id::Variable& var = id.members[ii];
  438. printf("\t\t%s %s %d %s\n"
  439. , spvx.getTypeName(var.type).c_str()
  440. , var.name.c_str()
  441. , var.offset
  442. , getName(var.storageClass)
  443. );
  444. }
  445. printf("}\n");
  446. }
  447. }
  448. }
  449. }
  450. struct DebugOutputWriter : public bx::WriterI
  451. {
  452. virtual int32_t write(const void* _data, int32_t _size, bx::Error*) BX_OVERRIDE
  453. {
  454. char* out = (char*)alloca(_size + 1);
  455. memcpy(out, _data, _size);
  456. out[_size] = '\0';
  457. printf("%s", out);
  458. return _size;
  459. }
  460. };
  461. static EShLanguage getLang(char _p)
  462. {
  463. switch (_p)
  464. {
  465. case 'c': return EShLangCompute;
  466. case 'f': return EShLangFragment;
  467. default: break;
  468. }
  469. return EShLangVertex;
  470. }
  471. // static void printError(spv_message_level_t, const char*, const spv_position_t&, const char* _message)
  472. // {
  473. // fprintf(stderr, "%s\n", _message);
  474. // }
  475. static bool compile(bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer)
  476. {
  477. BX_UNUSED(_cmdLine, _version, _code, _writer);
  478. const char* profile = _cmdLine.findOption('p', "profile");
  479. if (NULL == profile)
  480. {
  481. fprintf(stderr, "Error: Shader profile must be specified.\n");
  482. return false;
  483. }
  484. glslang::InitializeProcess();
  485. glslang::TProgram* program = new glslang::TProgram;
  486. EShLanguage stage = getLang(profile[0]);
  487. glslang::TShader* shader = new glslang::TShader(stage);
  488. EShMessages messages = EShMessages(0
  489. | EShMsgDefault
  490. | EShMsgReadHlsl
  491. | EShMsgVulkanRules
  492. | EShMsgSpvRules
  493. );
  494. const char* shaderStrings[] = { _code.c_str() };
  495. const char* shaderNames[] = { "" };
  496. shader->setStringsWithLengthsAndNames(
  497. shaderStrings
  498. , NULL
  499. , shaderNames
  500. , BX_COUNTOF(shaderNames)
  501. );
  502. bool compiled = shader->parse(&resourceLimits
  503. , 110
  504. , false
  505. , messages
  506. );
  507. bool linked = false;
  508. bool validated = true;
  509. bool optimized = true;
  510. if (!compiled)
  511. {
  512. const char* log = shader->getInfoLog();
  513. if (NULL != log)
  514. {
  515. int32_t source = 0;
  516. int32_t line = 0;
  517. int32_t column = 0;
  518. int32_t start = 0;
  519. int32_t end = INT32_MAX;
  520. const char* err = strstr(log, "ERROR:");
  521. bool found = false;
  522. if (NULL != err)
  523. {
  524. found = 2 == sscanf(err, "ERROR: %u:%u: '", &source, &line);
  525. if (found)
  526. {
  527. ++line;
  528. }
  529. }
  530. if (found)
  531. {
  532. start = bx::uint32_imax(1, line-10);
  533. end = start + 20;
  534. }
  535. printCode(_code.c_str(), line, start, end, column);
  536. fprintf(stderr, "%s\n", log);
  537. }
  538. }
  539. else
  540. {
  541. program->addShader(shader);
  542. linked = true
  543. && program->link(messages)
  544. && program->mapIO()
  545. ;
  546. if (!linked)
  547. {
  548. const char* log = program->getInfoLog();
  549. if (NULL != log)
  550. {
  551. fprintf(stderr, "%s\n", log);
  552. }
  553. }
  554. else
  555. {
  556. // program->buildReflection();
  557. // fprintf(stderr, "attributes %d, uniforms %d\n"
  558. // , program->getNumLiveAttributes()
  559. // , program->getNumLiveUniformVariables()
  560. // );
  561. // program->dumpReflection();
  562. glslang::TIntermediate* intermediate = program->getIntermediate(stage);
  563. std::vector<uint32_t> spirv;
  564. glslang::GlslangToSpv(*intermediate, spirv);
  565. spv::spirvbin_t spvBin;
  566. spvBin.remap(
  567. spirv
  568. , 0
  569. | spv::spirvbin_t::DCE_ALL
  570. | spv::spirvbin_t::OPT_ALL
  571. | spv::spirvbin_t::MAP_ALL
  572. // | spv::spirvbin_t::STRIP
  573. );
  574. bx::Error err;
  575. DebugOutputWriter writer;
  576. bx::MemoryReader reader(spirv.data(), uint32_t(spirv.size()*4) );
  577. disassemble(&writer, &reader, &err);
  578. #if 0
  579. spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
  580. tools.SetMessageConsumer(printError);
  581. validated = tools.Validate(spirv);
  582. if (!validated)
  583. {
  584. std::string out;
  585. tools.Disassemble(spirv, &out);
  586. printf("%s\n", out.c_str());
  587. }
  588. if (validated)
  589. {
  590. spvtools::Optimizer optm(SPV_ENV_VULKAN_1_0);
  591. optm.SetMessageConsumer(printError);
  592. optm
  593. .RegisterPass(spvtools::CreateStripDebugInfoPass() )
  594. // .RegisterPass(spvtools::CreateSetSpecConstantDefaultValuePass({ {1, "42" } }) )
  595. .RegisterPass(spvtools::CreateFreezeSpecConstantValuePass() )
  596. .RegisterPass(spvtools::CreateFoldSpecConstantOpAndCompositePass() )
  597. .RegisterPass(spvtools::CreateEliminateDeadConstantPass() )
  598. .RegisterPass(spvtools::CreateUnifyConstantPass() )
  599. ;
  600. optimized = optm.Run(spirv.data(), spirv.size(), &spirv);
  601. }
  602. #endif // 0
  603. if (optimized)
  604. {
  605. uint16_t shaderSize = (uint16_t)spirv.size()*sizeof(uint32_t);
  606. bx::write(_writer, shaderSize);
  607. bx::write(_writer, spirv.data(), shaderSize);
  608. uint8_t nul = 0;
  609. bx::write(_writer, nul);
  610. }
  611. }
  612. }
  613. delete program;
  614. delete shader;
  615. glslang::FinalizeProcess();
  616. return compiled && linked && validated && optimized;
  617. }
  618. } // namespace spirv
  619. bool compileSPIRVShader(bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer)
  620. {
  621. return spirv::compile(_cmdLine, _version, _code, _writer);
  622. }
  623. } // namespace bgfx