From 00974b582033fbd5007c7199570cfa24f0ad4c9d Mon Sep 17 00:00:00 2001 From: niki Date: Mon, 18 Jul 2022 22:28:41 +0200 Subject: [PATCH] vulkan: move shader compilation into Shader --- src/modules/graphics/Graphics.cpp | 4 +- src/modules/graphics/Shader.cpp | 62 ++--- src/modules/graphics/Shader.h | 1 - src/modules/graphics/vulkan/Graphics.cpp | 2 +- src/modules/graphics/vulkan/Shader.cpp | 239 +++++++++++++++++++- src/modules/graphics/vulkan/Shader.h | 10 +- src/modules/graphics/vulkan/ShaderStage.cpp | 210 +---------------- src/modules/graphics/vulkan/ShaderStage.h | 16 +- 8 files changed, 270 insertions(+), 274 deletions(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 17b7350dc..d1c851cea 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -368,7 +368,9 @@ Shader *Graphics::newShader(const std::vector &stagessource, const for (const std::string &source : stagessource) { Shader::SourceInfo info = Shader::getSourceInfo(source); - info.vulkan = options.defines.find("vulkan") != options.defines.end(); + if (capabilities.features[FEATURE_GLSL4]) { + info.language = Shader::LANGUAGE_GLSL4; + } bool isanystage = false; for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index 3ef32692e..e0eec23ff 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -56,8 +56,10 @@ static const char global_syntax[] = R"( #endif #if __VERSION__ >= 300 #define LOVE_IO_LOCATION(x) layout (location = x) +#define LOVE_IO_BINDING(x) layout (binding = x) #else #define LOVE_IO_LOCATION(x) +#define LOVE_IO_BINDING(x) #endif #define number float #define Image sampler2D @@ -83,27 +85,13 @@ static const char global_syntax[] = R"( #ifdef GL_OES_standard_derivatives #extension GL_OES_standard_derivatives : enable #endif -#ifdef USE_VULKAN - #define VULKAN_LOCATION(x) layout(location=x) - #define VULKAN_BINDING(x) layout(binding=x) -#else - #define VULKAN_LOCATION(x) - #define VULKAN_BINDING(x) -#endif )"; static const char render_uniforms[] = R"( -#ifdef USE_VULKAN - layout(binding=0) uniform LoveUniformsPerDraw { - vec4 uniformsPerDraw[13]; - } udp; - #define love_UniformsPerDraw udp.uniformsPerDraw -#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. - uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13]; -#endif +// 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. +uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13]; // These are initialized in love_initializeBuiltinUniforms below. GLSL ES can't // do it as an initializer. @@ -278,12 +266,12 @@ static const char vertex_header[] = R"( static const char vertex_functions[] = R"()"; static const char vertex_main[] = R"( -VULKAN_LOCATION(0) attribute vec4 VertexPosition; -VULKAN_LOCATION(1) attribute vec4 VertexTexCoord; -VULKAN_LOCATION(2) attribute vec4 VertexColor; +LOVE_IO_LOCATION(0) attribute vec4 VertexPosition; +LOVE_IO_LOCATION(1) attribute vec4 VertexTexCoord; +LOVE_IO_LOCATION(2) attribute vec4 VertexColor; -VULKAN_LOCATION(0) varying vec4 VaryingTexCoord; -VULKAN_LOCATION(1) varying vec4 VaryingColor; +LOVE_IO_LOCATION(0) varying vec4 VaryingTexCoord; +LOVE_IO_LOCATION(1) varying vec4 VaryingColor; vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition); @@ -323,9 +311,9 @@ static const char pixel_header[] = R"( )"; static const char pixel_functions[] = R"( -VULKAN_BINDING(2) uniform sampler2D love_VideoYChannel; -VULKAN_BINDING(3) uniform sampler2D love_VideoCbChannel; -VULKAN_BINDING(4) uniform sampler2D love_VideoCrChannel; +LOVE_IO_BINDING(2) uniform sampler2D love_VideoYChannel; +LOVE_IO_BINDING(3) uniform sampler2D love_VideoCbChannel; +LOVE_IO_BINDING(4) uniform sampler2D love_VideoCrChannel; vec4 VideoTexel(vec2 texcoords) { vec3 yuv; @@ -351,9 +339,9 @@ static const char pixel_main[] = R"( #define love_PixelColor gl_FragColor #endif -VULKAN_BINDING(1) uniform sampler2D MainTex; -VULKAN_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; -VULKAN_LOCATION(1) varying mediump vec4 VaryingColor; +LOVE_IO_BINDING(1) uniform sampler2D MainTex; +LOVE_IO_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; +LOVE_IO_LOCATION(1) varying mediump vec4 VaryingColor; vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord); @@ -388,8 +376,8 @@ static const char pixel_main_custom[] = R"( #define LOVE_MULTI_CANVASES 1 #endif -VULKAN_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; -VULKAN_LOCATION(1) varying mediump vec4 VaryingColor; +LOVE_IO_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; +LOVE_IO_LOCATION(1) varying mediump vec4 VaryingColor; void effect(); @@ -580,15 +568,9 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage, std::stringstream ss; - if (info.vulkan) { - ss << "#version 450\n"; - ss << "#define USE_VULKAN 1\n"; - } - else { - ss << (gles ? glsl::versions[lang].glsles : glsl::versions[lang].glsl) << "\n"; - if (glsl1on3) - ss << "#define LOVE_GLSL1_ON_GLSL3 1\n"; - } + ss << (gles ? glsl::versions[lang].glsles : glsl::versions[lang].glsl) << "\n"; + if (glsl1on3) + ss << "#define LOVE_GLSL1_ON_GLSL3 1\n"; if (isGammaCorrect()) ss << "#define LOVE_GAMMA_CORRECT 1\n"; diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index c8da04284..348943239 100644 --- a/src/modules/graphics/Shader.h +++ b/src/modules/graphics/Shader.h @@ -117,7 +117,6 @@ public: Language language; EntryPoint stages[SHADERSTAGE_MAX_ENUM]; bool usesMRT; - bool vulkan; }; struct MatrixSize diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 05c049e75..5bed538e4 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -1077,7 +1077,7 @@ namespace love { std::vector stages; stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_VERTEX)); stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_PIXEL)); - Shader::standardShaders[i] = newShader(stages, { { {"vulkan", "1"} } }); + Shader::standardShaders[i] = newShader(stages, {}); } } } diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 17485a660..67c14dd0a 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -1,10 +1,122 @@ #include "Shader.h" +#include "Graphics.h" + +#include "libraries/glslang/glslang/Public/ShaderLang.h" +#include "libraries/glslang/SPIRV/GlslangToSpv.h" +#include "libraries/spirv_cross/spirv_cross.hpp" #include namespace love { namespace graphics { namespace vulkan { + static const TBuiltInResource defaultTBuiltInResource = { + /* .MaxLights = */ 32, + /* .MaxClipPlanes = */ 6, + /* .MaxTextureUnits = */ 32, + /* .MaxTextureCoords = */ 32, + /* .MaxVertexAttribs = */ 64, + /* .MaxVertexUniformComponents = */ 16384, + /* .MaxVaryingFloats = */ 128, + /* .MaxVertexTextureImageUnits = */ 32, + /* .MaxCombinedTextureImageUnits = */ 80, + /* .MaxTextureImageUnits = */ 32, + /* .MaxFragmentUniformComponents = */ 16384, + /* .MaxDrawBuffers = */ 8, + /* .MaxVertexUniformVectors = */ 4096, + /* .MaxVaryingVectors = */ 32, + /* .MaxFragmentUniformVectors = */ 4096, + /* .MaxVertexOutputVectors = */ 32, + /* .MaxFragmentInputVectors = */ 31, + /* .MinProgramTexelOffset = */ -8, + /* .MaxProgramTexelOffset = */ 7, + /* .MaxClipDistances = */ 8, + /* .MaxComputeWorkGroupCountX = */ 65535, + /* .MaxComputeWorkGroupCountY = */ 65535, + /* .MaxComputeWorkGroupCountZ = */ 65535, + /* .MaxComputeWorkGroupSizeX = */ 1024, + /* .MaxComputeWorkGroupSizeY = */ 1024, + /* .MaxComputeWorkGroupSizeZ = */ 64, + /* .MaxComputeUniformComponents = */ 1024, + /* .MaxComputeTextureImageUnits = */ 32, + /* .MaxComputeImageUniforms = */ 16, + /* .MaxComputeAtomicCounters = */ 4096, + /* .MaxComputeAtomicCounterBuffers = */ 8, + /* .MaxVaryingComponents = */ 128, + /* .MaxVertexOutputComponents = */ 128, + /* .MaxGeometryInputComponents = */ 128, + /* .MaxGeometryOutputComponents = */ 128, + /* .MaxFragmentInputComponents = */ 128, + /* .MaxImageUnits = */ 192, + /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 144, + /* .MaxCombinedShaderOutputResources = */ 144, + /* .MaxImageSamples = */ 32, + /* .MaxVertexImageUniforms = */ 16, + /* .MaxTessControlImageUniforms = */ 16, + /* .MaxTessEvaluationImageUniforms = */ 16, + /* .MaxGeometryImageUniforms = */ 16, + /* .MaxFragmentImageUniforms = */ 16, + /* .MaxCombinedImageUniforms = */ 80, + /* .MaxGeometryTextureImageUnits = */ 16, + /* .MaxGeometryOutputVertices = */ 256, + /* .MaxGeometryTotalOutputComponents = */ 1024, + /* .MaxGeometryUniformComponents = */ 1024, + /* .MaxGeometryVaryingComponents = */ 64, + /* .MaxTessControlInputComponents = */ 128, + /* .MaxTessControlOutputComponents = */ 128, + /* .MaxTessControlTextureImageUnits = */ 16, + /* .MaxTessControlUniformComponents = */ 1024, + /* .MaxTessControlTotalOutputComponents = */ 4096, + /* .MaxTessEvaluationInputComponents = */ 128, + /* .MaxTessEvaluationOutputComponents = */ 128, + /* .MaxTessEvaluationTextureImageUnits = */ 16, + /* .MaxTessEvaluationUniformComponents = */ 1024, + /* .MaxTessPatchComponents = */ 120, + /* .MaxPatchVertices = */ 32, + /* .MaxTessGenLevel = */ 64, + /* .MaxViewports = */ 16, + /* .MaxVertexAtomicCounters = */ 4096, + /* .MaxTessControlAtomicCounters = */ 4096, + /* .MaxTessEvaluationAtomicCounters = */ 4096, + /* .MaxGeometryAtomicCounters = */ 4096, + /* .MaxFragmentAtomicCounters = */ 4096, + /* .MaxCombinedAtomicCounters = */ 4096, + /* .MaxAtomicCounterBindings = */ 8, + /* .MaxVertexAtomicCounterBuffers = */ 8, + /* .MaxTessControlAtomicCounterBuffers = */ 8, + /* .MaxTessEvaluationAtomicCounterBuffers = */ 8, + /* .MaxGeometryAtomicCounterBuffers = */ 8, + /* .MaxFragmentAtomicCounterBuffers = */ 8, + /* .MaxCombinedAtomicCounterBuffers = */ 8, + /* .MaxAtomicCounterBufferSize = */ 16384, + /* .MaxTransformFeedbackBuffers = */ 4, + /* .MaxTransformFeedbackInterleavedComponents = */ 64, + /* .MaxCullDistances = */ 8, + /* .MaxCombinedClipAndCullDistances = */ 8, + /* .MaxSamples = */ 32, + /* .maxMeshOutputVerticesNV = */ 256, + /* .maxMeshOutputPrimitivesNV = */ 512, + /* .maxMeshWorkGroupSizeX_NV = */ 32, + /* .maxMeshWorkGroupSizeY_NV = */ 1, + /* .maxMeshWorkGroupSizeZ_NV = */ 1, + /* .maxTaskWorkGroupSizeX_NV = */ 32, + /* .maxTaskWorkGroupSizeY_NV = */ 1, + /* .maxTaskWorkGroupSizeZ_NV = */ 1, + /* .maxMeshViewCountNV = */ 4, + /* .maxDualSourceDrawBuffersEXT = */ 1, + /* .limits = */ { + /* .nonInductiveForLoops = */ 1, + /* .whileLoops = */ 1, + /* .doWhileLoops = */ 1, + /* .generalUniformIndexing = */ 1, + /* .generalAttributeMatrixVectorIndexing = */ 1, + /* .generalVaryingIndexing = */ 1, + /* .generalSamplerIndexing = */ 1, + /* .generalVariableIndexing = */ 1, + /* .generalConstantMatrixVectorIndexing = */ 1, + } + }; + static VkShaderStageFlagBits getStageBit(ShaderStageType type) { switch (type) { case SHADERSTAGE_VERTEX: @@ -17,22 +129,139 @@ namespace love { throw love::Exception("invalid type"); } + 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"); + } + } + Shader::Shader(StrongRef stages[]) : graphics::Shader(stages) { + loadVolatile(); + } + + bool Shader::loadVolatile() { + using namespace glslang; + using namespace spirv_cross; + + TProgram* program = new TProgram(); + + auto gfx = Module::getInstance(Module::ModuleType::M_GRAPHICS); + for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) { - if (!stages[i]) + if (!stages[i]) continue; - - auto stage = dynamic_cast(stages[i].get()); + + auto stage = (ShaderStageType)i; + auto glslangShaderStage = getGlslShaderType(stage); + auto tshader = new TShader(glslangShaderStage); + + tshader->setEnvInput(EShSourceGlsl, glslangShaderStage, EShClientVulkan, 450); + tshader->setEnvClient(EShClientVulkan, EShTargetVulkan_1_2); + tshader->setEnvTarget(EshTargetSpv, EShTargetSpv_1_5); + 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 = glsl.length(); + tshader->setStringsWithLengths(&csrc, &sourceLength, 1); + + int defaultVersio = 450; + EProfile defaultProfile = ECoreProfile; + bool forceDefault = false; + bool forwardCompat = true; + + if (!tshader->parse(&defaultTBuiltInResource, defaultVersio, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings)) { + const char* msg1 = tshader->getInfoLog(); + const char* msg2 = tshader->getInfoDebugLog(); + + throw love::Exception("error while parsing shader"); + } + + program->addShader(tshader); + } + + if (!program->link(EShMsgDefault)) { + throw love::Exception("link failed! %s\n", program->getInfoLog()); + } + + if (!program->mapIO()) { + throw love::Exception("mapIO failed"); + } + + for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) { + auto glslangStage = getGlslShaderType((ShaderStageType)i); + auto intermediate = program->getIntermediate(glslangStage); + if (intermediate == nullptr) { + continue; + } + + spv::SpvBuildLogger logger; + glslang::SpvOptions opt; + opt.validate = true; + + std::vector spirv; + GlslangToSpv(*intermediate, spirv, &logger, &opt); + + 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(); + + Graphics* vkGfx = (Graphics*)gfx; + auto device = vkGfx->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(stage->getStageType()); - shaderStageInfo.module = stage->getShaderModule(); + shaderStageInfo.stage = getStageBit((ShaderStageType)i); + shaderStageInfo.module = shaderModule; shaderStageInfo.pName = "main"; shaderStages.push_back(shaderStageInfo); } + + return true; + } + + void Shader::unloadVolatile() { + if (shaderModules.size() == 0) { + return; + } + + auto gfx = Module::getInstance(Module::M_GRAPHICS); + auto device = gfx->getDevice(); + // fixme: we shouldn't do a greedy wait here. + vkDeviceWaitIdle(device); + for (const auto shaderModule : shaderModules) { + vkDestroyShaderModule(device, shaderModule, nullptr); + } + shaderModules.clear(); + shaderStages.clear(); + } + + Shader::~Shader() { + unloadVolatile(); } void Shader::attach() { diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index b9287e929..29ba11ebd 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -13,10 +13,13 @@ namespace love { namespace graphics { namespace vulkan { - class Shader final : public graphics::Shader { + class Shader final : public graphics::Shader, public Volatile { public: Shader(StrongRef stages[]); - virtual ~Shader() = default; + virtual ~Shader(); + + bool loadVolatile() override; + void unloadVolatile() override; const std::vector& getShaderStages() const { return shaderStages; @@ -44,6 +47,7 @@ namespace love { private: std::vector shaderStages; + std::vector shaderModules; std::map vertexAttributeIndices = { { "VertexPosition", 0 }, @@ -59,7 +63,7 @@ namespace love { { "MainTex", 4 } }; - + std::map uniforms; }; } } diff --git a/src/modules/graphics/vulkan/ShaderStage.cpp b/src/modules/graphics/vulkan/ShaderStage.cpp index b377fc6bc..9919db7f5 100644 --- a/src/modules/graphics/vulkan/ShaderStage.cpp +++ b/src/modules/graphics/vulkan/ShaderStage.cpp @@ -14,215 +14,9 @@ namespace love { namespace graphics { namespace vulkan { - static const TBuiltInResource defaultTBuiltInResource = { - /* .MaxLights = */ 32, - /* .MaxClipPlanes = */ 6, - /* .MaxTextureUnits = */ 32, - /* .MaxTextureCoords = */ 32, - /* .MaxVertexAttribs = */ 64, - /* .MaxVertexUniformComponents = */ 16384, - /* .MaxVaryingFloats = */ 128, - /* .MaxVertexTextureImageUnits = */ 32, - /* .MaxCombinedTextureImageUnits = */ 80, - /* .MaxTextureImageUnits = */ 32, - /* .MaxFragmentUniformComponents = */ 16384, - /* .MaxDrawBuffers = */ 8, - /* .MaxVertexUniformVectors = */ 4096, - /* .MaxVaryingVectors = */ 32, - /* .MaxFragmentUniformVectors = */ 4096, - /* .MaxVertexOutputVectors = */ 32, - /* .MaxFragmentInputVectors = */ 31, - /* .MinProgramTexelOffset = */ -8, - /* .MaxProgramTexelOffset = */ 7, - /* .MaxClipDistances = */ 8, - /* .MaxComputeWorkGroupCountX = */ 65535, - /* .MaxComputeWorkGroupCountY = */ 65535, - /* .MaxComputeWorkGroupCountZ = */ 65535, - /* .MaxComputeWorkGroupSizeX = */ 1024, - /* .MaxComputeWorkGroupSizeY = */ 1024, - /* .MaxComputeWorkGroupSizeZ = */ 64, - /* .MaxComputeUniformComponents = */ 1024, - /* .MaxComputeTextureImageUnits = */ 32, - /* .MaxComputeImageUniforms = */ 16, - /* .MaxComputeAtomicCounters = */ 4096, - /* .MaxComputeAtomicCounterBuffers = */ 8, - /* .MaxVaryingComponents = */ 128, - /* .MaxVertexOutputComponents = */ 128, - /* .MaxGeometryInputComponents = */ 128, - /* .MaxGeometryOutputComponents = */ 128, - /* .MaxFragmentInputComponents = */ 128, - /* .MaxImageUnits = */ 192, - /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 144, - /* .MaxCombinedShaderOutputResources = */ 144, - /* .MaxImageSamples = */ 32, - /* .MaxVertexImageUniforms = */ 16, - /* .MaxTessControlImageUniforms = */ 16, - /* .MaxTessEvaluationImageUniforms = */ 16, - /* .MaxGeometryImageUniforms = */ 16, - /* .MaxFragmentImageUniforms = */ 16, - /* .MaxCombinedImageUniforms = */ 80, - /* .MaxGeometryTextureImageUnits = */ 16, - /* .MaxGeometryOutputVertices = */ 256, - /* .MaxGeometryTotalOutputComponents = */ 1024, - /* .MaxGeometryUniformComponents = */ 1024, - /* .MaxGeometryVaryingComponents = */ 64, - /* .MaxTessControlInputComponents = */ 128, - /* .MaxTessControlOutputComponents = */ 128, - /* .MaxTessControlTextureImageUnits = */ 16, - /* .MaxTessControlUniformComponents = */ 1024, - /* .MaxTessControlTotalOutputComponents = */ 4096, - /* .MaxTessEvaluationInputComponents = */ 128, - /* .MaxTessEvaluationOutputComponents = */ 128, - /* .MaxTessEvaluationTextureImageUnits = */ 16, - /* .MaxTessEvaluationUniformComponents = */ 1024, - /* .MaxTessPatchComponents = */ 120, - /* .MaxPatchVertices = */ 32, - /* .MaxTessGenLevel = */ 64, - /* .MaxViewports = */ 16, - /* .MaxVertexAtomicCounters = */ 4096, - /* .MaxTessControlAtomicCounters = */ 4096, - /* .MaxTessEvaluationAtomicCounters = */ 4096, - /* .MaxGeometryAtomicCounters = */ 4096, - /* .MaxFragmentAtomicCounters = */ 4096, - /* .MaxCombinedAtomicCounters = */ 4096, - /* .MaxAtomicCounterBindings = */ 8, - /* .MaxVertexAtomicCounterBuffers = */ 8, - /* .MaxTessControlAtomicCounterBuffers = */ 8, - /* .MaxTessEvaluationAtomicCounterBuffers = */ 8, - /* .MaxGeometryAtomicCounterBuffers = */ 8, - /* .MaxFragmentAtomicCounterBuffers = */ 8, - /* .MaxCombinedAtomicCounterBuffers = */ 8, - /* .MaxAtomicCounterBufferSize = */ 16384, - /* .MaxTransformFeedbackBuffers = */ 4, - /* .MaxTransformFeedbackInterleavedComponents = */ 64, - /* .MaxCullDistances = */ 8, - /* .MaxCombinedClipAndCullDistances = */ 8, - /* .MaxSamples = */ 32, - /* .maxMeshOutputVerticesNV = */ 256, - /* .maxMeshOutputPrimitivesNV = */ 512, - /* .maxMeshWorkGroupSizeX_NV = */ 32, - /* .maxMeshWorkGroupSizeY_NV = */ 1, - /* .maxMeshWorkGroupSizeZ_NV = */ 1, - /* .maxTaskWorkGroupSizeX_NV = */ 32, - /* .maxTaskWorkGroupSizeY_NV = */ 1, - /* .maxTaskWorkGroupSizeZ_NV = */ 1, - /* .maxMeshViewCountNV = */ 4, - /* .maxDualSourceDrawBuffersEXT = */ 1, - /* .limits = */ { - /* .nonInductiveForLoops = */ 1, - /* .whileLoops = */ 1, - /* .doWhileLoops = */ 1, - /* .generalUniformIndexing = */ 1, - /* .generalAttributeMatrixVectorIndexing = */ 1, - /* .generalVaryingIndexing = */ 1, - /* .generalSamplerIndexing = */ 1, - /* .generalVariableIndexing = */ 1, - /* .generalConstantMatrixVectorIndexing = */ 1, - } - }; - - 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"); - } - } - - static std::vector compileShaderWithGlslang(const std::string& glsl, ShaderStageType stage) { - using namespace glslang; - - auto glslangShaderStage = getGlslShaderType(stage); - auto tshader = new TShader(glslangShaderStage); - - tshader->setEnvInput(EShSourceGlsl, glslangShaderStage, EShClientVulkan, 450); - tshader->setEnvClient(EShClientVulkan, EShTargetVulkan_1_2); - tshader->setEnvTarget(EshTargetSpv, EShTargetSpv_1_5); - tshader->setAutoMapLocations(true); - tshader->setAutoMapBindings(true); - - /* - tshader->getEnvInputVulkanRulesRelaxed(); - tshader->setGlobalUniformBinding(0); - tshader->setGlobalUniformSet(0); - */ - - const char* csrc = glsl.c_str(); - const int sourceLength = glsl.length(); - tshader->setStringsWithLengths(&csrc, &sourceLength, 1); - - int defaultVersio = 450; - EProfile defaultProfile = ECoreProfile; - bool forceDefault = false; - bool forwardCompat = true; - - if (!tshader->parse(&defaultTBuiltInResource, defaultVersio, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings)) { - const char* msg1 = tshader->getInfoLog(); - const char* msg2 = tshader->getInfoDebugLog(); - - throw love::Exception("error while parsing shader"); - } - - auto intermediate = tshader->getIntermediate(); - - if (intermediate == nullptr) { - throw love::Exception("error when getting the intermediate"); - } - spv::SpvBuildLogger logger; - SpvOptions opt; - opt.validate = true; - - std::vector spirv; - GlslangToSpv(*intermediate, spirv, &logger, &opt); - - delete tshader; - - return spirv; - } - ShaderStage::ShaderStage(love::graphics::Graphics* gfx, ShaderStageType stage, const std::string& glsl, bool gles, const std::string& cachekey) - : love::graphics::ShaderStage(gfx, stage, glsl, gles, cachekey), gfx(gfx) { - loadVolatile(); - } - - bool ShaderStage::loadVolatile() { - auto stage = getStageType(); - auto glsl = getSource(); - auto code = compileShaderWithGlslang(glsl, stage); - - VkShaderModuleCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = code.size() * sizeof(uint32_t); - createInfo.pCode = code.data(); - - Graphics* vkGfx = (Graphics*)gfx; - device = vkGfx->getDevice(); - - if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { - throw love::Exception("failed to create shader module"); - } - - return true; - } - - void ShaderStage::unloadVolatile() { - if (shaderModule == VK_NULL_HANDLE) - return; - - // FIXME: objects for deletion should probably be put on a queue - // instead of greedy waiting here. - vkDeviceWaitIdle(device); - vkDestroyShaderModule(device, shaderModule, nullptr); - shaderModule = VK_NULL_HANDLE; - } - - ShaderStage::~ShaderStage() { - unloadVolatile(); + : love::graphics::ShaderStage(gfx, stage, glsl, gles, cachekey) { + // the compilation is done in Shader. } } } diff --git a/src/modules/graphics/vulkan/ShaderStage.h b/src/modules/graphics/vulkan/ShaderStage.h index 6f06ae0db..4652ef7dc 100644 --- a/src/modules/graphics/vulkan/ShaderStage.h +++ b/src/modules/graphics/vulkan/ShaderStage.h @@ -8,27 +8,13 @@ namespace love { namespace graphics { namespace vulkan { - class ShaderStage final : public graphics::ShaderStage, public Volatile { + class ShaderStage final : public graphics::ShaderStage { public: ShaderStage(love::graphics::Graphics* gfx, ShaderStageType stage, const std::string& glsl, bool gles, const std::string& cachekey); - virtual ~ShaderStage(); - - virtual bool loadVolatile() override; - - virtual void unloadVolatile() override; - - VkShaderModule getShaderModule() const { - return shaderModule; - } ptrdiff_t getHandle() const { return 0; } - - private: - VkShaderModule shaderModule = VK_NULL_HANDLE; - VkDevice device; - love::graphics::Graphics* gfx; }; } }