shaderc_spirv.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  1. /*
  2. * Copyright 2011-2019 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(4100) // error C4100: 'inclusionDepth' : unreferenced formal parameter
  8. BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4265) // error C4265: 'spv::spirvbin_t': class has virtual functions, but destructor is not virtual
  9. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wshadow") // warning: declaration of 'userData' shadows a member of 'glslang::TShader::Includer::IncludeResult'
  10. #define ENABLE_OPT 1
  11. #include <ShaderLang.h>
  12. #include <ResourceLimits.h>
  13. #include <SPIRV/SPVRemapper.h>
  14. #include <SPIRV/GlslangToSpv.h>
  15. #define SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
  16. #include <spirv_msl.hpp>
  17. #include <spirv_reflect.hpp>
  18. #include <spirv-tools/optimizer.hpp>
  19. BX_PRAGMA_DIAGNOSTIC_POP()
  20. namespace bgfx
  21. {
  22. static bx::DefaultAllocator s_allocator;
  23. bx::AllocatorI* g_allocator = &s_allocator;
  24. struct TinyStlAllocator
  25. {
  26. static void* static_allocate(size_t _bytes);
  27. static void static_deallocate(void* _ptr, size_t /*_bytes*/);
  28. };
  29. void* TinyStlAllocator::static_allocate(size_t _bytes)
  30. {
  31. return BX_ALLOC(g_allocator, _bytes);
  32. }
  33. void TinyStlAllocator::static_deallocate(void* _ptr, size_t /*_bytes*/)
  34. {
  35. if (NULL != _ptr)
  36. {
  37. BX_FREE(g_allocator, _ptr);
  38. }
  39. }
  40. } // namespace bgfx
  41. #define TINYSTL_ALLOCATOR bgfx::TinyStlAllocator
  42. #include <tinystl/allocator.h>
  43. #include <tinystl/string.h>
  44. #include <tinystl/unordered_map.h>
  45. #include <tinystl/vector.h>
  46. namespace stl = tinystl;
  47. #include "../../src/shader_spirv.h"
  48. namespace bgfx { namespace spirv
  49. {
  50. const TBuiltInResource resourceLimits =
  51. {
  52. 32, // MaxLights
  53. 6, // MaxClipPlanes
  54. 32, // MaxTextureUnits
  55. 32, // MaxTextureCoords
  56. 64, // MaxVertexAttribs
  57. 4096, // MaxVertexUniformComponents
  58. 64, // MaxVaryingFloats
  59. 32, // MaxVertexTextureImageUnits
  60. 80, // MaxCombinedTextureImageUnits
  61. 32, // MaxTextureImageUnits
  62. 4096, // MaxFragmentUniformComponents
  63. 32, // MaxDrawBuffers
  64. 128, // MaxVertexUniformVectors
  65. 8, // MaxVaryingVectors
  66. 16, // MaxFragmentUniformVectors
  67. 16, // MaxVertexOutputVectors
  68. 15, // MaxFragmentInputVectors
  69. -8, // MinProgramTexelOffset
  70. 7, // MaxProgramTexelOffset
  71. 8, // MaxClipDistances
  72. 65535, // MaxComputeWorkGroupCountX
  73. 65535, // MaxComputeWorkGroupCountY
  74. 65535, // MaxComputeWorkGroupCountZ
  75. 1024, // MaxComputeWorkGroupSizeX
  76. 1024, // MaxComputeWorkGroupSizeY
  77. 64, // MaxComputeWorkGroupSizeZ
  78. 1024, // MaxComputeUniformComponents
  79. 16, // MaxComputeTextureImageUnits
  80. 8, // MaxComputeImageUniforms
  81. 8, // MaxComputeAtomicCounters
  82. 1, // MaxComputeAtomicCounterBuffers
  83. 60, // MaxVaryingComponents
  84. 64, // MaxVertexOutputComponents
  85. 64, // MaxGeometryInputComponents
  86. 128, // MaxGeometryOutputComponents
  87. 128, // MaxFragmentInputComponents
  88. 8, // MaxImageUnits
  89. 8, // MaxCombinedImageUnitsAndFragmentOutputs
  90. 8, // MaxCombinedShaderOutputResources
  91. 0, // MaxImageSamples
  92. 0, // MaxVertexImageUniforms
  93. 0, // MaxTessControlImageUniforms
  94. 0, // MaxTessEvaluationImageUniforms
  95. 0, // MaxGeometryImageUniforms
  96. 8, // MaxFragmentImageUniforms
  97. 8, // MaxCombinedImageUniforms
  98. 16, // MaxGeometryTextureImageUnits
  99. 256, // MaxGeometryOutputVertices
  100. 1024, // MaxGeometryTotalOutputComponents
  101. 1024, // MaxGeometryUniformComponents
  102. 64, // MaxGeometryVaryingComponents
  103. 128, // MaxTessControlInputComponents
  104. 128, // MaxTessControlOutputComponents
  105. 16, // MaxTessControlTextureImageUnits
  106. 1024, // MaxTessControlUniformComponents
  107. 4096, // MaxTessControlTotalOutputComponents
  108. 128, // MaxTessEvaluationInputComponents
  109. 128, // MaxTessEvaluationOutputComponents
  110. 16, // MaxTessEvaluationTextureImageUnits
  111. 1024, // MaxTessEvaluationUniformComponents
  112. 120, // MaxTessPatchComponents
  113. 32, // MaxPatchVertices
  114. 64, // MaxTessGenLevel
  115. 16, // MaxViewports
  116. 0, // MaxVertexAtomicCounters
  117. 0, // MaxTessControlAtomicCounters
  118. 0, // MaxTessEvaluationAtomicCounters
  119. 0, // MaxGeometryAtomicCounters
  120. 8, // MaxFragmentAtomicCounters
  121. 8, // MaxCombinedAtomicCounters
  122. 1, // MaxAtomicCounterBindings
  123. 0, // MaxVertexAtomicCounterBuffers
  124. 0, // MaxTessControlAtomicCounterBuffers
  125. 0, // MaxTessEvaluationAtomicCounterBuffers
  126. 0, // MaxGeometryAtomicCounterBuffers
  127. 1, // MaxFragmentAtomicCounterBuffers
  128. 1, // MaxCombinedAtomicCounterBuffers
  129. 16384, // MaxAtomicCounterBufferSize
  130. 4, // MaxTransformFeedbackBuffers
  131. 64, // MaxTransformFeedbackInterleavedComponents
  132. 8, // MaxCullDistances
  133. 8, // MaxCombinedClipAndCullDistances
  134. 4, // MaxSamples
  135. 0, // maxMeshOutputVerticesNV;
  136. 0, // maxMeshOutputPrimitivesNV;
  137. 0, // maxMeshWorkGroupSizeX_NV;
  138. 0, // maxMeshWorkGroupSizeY_NV;
  139. 0, // maxMeshWorkGroupSizeZ_NV;
  140. 0, // maxTaskWorkGroupSizeX_NV;
  141. 0, // maxTaskWorkGroupSizeY_NV;
  142. 0, // maxTaskWorkGroupSizeZ_NV;
  143. 0, // maxMeshViewCountNV
  144. { // limits
  145. true, // nonInductiveForLoops
  146. true, // whileLoops
  147. true, // doWhileLoops
  148. true, // generalUniformIndexing
  149. true, // generalAttributeMatrixVectorIndexing
  150. true, // generalVaryingIndexing
  151. true, // generalSamplerIndexing
  152. true, // generalVariableIndexing
  153. true, // generalConstantMatrixVectorIndexing
  154. },
  155. };
  156. bool printAsm(uint32_t _offset, const SpvInstruction& _instruction, void* _userData)
  157. {
  158. BX_UNUSED(_userData);
  159. char temp[512];
  160. toString(temp, sizeof(temp), _instruction);
  161. BX_TRACE("%5d: %s", _offset, temp);
  162. return true;
  163. }
  164. struct SpvReflection
  165. {
  166. struct TypeId
  167. {
  168. enum Enum
  169. {
  170. Void,
  171. Bool,
  172. Int32,
  173. Int64,
  174. Uint32,
  175. Uint64,
  176. Float,
  177. Double,
  178. Vector,
  179. Matrix,
  180. Count
  181. };
  182. TypeId()
  183. : baseType(Enum::Count)
  184. , type(Enum::Count)
  185. , numComponents(0)
  186. {
  187. }
  188. Enum baseType;
  189. Enum type;
  190. uint32_t numComponents;
  191. stl::string toString()
  192. {
  193. stl::string result;
  194. switch (type)
  195. {
  196. case Float:
  197. result.append("float");
  198. break;
  199. case Vector:
  200. bx::stringPrintf(result, "vec%d"
  201. , numComponents
  202. );
  203. break;
  204. case Matrix:
  205. bx::stringPrintf(result, "mat%d"
  206. , numComponents
  207. );
  208. default:
  209. break;
  210. }
  211. return result;
  212. }
  213. };
  214. struct Id
  215. {
  216. struct Variable
  217. {
  218. Variable()
  219. : decoration(SpvDecoration::Count)
  220. , builtin(SpvBuiltin::Count)
  221. , storageClass(SpvStorageClass::Count)
  222. , location(UINT32_MAX)
  223. , offset(UINT32_MAX)
  224. , type(UINT32_MAX)
  225. {
  226. }
  227. stl::string name;
  228. SpvDecoration::Enum decoration;
  229. SpvBuiltin::Enum builtin;
  230. SpvStorageClass::Enum storageClass;
  231. uint32_t location;
  232. uint32_t offset;
  233. uint32_t type;
  234. };
  235. typedef stl::vector<Variable> MemberArray;
  236. Variable var;
  237. MemberArray members;
  238. };
  239. typedef stl::unordered_map<uint32_t, TypeId> TypeIdMap;
  240. typedef stl::unordered_map<uint32_t, Id> IdMap;
  241. TypeIdMap typeIdMap;
  242. IdMap idMap;
  243. stl::string getTypeName(uint32_t _typeId)
  244. {
  245. return getTypeId(_typeId).toString();
  246. }
  247. Id& getId(uint32_t _id)
  248. {
  249. IdMap::iterator it = idMap.find(_id);
  250. if (it == idMap.end() )
  251. {
  252. Id id;
  253. stl::pair<IdMap::iterator, bool> result = idMap.insert(stl::make_pair(_id, id) );
  254. it = result.first;
  255. }
  256. return it->second;
  257. }
  258. Id::Variable& get(uint32_t _id, uint32_t _idx)
  259. {
  260. Id& id = getId(_id);
  261. id.members.resize(bx::uint32_max(_idx+1, uint32_t(id.members.size() ) ) );
  262. return id.members[_idx];
  263. }
  264. TypeId& getTypeId(uint32_t _id)
  265. {
  266. TypeIdMap::iterator it = typeIdMap.find(_id);
  267. if (it == typeIdMap.end() )
  268. {
  269. TypeId id;
  270. stl::pair<TypeIdMap::iterator, bool> result = typeIdMap.insert(stl::make_pair(_id, id) );
  271. it = result.first;
  272. }
  273. return it->second;
  274. }
  275. void update(uint32_t _id, const stl::string& _name)
  276. {
  277. getId(_id).var.name = _name;
  278. }
  279. BX_NO_INLINE void update(Id::Variable& _variable, SpvDecoration::Enum _decoration, uint32_t _literal)
  280. {
  281. _variable.decoration = _decoration;
  282. switch (_decoration)
  283. {
  284. case SpvDecoration::Location:
  285. _variable.location = _literal;
  286. break;
  287. case SpvDecoration::Offset:
  288. _variable.offset = _literal;
  289. break;
  290. case SpvDecoration::BuiltIn:
  291. _variable.builtin = SpvBuiltin::Enum(_literal);
  292. break;
  293. default:
  294. break;
  295. }
  296. }
  297. BX_NO_INLINE void update(Id::Variable& _variable, uint32_t _type, SpvStorageClass::Enum _storageClass)
  298. {
  299. _variable.type = _type;
  300. _variable.storageClass = _storageClass;
  301. }
  302. void update(uint32_t _id, SpvDecoration::Enum _decoration, uint32_t _literal)
  303. {
  304. update(getId(_id).var, _decoration, _literal);
  305. }
  306. void update(uint32_t _id, uint32_t _type, SpvStorageClass::Enum _storageClass)
  307. {
  308. update(getId(_id).var, _type, _storageClass);
  309. }
  310. void update(uint32_t _id, uint32_t _idx, const stl::string& _name)
  311. {
  312. Id::Variable& var = get(_id, _idx);
  313. var.name = _name;
  314. }
  315. BX_NO_INLINE void update(uint32_t _id, uint32_t _idx, SpvDecoration::Enum _decoration, uint32_t _literal)
  316. {
  317. update(get(_id, _idx), _decoration, _literal);
  318. }
  319. void update(uint32_t _id, TypeId::Enum _type)
  320. {
  321. TypeId& type = getTypeId(_id);
  322. type.type = _type;
  323. }
  324. void update(uint32_t _id, TypeId::Enum _type, uint32_t _baseTypeId, uint32_t _numComonents)
  325. {
  326. TypeId& type = getTypeId(_id);
  327. type.type = _type;
  328. type.baseType = getTypeId(_baseTypeId).type;
  329. type.numComponents = _numComonents;
  330. }
  331. };
  332. bool spvParse(uint32_t _offset, const SpvInstruction& _instruction, void* _userData)
  333. {
  334. BX_UNUSED(_offset);
  335. SpvReflection* spv = (SpvReflection*)_userData;
  336. switch (_instruction.opcode)
  337. {
  338. case SpvOpcode::Name:
  339. spv->update(_instruction.result
  340. , _instruction.operand[0].literalString
  341. );
  342. break;
  343. case SpvOpcode::Decorate:
  344. spv->update(_instruction.operand[0].data
  345. , SpvDecoration::Enum(_instruction.operand[1].data)
  346. , _instruction.operand[2].data
  347. );
  348. break;
  349. case SpvOpcode::MemberName:
  350. spv->update(_instruction.result
  351. , _instruction.operand[0].data
  352. , _instruction.operand[1].literalString
  353. );
  354. break;
  355. case SpvOpcode::MemberDecorate:
  356. spv->update(_instruction.operand[0].data
  357. , _instruction.operand[1].data
  358. , SpvDecoration::Enum(_instruction.operand[2].data)
  359. , _instruction.operand[3].data
  360. );
  361. break;
  362. case SpvOpcode::Variable:
  363. spv->update(_instruction.result
  364. , _instruction.type
  365. , SpvStorageClass::Enum(_instruction.operand[0].data)
  366. );
  367. break;
  368. case SpvOpcode::TypeVoid:
  369. spv->update(_instruction.result, SpvReflection::TypeId::Void);
  370. break;
  371. case SpvOpcode::TypeBool:
  372. spv->update(_instruction.result, SpvReflection::TypeId::Bool);
  373. break;
  374. case SpvOpcode::TypeInt:
  375. spv->update(_instruction.result
  376. , 32 == _instruction.operand[0].data
  377. ? 0 == _instruction.operand[1].data
  378. ? SpvReflection::TypeId::Uint32
  379. : SpvReflection::TypeId::Int32
  380. : 0 == _instruction.operand[1].data
  381. ? SpvReflection::TypeId::Uint64
  382. : SpvReflection::TypeId::Int64
  383. );
  384. break;
  385. case SpvOpcode::TypeFloat:
  386. spv->update(_instruction.result
  387. , 32 == _instruction.operand[0].data
  388. ? SpvReflection::TypeId::Float
  389. : SpvReflection::TypeId::Double
  390. );
  391. break;
  392. case SpvOpcode::TypeVector:
  393. spv->update(_instruction.result
  394. , SpvReflection::TypeId::Vector
  395. , _instruction.operand[0].data
  396. , _instruction.operand[1].data
  397. );
  398. break;
  399. case SpvOpcode::TypeMatrix:
  400. spv->update(_instruction.result
  401. , SpvReflection::TypeId::Matrix
  402. , _instruction.operand[0].data
  403. , _instruction.operand[1].data
  404. );
  405. break;
  406. case SpvOpcode::TypeImage:
  407. case SpvOpcode::TypeSampler:
  408. case SpvOpcode::TypeSampledImage:
  409. break;
  410. case SpvOpcode::TypeStruct:
  411. for (uint32_t ii = 0, num = _instruction.numOperands; ii < num; ++ii)
  412. {
  413. SpvReflection::Id::Variable& var = spv->get(_instruction.result, ii);
  414. var.type = _instruction.operand[ii].data;
  415. }
  416. break;
  417. default:
  418. break;
  419. }
  420. return true;
  421. }
  422. #define DBG(...) // bx::debugPrintf(__VA_ARGS__)
  423. void disassemble(bx::WriterI* _writer, bx::ReaderSeekerI* _reader, bx::Error* _err)
  424. {
  425. BX_UNUSED(_writer);
  426. uint32_t magic;
  427. bx::peek(_reader, magic);
  428. SpvReflection spvx;
  429. if (magic == SPV_CHUNK_HEADER)
  430. {
  431. SpirV spirv;
  432. read(_reader, spirv, _err);
  433. parse(spirv.shader, spvParse, &spvx, _err);
  434. for (SpvReflection::IdMap::const_iterator it = spvx.idMap.begin(), itEnd = spvx.idMap.end(); it != itEnd; ++it)
  435. {
  436. const SpvReflection::Id& id = it->second;
  437. uint32_t num = uint32_t(id.members.size() );
  438. if (0 < num
  439. && 0 != bx::strCmp(id.var.name.c_str(), "gl_PerVertex") )
  440. {
  441. DBG("%3d: %s %d %s\n"
  442. , it->first
  443. , id.var.name.c_str()
  444. , id.var.location
  445. , getName(id.var.storageClass)
  446. );
  447. DBG("{\n");
  448. for (uint32_t ii = 0; ii < num; ++ii)
  449. {
  450. const SpvReflection::Id::Variable& var = id.members[ii];
  451. DBG("\t\t%s %s %d %s\n"
  452. , spvx.getTypeName(var.type).c_str()
  453. , var.name.c_str()
  454. , var.offset
  455. , getName(var.storageClass)
  456. );
  457. BX_UNUSED(var);
  458. }
  459. DBG("}\n");
  460. }
  461. }
  462. }
  463. }
  464. static EShLanguage getLang(char _p)
  465. {
  466. switch (_p)
  467. {
  468. case 'c': return EShLangCompute;
  469. case 'f': return EShLangFragment;
  470. case 'v': return EShLangVertex;
  471. default: return EShLangCount;
  472. }
  473. }
  474. // static void printError(spv_message_level_t, const char*, const spv_position_t&, const char* _message)
  475. // {
  476. // fprintf(stderr, "%s\n", _message);
  477. // }
  478. static const char* s_attribName[] =
  479. {
  480. "a_position",
  481. "a_normal",
  482. "a_tangent",
  483. "a_bitangent",
  484. "a_color0",
  485. "a_color1",
  486. "a_color2",
  487. "a_color3",
  488. "a_indices",
  489. "a_weight",
  490. "a_texcoord0",
  491. "a_texcoord1",
  492. "a_texcoord2",
  493. "a_texcoord3",
  494. "a_texcoord4",
  495. "a_texcoord5",
  496. "a_texcoord6",
  497. "a_texcoord7",
  498. };
  499. BX_STATIC_ASSERT(bgfx::Attrib::Count == BX_COUNTOF(s_attribName) );
  500. bgfx::Attrib::Enum toAttribEnum(const bx::StringView& _name)
  501. {
  502. for (uint8_t ii = 0; ii < Attrib::Count; ++ii)
  503. {
  504. if (0 == bx::strCmp(s_attribName[ii], _name) )
  505. {
  506. return bgfx::Attrib::Enum(ii);
  507. }
  508. }
  509. return bgfx::Attrib::Count;
  510. }
  511. static uint16_t writeUniformArray(bx::WriterI* _writer, const UniformArray& uniforms, bool isFragmentShader)
  512. {
  513. uint16_t size = 0;
  514. uint16_t count = static_cast<uint16_t>(uniforms.size());
  515. bx::write(_writer, count);
  516. uint32_t fragmentBit = isFragmentShader ? BGFX_UNIFORM_FRAGMENTBIT : 0;
  517. for (uint16_t ii = 0; ii < count; ++ii)
  518. {
  519. const Uniform& un = uniforms[ii];
  520. size += un.regCount*16;
  521. uint8_t nameSize = (uint8_t)un.name.size();
  522. bx::write(_writer, nameSize);
  523. bx::write(_writer, un.name.c_str(), nameSize);
  524. bx::write(_writer, uint8_t(un.type | fragmentBit));
  525. bx::write(_writer, un.num);
  526. bx::write(_writer, un.regIndex);
  527. bx::write(_writer, un.regCount);
  528. BX_TRACE("%s, %s, %d, %d, %d"
  529. , un.name.c_str()
  530. , getUniformTypeName(un.type)
  531. , un.num
  532. , un.regIndex
  533. , un.regCount
  534. );
  535. }
  536. return size;
  537. }
  538. static bool compile(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer, bool _firstPass)
  539. {
  540. BX_UNUSED(_version);
  541. glslang::InitializeProcess();
  542. glslang::TProgram* program = new glslang::TProgram;
  543. EShLanguage stage = getLang(_options.shaderType);
  544. if (EShLangCount == stage)
  545. {
  546. fprintf(stderr, "Error: Unknown shader type '%c'.\n", _options.shaderType);
  547. return false;
  548. }
  549. glslang::TShader* shader = new glslang::TShader(stage);
  550. EShMessages messages = EShMessages(0
  551. | EShMsgDefault
  552. | EShMsgReadHlsl
  553. | EShMsgVulkanRules
  554. | EShMsgSpvRules
  555. );
  556. shader->setEntryPoint("main");
  557. const char* shaderStrings[] = { _code.c_str() };
  558. shader->setStrings(
  559. shaderStrings
  560. , BX_COUNTOF(shaderStrings)
  561. );
  562. bool compiled = shader->parse(&resourceLimits
  563. , 110
  564. , false
  565. , messages
  566. );
  567. bool linked = false;
  568. bool validated = true;
  569. if (!compiled)
  570. {
  571. const char* log = shader->getInfoLog();
  572. if (NULL != log)
  573. {
  574. int32_t source = 0;
  575. int32_t line = 0;
  576. int32_t column = 0;
  577. int32_t start = 0;
  578. int32_t end = INT32_MAX;
  579. bx::StringView err = bx::strFind(log, "ERROR:");
  580. bool found = false;
  581. if (!err.isEmpty() )
  582. {
  583. found = 2 == sscanf(err.getPtr(), "ERROR: %u:%u: '", &source, &line);
  584. if (found)
  585. {
  586. ++line;
  587. }
  588. }
  589. if (found)
  590. {
  591. start = bx::uint32_imax(1, line-10);
  592. end = start + 20;
  593. }
  594. printCode(_code.c_str(), line, start, end, column);
  595. fprintf(stderr, "%s\n", log);
  596. }
  597. }
  598. else
  599. {
  600. program->addShader(shader);
  601. linked = true
  602. && program->link(messages)
  603. && program->mapIO()
  604. ;
  605. if (!linked)
  606. {
  607. const char* log = program->getInfoLog();
  608. if (NULL != log)
  609. {
  610. fprintf(stderr, "%s\n", log);
  611. }
  612. }
  613. else
  614. {
  615. program->buildReflection();
  616. if (_firstPass)
  617. {
  618. // first time through, we just find unused uniforms and get rid of them
  619. std::string output;
  620. bx::Error err;
  621. LineReader reader(_code.c_str() );
  622. while (err.isOk() )
  623. {
  624. char str[4096];
  625. int32_t len = bx::read(&reader, str, BX_COUNTOF(str), &err);
  626. if (err.isOk() )
  627. {
  628. std::string strLine(str, len);
  629. size_t index = strLine.find("uniform ");
  630. if (index != std::string::npos)
  631. {
  632. bool found = false;
  633. if (!bx::findIdentifierMatch(strLine.c_str(), "SamplerState").isEmpty() ||
  634. !bx::findIdentifierMatch(strLine.c_str(), "SamplerComparisonState").isEmpty())
  635. {
  636. found = true;
  637. }
  638. else
  639. {
  640. for (int32_t ii = 0, num = program->getNumLiveUniformVariables(); ii < num; ++ii)
  641. {
  642. // matching lines like: uniform u_name;
  643. // we want to replace "uniform" with "static" so that it's no longer
  644. // included in the uniform blob that the application must upload
  645. // we can't just remove them, because unused functions might still reference
  646. // them and cause a compile error when they're gone
  647. if (!bx::findIdentifierMatch(strLine.c_str(), program->getUniformName(ii)).isEmpty())
  648. {
  649. found = true;
  650. break;
  651. }
  652. }
  653. }
  654. if (!found)
  655. {
  656. strLine = strLine.replace(index, 7 /* uniform */, "static");
  657. }
  658. }
  659. output += strLine;
  660. }
  661. }
  662. // recompile with the unused uniforms converted to statics
  663. return compile(_options, _version, output.c_str(), _writer, false);
  664. }
  665. UniformArray uniforms;
  666. {
  667. uint16_t count = (uint16_t)program->getNumLiveUniformVariables();
  668. for (uint16_t ii = 0; ii < count; ++ii)
  669. {
  670. Uniform un;
  671. un.name = program->getUniformName(ii);
  672. un.num = uint8_t(program->getUniformArraySize(ii) );
  673. const uint32_t offset = program->getUniformBufferOffset(ii);
  674. un.regIndex = uint16_t(offset);
  675. un.regCount = un.num;
  676. switch (program->getUniformType(ii))
  677. {
  678. case 0x1404: // GL_INT:
  679. un.type = UniformType::Sampler;
  680. break;
  681. case 0x8B52: // GL_FLOAT_VEC4:
  682. un.type = UniformType::Vec4;
  683. break;
  684. case 0x8B5B: // GL_FLOAT_MAT3:
  685. un.type = UniformType::Mat3;
  686. un.regCount *= 3;
  687. break;
  688. case 0x8B5C: // GL_FLOAT_MAT4:
  689. un.type = UniformType::Mat4;
  690. un.regCount *= 4;
  691. break;
  692. default:
  693. un.type = UniformType::End;
  694. break;
  695. }
  696. uniforms.push_back(un);
  697. }
  698. }
  699. if (g_verbose)
  700. {
  701. program->dumpReflection();
  702. }
  703. BX_UNUSED(spv::MemorySemanticsAllMemory);
  704. glslang::TIntermediate* intermediate = program->getIntermediate(stage);
  705. std::vector<uint32_t> spirv;
  706. glslang::SpvOptions options;
  707. options.disableOptimizer = false;
  708. glslang::GlslangToSpv(*intermediate, spirv, &options);
  709. spvtools::Optimizer opt(SPV_ENV_VULKAN_1_0);
  710. auto print_msg_to_stderr = [](spv_message_level_t, const char*,
  711. const spv_position_t&, const char* m) {
  712. fprintf(stderr, "error:%s\n", m);
  713. };
  714. opt.SetMessageConsumer(print_msg_to_stderr);
  715. opt.RegisterLegalizationPasses();
  716. if (!opt.Run(spirv.data(), spirv.size(), &spirv))
  717. {
  718. compiled = false;
  719. }
  720. else
  721. {
  722. bx::Error err;
  723. bx::WriterI* writer = bx::getDebugOut();
  724. bx::MemoryReader reader(spirv.data(), uint32_t(spirv.size()*4) );
  725. disassemble(writer, &reader, &err);
  726. spirv_cross::CompilerReflection refl(spirv);
  727. spirv_cross::ShaderResources resourcesrefl = refl.get_shader_resources();
  728. // Loop through the separate_images, and extract the uniform names:
  729. for (auto &resource : resourcesrefl.separate_images)
  730. {
  731. std::string name = refl.get_name(resource.id);
  732. if (name.size() > 7 && 0 == bx::strCmp(name.c_str() + name.length() - 7, "Texture") )
  733. {
  734. auto uniform_name = name.substr(0, name.length() - 7);
  735. Uniform un;
  736. un.name = uniform_name;
  737. un.type = UniformType::Sampler;
  738. un.num = 0; // needed?
  739. un.regIndex = 0; // needed?
  740. un.regCount = 0; // needed?
  741. uniforms.push_back(un);
  742. }
  743. }
  744. uint16_t size = writeUniformArray( _writer, uniforms, _options.shaderType == 'f');
  745. if (_version == BX_MAKEFOURCC('M', 'T', 'L', 0))
  746. {
  747. if (g_verbose)
  748. {
  749. glslang::SpirvToolsDisassemble(std::cout, spirv);
  750. }
  751. spirv_cross::CompilerMSL msl(std::move(spirv));
  752. spirv_cross::ShaderResources resources = msl.get_shader_resources();
  753. std::vector<spirv_cross::EntryPoint> entryPoints = msl.get_entry_points_and_stages();
  754. if (!entryPoints.empty())
  755. msl.rename_entry_point(entryPoints[0].name, "xlatMtlMain", entryPoints[0].execution_model);
  756. for (auto &resource : resources.uniform_buffers)
  757. {
  758. msl.set_name(resource.id, "_mtl_u");
  759. }
  760. for (auto &resource : resources.storage_buffers)
  761. {
  762. unsigned binding = msl.get_decoration(resource.id, spv::DecorationBinding);
  763. msl.set_decoration(resource.id, spv::DecorationBinding, binding + 1);
  764. }
  765. for (auto &resource : resources.separate_images)
  766. {
  767. std::string name = msl.get_name(resource.id);
  768. if (name.size() > 7 && 0 == bx::strCmp(name.c_str() + name.length() - 7, "Texture") )
  769. msl.set_name(resource.id, name.substr(0, name.length() - 7));
  770. }
  771. std::string source = msl.compile();
  772. if ('c' == _options.shaderType)
  773. {
  774. for (int i = 0; i < 3; ++i)
  775. {
  776. uint16_t dim = (uint16_t)msl.get_execution_mode_argument(spv::ExecutionMode::ExecutionModeLocalSize, i);
  777. bx::write(_writer, dim);
  778. }
  779. }
  780. uint32_t shaderSize = (uint32_t)source.size();
  781. bx::write(_writer, shaderSize);
  782. bx::write(_writer, source.c_str(), shaderSize);
  783. uint8_t nul = 0;
  784. bx::write(_writer, nul);
  785. }
  786. else
  787. {
  788. uint32_t shaderSize = (uint32_t)spirv.size() * sizeof(uint32_t);
  789. bx::write(_writer, shaderSize);
  790. bx::write(_writer, spirv.data(), shaderSize);
  791. uint8_t nul = 0;
  792. bx::write(_writer, nul);
  793. }
  794. //
  795. const uint8_t numAttr = (uint8_t)program->getNumLiveAttributes();
  796. bx::write(_writer, numAttr);
  797. for (uint8_t ii = 0; ii < numAttr; ++ii)
  798. {
  799. bgfx::Attrib::Enum attr = toAttribEnum(program->getAttributeName(ii) );
  800. if (bgfx::Attrib::Count != attr)
  801. {
  802. bx::write(_writer, bgfx::attribToId(attr) );
  803. }
  804. else
  805. {
  806. bx::write(_writer, uint16_t(UINT16_MAX) );
  807. }
  808. }
  809. bx::write(_writer, size);
  810. }
  811. }
  812. }
  813. delete program;
  814. delete shader;
  815. glslang::FinalizeProcess();
  816. return compiled && linked && validated;
  817. }
  818. } // namespace spirv
  819. bool compileSPIRVShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer)
  820. {
  821. return spirv::compile(_options, _version, _code, _writer, true);
  822. }
  823. } // namespace bgfx