diff options
Diffstat (limited to '3rdparty/bgfx/tools/shaderc/shaderc.cpp')
-rw-r--r-- | 3rdparty/bgfx/tools/shaderc/shaderc.cpp | 1937 |
1 files changed, 1066 insertions, 871 deletions
diff --git a/3rdparty/bgfx/tools/shaderc/shaderc.cpp b/3rdparty/bgfx/tools/shaderc/shaderc.cpp index 57934b5c632..f8d22df4fd1 100644 --- a/3rdparty/bgfx/tools/shaderc/shaderc.cpp +++ b/3rdparty/bgfx/tools/shaderc/shaderc.cpp @@ -5,6 +5,7 @@ #include "shaderc.h" #include <bx/commandline.h> +#include <bx/filepath.h> #define MAX_TAGS 256 extern "C" @@ -12,14 +13,17 @@ extern "C" #include <fpp.h> } // extern "C" +#define BGFX_CHUNK_MAGIC_CSH BX_MAKEFOURCC('C', 'S', 'H', 0x3) +#define BGFX_CHUNK_MAGIC_FSH BX_MAKEFOURCC('F', 'S', 'H', 0x5) +#define BGFX_CHUNK_MAGIC_VSH BX_MAKEFOURCC('V', 'S', 'H', 0x5) + +#define BGFX_SHADERC_VERSION_MAJOR 1 +#define BGFX_SHADERC_VERSION_MINOR 6 + namespace bgfx { bool g_verbose = false; - #define BGFX_CHUNK_MAGIC_CSH BX_MAKEFOURCC('C', 'S', 'H', 0x2) - #define BGFX_CHUNK_MAGIC_FSH BX_MAKEFOURCC('F', 'S', 'H', 0x4) - #define BGFX_CHUNK_MAGIC_VSH BX_MAKEFOURCC('V', 'S', 'H', 0x4) - static const char* s_ARB_shader_texture_lod[] = { "texture2DLod", @@ -78,6 +82,13 @@ namespace bgfx NULL }; + static const char* s_EXT_gpu_shader4[] = + { + "gl_VertexID", + "gl_InstanceID", + NULL + }; + static const char* s_ARB_gpu_shader5[] = { "bitfieldReverse", @@ -139,13 +150,84 @@ namespace bgfx }; BX_STATIC_ASSERT(BX_COUNTOF(s_uniformTypeName) == UniformType::Count*2); + + Options::Options() + : shaderType(' ') + , disasm(false) + , raw(false) + , preprocessOnly(false) + , depends(false) + , debugInformation(false) + , avoidFlowControl(false) + , noPreshader(false) + , partialPrecision(false) + , preferFlowControl(false) + , backwardsCompatibility(false) + , warningsAreErrors(false) + , optimize(false) + , optimizationLevel(3) + { + } + + void Options::dump() + { + BX_TRACE("Options:\n" + "\t shaderType: %c\n" + "\t platform: %s\n" + "\t profile: %s\n" + "\t inputFile: %s\n" + "\t outputFile: %s\n" + "\t disasm: %s\n" + "\t raw: %s\n" + "\t preprocessOnly: %s\n" + "\t depends: %s\n" + "\t debugInformation: %s\n" + "\t avoidFlowControl: %s\n" + "\t noPreshader: %s\n" + "\t partialPrecision: %s\n" + "\t preferFlowControl: %s\n" + "\t backwardsCompatibility: %s\n" + "\t warningsAreErrors: %s\n" + "\t optimize: %s\n" + "\t optimizationLevel: %d\n" + + , shaderType + , platform.c_str() + , profile.c_str() + , inputFilePath.c_str() + , outputFilePath.c_str() + , disasm ? "true" : "false" + , raw ? "true" : "false" + , preprocessOnly ? "true" : "false" + , depends ? "true" : "false" + , debugInformation ? "true" : "false" + , avoidFlowControl ? "true" : "false" + , noPreshader ? "true" : "false" + , partialPrecision ? "true" : "false" + , preferFlowControl ? "true" : "false" + , backwardsCompatibility ? "true" : "false" + , warningsAreErrors ? "true" : "false" + , optimize ? "true" : "false" + , optimizationLevel + ); + + for(size_t i=0; i<includeDirs.size(); ++i) + BX_TRACE("\t include :%s\n", includeDirs[i].c_str()); + + for(size_t i=0; i<defines.size(); ++i) + BX_TRACE("\t define :%s\n", defines[i].c_str()); + + for(size_t i=0; i<dependencies.size(); ++i) + BX_TRACE("\t dependency :%s\n", dependencies[i].c_str()); + } + const char* interpolationDx11(const char* _glsl) { - if (0 == strcmp(_glsl, "smooth") ) + if (0 == bx::strCmp(_glsl, "smooth") ) { return "linear"; } - else if (0 == strcmp(_glsl, "flat") ) + else if (0 == bx::strCmp(_glsl, "flat") ) { return "nointerpolation"; } @@ -169,7 +251,7 @@ namespace bgfx for (uint32_t ii = 0; ii < UniformType::Count*2; ++ii) { if (NULL != s_uniformTypeName[ii] - && 0 == strcmp(_name, s_uniformTypeName[ii]) ) + && 0 == bx::strCmp(_name, s_uniformTypeName[ii]) ) { return UniformType::Enum(ii/2); } @@ -201,7 +283,7 @@ namespace bgfx return len; } - class Bin2cWriter : public bx::CrtFileWriter + class Bin2cWriter : public bx::FileWriter { public: Bin2cWriter(const char* _name) @@ -213,13 +295,13 @@ namespace bgfx { } - virtual void close() BX_OVERRIDE + virtual void close() override { generate(); - return bx::CrtFileWriter::close(); + return bx::FileWriter::close(); } - virtual int32_t write(const void* _data, int32_t _size, bx::Error*) BX_OVERRIDE + virtual int32_t write(const void* _data, int32_t _size, bx::Error*) override { const char* data = (const char*)_data; m_buffer.insert(m_buffer.end(), data, data+_size); @@ -290,7 +372,7 @@ namespace bgfx } bx::Error err; - int32_t size = bx::CrtFileWriter::write(out, len, &err); + int32_t size = bx::FileWriter::write(out, len, &err); va_end(argList); @@ -321,7 +403,7 @@ namespace bgfx File(const char* _filePath) : m_data(NULL) { - bx::CrtFileReader reader; + bx::FileReader reader; if (bx::open(&reader, _filePath) ) { m_size = (uint32_t)bx::getSize(&reader); @@ -333,7 +415,7 @@ namespace bgfx && m_data[1] == '\xbb' && m_data[2] == '\xbf') { - memmove(m_data, &m_data[3], m_size-3); + bx::memMove(m_data, &m_data[3], m_size-3); m_size -= 3; } @@ -363,26 +445,29 @@ namespace bgfx char* strInsert(char* _str, const char* _insert) { - uint32_t len = bx::strnlen(_insert); - bx::memMove(&_str[len], _str, bx::strnlen(_str) ); + uint32_t len = bx::strLen(_insert); + bx::memMove(&_str[len], _str, bx::strLen(_str) ); bx::memCopy(_str, _insert, len); return _str + len; } void strReplace(char* _str, const char* _find, const char* _replace) { - const int32_t len = bx::strnlen(_find); + const int32_t len = bx::strLen(_find); char* replace = (char*)alloca(len+1); - bx::strlcpy(replace, _replace, len+1); - for (int32_t ii = bx::strnlen(replace); ii < len; ++ii) + bx::strCopy(replace, len+1, _replace); + for (int32_t ii = bx::strLen(replace); ii < len; ++ii) { replace[ii] = ' '; } replace[len] = '\0'; - BX_CHECK(len >= bx::strnlen(_replace), ""); - for (const char* ptr = bx::strnstr(_str, _find); NULL != ptr; ptr = bx::strnstr(ptr + len, _find) ) + BX_CHECK(len >= bx::strLen(_replace), ""); + for (const char* ptr = bx::strFind(_str, _find) + ; NULL != ptr + ; ptr = bx::strFind(ptr + len, _find) + ) { bx::memCopy(const_cast<char*>(ptr), replace, len); } @@ -398,15 +483,22 @@ namespace bgfx { fprintf(stderr, "Code:\n---\n"); - LineReader lr(_code); - for (int32_t line = 1; !lr.isEof() && line < _end; ++line) + bx::Error err; + LineReader reader(_code); + for (int32_t line = 1; err.isOk() && line < _end; ++line) { - if (line >= _start) + char str[4096]; + int32_t len = bx::read(&reader, str, BX_COUNTOF(str), &err); + + if (err.isOk() + && line >= _start) { + std::string strLine(str, len); + if (_line == line) { fprintf(stderr, "\n"); - fprintf(stderr, ">>> %3d: %s", line, lr.getLine().c_str() ); + fprintf(stderr, ">>> %3d: %s", line, strLine.c_str() ); if (-1 != _column) { fprintf(stderr, ">>> %3d: %*s\n", _column, _column, "^"); @@ -415,13 +507,9 @@ namespace bgfx } else { - fprintf(stderr, " %3d: %s", line, lr.getLine().c_str() ); + fprintf(stderr, " %3d: %s", line, strLine.c_str() ); } } - else - { - lr.skipLine(); - } } fprintf(stderr, "---\n"); @@ -429,7 +517,7 @@ namespace bgfx void writeFile(const char* _filePath, const void* _data, int32_t _size) { - bx::CrtFileWriter out; + bx::FileWriter out; if (bx::open(&out, _filePath) ) { bx::write(&out, _data, _size); @@ -517,7 +605,10 @@ namespace bgfx { char* start = scratch(_includeDir); - for (char* split = strchr(start, ';'); NULL != split; split = strchr(start, ';') ) + for (char* split = const_cast<char*>(bx::strFind(start, ';') ) + ; NULL != split + ; split = const_cast<char*>(bx::strFind(start, ';') ) + ) { *split = '\0'; m_tagptr->tag = FPPTAG_INCLUDE_DIR; @@ -545,7 +636,7 @@ namespace bgfx m_input = m_default; m_input += "\n\n"; - int32_t len = bx::strnlen(_input)+1; + int32_t len = bx::strLen(_input)+1; char* temp = new char[len]; bx::eolLF(temp, len, _input); m_input += temp; @@ -606,8 +697,8 @@ namespace bgfx char* scratch(const char* _str) { char* result = &m_scratch[m_scratchPos]; - strcpy(result, _str); - m_scratchPos += (uint32_t)strlen(_str)+1; + bx::strCopy(result, uint32_t(sizeof(m_scratch)-m_scratchPos), _str); + m_scratchPos += (uint32_t)bx::strLen(_str)+1; return result; } @@ -688,6 +779,15 @@ namespace bgfx strReplace(_data, find, "bgfx_VoidFrag"); } + const char* baseName(const char* _filePath) + { + bx::FilePath fp(_filePath); + char tmp[bx::kMaxFilePath]; + bx::strCopy(tmp, BX_COUNTOF(tmp), fp.getFileName() ); + const char* base = bx::strFind(_filePath, tmp); + return base; + } + // c - compute // d - domain // f - fragment @@ -715,9 +815,12 @@ namespace bgfx } fprintf(stderr - , "shaderc, bgfx shader compiler tool\n" + , "shaderc, bgfx shader compiler tool, version %d.%d.%d.\n" "Copyright 2011-2017 Branimir Karadzic. All rights reserved.\n" "License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause\n\n" + , BGFX_SHADERC_VERSION_MAJOR + , BGFX_SHADERC_VERSION_MINOR + , BGFX_API_VERSION ); fprintf(stderr @@ -725,6 +828,8 @@ namespace bgfx "\n" "Options:\n" + " -h, --help Help.\n" + " -v, --version Version information only.\n" " -f <file path> Input file path.\n" " -i <include path> Include path (for multiple paths use use -i multiple times).\n" " -o <file path> Output file path.\n" @@ -760,47 +865,9 @@ namespace bgfx ); } - int compileShader(int _argc, const char* _argv[]) - { - bx::CommandLine cmdLine(_argc, _argv); - - if (cmdLine.hasArg('h', "help") ) - { - help(); - return EXIT_FAILURE; - } - - g_verbose = cmdLine.hasArg("verbose"); - - const char* filePath = cmdLine.findOption('f'); - if (NULL == filePath) - { - help("Shader file name must be specified."); - return EXIT_FAILURE; - } - - const char* outFilePath = cmdLine.findOption('o'); - if (NULL == outFilePath) - { - help("Output file name must be specified."); - return EXIT_FAILURE; - } - - const char* type = cmdLine.findOption('\0', "type"); - if (NULL == type) - { - help("Must specify shader type."); - return EXIT_FAILURE; - } - - const char* platform = cmdLine.findOption('\0', "platform"); - if (NULL == platform) - { - platform = ""; - } - - bool raw = cmdLine.hasArg('\0', "raw"); + bool compileShader(const char* _varying, char* _shader, uint32_t _shaderLen, Options& _options, bx::FileWriter* _writer) + { uint32_t glsl = 0; uint32_t essl = 0; uint32_t hlsl = 0; @@ -808,35 +875,35 @@ namespace bgfx uint32_t metal = 0; uint32_t pssl = 0; uint32_t spirv = 0; - const char* profile = cmdLine.findOption('p', "profile"); - if (NULL != profile) + const char* profile = _options.profile.c_str(); + if ('\0' != profile[0]) { - if (0 == strncmp(&profile[1], "s_4_0_level", 11) ) + if (0 == bx::strCmp(&profile[1], "s_4_0_level", 11) ) { hlsl = 2; } - else if (0 == strncmp(&profile[1], "s_3", 3) ) + else if (0 == bx::strCmp(&profile[1], "s_3", 3) ) { hlsl = 3; d3d = 9; } - else if (0 == strncmp(&profile[1], "s_4", 3) ) + else if (0 == bx::strCmp(&profile[1], "s_4", 3) ) { hlsl = 4; } - else if (0 == strncmp(&profile[1], "s_5", 3) ) + else if (0 == bx::strCmp(&profile[1], "s_5", 3) ) { hlsl = 5; } - else if (0 == strcmp(profile, "metal") ) + else if (0 == bx::strCmp(profile, "metal") ) { metal = 1; } - else if (0 == strcmp(profile, "pssl") ) + else if (0 == bx::strCmp(profile, "pssl") ) { pssl = 1; } - else if (0 == strcmp(profile, "spirv") ) + else if (0 == bx::strCmp(profile, "spirv") ) { spirv = 1; } @@ -850,84 +917,24 @@ namespace bgfx essl = 2; } - const char* bin2c = NULL; - if (cmdLine.hasArg("bin2c") ) - { - bin2c = cmdLine.findOption("bin2c"); - if (NULL == bin2c) - { - bin2c = bx::baseName(outFilePath); - uint32_t len = (uint32_t)strlen(bin2c); - char* temp = (char*)alloca(len+1); - for (char *out = temp; *bin2c != '\0';) - { - char ch = *bin2c++; - if (isalnum(ch) ) - { - *out++ = ch; - } - else - { - *out++ = '_'; - } - } - temp[len] = '\0'; - - bin2c = temp; - } - } - - bool depends = cmdLine.hasArg("depends"); - bool preprocessOnly = cmdLine.hasArg("preprocess"); - const char* includeDir = cmdLine.findOption('i'); - - BX_TRACE("depends: %d", depends); - BX_TRACE("preprocessOnly: %d", preprocessOnly); - BX_TRACE("includeDir: %s", includeDir); - - Preprocessor preprocessor(filePath, 0 != essl); + Preprocessor preprocessor(_options.inputFilePath.c_str(), 0 != essl); - for (int ii = 1; NULL != includeDir; ++ii) - { - preprocessor.addInclude(includeDir); - includeDir = cmdLine.findOption(ii, 'i'); - } - - std::string dir; - { - const char* base = bx::baseName(filePath); + for(size_t i=0; i<_options.includeDirs.size(); ++i) + preprocessor.addInclude(_options.includeDirs[i].c_str()); - if (base != filePath) - { - dir.assign(filePath, base-filePath); - preprocessor.addInclude(dir.c_str() ); - } - } + for(size_t i=0; i<_options.defines.size(); ++i) + preprocessor.setDefine(_options.defines[i].c_str()); - const char* defines = cmdLine.findOption("define"); - while (NULL != defines - && '\0' != *defines) - { - defines = bx::strws(defines); - const char* eol = strchr(defines, ';'); - if (NULL == eol) - { - eol = defines + strlen(defines); - } - std::string define(defines, eol); - preprocessor.setDefine(define.c_str() ); - defines = ';' == *eol ? eol+1 : eol; - } + for(size_t i=0; i<_options.dependencies.size(); ++i) + preprocessor.addDependency(_options.dependencies[i].c_str()); preprocessor.setDefaultDefine("BX_PLATFORM_ANDROID"); preprocessor.setDefaultDefine("BX_PLATFORM_EMSCRIPTEN"); preprocessor.setDefaultDefine("BX_PLATFORM_IOS"); preprocessor.setDefaultDefine("BX_PLATFORM_LINUX"); - preprocessor.setDefaultDefine("BX_PLATFORM_NACL"); preprocessor.setDefaultDefine("BX_PLATFORM_OSX"); preprocessor.setDefaultDefine("BX_PLATFORM_PS4"); preprocessor.setDefaultDefine("BX_PLATFORM_WINDOWS"); - preprocessor.setDefaultDefine("BX_PLATFORM_XBOX360"); preprocessor.setDefaultDefine("BX_PLATFORM_XBOXONE"); // preprocessor.setDefaultDefine("BGFX_SHADER_LANGUAGE_ESSL"); @@ -947,22 +954,24 @@ namespace bgfx , essl ? 1 : glsl ); - if (0 == bx::strincmp(platform, "android") ) + const char* platform = _options.platform.c_str(); + + if (0 == bx::strCmpI(platform, "android") ) { preprocessor.setDefine("BX_PLATFORM_ANDROID=1"); preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1"); } - else if (0 == bx::strincmp(platform, "asm.js") ) + else if (0 == bx::strCmpI(platform, "asm.js") ) { preprocessor.setDefine("BX_PLATFORM_EMSCRIPTEN=1"); preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1"); } - else if (0 == bx::strincmp(platform, "ios") ) + else if (0 == bx::strCmpI(platform, "ios") ) { preprocessor.setDefine("BX_PLATFORM_IOS=1"); preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1"); } - else if (0 == bx::strincmp(platform, "linux") ) + else if (0 == bx::strCmpI(platform, "linux") ) { preprocessor.setDefine("BX_PLATFORM_LINUX=1"); if (0 != spirv) @@ -974,12 +983,7 @@ namespace bgfx preprocessor.setDefine(glslDefine); } } - else if (0 == bx::strincmp(platform, "nacl") ) - { - preprocessor.setDefine("BX_PLATFORM_NACL=1"); - preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1"); - } - else if (0 == bx::strincmp(platform, "osx") ) + else if (0 == bx::strCmpI(platform, "osx") ) { preprocessor.setDefine("BX_PLATFORM_OSX=1"); preprocessor.setDefine(glslDefine); @@ -987,19 +991,14 @@ namespace bgfx bx::snprintf(temp, sizeof(temp), "BGFX_SHADER_LANGUAGE_METAL=%d", metal); preprocessor.setDefine(temp); } - else if (0 == bx::strincmp(platform, "windows") ) + else if (0 == bx::strCmpI(platform, "windows") ) { preprocessor.setDefine("BX_PLATFORM_WINDOWS=1"); char temp[256]; bx::snprintf(temp, sizeof(temp), "BGFX_SHADER_LANGUAGE_HLSL=%d", hlsl); preprocessor.setDefine(temp); } - else if (0 == bx::strincmp(platform, "xbox360") ) - { - preprocessor.setDefine("BX_PLATFORM_XBOX360=1"); - preprocessor.setDefine("BGFX_SHADER_LANGUAGE_HLSL=3"); - } - else if (0 == bx::strincmp(platform, "orbis") ) + else if (0 == bx::strCmpI(platform, "orbis") ) { preprocessor.setDefine("BX_PLATFORM_PS4=1"); preprocessor.setDefine("BGFX_SHADER_LANGUAGE_PSSL=1"); @@ -1008,8 +1007,7 @@ namespace bgfx preprocessor.setDefine("M_PI=3.1415926535897932384626433832795"); - char shaderType = bx::toLower(type[0]); - switch (shaderType) + switch (_options.shaderType) { case 'c': preprocessor.setDefine("BGFX_SHADER_TYPE_COMPUTE=1"); @@ -1024,836 +1022,774 @@ namespace bgfx break; default: - fprintf(stderr, "Unknown type: %s?!", type); - return EXIT_FAILURE; + fprintf(stderr, "Unknown type: %c?!", _options.shaderType); + return false; } bool compiled = false; - bx::CrtFileReader reader; - if (!bx::open(&reader, filePath) ) - { - fprintf(stderr, "Unable to open file '%s'.\n", filePath); - } - else - { - VaryingMap varyingMap; + VaryingMap varyingMap; + const char* parse = _varying; - std::string defaultVarying = dir + "varying.def.sc"; - const char* varyingdef = cmdLine.findOption("varyingdef", defaultVarying.c_str() ); - File attribdef(varyingdef); - const char* parse = attribdef.getData(); - if (NULL != parse + while (NULL != parse && *parse != '\0') + { + parse = bx::strws(parse); + const char* eol = bx::strFind(parse, ';'); + if (NULL == eol) { - preprocessor.addDependency(varyingdef); - } - else - { - fprintf(stderr, "ERROR: Failed to parse varying def file: \"%s\" No input/output semantics will be generated in the code!\n", varyingdef); + eol = bx::streol(parse); } - while (NULL != parse - && *parse != '\0') + if (NULL != eol) { - parse = bx::strws(parse); - const char* eol = strchr(parse, ';'); - if (NULL == eol) + const char* precision = NULL; + const char* interpolation = NULL; + const char* typen = parse; + + if (0 == bx::strCmp(typen, "lowp", 4) + || 0 == bx::strCmp(typen, "mediump", 7) + || 0 == bx::strCmp(typen, "highp", 5) ) { - eol = bx::streol(parse); + precision = typen; + typen = parse = bx::strws(bx::strword(parse) ); } - if (NULL != eol) + if (0 == bx::strCmp(typen, "flat", 4) + || 0 == bx::strCmp(typen, "smooth", 6) + || 0 == bx::strCmp(typen, "noperspective", 13) + || 0 == bx::strCmp(typen, "centroid", 8) ) { - const char* precision = NULL; - const char* interpolation = NULL; - const char* typen = parse; + interpolation = typen; + typen = parse = bx::strws(bx::strword(parse) ); + } - if (0 == strncmp(typen, "lowp", 4) - || 0 == strncmp(typen, "mediump", 7) - || 0 == strncmp(typen, "highp", 5) ) + const char* name = parse = bx::strws(bx::strword(parse) ); + const char* column = parse = bx::strws(bx::strword(parse) ); + const char* semantics = parse = bx::strws( (*parse == ':' ? ++parse : parse) ); + const char* assign = parse = bx::strws(bx::strword(parse) ); + const char* init = parse = bx::strws( (*parse == '=' ? ++parse : parse) ); + + if (typen < eol + && name < eol + && column < eol + && ':' == *column + && semantics < eol) + { + Varying var; + if (NULL != precision) { - precision = typen; - typen = parse = bx::strws(bx::strword(parse) ); + var.m_precision.assign(precision, bx::strword(precision)-precision); } - if (0 == strncmp(typen, "flat", 4) - || 0 == strncmp(typen, "smooth", 6) - || 0 == strncmp(typen, "noperspective", 13) - || 0 == strncmp(typen, "centroid", 8) ) + if (NULL != interpolation) { - interpolation = typen; - typen = parse = bx::strws(bx::strword(parse) ); + var.m_interpolation.assign(interpolation, bx::strword(interpolation)-interpolation); } - const char* name = parse = bx::strws(bx::strword(parse) ); - const char* column = parse = bx::strws(bx::strword(parse) ); - const char* semantics = parse = bx::strws( (*parse == ':' ? ++parse : parse) ); - const char* assign = parse = bx::strws(bx::strword(parse) ); - const char* init = parse = bx::strws( (*parse == '=' ? ++parse : parse) ); - - if (typen < eol - && name < eol - && column < eol - && ':' == *column - && semantics < eol) - { - Varying var; - if (NULL != precision) - { - var.m_precision.assign(precision, bx::strword(precision)-precision); - } - - if (NULL != interpolation) - { - var.m_interpolation.assign(interpolation, bx::strword(interpolation)-interpolation); - } - - var.m_type.assign(typen, bx::strword(typen)-typen); - var.m_name.assign(name, bx::strword(name)-name); - var.m_semantics.assign(semantics, bx::strword(semantics)-semantics); - - if (d3d == 9 - && var.m_semantics == "BITANGENT") - { - var.m_semantics = "BINORMAL"; - } + var.m_type.assign(typen, bx::strword(typen)-typen); + var.m_name.assign(name, bx::strword(name)-name); + var.m_semantics.assign(semantics, bx::strword(semantics)-semantics); - if (assign < eol - && '=' == *assign - && init < eol) - { - var.m_init.assign(init, eol-init); - } + if (d3d == 9 + && var.m_semantics == "BITANGENT") + { + var.m_semantics = "BINORMAL"; + } - varyingMap.insert(std::make_pair(var.m_name, var) ); + if (assign < eol + && '=' == *assign + && init < eol) + { + var.m_init.assign(init, eol-init); } - parse = bx::strws(bx::strnl(eol) ); + varyingMap.insert(std::make_pair(var.m_name, var) ); } - } - InOut shaderInputs; - InOut shaderOutputs; - uint32_t inputHash = 0; - uint32_t outputHash = 0; - - char* data; - char* input; - { - const size_t padding = 4096; - uint32_t size = (uint32_t)bx::getSize(&reader); - data = new char[size+padding+1]; - size = (uint32_t)bx::read(&reader, data, size); - - if (data[0] == '\xef' - && data[1] == '\xbb' - && data[2] == '\xbf') - { - memmove(data, &data[3], size-3); - size -= 3; - } + parse = bx::strws(bx::strnl(eol) ); + } + } - // Compiler generates "error X3000: syntax error: unexpected end of file" - // if input doesn't have empty line at EOF. - data[size] = '\n'; - memset(&data[size+1], 0, padding); - bx::close(&reader); + bool raw = _options.raw; - if (!raw) - { - // To avoid commented code being recognized as used feature, - // first preprocess pass is used to strip all comments before - // substituting code. - preprocessor.run(data); - delete [] data; - - size = (uint32_t)preprocessor.m_preprocessed.size(); - data = new char[size+padding+1]; - memcpy(data, preprocessor.m_preprocessed.c_str(), size); - memset(&data[size], 0, padding+1); - } + InOut shaderInputs; + InOut shaderOutputs; + uint32_t inputHash = 0; + uint32_t outputHash = 0; - strNormalizeEol(data); + char* data; + char* input; + { + data = _shader; + uint32_t size = _shaderLen; - input = const_cast<char*>(bx::strws(data) ); - while (input[0] == '$') - { - const char* str = bx::strws(input+1); - const char* eol = bx::streol(str); - const char* nl = bx::strnl(eol); - input = const_cast<char*>(nl); + const size_t padding = 4096; - if (0 == strncmp(str, "input", 5) ) - { - str += 5; - const char* comment = strstr(str, "//"); - eol = NULL != comment && comment < eol ? comment : eol; - inputHash = parseInOut(shaderInputs, str, eol); - } - else if (0 == strncmp(str, "output", 6) ) - { - str += 6; - const char* comment = strstr(str, "//"); - eol = NULL != comment && comment < eol ? comment : eol; - outputHash = parseInOut(shaderOutputs, str, eol); - } - else if (0 == strncmp(str, "raw", 3) ) - { - raw = true; - str += 3; - } + if (!raw) + { + // To avoid commented code being recognized as used feature, + // first preprocess pass is used to strip all comments before + // substituting code. + preprocessor.run(data); + delete [] data; - input = const_cast<char*>(bx::strws(input) ); - } + size = (uint32_t)preprocessor.m_preprocessed.size(); + data = new char[size+padding+1]; + bx::memCopy(data, preprocessor.m_preprocessed.c_str(), size); + bx::memSet(&data[size], 0, padding+1); } - if (raw) + strNormalizeEol(data); + + input = const_cast<char*>(bx::strws(data) ); + while (input[0] == '$') { - bx::CrtFileWriter* writer = NULL; + const char* str = bx::strws(input+1); + const char* eol = bx::streol(str); + const char* nl = bx::strnl(eol); + input = const_cast<char*>(nl); - if (NULL != bin2c) + if (0 == bx::strCmp(str, "input", 5) ) { - writer = new Bin2cWriter(bin2c); + str += 5; + const char* comment = bx::strFind(str, "//"); + eol = NULL != comment && comment < eol ? comment : eol; + inputHash = parseInOut(shaderInputs, str, eol); } - else + else if (0 == bx::strCmp(str, "output", 6) ) { - writer = new bx::CrtFileWriter; + str += 6; + const char* comment = bx::strFind(str, "//"); + eol = NULL != comment && comment < eol ? comment : eol; + outputHash = parseInOut(shaderOutputs, str, eol); } - - if (!bx::open(writer, outFilePath) ) + else if (0 == bx::strCmp(str, "raw", 3) ) { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return EXIT_FAILURE; + raw = true; + str += 3; } - if ('f' == shaderType) - { - bx::write(writer, BGFX_CHUNK_MAGIC_FSH); - bx::write(writer, inputHash); - } - else if ('v' == shaderType) - { - bx::write(writer, BGFX_CHUNK_MAGIC_VSH); - bx::write(writer, outputHash); - } - else - { - bx::write(writer, BGFX_CHUNK_MAGIC_CSH); - bx::write(writer, outputHash); - } + input = const_cast<char*>(bx::strws(input) ); + } + } - if (0 != glsl) - { - bx::write(writer, uint16_t(0) ); + if (raw) + { + if ('f' == _options.shaderType) + { + bx::write(_writer, BGFX_CHUNK_MAGIC_FSH); + bx::write(_writer, inputHash); + } + else if ('v' == _options.shaderType) + { + bx::write(_writer, BGFX_CHUNK_MAGIC_VSH); + bx::write(_writer, outputHash); + } + else + { + bx::write(_writer, BGFX_CHUNK_MAGIC_CSH); + bx::write(_writer, outputHash); + } - uint32_t shaderSize = (uint32_t)strlen(input); - bx::write(writer, shaderSize); - bx::write(writer, input, shaderSize); - bx::write(writer, uint8_t(0) ); + if (0 != glsl) + { + bx::write(_writer, uint16_t(0) ); - compiled = true; - } - else if (0 != pssl) - { - compiled = compilePSSLShader(cmdLine, 0, input, writer); - } - else - { - compiled = compileHLSLShader(cmdLine, d3d, input, writer); - } + uint32_t shaderSize = (uint32_t)bx::strLen(input); + bx::write(_writer, shaderSize); + bx::write(_writer, input, shaderSize); + bx::write(_writer, uint8_t(0) ); - bx::close(writer); - delete writer; + compiled = true; } - else if ('c' == shaderType) // Compute + else if (0 != pssl) + { + compiled = compilePSSLShader(_options, 0, input, _writer); + } + else { - char* entry = strstr(input, "void main()"); - if (NULL == entry) + compiled = compileHLSLShader(_options, d3d, input, _writer); + } + } + else if ('c' == _options.shaderType) // Compute + { + char* entry = const_cast<char*>(bx::strFind(input, "void main()") ); + if (NULL == entry) + { + fprintf(stderr, "Shader entry point 'void main()' is not found.\n"); + } + else + { + if (0 != glsl + || 0 != essl + || 0 != metal) { - fprintf(stderr, "Shader entry point 'void main()' is not found.\n"); } else { - if (0 != glsl - || 0 != essl - || 0 != metal) + preprocessor.writef( + "#define lowp\n" + "#define mediump\n" + "#define highp\n" + "#define ivec2 int2\n" + "#define ivec3 int3\n" + "#define ivec4 int4\n" + "#define uvec2 uint2\n" + "#define uvec3 uint3\n" + "#define uvec4 uint4\n" + "#define vec2 float2\n" + "#define vec3 float3\n" + "#define vec4 float4\n" + "#define mat2 float2x2\n" + "#define mat3 float3x3\n" + "#define mat4 float4x4\n" + ); + + entry[4] = '_'; + + preprocessor.writef("#define void_main()"); + preprocessor.writef(" \\\n\tvoid main("); + + uint32_t arg = 0; + + const bool hasLocalInvocationID = NULL != bx::strFind(input, "gl_LocalInvocationID"); + const bool hasLocalInvocationIndex = NULL != bx::strFind(input, "gl_LocalInvocationIndex"); + const bool hasGlobalInvocationID = NULL != bx::strFind(input, "gl_GlobalInvocationID"); + const bool hasWorkGroupID = NULL != bx::strFind(input, "gl_WorkGroupID"); + + if (hasLocalInvocationID) { + preprocessor.writef( + " \\\n\t%sint3 gl_LocalInvocationID : SV_GroupThreadID" + , arg++ > 0 ? ", " : " " + ); } - else + + if (hasLocalInvocationIndex) { preprocessor.writef( - "#define lowp\n" - "#define mediump\n" - "#define highp\n" - "#define ivec2 int2\n" - "#define ivec3 int3\n" - "#define ivec4 int4\n" - "#define uvec2 uint2\n" - "#define uvec3 uint3\n" - "#define uvec4 uint4\n" - "#define vec2 float2\n" - "#define vec3 float3\n" - "#define vec4 float4\n" - "#define mat2 float2x2\n" - "#define mat3 float3x3\n" - "#define mat4 float4x4\n" + " \\\n\t%sint gl_LocalInvocationIndex : SV_GroupIndex" + , arg++ > 0 ? ", " : " " ); + } - entry[4] = '_'; - - preprocessor.writef("#define void_main()"); - preprocessor.writef(" \\\n\tvoid main("); - - uint32_t arg = 0; - - const bool hasLocalInvocationID = NULL != strstr(input, "gl_LocalInvocationID"); - const bool hasLocalInvocationIndex = NULL != strstr(input, "gl_LocalInvocationIndex"); - const bool hasGlobalInvocationID = NULL != strstr(input, "gl_GlobalInvocationID"); - const bool hasWorkGroupID = NULL != strstr(input, "gl_WorkGroupID"); - - if (hasLocalInvocationID) - { - preprocessor.writef( - " \\\n\t%sint3 gl_LocalInvocationID : SV_GroupThreadID" - , arg++ > 0 ? ", " : " " - ); - } - - if (hasLocalInvocationIndex) - { - preprocessor.writef( - " \\\n\t%sint gl_LocalInvocationIndex : SV_GroupIndex" - , arg++ > 0 ? ", " : " " - ); - } - - if (hasGlobalInvocationID) - { - preprocessor.writef( - " \\\n\t%sint3 gl_GlobalInvocationID : SV_DispatchThreadID" - , arg++ > 0 ? ", " : " " - ); - } - - if (hasWorkGroupID) - { - preprocessor.writef( - " \\\n\t%sint3 gl_WorkGroupID : SV_GroupID" - , arg++ > 0 ? ", " : " " - ); - } - + if (hasGlobalInvocationID) + { preprocessor.writef( - " \\\n\t)\n" + " \\\n\t%sint3 gl_GlobalInvocationID : SV_DispatchThreadID" + , arg++ > 0 ? ", " : " " ); } - if (preprocessor.run(input) ) + if (hasWorkGroupID) { - BX_TRACE("Input file: %s", filePath); - BX_TRACE("Output file: %s", outFilePath); + preprocessor.writef( + " \\\n\t%sint3 gl_WorkGroupID : SV_GroupID" + , arg++ > 0 ? ", " : " " + ); + } - if (preprocessOnly) - { - bx::CrtFileWriter writer; + preprocessor.writef( + " \\\n\t)\n" + ); + } - if (!bx::open(&writer, outFilePath) ) - { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return EXIT_FAILURE; - } + if (preprocessor.run(input) ) + { + //BX_TRACE("Input file: %s", filePath); + //BX_TRACE("Output file: %s", outFilePath); - bx::write(&writer, preprocessor.m_preprocessed.c_str(), (int32_t)preprocessor.m_preprocessed.size() ); - bx::close(&writer); + if (_options.preprocessOnly) + { + bx::write(_writer, preprocessor.m_preprocessed.c_str(), (int32_t)preprocessor.m_preprocessed.size() ); - return EXIT_SUCCESS; - } + return true; + } + { + bx::write(_writer, BGFX_CHUNK_MAGIC_CSH); + bx::write(_writer, outputHash); + + if (0 != glsl + || 0 != essl) { - bx::CrtFileWriter* writer = NULL; + std::string code; - if (NULL != bin2c) + if (essl) { - writer = new Bin2cWriter(bin2c); + bx::stringPrintf(code, "#version 310 es\n"); } else { - writer = new bx::CrtFileWriter; + bx::stringPrintf(code, "#version %d\n", glsl == 0 ? 430 : glsl); } - if (!bx::open(writer, outFilePath) ) - { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return EXIT_FAILURE; - } - - bx::write(writer, BGFX_CHUNK_MAGIC_CSH); - bx::write(writer, outputHash); + code += preprocessor.m_preprocessed; +#if 1 + bx::write(_writer, uint16_t(0) ); - if (0 != glsl - || 0 != essl) - { - std::string code; + uint32_t shaderSize = (uint32_t)code.size(); + bx::write(_writer, shaderSize); + bx::write(_writer, code.c_str(), shaderSize); + bx::write(_writer, uint8_t(0) ); - if (essl) - { - bx::stringPrintf(code, "#version 310 es\n"); - } - else - { - bx::stringPrintf(code, "#version %d\n", glsl == 0 ? 430 : glsl); - } - - code += preprocessor.m_preprocessed; - #if 1 - bx::write(writer, uint16_t(0) ); - - uint32_t shaderSize = (uint32_t)code.size(); - bx::write(writer, shaderSize); - bx::write(writer, code.c_str(), shaderSize); - bx::write(writer, uint8_t(0) ); + compiled = true; +#else + compiled = compileGLSLShader(cmdLine, essl, code, writer); +#endif // 0 + } + else if (0 != spirv) + { + compiled = compileSPIRVShader(_options, 0, preprocessor.m_preprocessed, _writer); + } + else if (0 != pssl) + { + compiled = compilePSSLShader(_options, 0, preprocessor.m_preprocessed, _writer); + } + else + { + compiled = compileHLSLShader(_options, d3d, preprocessor.m_preprocessed, _writer); + } + } - compiled = true; - #else - compiled = compileGLSLShader(cmdLine, essl, code, writer); - #endif // 0 - } - else if (0 != spirv) + if (compiled) + { + if (_options.depends) + { + std::string ofp = _options.outputFilePath; + ofp += ".d"; + bx::FileWriter writer; + if (bx::open(&writer, ofp.c_str() ) ) { - compiled = compileSPIRVShader(cmdLine, 0, preprocessor.m_preprocessed, writer); + writef(&writer, "%s : %s\n", _options.outputFilePath.c_str(), preprocessor.m_depends.c_str() ); + bx::close(&writer); } - else if (0 != pssl) + } + } + } + } + } + else // Vertex/Fragment + { + char* entry = const_cast<char*>(bx::strFind(input, "void main()") ); + if (NULL == entry) + { + fprintf(stderr, "Shader entry point 'void main()' is not found.\n"); + } + else + { + if (0 != glsl + || 0 != essl + || 0 != metal) + { + if (0 == essl) + { + // bgfx shadow2D/Proj behave like EXT_shadow_samplers + // not as GLSL language 1.2 specs shadow2D/Proj. + preprocessor.writef( + "#define shadow2D(_sampler, _coord) bgfxShadow2D(_sampler, _coord).x\n" + "#define shadow2DProj(_sampler, _coord) bgfxShadow2DProj(_sampler, _coord).x\n" + ); + } + + for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.end(); it != itEnd; ++it) + { + VaryingMap::const_iterator varyingIt = varyingMap.find(*it); + if (varyingIt != varyingMap.end() ) + { + const Varying& var = varyingIt->second; + const char* name = var.m_name.c_str(); + + if (0 == bx::strCmp(name, "a_", 2) + || 0 == bx::strCmp(name, "i_", 2) ) { - compiled = compilePSSLShader(cmdLine, 0, preprocessor.m_preprocessed, writer); + preprocessor.writef("attribute %s %s %s %s;\n" + , var.m_precision.c_str() + , var.m_interpolation.c_str() + , var.m_type.c_str() + , name + ); } else { - compiled = compileHLSLShader(cmdLine, d3d, preprocessor.m_preprocessed, writer); + preprocessor.writef("%s varying %s %s %s;\n" + , var.m_interpolation.c_str() + , var.m_precision.c_str() + , var.m_type.c_str() + , name + ); } - - bx::close(writer); - delete writer; } + } - if (compiled) + for (InOut::const_iterator it = shaderOutputs.begin(), itEnd = shaderOutputs.end(); it != itEnd; ++it) + { + VaryingMap::const_iterator varyingIt = varyingMap.find(*it); + if (varyingIt != varyingMap.end() ) { - if (depends) - { - std::string ofp = outFilePath; - ofp += ".d"; - bx::CrtFileWriter writer; - if (bx::open(&writer, ofp.c_str() ) ) - { - writef(&writer, "%s : %s\n", outFilePath, preprocessor.m_depends.c_str() ); - bx::close(&writer); - } - } + const Varying& var = varyingIt->second; + preprocessor.writef("%s varying %s %s;\n" + , var.m_interpolation.c_str() + , var.m_type.c_str() + , var.m_name.c_str() + ); } } } - } - else // Vertex/Fragment - { - char* entry = strstr(input, "void main()"); - if (NULL == entry) - { - fprintf(stderr, "Shader entry point 'void main()' is not found.\n"); - } else { - if (0 != glsl - || 0 != essl - || 0 != metal) + preprocessor.writef( + "#define lowp\n" + "#define mediump\n" + "#define highp\n" + "#define ivec2 int2\n" + "#define ivec3 int3\n" + "#define ivec4 int4\n" + "#define uvec2 uint2\n" + "#define uvec3 uint3\n" + "#define uvec4 uint4\n" + "#define vec2 float2\n" + "#define vec3 float3\n" + "#define vec4 float4\n" + "#define mat2 float2x2\n" + "#define mat3 float3x3\n" + "#define mat4 float4x4\n" + ); + + if (hlsl != 0 + && hlsl < 4) { - if (0 == essl) + preprocessor.writef( + "#define centroid\n" + "#define flat\n" + "#define noperspective\n" + "#define smooth\n" + ); + } + + entry[4] = '_'; + + if ('f' == _options.shaderType) + { + const char* insert = bx::strFind(entry, "{"); + if (NULL != insert) { - // bgfx shadow2D/Proj behave like EXT_shadow_samplers - // not as GLSL language 1.2 specs shadow2D/Proj. - preprocessor.writef( - "#define shadow2D(_sampler, _coord) bgfxShadow2D(_sampler, _coord).x\n" - "#define shadow2DProj(_sampler, _coord) bgfxShadow2DProj(_sampler, _coord).x\n" - ); + insert = strInsert(const_cast<char*>(insert+1), "\nvec4 bgfx_VoidFrag = vec4_splat(0.0);\n"); } - for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.end(); it != itEnd; ++it) + const bool hasFragColor = NULL != bx::strFind(input, "gl_FragColor"); + const bool hasFragCoord = NULL != bx::strFind(input, "gl_FragCoord") || hlsl > 3 || hlsl == 2; + const bool hasFragDepth = NULL != bx::strFind(input, "gl_FragDepth"); + const bool hasFrontFacing = NULL != bx::strFind(input, "gl_FrontFacing"); + const bool hasPrimitiveId = NULL != bx::strFind(input, "gl_PrimitiveID"); + + bool hasFragData[8] = {}; + uint32_t numFragData = 0; + for (uint32_t ii = 0; ii < BX_COUNTOF(hasFragData); ++ii) { - VaryingMap::const_iterator varyingIt = varyingMap.find(*it); - if (varyingIt != varyingMap.end() ) - { - const Varying& var = varyingIt->second; - const char* name = var.m_name.c_str(); + char temp[32]; + bx::snprintf(temp, BX_COUNTOF(temp), "gl_FragData[%d]", ii); + hasFragData[ii] = NULL != bx::strFind(input, temp); + numFragData += hasFragData[ii]; + } - if (0 == strncmp(name, "a_", 2) - || 0 == strncmp(name, "i_", 2) ) - { - preprocessor.writef("attribute %s %s %s %s;\n" - , var.m_precision.c_str() - , var.m_interpolation.c_str() - , var.m_type.c_str() - , name - ); - } - else - { - preprocessor.writef("%s varying %s %s %s;\n" - , var.m_interpolation.c_str() - , var.m_precision.c_str() - , var.m_type.c_str() - , name - ); - } + if (0 == numFragData) + { + // GL errors when both gl_FragColor and gl_FragData is used. + // This will trigger the same error with HLSL compiler too. + preprocessor.writef("#define gl_FragColor gl_FragData_0_\n"); + + // If it has gl_FragData or gl_FragColor, color target at + // index 0 exists, otherwise shader is not modifying color + // targets. + hasFragData[0] |= hasFragColor || d3d < 11; + + if (NULL != insert + && d3d < 11 + && !hasFragColor) + { + insert = strInsert(const_cast<char*>(insert+1), "\ngl_FragColor = bgfx_VoidFrag;\n"); } } - for (InOut::const_iterator it = shaderOutputs.begin(), itEnd = shaderOutputs.end(); it != itEnd; ++it) + preprocessor.writef("#define void_main()"); + preprocessor.writef(" \\\n\tvoid main("); + + uint32_t arg = 0; + + if (hasFragCoord) + { + preprocessor.writef(" \\\n\tvec4 gl_FragCoord : SV_POSITION"); + ++arg; + } + + for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.end(); it != itEnd; ++it) { VaryingMap::const_iterator varyingIt = varyingMap.find(*it); if (varyingIt != varyingMap.end() ) { const Varying& var = varyingIt->second; - preprocessor.writef("%s varying %s %s;\n" - , var.m_interpolation.c_str() + preprocessor.writef(" \\\n\t%s%s %s %s : %s" + , arg++ > 0 ? ", " : " " + , interpolationDx11(var.m_interpolation.c_str() ) , var.m_type.c_str() , var.m_name.c_str() + , var.m_semantics.c_str() ); } } - } - else - { - preprocessor.writef( - "#define lowp\n" - "#define mediump\n" - "#define highp\n" - "#define ivec2 int2\n" - "#define ivec3 int3\n" - "#define ivec4 int4\n" - "#define uvec2 uint2\n" - "#define uvec3 uint3\n" - "#define uvec4 uint4\n" - "#define vec2 float2\n" - "#define vec3 float3\n" - "#define vec4 float4\n" - "#define mat2 float2x2\n" - "#define mat3 float3x3\n" - "#define mat4 float4x4\n" - ); - if (hlsl != 0 - && hlsl < 4) + const uint32_t maxRT = d3d > 9 ? BX_COUNTOF(hasFragData) : 4; + + for (uint32_t ii = 0; ii < BX_COUNTOF(hasFragData); ++ii) + { + if (ii < maxRT) + { + if (hasFragData[ii]) + { + addFragData(preprocessor, input, ii, arg++ > 0); + } + } + else + { + voidFragData(input, ii); + } + } + + if (hasFragDepth) { preprocessor.writef( - "#define centroid\n" - "#define flat\n" - "#define noperspective\n" - "#define smooth\n" + " \\\n\t%sout float gl_FragDepth : SV_DEPTH" + , arg++ > 0 ? ", " : " " ); } - entry[4] = '_'; + if (hasFrontFacing + && hlsl >= 3) + { + preprocessor.writef( + " \\\n\t%sfloat __vface : VFACE" + , arg++ > 0 ? ", " : " " + ); + } - if ('f' == shaderType) + if (hasPrimitiveId) { - const char* insert = strstr(entry, "{"); - if (NULL != insert) + if (d3d > 9) { - insert = strInsert(const_cast<char*>(insert+1), "\nvec4 bgfx_VoidFrag = vec4_splat(0.0);\n"); + preprocessor.writef( + " \\\n\t%suint gl_PrimitiveID : SV_PrimitiveID" + , arg++ > 0 ? ", " : " " + ); } - - const bool hasFragColor = NULL != strstr(input, "gl_FragColor"); - const bool hasFragCoord = NULL != strstr(input, "gl_FragCoord") || hlsl > 3 || hlsl == 2; - const bool hasFragDepth = NULL != strstr(input, "gl_FragDepth"); - const bool hasFrontFacing = NULL != strstr(input, "gl_FrontFacing"); - const bool hasPrimitiveId = NULL != strstr(input, "gl_PrimitiveID"); - - bool hasFragData[8] = {}; - uint32_t numFragData = 0; - for (uint32_t ii = 0; ii < BX_COUNTOF(hasFragData); ++ii) + else { - char temp[32]; - bx::snprintf(temp, BX_COUNTOF(temp), "gl_FragData[%d]", ii); - hasFragData[ii] = NULL != strstr(input, temp); - numFragData += hasFragData[ii]; + fprintf(stderr, "gl_PrimitiveID builtin is not supported by this D3D9 HLSL.\n"); + return false; } + } + + preprocessor.writef( + " \\\n\t)\n" + ); - if (0 == numFragData) + if (hasFrontFacing) + { + if (hlsl >= 3) { - // GL errors when both gl_FragColor and gl_FragData is used. - // This will trigger the same error with HLSL compiler too. - preprocessor.writef("#define gl_FragColor gl_FragData_0_\n"); - - // If it has gl_FragData or gl_FragColor, color target at - // index 0 exists, otherwise shader is not modifying color - // targets. - hasFragData[0] |= hasFragColor || d3d < 11; - - if (NULL != insert - && d3d < 11 - && !hasFragColor) - { - insert = strInsert(const_cast<char*>(insert+1), "\ngl_FragColor = bgfx_VoidFrag;\n"); - } + preprocessor.writef( + "#define gl_FrontFacing (__vface <= 0.0)\n" + ); } - - preprocessor.writef("#define void_main()"); - preprocessor.writef(" \\\n\tvoid main("); - - uint32_t arg = 0; - - if (hasFragCoord) + else { - preprocessor.writef(" \\\n\tvec4 gl_FragCoord : SV_POSITION"); - ++arg; + preprocessor.writef( + "#define gl_FrontFacing false\n" + ); } + } + } + else if ('v' == _options.shaderType) + { + const bool hasVertexId = NULL != bx::strFind(input, "gl_VertexID"); + const bool hasInstanceId = NULL != bx::strFind(input, "gl_InstanceID"); - for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.end(); it != itEnd; ++it) + const char* brace = bx::strFind(entry, "{"); + if (NULL != brace) + { + const char* end = bx::strmb(brace, '{', '}'); + if (NULL != end) { - VaryingMap::const_iterator varyingIt = varyingMap.find(*it); - if (varyingIt != varyingMap.end() ) - { - const Varying& var = varyingIt->second; - preprocessor.writef(" \\\n\t%s%s %s %s : %s" - , arg++ > 0 ? ", " : " " - , interpolationDx11(var.m_interpolation.c_str() ) - , var.m_type.c_str() - , var.m_name.c_str() - , var.m_semantics.c_str() - ); - } + strInsert(const_cast<char*>(end), "__RETURN__;\n"); } + } - const uint32_t maxRT = d3d > 9 ? BX_COUNTOF(hasFragData) : 4; - - for (uint32_t ii = 0; ii < BX_COUNTOF(hasFragData); ++ii) + preprocessor.writef( + "struct Output\n" + "{\n" + "\tvec4 gl_Position : SV_POSITION;\n" + "#define gl_Position _varying_.gl_Position\n" + ); + for (InOut::const_iterator it = shaderOutputs.begin(), itEnd = shaderOutputs.end(); it != itEnd; ++it) + { + VaryingMap::const_iterator varyingIt = varyingMap.find(*it); + if (varyingIt != varyingMap.end() ) { - if (ii < maxRT) - { - if (hasFragData[ii]) - { - addFragData(preprocessor, input, ii, arg++ > 0); - } - } - else - { - voidFragData(input, ii); - } + const Varying& var = varyingIt->second; + preprocessor.writef("\t%s %s : %s;\n", var.m_type.c_str(), var.m_name.c_str(), var.m_semantics.c_str() ); + preprocessor.writef("#define %s _varying_.%s\n", var.m_name.c_str(), var.m_name.c_str() ); } + } + preprocessor.writef( + "};\n" + ); - if (hasFragDepth) + preprocessor.writef("#define void_main() \\\n"); + preprocessor.writef("Output main("); + uint32_t arg = 0; + for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.end(); it != itEnd; ++it) + { + VaryingMap::const_iterator varyingIt = varyingMap.find(*it); + if (varyingIt != varyingMap.end() ) { + const Varying& var = varyingIt->second; preprocessor.writef( - " \\\n\t%sout float gl_FragDepth : SV_DEPTH" - , arg++ > 0 ? ", " : " " + " \\\n\t%s%s %s : %s" + , arg++ > 0 ? ", " : "" + , var.m_type.c_str() + , var.m_name.c_str() + , var.m_semantics.c_str() ); } + } - if (hasFrontFacing - && hlsl >= 3) + if (hasVertexId) + { + if (d3d > 9) { preprocessor.writef( - " \\\n\t%sfloat __vface : VFACE" + " \\\n\t%suint gl_VertexID : SV_VertexID" , arg++ > 0 ? ", " : " " ); } - - if (hasPrimitiveId) - { - if (d3d > 9) - { - preprocessor.writef( - " \\\n\t%suint gl_PrimitiveID : SV_PrimitiveID" - , arg++ > 0 ? ", " : " " - ); - } - else - { - fprintf(stderr, "PrimitiveID builtin is not supported by this D3D9 HLSL.\n"); - return EXIT_FAILURE; - } - } - - preprocessor.writef( - " \\\n\t)\n" - ); - - if (hasFrontFacing) + else { - if (hlsl >= 3) - { - preprocessor.writef( - "#define gl_FrontFacing (__vface <= 0.0)\n" - ); - } - else - { - preprocessor.writef( - "#define gl_FrontFacing false\n" - ); - } + fprintf(stderr, "gl_VertexID builtin is not supported by this D3D9 HLSL.\n"); + return false; } } - else if ('v' == shaderType) + + if (hasInstanceId) { - const char* brace = strstr(entry, "{"); - if (NULL != brace) + if (d3d > 9) { - const char* end = bx::strmb(brace, '{', '}'); - if (NULL != end) - { - strInsert(const_cast<char*>(end), "__RETURN__;\n"); - } + preprocessor.writef( + " \\\n\t%suint gl_InstanceID : SV_InstanceID" + , arg++ > 0 ? ", " : " " + ); } - - preprocessor.writef( - "struct Output\n" - "{\n" - "\tvec4 gl_Position : SV_POSITION;\n" - "#define gl_Position _varying_.gl_Position\n" - ); - for (InOut::const_iterator it = shaderOutputs.begin(), itEnd = shaderOutputs.end(); it != itEnd; ++it) + else { - VaryingMap::const_iterator varyingIt = varyingMap.find(*it); - if (varyingIt != varyingMap.end() ) - { - const Varying& var = varyingIt->second; - preprocessor.writef("\t%s %s : %s;\n", var.m_type.c_str(), var.m_name.c_str(), var.m_semantics.c_str() ); - preprocessor.writef("#define %s _varying_.%s\n", var.m_name.c_str(), var.m_name.c_str() ); - } + fprintf(stderr, "gl_InstanceID builtin is not supported by this D3D9 HLSL.\n"); + return false; } - preprocessor.writef( - "};\n" - ); + } - preprocessor.writef("#define void_main() \\\n"); - preprocessor.writef("Output main("); - bool first = true; - for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.end(); it != itEnd; ++it) - { - VaryingMap::const_iterator varyingIt = varyingMap.find(*it); - if (varyingIt != varyingMap.end() ) - { - const Varying& var = varyingIt->second; - preprocessor.writef("%s%s %s : %s\\\n", first ? "" : "\t, ", var.m_type.c_str(), var.m_name.c_str(), var.m_semantics.c_str() ); - first = false; - } - } - preprocessor.writef( - ") \\\n" - "{ \\\n" - "\tOutput _varying_;" - ); + preprocessor.writef( + ") \\\n" + "{ \\\n" + "\tOutput _varying_;" + ); - for (InOut::const_iterator it = shaderOutputs.begin(), itEnd = shaderOutputs.end(); it != itEnd; ++it) + for (InOut::const_iterator it = shaderOutputs.begin(), itEnd = shaderOutputs.end(); it != itEnd; ++it) + { + VaryingMap::const_iterator varyingIt = varyingMap.find(*it); + if (varyingIt != varyingMap.end() ) { - VaryingMap::const_iterator varyingIt = varyingMap.find(*it); - if (varyingIt != varyingMap.end() ) + const Varying& var = varyingIt->second; + preprocessor.writef(" \\\n\t%s", var.m_name.c_str() ); + if (!var.m_init.empty() ) { - const Varying& var = varyingIt->second; - preprocessor.writef(" \\\n\t%s", var.m_name.c_str() ); - if (!var.m_init.empty() ) - { - preprocessor.writef(" = %s", var.m_init.c_str() ); - } - preprocessor.writef(";"); + preprocessor.writef(" = %s", var.m_init.c_str() ); } + preprocessor.writef(";"); } + } - preprocessor.writef( - "\n#define __RETURN__ \\\n" - "\t} \\\n" - ); + preprocessor.writef( + "\n#define __RETURN__ \\\n" + "\t} \\\n" + ); - if (hlsl != 0 - && hlsl <= 3) - { + if (hlsl != 0 + && hlsl <= 3) + { // preprocessor.writef( // "\tgl_Position.xy += u_viewTexel.xy * gl_Position.w; \\\n" // ); - } - - preprocessor.writef( - "\treturn _varying_" - ); } + + preprocessor.writef( + "\treturn _varying_" + ); } + } - if (preprocessor.run(input) ) - { - BX_TRACE("Input file: %s", filePath); - BX_TRACE("Output file: %s", outFilePath); + if (preprocessor.run(input) ) + { + //BX_TRACE("Input file: %s", filePath); + //BX_TRACE("Output file: %s", outFilePath); - if (preprocessOnly) + if (_options.preprocessOnly) + { + if (0 != glsl) { - bx::CrtFileWriter writer; - - if (!bx::open(&writer, outFilePath) ) + if (essl != 0) { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return EXIT_FAILURE; + writef(_writer + , "#ifdef GL_ES\n" + "precision highp float;\n" + "#endif // GL_ES\n\n" + ); } + } + bx::write(_writer, preprocessor.m_preprocessed.c_str(), (int32_t)preprocessor.m_preprocessed.size() ); - if (0 != glsl) - { - if (NULL == profile) - { - writef(&writer - , "#ifdef GL_ES\n" - "precision highp float;\n" - "#endif // GL_ES\n\n" - ); - } - } - bx::write(&writer, preprocessor.m_preprocessed.c_str(), (int32_t)preprocessor.m_preprocessed.size() ); - bx::close(&writer); + return true; + } - return EXIT_SUCCESS; + { + if ('f' == _options.shaderType) + { + bx::write(_writer, BGFX_CHUNK_MAGIC_FSH); + bx::write(_writer, inputHash); } - + else if ('v' == _options.shaderType) { - bx::CrtFileWriter* writer = NULL; - - if (NULL != bin2c) - { - writer = new Bin2cWriter(bin2c); - } - else - { - writer = new bx::CrtFileWriter; - } - - if (!bx::open(writer, outFilePath) ) - { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return EXIT_FAILURE; - } + bx::write(_writer, BGFX_CHUNK_MAGIC_VSH); + bx::write(_writer, outputHash); + } + else + { + bx::write(_writer, BGFX_CHUNK_MAGIC_CSH); + bx::write(_writer, outputHash); + } - if ('f' == shaderType) - { - bx::write(writer, BGFX_CHUNK_MAGIC_FSH); - bx::write(writer, inputHash); - } - else if ('v' == shaderType) - { - bx::write(writer, BGFX_CHUNK_MAGIC_VSH); - bx::write(writer, outputHash); - } - else - { - bx::write(writer, BGFX_CHUNK_MAGIC_CSH); - bx::write(writer, outputHash); - } + if (0 != glsl + || 0 != essl + || 0 != metal) + { + std::string code; - if (0 != glsl - || 0 != essl - || 0 != metal) + if (glsl < 400) { - std::string code; - const bool usesTextureLod = false || !!bx::findIdentifierMatch(input, s_ARB_shader_texture_lod) || !!bx::findIdentifierMatch(input, s_EXT_shader_texture_lod) ; + const bool usesInstanceID = !!bx::strFind(input, "gl_InstanceID"); + const bool usesGpuShader4 = !!bx::findIdentifierMatch(input, s_EXT_gpu_shader4); const bool usesGpuShader5 = !!bx::findIdentifierMatch(input, s_ARB_gpu_shader5); const bool usesTexelFetch = !!bx::findIdentifierMatch(input, s_texelFetch); const bool usesTextureMS = !!bx::findIdentifierMatch(input, s_ARB_texture_multisample); @@ -1873,7 +1809,22 @@ namespace bgfx } else { - bx::stringPrintf(code, "#version %s\n", need130 ? "130" : profile); + bx::stringPrintf(code, "#version %s\n", need130 ? "130" : _options.profile.c_str()); + glsl = 130; + } + + if (usesInstanceID) + { + bx::stringPrintf(code + , "#extension GL_ARB_draw_instanced : enable\n" + ); + } + + if (usesGpuShader4) + { + bx::stringPrintf(code + , "#extension GL_EXT_gpu_shader4 : enable\n" + ); } if (usesGpuShader5) @@ -1895,8 +1846,7 @@ namespace bgfx if (usesTextureLod) { - if ( (0 != metal || 130 > glsl) - && 'f' == shaderType) + if ('f' == _options.shaderType) { ARB_shader_texture_lod = true; bx::stringPrintf(code @@ -1954,10 +1904,20 @@ namespace bgfx ); } - bx::stringPrintf(code - , "#define bgfxShadow2D shadow2D\n" - "#define bgfxShadow2DProj shadow2DProj\n" - ); + if (need130) + { + bx::stringPrintf(code + , "#define bgfxShadow2D(_sampler, _coord) vec4_splat(texture(_sampler, _coord))\n" + "#define bgfxShadow2DProj(_sampler, _coord) vec4_splat(textureProj(_sampler, _coord))\n" + ); + } + else + { + bx::stringPrintf(code + , "#define bgfxShadow2D shadow2D\n" + "#define bgfxShadow2DProj shadow2DProj\n" + ); + } } else { @@ -1967,12 +1927,12 @@ namespace bgfx { bx::stringPrintf(code , "#extension GL_EXT_shader_texture_lod : enable\n" - "#define texture2DLod texture2DLodEXT\n" - "#define texture2DGrad texture2DGradEXT\n" - "#define texture2DProjLod texture2DProjLodEXT\n" - "#define texture2DProjGrad texture2DProjGradEXT\n" - "#define textureCubeLod textureCubeLodEXT\n" - "#define textureCubeGrad textureCubeGradEXT\n" + "#define texture2DLod texture2DLodEXT\n" + "#define texture2DGrad texture2DGradEXT\n" + "#define texture2DProjLod texture2DProjLodEXT\n" + "#define texture2DProjGrad texture2DProjGradEXT\n" + "#define textureCubeLod textureCubeLodEXT\n" + "#define textureCubeGrad textureCubeGradEXT\n" ); } @@ -1990,8 +1950,8 @@ namespace bgfx { bx::stringPrintf(code , "#extension GL_EXT_shadow_samplers : enable\n" - "#define shadow2D shadow2DEXT\n" - "#define shadow2DProj shadow2DProjEXT\n" + "#define shadow2D shadow2DEXT\n" + "#define shadow2DProj shadow2DProjEXT\n" ); } @@ -2013,7 +1973,7 @@ namespace bgfx { bx::stringPrintf(code , "#extension GL_EXT_frag_depth : enable\n" - "#define gl_FragDepth gl_FragDepthEXT\n" + "#define gl_FragDepth gl_FragDepthEXT\n" ); } @@ -2030,74 +1990,309 @@ namespace bgfx "#define ivec4 vec4\n" ); } - - code += preprocessor.m_preprocessed; - - compiled = compileGLSLShader(cmdLine - , metal ? BX_MAKEFOURCC('M', 'T', 'L', 0) : essl - , code - , writer - ); } - else if (0 != spirv) + else { - compiled = compileSPIRVShader(cmdLine - , 0 - , preprocessor.m_preprocessed - , writer - ); + bx::stringPrintf(code, "#version %d\n", glsl); } - else if (0 != pssl) + + code += preprocessor.m_preprocessed; + + if (glsl > 400) { - compiled = compilePSSLShader(cmdLine - , 0 - , preprocessor.m_preprocessed - , writer - ); + bx::write(_writer, uint16_t(0) ); + + uint32_t shaderSize = (uint32_t)code.size(); + bx::write(_writer, shaderSize); + bx::write(_writer, code.c_str(), shaderSize); + bx::write(_writer, uint8_t(0) ); + + compiled = true; } else { - compiled = compileHLSLShader(cmdLine - , d3d - , preprocessor.m_preprocessed - , writer + compiled = compileGLSLShader(_options + , metal ? BX_MAKEFOURCC('M', 'T', 'L', 0) : essl + , code + , _writer ); } - - bx::close(writer); - delete writer; } + else if (0 != spirv) + { + compiled = compileSPIRVShader(_options + , 0 + , preprocessor.m_preprocessed + , _writer + ); + } + else if (0 != pssl) + { + compiled = compilePSSLShader(_options + , 0 + , preprocessor.m_preprocessed + , _writer + ); + } + else + { + compiled = compileHLSLShader(_options + , d3d + , preprocessor.m_preprocessed + , _writer + ); + } + } - if (compiled) + if (compiled) + { + if (_options.depends) { - if (depends) + std::string ofp = _options.outputFilePath + ".d"; + bx::FileWriter writer; + if (bx::open(&writer, ofp.c_str() ) ) { - std::string ofp = outFilePath; - ofp += ".d"; - bx::CrtFileWriter writer; - if (bx::open(&writer, ofp.c_str() ) ) - { - writef(&writer, "%s : %s\n", outFilePath, preprocessor.m_depends.c_str() ); - bx::close(&writer); - } + writef(&writer, "%s : %s\n", _options.outputFilePath.c_str(), preprocessor.m_depends.c_str() ); + bx::close(&writer); } } } } } + } + + delete [] data; + + return compiled; + } + + int compileShader(int _argc, const char* _argv[]) + { + bx::CommandLine cmdLine(_argc, _argv); + + if (cmdLine.hasArg('v', "version") ) + { + fprintf(stderr + , "shaderc, bgfx shader compiler tool, version %d.%d.%d.\n" + , BGFX_SHADERC_VERSION_MAJOR + , BGFX_SHADERC_VERSION_MINOR + , BGFX_API_VERSION + ); + return bx::kExitSuccess; + } + + if (cmdLine.hasArg('h', "help") ) + { + help(); + return bx::kExitFailure; + } + + g_verbose = cmdLine.hasArg("verbose"); + + const char* filePath = cmdLine.findOption('f'); + if (NULL == filePath) + { + help("Shader file name must be specified."); + return bx::kExitFailure; + } + + const char* outFilePath = cmdLine.findOption('o'); + if (NULL == outFilePath) + { + help("Output file name must be specified."); + return bx::kExitFailure; + } + + const char* type = cmdLine.findOption('\0', "type"); + if (NULL == type) + { + help("Must specify shader type."); + return bx::kExitFailure; + } + + Options options; + options.inputFilePath = filePath; + options.outputFilePath = outFilePath; + options.shaderType = bx::toLower(type[0]); + + options.disasm = cmdLine.hasArg('\0', "disasm"); + + const char* platform = cmdLine.findOption('\0', "platform"); + if (NULL == platform) + { + platform = ""; + } + + options.platform = platform; + + options.raw = cmdLine.hasArg('\0', "raw"); + + const char* profile = cmdLine.findOption('p', "profile"); + + if ( NULL != profile) + { + options.profile = profile; + } + + { // hlsl only + options.debugInformation = cmdLine.hasArg('\0', "debug"); + options.avoidFlowControl = cmdLine.hasArg('\0', "avoid-flow-control"); + options.noPreshader = cmdLine.hasArg('\0', "no-preshader"); + options.partialPrecision = cmdLine.hasArg('\0', "partial-precision"); + options.preferFlowControl = cmdLine.hasArg('\0', "prefer-flow-control"); + options.backwardsCompatibility = cmdLine.hasArg('\0', "backwards-compatibility"); + options.warningsAreErrors = cmdLine.hasArg('\0', "Werror"); + + uint32_t optimization = 3; + if (cmdLine.hasArg(optimization, 'O') ) + { + options.optimize = true; + options.optimizationLevel = optimization; + } + } + + const char* bin2c = NULL; + if (cmdLine.hasArg("bin2c") ) + { + bin2c = cmdLine.findOption("bin2c"); + if (NULL == bin2c) + { + bin2c = baseName(outFilePath); + uint32_t len = (uint32_t)bx::strLen(bin2c); + char* temp = (char*)alloca(len+1); + for (char *out = temp; *bin2c != '\0';) + { + char ch = *bin2c++; + if (isalnum(ch) ) + { + *out++ = ch; + } + else + { + *out++ = '_'; + } + } + temp[len] = '\0'; + + bin2c = temp; + } + } + + bool depends = cmdLine.hasArg("depends"); + options.preprocessOnly = cmdLine.hasArg("preprocess"); + const char* includeDir = cmdLine.findOption('i'); + + BX_TRACE("depends: %d", depends); + BX_TRACE("preprocessOnly: %d", options.preprocessOnly); + BX_TRACE("includeDir: %s", includeDir); + + for (int ii = 1; NULL != includeDir; ++ii) + { + options.includeDirs.push_back(includeDir); + includeDir = cmdLine.findOption(ii, 'i'); + } + + std::string dir; + { + const char* base = baseName(filePath); + + if (base != filePath) + { + dir.assign(filePath, base-filePath); + options.includeDirs.push_back(dir.c_str()); + } + } + + const char* defines = cmdLine.findOption("define"); + while (NULL != defines + && '\0' != *defines) + { + defines = bx::strws(defines); + const char* eol = bx::strFind(defines, ';'); + if (NULL == eol) + { + eol = defines + bx::strLen(defines); + } + std::string define(defines, eol); + options.defines.push_back(define.c_str() ); + defines = ';' == *eol ? eol+1 : eol; + } + + bool compiled = false; + + bx::FileReader reader; + if (!bx::open(&reader, filePath) ) + { + fprintf(stderr, "Unable to open file '%s'.\n", filePath); + } + else + { + std::string defaultVarying = dir + "varying.def.sc"; + const char* varyingdef = cmdLine.findOption("varyingdef", defaultVarying.c_str() ); + File attribdef(varyingdef); + const char* parse = attribdef.getData(); + if (NULL != parse + && *parse != '\0') + { + options.dependencies.push_back(varyingdef); + } + else + { + fprintf(stderr, "ERROR: Failed to parse varying def file: \"%s\" No input/output semantics will be generated in the code!\n", varyingdef); + } + + const size_t padding = 4096; + uint32_t size = (uint32_t)bx::getSize(&reader); + char* data = new char[size+padding+1]; + size = (uint32_t)bx::read(&reader, data, size); + + if (data[0] == '\xef' + && data[1] == '\xbb' + && data[2] == '\xbf') + { + bx::memMove(data, &data[3], size-3); + size -= 3; + } + + // Compiler generates "error X3000: syntax error: unexpected end of file" + // if input doesn't have empty line at EOF. + data[size] = '\n'; + bx::memSet(&data[size+1], 0, padding); + bx::close(&reader); + + bx::FileWriter* writer = NULL; + + if (NULL != bin2c) + { + writer = new Bin2cWriter(bin2c); + } + else + { + writer = new bx::FileWriter; + } + + if (!bx::open(writer, outFilePath) ) + { + fprintf(stderr, "Unable to open output file '%s'.", outFilePath); + return bx::kExitFailure; + } + + if ( compileShader(attribdef.getData(), data, size, options, writer) ) + compiled = true; - delete [] data; + bx::close(writer); + delete writer; } if (compiled) { - return EXIT_SUCCESS; + return bx::kExitSuccess; } remove(outFilePath); fprintf(stderr, "Failed to build shader.\n"); - return EXIT_FAILURE; + return bx::kExitFailure; } } // namespace bgfx |