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

Fixes #1581.
This commit is contained in:
Sasha Szpakowski
2023-02-04 10:25:13 -04:00
parent defe811f62
commit e13b0078a2
+123 -18
View File
@@ -22,6 +22,7 @@
#include "Shader.h"
#include "Graphics.h"
#include "math/MathModule.h"
#include "common/Range.h"
// glslang
#include "libraries/glslang/glslang/Public/ShaderLang.h"
@@ -425,6 +426,111 @@ static const Version versions[] =
{ "#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)
{
std::regex r("^\\s*#pragma language (\\w+)");
@@ -435,33 +541,30 @@ static Shader::Language getTargetLanguage(const std::string &src)
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;
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_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;
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;
if (std::regex_search(src, m, std::regex("vec4\\s+effect\\s*\\(")))
if (regexSearch(src, "vec4\\s+effect\\s*\\(", comments))
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;
return Shader::ENTRYPOINT_CUSTOM;
}
@@ -469,10 +572,9 @@ static Shader::EntryPoint getPixelEntryPoint(const std::string &src, bool &mrt)
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_NONE;
@@ -489,11 +591,14 @@ Shader *Shader::standardShaders[Shader::STANDARD_MAX_ENUM] = {nullptr};
Shader::SourceInfo Shader::getSourceInfo(const std::string &src)
{
std::vector<Range> comments;
glsl::parseComments(src, comments);
SourceInfo info = {};
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])
info.language = LANGUAGE_GLSL4;
return info;