| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- #include "anki/resource/ShaderProgramPrePreprocessor.h"
- #include "anki/util/Filesystem.h"
- #include "anki/util/Exception.h"
- #include "anki/util/Functions.h"
- #include <iomanip>
- #include <cstring>
- #include <iostream>
- namespace anki {
- //==============================================================================
- // Keep the strings in that order so that the start pragmas will match to the
- // ShaderType enums
- static Array<const char*, 8> commands = {{
- "#pragma anki start vertexShader",
- "#pragma anki start teShader",
- "#pragma anki start tcShader",
- "#pragma anki start geometryShader",
- "#pragma anki start fragmentShader",
- "#pragma anki include",
- "#pragma anki transformFeedbackVaryings separate",
- "#pragma anki transformFeedbackVaryings interleaved"}};
- static_assert(ST_VERTEX == 0 && ST_FRAGMENT == 4, "See file");
- static const char* ENTRYPOINT_NOT_DEFINED = "Entry point not defined: ";
- const U32 MAX_DEPTH = 8;
- //==============================================================================
- void ShaderProgramPrePreprocessor::printSourceLines() const
- {
- for(U32 i = 0; i < sourceLines.size(); ++i)
- {
- std::cout << std::setw(3) << (i + 1) << ": "
- << sourceLines[i] << std::endl;
- }
- }
- //==============================================================================
- void ShaderProgramPrePreprocessor::parseFileForPragmas(
- const std::string& filename, U32 depth)
- {
- // first check the depth
- if(depth > MAX_DEPTH)
- {
- throw ANKI_EXCEPTION("The include depth is too high. "
- "Probably circular includance. Last: " + filename);
- }
- // load file in lines
- StringList lines = readFileLines(filename.c_str());
- if(lines.size() < 1)
- {
- throw ANKI_EXCEPTION("File is empty: " + filename);
- }
- for(const std::string& line : lines)
- {
- std::string::size_type npos = 0;
- Bool expectPragmaAnki = false;
- Bool gotPragmaAnki = true;
- if(line.find("#pragma anki") == 0)
- {
- expectPragmaAnki = true;
- }
- if(line.find(commands[ST_VERTEX]) == 0)
- {
- parseStartPragma(ST_VERTEX, line);
- }
- else if(line.find(commands[ST_TC]) == 0)
- {
- parseStartPragma(ST_TC, line);
- }
- else if(line.find(commands[ST_TE]) == 0)
- {
- parseStartPragma(ST_TE, line);
- }
- else if(line.find(commands[ST_GEOMETRY]) == 0)
- {
- parseStartPragma(ST_GEOMETRY, line);
- }
- else if(line.find(commands[ST_FRAGMENT]) == 0)
- {
- parseStartPragma(ST_FRAGMENT, line);
- }
- else if((npos = line.find(commands[5])) == 0)
- {
- std::string filen = {line, strlen(commands[5]), std::string::npos};
- filen = trimString(filen, " \"");
- parseFileForPragmas(filen, depth + 1);
- }
- else if((npos = line.find(commands[6])) == 0)
- {
- std::string slist = {line, strlen(commands[6]), std::string::npos};
- trffbVaryings = StringList::splitString(slist.c_str(), ' ');
- xfbBufferMode = XFBBM_SEPARATE;
- }
- else if((npos = line.find(commands[7])) == 0)
- {
- std::string slist = {line, strlen(commands[7]), std::string::npos};
- trffbVaryings = StringList::splitString(slist.c_str(), ' ');
- xfbBufferMode = XFBBM_INTERLEAVED;
- }
- else
- {
- gotPragmaAnki = false;
- sourceLines.push_back(line);
- }
- // Sanity check
- if(expectPragmaAnki && !gotPragmaAnki)
- {
- throw ANKI_EXCEPTION("Malformed pragma anki: " + line);
- }
- }
- }
- //==============================================================================
- void ShaderProgramPrePreprocessor::parseFile(const char* filename)
- {
- try
- {
- parseFileInternal(filename);
- }
- catch(Exception& e)
- {
- throw ANKI_EXCEPTION("Loading file failed: " + filename) << e;
- }
- }
- //==============================================================================
- void ShaderProgramPrePreprocessor::parseFileInternal(const char* filename)
- {
- // parse master file
- parseFileForPragmas(filename);
- // sanity checks
- if(!shaderStarts[ST_VERTEX].isDefined())
- {
- throw ANKI_EXCEPTION(ENTRYPOINT_NOT_DEFINED
- + commands[ST_VERTEX]);
- }
- if(!shaderStarts[ST_FRAGMENT].isDefined())
- {
- throw ANKI_EXCEPTION(ENTRYPOINT_NOT_DEFINED
- + commands[ST_FRAGMENT]);
- }
- // construct each shaders' source code
- for(U i = 0; i < ST_NUM; i++)
- {
- // If not defined bb
- if(!shaderStarts[i].isDefined())
- {
- continue;
- }
- std::string& src = shaderSources[i];
- src = "";
- // Sanity check: Check the correct order of i
- I32 k = (I32)i - 1;
- while(k > -1)
- {
- if(shaderStarts[k].isDefined()
- && shaderStarts[k].definedLine >= shaderStarts[i].definedLine)
- {
- throw ANKI_EXCEPTION(commands[i] + " must be after "
- + commands[k]);
- }
- --k;
- }
- k = (I32)i + 1;
- while(k < ST_NUM)
- {
- if(shaderStarts[k].isDefined()
- && shaderStarts[k].definedLine <= shaderStarts[i].definedLine)
- {
- throw ANKI_EXCEPTION(commands[k] + " must be after "
- + commands[i]);
- }
- ++k;
- }
- // put global source code
- for(I32 j = 0; j < shaderStarts[ST_VERTEX].definedLine; ++j)
- {
- src += sourceLines[j] + "\n";
- }
- // put the actual code
- U32 from = i;
- U32 to;
- for(to = i + 1; to < ST_NUM; to++)
- {
- if(shaderStarts[to].definedLine != -1)
- {
- break;
- }
- }
- I32 toLine = (to == ST_NUM) ? sourceLines.size()
- : shaderStarts[to].definedLine;
- for(I32 j = shaderStarts[from].definedLine; j < toLine; ++j)
- {
- src += sourceLines[j] + "\n";
- }
- }
- //PRINT("vertShaderBegins.globalLine: " << vertShaderBegins.globalLine)
- //PRINT("fragShaderBegins.globalLine: " << fragShaderBegins.globalLine)
- //printSourceLines();
- //printShaderVars();
- }
- //==============================================================================
- void ShaderProgramPrePreprocessor::parseStartPragma(U32 shaderType,
- const std::string& line)
- {
- CodeBeginningPragma& pragma = shaderStarts[shaderType];
- if(pragma.definedLine != -1)
- {
- throw ANKI_EXCEPTION("Redefinition of: " + commands[shaderType]);
- }
- pragma.definedLine = sourceLines.size();
- sourceLines.push_back("//" + line);
- }
- } // end namespace anki
|