std::string OSLCompilerImpl::default_output_filename () { if (m_shader && shader_decl()) return shader_decl()->shadername().string() + ".oso"; return std::string(); }
void OSLCompilerImpl::write_oso_file (const std::string &outfilename) { ASSERT (m_osofile == NULL); m_osofile = fopen (outfilename.c_str(), "w"); if (! m_osofile) { error (ustring(), 0, "Could not open \"%s\"", outfilename.c_str()); return; } // FIXME -- remove the hard-coded version! oso ("OpenShadingLanguage %d.%02d\n", OSO_FILE_VERSION_MAJOR, OSO_FILE_VERSION_MINOR); oso ("# Compiled by oslc %s\n", OSL_LIBRARY_VERSION_STRING); ASTshader_declaration *shaderdecl = shader_decl(); oso ("%s %s", shaderdecl->shadertypename(), shaderdecl->shadername().c_str()); // FIXME -- output global hints and metadata oso ("\n"); // Output params, so they are first BOOST_FOREACH (const Symbol *s, symtab()) { if (s->symtype() == SymTypeParam || s->symtype() == SymTypeOutputParam) write_oso_symbol (s); } // Output globals, locals, temps, const BOOST_FOREACH (const Symbol *s, symtab()) { if (s->symtype() == SymTypeLocal || s->symtype() == SymTypeTemp || s->symtype() == SymTypeGlobal || s->symtype() == SymTypeConst) { // Don't bother writing symbols that are never used if (s->lastuse() >= 0) { write_oso_symbol (s); } } } // Output all opcodes int lastline = -1; ustring lastfile; ustring lastmethod ("___uninitialized___"); for (OpcodeVec::iterator op = m_ircode.begin(); op != m_ircode.end(); ++op) { if (lastmethod != op->method()) { oso ("code %s\n", op->method().c_str()); lastmethod = op->method(); lastfile = ustring(); lastline = -1; } if (/*m_debug &&*/ op->sourcefile()) { ustring file = op->sourcefile(); int line = op->sourceline(); if (file != lastfile || line != lastline) oso ("# %s:%d\n# %s\n", file.c_str(), line, retrieve_source (file, line).c_str()); } // Op name oso ("\t%s", op->opname().c_str()); // Register arguments if (op->nargs()) oso (op->opname().length() < 8 ? "\t\t" : "\t"); for (int i = 0; i < op->nargs(); ++i) { int arg = op->firstarg() + i; oso ("%s ", m_opargs[arg]->dealias()->mangled().c_str()); } // Jump targets for (size_t i = 0; i < Opcode::max_jumps; ++i) if (op->jump(i) >= 0) oso ("%d ", op->jump(i)); // // Opcode Hints // bool firsthint = true; // %filename and %line document the source code file and line that // contained code that generated this op. To avoid clutter, we // only output these hints when they DIFFER from the previous op. if (op->sourcefile()) { if (op->sourcefile() != lastfile) { lastfile = op->sourcefile(); oso ("%c%%filename{\"%s\"}", firsthint ? '\t' : ' ', lastfile.c_str()); firsthint = false; } if (op->sourceline() != lastline) { lastline = op->sourceline(); oso ("%c%%line{%d}", firsthint ? '\t' : ' ', lastline); firsthint = false; } } // %argrw documents which arguments are read, written, or both (rwW). if (op->nargs()) { oso ("%c%%argrw{\"", firsthint ? '\t' : ' '); for (int i = 0; i < op->nargs(); ++i) { if (op->argwrite(i)) oso (op->argread(i) ? "W" : "w"); else oso (op->argread(i) ? "r" : "-"); } oso ("\"}"); firsthint = false; } // %argderivs documents which arguments have derivs taken of // them by the op. if (op->argtakesderivs_all()) { oso (" %%argderivs{"); int any = 0; for (int i = 0; i < op->nargs(); ++i) if (op->argtakesderivs(i)) { if (any++) oso (","); oso ("%d", i); } oso ("}"); firsthint = false; } oso ("\n"); } if (lastmethod != main_method_name()) // If no code, still need a code marker oso ("code %s\n", main_method_name().c_str()); oso ("\tend\n"); fclose (m_osofile); m_osofile = NULL; }
bool OSLCompilerImpl::compile (const std::string &filename, const std::vector<std::string> &options) { if (! boost::filesystem::exists (filename)) { error (ustring(), 0, "Input file \"%s\" not found", filename.c_str()); return false; } std::string stdinclude; #ifdef USE_BOOST_WAVE std::vector<std::string> defines; std::vector<std::string> undefines; std::vector<std::string> includepaths; #else std::string cppoptions; #endif // Determine where the installed shader include directory is, and // look for ../shaders/stdosl.h and force it to include. std::string program = Sysutil::this_program_path (); if (program.size()) { boost::filesystem::path path (program); // our program #if BOOST_VERSION >= 103600 path = path.parent_path (); // now the bin dir of our program path = path.parent_path (); // now the parent dir #else path = path.branch_path (); // now the bin dir of our program path = path.branch_path (); // now the parent dir #endif path = path / "shaders"; bool found = false; if (boost::filesystem::exists (path)) { path = path / "stdosl.h"; if (boost::filesystem::exists (path)) { stdinclude = path.string(); found = true; } } if (! found) warning (ustring(filename), 0, "Unable to find \"%s\"", path.string().c_str()); } m_output_filename.clear (); bool preprocess_only = false; for (size_t i = 0; i < options.size(); ++i) { if (options[i] == "-v") { // verbose mode m_verbose = true; } else if (options[i] == "-q") { // quiet mode m_quiet = true; } else if (options[i] == "-d") { // debug mode m_debug = true; } else if (options[i] == "-E") { preprocess_only = true; } else if (options[i] == "-o" && i < options.size()-1) { ++i; m_output_filename = options[i]; } else if (options[i] == "-O0") { m_optimizelevel = 0; } else if (options[i] == "-O" || options[i] == "-O1") { m_optimizelevel = 1; } else if (options[i] == "-O2") { m_optimizelevel = 2; #ifdef USE_BOOST_WAVE } else if (options[i].c_str()[0] == '-' && options[i].size() > 2) { // options meant for the preprocessor if(options[i].c_str()[1] == 'D') defines.push_back(options[i].substr(2)); else if(options[i].c_str()[1] == 'U') undefines.push_back(options[i].substr(2)); else if(options[i].c_str()[1] == 'I') includepaths.push_back(options[i].substr(2)); #else } else { // something meant for the cpp command cppoptions += "\""; cppoptions += options[i]; cppoptions += "\" "; #endif } } std::string preprocess_result; #ifdef USE_BOOST_WAVE if (! preprocess(filename, stdinclude, defines, undefines, includepaths, preprocess_result)) { #else if (! preprocess(filename, stdinclude, cppoptions, preprocess_result)) { #endif return false; } else if (preprocess_only) { std::cout << preprocess_result; } else { std::istringstream in (preprocess_result); oslcompiler = this; // Create a lexer, parse the file, delete the lexer m_lexer = new oslFlexLexer (&in); oslparse (); bool parseerr = error_encountered(); delete m_lexer; if (! parseerr) { shader()->typecheck (); } // Print the parse tree if there were no errors if (m_debug) { symtab().print (); if (shader()) shader()->print (std::cout); } if (! error_encountered()) { shader()->codegen (); // add_useparam (); track_variable_dependencies (); track_variable_lifetimes (); check_for_illegal_writes (); // if (m_optimizelevel >= 1) // coalesce_temporaries (); } if (! error_encountered()) { if (m_output_filename.size() == 0) m_output_filename = default_output_filename (); write_oso_file (m_output_filename); } oslcompiler = NULL; } return ! error_encountered(); } struct GlobalTable { const char *name; TypeSpec type; }; static GlobalTable globals[] = { { "P", TypeDesc::TypePoint }, { "I", TypeDesc::TypeVector }, { "N", TypeDesc::TypeNormal }, { "Ng", TypeDesc::TypeNormal }, { "u", TypeDesc::TypeFloat }, { "v", TypeDesc::TypeFloat }, { "dPdu", TypeDesc::TypeVector }, { "dPdv", TypeDesc::TypeVector }, #if 0 // Light variables -- we don't seem to be on a route to support this // kind of light shader, so comment these out for now. { "L", TypeDesc::TypeVector }, { "Cl", TypeDesc::TypeColor }, { "Ns", TypeDesc::TypeNormal }, { "Pl", TypeDesc::TypePoint }, { "Nl", TypeDesc::TypeNormal }, #endif { "Ps", TypeDesc::TypePoint }, { "Ci", TypeSpec (TypeDesc::TypeColor, true) }, { "time", TypeDesc::TypeFloat }, { "dtime", TypeDesc::TypeFloat }, { "dPdtime", TypeDesc::TypeVector }, { NULL } }; void OSLCompilerImpl::initialize_globals () { for (int i = 0; globals[i].name; ++i) { Symbol *s = new Symbol (ustring(globals[i].name), globals[i].type, SymTypeGlobal); symtab().insert (s); } } std::string OSLCompilerImpl::default_output_filename () { if (m_shader && shader_decl()) return shader_decl()->shadername().string() + ".oso"; return std::string(); } void OSLCompilerImpl::write_oso_metadata (const ASTNode *metanode) const { ASSERT (metanode->nodetype() == ASTNode::variable_declaration_node); const ASTvariable_declaration *metavar = static_cast<const ASTvariable_declaration *>(metanode); Symbol *metasym = metavar->sym(); ASSERT (metasym); TypeSpec ts = metasym->typespec(); oso ("%%meta{%s,%s,", ts.string().c_str(), metasym->name().c_str()); const ASTNode *init = metavar->init().get(); ASSERT (init); if (ts.is_string() && init->nodetype() == ASTNode::literal_node) oso ("\"%s\"", ((const ASTliteral *)init)->strval()); else if (ts.is_int() && init->nodetype() == ASTNode::literal_node) oso ("%d", ((const ASTliteral *)init)->intval()); else if (ts.is_float() && init->nodetype() == ASTNode::literal_node) oso ("%.8g", ((const ASTliteral *)init)->floatval()); // FIXME -- what about type constructors? else { std::cout << "Error, don't know how to print metadata " << ts.string() << " with node type " << init->nodetypename() << "\n"; ASSERT (0); // FIXME } oso ("} "); }