diff options
Diffstat (limited to '3rdparty/bgfx/tools/shaderc/shaderc.cpp')
-rw-r--r-- | 3rdparty/bgfx/tools/shaderc/shaderc.cpp | 2839 |
1 files changed, 1433 insertions, 1406 deletions
diff --git a/3rdparty/bgfx/tools/shaderc/shaderc.cpp b/3rdparty/bgfx/tools/shaderc/shaderc.cpp index 4b6c7ec0ff1..915119afc91 100644 --- a/3rdparty/bgfx/tools/shaderc/shaderc.cpp +++ b/3rdparty/bgfx/tools/shaderc/shaderc.cpp @@ -4,8 +4,7 @@ */ #include "shaderc.h" - -bool g_verbose = false; +#include <bx/tokenizecmd.h> #define MAX_TAGS 256 extern "C" @@ -13,215 +12,124 @@ extern "C" #include <fpp.h> } // extern "C" -#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) - -long int fsize(FILE* _file) +namespace bgfx { - long int pos = ftell(_file); - fseek(_file, 0L, SEEK_END); - long int size = ftell(_file); - fseek(_file, pos, SEEK_SET); - return size; -} + bool g_verbose = false; -static const char* s_ARB_shader_texture_lod[] = -{ - "texture2DLod", - "texture2DProjLod", - "texture3DLod", - "texture3DProjLod", - "textureCubeLod", - "shadow2DLod", - "shadow2DProjLod", - NULL - // "texture1DLod", - // "texture1DProjLod", - // "shadow1DLod", - // "shadow1DProjLod", -}; - -static const char* s_EXT_shadow_samplers[] = -{ - "shadow2D", - "shadow2DProj", - "sampler2DShadow", - NULL -}; - -static const char* s_OES_standard_derivatives[] = -{ - "dFdx", - "dFdy", - "fwidth", - NULL -}; + #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_OES_texture_3D[] = -{ - "texture3D", - "texture3DProj", - "texture3DLod", - "texture3DProjLod", - NULL -}; - -static const char* s_130[] = -{ - "uint", - "uint2", - "uint3", - "uint4", - "isampler3D", - "usampler3D", - NULL -}; - -const char* s_uniformTypeName[UniformType::Count] = -{ - "int", - NULL, - "vec4", - "mat3", - "mat4", -}; - -const char* interpolationDx11(const char* _glsl) -{ - if (0 == strcmp(_glsl, "smooth") ) - { - return "linear"; - } - else if (0 == strcmp(_glsl, "flat") ) + long int fsize(FILE* _file) { - return "nointerpolation"; + long int pos = ftell(_file); + fseek(_file, 0L, SEEK_END); + long int size = ftell(_file); + fseek(_file, pos, SEEK_SET); + return size; } - return _glsl; // noperspective -} - -const char* getUniformTypeName(UniformType::Enum _enum) -{ - return s_uniformTypeName[_enum]; -} - -UniformType::Enum nameToUniformTypeEnum(const char* _name) -{ - for (uint32_t ii = 0; ii < UniformType::Count; ++ii) + static const char* s_ARB_shader_texture_lod[] = { - if (NULL != s_uniformTypeName[ii] - && 0 == strcmp(_name, s_uniformTypeName[ii]) ) - { - return UniformType::Enum(ii); - } - } - - return UniformType::Count; -} - -int32_t writef(bx::WriterI* _writer, const char* _format, ...) -{ - va_list argList; - va_start(argList, _format); - - char temp[2048]; - - char* out = temp; - int32_t max = sizeof(temp); - int32_t len = bx::vsnprintf(out, max, _format, argList); - if (len > max) + "texture2DLod", + "texture2DProjLod", + "texture3DLod", + "texture3DProjLod", + "textureCubeLod", + "shadow2DLod", + "shadow2DProjLod", + NULL + // "texture1DLod", + // "texture1DProjLod", + // "shadow1DLod", + // "shadow1DProjLod", + }; + + static const char* s_EXT_shadow_samplers[] = { - out = (char*)alloca(len); - len = bx::vsnprintf(out, len, _format, argList); - } + "shadow2D", + "shadow2DProj", + "sampler2DShadow", + NULL + }; - len = bx::write(_writer, out, len); - - va_end(argList); - - return len; -} - -class Bin2cWriter : public bx::CrtFileWriter -{ -public: - Bin2cWriter(const char* _name) - : m_name(_name) + static const char* s_OES_standard_derivatives[] = { - } + "dFdx", + "dFdy", + "fwidth", + NULL + }; - virtual ~Bin2cWriter() + static const char* s_OES_texture_3D[] = { - } - - virtual int32_t close() BX_OVERRIDE + "texture3D", + "texture3DProj", + "texture3DLod", + "texture3DProjLod", + NULL + }; + + static const char* s_130[] = + { + "uint", + "uint2", + "uint3", + "uint4", + "isampler3D", + "usampler3D", + NULL + }; + + const char* s_uniformTypeName[UniformType::Count] = { - generate(); - return bx::CrtFileWriter::close(); + "int", + NULL, + "vec4", + "mat3", + "mat4", + }; + + const char* interpolationDx11(const char* _glsl) + { + if (0 == strcmp(_glsl, "smooth") ) + { + return "linear"; + } + else if (0 == strcmp(_glsl, "flat") ) + { + return "nointerpolation"; + } + + return _glsl; // noperspective } - virtual int32_t write(const void* _data, int32_t _size) BX_OVERRIDE + const char* getUniformTypeName(UniformType::Enum _enum) { - const char* data = (const char*)_data; - m_buffer.insert(m_buffer.end(), data, data+_size); - return _size; + return s_uniformTypeName[_enum]; } -private: - void generate() + UniformType::Enum nameToUniformTypeEnum(const char* _name) { -#define HEX_DUMP_WIDTH 16 -#define HEX_DUMP_SPACE_WIDTH 96 -#define HEX_DUMP_FORMAT "%-" BX_STRINGIZE(HEX_DUMP_SPACE_WIDTH) "." BX_STRINGIZE(HEX_DUMP_SPACE_WIDTH) "s" - const uint8_t* data = &m_buffer[0]; - uint32_t size = (uint32_t)m_buffer.size(); - - outf("static const uint8_t %s[%d] =\n{\n", m_name.c_str(), size); - - if (NULL != data) + for (uint32_t ii = 0; ii < UniformType::Count; ++ii) { - char hex[HEX_DUMP_SPACE_WIDTH+1]; - char ascii[HEX_DUMP_WIDTH+1]; - uint32_t hexPos = 0; - uint32_t asciiPos = 0; - for (uint32_t ii = 0; ii < size; ++ii) - { - bx::snprintf(&hex[hexPos], sizeof(hex)-hexPos, "0x%02x, ", data[asciiPos]); - hexPos += 6; - - ascii[asciiPos] = isprint(data[asciiPos]) && data[asciiPos] != '\\' ? data[asciiPos] : '.'; - asciiPos++; - - if (HEX_DUMP_WIDTH == asciiPos) - { - ascii[asciiPos] = '\0'; - outf("\t" HEX_DUMP_FORMAT "// %s\n", hex, ascii); - data += asciiPos; - hexPos = 0; - asciiPos = 0; - } - } - - if (0 != asciiPos) + if (NULL != s_uniformTypeName[ii] + && 0 == strcmp(_name, s_uniformTypeName[ii]) ) { - ascii[asciiPos] = '\0'; - outf("\t" HEX_DUMP_FORMAT "// %s\n", hex, ascii); + return UniformType::Enum(ii); } } - outf("};\n"); -#undef HEX_DUMP_WIDTH -#undef HEX_DUMP_SPACE_WIDTH -#undef HEX_DUMP_FORMAT + return UniformType::Count; } - int32_t outf(const char* _format, ...) + int32_t writef(bx::WriterI* _writer, const char* _format, ...) { va_list argList; va_start(argList, _format); char temp[2048]; + char* out = temp; int32_t max = sizeof(temp); int32_t len = bx::vsnprintf(out, max, _format, argList); @@ -231,1584 +139,1703 @@ private: len = bx::vsnprintf(out, len, _format, argList); } - int32_t size = bx::CrtFileWriter::write(out, len); + len = bx::write(_writer, out, len); va_end(argList); - return size; + return len; } - std::string m_filePath; - std::string m_name; - typedef std::vector<uint8_t> Buffer; - Buffer m_buffer; -}; - -struct Varying -{ - std::string m_precision; - std::string m_interpolation; - std::string m_name; - std::string m_type; - std::string m_init; - std::string m_semantics; -}; - -typedef std::unordered_map<std::string, Varying> VaryingMap; - -class File -{ -public: - File(const char* _filePath) - : m_data(NULL) + class Bin2cWriter : public bx::CrtFileWriter { - FILE* file = fopen(_filePath, "r"); - if (NULL != file) + public: + Bin2cWriter(const char* _name) + : m_name(_name) { - m_size = fsize(file); - m_data = new char[m_size+1]; - m_size = (uint32_t)fread(m_data, 1, m_size, file); - m_data[m_size] = '\0'; - fclose(file); } - } - ~File() - { - delete [] m_data; - } - - const char* getData() const - { - return m_data; - } + virtual ~Bin2cWriter() + { + } - uint32_t getSize() const - { - return m_size; - } + virtual void close() BX_OVERRIDE + { + generate(); + return bx::CrtFileWriter::close(); + } -private: - char* m_data; - uint32_t m_size; -}; + virtual int32_t write(const void* _data, int32_t _size, bx::Error*) BX_OVERRIDE + { + const char* data = (const char*)_data; + m_buffer.insert(m_buffer.end(), data, data+_size); + return _size; + } -void strInsert(char* _str, const char* _insert) -{ - size_t len = strlen(_insert); - memmove(&_str[len], _str, strlen(_str) ); - memcpy(_str, _insert, len); -} + private: + void generate() + { +#define HEX_DUMP_WIDTH 16 +#define HEX_DUMP_SPACE_WIDTH 96 +#define HEX_DUMP_FORMAT "%-" BX_STRINGIZE(HEX_DUMP_SPACE_WIDTH) "." BX_STRINGIZE(HEX_DUMP_SPACE_WIDTH) "s" + const uint8_t* data = &m_buffer[0]; + uint32_t size = (uint32_t)m_buffer.size(); -void strReplace(char* _str, const char* _find, const char* _replace) -{ - const size_t len = strlen(_find); + outf("static const uint8_t %s[%d] =\n{\n", m_name.c_str(), size); - char* replace = (char*)alloca(len+1); - bx::strlcpy(replace, _replace, len+1); - for (size_t ii = strlen(replace); ii < len; ++ii) - { - replace[ii] = ' '; - } - replace[len] = '\0'; + if (NULL != data) + { + char hex[HEX_DUMP_SPACE_WIDTH+1]; + char ascii[HEX_DUMP_WIDTH+1]; + uint32_t hexPos = 0; + uint32_t asciiPos = 0; + for (uint32_t ii = 0; ii < size; ++ii) + { + bx::snprintf(&hex[hexPos], sizeof(hex)-hexPos, "0x%02x, ", data[asciiPos]); + hexPos += 6; - BX_CHECK(len >= strlen(_replace), ""); - for (char* ptr = strstr(_str, _find); NULL != ptr; ptr = strstr(ptr + len, _find) ) - { - memcpy(ptr, replace, len); - } -} + ascii[asciiPos] = isprint(data[asciiPos]) && data[asciiPos] != '\\' ? data[asciiPos] : '.'; + asciiPos++; -void strNormalizeEol(char* _str) -{ - strReplace(_str, "\r\n", "\n"); - strReplace(_str, "\r", "\n"); -} + if (HEX_DUMP_WIDTH == asciiPos) + { + ascii[asciiPos] = '\0'; + outf("\t" HEX_DUMP_FORMAT "// %s\n", hex, ascii); + data += asciiPos; + hexPos = 0; + asciiPos = 0; + } + } -void printCode(const char* _code, int32_t _line, int32_t _start, int32_t _end) -{ - fprintf(stderr, "Code:\n---\n"); + if (0 != asciiPos) + { + ascii[asciiPos] = '\0'; + outf("\t" HEX_DUMP_FORMAT "// %s\n", hex, ascii); + } + } - LineReader lr(_code); - for (int32_t line = 1; !lr.isEof() && line < _end; ++line) - { - if (line >= _start) - { - fprintf(stderr, "%s%3d: %s", _line == line ? ">>> " : " ", line, lr.getLine().c_str() ); - } - else - { - lr.skipLine(); + outf("};\n"); +#undef HEX_DUMP_WIDTH +#undef HEX_DUMP_SPACE_WIDTH +#undef HEX_DUMP_FORMAT } - } - - fprintf(stderr, "---\n"); -} -void writeFile(const char* _filePath, const void* _data, int32_t _size) -{ - bx::CrtFileWriter out; - if (0 == out.open(_filePath) ) - { - out.write(_data, _size); - out.close(); - } -} + int32_t outf(const char* _format, ...) + { + va_list argList; + va_start(argList, _format); + + char temp[2048]; + char* out = temp; + int32_t max = sizeof(temp); + int32_t len = bx::vsnprintf(out, max, _format, argList); + if (len > max) + { + out = (char*)alloca(len); + len = bx::vsnprintf(out, len, _format, argList); + } -struct Preprocessor -{ - Preprocessor(const char* _filePath, bool _gles, const char* _includeDir = NULL) - : m_tagptr(m_tags) - , m_scratchPos(0) - , m_fgetsPos(0) - { - m_tagptr->tag = FPPTAG_USERDATA; - m_tagptr->data = this; - m_tagptr++; + bx::Error err; + int32_t size = bx::CrtFileWriter::write(out, len, &err); - m_tagptr->tag = FPPTAG_DEPENDS; - m_tagptr->data = (void*)fppDepends; - m_tagptr++; + va_end(argList); - m_tagptr->tag = FPPTAG_INPUT; - m_tagptr->data = (void*)fppInput; - m_tagptr++; + return size; + } - m_tagptr->tag = FPPTAG_OUTPUT; - m_tagptr->data = (void*)fppOutput; - m_tagptr++; + std::string m_filePath; + std::string m_name; + typedef std::vector<uint8_t> Buffer; + Buffer m_buffer; + }; - m_tagptr->tag = FPPTAG_ERROR; - m_tagptr->data = (void*)fppError; - m_tagptr++; + struct Varying + { + std::string m_precision; + std::string m_interpolation; + std::string m_name; + std::string m_type; + std::string m_init; + std::string m_semantics; + }; - m_tagptr->tag = FPPTAG_IGNOREVERSION; - m_tagptr->data = (void*)0; - m_tagptr++; + typedef std::unordered_map<std::string, Varying> VaryingMap; - m_tagptr->tag = FPPTAG_LINE; - m_tagptr->data = (void*)0; - m_tagptr++; + class File + { + public: + File(const char* _filePath) + : m_data(NULL) + { + FILE* file = fopen(_filePath, "r"); + if (NULL != file) + { + m_size = fsize(file); + m_data = new char[m_size+1]; + m_size = (uint32_t)fread(m_data, 1, m_size, file); + m_data[m_size] = '\0'; + fclose(file); + } + } - m_tagptr->tag = FPPTAG_INPUT_NAME; - m_tagptr->data = scratch(_filePath); - m_tagptr++; + ~File() + { + delete [] m_data; + } - if (NULL != _includeDir) + const char* getData() const { - addInclude(_includeDir); + return m_data; } - if (!_gles) + uint32_t getSize() const { - m_default = "#define lowp\n#define mediump\n#define highp\n"; + return m_size; } - } - void setDefine(const char* _define) + private: + char* m_data; + uint32_t m_size; + }; + + void strInsert(char* _str, const char* _insert) { - m_tagptr->tag = FPPTAG_DEFINE; - m_tagptr->data = scratch(_define); - m_tagptr++; + size_t len = strlen(_insert); + memmove(&_str[len], _str, strlen(_str) ); + memcpy(_str, _insert, len); } - void setDefaultDefine(const char* _name) + void strReplace(char* _str, const char* _find, const char* _replace) { - char temp[1024]; - bx::snprintf(temp, BX_COUNTOF(temp) - , "#ifndef %s\n" - "# define %s 0\n" - "#endif // %s\n" - "\n" - , _name - , _name - , _name - ); + const size_t len = strlen(_find); - m_default += temp; + char* replace = (char*)alloca(len+1); + bx::strlcpy(replace, _replace, len+1); + for (size_t ii = strlen(replace); ii < len; ++ii) + { + replace[ii] = ' '; + } + replace[len] = '\0'; + + BX_CHECK(len >= strlen(_replace), ""); + for (char* ptr = strstr(_str, _find); NULL != ptr; ptr = strstr(ptr + len, _find) ) + { + memcpy(ptr, replace, len); + } } - void writef(const char* _format, ...) + void strNormalizeEol(char* _str) { - va_list argList; - va_start(argList, _format); - bx::stringPrintfVargs(m_default, _format, argList); - va_end(argList); + strReplace(_str, "\r\n", "\n"); + strReplace(_str, "\r", "\n"); } - void addInclude(const char* _includeDir) + void printCode(const char* _code, int32_t _line, int32_t _start, int32_t _end) { - char* start = scratch(_includeDir); + fprintf(stderr, "Code:\n---\n"); - for (char* split = strchr(start, ';'); NULL != split; split = strchr(start, ';')) + LineReader lr(_code); + for (int32_t line = 1; !lr.isEof() && line < _end; ++line) { - *split = '\0'; - m_tagptr->tag = FPPTAG_INCLUDE_DIR; - m_tagptr->data = start; - m_tagptr++; - start = split + 1; + if (line >= _start) + { + fprintf(stderr, "%s%3d: %s", _line == line ? ">>> " : " ", line, lr.getLine().c_str() ); + } + else + { + lr.skipLine(); + } } - m_tagptr->tag = FPPTAG_INCLUDE_DIR; - m_tagptr->data = start; - m_tagptr++; + fprintf(stderr, "---\n"); } - void addDependency(const char* _fileName) + void writeFile(const char* _filePath, const void* _data, int32_t _size) { - m_depends += " \\\n "; - m_depends += _fileName; + bx::CrtFileWriter out; + if (bx::open(&out, _filePath) ) + { + bx::write(&out, _data, _size); + bx::close(&out); + } } - bool run(const char* _input) + struct Preprocessor { - m_fgetsPos = 0; + Preprocessor(const char* _filePath, bool _gles, const char* _includeDir = NULL) + : m_tagptr(m_tags) + , m_scratchPos(0) + , m_fgetsPos(0) + { + m_tagptr->tag = FPPTAG_USERDATA; + m_tagptr->data = this; + m_tagptr++; - m_preprocessed.clear(); - m_input = m_default; - m_input += "\n\n"; + m_tagptr->tag = FPPTAG_DEPENDS; + m_tagptr->data = (void*)fppDepends; + m_tagptr++; - size_t len = strlen(_input)+1; - char* temp = new char[len]; - bx::eolLF(temp, len, _input); - m_input += temp; - delete [] temp; + m_tagptr->tag = FPPTAG_INPUT; + m_tagptr->data = (void*)fppInput; + m_tagptr++; - fppTag* tagptr = m_tagptr; + m_tagptr->tag = FPPTAG_OUTPUT; + m_tagptr->data = (void*)fppOutput; + m_tagptr++; - tagptr->tag = FPPTAG_END; - tagptr->data = 0; - tagptr++; + m_tagptr->tag = FPPTAG_ERROR; + m_tagptr->data = (void*)fppError; + m_tagptr++; - int result = fppPreProcess(m_tags); + m_tagptr->tag = FPPTAG_IGNOREVERSION; + m_tagptr->data = (void*)0; + m_tagptr++; - return 0 == result; - } + m_tagptr->tag = FPPTAG_LINE; + m_tagptr->data = (void*)0; + m_tagptr++; - char* fgets(char* _buffer, int _size) - { - int ii = 0; - for (char ch = m_input[m_fgetsPos]; m_fgetsPos < m_input.size() && ii < _size-1; ch = m_input[++m_fgetsPos]) - { - _buffer[ii++] = ch; + m_tagptr->tag = FPPTAG_INPUT_NAME; + m_tagptr->data = scratch(_filePath); + m_tagptr++; + + if (NULL != _includeDir) + { + addInclude(_includeDir); + } - if (ch == '\n' || ii == _size) + if (!_gles) { - _buffer[ii] = '\0'; - m_fgetsPos++; - return _buffer; + m_default = "#define lowp\n#define mediump\n#define highp\n"; } } - return NULL; - } + void setDefine(const char* _define) + { + m_tagptr->tag = FPPTAG_DEFINE; + m_tagptr->data = scratch(_define); + m_tagptr++; + } - static void fppDepends(char* _fileName, void* _userData) - { - Preprocessor* thisClass = (Preprocessor*)_userData; - thisClass->addDependency(_fileName); - } + void setDefaultDefine(const char* _name) + { + char temp[1024]; + bx::snprintf(temp, BX_COUNTOF(temp) + , "#ifndef %s\n" + "# define %s 0\n" + "#endif // %s\n" + "\n" + , _name + , _name + , _name + ); + + m_default += temp; + } - static char* fppInput(char* _buffer, int _size, void* _userData) - { - Preprocessor* thisClass = (Preprocessor*)_userData; - return thisClass->fgets(_buffer, _size); - } + void writef(const char* _format, ...) + { + va_list argList; + va_start(argList, _format); + bx::stringPrintfVargs(m_default, _format, argList); + va_end(argList); + } - static void fppOutput(int _ch, void* _userData) - { - Preprocessor* thisClass = (Preprocessor*)_userData; - thisClass->m_preprocessed += _ch; - } + void addInclude(const char* _includeDir) + { + char* start = scratch(_includeDir); - static void fppError(void* /*_userData*/, char* _format, va_list _vargs) - { - vfprintf(stderr, _format, _vargs); - } + for (char* split = strchr(start, ';'); NULL != split; split = strchr(start, ';') ) + { + *split = '\0'; + m_tagptr->tag = FPPTAG_INCLUDE_DIR; + m_tagptr->data = start; + m_tagptr++; + start = split + 1; + } - char* scratch(const char* _str) - { - char* result = &m_scratch[m_scratchPos]; - strcpy(result, _str); - m_scratchPos += (uint32_t)strlen(_str)+1; + m_tagptr->tag = FPPTAG_INCLUDE_DIR; + m_tagptr->data = start; + m_tagptr++; + } - return result; - } + void addDependency(const char* _fileName) + { + m_depends += " \\\n "; + m_depends += _fileName; + } - fppTag m_tags[MAX_TAGS]; - fppTag* m_tagptr; + bool run(const char* _input) + { + m_fgetsPos = 0; - std::string m_depends; - std::string m_default; - std::string m_input; - std::string m_preprocessed; - char m_scratch[16<<10]; - uint32_t m_scratchPos; - uint32_t m_fgetsPos; -}; + m_preprocessed.clear(); + m_input = m_default; + m_input += "\n\n"; -typedef std::vector<std::string> InOut; + size_t len = strlen(_input)+1; + char* temp = new char[len]; + bx::eolLF(temp, len, _input); + m_input += temp; + delete [] temp; -uint32_t parseInOut(InOut& _inout, const char* _str, const char* _eol) -{ - uint32_t hash = 0; - _str = bx::strws(_str); + fppTag* tagptr = m_tagptr; - if (_str < _eol) - { - const char* delim; - do + tagptr->tag = FPPTAG_END; + tagptr->data = 0; + tagptr++; + + int result = fppPreProcess(m_tags); + + return 0 == result; + } + + char* fgets(char* _buffer, int _size) { - delim = strpbrk(_str, " ,"); - if (NULL != delim) + int ii = 0; + for (char ch = m_input[m_fgetsPos]; m_fgetsPos < m_input.size() && ii < _size-1; ch = m_input[++m_fgetsPos]) { - delim = delim > _eol ? _eol : delim; - std::string token; - token.assign(_str, delim-_str); - _inout.push_back(token); - _str = bx::strws(delim + 1); + _buffer[ii++] = ch; + + if (ch == '\n' || ii == _size) + { + _buffer[ii] = '\0'; + m_fgetsPos++; + return _buffer; + } } + + return NULL; } - while (delim < _eol && _str < _eol && NULL != delim); - std::sort(_inout.begin(), _inout.end() ); + static void fppDepends(char* _fileName, void* _userData) + { + Preprocessor* thisClass = (Preprocessor*)_userData; + thisClass->addDependency(_fileName); + } - bx::HashMurmur2A murmur; - murmur.begin(); - for (InOut::const_iterator it = _inout.begin(), itEnd = _inout.end(); it != itEnd; ++it) + static char* fppInput(char* _buffer, int _size, void* _userData) { - murmur.add(it->c_str(), (uint32_t)it->size() ); + Preprocessor* thisClass = (Preprocessor*)_userData; + return thisClass->fgets(_buffer, _size); } - hash = murmur.end(); - } - return hash; -} + static void fppOutput(int _ch, void* _userData) + { + Preprocessor* thisClass = (Preprocessor*)_userData; + thisClass->m_preprocessed += _ch; + } -void addFragData(Preprocessor& _preprocessor, char* _data, uint32_t _idx, bool _comma) -{ - char find[32]; - bx::snprintf(find, sizeof(find), "gl_FragData[%d]", _idx); + static void fppError(void* /*_userData*/, char* _format, va_list _vargs) + { + vfprintf(stderr, _format, _vargs); + } - char replace[32]; - bx::snprintf(replace, sizeof(replace), "gl_FragData_%d_", _idx); + char* scratch(const char* _str) + { + char* result = &m_scratch[m_scratchPos]; + strcpy(result, _str); + m_scratchPos += (uint32_t)strlen(_str)+1; - strReplace(_data, find, replace); + return result; + } - _preprocessor.writef( - " \\\n\t%sout vec4 gl_FragData_%d_ : SV_TARGET%d" - , _comma ? ", " : " " - , _idx - , _idx - ); -} + fppTag m_tags[MAX_TAGS]; + fppTag* m_tagptr; -void voidFragData(char* _data, uint32_t _idx) -{ - char find[32]; - bx::snprintf(find, sizeof(find), "gl_FragData[%d]", _idx); + std::string m_depends; + std::string m_default; + std::string m_input; + std::string m_preprocessed; + char m_scratch[16<<10]; + uint32_t m_scratchPos; + uint32_t m_fgetsPos; + }; - strReplace(_data, find, "bgfx_VoidFrag"); -} + typedef std::vector<std::string> InOut; -// c - compute -// d - domain -// f - fragment -// g - geometry -// h - hull -// v - vertex -// -// OpenGL #version Features Direct3D Features Shader Model -// 2.1 120 vf 9.0 vf 2.0 -// 3.0 130 -// 3.1 140 -// 3.2 150 vgf -// 3.3 330 10.0 vgf 4.0 -// 4.0 400 vhdgf -// 4.1 410 -// 4.2 420 11.0 vhdgf+c 5.0 -// 4.3 430 vhdgf+c -// 4.4 440 - -void help(const char* _error = NULL) -{ - if (NULL != _error) + uint32_t parseInOut(InOut& _inout, const char* _str, const char* _eol) { - fprintf(stderr, "Error:\n%s\n\n", _error); - } + uint32_t hash = 0; + _str = bx::strws(_str); - fprintf(stderr - , "shaderc, bgfx shader compiler tool\n" - "Copyright 2011-2016 Branimir Karadzic. All rights reserved.\n" - "License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause\n\n" - ); - - fprintf(stderr - , "Usage: shaderc -f <in> -o <out> --type <v/f> --platform <platform>\n" - - "\n" - "Options:\n" - " -f <file path> Input file path.\n" - " -i <include path> Include path (for multiple paths use semicolon).\n" - " -o <file path> Output file path.\n" - " --bin2c <file path> Generate C header file.\n" - " --depends Generate makefile style depends file.\n" - " --platform <platform> Target platform.\n" - " android\n" - " asm.js\n" - " ios\n" - " linux\n" - " nacl\n" - " osx\n" - " windows\n" - " --preprocess Preprocess only.\n" - " --raw Do not process shader. No preprocessor, and no glsl-optimizer (GLSL only).\n" - " --type <type> Shader type (vertex, fragment)\n" - " --varyingdef <file path> Path to varying.def.sc file.\n" - " --verbose Verbose.\n" - - "\n" - "Options (DX9 and DX11 only):\n" - - "\n" - " --debug Debug information.\n" - " --disasm Disassemble compiled shader.\n" - " -p, --profile <profile> Shader model (f.e. ps_3_0).\n" - " -O <level> Optimization level (0, 1, 2, 3).\n" - " --Werror Treat warnings as errors.\n" - - "\n" - "For additional information, see https://github.com/bkaradzic/bgfx\n" - ); -} + if (_str < _eol) + { + const char* delim; + do + { + delim = strpbrk(_str, " ,"); + if (NULL != delim) + { + delim = delim > _eol ? _eol : delim; + std::string token; + token.assign(_str, delim-_str); + _inout.push_back(token); + _str = bx::strws(delim + 1); + } + } + while (delim < _eol && _str < _eol && NULL != delim); -int main(int _argc, const char* _argv[]) -{ - bx::CommandLine cmdLine(_argc, _argv); + std::sort(_inout.begin(), _inout.end() ); - if (cmdLine.hasArg('h', "help") ) - { - help(); - return EXIT_FAILURE; - } + bx::HashMurmur2A murmur; + murmur.begin(); + for (InOut::const_iterator it = _inout.begin(), itEnd = _inout.end(); it != itEnd; ++it) + { + murmur.add(it->c_str(), (uint32_t)it->size() ); + } + hash = murmur.end(); + } - g_verbose = cmdLine.hasArg("verbose"); + return hash; + } - const char* filePath = cmdLine.findOption('f'); - if (NULL == filePath) + void addFragData(Preprocessor& _preprocessor, char* _data, uint32_t _idx, bool _comma) { - help("Shader file name must be specified."); - return EXIT_FAILURE; + char find[32]; + bx::snprintf(find, sizeof(find), "gl_FragData[%d]", _idx); + + char replace[32]; + bx::snprintf(replace, sizeof(replace), "gl_FragData_%d_", _idx); + + strReplace(_data, find, replace); + + _preprocessor.writef( + " \\\n\t%sout vec4 gl_FragData_%d_ : SV_TARGET%d" + , _comma ? ", " : " " + , _idx + , _idx + ); } - const char* outFilePath = cmdLine.findOption('o'); - if (NULL == outFilePath) + void voidFragData(char* _data, uint32_t _idx) { - help("Output file name must be specified."); - return EXIT_FAILURE; + char find[32]; + bx::snprintf(find, sizeof(find), "gl_FragData[%d]", _idx); + + strReplace(_data, find, "bgfx_VoidFrag"); } - const char* type = cmdLine.findOption('\0', "type"); - if (NULL == type) + // c - compute + // d - domain + // f - fragment + // g - geometry + // h - hull + // v - vertex + // + // OpenGL #version Features Direct3D Features Shader Model + // 2.1 120 vf 9.0 vf 2.0 + // 3.0 130 + // 3.1 140 + // 3.2 150 vgf + // 3.3 330 10.0 vgf 4.0 + // 4.0 400 vhdgf + // 4.1 410 + // 4.2 420 11.0 vhdgf+c 5.0 + // 4.3 430 vhdgf+c + // 4.4 440 + + void help(const char* _error = NULL) { - help("Must specify shader type."); - return EXIT_FAILURE; + if (NULL != _error) + { + fprintf(stderr, "Error:\n%s\n\n", _error); + } + + fprintf(stderr + , "shaderc, bgfx shader compiler tool\n" + "Copyright 2011-2016 Branimir Karadzic. All rights reserved.\n" + "License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause\n\n" + ); + + fprintf(stderr + , "Usage: shaderc -f <in> -o <out> --type <v/f> --platform <platform>\n" + + "\n" + "Options:\n" + " -f <file path> Input file path.\n" + " -i <include path> Include path (for multiple paths use semicolon).\n" + " -o <file path> Output file path.\n" + " --bin2c <file path> Generate C header file.\n" + " --depends Generate makefile style depends file.\n" + " --platform <platform> Target platform.\n" + " android\n" + " asm.js\n" + " ios\n" + " linux\n" + " nacl\n" + " osx\n" + " windows\n" + " --preprocess Preprocess only.\n" + " --define <defines> Add defines to preprocessor (semicolon separated).\n" + " --raw Do not process shader. No preprocessor, and no glsl-optimizer (GLSL only).\n" + " --type <type> Shader type (vertex, fragment)\n" + " --varyingdef <file path> Path to varying.def.sc file.\n" + " --verbose Verbose.\n" + + "\n" + "Options (DX9 and DX11 only):\n" + + "\n" + " --debug Debug information.\n" + " --disasm Disassemble compiled shader.\n" + " -p, --profile <profile> Shader model (f.e. ps_3_0).\n" + " -O <level> Optimization level (0, 1, 2, 3).\n" + " --Werror Treat warnings as errors.\n" + + "\n" + "For additional information, see https://github.com/bkaradzic/bgfx\n" + ); } - const char* platform = cmdLine.findOption('\0', "platform"); - if (NULL == platform) + int compileShader(int _argc, const char* _argv[]) { - help("Must specify platform."); - return EXIT_FAILURE; - } + bx::CommandLine cmdLine(_argc, _argv); - bool raw = cmdLine.hasArg('\0', "raw"); + if (cmdLine.hasArg('h', "help") ) + { + help(); + return EXIT_FAILURE; + } - uint32_t glsl = 0; - uint32_t essl = 0; - uint32_t hlsl = 2; - uint32_t d3d = 11; - uint32_t metal = 0; - const char* profile = cmdLine.findOption('p', "profile"); - if (NULL != profile) - { - if (0 == strncmp(&profile[1], "s_4_0_level", 11) ) + g_verbose = cmdLine.hasArg("verbose"); + + const char* filePath = cmdLine.findOption('f'); + if (NULL == filePath) { - hlsl = 2; + help("Shader file name must be specified."); + return EXIT_FAILURE; } - else if (0 == strncmp(&profile[1], "s_3", 3) ) + + const char* outFilePath = cmdLine.findOption('o'); + if (NULL == outFilePath) { - hlsl = 3; - d3d = 9; + help("Output file name must be specified."); + return EXIT_FAILURE; } - else if (0 == strncmp(&profile[1], "s_4", 3) ) + + const char* type = cmdLine.findOption('\0', "type"); + if (NULL == type) { - hlsl = 4; + help("Must specify shader type."); + return EXIT_FAILURE; } - else if (0 == strncmp(&profile[1], "s_5", 3) ) + + const char* platform = cmdLine.findOption('\0', "platform"); + if (NULL == platform) { - hlsl = 5; + help("Must specify platform."); + return EXIT_FAILURE; } - else if (0 == strcmp(profile, "metal") ) + + bool raw = cmdLine.hasArg('\0', "raw"); + + uint32_t glsl = 0; + uint32_t essl = 0; + uint32_t hlsl = 2; + uint32_t d3d = 11; + uint32_t metal = 0; + const char* profile = cmdLine.findOption('p', "profile"); + if (NULL != profile) { - metal = 1; + if (0 == strncmp(&profile[1], "s_4_0_level", 11) ) + { + hlsl = 2; + } + else if (0 == strncmp(&profile[1], "s_3", 3) ) + { + hlsl = 3; + d3d = 9; + } + else if (0 == strncmp(&profile[1], "s_4", 3) ) + { + hlsl = 4; + } + else if (0 == strncmp(&profile[1], "s_5", 3) ) + { + hlsl = 5; + } + else if (0 == strcmp(profile, "metal") ) + { + metal = 1; + } + else + { + glsl = atoi(profile); + } } else { - glsl = atoi(profile); + essl = 2; } - } - else - { - essl = 2; - } - const char* bin2c = NULL; - if (cmdLine.hasArg("bin2c") ) - { - bin2c = cmdLine.findOption("bin2c"); - if (NULL == bin2c) + const char* bin2c = NULL; + if (cmdLine.hasArg("bin2c") ) { - bin2c = bx::baseName(outFilePath); - uint32_t len = (uint32_t)strlen(bin2c); - char* temp = (char*)alloca(len+1); - for (char *out = temp; *bin2c != '\0';) + bin2c = cmdLine.findOption("bin2c"); + if (NULL == bin2c) { - char ch = *bin2c++; - if (isalnum(ch) ) + bin2c = bx::baseName(outFilePath); + uint32_t len = (uint32_t)strlen(bin2c); + char* temp = (char*)alloca(len+1); + for (char *out = temp; *bin2c != '\0';) { - *out++ = ch; - } - else - { - *out++ = '_'; + char ch = *bin2c++; + if (isalnum(ch) ) + { + *out++ = ch; + } + else + { + *out++ = '_'; + } } - } - temp[len] = '\0'; + temp[len] = '\0'; - bin2c = temp; + bin2c = temp; + } } - } - bool depends = cmdLine.hasArg("depends"); - bool preprocessOnly = cmdLine.hasArg("preprocess"); - const char* includeDir = cmdLine.findOption('i'); + bool depends = cmdLine.hasArg("depends"); + bool preprocessOnly = cmdLine.hasArg("preprocess"); + const char* includeDir = cmdLine.findOption('i'); - Preprocessor preprocessor(filePath, 0 != essl, includeDir); + Preprocessor preprocessor(filePath, 0 != essl, includeDir); - std::string dir; - { - const char* base = bx::baseName(filePath); + std::string dir; + { + const char* base = bx::baseName(filePath); - if (base != filePath) + if (base != filePath) + { + dir.assign(filePath, base-filePath); + preprocessor.addInclude(dir.c_str() ); + } + } + + const char* defines = cmdLine.findOption("define"); + while (NULL != defines + && '\0' != *defines) { - dir.assign(filePath, base-filePath); - preprocessor.addInclude(dir.c_str() ); + 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; } - } - 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_WINDOWS"); - preprocessor.setDefaultDefine("BX_PLATFORM_XBOX360"); -// preprocessor.setDefaultDefine("BGFX_SHADER_LANGUAGE_ESSL"); - preprocessor.setDefaultDefine("BGFX_SHADER_LANGUAGE_GLSL"); - preprocessor.setDefaultDefine("BGFX_SHADER_LANGUAGE_HLSL"); - preprocessor.setDefaultDefine("BGFX_SHADER_LANGUAGE_METAL"); - preprocessor.setDefaultDefine("BGFX_SHADER_TYPE_COMPUTE"); - preprocessor.setDefaultDefine("BGFX_SHADER_TYPE_FRAGMENT"); - preprocessor.setDefaultDefine("BGFX_SHADER_TYPE_VERTEX"); - - char glslDefine[128]; - bx::snprintf(glslDefine, BX_COUNTOF(glslDefine), "BGFX_SHADER_LANGUAGE_GLSL=%d", essl ? 1 : glsl); - - if (0 == bx::stricmp(platform, "android") ) - { - preprocessor.setDefine("BX_PLATFORM_ANDROID=1"); - preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1"); - } - else if (0 == bx::stricmp(platform, "asm.js") ) - { - preprocessor.setDefine("BX_PLATFORM_EMSCRIPTEN=1"); - preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1"); - } - else if (0 == bx::stricmp(platform, "ios") ) - { - preprocessor.setDefine("BX_PLATFORM_IOS=1"); - preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1"); - } - else if (0 == bx::stricmp(platform, "linux") ) - { - preprocessor.setDefine("BX_PLATFORM_LINUX=1"); - preprocessor.setDefine(glslDefine); - } - else if (0 == bx::stricmp(platform, "nacl") ) - { - preprocessor.setDefine("BX_PLATFORM_NACL=1"); - preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1"); - } - else if (0 == bx::stricmp(platform, "osx") ) - { - preprocessor.setDefine("BX_PLATFORM_OSX=1"); - preprocessor.setDefine(glslDefine); - char temp[256]; - bx::snprintf(temp, sizeof(temp), "BGFX_SHADER_LANGUAGE_METAL=%d", metal); - preprocessor.setDefine(temp); - } - else if (0 == bx::stricmp(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::stricmp(platform, "xbox360") ) - { - preprocessor.setDefine("BX_PLATFORM_XBOX360=1"); - preprocessor.setDefine("BGFX_SHADER_LANGUAGE_HLSL=3"); - } - else - { - fprintf(stderr, "Unknown platform %s?!", platform); - return EXIT_FAILURE; - } + 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_WINDOWS"); + preprocessor.setDefaultDefine("BX_PLATFORM_XBOX360"); + // preprocessor.setDefaultDefine("BGFX_SHADER_LANGUAGE_ESSL"); + preprocessor.setDefaultDefine("BGFX_SHADER_LANGUAGE_GLSL"); + preprocessor.setDefaultDefine("BGFX_SHADER_LANGUAGE_HLSL"); + preprocessor.setDefaultDefine("BGFX_SHADER_LANGUAGE_METAL"); + preprocessor.setDefaultDefine("BGFX_SHADER_TYPE_COMPUTE"); + preprocessor.setDefaultDefine("BGFX_SHADER_TYPE_FRAGMENT"); + preprocessor.setDefaultDefine("BGFX_SHADER_TYPE_VERTEX"); + + char glslDefine[128]; + bx::snprintf(glslDefine, BX_COUNTOF(glslDefine), "BGFX_SHADER_LANGUAGE_GLSL=%d", essl ? 1 : glsl); + + if (0 == bx::stricmp(platform, "android") ) + { + preprocessor.setDefine("BX_PLATFORM_ANDROID=1"); + preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1"); + } + else if (0 == bx::stricmp(platform, "asm.js") ) + { + preprocessor.setDefine("BX_PLATFORM_EMSCRIPTEN=1"); + preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1"); + } + else if (0 == bx::stricmp(platform, "ios") ) + { + preprocessor.setDefine("BX_PLATFORM_IOS=1"); + preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1"); + } + else if (0 == bx::stricmp(platform, "linux") ) + { + preprocessor.setDefine("BX_PLATFORM_LINUX=1"); + preprocessor.setDefine(glslDefine); + } + else if (0 == bx::stricmp(platform, "nacl") ) + { + preprocessor.setDefine("BX_PLATFORM_NACL=1"); + preprocessor.setDefine("BGFX_SHADER_LANGUAGE_GLSL=1"); + } + else if (0 == bx::stricmp(platform, "osx") ) + { + preprocessor.setDefine("BX_PLATFORM_OSX=1"); + preprocessor.setDefine(glslDefine); + char temp[256]; + bx::snprintf(temp, sizeof(temp), "BGFX_SHADER_LANGUAGE_METAL=%d", metal); + preprocessor.setDefine(temp); + } + else if (0 == bx::stricmp(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::stricmp(platform, "xbox360") ) + { + preprocessor.setDefine("BX_PLATFORM_XBOX360=1"); + preprocessor.setDefine("BGFX_SHADER_LANGUAGE_HLSL=3"); + } + else + { + fprintf(stderr, "Unknown platform %s?!", platform); + return EXIT_FAILURE; + } - preprocessor.setDefine("M_PI=3.1415926535897932384626433832795"); + preprocessor.setDefine("M_PI=3.1415926535897932384626433832795"); - char shaderType = tolower(type[0]); - switch (shaderType) - { - case 'c': - preprocessor.setDefine("BGFX_SHADER_TYPE_COMPUTE=1"); - break; + char shaderType = tolower(type[0]); + switch (shaderType) + { + case 'c': + preprocessor.setDefine("BGFX_SHADER_TYPE_COMPUTE=1"); + break; - case 'f': - preprocessor.setDefine("BGFX_SHADER_TYPE_FRAGMENT=1"); - break; + case 'f': + preprocessor.setDefine("BGFX_SHADER_TYPE_FRAGMENT=1"); + break; - case 'v': - preprocessor.setDefine("BGFX_SHADER_TYPE_VERTEX=1"); - break; + case 'v': + preprocessor.setDefine("BGFX_SHADER_TYPE_VERTEX=1"); + break; - default: - fprintf(stderr, "Unknown type: %s?!", type); - return EXIT_FAILURE; - } + default: + fprintf(stderr, "Unknown type: %s?!", type); + return EXIT_FAILURE; + } - bool compiled = false; + bool compiled = false; - FILE* file = fopen(filePath, "r"); - if (NULL == file) - { - fprintf(stderr, "Unable to open file '%s'.\n", filePath); - } - else - { - VaryingMap varyingMap; - - 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') + FILE* file = fopen(filePath, "r"); + if (NULL == file) { - preprocessor.addDependency(varyingdef); + fprintf(stderr, "Unable to open file '%s'.\n", filePath); } else { - fprintf(stderr, "ERROR: Failed to parse varying def file: \"%s\" No input/output semantics will be generated in the code!\n", varyingdef); - } - - while (NULL != parse - && *parse != '\0') - { - parse = bx::strws(parse); - const char* eol = strchr(parse, ';'); - if (NULL == eol) + VaryingMap varyingMap; + + 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') { - eol = bx::streol(parse); + preprocessor.addDependency(varyingdef); } - - if (NULL != eol) + else { - const char* precision = NULL; - const char* interpolation = NULL; - const char* typen = parse; + fprintf(stderr, "ERROR: Failed to parse varying def file: \"%s\" No input/output semantics will be generated in the code!\n", varyingdef); + } - if (0 == strncmp(typen, "lowp", 4) - || 0 == strncmp(typen, "mediump", 7) - || 0 == strncmp(typen, "highp", 5) ) + while (NULL != parse + && *parse != '\0') + { + parse = bx::strws(parse); + const char* eol = strchr(parse, ';'); + if (NULL == eol) { - precision = typen; - typen = parse = bx::strws(bx::strword(parse) ); + eol = bx::streol(parse); } - if (0 == strncmp(typen, "flat", 4) - || 0 == strncmp(typen, "smooth", 6) - || 0 == strncmp(typen, "noperspective", 13) ) + if (NULL != eol) { - interpolation = typen; - typen = parse = bx::strws(bx::strword(parse) ); - } + const char* precision = NULL; + const char* interpolation = NULL; + const char* typen = parse; - 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) + if (0 == strncmp(typen, "lowp", 4) + || 0 == strncmp(typen, "mediump", 7) + || 0 == strncmp(typen, "highp", 5) ) { - var.m_precision.assign(precision, bx::strword(precision)-precision); + precision = typen; + typen = parse = bx::strws(bx::strword(parse) ); } - if (NULL != interpolation) + if (0 == strncmp(typen, "flat", 4) + || 0 == strncmp(typen, "smooth", 6) + || 0 == strncmp(typen, "noperspective", 13) ) { - var.m_interpolation.assign(interpolation, bx::strword(interpolation)-interpolation); + interpolation = typen; + typen = parse = bx::strws(bx::strword(parse) ); } - 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") + 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) { - var.m_semantics = "BINORMAL"; - } + Varying var; + if (NULL != precision) + { + var.m_precision.assign(precision, bx::strword(precision)-precision); + } - if (assign < eol - && '=' == *assign - && init < eol) - { - var.m_init.assign(init, eol-init); + 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"; + } + + if (assign < eol + && '=' == *assign + && init < eol) + { + var.m_init.assign(init, eol-init); + } + + varyingMap.insert(std::make_pair(var.m_name, var) ); } - varyingMap.insert(std::make_pair(var.m_name, var) ); + parse = bx::strws(bx::strnl(eol) ); } - - parse = bx::strws(bx::strnl(eol) ); } - } - InOut shaderInputs; - InOut shaderOutputs; - uint32_t inputHash = 0; - uint32_t outputHash = 0; + InOut shaderInputs; + InOut shaderOutputs; + uint32_t inputHash = 0; + uint32_t outputHash = 0; - char* data; - char* input; - { - const size_t padding = 1024; - uint32_t size = (uint32_t)fsize(file); - data = new char[size+padding+1]; - size = (uint32_t)fread(data, 1, size, file); - // 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); - fclose(file); - - strNormalizeEol(data); - - input = const_cast<char*>(bx::strws(data) ); - while (input[0] == '$') + char* data; + char* input; { - 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 = 1024; + uint32_t size = (uint32_t)fsize(file); + data = new char[size+padding+1]; + size = (uint32_t)fread(data, 1, size, file); + // 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); + fclose(file); - 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) ) + strNormalizeEol(data); + + input = const_cast<char*>(bx::strws(data) ); + while (input[0] == '$') { - str += 6; - const char* comment = strstr(str, "//"); - eol = NULL != comment && comment < eol ? comment : eol; - outputHash = parseInOut(shaderOutputs, str, eol); + 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 (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; + } + + input = const_cast<char*>(bx::strws(input) ); } - else if (0 == strncmp(str, "raw", 3) ) + + if (!raw) { - raw = true; - str += 3; + // To avoid commented code being recognized as used feature, + // first preprocess pass is used to strip all comments before + // substituting code. + preprocessor.run(input); + 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); + input = data; } - - input = const_cast<char*>(bx::strws(input) ); } - if (!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(input); - 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); - input = data; - } - } + bx::CrtFileWriter* writer = NULL; - if (raw) - { - bx::CrtFileWriter* writer = NULL; - - if (NULL != bin2c) - { - writer = new Bin2cWriter(bin2c); - } - else - { - writer = new bx::CrtFileWriter; - } + if (NULL != bin2c) + { + writer = new Bin2cWriter(bin2c); + } + else + { + writer = new bx::CrtFileWriter; + } - if (0 != writer->open(outFilePath) ) - { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return EXIT_FAILURE; - } + if (!bx::open(writer, outFilePath) ) + { + fprintf(stderr, "Unable to open output file '%s'.", outFilePath); + return EXIT_FAILURE; + } - 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 ('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) - { - bx::write(writer, uint16_t(0) ); + if (0 != glsl) + { + bx::write(writer, uint16_t(0) ); - uint32_t shaderSize = (uint32_t)strlen(input); - bx::write(writer, shaderSize); - bx::write(writer, input, shaderSize); - bx::write(writer, uint8_t(0) ); + uint32_t shaderSize = (uint32_t)strlen(input); + bx::write(writer, shaderSize); + bx::write(writer, input, shaderSize); + bx::write(writer, uint8_t(0) ); - compiled = true; - } - else - { - compiled = compileHLSLShader(cmdLine, d3d, input, writer); - } + compiled = true; + } + else + { + compiled = compileHLSLShader(cmdLine, d3d, input, writer); + } - writer->close(); - delete writer; - } - else if ('c' == shaderType) // Compute - { - char* entry = strstr(input, "void main()"); - if (NULL == entry) - { - fprintf(stderr, "Shader entry point 'void main()' is not found.\n"); + bx::close(writer); + delete writer; } - else + else if ('c' == shaderType) // Compute { - if (0 != glsl - || 0 != essl - || 0 != metal) + char* entry = strstr(input, "void main()"); + if (NULL == entry) { + fprintf(stderr, "Shader entry point 'void main()' is not found.\n"); } 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" - ); - - 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) + if (0 != glsl + || 0 != essl + || 0 != metal) { - preprocessor.writef( - " \\\n\t%sint gl_LocalInvocationIndex : SV_GroupIndex" - , arg++ > 0 ? ", " : " " - ); } - - if (hasGlobalInvocationID) + else { preprocessor.writef( - " \\\n\t%sint3 gl_GlobalInvocationID : SV_DispatchThreadID" - , arg++ > 0 ? ", " : " " + "#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 (hasWorkGroupID) - { - preprocessor.writef( - " \\\n\t%sint3 gl_WorkGroupID : SV_GroupID" - , arg++ > 0 ? ", " : " " - ); - } + entry[4] = '_'; - preprocessor.writef( - " \\\n\t)\n" - ); - } + preprocessor.writef("#define void_main()"); + preprocessor.writef(" \\\n\tvoid main("); - if (preprocessor.run(input) ) - { - BX_TRACE("Input file: %s", filePath); - BX_TRACE("Output file: %s", outFilePath); + uint32_t arg = 0; - if (preprocessOnly) - { - bx::CrtFileWriter writer; + 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 (0 != writer.open(outFilePath) ) + if (hasLocalInvocationID) { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return EXIT_FAILURE; + preprocessor.writef( + " \\\n\t%sint3 gl_LocalInvocationID : SV_GroupThreadID" + , arg++ > 0 ? ", " : " " + ); } - writer.write(preprocessor.m_preprocessed.c_str(), (int32_t)preprocessor.m_preprocessed.size() ); - writer.close(); - - return EXIT_SUCCESS; - } - - { - bx::CrtFileWriter* writer = NULL; - - if (NULL != bin2c) + if (hasLocalInvocationIndex) { - writer = new Bin2cWriter(bin2c); + preprocessor.writef( + " \\\n\t%sint gl_LocalInvocationIndex : SV_GroupIndex" + , arg++ > 0 ? ", " : " " + ); } - else + + if (hasGlobalInvocationID) { - writer = new bx::CrtFileWriter; + preprocessor.writef( + " \\\n\t%sint3 gl_GlobalInvocationID : SV_DispatchThreadID" + , arg++ > 0 ? ", " : " " + ); } - if (0 != writer->open(outFilePath) ) + if (hasWorkGroupID) { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return EXIT_FAILURE; + preprocessor.writef( + " \\\n\t%sint3 gl_WorkGroupID : SV_GroupID" + , arg++ > 0 ? ", " : " " + ); } - bx::write(writer, BGFX_CHUNK_MAGIC_CSH); - bx::write(writer, outputHash); + preprocessor.writef( + " \\\n\t)\n" + ); + } - if (0 != glsl - || 0 != essl) + if (preprocessor.run(input) ) + { + BX_TRACE("Input file: %s", filePath); + BX_TRACE("Output file: %s", outFilePath); + + if (preprocessOnly) { - std::string code; + bx::CrtFileWriter writer; - if (essl) - { - bx::stringPrintf(code, "#version 310 es\n"); - } - else + if (!bx::open(&writer, outFilePath) ) { - bx::stringPrintf(code, "#version %d\n", glsl == 0 ? 430 : glsl); + fprintf(stderr, "Unable to open output file '%s'.", outFilePath); + return EXIT_FAILURE; } - 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) ); + bx::write(&writer, preprocessor.m_preprocessed.c_str(), (int32_t)preprocessor.m_preprocessed.size() ); + bx::close(&writer); - compiled = true; -#else - compiled = compileGLSLShader(cmdLine, essl, code, writer); -#endif // 0 - } - else - { - compiled = compileHLSLShader(cmdLine, d3d, preprocessor.m_preprocessed, writer); + return EXIT_SUCCESS; } - writer->close(); - delete writer; - } - - if (compiled) - { - if (depends) { - std::string ofp = outFilePath; - ofp += ".d"; - bx::CrtFileWriter writer; - if (0 == writer.open(ofp.c_str() ) ) + bx::CrtFileWriter* writer = NULL; + + if (NULL != bin2c) { - writef(&writer, "%s : %s\n", outFilePath, preprocessor.m_depends.c_str() ); - writer.close(); + writer = new Bin2cWriter(bin2c); + } + else + { + writer = new bx::CrtFileWriter; } - } - } - } - } - } - 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) - { - if (120 == glsl - || 0 != essl) - { - preprocessor.writef( - "#define ivec2 vec2\n" - "#define ivec3 vec3\n" - "#define ivec4 vec4\n" - ); - } - 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" - ); - } + if (!bx::open(writer, outFilePath) ) + { + fprintf(stderr, "Unable to open output file '%s'.", outFilePath); + return EXIT_FAILURE; + } - 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(); + bx::write(writer, BGFX_CHUNK_MAGIC_CSH); + bx::write(writer, outputHash); - if (0 == strncmp(name, "a_", 2) - || 0 == strncmp(name, "i_", 2) ) + if (0 != glsl + || 0 != essl) { - preprocessor.writef("attribute %s %s %s %s;\n" - , var.m_precision.c_str() - , var.m_interpolation.c_str() - , var.m_type.c_str() - , name - ); + std::string code; + + 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 { - preprocessor.writef("%s varying %s %s %s;\n" - , var.m_interpolation.c_str() - , var.m_precision.c_str() - , var.m_type.c_str() - , name - ); + compiled = compileHLSLShader(cmdLine, d3d, preprocessor.m_preprocessed, writer); } + + bx::close(writer); + delete writer; } - } - 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 (compiled) { - 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() - ); + 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); + } + } } } } + } + else // Vertex/Fragment + { + char* entry = strstr(input, "void main()"); + if (NULL == entry) + { + fprintf(stderr, "Shader entry point 'void main()' is not found.\n"); + } 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 < 4) + if (0 != glsl + || 0 != essl + || 0 != metal) { - preprocessor.writef( - "#define flat\n" - "#define smooth\n" - "#define noperspective\n" - ); - } - - entry[4] = '_'; - - if ('f' == shaderType) - { - const char* brace = strstr(entry, "{"); - if (NULL != brace) + if (120 == glsl + || 0 != essl) { - strInsert(const_cast<char*>(brace+1), "\nvec4 bgfx_VoidFrag;\n"); + preprocessor.writef( + "#define ivec2 vec2\n" + "#define ivec3 vec3\n" + "#define ivec4 vec4\n" + ); } - 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) + if (0 == essl) { - char temp[32]; - bx::snprintf(temp, BX_COUNTOF(temp), "gl_FragData[%d]", ii); - hasFragData[ii] = NULL != strstr(input, temp); - numFragData += hasFragData[ii]; + // 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" + ); } - if (0 == numFragData) + for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.end(); it != itEnd; ++it) { - // 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"); - } - - preprocessor.writef("#define void_main()"); - preprocessor.writef(" \\\n\tvoid main("); - - uint32_t arg = 0; + 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 (hasFragCoord) - { - preprocessor.writef(" \\\n\tvec4 gl_FragCoord : SV_POSITION"); - ++arg; + 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 + ); + } + } } - for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.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() ) { const Varying& var = varyingIt->second; - preprocessor.writef(" \\\n\t%s%s %s %s : %s" - , arg++ > 0 ? ", " : " " - , interpolationDx11(var.m_interpolation.c_str() ) + preprocessor.writef("%s varying %s %s;\n" + , 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" + ); - addFragData(preprocessor, input, 0, arg++ > 0); + if (hlsl < 4) + { + preprocessor.writef( + "#define flat\n" + "#define smooth\n" + "#define noperspective\n" + ); + } - const uint32_t maxRT = d3d > 9 ? BX_COUNTOF(hasFragData) : 4; + entry[4] = '_'; - for (uint32_t ii = 1; ii < BX_COUNTOF(hasFragData); ++ii) + if ('f' == shaderType) { - if (ii < maxRT) + const char* brace = strstr(entry, "{"); + if (NULL != brace) { - if (hasFragData[ii]) - { - addFragData(preprocessor, input, ii, arg++ > 0); - } + strInsert(const_cast<char*>(brace+1), "\nvec4 bgfx_VoidFrag;\n"); } - else + + 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) { - voidFragData(input, ii); + char temp[32]; + bx::snprintf(temp, BX_COUNTOF(temp), "gl_FragData[%d]", ii); + hasFragData[ii] = NULL != strstr(input, temp); + numFragData += hasFragData[ii]; } - } - if (hasFragDepth) - { - preprocessor.writef( - " \\\n\t%sout float gl_FragDepth : SV_DEPTH" - , arg++ > 0 ? ", " : " " - ); - } + 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 (hasFrontFacing - && hlsl >= 3) - { - preprocessor.writef( - " \\\n\t%sfloat __vface : VFACE" - , arg++ > 0 ? ", " : " " - ); - } + preprocessor.writef("#define void_main()"); + preprocessor.writef(" \\\n\tvoid main("); - if (hasPrimitiveId) - { - if (d3d > 9) + uint32_t arg = 0; + + if (hasFragCoord) { - preprocessor.writef( - " \\\n\t%suint gl_PrimitiveID : SV_PrimitiveID" - , arg++ > 0 ? ", " : " " - ); + preprocessor.writef(" \\\n\tvec4 gl_FragCoord : SV_POSITION"); + ++arg; } - else + + for (InOut::const_iterator it = shaderInputs.begin(), itEnd = shaderInputs.end(); it != itEnd; ++it) { - fprintf(stderr, "PrimitiveID builtin is not supported by this D3D9 HLSL.\n"); - return EXIT_FAILURE; + 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() + ); + } } - } - preprocessor.writef( - " \\\n\t)\n" - ); + addFragData(preprocessor, input, 0, arg++ > 0); - if (hasFrontFacing) - { - if (hlsl >= 3) + const uint32_t maxRT = d3d > 9 ? BX_COUNTOF(hasFragData) : 4; + + for (uint32_t ii = 1; 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 gl_FrontFacing (__vface <= 0.0)\n" + " \\\n\t%sout float gl_FragDepth : SV_DEPTH" + , arg++ > 0 ? ", " : " " ); } - else + + if (hasFrontFacing + && hlsl >= 3) { preprocessor.writef( - "#define gl_FrontFacing false\n" + " \\\n\t%sfloat __vface : VFACE" + , arg++ > 0 ? ", " : " " ); } - } - } - else if ('v' == shaderType) - { - const char* brace = strstr(entry, "{"); - if (NULL != brace) - { - const char* end = bx::strmb(brace, '{', '}'); - if (NULL != end) + + if (hasPrimitiveId) { - strInsert(const_cast<char*>(end), "__RETURN__;\n"); + 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( - "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() ) + preprocessor.writef( + " \\\n\t)\n" + ); + + if (hasFrontFacing) { - 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() ); + if (hlsl >= 3) + { + preprocessor.writef( + "#define gl_FrontFacing (__vface <= 0.0)\n" + ); + } + else + { + preprocessor.writef( + "#define gl_FrontFacing false\n" + ); + } } } - 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) + else if ('v' == shaderType) { - VaryingMap::const_iterator varyingIt = varyingMap.find(*it); - if (varyingIt != varyingMap.end() ) + const char* brace = strstr(entry, "{"); + if (NULL != brace) { - 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; + const char* end = bx::strmb(brace, '{', '}'); + if (NULL != end) + { + strInsert(const_cast<char*>(end), "__RETURN__;\n"); + } } - } - preprocessor.writef( - ") \\\n" - "{ \\\n" - "\tOutput _varying_;" - ); - for (InOut::const_iterator it = shaderOutputs.begin(), itEnd = shaderOutputs.end(); it != itEnd; ++it) - { - VaryingMap::const_iterator varyingIt = varyingMap.find(*it); - if (varyingIt != varyingMap.end() ) + 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) { - const Varying& var = varyingIt->second; - preprocessor.writef(" \\\n\t%s", var.m_name.c_str() ); - if (!var.m_init.empty() ) + VaryingMap::const_iterator varyingIt = varyingMap.find(*it); + if (varyingIt != varyingMap.end() ) { - preprocessor.writef(" = %s", var.m_init.c_str() ); + 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(";"); } - } - - preprocessor.writef( - "\n#define __RETURN__ \\\n" - "\t} \\\n" - "\treturn _varying_" - ); - } - } - - if (preprocessor.run(input) ) - { - BX_TRACE("Input file: %s", filePath); - BX_TRACE("Output file: %s", outFilePath); - - if (preprocessOnly) - { - bx::CrtFileWriter writer; + preprocessor.writef( + "};\n" + ); - if (0 != writer.open(outFilePath) ) - { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return EXIT_FAILURE; - } + 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_;" + ); - if (0 != glsl) - { - if (NULL == profile) + for (InOut::const_iterator it = shaderOutputs.begin(), itEnd = shaderOutputs.end(); it != itEnd; ++it) { - writef(&writer - , "#ifdef GL_ES\n" - "precision highp float;\n" - "#endif // GL_ES\n\n" - ); + 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() ) + { + preprocessor.writef(" = %s", var.m_init.c_str() ); + } + preprocessor.writef(";"); + } } - } - writer.write(preprocessor.m_preprocessed.c_str(), (int32_t)preprocessor.m_preprocessed.size() ); - writer.close(); - return EXIT_SUCCESS; + preprocessor.writef( + "\n#define __RETURN__ \\\n" + "\t} \\\n" + "\treturn _varying_" + ); + } } + if (preprocessor.run(input) ) { - bx::CrtFileWriter* writer = NULL; + BX_TRACE("Input file: %s", filePath); + BX_TRACE("Output file: %s", outFilePath); - if (NULL != bin2c) - { - writer = new Bin2cWriter(bin2c); - } - else + if (preprocessOnly) { - writer = new bx::CrtFileWriter; - } + bx::CrtFileWriter writer; - if (0 != writer->open(outFilePath) ) - { - fprintf(stderr, "Unable to open output file '%s'.", outFilePath); - return EXIT_FAILURE; - } + if (!bx::open(&writer, outFilePath) ) + { + fprintf(stderr, "Unable to open output file '%s'.", outFilePath); + return EXIT_FAILURE; + } - 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) + { + 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 EXIT_SUCCESS; } - if (0 != glsl - || 0 != essl - || 0 != metal) { - std::string code; - - bool hasTextureLod = NULL != bx::findIdentifierMatch(input, s_ARB_shader_texture_lod /*EXT_shader_texture_lod*/); + bx::CrtFileWriter* writer = NULL; - if (0 == essl) + if (NULL != bin2c) { - const bool need130 = 120 == glsl - && bx::findIdentifierMatch(input, s_130) - ; - - if (0 != metal) - { - bx::stringPrintf(code, "#version 120\n"); - } - else - { - bx::stringPrintf(code, "#version %s\n", need130 ? "130" : profile); - } + writer = new Bin2cWriter(bin2c); + } + else + { + writer = new bx::CrtFileWriter; + } - bx::stringPrintf(code - , "#define bgfxShadow2D shadow2D\n" - "#define bgfxShadow2DProj shadow2DProj\n" - ); + if (!bx::open(writer, outFilePath) ) + { + fprintf(stderr, "Unable to open output file '%s'.", outFilePath); + return EXIT_FAILURE; + } - if (hasTextureLod - && 130 > glsl) - { - bx::stringPrintf(code - , "#extension GL_ARB_shader_texture_lod : enable\n" - ); - } + 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 { - // Pretend that all extensions are available. - // This will be stripped later. - if (hasTextureLod) + bx::write(writer, BGFX_CHUNK_MAGIC_CSH); + bx::write(writer, outputHash); + } + + if (0 != glsl + || 0 != essl + || 0 != metal) + { + std::string code; + + bool hasTextureLod = NULL != bx::findIdentifierMatch(input, s_ARB_shader_texture_lod /*EXT_shader_texture_lod*/); + + if (0 == essl) { + const bool need130 = 120 == glsl + && bx::findIdentifierMatch(input, s_130) + ; + + if (0 != metal) + { + bx::stringPrintf(code, "#version 120\n"); + } + else + { + bx::stringPrintf(code, "#version %s\n", need130 ? "130" : profile); + } + bx::stringPrintf(code - , "#extension GL_EXT_shader_texture_lod : enable\n" - "#define texture2DLod texture2DLodEXT\n" - "#define texture2DProjLod texture2DProjLodEXT\n" - "#define textureCubeLod textureCubeLodEXT\n" -// "#define texture2DGrad texture2DGradEXT\n" -// "#define texture2DProjGrad texture2DProjGradEXT\n" -// "#define textureCubeGrad textureCubeGradEXT\n" + , "#define bgfxShadow2D shadow2D\n" + "#define bgfxShadow2DProj shadow2DProj\n" ); - } - if (NULL != bx::findIdentifierMatch(input, s_OES_standard_derivatives) ) - { - bx::stringPrintf(code, "#extension GL_OES_standard_derivatives : enable\n"); + if (hasTextureLod + && 130 > glsl) + { + bx::stringPrintf(code + , "#extension GL_ARB_shader_texture_lod : enable\n" + ); + } } - - if (NULL != bx::findIdentifierMatch(input, s_OES_texture_3D) ) + else { - bx::stringPrintf(code, "#extension GL_OES_texture_3D : enable\n"); + // Pretend that all extensions are available. + // This will be stripped later. + if (hasTextureLod) + { + bx::stringPrintf(code + , "#extension GL_EXT_shader_texture_lod : enable\n" + "#define texture2DLod texture2DLodEXT\n" + "#define texture2DProjLod texture2DProjLodEXT\n" + "#define textureCubeLod textureCubeLodEXT\n" + // "#define texture2DGrad texture2DGradEXT\n" + // "#define texture2DProjGrad texture2DProjGradEXT\n" + // "#define textureCubeGrad textureCubeGradEXT\n" + ); + } + + if (NULL != bx::findIdentifierMatch(input, s_OES_standard_derivatives) ) + { + bx::stringPrintf(code, "#extension GL_OES_standard_derivatives : enable\n"); + } + + if (NULL != bx::findIdentifierMatch(input, s_OES_texture_3D) ) + { + bx::stringPrintf(code, "#extension GL_OES_texture_3D : enable\n"); + } + + if (NULL != bx::findIdentifierMatch(input, s_EXT_shadow_samplers) ) + { + bx::stringPrintf(code + , "#extension GL_EXT_shadow_samplers : enable\n" + "#define shadow2D shadow2DEXT\n" + "#define shadow2DProj shadow2DProjEXT\n" + ); + } + + if (NULL != bx::findIdentifierMatch(input, "gl_FragDepth") ) + { + bx::stringPrintf(code + , "#extension GL_EXT_frag_depth : enable\n" + "#define gl_FragDepth gl_FragDepthEXT\n" + ); + } } - if (NULL != bx::findIdentifierMatch(input, s_EXT_shadow_samplers) ) - { - bx::stringPrintf(code - , "#extension GL_EXT_shadow_samplers : enable\n" - "#define shadow2D shadow2DEXT\n" - "#define shadow2DProj shadow2DProjEXT\n" + code += preprocessor.m_preprocessed; + compiled = compileGLSLShader(cmdLine + , metal ? BX_MAKEFOURCC('M', 'T', 'L', 0) : essl + , code + , writer ); - } - - if (NULL != bx::findIdentifierMatch(input, "gl_FragDepth") ) - { - bx::stringPrintf(code - , "#extension GL_EXT_frag_depth : enable\n" - "#define gl_FragDepth gl_FragDepthEXT\n" + } + else + { + compiled = compileHLSLShader(cmdLine + , d3d + , preprocessor.m_preprocessed + , writer ); - } } - code += preprocessor.m_preprocessed; - compiled = compileGLSLShader(cmdLine - , metal ? BX_MAKEFOURCC('M', 'T', 'L', 0) : essl - , code - , writer - ); - } - else - { - compiled = compileHLSLShader(cmdLine - , d3d - , preprocessor.m_preprocessed - , writer - ); + bx::close(writer); + delete writer; } - writer->close(); - delete writer; - } - - if (compiled) - { - if (depends) + if (compiled) { - std::string ofp = outFilePath; - ofp += ".d"; - bx::CrtFileWriter writer; - if (0 == writer.open(ofp.c_str() ) ) + if (depends) { - writef(&writer, "%s : %s\n", outFilePath, preprocessor.m_depends.c_str() ); - writer.close(); + 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); + } } } } } } + + delete [] data; } - delete [] data; - } + if (compiled) + { + return EXIT_SUCCESS; + } - if (compiled) - { - return EXIT_SUCCESS; + remove(outFilePath); + + fprintf(stderr, "Failed to build shader.\n"); + return EXIT_FAILURE; } - remove(outFilePath); +} // namespace bgfx - fprintf(stderr, "Failed to build shader.\n"); - return EXIT_FAILURE; +int main(int _argc, const char* _argv[]) +{ + return bgfx::compileShader(_argc, _argv); } |