Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

GlslEmit.cpp

00001 // Sh: A GPU metaprogramming language.
00002 //
00003 // Copyright 2003-2005 Serious Hack Inc.
00004 // 
00005 // This software is provided 'as-is', without any express or implied
00006 // warranty. In no event will the authors be held liable for any damages
00007 // arising from the use of this software.
00008 // 
00009 // Permission is granted to anyone to use this software for any purpose,
00010 // including commercial applications, and to alter it and redistribute it
00011 // freely, subject to the following restrictions:
00012 // 
00013 // 1. The origin of this software must not be misrepresented; you must
00014 // not claim that you wrote the original software. If you use this
00015 // software in a product, an acknowledgment in the product documentation
00016 // would be appreciated but is not required.
00017 // 
00018 // 2. Altered source versions must be plainly marked as such, and must
00019 // not be misrepresented as being the original software.
00020 // 
00021 // 3. This notice may not be removed or altered from any source
00022 // distribution.
00024 #include "GlslCode.hpp"
00025 #include <iostream>
00026 #include <cmath>
00027 
00028 namespace shgl {
00029 
00030 using namespace SH;
00031 using namespace std;
00032 
00033 static GlslMapping opCodeTable[] = {
00034   {SH_OP_ABS,   "abs($0)"},
00035   {SH_OP_ACOS,  "acos($0)"},
00036   {SH_OP_ADD,   "$0 + $1"},
00037   {SH_OP_ASIN,  "asin($0)"},
00038   {SH_OP_ASN,   "$0"},
00039   {SH_OP_ATAN,  "atan($0)"},
00040   //{SH_OP_ATAN2, "atan($1 / $0)"}, // FIXME
00041   {SH_OP_CEIL,  "ceil($0)"},
00042   {SH_OP_COND,  "($0 > 0) ? $1 : $2"},
00043   {SH_OP_COS,   "cos($0)"},
00044   {SH_OP_DOT,   "dot($0, $1)"},
00045   {SH_OP_DIV,   "$0 / $1"},
00046   {SH_OP_DX,    "dFdx($0)"},
00047   {SH_OP_DY,    "dFdy($0)"},
00048   {SH_OP_EXP2,  "exp2($0)"},
00049   {SH_OP_FLR,   "floor($0)"},
00050   {SH_OP_FRAC,  "fract($0)"},
00051   {SH_OP_LOG2,  "log2($0)"},
00052   {SH_OP_LRP,   "mix($2, $1, $0)"},
00053   {SH_OP_MAD,   "$0 * $1 + $2"},
00054   {SH_OP_MAX,   "max($0, $1)"},
00055   {SH_OP_MIN,   "min($0, $1)"},
00056   {SH_OP_MOD,   "mod($0, $1)"},
00057   {SH_OP_MUL,   "$0 * $1"},
00058   {SH_OP_NEG,   "-($0)"},
00059   {SH_OP_NORM,  "normalize($0)"},
00060   {SH_OP_POW,   "pow($0, $1)"},
00061   {SH_OP_RCP,   "1.0 / $0"},
00062   {SH_OP_RND,   "floor($0 + 0.5)"},
00063   {SH_OP_RSQ,   "inversesqrt($0)"},
00064   {SH_OP_SGN,   "sign($0)"},
00065   {SH_OP_SIN,   "sin($0)"},
00066   {SH_OP_SQRT,  "sqrt($0)"},
00067   {SH_OP_TAN,   "tan($0)"},
00068   {SH_OP_XPD,   "cross($0, $1)"},
00069 
00070   {SH_OPERATION_END,  0} 
00071 };
00072 
00073 typedef map<SH::ShOperation, GlslOpCodeVecs> GlslOpCodeMap;
00074 
00075 GlslOpCodeVecs::GlslOpCodeVecs(const GlslMapping& mapping)
00076 {
00077   string code(mapping.code);
00078 
00079   // Dices up the code string into references #i or $i to 
00080   // src variables and the code fragments between references. 
00081   unsigned i, j;
00082   i = j = 0;
00083   for (; (j = code.find_first_of("$", i)) != string::npos;) {
00084     frag.push_back(code.substr(i, j - i));
00085     i = j + 1;
00086     j = code.find_first_not_of("012345689", i);
00087     index.push_back(atoi(code.substr(i, j - i).c_str()));
00088     i = j;
00089   }
00090   if (i == string::npos) {
00091     frag.push_back("");
00092   } else {
00093     frag.push_back(code.substr(i));
00094   }
00095 }
00096 
00097 void GlslCode::table_substitution(const ShStatement& stmt, GlslOpCodeVecs codeVecs)
00098 {
00099   stringstream line;
00100   line << resolve(stmt.dest) << " = ";
00101   line << glsl_typename(stmt.dest.valueType(), stmt.dest.size()) << "("; // cast for the destination size
00102   
00103   // find the size of the biggest parameter
00104   int param_size=0;
00105   for (unsigned i=0; i < codeVecs.index.size(); i++) {
00106     const ShVariable& src = stmt.src[codeVecs.index[i]];
00107     if (src.size() > param_size) {
00108       param_size = src.size();
00109     }
00110   }
00111 
00112   // print each parameter
00113   unsigned i;
00114   for (i=0; i < codeVecs.index.size(); i++) { 
00115     const ShVariable& src = stmt.src[codeVecs.index[i]];
00116     line << codeVecs.frag[i] << glsl_typename(src.valueType(), param_size)
00117          << "(" << resolve(src) << ")";
00118   }
00119 
00120   line << codeVecs.frag[i]; // code fragment after the last variable
00121 
00122   line << ")";
00123   append_line(line.str());
00124 }
00125 
00126 void GlslCode::emit(const ShStatement &stmt)
00127 {
00128   static GlslOpCodeMap opCodeMap;
00129 
00130   // Lazily fill-in opCodeMap from the above table
00131   if (opCodeMap.empty()) {
00132     for (int i=0; opCodeTable[i].op != SH_OPERATION_END; i++) {
00133       opCodeMap[opCodeTable[i].op] = GlslOpCodeVecs(opCodeTable[i]);
00134     }
00135   }
00136 
00137   if(opCodeMap.find(stmt.op) != opCodeMap.end()) {
00138     // Handle ops in the table first  
00139     table_substitution(stmt, opCodeMap[stmt.op]);
00140   } 
00141   else {
00142     // Handle the rest of the operations
00143     switch(stmt.op) {
00144     case SH_OP_CBRT:
00145       emit_cbrt(stmt);
00146       break;
00147     case SH_OP_CMUL:
00148       emit_prod(stmt);
00149       break;
00150     case SH_OP_CSUM:
00151       emit_sum(stmt);
00152       break;
00153     case SH_OP_EXP:
00154       emit_exp(stmt, M_E);
00155       break;
00156     case SH_OP_EXP10:
00157       emit_exp(stmt, 10);
00158       break;
00159     case SH_OP_KIL:
00160       emit_discard(stmt);
00161       break;
00162     case SH_OP_LIT:
00163       emit_lit(stmt);
00164       break;
00165     case SH_OP_LOG:
00166       emit_log(stmt, M_E);
00167       break;
00168     case SH_OP_LOG10:
00169       emit_log(stmt, 10);
00170       break;
00171     case SH_OP_PAL:
00172       emit_pal(stmt);
00173       break;
00174     case SH_OP_SEQ:
00175     case SH_OP_SGE:
00176     case SH_OP_SGT:
00177     case SH_OP_SLE:
00178     case SH_OP_SLT:
00179     case SH_OP_SNE:
00180       emit_logic(stmt);
00181       break;
00182     case SH_OP_TEX:
00183     case SH_OP_TEXI:
00184       emit_texture(stmt);
00185       break;
00186     default:
00187       shError(ShException(string("Glsl Code: Unknown operation ") + opInfo[stmt.op].name));
00188       break;
00189     }
00190   }
00191 }
00192 
00193 ShVariableNodePtr GlslCode::allocate_constant(const ShStatement& stmt, double constant, int size) const
00194 {
00195   if (size <= 0) size = stmt.dest.size(); // default size is size of destination variable
00196 
00197   const ShVariableNodePtr& dest_node = stmt.dest.node();
00198   ShVariableNode* node = new ShVariableNode(SH_CONST, size, dest_node->valueType(), dest_node->specialType());
00199   
00200   ShDataVariant<double>* variant = new ShDataVariant<double>(size, constant);
00201   node->setVariant(variant);
00202 
00203   ShVariableNodePtr node_ptr = ShPointer<ShVariableNode>(node);
00204   return node_ptr;
00205 }
00206 
00207 ShVariableNodePtr GlslCode::allocate_temp(const ShStatement& stmt, int size) const
00208 {
00209   if (size <= 0) size = stmt.dest.size(); // default size is size of destination variable
00210   
00211   const ShVariableNodePtr& dest_node = stmt.dest.node();
00212   ShVariableNode* node = new ShVariableNode(SH_TEMP, size, dest_node->valueType(), dest_node->specialType());
00213   ShVariableNodePtr node_ptr = ShPointer<ShVariableNode>(node);
00214   return node_ptr;
00215 }
00216 
00217 string GlslCode::resolve_constant(double constant, const ShVariable& var, int size) const
00218 {
00219   if (size <= 0) size = var.size(); // default size is size of variable
00220 
00221   stringstream s;
00222   s.precision(16);
00223   s << glsl_typename(var.valueType(), size);
00224 
00225   s << "(";
00226   for (int i=0; i < size; i++) {
00227     if (i > 0) s << ", ";
00228     s << constant;
00229   }
00230   s << ")";
00231 
00232   return s.str();
00233 }
00234 
00235 void GlslCode::emit_cbrt(const ShStatement& stmt)
00236 {
00237   SH_DEBUG_ASSERT(SH_OP_CBRT == stmt.op);
00238 
00239   ShVariable temp(allocate_constant(stmt, 1.0 / 3.0));
00240   append_line(resolve(stmt.dest) + " = pow(" + resolve(stmt.src[0]) + ", " + resolve(temp) + ")");
00241 }
00242 
00243 void GlslCode::emit_discard(const ShStatement& stmt)
00244 {
00245   SH_DEBUG_ASSERT(SH_OP_KIL == stmt.op);
00246 
00247   append_line(string("if (") + resolve(stmt.src[0]) + " > 0) discard");
00248 }
00249 
00250 void GlslCode::emit_exp(const ShStatement& stmt, double power)
00251 {
00252   SH_DEBUG_ASSERT((SH_OP_EXP == stmt.op) || (SH_OP_EXP10 == stmt.op));
00253 
00254   ShVariable temp(allocate_constant(stmt, power));
00255   append_line(resolve(stmt.dest) + " = pow(" + resolve(temp) + ", " + resolve(stmt.src[0]) + ")");
00256 }
00257 
00258 void GlslCode::emit_lit(const ShStatement& stmt)
00259 {
00260   SH_DEBUG_ASSERT(SH_OP_LIT == stmt.op);
00261   
00262   // Result according to OpenGL spec
00263   append_line(resolve(stmt.dest, 0) + " = " + resolve_constant(1, stmt.dest, 1));
00264 
00265   append_line(resolve(stmt.dest, 1) + " = max(" + resolve_constant(0, stmt.dest, 1) +
00266               ", " + resolve(stmt.src[0], 0) + ")");
00267 
00268   append_line(resolve(stmt.dest, 2) + " = " + resolve(stmt.src[0], 0) + 
00269               " > " + resolve_constant(0, stmt.src[0], 1) + " ? pow(max(" + 
00270               resolve_constant(0, stmt.dest, 1) + ", " + resolve(stmt.src[0], 1) + 
00271               "), clamp(" + resolve(stmt.src[0], 2) + ", " + 
00272               resolve_constant(-128, stmt.dest, 1) + ", " + 
00273               resolve_constant(128, stmt.dest, 1) + ")) : " + resolve_constant(0, stmt.dest, 1));
00274 
00275   append_line(resolve(stmt.dest, 3) + " = " + resolve_constant(1, stmt.dest, 1));
00276 }
00277 
00278 void GlslCode::emit_log(const ShStatement& stmt, double base)
00279 {
00280   SH_DEBUG_ASSERT((SH_OP_LOG == stmt.op) || (SH_OP_LOG10 == stmt.op));
00281 
00282   const double log2_base = log(base) / log(2.0);
00283 
00284   ShVariable temp(allocate_constant(stmt, log2_base)); 
00285   append_line(resolve(stmt.dest) + " = log2(" + resolve(stmt.src[0]) + ") / " + resolve(temp) + "");
00286 }
00287 
00288 void GlslCode::emit_logic(const ShStatement& stmt)
00289 {
00290   GlslMapping mapping;
00291   mapping.op = stmt.op;
00292 
00293   if ((stmt.src[0].size() > 1) || (stmt.src[1].size() > 1) ) {
00294     switch (stmt.op) {
00295     case SH_OP_SEQ:
00296       mapping.code = "equal($0, $1)";
00297       break;
00298     case SH_OP_SGT:
00299       mapping.code = "greaterThan($0, $1)";
00300       break;
00301     case SH_OP_SGE:
00302       mapping.code = "greaterThanEqual($0, $1)";
00303       break;
00304     case SH_OP_SNE:
00305       mapping.code = "notEqual($0, $1)";
00306       break;
00307     case SH_OP_SLT:
00308       mapping.code = "lessThan($0, $1)";
00309       break;
00310     case SH_OP_SLE:
00311       mapping.code = "lessThanEqual($0, $1)";
00312       break;
00313     default:
00314       SH_DEBUG_ASSERT(0);
00315     }
00316   } else {
00317     switch (stmt.op) {
00318     case SH_OP_SEQ:
00319       mapping.code = "$0 == $1";
00320       break;
00321     case SH_OP_SGT:
00322       mapping.code = "$0 > $1";
00323       break;
00324     case SH_OP_SGE:
00325       mapping.code = "$0 >= $1";
00326       break;
00327     case SH_OP_SNE:
00328       mapping.code = "$0 != $1";
00329       break;
00330     case SH_OP_SLT:
00331       mapping.code = "$0 < $1";
00332       break;
00333     case SH_OP_SLE:
00334       mapping.code = "$0 <= $1";
00335       break;
00336     default:
00337       SH_DEBUG_ASSERT(0);
00338     }
00339   }
00340 
00341   // TODO: cache these mappings
00342   
00343   table_substitution(stmt, mapping);
00344 }
00345 
00346 void GlslCode::emit_pal(const ShStatement& stmt)
00347 {
00348   SH_DEBUG_ASSERT(SH_OP_PAL == stmt.op);
00349 
00350   append_line(resolve(stmt.dest) + " = " + resolve(stmt.src[0], stmt.src[1]));
00351 }
00352 
00353 void GlslCode::emit_prod(const ShStatement& stmt)
00354 {
00355   SH_DEBUG_ASSERT(SH_OP_CMUL == stmt.op);
00356 
00357   ShVariable temp(allocate_temp(stmt, 1));
00358   append_line(resolve(temp) + " = " + resolve(stmt.src[0], 0));
00359 
00360   int size = stmt.src[0].size();
00361   for (int i=1; i < size; i++) {
00362     append_line(resolve(temp) + " *= " + resolve(stmt.src[0], i));
00363   }
00364 
00365   append_line(resolve(stmt.dest) + " = " + resolve(temp));
00366 }
00367 
00368 void GlslCode::emit_sum(const ShStatement& stmt)
00369 {
00370   SH_DEBUG_ASSERT(SH_OP_CSUM == stmt.op);
00371 
00372   ShVariable temp(allocate_temp(stmt, 1));
00373   append_line(resolve(temp) + " = " + resolve(stmt.src[0], 0));
00374 
00375   int size = stmt.src[0].size();
00376   for (int i=1; i < size; i++) {
00377     append_line(resolve(temp) + " += " + resolve(stmt.src[0], i));
00378   }
00379 
00380   append_line(resolve(stmt.dest) + " = " + resolve(temp));
00381 }
00382 
00383 void GlslCode::emit_texture(const ShStatement& stmt)
00384 {
00385   SH_DEBUG_ASSERT((SH_OP_TEX == stmt.op) || (SH_OP_TEXI == stmt.op));
00386 
00387   stringstream line;
00388   line << resolve(stmt.dest) << " = texture";
00389 
00390   ShTextureNodePtr texture = shref_dynamic_cast<ShTextureNode>(stmt.src[0].node());
00391   switch (texture->dims()) {
00392   case SH_TEXTURE_1D:
00393     line << "1D";
00394     break;
00395   case SH_TEXTURE_2D:
00396     line << "2D";
00397     break;
00398   case SH_TEXTURE_3D:
00399     line << "3D";
00400     break;
00401   case SH_TEXTURE_CUBE:
00402     line << "Cube";
00403     break;
00404   case SH_TEXTURE_RECT:
00405     line << "2DRect";
00406     break;
00407   }
00408 
00409   line << "(" << resolve(stmt.src[0]) << ", " << resolve(stmt.src[1]) << ")";
00410   if (texture->size() != 4) {
00411     line << ".";
00412     for (int i = 0; i < texture->size(); i++) {
00413       line << "xyzw"[i];
00414     }
00415   }
00416 
00417   append_line(line.str());
00418 }
00419 
00420 }

Generated on Thu Apr 21 17:32:45 2005 for Sh by  doxygen 1.4.2