Shader.cpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. /**
  2. * Copyright (c) 2006-2022 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. #include "Shader.h"
  21. #include "Graphics.h"
  22. #include "libraries/glslang/glslang/Public/ShaderLang.h"
  23. #include "libraries/glslang/SPIRV/GlslangToSpv.h"
  24. #include <vector>
  25. namespace love
  26. {
  27. namespace graphics
  28. {
  29. namespace vulkan
  30. {
  31. static const TBuiltInResource defaultTBuiltInResource = {
  32. /* .MaxLights = */ 32,
  33. /* .MaxClipPlanes = */ 6,
  34. /* .MaxTextureUnits = */ 32,
  35. /* .MaxTextureCoords = */ 32,
  36. /* .MaxVertexAttribs = */ 64,
  37. /* .MaxVertexUniformComponents = */ 16384,
  38. /* .MaxVaryingFloats = */ 128,
  39. /* .MaxVertexTextureImageUnits = */ 32,
  40. /* .MaxCombinedTextureImageUnits = */ 80,
  41. /* .MaxTextureImageUnits = */ 32,
  42. /* .MaxFragmentUniformComponents = */ 16384,
  43. /* .MaxDrawBuffers = */ 8,
  44. /* .MaxVertexUniformVectors = */ 4096,
  45. /* .MaxVaryingVectors = */ 32,
  46. /* .MaxFragmentUniformVectors = */ 4096,
  47. /* .MaxVertexOutputVectors = */ 32,
  48. /* .MaxFragmentInputVectors = */ 31,
  49. /* .MinProgramTexelOffset = */ -8,
  50. /* .MaxProgramTexelOffset = */ 7,
  51. /* .MaxClipDistances = */ 8,
  52. /* .MaxComputeWorkGroupCountX = */ 65535,
  53. /* .MaxComputeWorkGroupCountY = */ 65535,
  54. /* .MaxComputeWorkGroupCountZ = */ 65535,
  55. /* .MaxComputeWorkGroupSizeX = */ 1024,
  56. /* .MaxComputeWorkGroupSizeY = */ 1024,
  57. /* .MaxComputeWorkGroupSizeZ = */ 64,
  58. /* .MaxComputeUniformComponents = */ 1024,
  59. /* .MaxComputeTextureImageUnits = */ 32,
  60. /* .MaxComputeImageUniforms = */ 16,
  61. /* .MaxComputeAtomicCounters = */ 4096,
  62. /* .MaxComputeAtomicCounterBuffers = */ 8,
  63. /* .MaxVaryingComponents = */ 128,
  64. /* .MaxVertexOutputComponents = */ 128,
  65. /* .MaxGeometryInputComponents = */ 128,
  66. /* .MaxGeometryOutputComponents = */ 128,
  67. /* .MaxFragmentInputComponents = */ 128,
  68. /* .MaxImageUnits = */ 192,
  69. /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 144,
  70. /* .MaxCombinedShaderOutputResources = */ 144,
  71. /* .MaxImageSamples = */ 32,
  72. /* .MaxVertexImageUniforms = */ 16,
  73. /* .MaxTessControlImageUniforms = */ 16,
  74. /* .MaxTessEvaluationImageUniforms = */ 16,
  75. /* .MaxGeometryImageUniforms = */ 16,
  76. /* .MaxFragmentImageUniforms = */ 16,
  77. /* .MaxCombinedImageUniforms = */ 80,
  78. /* .MaxGeometryTextureImageUnits = */ 16,
  79. /* .MaxGeometryOutputVertices = */ 256,
  80. /* .MaxGeometryTotalOutputComponents = */ 1024,
  81. /* .MaxGeometryUniformComponents = */ 1024,
  82. /* .MaxGeometryVaryingComponents = */ 64,
  83. /* .MaxTessControlInputComponents = */ 128,
  84. /* .MaxTessControlOutputComponents = */ 128,
  85. /* .MaxTessControlTextureImageUnits = */ 16,
  86. /* .MaxTessControlUniformComponents = */ 1024,
  87. /* .MaxTessControlTotalOutputComponents = */ 4096,
  88. /* .MaxTessEvaluationInputComponents = */ 128,
  89. /* .MaxTessEvaluationOutputComponents = */ 128,
  90. /* .MaxTessEvaluationTextureImageUnits = */ 16,
  91. /* .MaxTessEvaluationUniformComponents = */ 1024,
  92. /* .MaxTessPatchComponents = */ 120,
  93. /* .MaxPatchVertices = */ 32,
  94. /* .MaxTessGenLevel = */ 64,
  95. /* .MaxViewports = */ 16,
  96. /* .MaxVertexAtomicCounters = */ 4096,
  97. /* .MaxTessControlAtomicCounters = */ 4096,
  98. /* .MaxTessEvaluationAtomicCounters = */ 4096,
  99. /* .MaxGeometryAtomicCounters = */ 4096,
  100. /* .MaxFragmentAtomicCounters = */ 4096,
  101. /* .MaxCombinedAtomicCounters = */ 4096,
  102. /* .MaxAtomicCounterBindings = */ 8,
  103. /* .MaxVertexAtomicCounterBuffers = */ 8,
  104. /* .MaxTessControlAtomicCounterBuffers = */ 8,
  105. /* .MaxTessEvaluationAtomicCounterBuffers = */ 8,
  106. /* .MaxGeometryAtomicCounterBuffers = */ 8,
  107. /* .MaxFragmentAtomicCounterBuffers = */ 8,
  108. /* .MaxCombinedAtomicCounterBuffers = */ 8,
  109. /* .MaxAtomicCounterBufferSize = */ 16384,
  110. /* .MaxTransformFeedbackBuffers = */ 4,
  111. /* .MaxTransformFeedbackInterleavedComponents = */ 64,
  112. /* .MaxCullDistances = */ 8,
  113. /* .MaxCombinedClipAndCullDistances = */ 8,
  114. /* .MaxSamples = */ 32,
  115. /* .maxMeshOutputVerticesNV = */ 256,
  116. /* .maxMeshOutputPrimitivesNV = */ 512,
  117. /* .maxMeshWorkGroupSizeX_NV = */ 32,
  118. /* .maxMeshWorkGroupSizeY_NV = */ 1,
  119. /* .maxMeshWorkGroupSizeZ_NV = */ 1,
  120. /* .maxTaskWorkGroupSizeX_NV = */ 32,
  121. /* .maxTaskWorkGroupSizeY_NV = */ 1,
  122. /* .maxTaskWorkGroupSizeZ_NV = */ 1,
  123. /* .maxMeshViewCountNV = */ 4,
  124. /* .maxDualSourceDrawBuffersEXT = */ 1,
  125. /* .limits = */ {
  126. /* .nonInductiveForLoops = */ 1,
  127. /* .whileLoops = */ 1,
  128. /* .doWhileLoops = */ 1,
  129. /* .generalUniformIndexing = */ 1,
  130. /* .generalAttributeMatrixVectorIndexing = */ 1,
  131. /* .generalVaryingIndexing = */ 1,
  132. /* .generalSamplerIndexing = */ 1,
  133. /* .generalVariableIndexing = */ 1,
  134. /* .generalConstantMatrixVectorIndexing = */ 1,
  135. }
  136. };
  137. static const uint32_t STREAMBUFFER_DEFAULT_SIZE = 16;
  138. static const uint32_t DESCRIPTOR_POOL_SIZE = 1;
  139. static VkShaderStageFlagBits getStageBit(ShaderStageType type)
  140. {
  141. switch (type)
  142. {
  143. case SHADERSTAGE_VERTEX:
  144. return VK_SHADER_STAGE_VERTEX_BIT;
  145. case SHADERSTAGE_PIXEL:
  146. return VK_SHADER_STAGE_FRAGMENT_BIT;
  147. case SHADERSTAGE_COMPUTE:
  148. return VK_SHADER_STAGE_COMPUTE_BIT;
  149. default:
  150. throw love::Exception("invalid type");
  151. }
  152. }
  153. static EShLanguage getGlslShaderType(ShaderStageType stage)
  154. {
  155. switch (stage)
  156. {
  157. case SHADERSTAGE_VERTEX:
  158. return EShLangVertex;
  159. case SHADERSTAGE_PIXEL:
  160. return EShLangFragment;
  161. case SHADERSTAGE_COMPUTE:
  162. return EShLangCompute;
  163. default:
  164. throw love::Exception("unkonwn shader stage type");
  165. }
  166. }
  167. Shader::Shader(StrongRef<love::graphics::ShaderStage> stages[])
  168. : graphics::Shader(stages)
  169. {
  170. auto gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS);
  171. vgfx = dynamic_cast<Graphics*>(gfx);
  172. loadVolatile();
  173. }
  174. bool Shader::loadVolatile()
  175. {
  176. computePipeline = VK_NULL_HANDLE;
  177. for (int i = 0; i < BUILTIN_MAX_ENUM; i++)
  178. builtinUniformInfo[i] = nullptr;
  179. compileShaders();
  180. calculateUniformBufferSizeAligned();
  181. createDescriptorSetLayout();
  182. createPipelineLayout();
  183. createDescriptorPoolSizes();
  184. createStreamBuffers();
  185. descriptorSetsVector.resize(MAX_FRAMES_IN_FLIGHT);
  186. currentFrame = 0;
  187. currentUsedUniformStreamBuffersCount = 0;
  188. currentUsedDescriptorSetsCount = 0;
  189. return true;
  190. }
  191. void Shader::unloadVolatile()
  192. {
  193. if (shaderModules.empty())
  194. return;
  195. for (const auto &uniform : uniformInfos)
  196. {
  197. switch (uniform.second.baseType)
  198. {
  199. case UNIFORM_SAMPLER:
  200. case UNIFORM_STORAGETEXTURE:
  201. for (int i = 0; i < uniform.second.count; i++)
  202. {
  203. if (uniform.second.textures[i] != nullptr)
  204. uniform.second.textures[i]->release();
  205. }
  206. delete[] uniform.second.textures;
  207. break;
  208. case UNIFORM_TEXELBUFFER:
  209. case UNIFORM_STORAGEBUFFER:
  210. for (int i = 0; i < uniform.second.count; i++)
  211. {
  212. if (uniform.second.buffers[i] != nullptr)
  213. uniform.second.buffers[i]->release();
  214. }
  215. delete[] uniform.second.buffers;
  216. break;
  217. }
  218. }
  219. auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
  220. gfx->queueCleanUp([shaderModules = std::move(shaderModules), device = device, descriptorSetLayout = descriptorSetLayout, pipelineLayout = pipelineLayout, descriptorPools = descriptorPools, computePipeline = computePipeline](){
  221. for (const auto pool : descriptorPools)
  222. vkDestroyDescriptorPool(device, pool, nullptr);
  223. for (const auto shaderModule : shaderModules)
  224. vkDestroyShaderModule(device, shaderModule, nullptr);
  225. vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
  226. vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
  227. if (computePipeline != VK_NULL_HANDLE)
  228. vkDestroyPipeline(device, computePipeline, nullptr);
  229. });
  230. while (!freeDescriptorSets.empty())
  231. freeDescriptorSets.pop();
  232. for (const auto streamBuffer : streamBuffers)
  233. streamBuffer->release();
  234. shaderModules.clear();
  235. shaderStages.clear();
  236. streamBuffers.clear();
  237. descriptorPools.clear();
  238. descriptorSetsVector.clear();
  239. }
  240. const std::vector<VkPipelineShaderStageCreateInfo> &Shader::getShaderStages() const
  241. {
  242. return shaderStages;
  243. }
  244. const VkPipelineLayout Shader::getGraphicsPipelineLayout() const
  245. {
  246. return pipelineLayout;
  247. }
  248. VkPipeline Shader::getComputePipeline() const
  249. {
  250. return computePipeline;
  251. }
  252. void Shader::newFrame()
  253. {
  254. currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
  255. updatedUniforms.clear();
  256. currentUsedUniformStreamBuffersCount = 0;
  257. currentUsedDescriptorSetsCount = 0;
  258. if (streamBuffers.size() > 1)
  259. {
  260. size_t newSize = 0;
  261. for (auto streamBuffer : streamBuffers)
  262. {
  263. newSize += streamBuffer->getSize();
  264. streamBuffer->release();
  265. }
  266. streamBuffers.clear();
  267. streamBuffers.push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, newSize));
  268. }
  269. else
  270. streamBuffers.at(0)->nextFrame();
  271. if (descriptorSetsVector.at(currentFrame).size() == 0)
  272. descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet());
  273. currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(0);
  274. }
  275. void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint bindPoint)
  276. {
  277. if (!localUniformData.empty())
  278. {
  279. auto usedStreamBufferMemory = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned;
  280. if (usedStreamBufferMemory >= streamBuffers.back()->getSize())
  281. {
  282. streamBuffers.push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned));
  283. currentUsedUniformStreamBuffersCount = 0;
  284. }
  285. if (builtinUniformDataOffset.hasValue)
  286. {
  287. auto builtinData = vgfx->getCurrentBuiltinUniformData();
  288. auto dst = localUniformData.data() + builtinUniformDataOffset.value;
  289. memcpy(dst, &builtinData, sizeof(builtinData));
  290. }
  291. auto currentStreamBuffer = streamBuffers.back();
  292. auto mapInfo = currentStreamBuffer->map(uniformBufferSizeAligned);
  293. memcpy(mapInfo.data, localUniformData.data(), localUniformData.size());
  294. auto offset = currentStreamBuffer->unmap(uniformBufferSizeAligned);
  295. currentStreamBuffer->markUsed(uniformBufferSizeAligned);
  296. VkDescriptorBufferInfo bufferInfo{};
  297. bufferInfo.buffer = (VkBuffer)currentStreamBuffer->getHandle();
  298. bufferInfo.offset = offset;
  299. bufferInfo.range = localUniformData.size();
  300. VkWriteDescriptorSet uniformWrite{};
  301. uniformWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
  302. uniformWrite.dstSet = currentDescriptorSet;
  303. uniformWrite.dstBinding = localUniformLocation;
  304. uniformWrite.dstArrayElement = 0;
  305. uniformWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
  306. uniformWrite.descriptorCount = 1;
  307. uniformWrite.pBufferInfo = &bufferInfo;
  308. vkUpdateDescriptorSets(device, 1, &uniformWrite, 0, nullptr);
  309. currentUsedUniformStreamBuffersCount++;
  310. updatedUniforms.insert(localUniformLocation);
  311. }
  312. static const std::vector<BuiltinUniform> builtinUniformTextures = {
  313. BUILTIN_TEXTURE_MAIN,
  314. BUILTIN_TEXTURE_VIDEO_Y,
  315. BUILTIN_TEXTURE_VIDEO_CB,
  316. BUILTIN_TEXTURE_VIDEO_CR,
  317. };
  318. for (const auto &builtin : builtinUniformTextures)
  319. {
  320. if (builtinUniformInfo[builtin] != nullptr)
  321. {
  322. auto texture = dynamic_cast<Texture*>(builtinUniformInfo[builtin]->textures[0]);
  323. VkDescriptorImageInfo imageInfo{};
  324. imageInfo.imageLayout = texture->getImageLayout();
  325. imageInfo.imageView = (VkImageView)texture->getRenderTargetHandle();
  326. imageInfo.sampler = (VkSampler)texture->getSamplerHandle();
  327. auto location = builtinUniformInfo[builtin]->location;
  328. VkWriteDescriptorSet textureWrite{};
  329. textureWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
  330. textureWrite.dstSet = currentDescriptorSet;
  331. textureWrite.dstBinding = location;
  332. textureWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
  333. textureWrite.descriptorCount = 1;
  334. textureWrite.pImageInfo = &imageInfo;
  335. vkUpdateDescriptorSets(device, 1, &textureWrite, 0, nullptr);
  336. updatedUniforms.insert(location);
  337. }
  338. }
  339. for (const auto &u : uniformInfos)
  340. {
  341. if (updatedUniforms.find(u.second.location) == updatedUniforms.end())
  342. updateUniform(&u.second, u.second.count);
  343. }
  344. vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, &currentDescriptorSet, 0, nullptr);
  345. currentUsedDescriptorSetsCount++;
  346. if (currentUsedDescriptorSetsCount >= static_cast<uint32_t>(descriptorSetsVector.at(currentFrame).size()))
  347. descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet());
  348. currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount);
  349. updatedUniforms.clear();
  350. }
  351. Shader::~Shader()
  352. {
  353. unloadVolatile();
  354. }
  355. void Shader::attach()
  356. {
  357. auto &usedShadersInFrame = vgfx->getUsedShadersInFrame();
  358. if (usedShadersInFrame.find(this) == usedShadersInFrame.end())
  359. {
  360. newFrame();
  361. usedShadersInFrame.insert(this);
  362. }
  363. if (!isCompute)
  364. {
  365. if (Shader::current != this)
  366. {
  367. Graphics::flushBatchedDrawsGlobal();
  368. Shader::current = this;
  369. Vulkan::shaderSwitch();
  370. }
  371. }
  372. else
  373. vgfx->setComputeShader(this);
  374. }
  375. int Shader::getVertexAttributeIndex(const std::string &name)
  376. {
  377. auto it = attributes.find(name);
  378. return it == attributes.end() ? -1 : it->second;
  379. }
  380. const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const
  381. {
  382. return &uniformInfos.at(name);
  383. }
  384. const Shader::UniformInfo *Shader::getUniformInfo(BuiltinUniform builtin) const
  385. {
  386. return builtinUniformInfo[builtin];
  387. }
  388. static bool usesLocalUniformData(const graphics::Shader::UniformInfo *info)
  389. {
  390. return info->baseType == graphics::Shader::UNIFORM_BOOL ||
  391. info->baseType == graphics::Shader::UNIFORM_FLOAT ||
  392. info->baseType == graphics::Shader::UNIFORM_INT ||
  393. info->baseType == graphics::Shader::UNIFORM_MATRIX ||
  394. info->baseType == graphics::Shader::UNIFORM_UINT;
  395. }
  396. void Shader::updateUniform(const UniformInfo *info, int count)
  397. {
  398. updateUniform(info, count, false);
  399. }
  400. void Shader::updateUniform(const UniformInfo* info, int count, bool internal)
  401. {
  402. if (!internal && current == this)
  403. Graphics::flushBatchedDrawsGlobal();
  404. if (usesLocalUniformData(info))
  405. memcpy(localUniformData.data(), localUniformStagingData.data(), localUniformStagingData.size());
  406. if (info->baseType == UNIFORM_SAMPLER || info->baseType == UNIFORM_STORAGETEXTURE)
  407. {
  408. bool isSampler = info->baseType == UNIFORM_SAMPLER;
  409. std::vector<VkDescriptorImageInfo> imageInfos;
  410. for (int i = 0; i < count; i++)
  411. {
  412. auto vkTexture = dynamic_cast<Texture*>(info->textures[i]);
  413. if (vkTexture == nullptr)
  414. throw love::Exception("uniform variable %s is not set.", info->name.c_str());
  415. VkDescriptorImageInfo imageInfo{};
  416. imageInfo.imageLayout = vkTexture->getImageLayout();
  417. imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle();
  418. if (isSampler)
  419. imageInfo.sampler = (VkSampler)vkTexture->getSamplerHandle();
  420. imageInfos.push_back(imageInfo);
  421. }
  422. VkWriteDescriptorSet write{};
  423. write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
  424. write.dstSet = currentDescriptorSet;
  425. write.dstBinding = info->location;
  426. write.dstArrayElement = 0;
  427. if (isSampler)
  428. write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
  429. else
  430. write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
  431. write.descriptorCount = static_cast<uint32_t>(count);
  432. write.pImageInfo = imageInfos.data();
  433. vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
  434. }
  435. if (info->baseType == UNIFORM_STORAGEBUFFER)
  436. {
  437. VkWriteDescriptorSet write{};
  438. write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
  439. write.dstSet = currentDescriptorSet;
  440. write.dstBinding = info->location;
  441. write.dstArrayElement = 0;
  442. write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
  443. write.descriptorCount = info->count;
  444. std::vector<VkDescriptorBufferInfo> bufferInfos;
  445. for (int i = 0; i < info->count; i++)
  446. {
  447. if (info->buffers[i] == nullptr)
  448. throw love::Exception("uniform variable %s is not set.", info->name.c_str());
  449. VkDescriptorBufferInfo bufferInfo{};
  450. bufferInfo.buffer = (VkBuffer)info->buffers[i]->getHandle();;
  451. bufferInfo.offset = 0;
  452. bufferInfo.range = info->buffers[i]->getSize();
  453. bufferInfos.push_back(bufferInfo);
  454. }
  455. write.pBufferInfo = bufferInfos.data();
  456. vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
  457. }
  458. if (info->baseType == UNIFORM_TEXELBUFFER)
  459. {
  460. VkWriteDescriptorSet write{};
  461. write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
  462. write.dstSet = currentDescriptorSet;
  463. write.dstBinding = info->location;
  464. write.dstArrayElement = 0;
  465. write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
  466. write.descriptorCount = info->count;
  467. std::vector<VkBufferView> bufferViews;
  468. for (int i = 0; i < info->count; i++)
  469. {
  470. if (info->buffers[i] == nullptr)
  471. throw love::Exception("uniform variable %s is not set.", info->name.c_str());
  472. bufferViews.push_back((VkBufferView)info->buffers[i]->getTexelBufferHandle());
  473. }
  474. write.pTexelBufferView = bufferViews.data();
  475. vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
  476. }
  477. updatedUniforms.insert(info->location);
  478. }
  479. void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures, int count)
  480. {
  481. for (int i = 0; i < count; i++)
  482. {
  483. auto oldTexture = info->textures[i];
  484. info->textures[i] = textures[i];
  485. info->textures[i]->retain();
  486. if (oldTexture)
  487. oldTexture->release();
  488. }
  489. updateUniform(info, count);
  490. }
  491. void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count)
  492. {
  493. for (int i = 0; i < count; i++)
  494. {
  495. auto oldBuffer = info->buffers[i];
  496. info->buffers[i] = buffers[i];
  497. info->buffers[i]->retain();
  498. if (oldBuffer)
  499. oldBuffer->release();
  500. }
  501. updateUniform(info, count);
  502. }
  503. void Shader::calculateUniformBufferSizeAligned()
  504. {
  505. auto minAlignment = vgfx->getMinUniformBufferOffsetAlignment();
  506. size_t size = localUniformStagingData.size();
  507. auto factor = static_cast<VkDeviceSize>(std::ceil(
  508. static_cast<float>(size) / static_cast<float>(minAlignment)
  509. ));
  510. uniformBufferSizeAligned = factor * minAlignment;
  511. }
  512. void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename)
  513. {
  514. using namespace spirv_cross;
  515. const auto &membertypes = type.member_types;
  516. for (size_t uindex = 0; uindex < membertypes.size(); uindex++)
  517. {
  518. const auto &memberType = comp.get_type(membertypes[uindex]);
  519. size_t memberSize = comp.get_declared_struct_member_size(type, uindex);
  520. size_t offset = baseoff + comp.type_struct_member_offset(type, uindex);
  521. std::string name = basename + comp.get_member_name(type.self, uindex);
  522. switch (memberType.basetype)
  523. {
  524. case SPIRType::Struct:
  525. name += ".";
  526. buildLocalUniforms(comp, memberType, offset, name);
  527. continue;
  528. case SPIRType::Int:
  529. case SPIRType::UInt:
  530. case SPIRType::Float:
  531. break;
  532. default:
  533. continue;
  534. }
  535. UniformInfo u{};
  536. u.name = name;
  537. u.dataSize = memberSize;
  538. u.count = memberType.array.empty() ? 1 : memberType.array[0];
  539. u.components = 1;
  540. u.data = localUniformStagingData.data() + offset;
  541. if (memberType.columns == 1)
  542. {
  543. if (memberType.basetype == SPIRType::Int)
  544. u.baseType = UNIFORM_INT;
  545. else if (memberType.basetype == SPIRType::UInt)
  546. u.baseType = UNIFORM_UINT;
  547. else
  548. u.baseType = UNIFORM_FLOAT;
  549. u.components = memberType.vecsize;
  550. }
  551. else
  552. {
  553. u.baseType = UNIFORM_MATRIX;
  554. u.matrix.rows = memberType.vecsize;
  555. u.matrix.columns = memberType.columns;
  556. }
  557. const auto &reflectionIt = validationReflection.localUniforms.find(u.name);
  558. if (reflectionIt != validationReflection.localUniforms.end())
  559. {
  560. const auto &localUniform = reflectionIt->second;
  561. const auto &values = localUniform.initializerValues;
  562. if (!values.empty())
  563. memcpy(
  564. u.data,
  565. values.data(),
  566. std::min(u.dataSize, values.size() * sizeof(LocalUniformValue)));
  567. }
  568. uniformInfos[u.name] = u;
  569. BuiltinUniform builtin = BUILTIN_MAX_ENUM;
  570. if (getConstant(u.name.c_str(), builtin))
  571. {
  572. if (builtin == BUILTIN_UNIFORMS_PER_DRAW)
  573. builtinUniformDataOffset = offset;
  574. builtinUniformInfo[builtin] = &uniformInfos[u.name];
  575. }
  576. }
  577. }
  578. void Shader::compileShaders()
  579. {
  580. using namespace glslang;
  581. using namespace spirv_cross;
  582. std::vector<TShader*> glslangShaders;
  583. auto program = new TProgram();
  584. device = vgfx->getDevice();
  585. const auto &enabledExtensions = vgfx->getEnabledOptionalDeviceExtensions();
  586. for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++)
  587. {
  588. if (!stages[i])
  589. continue;
  590. auto stage = (ShaderStageType)i;
  591. if (stage == SHADERSTAGE_COMPUTE)
  592. isCompute = true;
  593. auto glslangShaderStage = getGlslShaderType(stage);
  594. auto tshader = new TShader(glslangShaderStage);
  595. tshader->setEnvInput(EShSourceGlsl, glslangShaderStage, EShClientVulkan, 450);
  596. tshader->setEnvClient(EShClientVulkan, EShTargetVulkan_1_2);
  597. if (enabledExtensions.spirv14)
  598. tshader->setEnvTarget(EshTargetSpv, EShTargetSpv_1_4);
  599. else
  600. tshader->setEnvTarget(EshTargetSpv, EShTargetSpv_1_0);
  601. tshader->setAutoMapLocations(true);
  602. tshader->setAutoMapBindings(true);
  603. tshader->setEnvInputVulkanRulesRelaxed();
  604. tshader->setGlobalUniformBinding(0);
  605. tshader->setGlobalUniformSet(0);
  606. auto &glsl = stages[i]->getSource();
  607. const char *csrc = glsl.c_str();
  608. const int sourceLength = static_cast<int>(glsl.length());
  609. tshader->setStringsWithLengths(&csrc, &sourceLength, 1);
  610. int defaultVersion = 450;
  611. EProfile defaultProfile = ECoreProfile;
  612. bool forceDefault = false;
  613. bool forwardCompat = true;
  614. if (!tshader->parse(&defaultTBuiltInResource, defaultVersion, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings))
  615. {
  616. const char *msg1 = tshader->getInfoLog();
  617. const char *msg2 = tshader->getInfoDebugLog();
  618. throw love::Exception("error while parsing shader");
  619. }
  620. program->addShader(tshader);
  621. glslangShaders.push_back(tshader);
  622. }
  623. if (!program->link(EShMsgDefault))
  624. throw love::Exception("link failed! %s\n", program->getInfoLog());
  625. if (!program->mapIO())
  626. throw love::Exception("mapIO failed");
  627. uniformInfos.clear();
  628. for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++)
  629. {
  630. auto shaderStage = (ShaderStageType)i;
  631. auto glslangStage = getGlslShaderType(shaderStage);
  632. auto intermediate = program->getIntermediate(glslangStage);
  633. if (intermediate == nullptr) {
  634. continue;
  635. }
  636. spv::SpvBuildLogger logger;
  637. glslang::SpvOptions opt;
  638. opt.validate = true;
  639. std::vector<uint32_t> spirv;
  640. GlslangToSpv(*intermediate, spirv, &logger, &opt);
  641. std::string msgs = logger.getAllMessages();
  642. VkShaderModuleCreateInfo createInfo{};
  643. createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
  644. createInfo.codeSize = spirv.size() * sizeof(uint32_t);
  645. createInfo.pCode = spirv.data();
  646. auto device = vgfx->getDevice();
  647. VkShaderModule shaderModule;
  648. if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
  649. throw love::Exception("failed to create shader module");
  650. }
  651. shaderModules.push_back(shaderModule);
  652. VkPipelineShaderStageCreateInfo shaderStageInfo{};
  653. shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
  654. shaderStageInfo.stage = getStageBit((ShaderStageType)i);
  655. shaderStageInfo.module = shaderModule;
  656. shaderStageInfo.pName = "main";
  657. shaderStages.push_back(shaderStageInfo);
  658. spirv_cross::CompilerGLSL comp(spirv);
  659. // we only care about variables that are actually getting used.
  660. auto active = comp.get_active_interface_variables();
  661. auto shaderResources = comp.get_shader_resources(active);
  662. comp.set_enabled_interface_variables(std::move(active));
  663. for (const auto &resource : shaderResources.uniform_buffers)
  664. {
  665. if (resource.name == "gl_DefaultUniformBlock")
  666. {
  667. const auto& type = comp.get_type(resource.base_type_id);
  668. size_t uniformBufferObjectSize = comp.get_declared_struct_size(type);
  669. auto defaultUniformBlockSize = comp.get_declared_struct_size(type);
  670. localUniformStagingData.resize(defaultUniformBlockSize);
  671. localUniformData.resize(defaultUniformBlockSize);
  672. localUniformLocation = comp.get_decoration(resource.id, spv::DecorationBinding);
  673. memset(localUniformStagingData.data(), 0, defaultUniformBlockSize);
  674. memset(localUniformData.data(), 0, defaultUniformBlockSize);
  675. std::string basename("");
  676. buildLocalUniforms(comp, type, 0, basename);
  677. memcpy(localUniformData.data(), localUniformStagingData.data(), localUniformStagingData.size());
  678. }
  679. else
  680. throw love::Exception("unimplemented: non default uniform blocks.");
  681. }
  682. for (const auto &r : shaderResources.sampled_images)
  683. {
  684. const SPIRType &basetype = comp.get_type(r.base_type_id);
  685. const SPIRType &type = comp.get_type(r.type_id);
  686. const SPIRType &imagetype = comp.get_type(basetype.image.type);
  687. graphics::Shader::UniformInfo info;
  688. info.location = comp.get_decoration(r.id, spv::DecorationBinding);
  689. info.baseType = UNIFORM_SAMPLER;
  690. info.name = r.name;
  691. info.count = type.array.empty() ? 1 : type.array[0];
  692. info.isDepthSampler = type.image.depth;
  693. info.components = 1;
  694. switch (imagetype.basetype)
  695. {
  696. case SPIRType::Float:
  697. info.dataBaseType = DATA_BASETYPE_FLOAT;
  698. break;
  699. case SPIRType::Int:
  700. info.dataBaseType = DATA_BASETYPE_INT;
  701. break;
  702. case SPIRType::UInt:
  703. info.dataBaseType = DATA_BASETYPE_UINT;
  704. break;
  705. default:
  706. break;
  707. }
  708. switch (basetype.image.dim)
  709. {
  710. case spv::Dim2D:
  711. info.textureType = basetype.image.arrayed ? TEXTURE_2D_ARRAY : TEXTURE_2D;
  712. info.textures = new love::graphics::Texture *[info.count];
  713. break;
  714. case spv::Dim3D:
  715. info.textureType = TEXTURE_VOLUME;
  716. info.textures = new love::graphics::Texture *[info.count];
  717. break;
  718. case spv::DimCube:
  719. if (basetype.image.arrayed) {
  720. throw love::Exception("cubemap arrays are not currently supported");
  721. }
  722. info.textureType = TEXTURE_CUBE;
  723. info.textures = new love::graphics::Texture *[info.count];
  724. break;
  725. case spv::DimBuffer:
  726. info.baseType = UNIFORM_TEXELBUFFER;
  727. info.buffers = new love::graphics::Buffer *[info.count];
  728. break;
  729. default:
  730. throw love::Exception("unknown dim");
  731. }
  732. if (info.baseType == UNIFORM_TEXELBUFFER)
  733. {
  734. for (int i = 0; i < info.count; i++)
  735. info.buffers[i] = nullptr;
  736. }
  737. else
  738. {
  739. auto tex = vgfx->getDefaultTexture();
  740. for (int i = 0; i < info.count; i++)
  741. {
  742. info.textures[i] = tex;
  743. tex->retain();
  744. }
  745. }
  746. uniformInfos[r.name] = info;
  747. BuiltinUniform builtin;
  748. if (getConstant(r.name.c_str(), builtin))
  749. builtinUniformInfo[builtin] = &uniformInfos[info.name];
  750. }
  751. for (const auto &r : shaderResources.storage_buffers)
  752. {
  753. const auto &type = comp.get_type(r.type_id);
  754. UniformInfo u{};
  755. u.baseType = UNIFORM_STORAGEBUFFER;
  756. u.components = 1;
  757. u.name = r.name;
  758. u.count = type.array.empty() ? 1 : type.array[0];
  759. if (!fillUniformReflectionData(u))
  760. continue;
  761. u.location = comp.get_decoration(r.id, spv::DecorationBinding);
  762. u.buffers = new love::graphics::Buffer *[u.count];
  763. for (int i = 0; i < u.count; i++)
  764. u.buffers[i] = nullptr;
  765. uniformInfos[u.name] = u;
  766. }
  767. for (const auto &r : shaderResources.storage_images)
  768. {
  769. const auto &type = comp.get_type(r.type_id);
  770. UniformInfo u{};
  771. u.baseType = UNIFORM_STORAGETEXTURE;
  772. u.components = 1;
  773. u.name = r.name;
  774. u.count = type.array.empty() ? 1 : type.array[0];
  775. if (!fillUniformReflectionData(u))
  776. continue;
  777. u.textures = new love::graphics::Texture *[u.count];
  778. u.location = comp.get_decoration(r.id, spv::DecorationBinding);
  779. for (int i = 0; i < u.count; i++)
  780. u.textures[i] = nullptr;
  781. // some stuff missing ?
  782. uniformInfos[u.name] = u;
  783. }
  784. if (shaderStage == SHADERSTAGE_VERTEX)
  785. {
  786. for (const auto &r : shaderResources.stage_inputs)
  787. {
  788. const auto &name = r.name;
  789. const int attributeLocation = static_cast<int>(comp.get_decoration(r.id, spv::DecorationLocation));
  790. attributes[name] = attributeLocation;
  791. }
  792. }
  793. }
  794. delete program;
  795. for (auto shader : glslangShaders)
  796. delete shader;
  797. }
  798. void Shader::createDescriptorSetLayout()
  799. {
  800. std::vector<VkDescriptorSetLayoutBinding> bindings;
  801. VkShaderStageFlags stageFlags;
  802. if (isCompute)
  803. stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
  804. else
  805. stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
  806. for (auto const &entry : uniformInfos)
  807. {
  808. auto type = Vulkan::getDescriptorType(entry.second.baseType);
  809. if (type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
  810. {
  811. VkDescriptorSetLayoutBinding layoutBinding{};
  812. layoutBinding.binding = entry.second.location;
  813. layoutBinding.descriptorType = type;
  814. layoutBinding.descriptorCount = entry.second.count;
  815. layoutBinding.stageFlags = stageFlags;
  816. bindings.push_back(layoutBinding);
  817. }
  818. }
  819. if (!localUniformStagingData.empty())
  820. {
  821. VkDescriptorSetLayoutBinding uniformBinding{};
  822. uniformBinding.binding = localUniformLocation;
  823. uniformBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
  824. uniformBinding.descriptorCount = 1;
  825. uniformBinding.stageFlags = stageFlags;
  826. bindings.push_back(uniformBinding);
  827. }
  828. VkDescriptorSetLayoutCreateInfo layoutInfo{};
  829. layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
  830. layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
  831. layoutInfo.pBindings = bindings.data();
  832. if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS)
  833. throw love::Exception("failed to create descriptor set layout");
  834. }
  835. void Shader::createPipelineLayout()
  836. {
  837. VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
  838. pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
  839. pipelineLayoutInfo.setLayoutCount = 1;
  840. pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
  841. pipelineLayoutInfo.pushConstantRangeCount = 0;
  842. if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS)
  843. throw love::Exception("failed to create pipeline layout");
  844. if (isCompute)
  845. {
  846. assert(shaderStages.size() == 1);
  847. VkComputePipelineCreateInfo computeInfo{};
  848. computeInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
  849. computeInfo.stage = shaderStages.at(0);
  850. computeInfo.layout = pipelineLayout;
  851. if (vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &computeInfo, nullptr, &computePipeline) != VK_SUCCESS)
  852. throw love::Exception("failed to create compute pipeline");
  853. }
  854. }
  855. void Shader::createDescriptorPoolSizes()
  856. {
  857. if (!localUniformData.empty())
  858. {
  859. VkDescriptorPoolSize size{};
  860. size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
  861. size.descriptorCount = 1;
  862. descriptorPoolSizes.push_back(size);
  863. }
  864. for (const auto &entry : uniformInfos)
  865. {
  866. VkDescriptorPoolSize size{};
  867. auto type = Vulkan::getDescriptorType(entry.second.baseType);
  868. if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) {
  869. continue;
  870. }
  871. size.type = type;
  872. size.descriptorCount = 1;
  873. descriptorPoolSizes.push_back(size);
  874. }
  875. }
  876. void Shader::createStreamBuffers()
  877. {
  878. size_t size = STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned;
  879. if (size > 0)
  880. streamBuffers.push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, size));
  881. }
  882. void Shader::setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture)
  883. {
  884. std::array<graphics::Texture*, 3> textures = {
  885. ytexture, cbtexture, crtexture
  886. };
  887. std::array<BuiltinUniform, 3> builtIns = {
  888. BUILTIN_TEXTURE_VIDEO_Y,
  889. BUILTIN_TEXTURE_VIDEO_CB,
  890. BUILTIN_TEXTURE_VIDEO_CR,
  891. };
  892. static_assert(textures.size() == builtIns.size(), "expected number of textures to be the same");
  893. for (size_t i = 0; i < textures.size(); i++)
  894. {
  895. if (builtinUniformInfo[builtIns[i]] != nullptr)
  896. {
  897. textures[i]->retain();
  898. builtinUniformInfo[builtIns[i]]->textures[0]->release();
  899. builtinUniformInfo[builtIns[i]]->textures[0] = textures[i];
  900. }
  901. }
  902. }
  903. bool Shader::hasUniform(const std::string &name) const
  904. {
  905. return uniformInfos.find(name) != uniformInfos.end();
  906. }
  907. void Shader::setMainTex(graphics::Texture *texture)
  908. {
  909. if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN] != nullptr)
  910. {
  911. texture->retain();
  912. builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0]->release();
  913. builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0] = texture;
  914. }
  915. }
  916. VkDescriptorSet Shader::allocateDescriptorSet()
  917. {
  918. if (freeDescriptorSets.empty())
  919. {
  920. VkDescriptorPoolCreateInfo createInfo{};
  921. createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
  922. createInfo.maxSets = DESCRIPTOR_POOL_SIZE;
  923. createInfo.poolSizeCount = static_cast<uint32_t>(descriptorPoolSizes.size());
  924. createInfo.pPoolSizes = descriptorPoolSizes.data();
  925. VkDescriptorPool pool;
  926. if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS)
  927. throw love::Exception("failed to create descriptor pool");
  928. descriptorPools.push_back(pool);
  929. std::vector<VkDescriptorSetLayout> layouts(DESCRIPTOR_POOL_SIZE, descriptorSetLayout);
  930. VkDescriptorSetAllocateInfo allocInfo{};
  931. allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
  932. allocInfo.descriptorPool = pool;
  933. allocInfo.descriptorSetCount = DESCRIPTOR_POOL_SIZE;
  934. allocInfo.pSetLayouts = layouts.data();
  935. std::vector<VkDescriptorSet> descriptorSet;
  936. descriptorSet.resize(DESCRIPTOR_POOL_SIZE);
  937. VkResult result = vkAllocateDescriptorSets(device, &allocInfo, descriptorSet.data());
  938. if (result != VK_SUCCESS)
  939. throw love::Exception("failed to allocate descriptor set");
  940. for (const auto ds : descriptorSet)
  941. freeDescriptorSets.push(ds);
  942. }
  943. auto ds = freeDescriptorSets.front();
  944. freeDescriptorSets.pop();
  945. return ds;
  946. }
  947. } // vulkan
  948. } // graphics
  949. } // love