Skip to content

Commit

Permalink
Added support for the #include directive
Browse files Browse the repository at this point in the history
  • Loading branch information
houmain committed Mar 29, 2021
1 parent 2e337d0 commit 711ea05
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 35 deletions.
4 changes: 2 additions & 2 deletions samples/Particles/Particles.gpjs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@
{
"fileName": "particle.comp",
"id": 76,
"shaderType": "Compute",
"shaderType": "Includable",
"type": "Shader"
},
{
Expand All @@ -144,7 +144,7 @@
{
"fileName": "particle.comp",
"id": 75,
"shaderType": "Compute",
"shaderType": "Includable",
"type": "Shader"
},
{
Expand Down
1 change: 0 additions & 1 deletion samples/Particles/particle.comp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#version 430

struct Particle {
vec2 position;
Expand Down
3 changes: 3 additions & 0 deletions samples/Particles/reset.comp
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#version 430

#include "particle.comp"

layout (local_size_x = 256, local_size_y = 1, local_size_z = 1) in;

Expand Down
3 changes: 3 additions & 0 deletions samples/Particles/update.comp
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#version 430

#include "particle.comp"

uniform vec2 attractor;

Expand Down
2 changes: 2 additions & 0 deletions src/MessageList.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ enum MessageType
InvalidSubroutine,
ImageFormatNotBindable,
UniformComponentMismatch,
InvalidIncludeDirective,
IncludableNotFound,
};

struct Message
Expand Down
6 changes: 6 additions & 0 deletions src/MessageWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ QIcon MessageWindow::getMessageIcon(const Message &message) const
case CallFailed:
case ClearingTextureFailed:
case CopyingTextureFailed:
case InvalidIncludeDirective:
case IncludableNotFound:
return mErrorIcon;

case UnformNotSet:
Expand Down Expand Up @@ -157,6 +159,10 @@ QString MessageWindow::getMessageText(const Message &message) const
return tr("Image format not bindable");
case UniformComponentMismatch:
return tr("Uniform component mismatch %1").arg(message.text);
case InvalidIncludeDirective:
return tr("Invalid #include directive");
case IncludableNotFound:
return tr("Includable shader '%1' not found").arg(message.text);
}
return message.text;
}
Expand Down
6 changes: 4 additions & 2 deletions src/render/GLProgram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ GLProgram::GLProgram(const Program &program)
shaders[shader->shaderType].append(shader);
}

const auto includables = shaders[Shader::ShaderType::Includable];
for (auto type : shaders.keys())
mShaders.emplace_back(type, shaders[type]);
if (type != Shader::ShaderType::Includable)
mShaders.emplace_back(type, shaders[type], includables);
}

bool GLProgram::operator==(const GLProgram &rhs) const
Expand Down Expand Up @@ -161,7 +163,7 @@ bool GLProgram::link()
gl40->glGetActiveSubroutineUniformiv(program, stage, i,
GL_COMPATIBLE_SUBROUTINES, subroutineIndices.data());

auto subroutines = QList<QString>();
auto subroutines = QStringList();
for (auto index : subroutineIndices) {
gl40->glGetActiveSubroutineName(program, stage,
static_cast<GLuint>(index),
Expand Down
2 changes: 1 addition & 1 deletion src/render/GLProgram.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class GLProgram
struct SubroutineUniform
{
QString name;
QList<QString> subroutines;
QStringList subroutines;
ItemId bindingItemId;
QString boundSubroutine;
};
Expand Down
104 changes: 80 additions & 24 deletions src/render/GLShader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,66 @@
#include <QRegularExpression>

namespace {
QString removeVersion(QString *source, bool removeNewline) {
void removeVersion(QString *source, QString *maxVersion, bool removeNewline)
{
const auto regex = QRegularExpression(
(removeNewline ? "(#version[^\n]*\n?)" : "(#version[^\n]*)"),
QRegularExpression::MultilineOption);
auto version = QString();
if (auto match = regex.match(*source); match.hasMatch()) {
version = match.captured();

for (auto match = regex.match(*source); match.hasMatch(); match = regex.match(*source)) {
*maxVersion = qMax(*maxVersion, match.captured().trimmed());
source->remove(match.capturedStart(), match.capturedLength());
}
return version.trimmed();
}

int countLines(const QString &source, int offset)
{
auto line = 1;
for (auto i = 0; i < qMin(source.size(), offset); ++i)
if (source[i] == '\n')
++line;
return line;
}

QString substituteIncludes(QString source, int fileNo, int sourceFileCount,
const QStringList &includableSources, const QStringList &includableFileNames,
ItemId itemId, MessagePtrSet &messages)
{
const auto regex = QRegularExpression(R"(#include([^\n]*))");
for (auto match = regex.match(source); match.hasMatch(); match = regex.match(source)) {
source.remove(match.capturedStart(), match.capturedLength());
auto fileName = match.captured(1).trimmed();
if ((fileName.startsWith('<') && fileName.endsWith('>')) ||
(fileName.startsWith('"') && fileName.endsWith('"'))) {
fileName = fileName.mid(1, fileName.size() - 2);

if (const auto index = includableFileNames.indexOf(fileName); index >= 0) {
const auto lineNo = countLines(source, match.capturedStart());

const auto includableSource = substituteIncludes(
includableSources[index], sourceFileCount + index, sourceFileCount,
includableSources, includableFileNames, itemId, messages);

source.insert(match.capturedStart(),
includableSource + QString("\n#line %1 %2\n").arg(lineNo).arg(fileNo));
}
else {
messages += MessageList::insert(itemId,
MessageType::IncludableNotFound, fileName);
}
}
else {
messages += MessageList::insert(itemId,
MessageType::InvalidIncludeDirective, fileName);
}
}
return QString("#line 1 %1\n").arg(fileNo) + source;
}
} // namespace

void GLShader::parseLog(const QString &log,
MessagePtrSet &messages, ItemId itemId,
QList<QString> fileNames)
QStringList fileNames)
{
// Mesa: 0:13(2): error: `gl_Positin' undeclared
// NVidia: 0(13) : error C1008: undefined variable "gl_Positin"
Expand Down Expand Up @@ -55,27 +99,33 @@ void GLShader::parseLog(const QString &log,
}

GLShader::GLShader(Shader::ShaderType type,
const QList<const Shader*> &shaders)
const QList<const Shader*> &shaders,
const QList<const Shader*> &includables)
{
Q_ASSERT(!shaders.isEmpty());
mType = type;

for (const Shader *shader : shaders) {
mItemId = shaders.front()->id;

const auto add = [&](const Shader& shader, bool isIncludable) {
auto source = QString();
if (!Singletons::fileCache().getSource(shader->fileName, &source))
mMessages += MessageList::insert(shader->id,
MessageType::LoadingFileFailed, shader->fileName);
if (!Singletons::fileCache().getSource(shader.fileName, &source))
mMessages += MessageList::insert(shader.id,
MessageType::LoadingFileFailed, shader.fileName);

mItemId = shader->id;
mFileNames += shader->fileName;
mSources += source + "\n";
}
mFileNames += shader.fileName;
(isIncludable ? mIncludableSources : mSources) += source + "\n";
};

for (const Shader *shader : shaders)
add(*shader, false);
for (const Shader *shader : includables)
add(*shader, true);
}

bool GLShader::operator==(const GLShader &rhs) const
{
return std::tie(mSources, mType) ==
std::tie(rhs.mSources, rhs.mType);
return std::tie(mType, mSources, mIncludableSources, mFileNames) ==
std::tie(rhs.mType, rhs.mSources, rhs.mIncludableSources, rhs.mFileNames);
}

QString GLShader::getSource() const
Expand Down Expand Up @@ -142,13 +192,19 @@ bool GLShader::compile(GLPrintf* printf, bool silent)
QStringList GLShader::getPatchedSources(GLPrintf *printf)
{
Q_ASSERT(!mSources.isEmpty());
auto sources = mSources;

auto includableFileNames = QStringList();
for (auto i = mSources.size(); i < mFileNames.size(); ++i)
includableFileNames += QFileInfo(mFileNames[i]).fileName();

auto sources = QStringList();
for (auto i = 0; i < mSources.size(); ++i)
sources += substituteIncludes(mSources[i], i, mSources.size(),
mIncludableSources, includableFileNames, mItemId, mMessages);

auto maxVersion = QString();
for (auto i = 0; i < sources.size(); ++i) {
maxVersion = std::max(maxVersion,
removeVersion(&sources[i], (i > 0)));
sources[i] = QString("#line 1 %1\n").arg(i) + sources[i];
}
for (auto i = 0; i < sources.size(); ++i)
removeVersion(&sources[i], &maxVersion, (i > 0));

if (printf) {
for (auto i = 0; i < sources.size(); ++i)
Expand Down
10 changes: 6 additions & 4 deletions src/render/GLShader.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ class GLShader
public:
static void parseLog(const QString &log,
MessagePtrSet &messages, ItemId itemId,
QList<QString> fileNames);
QStringList fileNames);

GLShader(Shader::ShaderType type,
const QList<const Shader*> &shaders);
const QList<const Shader*> &shaders,
const QList<const Shader*> &includables = { });
bool operator==(const GLShader &rhs) const;
Shader::ShaderType type() const { return mType; }

Expand All @@ -26,8 +27,9 @@ class GLShader

ItemId mItemId{ };
MessagePtrSet mMessages;
QList<QString> mFileNames;
QList<QString> mSources;
QStringList mFileNames;
QStringList mSources;
QStringList mIncludableSources;
Shader::ShaderType mType;
GLObject mShaderObject;
};
Expand Down
2 changes: 1 addition & 1 deletion src/session/AttachmentProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ void AttachmentProperties::updateWidgets()
// TODO: implement
setFormVisibility(mUi->formLayout, mUi->labelColorWriteMask, mUi->colorWriteMask, false && kind.color);

static const QList<QString> tabTitles = {
static const QStringList tabTitles = {
mUi->tabDepthStencil->tabText(0),
mUi->tabDepthStencil->tabText(1),
mUi->tabDepthStencil->tabText(2)
Expand Down
1 change: 1 addition & 0 deletions src/session/ItemEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ namespace ItemEnums {
TessellationControl = GL_TESS_CONTROL_SHADER,
TessellationEvaluation = GL_TESS_EVALUATION_SHADER,
Compute = GL_COMPUTE_SHADER,
Includable = 0,
};
Q_ENUM_NS(ShaderType)

Expand Down

0 comments on commit 711ea05

Please sign in to comment.