Browse Source

vulkan: move shader compilation into Shader

niki 3 years ago
parent
commit
00974b5820

+ 3 - 1
src/modules/graphics/Graphics.cpp

@@ -368,7 +368,9 @@ Shader *Graphics::newShader(const std::vector<std::string> &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++)

+ 22 - 40
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";

+ 0 - 1
src/modules/graphics/Shader.h

@@ -117,7 +117,6 @@ public:
 		Language language;
 		EntryPoint stages[SHADERSTAGE_MAX_ENUM];
 		bool usesMRT;
-		bool vulkan;
 	};
 
 	struct MatrixSize

+ 1 - 1
src/modules/graphics/vulkan/Graphics.cpp

@@ -1077,7 +1077,7 @@ namespace love {
 						std::vector<std::string> 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, {});
 					}
 				}
 			}

+ 234 - 5
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 <vector>
 
 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<love::graphics::ShaderStage> stages[])
 				: graphics::Shader(stages) {
+				loadVolatile();
+			}
+
+			bool Shader::loadVolatile() {
+				using namespace glslang;
+				using namespace spirv_cross;
+
+				TProgram* program = new TProgram();
+
+				auto gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS);
+
 				for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) {
-					if (!stages[i]) 
+					if (!stages[i])
 						continue;
-					
-					auto stage = dynamic_cast<ShaderStage*>(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<uint32_t> 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<Graphics>(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() {

+ 7 - 3
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<love::graphics::ShaderStage> stages[]);
-				virtual ~Shader() = default;
+				virtual ~Shader();
+
+				bool loadVolatile() override;
+				void unloadVolatile() override;
 
 				const std::vector<VkPipelineShaderStageCreateInfo>& getShaderStages() const {
 					return shaderStages;
@@ -44,6 +47,7 @@ namespace love {
 
 			private:
 				std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
+				std::vector<VkShaderModule> shaderModules;
 
 				std::map<std::string, int> vertexAttributeIndices = {
 					{ "VertexPosition", 0 },
@@ -59,7 +63,7 @@ namespace love {
 					{ "MainTex", 4 }
 				};
 
-
+				std::map<std::string, UniformInfo> uniforms;
 			};
 		}
 	}

+ 2 - 208
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<uint32_t> 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<uint32_t> 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.
 			}
 		}
 	}

+ 1 - 15
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;
 			};
 		}
 	}