bgfx/tools/shaderc/shaderc_glsl.cpp

308 lines
7.8 KiB
C++
Raw Normal View History

/*
2017-01-01 11:18:41 +03:00
* Copyright 2011-2017 Branimir Karadzic. All rights reserved.
2016-01-01 11:11:04 +03:00
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
*/
#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
{
2016-10-01 04:16:04 +03:00
static bool compile(bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer)
{
2016-05-09 00:50:04 +03:00
char ch = char(tolower(_cmdLine.findOption('\0', "type")[0]) );
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;
2016-10-01 04:16:04 +03:00
switch (_version)
{
2016-01-31 08:13:41 +03:00
case BX_MAKEFOURCC('M', 'T', 'L', 0):
target = kGlslTargetMetal;
break;
2016-01-31 08:13:41 +03:00
case 2:
target = kGlslTargetOpenGLES20;
break;
2016-01-31 08:13:41 +03:00
case 3:
target = kGlslTargetOpenGLES30;
break;
2016-01-31 08:13:41 +03:00
default:
target = kGlslTargetOpenGL;
break;
}
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);
2016-01-31 08:13:41 +03:00
fprintf(stderr, "Error: %s\n", log);
glslopt_cleanup(ctx);
return false;
}
2016-01-31 08:13:41 +03:00
const char* optimizedShader = glslopt_get_output(shader);
2016-01-31 08:13:41 +03:00
// Trim all directives.
while ('#' == *optimizedShader)
{
optimizedShader = bx::strnl(optimizedShader);
}
2016-01-31 08:13:41 +03:00
{
char* code = const_cast<char*>(optimizedShader);
strReplace(code, "gl_FragDepthEXT", "gl_FragDepth");
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
{
const char* parse = optimizedShader;
2016-01-31 08:13:41 +03:00
while (NULL != parse
&& *parse != '\0')
{
parse = bx::strws(parse);
2017-04-04 03:53:14 +03:00
const char* eol = bx::strnchr(parse, ';');
2016-01-31 08:13:41 +03:00
if (NULL != eol)
{
2016-01-31 08:13:41 +03:00
const char* qualifier = parse;
parse = bx::strws(bx::strword(parse) );
2017-04-04 03:53:14 +03:00
if (0 == bx::strncmp(qualifier, "attribute", 9)
|| 0 == bx::strncmp(qualifier, "varying", 7)
|| 0 == bx::strncmp(qualifier, "in", 2)
|| 0 == bx::strncmp(qualifier, "out", 3)
)
2016-01-31 08:13:41 +03:00
{
// skip attributes and varyings.
parse = eol + 1;
continue;
}
2017-04-04 03:53:14 +03:00
if (0 != bx::strncmp(qualifier, "uniform", 7) )
2016-01-31 08:13:41 +03:00
{
// end if there is no uniform keyword.
parse = NULL;
continue;
}
const char* precision = NULL;
const char* typen = parse;
2017-04-04 03:53:14 +03:00
if (0 == bx::strncmp(typen, "lowp", 4)
|| 0 == bx::strncmp(typen, "mediump", 7)
|| 0 == bx::strncmp(typen, "highp", 5) )
2016-01-31 08:13:41 +03:00
{
precision = typen;
typen = parse = bx::strws(bx::strword(parse) );
}
BX_UNUSED(precision);
char uniformType[256];
parse = bx::strword(parse);
2017-04-04 06:43:57 +03:00
if (0 == bx::strncmp(typen, "sampler", 7) )
2016-01-31 08:13:41 +03:00
{
2017-04-04 03:53:14 +03:00
bx::strlncpy(uniformType, BX_COUNTOF(uniformType), "int");
2016-01-31 08:13:41 +03:00
}
else
{
2017-04-04 03:53:14 +03:00
bx::strlcpy(uniformType, typen, int32_t(parse-typen+1) );
2016-01-31 08:13:41 +03:00
}
const char* name = parse = bx::strws(parse);
char uniformName[256];
uint8_t num = 1;
2017-04-04 03:53:14 +03:00
const char* array = bx::strnstr(name, "[", int32_t(eol-parse) );
if (NULL != array)
{
2017-04-04 03:53:14 +03:00
bx::strlcpy(uniformName, name, int32_t(array-name+1) );
char arraySize[32];
2017-04-04 03:53:14 +03:00
const char* end = bx::strnstr(array, "]", int32_t(eol-array) );
bx::strlcpy(arraySize, array+1, int32_t(end-array) );
num = uint8_t(atoi(arraySize) );
}
else
{
2017-04-04 03:53:14 +03:00
bx::strlcpy(uniformName, name, int32_t(eol-name+1) );
}
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);
}
parse = eol + 1;
}
}
}
else
{
2017-04-04 03:53:14 +03:00
const char* parse = bx::strnstr(optimizedShader, "struct xlatMtlShaderUniform {");
const char* end = parse;
if (NULL != parse)
{
2017-04-04 03:53:14 +03:00
parse += bx::strnlen("struct xlatMtlShaderUniform {");
end = bx::strnstr(parse, "};");
}
while ( parse < end
&& *parse != '\0')
{
parse = bx::strws(parse);
2017-04-04 03:53:14 +03:00
const char* eol = bx::strnchr(parse, ';');
if (NULL != eol)
{
const char* typen = parse;
char uniformType[256];
parse = bx::strword(parse);
2017-04-04 03:53:14 +03:00
bx::strlcpy(uniformType, typen, int32_t(parse-typen+1) );
const char* name = parse = bx::strws(parse);
char uniformName[256];
uint8_t num = 1;
2017-04-04 03:53:14 +03:00
const char* array = bx::strnstr(name, "[", int32_t(eol-parse) );
2016-01-31 08:13:41 +03:00
if (NULL != array)
{
2017-04-04 03:53:14 +03:00
bx::strlcpy(uniformName, name, int32_t(array-name+1) );
2016-01-31 08:13:41 +03:00
char arraySize[32];
2017-04-04 03:53:14 +03:00
const char* arrayEnd = bx::strnstr(array, "]", int32_t(eol-array) );
bx::strlcpy(arraySize, array+1, int32_t(arrayEnd-array) );
2016-05-09 00:50:04 +03:00
num = uint8_t(atoi(arraySize) );
2016-01-31 08:13:41 +03:00
}
else
{
2017-04-04 03:53:14 +03:00
bx::strlcpy(uniformName, name, int32_t(eol-name+1) );
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);
}
2016-01-31 08:13:41 +03:00
parse = eol + 1;
}
}
}
2016-01-31 08:13:41 +03:00
uint16_t count = (uint16_t)uniforms.size();
bx::write(_writer, count);
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(_writer, nameSize);
bx::write(_writer, un.name.c_str(), nameSize);
2017-03-12 01:44:00 +03:00
uint8_t uniformType = uint8_t(un.type);
2016-01-31 08:13:41 +03:00
bx::write(_writer, uniformType);
bx::write(_writer, un.num);
bx::write(_writer, un.regIndex);
bx::write(_writer, un.regCount);
BX_TRACE("%s, %s, %d, %d, %d"
, un.name.c_str()
, getUniformTypeName(un.type)
, un.num
, un.regIndex
, un.regCount
);
}
2016-01-31 08:13:41 +03:00
uint32_t shaderSize = (uint32_t)strlen(optimizedShader);
bx::write(_writer, shaderSize);
bx::write(_writer, optimizedShader, shaderSize);
uint8_t nul = 0;
bx::write(_writer, nul);
if (_cmdLine.hasArg('\0', "disasm") )
{
std::string disasmfp = _cmdLine.findOption('o');
disasmfp += ".disasm";
writeFile(disasmfp.c_str(), optimizedShader, shaderSize);
}
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(bx::CommandLine& _cmdLine, uint32_t _version, const std::string& _code, bx::WriterI* _writer)
{
return glsl::compile(_cmdLine, _version, _code, _writer);
}
2016-01-31 03:15:25 +03:00
} // namespace bgfx