Commit 1cd43f7f authored by Laszlo Agocs's avatar Laszlo Agocs
Browse files

Add the option of running fxc from qsb

...and so using pre-compiled byecode transparently to the applications.
parent 7ae3d0d1
qsb --glsl "100 es,120" --hlsl 50 --msl 12 color.vert -o color.vert.qsb qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c color.vert -o color.vert.qsb
qsb --glsl "100 es,120" --hlsl 50 --msl 12 color.frag -o color.frag.qsb qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c color.frag -o color.frag.qsb
qsb --glsl "100 es,120" --hlsl 50 --msl 12 texture.vert -o texture.vert.qsb qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c texture.vert -o texture.vert.qsb
qsb --glsl "100 es,120" --hlsl 50 --msl 12 texture.frag -o texture.frag.qsb qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c texture.frag -o texture.frag.qsb
...@@ -1600,6 +1600,10 @@ static inline D3D11_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op) ...@@ -1600,6 +1600,10 @@ static inline D3D11_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
static QByteArray compileHlslShaderSource(const QBakedShader &shader, QString *error) static QByteArray compileHlslShaderSource(const QBakedShader &shader, QString *error)
{ {
QBakedShader::Shader dxbc = shader.shader({ QBakedShader::DxbcShader, 50 });
if (!dxbc.shader.isEmpty())
return dxbc.shader;
QBakedShader::Shader hlslSource = shader.shader({ QBakedShader::HlslShader, 50 }); QBakedShader::Shader hlslSource = shader.shader({ QBakedShader::HlslShader, 50 });
if (hlslSource.shader.isEmpty()) { if (hlslSource.shader.isEmpty()) {
qWarning() << "No HLSL (shader model 5.0) code found in baked shader" << shader; qWarning() << "No HLSL (shader model 5.0) code found in baked shader" << shader;
......
...@@ -128,6 +128,16 @@ void QBakedShader::setShader(const ShaderKey &key, const Shader &shader) ...@@ -128,6 +128,16 @@ void QBakedShader::setShader(const ShaderKey &key, const Shader &shader)
d->shaders[key] = shader; d->shaders[key] = shader;
} }
void QBakedShader::removeShader(const ShaderKey &key)
{
auto it = d->shaders.find(key);
if (it == d->shaders.end())
return;
detach();
d->shaders.erase(it);
}
QByteArray QBakedShader::serialized() const QByteArray QBakedShader::serialized() const
{ {
QBuffer buf; QBuffer buf;
......
...@@ -127,6 +127,7 @@ public: ...@@ -127,6 +127,7 @@ public:
QList<ShaderKey> availableShaders() const; QList<ShaderKey> availableShaders() const;
Shader shader(const ShaderKey &key) const; Shader shader(const ShaderKey &key) const;
void setShader(const ShaderKey &key, const Shader &shader); void setShader(const ShaderKey &key, const Shader &shader);
void removeShader(const ShaderKey &key);
QByteArray serialized() const; QByteArray serialized() const;
static QBakedShader fromSerialized(const QByteArray &data); static QBakedShader fromSerialized(const QByteArray &data);
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include <QtCore/qcommandlineparser.h> #include <QtCore/qcommandlineparser.h>
#include <QtCore/qtextstream.h> #include <QtCore/qtextstream.h>
#include <QtCore/qfile.h> #include <QtCore/qfile.h>
#include <QtCore/qdir.h>
#include <QtCore/qprocess.h>
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
#include <QtShaderTools/qshaderbaker.h> #include <QtShaderTools/qshaderbaker.h>
...@@ -60,6 +62,31 @@ static QByteArray readFile(const QString &filename, bool text = false) ...@@ -60,6 +62,31 @@ static QByteArray readFile(const QString &filename, bool text = false)
return f.readAll(); return f.readAll();
} }
static bool runProcess(const QString &cmd, QByteArray *output, QByteArray *errorOutput)
{
QProcess p;
p.start(cmd);
if (!p.waitForFinished()) {
qWarning("%s failed to finish");
return false;
}
if (p.exitStatus() == QProcess::CrashExit) {
qWarning("%s crashed", qPrintable(cmd));
return false;
}
*output = p.readAllStandardOutput();
*errorOutput = p.readAllStandardError();
if (p.exitCode() != 0) {
qWarning("%s returned non-zero error code %d", qPrintable(cmd), p.exitCode());
return false;
}
return true;
}
static QString stageStr(QBakedShader::ShaderStage stage) static QString stageStr(QBakedShader::ShaderStage stage)
{ {
switch (stage) { switch (stage) {
...@@ -158,6 +185,42 @@ static void dump(const QBakedShader &bs) ...@@ -158,6 +185,42 @@ static void dump(const QBakedShader &bs)
} }
} }
static QByteArray fxcProfile(const QBakedShader &bs, const QBakedShader::ShaderKey &k)
{
QByteArray t;
switch (bs.stage()) {
case QBakedShader::VertexStage:
t += QByteArrayLiteral("vs_");
break;
case QBakedShader::TessControlStage:
t += QByteArrayLiteral("hs_");
break;
case QBakedShader::TessEvaluationStage:
t += QByteArrayLiteral("ds_");
break;
case QBakedShader::GeometryStage:
t += QByteArrayLiteral("gs_");
break;
case QBakedShader::FragmentStage:
t += QByteArrayLiteral("ps_");
break;
case QBakedShader::ComputeStage:
t += QByteArrayLiteral("cs_");
break;
default:
break;
}
const int major = k.sourceVersion.version / 10;
const int minor = k.sourceVersion.version % 10;
t += QByteArray::number(major);
t += '_';
t += QByteArray::number(minor);
return t;
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
QCoreApplication app(argc, argv); QCoreApplication app(argc, argv);
...@@ -184,6 +247,8 @@ int main(int argc, char **argv) ...@@ -184,6 +247,8 @@ int main(int argc, char **argv)
QObject::tr("Output file for the baked shader pack."), QObject::tr("Output file for the baked shader pack."),
QObject::tr("output")); QObject::tr("output"));
cmdLineParser.addOption(outputOption); cmdLineParser.addOption(outputOption);
QCommandLineOption fxcOption({ "c", "fxc" }, QObject::tr("In combination with --hlsl invokes fxc to store DXBC instead of HLSL."));
cmdLineParser.addOption(fxcOption);
QCommandLineOption dumpOption({ "d", "dump" }, QObject::tr("Switches to dump mode. Input file is expected to be a baked shader pack.")); QCommandLineOption dumpOption({ "d", "dump" }, QObject::tr("Switches to dump mode. Input file is expected to be a baked shader pack."));
cmdLineParser.addOption(dumpOption); cmdLineParser.addOption(dumpOption);
...@@ -214,10 +279,13 @@ int main(int argc, char **argv) ...@@ -214,10 +279,13 @@ int main(int argc, char **argv)
variants << QBakedShader::NormalShader; variants << QBakedShader::NormalShader;
if (cmdLineParser.isSet(batchableOption)) if (cmdLineParser.isSet(batchableOption))
variants << QBakedShader::BatchableVertexShader; variants << QBakedShader::BatchableVertexShader;
baker.setGeneratedShaderVariants(variants); baker.setGeneratedShaderVariants(variants);
QVector<QShaderBaker::GeneratedShader> genShaders; QVector<QShaderBaker::GeneratedShader> genShaders;
genShaders << qMakePair(QBakedShader::SpirvShader, QBakedShader::ShaderSourceVersion(100)); genShaders << qMakePair(QBakedShader::SpirvShader, QBakedShader::ShaderSourceVersion(100));
if (cmdLineParser.isSet(glslOption)) { if (cmdLineParser.isSet(glslOption)) {
const QStringList versions = cmdLineParser.value(glslOption).trimmed().split(','); const QStringList versions = cmdLineParser.value(glslOption).trimmed().split(',');
for (QString version : versions) { for (QString version : versions) {
...@@ -237,6 +305,7 @@ int main(int argc, char **argv) ...@@ -237,6 +305,7 @@ int main(int argc, char **argv)
qWarning("Ignoring invalid GLSL version %s", qPrintable(version)); qWarning("Ignoring invalid GLSL version %s", qPrintable(version));
} }
} }
if (cmdLineParser.isSet(hlslOption)) { if (cmdLineParser.isSet(hlslOption)) {
const QStringList versions = cmdLineParser.value(hlslOption).trimmed().split(','); const QStringList versions = cmdLineParser.value(hlslOption).trimmed().split(',');
for (QString version : versions) { for (QString version : versions) {
...@@ -248,6 +317,7 @@ int main(int argc, char **argv) ...@@ -248,6 +317,7 @@ int main(int argc, char **argv)
qWarning("Ignoring invalid HLSL (Shader Model) version %s", qPrintable(version)); qWarning("Ignoring invalid HLSL (Shader Model) version %s", qPrintable(version));
} }
} }
if (cmdLineParser.isSet(mslOption)) { if (cmdLineParser.isSet(mslOption)) {
const QStringList versions = cmdLineParser.value(mslOption).trimmed().split(','); const QStringList versions = cmdLineParser.value(mslOption).trimmed().split(',');
for (QString version : versions) { for (QString version : versions) {
...@@ -259,6 +329,7 @@ int main(int argc, char **argv) ...@@ -259,6 +329,7 @@ int main(int argc, char **argv)
qWarning("Ignoring invalid MSL version %s", qPrintable(version)); qWarning("Ignoring invalid MSL version %s", qPrintable(version));
} }
} }
baker.setGeneratedShaders(genShaders); baker.setGeneratedShaders(genShaders);
QBakedShader bs = baker.bake(); QBakedShader bs = baker.bake();
...@@ -267,6 +338,57 @@ int main(int argc, char **argv) ...@@ -267,6 +338,57 @@ int main(int argc, char **argv)
return 1; return 1;
} }
if (cmdLineParser.isSet(fxcOption)) {
auto skeys = bs.availableShaders();
for (QBakedShader::ShaderKey &k : skeys) {
if (k.source == QBakedShader::HlslShader) {
QBakedShader::Shader s = bs.shader(k);
// fxc refuses to read files created with QTemporaryFile, no idea why, life is too short
const QString tmpOut = QLatin1String("qsb_hlsl_temp_out");
QFile f(QLatin1String("qsb_hlsl_temp"));
if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning("Failed to create temporary file");
return 1;
}
f.write(s.shader);
f.close();
const QByteArray tempOutFileName = QDir::toNativeSeparators(tmpOut).toUtf8();
const QByteArray inFileName = QDir::toNativeSeparators(f.fileName()).toUtf8();
const QByteArray typeArg = fxcProfile(bs, k);
const QString cmd = QString::asprintf("fxc /nologo /E %s /T %s /Fo %s %s",
s.entryPoint.constData(),
typeArg.constData(),
tempOutFileName.constData(),
inFileName.constData());
QByteArray output;
QByteArray errorOutput;
bool success = runProcess(cmd, &output, &errorOutput);
if (!success) {
qDebug("%s\n%s",
qPrintable(output.constData()),
qPrintable(errorOutput.constData()));
return 1;
}
f.remove();
f.setFileName(tmpOut);
if (!f.open(QIODevice::ReadOnly)) {
qWarning("Failed to open fxc output %s", qPrintable(tmpOut));
return 1;
}
const QByteArray bytecode = f.readAll();
f.close();
f.remove();
QBakedShader::ShaderKey dxbcKey = k;
dxbcKey.source = QBakedShader::DxbcShader;
QBakedShader::Shader dxbcShader(bytecode, s.entryPoint);
bs.setShader(dxbcKey, dxbcShader);
bs.removeShader(k);
}
}
}
if (cmdLineParser.isSet(outputOption)) if (cmdLineParser.isSet(outputOption))
writeToFile(bs.serialized(), cmdLineParser.value(outputOption)); writeToFile(bs.serialized(), cmdLineParser.value(outputOption));
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment