shaderc_metal.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. /*
  2. * Copyright 2011-2026 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
  4. */
  5. #include "shaderc.h"
  6. #include <iostream> // std::cout
  7. BX_PRAGMA_DIAGNOSTIC_PUSH()
  8. BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4100) // error C4100: 'inclusionDepth' : unreferenced formal parameter
  9. BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4265) // error C4265: 'spv::spirvbin_t': class has virtual functions, but destructor is not virtual
  10. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wattributes") // warning: attribute ignored
  11. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wdeprecated-declarations") // warning: ‘MSLVertexAttr’ is deprecated
  12. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wtype-limits") // warning: comparison of unsigned expression in ‘< 0’ is always false
  13. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wshadow") // warning: declaration of 'userData' shadows a member of 'glslang::TShader::Includer::IncludeResult'
  14. #define SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
  15. #include <spirv_common.hpp>
  16. #include <spirv_msl.hpp>
  17. #include <spirv_reflect.hpp>
  18. #define ENABLE_OPT 1
  19. #include <ShaderLang.h>
  20. #include <ResourceLimits.h>
  21. #include <SPIRV/GlslangToSpv.h>
  22. #include <SPIRV/SpvTools.h>
  23. #include <spirv-tools/optimizer.hpp>
  24. BX_PRAGMA_DIAGNOSTIC_POP()
  25. namespace bgfx
  26. {
  27. struct TinyStlAllocator
  28. {
  29. static void* static_allocate(size_t _bytes);
  30. static void static_deallocate(void* _ptr, size_t /*_bytes*/);
  31. };
  32. } // namespace bgfx
  33. #define TINYSTL_ALLOCATOR bgfx::TinyStlAllocator
  34. #include <tinystl/allocator.h>
  35. #include <tinystl/string.h>
  36. #include <tinystl/unordered_map.h>
  37. #include <tinystl/vector.h>
  38. namespace stl = tinystl;
  39. #include "../../src/shader.h"
  40. namespace bgfx { namespace metal
  41. {
  42. const TBuiltInResource resourceLimits =
  43. {
  44. 32, // MaxLights
  45. 6, // MaxClipPlanes
  46. 32, // MaxTextureUnits
  47. 32, // MaxTextureCoords
  48. 64, // MaxVertexAttribs
  49. 4096, // MaxVertexUniformComponents
  50. 64, // MaxVaryingFloats
  51. 32, // MaxVertexTextureImageUnits
  52. 80, // MaxCombinedTextureImageUnits
  53. 32, // MaxTextureImageUnits
  54. 4096, // MaxFragmentUniformComponents
  55. 32, // MaxDrawBuffers
  56. 128, // MaxVertexUniformVectors
  57. 8, // MaxVaryingVectors
  58. 16, // MaxFragmentUniformVectors
  59. 16, // MaxVertexOutputVectors
  60. 15, // MaxFragmentInputVectors
  61. -8, // MinProgramTexelOffset
  62. 7, // MaxProgramTexelOffset
  63. 8, // MaxClipDistances
  64. 65535, // MaxComputeWorkGroupCountX
  65. 65535, // MaxComputeWorkGroupCountY
  66. 65535, // MaxComputeWorkGroupCountZ
  67. 1024, // MaxComputeWorkGroupSizeX
  68. 1024, // MaxComputeWorkGroupSizeY
  69. 64, // MaxComputeWorkGroupSizeZ
  70. 1024, // MaxComputeUniformComponents
  71. 16, // MaxComputeTextureImageUnits
  72. 8, // MaxComputeImageUniforms
  73. 8, // MaxComputeAtomicCounters
  74. 1, // MaxComputeAtomicCounterBuffers
  75. 60, // MaxVaryingComponents
  76. 64, // MaxVertexOutputComponents
  77. 64, // MaxGeometryInputComponents
  78. 128, // MaxGeometryOutputComponents
  79. 128, // MaxFragmentInputComponents
  80. 8, // MaxImageUnits
  81. 8, // MaxCombinedImageUnitsAndFragmentOutputs
  82. 8, // MaxCombinedShaderOutputResources
  83. 0, // MaxImageSamples
  84. 0, // MaxVertexImageUniforms
  85. 0, // MaxTessControlImageUniforms
  86. 0, // MaxTessEvaluationImageUniforms
  87. 0, // MaxGeometryImageUniforms
  88. 8, // MaxFragmentImageUniforms
  89. 8, // MaxCombinedImageUniforms
  90. 16, // MaxGeometryTextureImageUnits
  91. 256, // MaxGeometryOutputVertices
  92. 1024, // MaxGeometryTotalOutputComponents
  93. 1024, // MaxGeometryUniformComponents
  94. 64, // MaxGeometryVaryingComponents
  95. 128, // MaxTessControlInputComponents
  96. 128, // MaxTessControlOutputComponents
  97. 16, // MaxTessControlTextureImageUnits
  98. 1024, // MaxTessControlUniformComponents
  99. 4096, // MaxTessControlTotalOutputComponents
  100. 128, // MaxTessEvaluationInputComponents
  101. 128, // MaxTessEvaluationOutputComponents
  102. 16, // MaxTessEvaluationTextureImageUnits
  103. 1024, // MaxTessEvaluationUniformComponents
  104. 120, // MaxTessPatchComponents
  105. 32, // MaxPatchVertices
  106. 64, // MaxTessGenLevel
  107. 16, // MaxViewports
  108. 0, // MaxVertexAtomicCounters
  109. 0, // MaxTessControlAtomicCounters
  110. 0, // MaxTessEvaluationAtomicCounters
  111. 0, // MaxGeometryAtomicCounters
  112. 8, // MaxFragmentAtomicCounters
  113. 8, // MaxCombinedAtomicCounters
  114. 1, // MaxAtomicCounterBindings
  115. 0, // MaxVertexAtomicCounterBuffers
  116. 0, // MaxTessControlAtomicCounterBuffers
  117. 0, // MaxTessEvaluationAtomicCounterBuffers
  118. 0, // MaxGeometryAtomicCounterBuffers
  119. 1, // MaxFragmentAtomicCounterBuffers
  120. 1, // MaxCombinedAtomicCounterBuffers
  121. 16384, // MaxAtomicCounterBufferSize
  122. 4, // MaxTransformFeedbackBuffers
  123. 64, // MaxTransformFeedbackInterleavedComponents
  124. 8, // MaxCullDistances
  125. 8, // MaxCombinedClipAndCullDistances
  126. 4, // MaxSamples
  127. 0, // maxMeshOutputVerticesNV
  128. 0, // maxMeshOutputPrimitivesNV
  129. 0, // maxMeshWorkGroupSizeX_NV
  130. 0, // maxMeshWorkGroupSizeY_NV
  131. 0, // maxMeshWorkGroupSizeZ_NV
  132. 0, // maxTaskWorkGroupSizeX_NV
  133. 0, // maxTaskWorkGroupSizeY_NV
  134. 0, // maxTaskWorkGroupSizeZ_NV
  135. 0, // maxMeshViewCountNV
  136. 0, // maxMeshOutputVerticesEXT
  137. 0, // maxMeshOutputPrimitivesEXT
  138. 0, // maxMeshWorkGroupSizeX_EXT
  139. 0, // maxMeshWorkGroupSizeY_EXT
  140. 0, // maxMeshWorkGroupSizeZ_EXT
  141. 0, // maxTaskWorkGroupSizeX_EXT
  142. 0, // maxTaskWorkGroupSizeY_EXT
  143. 0, // maxTaskWorkGroupSizeZ_EXT
  144. 0, // maxMeshViewCountEXT
  145. 0, // maxDualSourceDrawBuffersEXT
  146. { // limits
  147. true, // nonInductiveForLoops
  148. true, // whileLoops
  149. true, // doWhileLoops
  150. true, // generalUniformIndexing
  151. true, // generalAttributeMatrixVectorIndexing
  152. true, // generalVaryingIndexing
  153. true, // generalSamplerIndexing
  154. true, // generalVariableIndexing
  155. true, // generalConstantMatrixVectorIndexing
  156. },
  157. };
  158. static EShLanguage getLang(char _p)
  159. {
  160. switch (_p)
  161. {
  162. case 'c': return EShLangCompute;
  163. case 'f': return EShLangFragment;
  164. case 'v': return EShLangVertex;
  165. default: return EShLangCount;
  166. }
  167. }
  168. static const char* s_attribName[] =
  169. {
  170. "a_position",
  171. "a_normal",
  172. "a_tangent",
  173. "a_bitangent",
  174. "a_color0",
  175. "a_color1",
  176. "a_color2",
  177. "a_color3",
  178. "a_indices",
  179. "a_weight",
  180. "a_texcoord0",
  181. "a_texcoord1",
  182. "a_texcoord2",
  183. "a_texcoord3",
  184. "a_texcoord4",
  185. "a_texcoord5",
  186. "a_texcoord6",
  187. "a_texcoord7",
  188. };
  189. static_assert(bgfx::Attrib::Count == BX_COUNTOF(s_attribName) );
  190. bgfx::Attrib::Enum toAttribEnum(const bx::StringView& _name)
  191. {
  192. for (uint8_t ii = 0; ii < Attrib::Count; ++ii)
  193. {
  194. if (0 == bx::strCmp(s_attribName[ii], _name) )
  195. {
  196. return bgfx::Attrib::Enum(ii);
  197. }
  198. }
  199. return bgfx::Attrib::Count;
  200. }
  201. static const char* s_samplerTypes[] =
  202. {
  203. "BgfxSampler2D",
  204. "BgfxISampler2D",
  205. "BgfxUSampler2D",
  206. "BgfxSampler2DArray",
  207. "BgfxSampler2DShadow",
  208. "BgfxSampler2DArrayShadow",
  209. "BgfxSampler3D",
  210. "BgfxISampler3D",
  211. "BgfxUSampler3D",
  212. "BgfxSamplerCube",
  213. "BgfxSamplerCubeShadow",
  214. "BgfxSampler2DMS",
  215. };
  216. static uint16_t writeUniformArray(bx::WriterI* _shaderWriter, const UniformArray& uniforms, bool isFragmentShader)
  217. {
  218. uint16_t size = 0;
  219. bx::ErrorAssert err;
  220. uint16_t count = uint16_t(uniforms.size());
  221. bx::write(_shaderWriter, count, &err);
  222. uint32_t fragmentBit = isFragmentShader ? kUniformFragmentBit : 0;
  223. for (uint16_t ii = 0; ii < count; ++ii)
  224. {
  225. const Uniform& un = uniforms[ii];
  226. size += un.regCount*16;
  227. uint8_t nameSize = (uint8_t)un.name.size();
  228. bx::write(_shaderWriter, nameSize, &err);
  229. bx::write(_shaderWriter, un.name.c_str(), nameSize, &err);
  230. bx::write(_shaderWriter, uint8_t(un.type | fragmentBit), &err);
  231. bx::write(_shaderWriter, un.num, &err);
  232. bx::write(_shaderWriter, un.regIndex, &err);
  233. bx::write(_shaderWriter, un.regCount, &err);
  234. bx::write(_shaderWriter, un.texComponent, &err);
  235. bx::write(_shaderWriter, un.texDimension, &err);
  236. bx::write(_shaderWriter, un.texFormat, &err);
  237. BX_TRACE("%s, %s, %d, %d, %d"
  238. , un.name.c_str()
  239. , getUniformTypeName(un.type)
  240. , un.num
  241. , un.regIndex
  242. , un.regCount
  243. );
  244. }
  245. return size;
  246. }
  247. static spv_target_env getSpirvTargetVersion(uint32_t _version, bx::WriterI* _messageWriter)
  248. {
  249. bx::ErrorAssert err;
  250. switch (_version)
  251. {
  252. case 1000:
  253. case 1110:
  254. case 1210:
  255. return SPV_ENV_VULKAN_1_0;
  256. case 2011:
  257. case 2111:
  258. case 2211:
  259. return SPV_ENV_VULKAN_1_1;
  260. case 2314:
  261. case 2414:
  262. case 3014:
  263. case 3114:
  264. return SPV_ENV_VULKAN_1_1_SPIRV_1_4;
  265. default:
  266. bx::write(_messageWriter, &err, "Warning: Unknown SPIR-V version requested. Returning SPV_ENV_VULKAN_1_0 as default.\n");
  267. return SPV_ENV_VULKAN_1_0;
  268. }
  269. }
  270. static glslang::EShTargetLanguageVersion getGlslangTargetSpirvVersion(uint32_t _version, bx::WriterI* _messageWriter)
  271. {
  272. bx::ErrorAssert err;
  273. switch (_version)
  274. {
  275. case 1000:
  276. case 1110:
  277. case 1210:
  278. return glslang::EShTargetSpv_1_0;
  279. case 2011:
  280. case 2111:
  281. case 2211:
  282. return glslang::EShTargetSpv_1_1;
  283. case 2314:
  284. case 2414:
  285. case 3014:
  286. case 3114:
  287. return glslang::EShTargetSpv_1_4;
  288. default:
  289. bx::write(_messageWriter, &err, "Warning: Unknown SPIR-V version requested. Returning EShTargetSpv_1_0 as default.\n");
  290. return glslang::EShTargetSpv_1_0;
  291. }
  292. }
  293. static spirv_cross::CompilerMSL::Options::Platform getMslPlatform(const std::string& _platform)
  294. {
  295. return "ios" == _platform
  296. ? spirv_cross::CompilerMSL::Options::Platform::iOS
  297. : spirv_cross::CompilerMSL::Options::Platform::macOS;
  298. }
  299. static void getMSLVersion(const uint32_t _version, uint32_t& _major, uint32_t& _minor, bx::WriterI* _messageWriter)
  300. {
  301. bx::ErrorAssert err;
  302. _major = _version / 1000;
  303. _minor = (_version / 100) % 10;
  304. switch (_version)
  305. {
  306. case 1000:
  307. case 1110:
  308. case 1210:
  309. case 2011:
  310. case 2111:
  311. case 2211:
  312. case 2314:
  313. case 2414:
  314. case 3014:
  315. case 3114:
  316. return;
  317. default:
  318. bx::write(_messageWriter, &err, "Warning: Unknown MSL version requested. Returning 1.0 as default.\n");
  319. _major = 1;
  320. _minor = 0;
  321. }
  322. }
  323. static bool compile(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _shaderWriter, bx::WriterI* _messageWriter, bool _firstPass)
  324. {
  325. BX_UNUSED(_version);
  326. bx::ErrorAssert messageErr;
  327. glslang::InitializeProcess();
  328. EShLanguage stage = getLang(_options.shaderType);
  329. if (EShLangCount == stage)
  330. {
  331. bx::write(_messageWriter, &messageErr, "Error: Unknown shader type '%c'.\n", _options.shaderType);
  332. return false;
  333. }
  334. glslang::TProgram* program = new glslang::TProgram;
  335. glslang::TShader* shader = new glslang::TShader(stage);
  336. EShMessages messages = EShMessages(0
  337. | EShMsgDefault
  338. | EShMsgReadHlsl
  339. | EShMsgVulkanRules
  340. | EShMsgSpvRules
  341. | EShMsgDebugInfo
  342. );
  343. shader->setEntryPoint("main");
  344. shader->setAutoMapBindings(true);
  345. shader->setEnvTarget(glslang::EShTargetSpv, getGlslangTargetSpirvVersion(_version, _messageWriter));
  346. const int textureBindingOffset = 16;
  347. shader->setShiftBinding(glslang::EResTexture, textureBindingOffset);
  348. shader->setShiftBinding(glslang::EResSampler, textureBindingOffset);
  349. shader->setShiftBinding(glslang::EResImage, textureBindingOffset);
  350. const char* shaderStrings[] = { _code.c_str() };
  351. shader->setStrings(
  352. shaderStrings
  353. , BX_COUNTOF(shaderStrings)
  354. );
  355. bool compiled = shader->parse(&resourceLimits
  356. , 110
  357. , false
  358. , messages
  359. );
  360. bool linked = false;
  361. bool validated = true;
  362. if (!compiled)
  363. {
  364. const char* log = shader->getInfoLog();
  365. if (NULL != log)
  366. {
  367. int32_t source = 0;
  368. int32_t line = 0;
  369. int32_t column = 0;
  370. int32_t start = 0;
  371. int32_t end = INT32_MAX;
  372. bx::StringView err = bx::strFind(log, "ERROR:");
  373. bool found = false;
  374. if (!err.isEmpty() )
  375. {
  376. found = 2 == sscanf(err.getPtr(), "ERROR: %u:%u: '", &source, &line);
  377. if (found)
  378. {
  379. ++line;
  380. }
  381. }
  382. if (found)
  383. {
  384. start = bx::uint32_imax(1, line-10);
  385. end = start + 20;
  386. }
  387. printCode(_code.c_str(), bx::uint32_satsub(line, 1), start, end, column);
  388. bx::write(_messageWriter, &messageErr, "%s\n", log);
  389. }
  390. }
  391. else
  392. {
  393. program->addShader(shader);
  394. linked = true
  395. && program->link(messages)
  396. && program->mapIO()
  397. ;
  398. if (!linked)
  399. {
  400. const char* log = program->getInfoLog();
  401. if (NULL != log)
  402. {
  403. bx::write(_messageWriter, &messageErr, "%s\n", log);
  404. }
  405. }
  406. else
  407. {
  408. program->buildReflection();
  409. if (_firstPass)
  410. {
  411. // first time through, we just find unused uniforms and get rid of them
  412. std::string output;
  413. bx::Error err;
  414. bx::LineReader reader(_code.c_str() );
  415. while (!reader.isDone() )
  416. {
  417. bx::StringView strLine = reader.next();
  418. bx::StringView str = strFind(strLine, "uniform ");
  419. if (!str.isEmpty() )
  420. {
  421. // If the line declares a uniform, merge all next
  422. // lines until we encounter a semicolon.
  423. bx::StringView lineEnd = strFind(strLine, ";");
  424. while (lineEnd.isEmpty() && !reader.isDone())
  425. {
  426. bx::StringView nextLine = reader.next();
  427. strLine.set(strLine.getPtr(), nextLine.getTerm());
  428. lineEnd = strFind(nextLine, ";");
  429. }
  430. bool found = false;
  431. for (uint32_t ii = 0; ii < BX_COUNTOF(s_samplerTypes); ++ii)
  432. {
  433. if (!bx::findIdentifierMatch(strLine, s_samplerTypes[ii]).isEmpty() )
  434. {
  435. found = true;
  436. break;
  437. }
  438. }
  439. if (!found)
  440. {
  441. for (int32_t ii = 0, num = program->getNumLiveUniformVariables(); ii < num; ++ii)
  442. {
  443. // matching lines like: uniform u_name;
  444. // we want to replace "uniform" with "static" so that it's no longer
  445. // included in the uniform blob that the application must upload
  446. // we can't just remove them, because unused functions might still reference
  447. // them and cause a compile error when they're gone
  448. if (!bx::findIdentifierMatch(strLine, program->getUniformName(ii) ).isEmpty() )
  449. {
  450. found = true;
  451. break;
  452. }
  453. }
  454. }
  455. if (!found)
  456. {
  457. output.append(strLine.getPtr(), str.getPtr() );
  458. output += "static ";
  459. output.append(str.getTerm(), strLine.getTerm() );
  460. output += "\n";
  461. }
  462. else
  463. {
  464. output.append(strLine.getPtr(), strLine.getTerm() );
  465. output += "\n";
  466. }
  467. }
  468. else
  469. {
  470. output.append(strLine.getPtr(), strLine.getTerm() );
  471. output += "\n";
  472. }
  473. }
  474. // recompile with the unused uniforms converted to statics
  475. delete program;
  476. delete shader;
  477. return compile(_options, _version, output.c_str(), _shaderWriter, _messageWriter, false);
  478. }
  479. UniformArray uniforms;
  480. {
  481. uint16_t count = (uint16_t)program->getNumLiveUniformVariables();
  482. for (uint16_t ii = 0; ii < count; ++ii)
  483. {
  484. Uniform un;
  485. un.name = program->getUniformName(ii);
  486. if (bx::hasSuffix(un.name.c_str(), ".@data") )
  487. {
  488. continue;
  489. }
  490. un.num = uint8_t(program->getUniformArraySize(ii) );
  491. const uint32_t offset = program->getUniformBufferOffset(ii);
  492. un.regIndex = uint16_t(offset);
  493. un.regCount = un.num;
  494. switch (program->getUniformType(ii) )
  495. {
  496. case 0x1404: // GL_INT:
  497. un.type = UniformType::Sampler;
  498. break;
  499. case 0x8B52: // GL_FLOAT_VEC4:
  500. un.type = UniformType::Vec4;
  501. break;
  502. case 0x8B5B: // GL_FLOAT_MAT3:
  503. un.type = UniformType::Mat3;
  504. un.regCount *= 3;
  505. break;
  506. case 0x8B5C: // GL_FLOAT_MAT4:
  507. un.type = UniformType::Mat4;
  508. un.regCount *= 4;
  509. break;
  510. default:
  511. un.type = UniformType::End;
  512. break;
  513. }
  514. uniforms.push_back(un);
  515. }
  516. }
  517. if (g_verbose)
  518. {
  519. program->dumpReflection();
  520. }
  521. glslang::TIntermediate* intermediate = program->getIntermediate(stage);
  522. std::vector<uint32_t> spirv;
  523. glslang::SpvOptions options;
  524. options.disableOptimizer = _options.debugInformation;
  525. options.generateDebugInfo = _options.debugInformation;
  526. options.emitNonSemanticShaderDebugInfo = _options.debugInformation;
  527. options.emitNonSemanticShaderDebugSource = _options.debugInformation;
  528. glslang::GlslangToSpv(*intermediate, spirv, &options);
  529. spvtools::Optimizer opt(getSpirvTargetVersion(_version, _messageWriter));
  530. auto print_msg_to_stderr = [_messageWriter, &messageErr](
  531. spv_message_level_t
  532. , const char*
  533. , const spv_position_t&
  534. , const char* m
  535. )
  536. {
  537. bx::write(_messageWriter, &messageErr, "Error: %s\n", m);
  538. };
  539. opt.SetMessageConsumer(print_msg_to_stderr);
  540. opt.RegisterLegalizationPasses();
  541. opt.RegisterPerformancePasses();
  542. spvtools::ValidatorOptions validatorOptions;
  543. validatorOptions.SetBeforeHlslLegalization(true);
  544. if (!opt.Run(
  545. spirv.data()
  546. , spirv.size()
  547. , &spirv
  548. , validatorOptions
  549. , false
  550. ) )
  551. {
  552. compiled = false;
  553. }
  554. else
  555. {
  556. if (g_verbose)
  557. {
  558. glslang::SpirvToolsDisassemble(std::cout, spirv, getSpirvTargetVersion(_version, _messageWriter));
  559. }
  560. spirv_cross::CompilerReflection refl(spirv);
  561. spirv_cross::ShaderResources resourcesrefl = refl.get_shader_resources();
  562. // Loop through the separate_images, and extract the uniform names:
  563. for (auto& resource : resourcesrefl.separate_images)
  564. {
  565. std::string name = refl.get_name(resource.id);
  566. if (name.size() > 7 && 0 == bx::strCmp(name.c_str() + name.length() - 7, "Texture"))
  567. {
  568. name = name.substr(0, name.length() - 7);
  569. }
  570. Uniform un;
  571. un.name = name;
  572. un.type = UniformType::Sampler;
  573. un.num = 0; // needed?
  574. un.regIndex = 0; // needed?
  575. un.regCount = 0; // needed?
  576. uniforms.push_back(un);
  577. }
  578. uint16_t size = writeUniformArray(_shaderWriter, uniforms, _options.shaderType == 'f');
  579. bx::Error err;
  580. spirv_cross::CompilerMSL msl(std::move(spirv) );
  581. // Configure MSL cross compiler
  582. spirv_cross::CompilerMSL::Options mslOptions = msl.get_msl_options();
  583. {
  584. // - Platform
  585. mslOptions.platform = getMslPlatform(_options.platform);
  586. // - MSL Version
  587. uint32_t major, minor;
  588. getMSLVersion(_version, major, minor, _messageWriter);
  589. mslOptions.set_msl_version(major, minor);
  590. }
  591. msl.set_msl_options(mslOptions);
  592. auto executionModel = msl.get_execution_model();
  593. spirv_cross::MSLResourceBinding newBinding;
  594. newBinding.stage = executionModel;
  595. spirv_cross::ShaderResources resources = msl.get_shader_resources();
  596. spirv_cross::SmallVector<spirv_cross::EntryPoint> entryPoints = msl.get_entry_points_and_stages();
  597. if (!entryPoints.empty() )
  598. {
  599. msl.rename_entry_point(
  600. entryPoints[0].name
  601. , "xlatMtlMain"
  602. , entryPoints[0].execution_model
  603. );
  604. }
  605. for (auto& resource : resources.uniform_buffers)
  606. {
  607. unsigned set = msl.get_decoration(resource.id, spv::DecorationDescriptorSet);
  608. unsigned binding = msl.get_decoration(resource.id, spv::DecorationBinding);
  609. newBinding.desc_set = set;
  610. newBinding.binding = binding;
  611. newBinding.msl_buffer = 0;
  612. msl.add_msl_resource_binding(newBinding);
  613. msl.set_name(resource.id, "_mtl_u");
  614. }
  615. for (auto& resource : resources.storage_buffers)
  616. {
  617. unsigned set = msl.get_decoration(resource.id, spv::DecorationDescriptorSet);
  618. unsigned binding = msl.get_decoration(resource.id, spv::DecorationBinding);
  619. newBinding.desc_set = set;
  620. newBinding.binding = binding;
  621. newBinding.msl_buffer = binding + 1;
  622. msl.add_msl_resource_binding(newBinding);
  623. }
  624. for (auto& resource : resources.separate_samplers)
  625. {
  626. unsigned set = msl.get_decoration(resource.id, spv::DecorationDescriptorSet);
  627. unsigned binding = msl.get_decoration(resource.id, spv::DecorationBinding);
  628. newBinding.desc_set = set;
  629. newBinding.binding = binding;
  630. newBinding.msl_texture = binding - textureBindingOffset;
  631. newBinding.msl_sampler = binding - textureBindingOffset;
  632. msl.add_msl_resource_binding(newBinding);
  633. }
  634. for (auto& resource : resources.separate_images)
  635. {
  636. std::string name = msl.get_name(resource.id);
  637. if (name.size() > 7 && 0 == bx::strCmp(name.c_str() + name.length() - 7, "Texture") )
  638. {
  639. msl.set_name(resource.id, name.substr(0, name.length() - 7) );
  640. }
  641. unsigned set = msl.get_decoration(resource.id, spv::DecorationDescriptorSet);
  642. unsigned binding = msl.get_decoration(resource.id, spv::DecorationBinding);
  643. newBinding.desc_set = set;
  644. newBinding.binding = binding;
  645. newBinding.msl_texture = binding - textureBindingOffset;
  646. newBinding.msl_sampler = binding - textureBindingOffset;
  647. msl.add_msl_resource_binding(newBinding);
  648. }
  649. for (auto& resource : resources.storage_images)
  650. {
  651. std::string name = msl.get_name(resource.id);
  652. unsigned set = msl.get_decoration(resource.id, spv::DecorationDescriptorSet);
  653. unsigned binding = msl.get_decoration(resource.id, spv::DecorationBinding);
  654. newBinding.desc_set = set;
  655. newBinding.binding = binding;
  656. newBinding.msl_texture = binding - textureBindingOffset;
  657. newBinding.msl_sampler = binding - textureBindingOffset;
  658. msl.add_msl_resource_binding(newBinding);
  659. }
  660. std::string source = msl.compile();
  661. // fix https://github.com/bkaradzic/bgfx/issues/2822
  662. // insert struct member which declares point size, defaulted to 1
  663. if ('v' == _options.shaderType)
  664. {
  665. const bx::StringView xlatMtlMainOut("xlatMtlMain_out\n{");
  666. size_t pos = source.find(xlatMtlMainOut.getPtr() );
  667. if (pos != std::string::npos)
  668. {
  669. pos += xlatMtlMainOut.getLength();
  670. source.insert(pos, "\n\tfloat bgfx_metal_pointSize [[point_size]] = 1;");
  671. }
  672. }
  673. if ('c' == _options.shaderType)
  674. {
  675. for (int i = 0; i < 3; ++i)
  676. {
  677. uint16_t dim = (uint16_t)msl.get_execution_mode_argument(
  678. spv::ExecutionMode::ExecutionModeLocalSize
  679. , i
  680. );
  681. bx::write(_shaderWriter, dim, &err);
  682. }
  683. }
  684. const uint32_t shaderSize = (uint32_t)source.size();
  685. bx::write(_shaderWriter, shaderSize, &err);
  686. bx::write(_shaderWriter, source.c_str(), shaderSize, &err);
  687. const uint8_t nul = 0;
  688. bx::write(_shaderWriter, nul, &err);
  689. const uint8_t numAttr = (uint8_t)program->getNumLiveAttributes();
  690. bx::write(_shaderWriter, numAttr, &err);
  691. for (uint8_t ii = 0; ii < numAttr; ++ii)
  692. {
  693. bgfx::Attrib::Enum attr = toAttribEnum(program->getAttributeName(ii) );
  694. if (bgfx::Attrib::Count != attr)
  695. {
  696. bx::write(_shaderWriter, bgfx::attribToId(attr), &err);
  697. }
  698. else
  699. {
  700. bx::write(_shaderWriter, uint16_t(UINT16_MAX), &err);
  701. }
  702. }
  703. bx::write(_shaderWriter, size, &err);
  704. }
  705. }
  706. }
  707. delete program;
  708. delete shader;
  709. glslang::FinalizeProcess();
  710. return compiled && linked && validated;
  711. }
  712. } // namespace metal
  713. bool compileMetalShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _shaderWriter, bx::WriterI* _messageWriter)
  714. {
  715. return metal::compile(_options, _version, _code, _shaderWriter, _messageWriter, true);
  716. }
  717. } // namespace bgfx