diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index a4e391213..8c33d054f 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -155,6 +155,7 @@ public: FEATURE_FULL_NPOT, FEATURE_PIXEL_SHADER_HIGHP, FEATURE_SHADER_DERIVATIVES, + FEATURE_BUILTIN_UNIFORM_PUSH_CONSTANT, FEATURE_GLSL3, FEATURE_GLSL4, FEATURE_INSTANCING, diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index 8184823cd..a9cb18eec 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -86,6 +86,13 @@ static const char global_syntax[] = R"( )"; static const char render_uniforms[] = R"( +#ifdef LOVE_BUILTIN_UNIFORM_PUSH_CONSTANT +layout( push_constant, std430 ) uniform LoveBuiltinUniforms +{ + vec4 data[13]; +} LovePushConstants; +#define love_UniformsPerDraw (LovePushConstants.data) +#else // According to the GLSL ES 1.0 spec, uniform precision must match between stages, // but we can't guarantee that highp is always supported in fragment shaders... // We *really* don't want to use mediump for these in vertex shaders though. @@ -95,6 +102,7 @@ uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw2[1]; #else uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13]; #endif +#endif // Older GLSL doesn't support preprocessor line continuations... #define TransformMatrix mat4(love_UniformsPerDraw[0], love_UniformsPerDraw[1], love_UniformsPerDraw[2], love_UniformsPerDraw[3]) @@ -543,6 +551,9 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage, if (glsl1on3) ss << "#define LOVE_GLSL1_ON_GLSL3 1\n"; + if (gfx->getCapabilities().features[Graphics::FEATURE_BUILTIN_UNIFORM_PUSH_CONSTANT]) + ss << "#define LOVE_BUILTIN_UNIFORM_PUSH_CONSTANT 1\n"; + if (isGammaCorrect()) ss << "#define LOVE_GAMMA_CORRECT 1\n"; if (info.usesMRT) diff --git a/src/modules/graphics/ShaderStage.cpp b/src/modules/graphics/ShaderStage.cpp index a035481f8..ef31c2ecc 100644 --- a/src/modules/graphics/ShaderStage.cpp +++ b/src/modules/graphics/ShaderStage.cpp @@ -137,6 +137,21 @@ namespace love namespace graphics { +static EShLanguage getGlslShaderType(ShaderStageType stage) +{ + switch (stage) + { + case SHADERSTAGE_VERTEX: + return EShLangVertex; + case SHADERSTAGE_PIXEL: + return EShLangFragment; + case SHADERSTAGE_COMPUTE: + return EShLangCompute; + default: + throw love::Exception("unkonwn shader stage type"); + } +} + ShaderStage::ShaderStage(Graphics *gfx, ShaderStageType stage, const std::string &glsl, bool gles, const std::string &cachekey) : stageType(stage) , source(glsl) @@ -169,6 +184,21 @@ ShaderStage::ShaderStage(Graphics *gfx, ShaderStageType stage, const std::string bool forwardcompat = supportsGLSL3 && !forcedefault; + if (gfx->getCapabilities().features[Graphics::FEATURE_BUILTIN_UNIFORM_PUSH_CONSTANT]) { + forcedefault = true; + defaultversion = 450; + defaultprofile = ECoreProfile; + + glslangShader->setEnvInput(glslang::EShSourceGlsl, getGlslShaderType(stageType), glslang::EShClientVulkan, 450); + glslangShader->setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_2); + glslangShader->setEnvTarget(glslang::EshTargetSpv, glslang::EShTargetSpv_1_0); + glslangShader->setEnvInputVulkanRulesRelaxed(); + glslangShader->setAutoMapLocations(true); + glslangShader->setAutoMapBindings(true); + glslangShader->setGlobalUniformBinding(0); + glslangShader->setGlobalUniformSet(0); + } + if (!glslangShader->parse(&defaultTBuiltInResource, defaultversion, defaultprofile, forcedefault, forwardcompat, EShMsgSuppressWarnings)) { const char *stagename = "unknown"; diff --git a/src/modules/graphics/metal/Graphics.mm b/src/modules/graphics/metal/Graphics.mm index 5d2f42645..24b161296 100644 --- a/src/modules/graphics/metal/Graphics.mm +++ b/src/modules/graphics/metal/Graphics.mm @@ -2123,6 +2123,7 @@ void Graphics::initCapabilities() capabilities.features[FEATURE_FULL_NPOT] = true; capabilities.features[FEATURE_PIXEL_SHADER_HIGHP] = true; capabilities.features[FEATURE_SHADER_DERIVATIVES] = true; + capabilities.features[FEATURE_BUILTIN_UNIFORM_PUSH_CONSTANT] = false; capabilities.features[FEATURE_GLSL3] = true; capabilities.features[FEATURE_GLSL4] = true; capabilities.features[FEATURE_INSTANCING] = true; @@ -2132,7 +2133,7 @@ void Graphics::initCapabilities() capabilities.features[FEATURE_COPY_BUFFER_TO_TEXTURE] = true; capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER] = true; capabilities.features[FEATURE_COPY_RENDER_TARGET_TO_BUFFER] = true; - static_assert(FEATURE_MAX_ENUM == 17, "Graphics::initCapabilities must be updated when adding a new graphics feature!"); + static_assert(FEATURE_MAX_ENUM == 18, "Graphics::initCapabilities must be updated when adding a new graphics feature!"); // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf capabilities.limits[LIMIT_POINT_SIZE] = 511; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 18c2daf5a..f2e0d912d 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1649,6 +1649,7 @@ void Graphics::initCapabilities() capabilities.features[FEATURE_FULL_NPOT] = GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot; capabilities.features[FEATURE_PIXEL_SHADER_HIGHP] = gl.isPixelShaderHighpSupported(); capabilities.features[FEATURE_SHADER_DERIVATIVES] = GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_standard_derivatives; + capabilities.features[FEATURE_BUILTIN_UNIFORM_PUSH_CONSTANT] = false; capabilities.features[FEATURE_GLSL3] = GLAD_ES_VERSION_3_0 || gl.isCoreProfile(); capabilities.features[FEATURE_GLSL4] = GLAD_ES_VERSION_3_1 || (gl.isCoreProfile() && GLAD_VERSION_4_3); capabilities.features[FEATURE_INSTANCING] = gl.isInstancingSupported(); @@ -1658,7 +1659,7 @@ void Graphics::initCapabilities() capabilities.features[FEATURE_COPY_BUFFER_TO_TEXTURE] = gl.isCopyBufferToTextureSupported(); capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER] = gl.isCopyTextureToBufferSupported(); capabilities.features[FEATURE_COPY_RENDER_TARGET_TO_BUFFER] = gl.isCopyRenderTargetToBufferSupported(); - static_assert(FEATURE_MAX_ENUM == 17, "Graphics::initCapabilities must be updated when adding a new graphics feature!"); + static_assert(FEATURE_MAX_ENUM == 18, "Graphics::initCapabilities must be updated when adding a new graphics feature!"); capabilities.limits[LIMIT_POINT_SIZE] = gl.getMaxPointSize(); capabilities.limits[LIMIT_TEXTURE_SIZE] = gl.getMax2DTextureSize(); diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 0f79eab11..c95d186e3 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -226,7 +226,7 @@ void Graphics::discard(const std::vector& colorbuffers, bool depthstencil) startRenderPass(); } -void Graphics::submitGpuCommands(bool present, void* screenshotCallbackData) +void Graphics::submitGpuCommands(bool present, void *screenshotCallbackData) { flushBatchedDraws(); @@ -255,17 +255,6 @@ void Graphics::submitGpuCommands(bool present, void* screenshotCallbackData) VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - VkImageCopy imageCopy{}; - imageCopy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageCopy.srcSubresource.layerCount = 1; - imageCopy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageCopy.dstSubresource.layerCount = 1; - imageCopy.extent = { - swapChainExtent.width, - swapChainExtent.height, - 1 - }; - VkImageBlit blit{}; blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; blit.srcSubresource.layerCount = 1; @@ -407,7 +396,7 @@ void Graphics::present(void *screenshotCallbackdata) deprecations.draw(this); - submitGpuCommands(true); + submitGpuCommands(true, screenshotCallbackdata); VkPresentInfoKHR presentInfo{}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; @@ -533,6 +522,7 @@ void Graphics::initCapabilities() capabilities.features[FEATURE_FULL_NPOT] = false; capabilities.features[FEATURE_PIXEL_SHADER_HIGHP] = true; capabilities.features[FEATURE_SHADER_DERIVATIVES] = true; + capabilities.features[FEATURE_BUILTIN_UNIFORM_PUSH_CONSTANT] = canUsePushConstants; capabilities.features[FEATURE_GLSL3] = true; capabilities.features[FEATURE_GLSL4] = true; capabilities.features[FEATURE_INSTANCING] = true; @@ -542,7 +532,7 @@ void Graphics::initCapabilities() capabilities.features[FEATURE_COPY_BUFFER_TO_TEXTURE] = true; capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER] = true; capabilities.features[FEATURE_COPY_RENDER_TARGET_TO_BUFFER] = true; - static_assert(FEATURE_MAX_ENUM == 17, "Graphics::initCapabilities must be updated when adding a new graphics feature!"); + static_assert(FEATURE_MAX_ENUM == 18, "Graphics::initCapabilities must be updated when adding a new graphics feature!"); VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(physicalDevice, &properties); @@ -577,6 +567,12 @@ void Graphics::unSetMode() { created = false; vkDeviceWaitIdle(device); + + for (const auto &readbacks : readbackCallbacks) + for (const auto &readback : readbacks) + readback(); + readbackCallbacks.clear(); + Volatile::unloadAll(); cleanup(); } @@ -599,7 +595,7 @@ int Graphics::getBackbufferMSAA() const void Graphics::setFrontFaceWinding(Winding winding) { - const auto& currentState = states.back(); + const auto ¤tState = states.back(); if (currentState.winding == winding) return; @@ -1141,7 +1137,7 @@ graphics::Shader::BuiltinUniformData Graphics::getCurrentBuiltinUniformData() } // Store DPI scale in an unused component of another vector. - data.normalMatrix[0].w = (float)getCurrentDPIScale(); + data.normalMatrix[0].w = static_cast(getCurrentDPIScale()); // Same with point size. data.normalMatrix[1].w = getPointSize(); @@ -1296,6 +1292,9 @@ void Graphics::pickPhysicalDevice() vkGetPhysicalDeviceProperties(physicalDevice, &properties); minUniformBufferOffsetAlignment = properties.limits.minUniformBufferOffsetAlignment; + if (sizeof(graphics::Shader::BuiltinUniformData) <= properties.limits.maxPushConstantsSize) + canUsePushConstants = true; + msaaSamples = getMsaaCount(requestedMsaa); } @@ -2813,7 +2812,7 @@ void Graphics::cleanup() void Graphics::cleanupSwapChain() { - for (const auto& readbackBuffer : screenshotReadbackBuffers) + for (const auto &readbackBuffer : screenshotReadbackBuffers) { vmaDestroyBuffer(vmaAllocator, readbackBuffer.buffer, readbackBuffer.allocation); vmaDestroyImage(vmaAllocator, readbackBuffer.image, readbackBuffer.imageAllocation); diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 936205a84..398614b3e 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -373,6 +373,7 @@ private: uint32_t vulkanApiVersion = VK_VERSION_1_0; VkInstance instance = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + bool canUsePushConstants = false; int requestedMsaa = 0; VkDevice device = VK_NULL_HANDLE; OptionalInstanceExtensions optionalInstanceExtensions; diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 8bba0a252..3afe10d0c 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -4,7 +4,7 @@ #include "libraries/glslang/glslang/Public/ShaderLang.h" #include "libraries/glslang/SPIRV/GlslangToSpv.h" - +#include #include namespace love @@ -327,10 +327,24 @@ void Shader::newFrame(uint32_t frameIndex) vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); } } + + if (useBuiltinUniformPushConstant) + { + if (!localUniformData.empty()) + { + + } + } } void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint bindPoint) { + if (useBuiltinUniformPushConstant) + { + auto builtinData = vgfx->getCurrentBuiltinUniformData(); + vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(BuiltinUniformData), &builtinData); + } + if (!localUniformData.empty()) { auto usedStreamBufferMemory = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned; @@ -525,6 +539,7 @@ void Shader::calculateUniformBufferSizeAligned() uniformBufferSizeAligned = factor * minAlignment; } + void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename) { using namespace spirv_cross; @@ -601,6 +616,40 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross:: } } +static void parse(glslang::TShader* tshader, EShLanguage stage, const std::string &glsl, bool spirv14) +{ + using namespace glslang; + + tshader->setEnvInput(EShSourceGlsl, stage, EShClientVulkan, 450); + tshader->setEnvClient(EShClientVulkan, EShTargetVulkan_1_2); + if (spirv14) + tshader->setEnvTarget(EshTargetSpv, EShTargetSpv_1_4); + else + tshader->setEnvTarget(EshTargetSpv, EShTargetSpv_1_0); + tshader->setAutoMapLocations(true); + tshader->setAutoMapBindings(true); + tshader->setEnvInputVulkanRulesRelaxed(); + tshader->setGlobalUniformBinding(0); + tshader->setGlobalUniformSet(0); + + const char* csrc = glsl.c_str(); + const int sourceLength = static_cast(glsl.length()); + tshader->setStringsWithLengths(&csrc, &sourceLength, 1); + + int defaultVersion = 450; + EProfile defaultProfile = ECoreProfile; + bool forceDefault = false; + bool forwardCompat = true; + + if (!tshader->parse(&defaultTBuiltInResource, defaultVersion, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings)) + { + const char* msg1 = tshader->getInfoLog(); + const char* msg2 = tshader->getInfoDebugLog(); + + throw love::Exception("error while parsing shader"); + } +} + void Shader::compileShaders() { using namespace glslang; @@ -613,6 +662,7 @@ void Shader::compileShaders() device = vgfx->getDevice(); const auto &enabledExtensions = vgfx->getEnabledOptionalDeviceExtensions(); + auto useSpirv14 = enabledExtensions.spirv14; for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) { @@ -627,35 +677,7 @@ void Shader::compileShaders() auto glslangShaderStage = getGlslShaderType(stage); auto tshader = new TShader(glslangShaderStage); - tshader->setEnvInput(EShSourceGlsl, glslangShaderStage, EShClientVulkan, 450); - tshader->setEnvClient(EShClientVulkan, EShTargetVulkan_1_2); - if (enabledExtensions.spirv14) - tshader->setEnvTarget(EshTargetSpv, EShTargetSpv_1_4); - else - tshader->setEnvTarget(EshTargetSpv, EShTargetSpv_1_0); - tshader->setAutoMapLocations(true); - tshader->setAutoMapBindings(true); - tshader->setEnvInputVulkanRulesRelaxed(); - tshader->setGlobalUniformBinding(0); - tshader->setGlobalUniformSet(0); - - auto &glsl = stages[i]->getSource(); - const char *csrc = glsl.c_str(); - const int sourceLength = static_cast(glsl.length()); - tshader->setStringsWithLengths(&csrc, &sourceLength, 1); - - int defaultVersion = 450; - EProfile defaultProfile = ECoreProfile; - bool forceDefault = false; - bool forwardCompat = true; - - if (!tshader->parse(&defaultTBuiltInResource, defaultVersion, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings)) - { - const char *msg1 = tshader->getInfoLog(); - const char *msg2 = tshader->getInfoDebugLog(); - - throw love::Exception("error while parsing shader"); - } + parse(tshader, glslangShaderStage, stages[i]->getSource(), useSpirv14); program->addShader(tshader); glslangShaders.push_back(tshader); @@ -669,6 +691,8 @@ void Shader::compileShaders() uniformInfos.clear(); + std::set usedBufferBindings; + for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) { auto shaderStage = (ShaderStageType)i; @@ -678,6 +702,26 @@ void Shader::compileShaders() continue; } + bool recompile = false; + + auto getFreeBinding = [&](uint32_t binding) { + if (usedBufferBindings.find(binding) == usedBufferBindings.end()) + { + usedBufferBindings.insert(binding); + return binding; + } + + recompile = true; + for (uint32_t i = 0; ; i++) + { + if (usedBufferBindings.find(i) == usedBufferBindings.end()) + { + usedBufferBindings.insert(i); + return i; + } + } + }; + spv::SpvBuildLogger logger; glslang::SpvOptions opt; opt.validate = true; @@ -687,29 +731,6 @@ void Shader::compileShaders() std::string msgs = logger.getAllMessages(); - VkShaderModuleCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = spirv.size() * sizeof(uint32_t); - createInfo.pCode = spirv.data(); - - auto device = vgfx->getDevice(); - - VkShaderModule shaderModule; - - if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { - throw love::Exception("failed to create shader module"); - } - - shaderModules.push_back(shaderModule); - - VkPipelineShaderStageCreateInfo shaderStageInfo{}; - shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - shaderStageInfo.stage = getStageBit((ShaderStageType)i); - shaderStageInfo.module = shaderModule; - shaderStageInfo.pName = "main"; - - shaderStages.push_back(shaderStageInfo); - spirv_cross::CompilerGLSL comp(spirv); // we only care about variables that are actually getting used. @@ -717,16 +738,25 @@ void Shader::compileShaders() auto shaderResources = comp.get_shader_resources(active); comp.set_enabled_interface_variables(std::move(active)); - for (const auto &resource : shaderResources.uniform_buffers) + for (const auto &resource : shaderResources.push_constant_buffers) { + useBuiltinUniformPushConstant = true; + } + + for (const auto &resource : shaderResources.uniform_buffers) + { + if (uniformInfos.find(resource.name) != uniformInfos.end()) + continue; + if (resource.name == "gl_DefaultUniformBlock") { - const auto& type = comp.get_type(resource.base_type_id); + const auto &type = comp.get_type(resource.base_type_id); size_t uniformBufferObjectSize = comp.get_declared_struct_size(type); auto defaultUniformBlockSize = comp.get_declared_struct_size(type); localUniformStagingData.resize(defaultUniformBlockSize); localUniformData.resize(defaultUniformBlockSize); - uniformLocation = comp.get_decoration(resource.id, spv::DecorationBinding); + uniformLocation = getFreeBinding(comp.get_decoration(resource.id, spv::DecorationBinding)); + comp.set_decoration(resource.id, spv::DecorationBinding, uniformLocation); memset(localUniformStagingData.data(), 0, defaultUniformBlockSize); memset(localUniformData.data(), 0, defaultUniformBlockSize); @@ -742,12 +772,16 @@ void Shader::compileShaders() for (const auto &r : shaderResources.sampled_images) { + if (uniformInfos.find(r.name) != uniformInfos.end()) + continue; + const SPIRType &basetype = comp.get_type(r.base_type_id); const SPIRType &type = comp.get_type(r.type_id); const SPIRType &imagetype = comp.get_type(basetype.image.type); graphics::Shader::UniformInfo info; - info.location = comp.get_decoration(r.id, spv::DecorationBinding); + info.location = getFreeBinding(comp.get_decoration(r.id, spv::DecorationBinding)); + comp.set_decoration(r.id, spv::DecorationBinding, info.location); info.baseType = UNIFORM_SAMPLER; info.name = r.name; info.count = type.array.empty() ? 1 : type.array[0]; @@ -812,6 +846,9 @@ void Shader::compileShaders() for (const auto &r : shaderResources.storage_buffers) { + if (uniformInfos.find(r.name) != uniformInfos.end()) + continue; + const auto &type = comp.get_type(r.type_id); UniformInfo u{}; @@ -819,8 +856,9 @@ void Shader::compileShaders() u.components = 1; u.name = r.name; u.count = type.array.empty() ? 1 : type.array[0]; - u.location = comp.get_decoration(r.id, spv::DecorationBinding); - + u.location = getFreeBinding(comp.get_decoration(r.id, spv::DecorationBinding)); + comp.set_decoration(r.id, spv::DecorationBinding, u.location); + const auto reflectionit = validationReflection.storageBuffers.find(u.name); if (reflectionit != validationReflection.storageBuffers.end()) { @@ -844,6 +882,9 @@ void Shader::compileShaders() for (const auto &r : shaderResources.storage_images) { + if (uniformInfos.find(r.name) != uniformInfos.end()) + continue; + const auto &type = comp.get_type(r.type_id); UniformInfo u{}; @@ -851,8 +892,10 @@ void Shader::compileShaders() u.components = 1; u.name = r.name; u.count = type.array.empty() ? 1 : type.array[0]; + // fixme: memory leak u.textures = new love::graphics::Texture *[u.count]; u.location = comp.get_decoration(r.id, spv::DecorationBinding); + comp.set_decoration(r.id, spv::DecorationBinding, u.location); for (int i = 0; i < u.count; i++) u.textures[i] = nullptr; @@ -869,6 +912,50 @@ void Shader::compileShaders() const int attributeLocation = static_cast(comp.get_decoration(r.id, spv::DecorationLocation)); attributes[name] = attributeLocation; } + + if (recompile) + { + auto glslLanguage = getGlslShaderType((ShaderStageType)i); + TShader* shader = new TShader(glslLanguage); + + parse(shader, glslLanguage, comp.compile(), useSpirv14); + + auto intermediate = shader->getIntermediate(); + + spv::SpvBuildLogger logger; + glslang::SpvOptions opt; + + std::vector code; + + GlslangToSpv(*intermediate, code, &logger, &opt); + + spirv = std::move(code); + + delete shader; + } + + VkShaderModuleCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = spirv.size() * sizeof(uint32_t); + createInfo.pCode = spirv.data(); + + auto device = vgfx->getDevice(); + + VkShaderModule shaderModule; + + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { + throw love::Exception("failed to create shader module"); + } + + shaderModules.push_back(shaderModule); + + VkPipelineShaderStageCreateInfo shaderStageInfo{}; + shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStageInfo.stage = getStageBit((ShaderStageType)i); + shaderStageInfo.module = shaderModule; + shaderStageInfo.pName = "main"; + + shaderStages.push_back(shaderStageInfo); } delete program; @@ -927,7 +1014,19 @@ void Shader::createPipelineLayout() pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; - pipelineLayoutInfo.pushConstantRangeCount = 0; + + static_assert(sizeof(BuiltinUniformData) % 4 == 0, "size of push constant has to be a multiple of 4."); + + VkPushConstantRange range{}; + range.offset = 0; + range.size = sizeof(BuiltinUniformData); + range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + + if (useBuiltinUniformPushConstant) + { + pipelineLayoutInfo.pushConstantRangeCount = 1; + pipelineLayoutInfo.pPushConstantRanges = ⦥ + } if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) throw love::Exception("failed to create pipeline layout"); diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 757ad1f42..bc0ef3a0f 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -88,6 +88,7 @@ private: VkPipeline computePipeline; + bool useBuiltinUniformPushConstant = false; VkDescriptorSetLayout descriptorSetLayout; VkPipelineLayout pipelineLayout; std::vector descriptorPoolSizes;