Browse Source

start implementing vulkan Shader type

niki 3 years ago
parent
commit
197dfb9738

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

@@ -342,7 +342,7 @@ ShaderStage *Graphics::newShaderStage(ShaderStageType stage, const std::string &
 	return s;
 	return s;
 }
 }
 
 
-Shader *Graphics::newShader(const std::vector<std::string> &stagessource)
+Shader *Graphics::newShader(const std::vector<std::string> &stagessource, bool vulkan)
 {
 {
 	StrongRef<ShaderStage> stages[SHADERSTAGE_MAX_ENUM] = {};
 	StrongRef<ShaderStage> stages[SHADERSTAGE_MAX_ENUM] = {};
 
 
@@ -353,6 +353,7 @@ Shader *Graphics::newShader(const std::vector<std::string> &stagessource)
 	for (const std::string &source : stagessource)
 	for (const std::string &source : stagessource)
 	{
 	{
 		Shader::SourceInfo info = Shader::getSourceInfo(source);
 		Shader::SourceInfo info = Shader::getSourceInfo(source);
+		info.vulkan = vulkan;
 		bool isanystage = false;
 		bool isanystage = false;
 
 
 		for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++)
 		for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++)

+ 1 - 1
src/modules/graphics/Graphics.h

@@ -449,7 +449,7 @@ public:
 	SpriteBatch *newSpriteBatch(Texture *texture, int size, BufferDataUsage usage);
 	SpriteBatch *newSpriteBatch(Texture *texture, int size, BufferDataUsage usage);
 	ParticleSystem *newParticleSystem(Texture *texture, int size);
 	ParticleSystem *newParticleSystem(Texture *texture, int size);
 
 
-	Shader *newShader(const std::vector<std::string> &stagessource);
+	Shader *newShader(const std::vector<std::string> &stagessource, bool vulkan = false);
 	Shader *newComputeShader(const std::string &source);
 	Shader *newComputeShader(const std::string &source);
 
 
 	virtual Buffer *newBuffer(const Buffer::Settings &settings, const std::vector<Buffer::DataDeclaration> &format, const void *data, size_t size, size_t arraylength) = 0;
 	virtual Buffer *newBuffer(const Buffer::Settings &settings, const std::vector<Buffer::DataDeclaration> &format, const void *data, size_t size, size_t arraylength) = 0;

+ 38 - 18
src/modules/graphics/Shader.cpp

@@ -83,13 +83,27 @@ static const char global_syntax[] = R"(
 #ifdef GL_OES_standard_derivatives
 #ifdef GL_OES_standard_derivatives
 #extension GL_OES_standard_derivatives : enable
 #extension GL_OES_standard_derivatives : enable
 #endif
 #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"(
 static const char render_uniforms[] = R"(
-// 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];
+#ifdef USE_VULKAN
+	VULKAN_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
 
 
 // These are initialized in love_initializeBuiltinUniforms below. GLSL ES can't
 // These are initialized in love_initializeBuiltinUniforms below. GLSL ES can't
 // do it as an initializer.
 // do it as an initializer.
@@ -264,12 +278,12 @@ static const char vertex_header[] = R"(
 static const char vertex_functions[] = R"()";
 static const char vertex_functions[] = R"()";
 
 
 static const char vertex_main[] = R"(
 static const char vertex_main[] = R"(
-attribute vec4 VertexPosition;
-attribute vec4 VertexTexCoord;
-attribute vec4 VertexColor;
+VULKAN_LOCATION(0) attribute vec4 VertexPosition;
+VULKAN_LOCATION(1) attribute vec4 VertexTexCoord;
+VULKAN_LOCATION(2) attribute vec4 VertexColor;
 
 
-varying vec4 VaryingTexCoord;
-varying vec4 VaryingColor;
+VULKAN_LOCATION(0) varying vec4 VaryingTexCoord;
+VULKAN_LOCATION(1) varying vec4 VaryingColor;
 
 
 vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition);
 vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition);
 
 
@@ -309,9 +323,9 @@ static const char pixel_header[] = R"(
 )";
 )";
 
 
 static const char pixel_functions[] = R"(
 static const char pixel_functions[] = R"(
-uniform sampler2D love_VideoYChannel;
-uniform sampler2D love_VideoCbChannel;
-uniform sampler2D love_VideoCrChannel;
+VULKAN_BINDING(1) uniform sampler2D love_VideoYChannel;
+VULKAN_BINDING(2) uniform sampler2D love_VideoCbChannel;
+VULKAN_BINDING(3) uniform sampler2D love_VideoCrChannel;
 
 
 vec4 VideoTexel(vec2 texcoords) {
 vec4 VideoTexel(vec2 texcoords) {
 	vec3 yuv;
 	vec3 yuv;
@@ -337,9 +351,9 @@ static const char pixel_main[] = R"(
 	#define love_PixelColor gl_FragColor
 	#define love_PixelColor gl_FragColor
 #endif
 #endif
 
 
-uniform sampler2D MainTex;
-varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
-varying mediump vec4 VaryingColor;
+VULKAN_BINDING(4) uniform sampler2D MainTex;
+VULKAN_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
+VULKAN_LOCATION(1) varying mediump vec4 VaryingColor;
 
 
 vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord);
 vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord);
 
 
@@ -374,8 +388,8 @@ static const char pixel_main_custom[] = R"(
 #define LOVE_MULTI_CANVASES 1
 #define LOVE_MULTI_CANVASES 1
 #endif
 #endif
 
 
-varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
-varying mediump vec4 VaryingColor;
+VULKAN_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
+VULKAN_LOCATION(1) varying mediump vec4 VaryingColor;
 
 
 void effect();
 void effect();
 
 
@@ -562,6 +576,9 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage,
 	if (glsl1on3)
 	if (glsl1on3)
 		lang = LANGUAGE_GLSL3;
 		lang = LANGUAGE_GLSL3;
 
 
+	if (info.vulkan)
+		lang = LANGUAGE_GLSL4;
+
 	glsl::StageInfo stageinfo = glsl::stageInfo[stage];
 	glsl::StageInfo stageinfo = glsl::stageInfo[stage];
 
 
 	std::stringstream ss;
 	std::stringstream ss;
@@ -574,6 +591,8 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage,
 		ss << "#define LOVE_GAMMA_CORRECT 1\n";
 		ss << "#define LOVE_GAMMA_CORRECT 1\n";
 	if (info.usesMRT)
 	if (info.usesMRT)
 		ss << "#define LOVE_MULTI_RENDER_TARGETS 1\n";
 		ss << "#define LOVE_MULTI_RENDER_TARGETS 1\n";
+	if (info.vulkan)
+		ss << "#define USE_VULKAN\n";
 	ss << glsl::global_syntax;
 	ss << glsl::global_syntax;
 	ss << stageinfo.header;
 	ss << stageinfo.header;
 	ss << stageinfo.uniforms;
 	ss << stageinfo.uniforms;
@@ -893,7 +912,8 @@ bool Shader::validateInternal(StrongRef<ShaderStage> stages[], std::string &err,
 		{
 		{
 			LocalUniform u = {};
 			LocalUniform u = {};
 			auto &values = u.initializerValues;
 			auto &values = u.initializerValues;
-			const glslang::TConstUnionArray *constarray = info.getConstArray();
+			// const glslang::TConstUnionArray *constarray = info.getConstArray(); was this function deprecated in a later version?
+			const glslang::TConstUnionArray* constarray = nullptr;
 
 
 			// Store initializer values for local uniforms. Some love graphics
 			// Store initializer values for local uniforms. Some love graphics
 			// backends strip these out of the shader so we need to be able to
 			// backends strip these out of the shader so we need to be able to

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

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

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

@@ -215,6 +215,17 @@ namespace love {
 					batchedDrawState.indexBuffer = new StreamBuffer(device, physicalDevice, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
 					batchedDrawState.indexBuffer = new StreamBuffer(device, physicalDevice, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
 				}
 				}
 
 
+				for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++) {
+					auto stype = (Shader::StandardShader)i;
+
+					if (!Shader::standardShaders[i]) {
+						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, true);
+					}
+				}
+
 				return true;
 				return true;
 			}
 			}
 
 
@@ -759,7 +770,7 @@ namespace love {
 				rasterizer.rasterizerDiscardEnable = VK_FALSE;
 				rasterizer.rasterizerDiscardEnable = VK_FALSE;
 				rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
 				rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
 				rasterizer.lineWidth = 1.0f;
 				rasterizer.lineWidth = 1.0f;
-				rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
+				rasterizer.cullMode = VK_CULL_MODE_FRONT_BIT;
 				rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
 				rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
 				rasterizer.depthBiasEnable = VK_FALSE;
 				rasterizer.depthBiasEnable = VK_FALSE;
 				rasterizer.depthBiasConstantFactor = 0.0f;
 				rasterizer.depthBiasConstantFactor = 0.0f;

+ 10 - 2
src/modules/graphics/vulkan/Graphics.h

@@ -3,6 +3,8 @@
 
 
 #include "graphics/Graphics.h"
 #include "graphics/Graphics.h"
 #include "StreamBuffer.h"
 #include "StreamBuffer.h"
+#include "ShaderStage.h"
+#include "Shader.h"
 #include <vulkan/vulkan.h>
 #include <vulkan/vulkan.h>
 
 
 #include <common/config.h>
 #include <common/config.h>
@@ -66,8 +68,14 @@ namespace love {
 				void drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, Texture* texture) override { std::cout << "drawQuads "; }
 				void drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, Texture* texture) override { std::cout << "drawQuads "; }
 
 
 			protected:
 			protected:
-				graphics::ShaderStage* newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) override { std::cout << "newShaderStageInternal "; return nullptr; }
-				graphics::Shader* newShaderInternal(StrongRef<love::graphics::ShaderStage> stages[SHADERSTAGE_MAX_ENUM]) override { std::cout << "newShaderInternal "; return nullptr; }
+				graphics::ShaderStage* newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) override { 
+					std::cout << "newShaderStageInternal "; 
+					return new ShaderStage(this, stage, source, gles, cachekey); 
+				}
+				graphics::Shader* newShaderInternal(StrongRef<love::graphics::ShaderStage> stages[SHADERSTAGE_MAX_ENUM]) override { 
+					std::cout << "newShaderInternal "; 
+					return new Shader(stages);
+				}
 				graphics::StreamBuffer* newStreamBuffer(BufferUsage type, size_t size) override;
 				graphics::StreamBuffer* newStreamBuffer(BufferUsage type, size_t size) override;
 				bool dispatch(int x, int y, int z) override { std::cout << "dispatch "; return false; }
 				bool dispatch(int x, int y, int z) override { std::cout << "dispatch "; return false; }
 				void initCapabilities() override { std::cout << "initCapabilities "; }
 				void initCapabilities() override { std::cout << "initCapabilities "; }

+ 15 - 16
src/modules/graphics/vulkan/Shader.cpp

@@ -1,7 +1,5 @@
 #include "Shader.h"
 #include "Shader.h"
 
 
-#include "libraries/glslang/glslang/Public/ShaderLang.h"
-#include "libraries/glslang/SPIRV/GlslangToSpv.h"
 #include <vector>
 #include <vector>
 
 
 namespace love {
 namespace love {
@@ -21,24 +19,25 @@ namespace love {
 
 
 			Shader::Shader(StrongRef<love::graphics::ShaderStage> stages[])
 			Shader::Shader(StrongRef<love::graphics::ShaderStage> stages[])
 				: graphics::Shader(stages) {
 				: graphics::Shader(stages) {
-
-				if (false) {
-					for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) {
-						if (!stages[i]) 
-							continue;
+				for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) {
+					if (!stages[i]) 
+						continue;
 					
 					
-						auto stage = dynamic_cast<ShaderStage*>(stages[i].get());
+					auto stage = dynamic_cast<ShaderStage*>(stages[i].get());
 
 
-						VkPipelineShaderStageCreateInfo shaderStageInfo{};
-						shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
-						shaderStageInfo.stage = getStageBit(stage->getStageType());
-						shaderStageInfo.module = stage->getShaderModule();
-						shaderStageInfo.pName = "main";
+					VkPipelineShaderStageCreateInfo shaderStageInfo{};
+					shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+					shaderStageInfo.stage = getStageBit(stage->getStageType());
+					shaderStageInfo.module = stage->getShaderModule();
+					shaderStageInfo.pName = "main";
 
 
-						shaderStages.push_back(shaderStageInfo);
-					}
+					shaderStages.push_back(shaderStageInfo);
 				}
 				}
 			}
 			}
+
+			int Shader::getVertexAttributeIndex(const std::string& name) {
+				return vertexAttributeIndices.at(name);
+			}
 		}
 		}
 	}
 	}
-}
+}

+ 25 - 3
src/modules/graphics/vulkan/Shader.h

@@ -3,10 +3,10 @@
 
 
 #include <graphics/Shader.h>
 #include <graphics/Shader.h>
 #include <graphics/vulkan/ShaderStage.h>
 #include <graphics/vulkan/ShaderStage.h>
-#include "libraries/glslang/glslang/Public/ShaderLang.h"
-#include "libraries/glslang/SPIRV/GlslangToSpv.h"
 #include <vulkan/vulkan.h>
 #include <vulkan/vulkan.h>
 
 
+#include <map>
+
 
 
 namespace love {
 namespace love {
 	namespace graphics {
 	namespace graphics {
@@ -26,7 +26,7 @@ namespace love {
 
 
 				std::string getWarnings() const override { return ""; }
 				std::string getWarnings() const override { return ""; }
 
 
-				int getVertexAttributeIndex(const std::string& name) override { return 0;  }
+				int getVertexAttributeIndex(const std::string& name) override;
 
 
 				const UniformInfo* getUniformInfo(const std::string& name) const override { return nullptr; }
 				const UniformInfo* getUniformInfo(const std::string& name) const override { return nullptr; }
 				const UniformInfo* getUniformInfo(BuiltinUniform builtin) const override { return nullptr;  }
 				const UniformInfo* getUniformInfo(BuiltinUniform builtin) const override { return nullptr;  }
@@ -41,7 +41,29 @@ namespace love {
 				void setVideoTextures(Texture* ytexture, Texture* cbtexture, Texture* crtexture) override {}
 				void setVideoTextures(Texture* ytexture, Texture* cbtexture, Texture* crtexture) override {}
 
 
 			private:
 			private:
+				struct Vec4 {
+					float x, y, z, w;
+				};
+				
+				struct LoveUniformsPerDraw {
+					Vec4 uniformsPerDraw[13];
+				};
+
 				std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
 				std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
+
+				std::map<std::string, int> vertexAttributeIndices = {
+					{ "VertexPosition", 0 },
+					{ "VertexTexCoord", 1 },
+					{ "VertexColor", 2 }
+				};
+
+				std::map<std::string, int> uniformBindings = {
+					{ "love_UniformsPerDraw", 0 },
+					{ "love_VideoYChannel", 1 },
+					{ "love_VideoCbChannel", 2 },
+					{ "love_VideoCrChannel", 3 },
+					{ "MainTex", 4 }
+				};
 			};
 			};
 		}
 		}
 	}
 	}

+ 53 - 2
src/modules/graphics/vulkan/ShaderStage.cpp

@@ -9,12 +9,63 @@
 namespace love {
 namespace love {
 	namespace graphics {
 	namespace graphics {
 		namespace vulkan {
 		namespace vulkan {
+			static int someIndex = 0;
+
+			static std::string getFileEnding(ShaderStageType type) {
+				switch (type) {
+				case SHADERSTAGE_VERTEX:
+					return ".vert";
+				case SHADERSTAGE_PIXEL:
+					return ".frag";
+				default:
+					throw love::Exception("unsupported shader stage type");
+				}
+			}
+
+			static std::vector<char> readFile(const std::string& filename) {
+				std::ifstream file(filename, std::ios::ate | std::ios::binary);
+
+				if (!file.is_open()) {
+					throw std::runtime_error("failed to open file!");
+				}
+
+				size_t fileSize = (size_t)file.tellg();
+				std::vector<char> buffer(fileSize);
+
+				file.seekg(0);
+				file.read(buffer.data(), fileSize);
+
+				file.close();
+
+				return buffer;
+			}
+
+			static int shaderSourceId = 0;
+
+			std::vector<char> compileShader(const std::string& glsl, ShaderStageType stage) {
+				// fixme: use glslang or shaderc for this
+
+				std::string inputFileName = std::string("temp") + std::to_string(shaderSourceId++) + getFileEnding(stage);
+				std::string outputFileName = std::string("temp.spv");
+
+				std::ofstream out(inputFileName);
+				out << glsl;
+				out.close();
+
+				std::string command = std::string("glslc -fauto-bind-uniforms ") + inputFileName + " -o " + outputFileName;
+				system(command.c_str());
+
+				return readFile(outputFileName);
+			}
+
 			ShaderStage::ShaderStage(love::graphics::Graphics* gfx, ShaderStageType stage, const std::string& glsl, bool gles, const std::string& cachekey)
 			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) {
 				: love::graphics::ShaderStage(gfx, stage, glsl, gles, cachekey) {
+				auto code = compileShader(glsl, stage);
+
 				VkShaderModuleCreateInfo createInfo{};
 				VkShaderModuleCreateInfo createInfo{};
 				createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
 				createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
-				createInfo.codeSize = 0;
-				createInfo.pCode = nullptr;
+				createInfo.codeSize = code.size();
+				createInfo.pCode = reinterpret_cast<uint32_t*>(code.data());
 
 
 				Graphics* vkGfx = (Graphics*)gfx;
 				Graphics* vkGfx = (Graphics*)gfx;
 				device = vkGfx->getDevice();
 				device = vkGfx->getDevice();