Browse Source

shaders: ignore code in comments when parsing entry point functions.

Fixes #1581.
Sasha Szpakowski 2 years ago
parent
commit
e13b0078a2
1 changed files with 123 additions and 18 deletions
  1. 123 18
      src/modules/graphics/Shader.cpp

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

@@ -22,6 +22,7 @@
 #include "Shader.h"
 #include "Shader.h"
 #include "Graphics.h"
 #include "Graphics.h"
 #include "math/MathModule.h"
 #include "math/MathModule.h"
+#include "common/Range.h"
 
 
 // glslang
 // glslang
 #include "libraries/glslang/glslang/Public/ShaderLang.h"
 #include "libraries/glslang/glslang/Public/ShaderLang.h"
@@ -425,6 +426,111 @@ static const Version versions[] =
 	{ "#version 430 core", "#version 320 es" },
 	{ "#version 430 core", "#version 320 es" },
 };
 };
 
 
+enum CommentType
+{
+	COMMENT_NONE,
+	COMMENT_LINE,
+	COMMENT_BLOCK,
+};
+
+static void parseComments(const std::string &src, std::vector<Range> &comments)
+{
+	CommentType commenttype = COMMENT_NONE;
+	Range comment;
+
+	const char *srcbytes = src.data();
+	size_t len = src.length();
+
+	for (size_t i = 0; i < len; i++)
+	{
+		char curchar = srcbytes[i];
+
+		if (commenttype == COMMENT_NONE)
+		{
+			if (curchar == '/' && i + 1 < len)
+			{
+				char nextchar = srcbytes[i + 1];
+				if (nextchar == '/')
+				{
+					commenttype = COMMENT_LINE;
+					comment = Range(i, 1);
+				}
+				else if (nextchar == '*')
+				{
+					commenttype = COMMENT_BLOCK;
+					comment = Range(i, 1);
+				}
+			}
+		}
+		else if (commenttype == COMMENT_LINE)
+		{
+			if (curchar == '\n')
+			{
+				commenttype = COMMENT_NONE;
+				comment.last = i;
+				comments.push_back(comment);
+			}
+		}
+		else if (commenttype == COMMENT_BLOCK)
+		{
+			if (curchar == '/' && i > 0 && srcbytes[i - 1] == '*')
+			{
+				commenttype = COMMENT_NONE;
+				comment.last = i;
+				comments.push_back(comment);
+			}
+		}
+	}
+
+	if (commenttype == COMMENT_LINE)
+	{
+		comment.last = len - 1;
+		comments.push_back(comment);
+	}
+}
+
+static bool inComment(size_t i, const std::vector<Range> &comments)
+{
+	Range r(i, 1);
+
+	for (const Range &comment : comments)
+	{
+		if (comment.contains(r))
+			return true;
+	}
+
+	return false;
+}
+
+static bool textSearch(const std::string &src, const std::string &str, const std::vector<Range> &comments)
+{
+	size_t start = 0;
+	size_t found = std::string::npos;
+
+	while ((found = src.find(str, start)) != std::string::npos)
+	{
+		if (!inComment(found, comments))
+			return true;
+		start = found + str.size();
+	}
+
+	return false;
+}
+
+static bool regexSearch(const std::string &src, const std::string &rstr, const std::vector<Range> &comments)
+{
+	std::regex r(rstr);
+
+	for (auto it = std::sregex_iterator(src.begin(), src.end(), r); it != std::sregex_iterator(); it++)
+	{
+		const std::smatch &m = *it;
+		if (!inComment(m.position(), comments))
+			return true;
+	}
+
+	return false;
+}
+
 static Shader::Language getTargetLanguage(const std::string &src)
 static Shader::Language getTargetLanguage(const std::string &src)
 {
 {
 	std::regex r("^\\s*#pragma language (\\w+)");
 	std::regex r("^\\s*#pragma language (\\w+)");
@@ -435,33 +541,30 @@ static Shader::Language getTargetLanguage(const std::string &src)
 	return lang;
 	return lang;
 }
 }
 
 
-static Shader::EntryPoint getVertexEntryPoint(const std::string &src)
+static Shader::EntryPoint getVertexEntryPoint(const std::string &src, const std::vector<Range> &comments)
 {
 {
-	std::smatch m;
-
-	if (std::regex_search(src, m, std::regex("void\\s+vertexmain\\s*\\(")))
+	if (regexSearch(src, "void\\s+vertexmain\\s*\\(", comments))
 		return Shader::ENTRYPOINT_RAW;
 		return Shader::ENTRYPOINT_RAW;
 
 
-	if (std::regex_search(src, m, std::regex("vec4\\s+position\\s*\\(")))
+	if (regexSearch(src, "vec4\\s+position\\s*\\(", comments))
 		return Shader::ENTRYPOINT_HIGHLEVEL;
 		return Shader::ENTRYPOINT_HIGHLEVEL;
 
 
 	return Shader::ENTRYPOINT_NONE;
 	return Shader::ENTRYPOINT_NONE;
 }
 }
 
 
-static Shader::EntryPoint getPixelEntryPoint(const std::string &src, bool &mrt)
+static Shader::EntryPoint getPixelEntryPoint(const std::string &src, const std::vector<Range> &comments, bool &mrt)
 {
 {
 	mrt = false;
 	mrt = false;
-	std::smatch m;
 
 
-	if (std::regex_search(src, m, std::regex("void\\s+pixelmain\\s*\\(")))
+	if (regexSearch(src, "void\\s+pixelmain\\s*\\(", comments))
 		return Shader::ENTRYPOINT_RAW;
 		return Shader::ENTRYPOINT_RAW;
 
 
-	if (std::regex_search(src, m, std::regex("vec4\\s+effect\\s*\\(")))
+	if (regexSearch(src, "vec4\\s+effect\\s*\\(", comments))
 		return Shader::ENTRYPOINT_HIGHLEVEL;
 		return Shader::ENTRYPOINT_HIGHLEVEL;
 
 
-	if (std::regex_search(src, m, std::regex("void\\s+effect\\s*\\(")))
+	if (regexSearch(src, "void\\s+effect\\s*\\(", comments))
 	{
 	{
-		if (src.find("love_RenderTargets") != std::string::npos || src.find("love_Canvases") != std::string::npos)
+		if (textSearch(src, "love_RenderTargets", comments) || textSearch(src, "love_Canvases", comments))
 			mrt = true;
 			mrt = true;
 		return Shader::ENTRYPOINT_CUSTOM;
 		return Shader::ENTRYPOINT_CUSTOM;
 	}
 	}
@@ -469,10 +572,9 @@ static Shader::EntryPoint getPixelEntryPoint(const std::string &src, bool &mrt)
 	return Shader::ENTRYPOINT_NONE;
 	return Shader::ENTRYPOINT_NONE;
 }
 }
 
 
-static Shader::EntryPoint getComputeEntryPoint(const std::string &src) {
-	std::smatch m;
-
-	if (std::regex_search(src, m, std::regex("void\\s+computemain\\s*\\(")))
+static Shader::EntryPoint getComputeEntryPoint(const std::string &src, const std::vector<Range> &comments)
+{
+	if (regexSearch(src, "void\\s+computemain\\s*\\(", comments))
 		return Shader::ENTRYPOINT_RAW;
 		return Shader::ENTRYPOINT_RAW;
 
 
 	return Shader::ENTRYPOINT_NONE;
 	return Shader::ENTRYPOINT_NONE;
@@ -489,11 +591,14 @@ Shader *Shader::standardShaders[Shader::STANDARD_MAX_ENUM] = {nullptr};
 
 
 Shader::SourceInfo Shader::getSourceInfo(const std::string &src)
 Shader::SourceInfo Shader::getSourceInfo(const std::string &src)
 {
 {
+	std::vector<Range> comments;
+	glsl::parseComments(src, comments);
+
 	SourceInfo info = {};
 	SourceInfo info = {};
 	info.language = glsl::getTargetLanguage(src);
 	info.language = glsl::getTargetLanguage(src);
-	info.stages[SHADERSTAGE_VERTEX] = glsl::getVertexEntryPoint(src);
-	info.stages[SHADERSTAGE_PIXEL] = glsl::getPixelEntryPoint(src, info.usesMRT);
-	info.stages[SHADERSTAGE_COMPUTE] = glsl::getComputeEntryPoint(src);
+	info.stages[SHADERSTAGE_VERTEX] = glsl::getVertexEntryPoint(src, comments);
+	info.stages[SHADERSTAGE_PIXEL] = glsl::getPixelEntryPoint(src, comments, info.usesMRT);
+	info.stages[SHADERSTAGE_COMPUTE] = glsl::getComputeEntryPoint(src, comments);
 	if (info.stages[SHADERSTAGE_COMPUTE])
 	if (info.stages[SHADERSTAGE_COMPUTE])
 		info.language = LANGUAGE_GLSL4;
 		info.language = LANGUAGE_GLSL4;
 	return info;
 	return info;