bgfx/tools/shaderc/shaderc_glsl.cpp

405 lines
11 KiB
C++
Raw Normal View History

/*
2024-01-14 12:56:36 +03:00
* Copyright 2011-2024 Branimir Karadzic. All rights reserved.
2022-01-15 22:59:06 +03:00
* License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
*/
#include "shaderc.h"
#include "glsl_optimizer.h"
2016-10-01 04:16:04 +03:00
namespace bgfx { namespace glsl
2016-01-31 03:15:25 +03:00
{
static bool compile(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _shaderWriter, bx::WriterI* _messageWriter)
{
bx::ErrorAssert messageErr;
2017-11-24 21:01:13 +03:00
char ch = _options.shaderType;
2016-01-31 08:13:41 +03:00
const glslopt_shader_type type = ch == 'f'
? kGlslOptShaderFragment
: (ch == 'c' ? kGlslOptShaderCompute : kGlslOptShaderVertex);
2016-01-31 08:13:41 +03:00
glslopt_target target = kGlslTargetOpenGL;
if(_version == BX_MAKEFOURCC('M', 'T', 'L', 0))
{
2016-01-31 08:13:41 +03:00
target = kGlslTargetMetal;
} else if(_version < 0x80000000) {
2016-01-31 08:13:41 +03:00
target = kGlslTargetOpenGL;
}
else {
_version &= ~0x80000000;
target = (_version >= 300) ? kGlslTargetOpenGLES30 : kGlslTargetOpenGLES20;
2016-01-31 08:13:41 +03:00
}
2016-01-31 08:13:41 +03:00
glslopt_ctx* ctx = glslopt_initialize(target);
2016-01-31 08:13:41 +03:00
glslopt_shader* shader = glslopt_optimize(ctx, type, _code.c_str(), 0);
2016-01-31 08:13:41 +03:00
if (!glslopt_get_status(shader) )
{
2016-01-31 08:13:41 +03:00
const char* log = glslopt_get_log(shader);
2016-10-01 22:38:41 +03:00
int32_t source = 0;
int32_t line = 0;
int32_t column = 0;
int32_t start = 0;
int32_t end = INT32_MAX;
2016-01-31 08:13:41 +03:00
2016-10-01 22:38:41 +03:00
bool found = false
|| 3 == sscanf(log, "%u:%u(%u):", &source, &line, &column)
2017-04-04 03:53:14 +03:00
|| 2 == sscanf(log, "(%u,%u):", &line, &column)
2016-10-01 22:38:41 +03:00
;
if (found
2016-01-31 08:13:41 +03:00
&& 0 != line)
{
2016-01-31 08:13:41 +03:00
start = bx::uint32_imax(1, line-10);
2016-10-01 22:38:41 +03:00
end = start + 20;
2016-01-31 08:13:41 +03:00
}
2016-10-01 22:38:41 +03:00
printCode(_code.c_str(), line, start, end, column);
bx::write(_messageWriter, &messageErr, "Error: %s\n", log);
glslopt_shader_delete(shader);
2016-01-31 08:13:41 +03:00
glslopt_cleanup(ctx);
return false;
}
2016-01-31 08:13:41 +03:00
const char* optimizedShader = glslopt_get_output(shader);
std::string out;
2016-01-31 08:13:41 +03:00
// Trim all directives.
while ('#' == *optimizedShader)
{
2018-10-21 09:33:31 +03:00
optimizedShader = bx::strFindNl(optimizedShader).getPtr();
2016-01-31 08:13:41 +03:00
}
out.append(optimizedShader, strlen(optimizedShader));
optimizedShader = out.c_str();
2016-01-31 08:13:41 +03:00
{
char* code = const_cast<char*>(optimizedShader);
strReplace(code, "gl_FragDepthEXT", "gl_FragDepth");
strReplace(code, "textureLodEXT", "texture2DLod");
strReplace(code, "textureGradEXT", "texture2DGrad");
2017-03-24 03:33:29 +03:00
strReplace(code, "texture2DLodARB", "texture2DLod");
2016-01-31 08:13:41 +03:00
strReplace(code, "texture2DLodEXT", "texture2DLod");
2017-03-24 03:33:29 +03:00
strReplace(code, "texture2DGradARB", "texture2DGrad");
2016-01-31 08:13:41 +03:00
strReplace(code, "texture2DGradEXT", "texture2DGrad");
2017-03-24 03:33:29 +03:00
strReplace(code, "textureCubeLodARB", "textureCubeLod");
strReplace(code, "textureCubeLodEXT", "textureCubeLod");
strReplace(code, "textureCubeGradARB", "textureCubeGrad");
2016-01-31 08:13:41 +03:00
strReplace(code, "textureCubeGradEXT", "textureCubeGrad");
2017-03-24 03:33:29 +03:00
strReplace(code, "texture2DProjLodARB", "texture2DProjLod");
strReplace(code, "texture2DProjLodEXT", "texture2DProjLod");
strReplace(code, "texture2DProjGradARB", "texture2DProjGrad");
strReplace(code, "texture2DProjGradEXT", "texture2DProjGrad");
strReplace(code, "shadow2DARB", "shadow2D");
2016-01-31 08:13:41 +03:00
strReplace(code, "shadow2DEXT", "shadow2D");
2017-03-24 03:33:29 +03:00
strReplace(code, "shadow2DProjARB", "shadow2DProj");
2016-01-31 08:13:41 +03:00
strReplace(code, "shadow2DProjEXT", "shadow2DProj");
}
2016-01-31 08:13:41 +03:00
UniformArray uniforms;
if (target != kGlslTargetMetal)
2016-01-31 08:13:41 +03:00
{
2018-10-26 08:16:10 +03:00
bx::StringView parse(optimizedShader);
2018-10-26 08:16:10 +03:00
while (!parse.isEmpty() )
2016-01-31 08:13:41 +03:00
{
2018-10-26 08:16:10 +03:00
parse = bx::strLTrimSpace(parse);
bx::StringView eol = bx::strFind(parse, ';');
2018-10-21 09:33:31 +03:00
if (!eol.isEmpty() )
{
2018-10-26 08:16:10 +03:00
bx::StringView qualifier = nextWord(parse);
2016-01-31 08:13:41 +03:00
if (0 == bx::strCmp(qualifier, "precision", 9) )
{
// skip precision
parse.set(eol.getPtr() + 1, parse.getTerm() );
continue;
}
2017-04-23 00:47:02 +03:00
if (0 == bx::strCmp(qualifier, "attribute", 9)
|| 0 == bx::strCmp(qualifier, "varying", 7)
|| 0 == bx::strCmp(qualifier, "in", 2)
|| 0 == bx::strCmp(qualifier, "out", 3)
2017-04-04 03:53:14 +03:00
)
2016-01-31 08:13:41 +03:00
{
// skip attributes and varyings.
2018-10-26 08:16:10 +03:00
parse.set(eol.getPtr() + 1, parse.getTerm() );
2016-01-31 08:13:41 +03:00
continue;
}
if (0 == bx::strCmp(qualifier, "flat", 4)
|| 0 == bx::strCmp(qualifier, "smooth", 6)
|| 0 == bx::strCmp(qualifier, "noperspective", 13)
|| 0 == bx::strCmp(qualifier, "centroid", 8)
)
{
// skip interpolation qualifiers
parse.set(eol.getPtr() + 1, parse.getTerm() );
continue;
}
2017-09-18 02:54:37 +03:00
if (0 == bx::strCmp(parse, "tmpvar", 6) )
{
// skip temporaries
2018-10-26 08:16:10 +03:00
parse.set(eol.getPtr() + 1, parse.getTerm() );
2017-09-18 02:54:37 +03:00
continue;
}
2017-04-23 00:47:02 +03:00
if (0 != bx::strCmp(qualifier, "uniform", 7) )
2016-01-31 08:13:41 +03:00
{
// end if there is no uniform keyword.
2018-10-26 08:16:10 +03:00
parse.clear();
2016-01-31 08:13:41 +03:00
continue;
}
2018-10-26 08:16:10 +03:00
bx::StringView precision;
bx::StringView typen = nextWord(parse);
2016-01-31 08:13:41 +03:00
2017-04-23 00:47:02 +03:00
if (0 == bx::strCmp(typen, "lowp", 4)
|| 0 == bx::strCmp(typen, "mediump", 7)
|| 0 == bx::strCmp(typen, "highp", 5) )
2016-01-31 08:13:41 +03:00
{
precision = typen;
2018-10-26 08:16:10 +03:00
typen = nextWord(parse);
2016-01-31 08:13:41 +03:00
}
BX_UNUSED(precision);
char uniformType[256];
if (0 == bx::strCmp(typen, "sampler", 7)
|| 0 == bx::strCmp(typen, "isampler", 8)
|| 0 == bx::strCmp(typen, "usampler", 8) )
2016-01-31 08:13:41 +03:00
{
2017-04-17 07:56:17 +03:00
bx::strCopy(uniformType, BX_COUNTOF(uniformType), "int");
2016-01-31 08:13:41 +03:00
}
else
{
2018-10-26 08:16:10 +03:00
bx::strCopy(uniformType, BX_COUNTOF(uniformType), typen);
2016-01-31 08:13:41 +03:00
}
2018-10-26 08:16:10 +03:00
bx::StringView name = nextWord(parse);
2016-01-31 08:13:41 +03:00
uint8_t num = 1;
2018-10-26 08:16:10 +03:00
bx::StringView array = bx::strSubstr(parse, 0, 1);
if (0 == bx::strCmp(array, "[", 1) )
{
2018-10-26 08:16:10 +03:00
parse = bx::strLTrimSpace(bx::StringView(parse.getPtr() + 1, parse.getTerm() ) );
2018-10-22 06:33:29 +03:00
uint32_t tmp;
2018-10-26 08:16:10 +03:00
bx::fromString(&tmp, parse);
2018-10-22 06:33:29 +03:00
num = uint8_t(tmp);
}
Uniform un;
un.type = nameToUniformTypeEnum(uniformType);
if (UniformType::Count != un.type)
{
2018-10-26 08:16:10 +03:00
un.name.assign(name.getPtr(), name.getTerm());
BX_TRACE("name: %s (type %d, num %d)", un.name.c_str(), un.type, num);
un.num = num;
un.regIndex = 0;
un.regCount = num;
switch (un.type)
{
case UniformType::Mat3:
un.regCount *= 3;
break;
case UniformType::Mat4:
un.regCount *= 4;
break;
default:
break;
}
uniforms.push_back(un);
}
2018-10-26 08:16:10 +03:00
parse = bx::strLTrimSpace(bx::strFindNl(bx::StringView(eol.getPtr(), parse.getTerm() ) ) );
}
}
}
else
{
2018-10-21 09:33:31 +03:00
const bx::StringView optShader(optimizedShader);
bx::StringView parse = bx::strFind(optimizedShader, "struct xlatMtlShaderUniform {");
bx::StringView end = parse;
if (!parse.isEmpty() )
{
2018-10-21 09:33:31 +03:00
parse.set(parse.getPtr() + bx::strLen("struct xlatMtlShaderUniform {"), optShader.getTerm() );
end = bx::strFind(parse, "};");
}
2018-10-21 09:33:31 +03:00
while ( parse.getPtr() < end.getPtr()
&& !parse.isEmpty() )
{
2018-10-21 09:33:31 +03:00
parse.set(bx::strLTrimSpace(parse).getPtr(), optShader.getTerm() );
const bx::StringView eol = bx::strFind(parse, ';');
if (!eol.isEmpty() )
{
2018-10-21 09:33:31 +03:00
const char* typen = parse.getPtr();
char uniformType[256];
parse = bx::strWord(parse);
bx::strCopy(uniformType, parse.getLength()+1, typen);
parse.set(parse.getPtr()+parse.getLength(),optShader.getTerm());
2018-10-21 09:33:31 +03:00
const char* name = bx::strLTrimSpace(parse).getPtr();
parse.set(name, optShader.getTerm() );
char uniformName[256];
uint8_t num = 1;
2018-10-21 09:33:31 +03:00
bx::StringView array = bx::strFind(bx::StringView(name, int32_t(eol.getPtr()-parse.getPtr() ) ), "[");
if (!array.isEmpty() )
2016-01-31 08:13:41 +03:00
{
2018-10-21 09:33:31 +03:00
bx::strCopy(uniformName, int32_t(array.getPtr()-name+1), name);
2016-01-31 08:13:41 +03:00
char arraySize[32];
2018-10-21 09:33:31 +03:00
bx::StringView arrayEnd = bx::strFind(bx::StringView(array.getPtr(), int32_t(eol.getPtr()-array.getPtr() ) ), "]");
bx::strCopy(arraySize, int32_t(arrayEnd.getPtr()-array.getPtr() ), array.getPtr()+1);
2018-10-22 06:33:29 +03:00
uint32_t tmp;
bx::fromString(&tmp, arraySize);
num = uint8_t(tmp);
2016-01-31 08:13:41 +03:00
}
else
{
2018-10-21 09:33:31 +03:00
bx::strCopy(uniformName, int32_t(eol.getPtr()-name+1), name);
2016-01-31 08:13:41 +03:00
}
Uniform un;
un.type = nameToUniformTypeEnum(uniformType);
if (UniformType::Count != un.type)
{
BX_TRACE("name: %s (type %d, num %d)", uniformName, un.type, num);
un.name = uniformName;
un.num = num;
un.regIndex = 0;
un.regCount = num;
uniforms.push_back(un);
}
2018-10-21 09:33:31 +03:00
parse = eol.getPtr() + 1;
}
}
bx::StringView mainEntry("xlatMtlShaderOutput xlatMtlMain (");
parse = bx::strFind(optimizedShader, mainEntry);
end = parse;
if (!parse.isEmpty())
{
parse.set(parse.getPtr() + mainEntry.getLength(), optShader.getTerm());
end = bx::strFind(parse, "{");
}
while (parse.getPtr() < end.getPtr()
&& !parse.isEmpty())
{
parse.set(bx::strLTrimSpace(parse).getPtr(), optShader.getTerm());
const bx::StringView textureNameMark("[[texture(");
const bx::StringView textureName = bx::strFind(parse, textureNameMark);
if (!textureName.isEmpty())
{
Uniform un;
un.type = nameToUniformTypeEnum("int"); // int for sampler
const char* varNameEnd = textureName.getPtr() - 1;
parse.set(parse.getPtr(), varNameEnd - 1);
const char* varNameBeg = parse.getPtr();
for (int ii = parse.getLength() - 1; 0 <= ii; --ii)
{
if (varNameBeg[ii] == ' ')
{
parse.set(varNameBeg + ii + 1, varNameEnd);
break;
}
}
char uniformName[256];
2020-07-15 20:42:23 +03:00
bx::strCopy(uniformName, parse.getLength() + 1, parse);
un.name = uniformName;
const char* regIndexBeg = textureName.getPtr() + textureNameMark.getLength();
bx::StringView regIndex = bx::strFind(regIndexBeg, ")");
regIndex.set(regIndexBeg, regIndex.getPtr());
uint32_t tmp;
bx::fromString(&tmp, regIndex);
un.regIndex = uint16_t(tmp);
un.num = 1;
un.regCount = 1;
uniforms.push_back(un);
parse = regIndex.getPtr() + 1;
}
else
{
parse = textureName;
}
}
}
2021-10-26 05:26:38 +03:00
bx::ErrorAssert err;
2016-01-31 08:13:41 +03:00
uint16_t count = (uint16_t)uniforms.size();
bx::write(_shaderWriter, count, &err);
2016-01-31 08:13:41 +03:00
for (UniformArray::const_iterator it = uniforms.begin(); it != uniforms.end(); ++it)
{
const Uniform& un = *it;
uint8_t nameSize = (uint8_t)un.name.size();
bx::write(_shaderWriter, nameSize, &err);
bx::write(_shaderWriter, un.name.c_str(), nameSize, &err);
2017-03-12 01:44:00 +03:00
uint8_t uniformType = uint8_t(un.type);
bx::write(_shaderWriter, uniformType, &err);
bx::write(_shaderWriter, un.num, &err);
bx::write(_shaderWriter, un.regIndex, &err);
bx::write(_shaderWriter, un.regCount, &err);
bx::write(_shaderWriter, un.texComponent, &err);
bx::write(_shaderWriter, un.texDimension, &err);
bx::write(_shaderWriter, un.texFormat, &err);
2016-01-31 08:13:41 +03:00
BX_TRACE("%s, %s, %d, %d, %d"
, un.name.c_str()
, getUniformTypeName(un.type)
, un.num
, un.regIndex
, un.regCount
);
}
2017-04-17 07:56:17 +03:00
uint32_t shaderSize = (uint32_t)bx::strLen(optimizedShader);
bx::write(_shaderWriter, shaderSize, &err);
bx::write(_shaderWriter, optimizedShader, shaderSize, &err);
2016-01-31 08:13:41 +03:00
uint8_t nul = 0;
bx::write(_shaderWriter, nul, &err);
2017-11-24 21:01:13 +03:00
if (_options.disasm )
{
2017-11-24 21:01:13 +03:00
std::string disasmfp = _options.outputFilePath + ".disasm";
writeFile(disasmfp.c_str(), optimizedShader, shaderSize);
}
glslopt_shader_delete(shader);
2016-01-31 08:13:41 +03:00
glslopt_cleanup(ctx);
2016-01-31 08:13:41 +03:00
return true;
}
2016-01-31 03:15:25 +03:00
2016-10-01 04:16:04 +03:00
} // namespace glsl
bool compileGLSLShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _shaderWriter, bx::WriterI* _messageWriter)
2016-10-01 04:16:04 +03:00
{
return glsl::compile(_options, _version, _code, _shaderWriter, _messageWriter);
2016-10-01 04:16:04 +03:00
}
2016-01-31 03:15:25 +03:00
} // namespace bgfx