mirror of
https://github.com/love2d/love.git
synced 2026-08-12 16:40:57 +02:00
vulkan: use push constants for builtin uniforms
when available
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -226,7 +226,7 @@ void Graphics::discard(const std::vector<bool>& 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<float>(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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "libraries/glslang/glslang/Public/ShaderLang.h"
|
||||
#include "libraries/glslang/SPIRV/GlslangToSpv.h"
|
||||
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
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<int>(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<int>(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<uint32_t> 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<int>(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<uint32_t> 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");
|
||||
|
||||
@@ -88,6 +88,7 @@ private:
|
||||
|
||||
VkPipeline computePipeline;
|
||||
|
||||
bool useBuiltinUniformPushConstant = false;
|
||||
VkDescriptorSetLayout descriptorSetLayout;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
std::vector<VkDescriptorPoolSize> descriptorPoolSizes;
|
||||
|
||||
Reference in New Issue
Block a user