shaderc_wgsl.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  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 <BaseTypes.h>
  20. #include <Types.h>
  21. #include <ShaderLang.h>
  22. #include <ResourceLimits.h>
  23. #include <SPIRV/GlslangToSpv.h>
  24. #include <SPIRV/SpvTools.h>
  25. #include <spirv-tools/optimizer.hpp>
  26. #include <tint/api/tint.h>
  27. BX_PRAGMA_DIAGNOSTIC_POP()
  28. namespace bgfx
  29. {
  30. struct TinyStlAllocator
  31. {
  32. static void* static_allocate(size_t _bytes);
  33. static void static_deallocate(void* _ptr, size_t /*_bytes*/);
  34. };
  35. } // namespace bgfx
  36. #define TINYSTL_ALLOCATOR bgfx::TinyStlAllocator
  37. #include <tinystl/allocator.h>
  38. #include <tinystl/string.h>
  39. #include <tinystl/unordered_map.h>
  40. #include <tinystl/vector.h>
  41. namespace stl = tinystl;
  42. #include "../../src/shader.h"
  43. #include "../../src/shader_spirv.h"
  44. #include "../../3rdparty/khronos/vulkan-local/vulkan.h"
  45. namespace bgfx { namespace wgsl
  46. {
  47. const TBuiltInResource resourceLimits =
  48. {
  49. 32, // MaxLights
  50. 6, // MaxClipPlanes
  51. 32, // MaxTextureUnits
  52. 32, // MaxTextureCoords
  53. 64, // MaxVertexAttribs
  54. 4096, // MaxVertexUniformComponents
  55. 64, // MaxVaryingFloats
  56. 32, // MaxVertexTextureImageUnits
  57. 80, // MaxCombinedTextureImageUnits
  58. 32, // MaxTextureImageUnits
  59. 4096, // MaxFragmentUniformComponents
  60. 32, // MaxDrawBuffers
  61. 128, // MaxVertexUniformVectors
  62. 8, // MaxVaryingVectors
  63. 16, // MaxFragmentUniformVectors
  64. 16, // MaxVertexOutputVectors
  65. 15, // MaxFragmentInputVectors
  66. -8, // MinProgramTexelOffset
  67. 7, // MaxProgramTexelOffset
  68. 8, // MaxClipDistances
  69. 65535, // MaxComputeWorkGroupCountX
  70. 65535, // MaxComputeWorkGroupCountY
  71. 65535, // MaxComputeWorkGroupCountZ
  72. 1024, // MaxComputeWorkGroupSizeX
  73. 1024, // MaxComputeWorkGroupSizeY
  74. 64, // MaxComputeWorkGroupSizeZ
  75. 1024, // MaxComputeUniformComponents
  76. 16, // MaxComputeTextureImageUnits
  77. 8, // MaxComputeImageUniforms
  78. 8, // MaxComputeAtomicCounters
  79. 1, // MaxComputeAtomicCounterBuffers
  80. 60, // MaxVaryingComponents
  81. 64, // MaxVertexOutputComponents
  82. 64, // MaxGeometryInputComponents
  83. 128, // MaxGeometryOutputComponents
  84. 128, // MaxFragmentInputComponents
  85. 8, // MaxImageUnits
  86. 8, // MaxCombinedImageUnitsAndFragmentOutputs
  87. 8, // MaxCombinedShaderOutputResources
  88. 0, // MaxImageSamples
  89. 0, // MaxVertexImageUniforms
  90. 0, // MaxTessControlImageUniforms
  91. 0, // MaxTessEvaluationImageUniforms
  92. 0, // MaxGeometryImageUniforms
  93. 8, // MaxFragmentImageUniforms
  94. 8, // MaxCombinedImageUniforms
  95. 16, // MaxGeometryTextureImageUnits
  96. 256, // MaxGeometryOutputVertices
  97. 1024, // MaxGeometryTotalOutputComponents
  98. 1024, // MaxGeometryUniformComponents
  99. 64, // MaxGeometryVaryingComponents
  100. 128, // MaxTessControlInputComponents
  101. 128, // MaxTessControlOutputComponents
  102. 16, // MaxTessControlTextureImageUnits
  103. 1024, // MaxTessControlUniformComponents
  104. 4096, // MaxTessControlTotalOutputComponents
  105. 128, // MaxTessEvaluationInputComponents
  106. 128, // MaxTessEvaluationOutputComponents
  107. 16, // MaxTessEvaluationTextureImageUnits
  108. 1024, // MaxTessEvaluationUniformComponents
  109. 120, // MaxTessPatchComponents
  110. 32, // MaxPatchVertices
  111. 64, // MaxTessGenLevel
  112. 16, // MaxViewports
  113. 0, // MaxVertexAtomicCounters
  114. 0, // MaxTessControlAtomicCounters
  115. 0, // MaxTessEvaluationAtomicCounters
  116. 0, // MaxGeometryAtomicCounters
  117. 8, // MaxFragmentAtomicCounters
  118. 8, // MaxCombinedAtomicCounters
  119. 1, // MaxAtomicCounterBindings
  120. 0, // MaxVertexAtomicCounterBuffers
  121. 0, // MaxTessControlAtomicCounterBuffers
  122. 0, // MaxTessEvaluationAtomicCounterBuffers
  123. 0, // MaxGeometryAtomicCounterBuffers
  124. 1, // MaxFragmentAtomicCounterBuffers
  125. 1, // MaxCombinedAtomicCounterBuffers
  126. 16384, // MaxAtomicCounterBufferSize
  127. 4, // MaxTransformFeedbackBuffers
  128. 64, // MaxTransformFeedbackInterleavedComponents
  129. 8, // MaxCullDistances
  130. 8, // MaxCombinedClipAndCullDistances
  131. 4, // MaxSamples
  132. 0, // maxMeshOutputVerticesNV
  133. 0, // maxMeshOutputPrimitivesNV
  134. 0, // maxMeshWorkGroupSizeX_NV
  135. 0, // maxMeshWorkGroupSizeY_NV
  136. 0, // maxMeshWorkGroupSizeZ_NV
  137. 0, // maxTaskWorkGroupSizeX_NV
  138. 0, // maxTaskWorkGroupSizeY_NV
  139. 0, // maxTaskWorkGroupSizeZ_NV
  140. 0, // maxMeshViewCountNV
  141. 0, // maxMeshOutputVerticesEXT
  142. 0, // maxMeshOutputPrimitivesEXT
  143. 0, // maxMeshWorkGroupSizeX_EXT
  144. 0, // maxMeshWorkGroupSizeY_EXT
  145. 0, // maxMeshWorkGroupSizeZ_EXT
  146. 0, // maxTaskWorkGroupSizeX_EXT
  147. 0, // maxTaskWorkGroupSizeY_EXT
  148. 0, // maxTaskWorkGroupSizeZ_EXT
  149. 0, // maxMeshViewCountEXT
  150. 0, // maxDualSourceDrawBuffersEXT
  151. { // limits
  152. true, // nonInductiveForLoops
  153. true, // whileLoops
  154. true, // doWhileLoops
  155. true, // generalUniformIndexing
  156. true, // generalAttributeMatrixVectorIndexing
  157. true, // generalVaryingIndexing
  158. true, // generalSamplerIndexing
  159. true, // generalVariableIndexing
  160. true, // generalConstantMatrixVectorIndexing
  161. },
  162. };
  163. bgfx::TextureComponentType::Enum spirvCrossBaseTypeToFormatType(spirv_cross::SPIRType::BaseType _spirvBaseType, bool _depth)
  164. {
  165. if (_depth)
  166. {
  167. return bgfx::TextureComponentType::Depth;
  168. }
  169. switch (_spirvBaseType)
  170. {
  171. case spirv_cross::SPIRType::Float: return bgfx::TextureComponentType::Float;
  172. case spirv_cross::SPIRType::Int: return bgfx::TextureComponentType::Int;
  173. case spirv_cross::SPIRType::UInt: return bgfx::TextureComponentType::Uint;
  174. default: break;
  175. }
  176. return bgfx::TextureComponentType::Float;
  177. }
  178. bgfx::TextureDimension::Enum spirvDimToTextureViewDimension(spv::Dim _dim, bool _textureArray)
  179. {
  180. switch (_dim)
  181. {
  182. case spv::Dim::Dim1D: return bgfx::TextureDimension::Dimension1D;
  183. case spv::Dim::Dim2D: return _textureArray
  184. ? bgfx::TextureDimension::Dimension2DArray
  185. : bgfx::TextureDimension::Dimension2D
  186. ;
  187. case spv::Dim::Dim3D: return bgfx::TextureDimension::Dimension3D;
  188. case spv::Dim::DimCube: return _textureArray
  189. ? bgfx::TextureDimension::DimensionCubeArray
  190. : bgfx::TextureDimension::DimensionCube
  191. ;
  192. default:
  193. BX_ASSERT(false, "Unknown texture dimension %d", _dim);
  194. break;
  195. }
  196. return bgfx::TextureDimension::Dimension2D;
  197. }
  198. static bgfx::TextureFormat::Enum s_textureFormats[] =
  199. {
  200. bgfx::TextureFormat::Unknown, // spv::ImageFormatUnknown = 0
  201. bgfx::TextureFormat::RGBA32F, // spv::ImageFormatRgba32f = 1
  202. bgfx::TextureFormat::RGBA16F, // spv::ImageFormatRgba16f = 2
  203. bgfx::TextureFormat::R32F, // spv::ImageFormatR32f = 3
  204. bgfx::TextureFormat::RGBA8, // spv::ImageFormatRgba8 = 4
  205. bgfx::TextureFormat::RGBA8S, // spv::ImageFormatRgba8Snorm = 5
  206. bgfx::TextureFormat::RG32F, // spv::ImageFormatRg32f = 6
  207. bgfx::TextureFormat::RG16F, // spv::ImageFormatRg16f = 7
  208. bgfx::TextureFormat::RG11B10F, // spv::ImageFormatR11fG11fB10f = 8
  209. bgfx::TextureFormat::R16F, // spv::ImageFormatR16f = 9
  210. bgfx::TextureFormat::RGBA16, // spv::ImageFormatRgba16 = 10
  211. bgfx::TextureFormat::RGB10A2, // spv::ImageFormatRgb10A2 = 11
  212. bgfx::TextureFormat::RG16, // spv::ImageFormatRg16 = 12
  213. bgfx::TextureFormat::RG8, // spv::ImageFormatRg8 = 13
  214. bgfx::TextureFormat::R16, // spv::ImageFormatR16 = 14
  215. bgfx::TextureFormat::R8, // spv::ImageFormatR8 = 15
  216. bgfx::TextureFormat::RGBA16S, // spv::ImageFormatRgba16Snorm = 16
  217. bgfx::TextureFormat::RG16S, // spv::ImageFormatRg16Snorm = 17
  218. bgfx::TextureFormat::RG8S, // spv::ImageFormatRg8Snorm = 18
  219. bgfx::TextureFormat::R16S, // spv::ImageFormatR16Snorm = 19
  220. bgfx::TextureFormat::R8S, // spv::ImageFormatR8Snorm = 20
  221. bgfx::TextureFormat::RGBA32I, // spv::ImageFormatRgba32i = 21
  222. bgfx::TextureFormat::RGBA16I, // spv::ImageFormatRgba16i = 22
  223. bgfx::TextureFormat::RGBA8I, // spv::ImageFormatRgba8i = 23
  224. bgfx::TextureFormat::R32I, // spv::ImageFormatR32i = 24
  225. bgfx::TextureFormat::RG32I, // spv::ImageFormatRg32i = 25
  226. bgfx::TextureFormat::RG16I, // spv::ImageFormatRg16i = 26
  227. bgfx::TextureFormat::RG8I, // spv::ImageFormatRg8i = 27
  228. bgfx::TextureFormat::R16I, // spv::ImageFormatR16i = 28
  229. bgfx::TextureFormat::R8I, // spv::ImageFormatR8i = 29
  230. bgfx::TextureFormat::RGBA32U, // spv::ImageFormatRgba32ui = 30
  231. bgfx::TextureFormat::RGBA16U, // spv::ImageFormatRgba16ui = 31
  232. bgfx::TextureFormat::RGBA8U, // spv::ImageFormatRgba8ui = 32
  233. bgfx::TextureFormat::R32U, // spv::ImageFormatR32ui = 33
  234. bgfx::TextureFormat::Unknown, // spv::ImageFormatRgb10a2ui = 34
  235. bgfx::TextureFormat::RG32U, // spv::ImageFormatRg32ui = 35
  236. bgfx::TextureFormat::RG16U, // spv::ImageFormatRg16ui = 36
  237. bgfx::TextureFormat::RG8U, // spv::ImageFormatRg8ui = 37
  238. bgfx::TextureFormat::R16U, // spv::ImageFormatR16ui = 38
  239. bgfx::TextureFormat::R8U, // spv::ImageFormatR8ui = 39
  240. bgfx::TextureFormat::Unknown, // spv::ImageFormatR64ui = 40
  241. bgfx::TextureFormat::Unknown, // spv::ImageFormatR64i = 41
  242. };
  243. static_assert(BX_COUNTOF(s_textureFormats) == spv::ImageFormatR64i+1, "");
  244. static EShLanguage getLang(char _p)
  245. {
  246. switch (_p)
  247. {
  248. case 'c': return EShLangCompute;
  249. case 'f': return EShLangFragment;
  250. case 'v': return EShLangVertex;
  251. default: return EShLangCount;
  252. }
  253. }
  254. static const char* s_attribName[] =
  255. {
  256. "a_position",
  257. "a_normal",
  258. "a_tangent",
  259. "a_bitangent",
  260. "a_color0",
  261. "a_color1",
  262. "a_color2",
  263. "a_color3",
  264. "a_indices",
  265. "a_weight",
  266. "a_texcoord0",
  267. "a_texcoord1",
  268. "a_texcoord2",
  269. "a_texcoord3",
  270. "a_texcoord4",
  271. "a_texcoord5",
  272. "a_texcoord6",
  273. "a_texcoord7",
  274. };
  275. static_assert(bgfx::Attrib::Count == BX_COUNTOF(s_attribName) );
  276. bgfx::Attrib::Enum toAttribEnum(const bx::StringView& _name)
  277. {
  278. for (uint8_t ii = 0; ii < Attrib::Count; ++ii)
  279. {
  280. if (0 == bx::strCmp(s_attribName[ii], _name) )
  281. {
  282. return bgfx::Attrib::Enum(ii);
  283. }
  284. }
  285. return bgfx::Attrib::Count;
  286. }
  287. static const char* s_samplerTypes[] =
  288. {
  289. "BgfxSampler2D",
  290. "BgfxISampler2D",
  291. "BgfxUSampler2D",
  292. "BgfxSampler2DArray",
  293. "BgfxSampler2DShadow",
  294. "BgfxSampler2DArrayShadow",
  295. "BgfxSampler3D",
  296. "BgfxISampler3D",
  297. "BgfxUSampler3D",
  298. "BgfxSamplerCube",
  299. "BgfxSamplerCubeShadow",
  300. "BgfxSampler2DMS",
  301. };
  302. static uint16_t writeUniformArray(bx::WriterI* _shaderWriter, const UniformArray& uniforms, bool isFragmentShader)
  303. {
  304. uint16_t size = 0;
  305. bx::ErrorAssert err;
  306. uint16_t count = uint16_t(uniforms.size() );
  307. bx::write(_shaderWriter, count, &err);
  308. uint32_t fragmentBit = isFragmentShader ? kUniformFragmentBit : 0;
  309. for (uint16_t ii = 0; ii < count; ++ii)
  310. {
  311. const Uniform& un = uniforms[ii];
  312. if ( (un.type & ~kUniformMask) > UniformType::End)
  313. {
  314. size = bx::max(size, (uint16_t)(un.regIndex + un.regCount*16) );
  315. }
  316. uint8_t nameSize = (uint8_t)un.name.size();
  317. bx::write(_shaderWriter, nameSize, &err);
  318. bx::write(_shaderWriter, un.name.c_str(), nameSize, &err);
  319. bx::write(_shaderWriter, uint8_t(un.type | fragmentBit), &err);
  320. bx::write(_shaderWriter, un.num, &err);
  321. bx::write(_shaderWriter, un.regIndex, &err);
  322. bx::write(_shaderWriter, un.regCount, &err);
  323. bx::write(_shaderWriter, un.texComponent, &err);
  324. bx::write(_shaderWriter, un.texDimension, &err);
  325. bx::write(_shaderWriter, un.texFormat, &err);
  326. BX_TRACE("%s, %s, %d, %d, %d"
  327. , un.name.c_str()
  328. , getUniformTypeName(UniformType::Enum(un.type & ~kUniformMask))
  329. , un.num
  330. , un.regIndex
  331. , un.regCount
  332. );
  333. }
  334. return size;
  335. }
  336. static spv_target_env getSpirvTargetVersion(uint32_t _version, bx::WriterI* _messageWriter)
  337. {
  338. bx::ErrorAssert err;
  339. switch (_version)
  340. {
  341. case 1010:
  342. return SPV_ENV_VULKAN_1_0;
  343. case 1311:
  344. return SPV_ENV_VULKAN_1_1;
  345. case 1411:
  346. return SPV_ENV_VULKAN_1_1_SPIRV_1_4;
  347. case 1512:
  348. return SPV_ENV_VULKAN_1_2;
  349. case 1613:
  350. return SPV_ENV_VULKAN_1_3;
  351. default:
  352. bx::write(_messageWriter, &err, "Warning: Unknown SPIR-V version requested. Returning SPV_ENV_VULKAN_1_0 as default.\n");
  353. return SPV_ENV_VULKAN_1_0;
  354. }
  355. }
  356. static glslang::EShTargetClientVersion getGlslangTargetVulkanVersion(uint32_t _version, bx::WriterI* _messageWriter)
  357. {
  358. bx::ErrorAssert err;
  359. switch (_version)
  360. {
  361. case 1010:
  362. return glslang::EShTargetVulkan_1_0;
  363. case 1311:
  364. case 1411:
  365. return glslang::EShTargetVulkan_1_1;
  366. case 1512:
  367. return glslang::EShTargetVulkan_1_2;
  368. case 1613:
  369. return glslang::EShTargetVulkan_1_3;
  370. default:
  371. bx::write(_messageWriter, &err, "Warning: Unknown SPIR-V version requested. Returning EShTargetVulkan_1_0 as default.\n");
  372. return glslang::EShTargetVulkan_1_0;
  373. }
  374. }
  375. static glslang::EShTargetLanguageVersion getGlslangTargetSpirvVersion(uint32_t _version, bx::WriterI* _messageWriter)
  376. {
  377. bx::ErrorAssert err;
  378. switch (_version)
  379. {
  380. case 1010:
  381. return glslang::EShTargetSpv_1_0;
  382. case 1311:
  383. return glslang::EShTargetSpv_1_3;
  384. case 1411:
  385. return glslang::EShTargetSpv_1_4;
  386. case 1512:
  387. return glslang::EShTargetSpv_1_5;
  388. case 1613:
  389. return glslang::EShTargetSpv_1_6;
  390. default:
  391. bx::write(_messageWriter, &err, "Warning: Unknown SPIR-V version requested. Returning EShTargetSpv_1_0 as default.\n");
  392. return glslang::EShTargetSpv_1_0;
  393. }
  394. }
  395. /// This is the value used to fill out GLSLANG's SpvVersion object.
  396. /// The required value is that which is defined by GL_KHR_vulkan_glsl, which is defined here:
  397. /// https://github.com/KhronosGroup/GLSL/blob/master/extensions/khr/GL_KHR_vulkan_glsl.txt
  398. /// The value is 100.
  399. constexpr int s_GLSL_VULKAN_CLIENT_VERSION = 100;
  400. static bool compile(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _shaderWriter, bx::WriterI* _messageWriter, bool _firstPass)
  401. {
  402. BX_UNUSED(_version);
  403. bx::ErrorAssert messageErr;
  404. glslang::InitializeProcess();
  405. EShLanguage stage = getLang(_options.shaderType);
  406. if (EShLangCount == stage)
  407. {
  408. bx::write(_messageWriter, &messageErr, "Error: Unknown shader type '%c'.\n", _options.shaderType);
  409. return false;
  410. }
  411. glslang::TProgram* program = new glslang::TProgram;
  412. glslang::TShader* shader = new glslang::TShader(stage);
  413. EShMessages messages = EShMessages(0
  414. | EShMsgDefault
  415. | EShMsgReadHlsl
  416. | EShMsgVulkanRules
  417. | EShMsgSpvRules
  418. | EShMsgDebugInfo
  419. );
  420. shader->setEntryPoint("main");
  421. shader->setAutoMapBindings(true);
  422. shader->setEnvInput(glslang::EShSourceHlsl, stage, glslang::EShClientVulkan, s_GLSL_VULKAN_CLIENT_VERSION);
  423. shader->setEnvClient(glslang::EShClientVulkan, getGlslangTargetVulkanVersion(_version, _messageWriter));
  424. shader->setEnvTarget(glslang::EShTargetSpv, getGlslangTargetSpirvVersion(_version, _messageWriter));
  425. // Reserve two spots for the stage UBOs
  426. shader->setShiftBinding(glslang::EResUbo, (stage == EShLanguage::EShLangFragment ? kSpirvFragmentBinding : kSpirvVertexBinding));
  427. shader->setShiftBinding(glslang::EResTexture, kSpirvBindShift);
  428. shader->setShiftBinding(glslang::EResSampler, kSpirvBindShift + kSpirvSamplerShift);
  429. shader->setShiftBinding(glslang::EResSsbo, kSpirvBindShift);
  430. shader->setShiftBinding(glslang::EResImage, kSpirvBindShift);
  431. const char* shaderStrings[] = { _code.c_str() };
  432. shader->setStrings(
  433. shaderStrings
  434. , BX_COUNTOF(shaderStrings)
  435. );
  436. bool compiled = shader->parse(&resourceLimits
  437. , 110
  438. , false
  439. , messages
  440. );
  441. bool linked = false;
  442. bool validated = true;
  443. bool translated = false;
  444. if (!compiled)
  445. {
  446. const char* log = shader->getInfoLog();
  447. if (NULL != log)
  448. {
  449. int32_t source = 0;
  450. int32_t line = 0;
  451. int32_t column = 0;
  452. int32_t start = 0;
  453. int32_t end = INT32_MAX;
  454. bx::StringView err = bx::strFind(log, "ERROR:");
  455. bool found = false;
  456. if (!err.isEmpty() )
  457. {
  458. found = 2 == sscanf(err.getPtr(), "ERROR: %u:%u: '", &source, &line);
  459. if (found)
  460. {
  461. ++line;
  462. }
  463. }
  464. if (found)
  465. {
  466. start = bx::uint32_imax(1, line-10);
  467. end = start + 20;
  468. }
  469. printCode(_code.c_str(), bx::uint32_satsub(line, 1), start, end, column);
  470. bx::write(_messageWriter, &messageErr, "%s\n", log);
  471. }
  472. }
  473. else
  474. {
  475. program->addShader(shader);
  476. linked = true
  477. && program->link(messages)
  478. && program->mapIO()
  479. ;
  480. if (!linked)
  481. {
  482. const char* log = program->getInfoLog();
  483. if (NULL != log)
  484. {
  485. bx::write(_messageWriter, &messageErr, "%s\n", log);
  486. }
  487. }
  488. else
  489. {
  490. program->buildReflection();
  491. if (_firstPass)
  492. {
  493. // first time through, we just find unused uniforms and get rid of them
  494. std::string output;
  495. struct Uniform
  496. {
  497. std::string name;
  498. std::string decl;
  499. };
  500. std::vector<Uniform> uniforms;
  501. bx::LineReader reader(_code.c_str() );
  502. while (!reader.isDone() )
  503. {
  504. bx::StringView strLine = reader.next();
  505. bool moved = false;
  506. bx::StringView str = strFind(strLine, "uniform ");
  507. if (!str.isEmpty() )
  508. {
  509. bool found = false;
  510. bool sampler = false;
  511. std::string name = "";
  512. // add to samplers
  513. for (uint32_t ii = 0; ii < BX_COUNTOF(s_samplerTypes); ++ii)
  514. {
  515. if (!bx::findIdentifierMatch(strLine, s_samplerTypes[ii]).isEmpty() )
  516. {
  517. found = true;
  518. sampler = true;
  519. break;
  520. }
  521. }
  522. if (!found)
  523. {
  524. for (int32_t ii = 0, num = program->getNumLiveUniformVariables(); ii < num; ++ii)
  525. {
  526. // matching lines like: uniform u_name;
  527. // we want to replace "uniform" with "static" so that it's no longer
  528. // included in the uniform blob that the application must upload
  529. // we can't just remove them, because unused functions might still reference
  530. // them and cause a compile error when they're gone
  531. if (!bx::findIdentifierMatch(strLine, program->getUniformName(ii) ).isEmpty() )
  532. {
  533. found = true;
  534. name = program->getUniformName(ii);
  535. break;
  536. }
  537. }
  538. }
  539. if (!found)
  540. {
  541. output.append(strLine.getPtr(), str.getPtr() );
  542. output += "static ";
  543. output.append(str.getTerm(), strLine.getTerm() );
  544. output += "\n";
  545. moved = true;
  546. }
  547. else if (!sampler)
  548. {
  549. Uniform uniform;
  550. uniform.name = name;
  551. uniform.decl = std::string(strLine.getPtr(), strLine.getTerm() );
  552. uniforms.push_back(uniform);
  553. moved = true;
  554. }
  555. }
  556. if (!moved)
  557. {
  558. output.append(strLine.getPtr(), strLine.getTerm() );
  559. output += "\n";
  560. }
  561. }
  562. std::string uniformBlock;
  563. uniformBlock += "cbuffer UniformBlock\n";
  564. uniformBlock += "{\n";
  565. for (const Uniform& uniform : uniforms)
  566. {
  567. uniformBlock += uniform.decl.substr(7 /* uniform */);
  568. uniformBlock += "\n";
  569. }
  570. uniformBlock += "};\n";
  571. output = uniformBlock + output;
  572. // recompile with the unused uniforms converted to statics
  573. delete program;
  574. delete shader;
  575. return compile(_options, _version, output.c_str(), _shaderWriter, _messageWriter, false);
  576. }
  577. uint32_t blockIndex = 0;
  578. for (uint32_t ii = 0, num = program->getNumUniformVariables(); ii < num; ++ii)
  579. {
  580. const glslang::TType* type = program->getUniformBlockTType(ii);
  581. if (NULL != type
  582. && glslang::EbtBlock == type->getBasicType()
  583. && glslang::EvqUniform == type->getQualifier().storage)
  584. {
  585. blockIndex = ii;
  586. break;
  587. }
  588. }
  589. UniformArray uniforms;
  590. const uint16_t blockSize = bx::narrowCast<uint16_t>(bx::max<int32_t>(0, program->getUniformBlockSize(blockIndex) ) );
  591. {
  592. uint16_t count = (uint16_t)program->getNumLiveUniformVariables();
  593. for (uint16_t ii = 0; ii < count; ++ii)
  594. {
  595. Uniform un;
  596. un.name = program->getUniformName(ii);
  597. if (bx::hasSuffix(un.name.c_str(), ".@data") )
  598. {
  599. continue;
  600. }
  601. un.num = uint8_t(program->getUniformArraySize(ii) );
  602. const uint32_t offset = program->getUniformBufferOffset(ii);
  603. un.regIndex = uint16_t(offset);
  604. un.regCount = un.num;
  605. switch (program->getUniformType(ii) )
  606. {
  607. case 0x1404: // GL_INT:
  608. un.type = UniformType::Sampler;
  609. break;
  610. case 0x8B52: // GL_FLOAT_VEC4:
  611. un.type = UniformType::Vec4;
  612. break;
  613. case 0x8B5B: // GL_FLOAT_MAT3:
  614. un.type = UniformType::Mat3;
  615. un.regCount *= 3;
  616. break;
  617. case 0x8B5C: // GL_FLOAT_MAT4:
  618. un.type = UniformType::Mat4;
  619. un.regCount *= 4;
  620. break;
  621. default:
  622. continue;
  623. }
  624. uniforms.push_back(un);
  625. }
  626. }
  627. if (g_verbose)
  628. {
  629. program->dumpReflection();
  630. }
  631. glslang::TIntermediate* intermediate = program->getIntermediate(stage);
  632. std::vector<uint32_t> spirv;
  633. glslang::SpvOptions options;
  634. options.disableOptimizer = _options.debugInformation;
  635. options.generateDebugInfo = _options.debugInformation;
  636. options.emitNonSemanticShaderDebugInfo = _options.debugInformation;
  637. options.emitNonSemanticShaderDebugSource = _options.debugInformation;
  638. glslang::GlslangToSpv(*intermediate, spirv, &options);
  639. spvtools::Optimizer opt(getSpirvTargetVersion(_version, _messageWriter));
  640. auto print_msg_to_stderr = [_messageWriter, &messageErr](
  641. spv_message_level_t
  642. , const char*
  643. , const spv_position_t&
  644. , const char* m
  645. )
  646. {
  647. bx::write(_messageWriter, &messageErr, "Error: %s\n", m);
  648. };
  649. opt.SetMessageConsumer(print_msg_to_stderr);
  650. opt.RegisterLegalizationPasses();
  651. opt.RegisterPerformancePasses();
  652. spvtools::ValidatorOptions validatorOptions;
  653. validatorOptions.SetBeforeHlslLegalization(true);
  654. if (!opt.Run(
  655. spirv.data()
  656. , spirv.size()
  657. , &spirv
  658. , validatorOptions
  659. , false
  660. ) )
  661. {
  662. compiled = false;
  663. }
  664. else
  665. {
  666. tint::Result<std::string> result = tint::SpirvToWgsl(
  667. spirv
  668. , {
  669. .allow_non_uniform_derivatives = true,
  670. .allow_non_uniform_subgroup_operations = true,
  671. .allowed_features = {
  672. .extensions =
  673. {
  674. },
  675. .features =
  676. {
  677. tint::wgsl::LanguageFeature::kReadonlyAndReadwriteStorageTextures,
  678. }
  679. },
  680. }
  681. );
  682. translated = result == tint::Success;
  683. if (translated)
  684. {
  685. if (g_verbose)
  686. {
  687. bx::printf("%s", result.Get().c_str() );
  688. }
  689. spirv_cross::CompilerReflection refl(spirv);
  690. spirv_cross::ShaderResources shaderRes = refl.get_shader_resources();
  691. // Loop through the separate_images, and extract the uniform names:
  692. for (auto& resource : shaderRes.separate_images)
  693. {
  694. std::string name = refl.get_name(resource.id);
  695. if (name.size() > 7
  696. && 0 == bx::strCmp(name.c_str() + name.length() - 7, "Texture") )
  697. {
  698. name = name.substr(0, name.length() - 7);
  699. }
  700. uint32_t binding_index = refl.get_decoration(resource.id, spv::Decoration::DecorationBinding);
  701. spirv_cross::SPIRType::ImageType imageType = refl.get_type(resource.base_type_id).image;
  702. spirv_cross::SPIRType::BaseType componentType = refl.get_type(imageType.type).basetype;
  703. bool isCompareSampler = false;
  704. for (auto& sampler : shaderRes.separate_samplers)
  705. {
  706. if (binding_index + 16 == refl.get_decoration(sampler.id, spv::Decoration::DecorationBinding) )
  707. {
  708. std::string samplerName = refl.get_name(sampler.id);
  709. isCompareSampler = refl.variable_is_depth_or_compare(sampler.id) || samplerName.find("Comparison") != std::string::npos;
  710. break;
  711. }
  712. }
  713. Uniform un;
  714. un.name = name;
  715. un.type = UniformType::Enum(UniformType::Sampler
  716. | kUniformSamplerBit
  717. | (isCompareSampler ? kUniformCompareBit : 0)
  718. );
  719. un.texComponent = textureComponentTypeToId(spirvCrossBaseTypeToFormatType(componentType, imageType.depth) );
  720. un.texDimension = textureDimensionToId(spirvDimToTextureViewDimension(imageType.dim, imageType.arrayed) );
  721. un.texFormat = uint16_t(s_textureFormats[imageType.format]);
  722. un.regIndex = uint16_t(binding_index);
  723. un.regCount = 0; // unused
  724. uniforms.push_back(un);
  725. }
  726. // Loop through the storage_images, and extract the uniform names:
  727. for (auto& resource : shaderRes.storage_images)
  728. {
  729. const std::string& name = refl.get_name(resource.id);
  730. uint32_t binding_index = refl.get_decoration(resource.id, spv::Decoration::DecorationBinding);
  731. spirv_cross::SPIRType::ImageType imageType = refl.get_type(resource.base_type_id).image;
  732. spirv_cross::SPIRType::BaseType componentType = refl.get_type(imageType.type).basetype;
  733. spirv_cross::Bitset flags = refl.get_decoration_bitset(resource.id);
  734. UniformType::Enum type = flags.get(spv::DecorationNonWritable)
  735. ? UniformType::Enum(kUniformReadOnlyBit | UniformType::End)
  736. : UniformType::End
  737. ;
  738. Uniform un;
  739. un.name = name;
  740. un.type = type;
  741. un.texComponent = textureComponentTypeToId(spirvCrossBaseTypeToFormatType(componentType, imageType.depth) );
  742. un.texDimension = textureDimensionToId(spirvDimToTextureViewDimension(imageType.dim, imageType.arrayed) );
  743. un.texFormat = uint16_t(s_textureFormats[imageType.format]);
  744. un.texFormat |= 0
  745. | (spv::AccessQualifierReadOnly == imageType.access ? kAccessRead : 0)
  746. | (spv::AccessQualifierWriteOnly == imageType.access ? kAccessWrite : 0)
  747. | (spv::AccessQualifierReadOnly == imageType.access ? kAccessMask : 0)
  748. ;
  749. un.regIndex = uint16_t(binding_index);
  750. un.regCount = descriptorTypeToId(DescriptorType::StorageImage);
  751. uniforms.push_back(un);
  752. }
  753. bx::Error err;
  754. // Loop through the storage buffer, and extract the uniform names:
  755. for (auto& resource : shaderRes.storage_buffers)
  756. {
  757. const std::string& name = refl.get_name(resource.id);
  758. uint32_t binding_index = refl.get_decoration(resource.id, spv::Decoration::DecorationBinding);
  759. spirv_cross::Bitset flags = refl.get_buffer_block_flags(resource.id);
  760. UniformType::Enum type = flags.get(spv::DecorationNonWritable)
  761. ? UniformType::Enum(kUniformReadOnlyBit | UniformType::End)
  762. : UniformType::End
  763. ;
  764. Uniform un;
  765. un.name = name;
  766. un.type = type;
  767. un.num = 0;
  768. un.regIndex = uint16_t(binding_index);
  769. un.regCount = descriptorTypeToId(DescriptorType::StorageBuffer);
  770. uniforms.push_back(un);
  771. }
  772. const uint16_t size = writeUniformArray(_shaderWriter, uniforms, _options.shaderType == 'f');
  773. const bx::StringView code(result.Get().c_str() );
  774. bx::write(_shaderWriter, code.getLength(), &err);
  775. bx::write(_shaderWriter, code, &err);
  776. const uint8_t nul = 0;
  777. bx::write(_shaderWriter, nul, &err);
  778. const uint8_t numAttr = (uint8_t)program->getNumLiveAttributes();
  779. bx::write(_shaderWriter, numAttr, &err);
  780. for (uint8_t ii = 0; ii < numAttr; ++ii)
  781. {
  782. bgfx::Attrib::Enum attr = toAttribEnum(program->getAttributeName(ii) );
  783. if (bgfx::Attrib::Count != attr)
  784. {
  785. bx::write(_shaderWriter, bgfx::attribToId(attr), &err);
  786. }
  787. else
  788. {
  789. bx::write(_shaderWriter, uint16_t(UINT16_MAX), &err);
  790. }
  791. }
  792. bx::write(_shaderWriter, size, &err);
  793. bx::write(_shaderWriter, blockSize, &err);
  794. }
  795. else
  796. {
  797. bx::write(_messageWriter, &messageErr, "Error: %s\n", result.Failure().reason.c_str() );
  798. }
  799. }
  800. }
  801. }
  802. delete program;
  803. delete shader;
  804. glslang::FinalizeProcess();
  805. return compiled && linked && validated && translated;
  806. }
  807. } // namespace wgsl
  808. bool compileWgslShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _shaderWriter, bx::WriterI* _messageWriter)
  809. {
  810. return wgsl::compile(_options, _version, _code, _shaderWriter, _messageWriter, true);
  811. }
  812. } // namespace bgfx