00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00020 #include "GlslCode.hpp"
00021 #include <iostream>
00022 #include <cmath>
00023
00024 namespace shgl {
00025
00026 using namespace SH;
00027 using namespace std;
00028
00029 static GlslMapping opCodeTable[] = {
00030 {SH_OP_ABS, "abs($0)"},
00031 {SH_OP_ACOS, "acos($0)"},
00032 {SH_OP_ADD, "$0 + $1"},
00033 {SH_OP_ASIN, "asin($0)"},
00034 {SH_OP_ASN, "$0"},
00035 {SH_OP_ATAN, "atan($0)"},
00036 {SH_OP_CEIL, "ceil($0)"},
00037 {SH_OP_COS, "cos($0)"},
00038 {SH_OP_DOT, "dot($0, $1)"},
00039 {SH_OP_DIV, "$0 / $1"},
00040 {SH_OP_DX, "dFdx($0)"},
00041 {SH_OP_DY, "dFdy($0)"},
00042 {SH_OP_EXP, "exp($0)"},
00043 {SH_OP_EXP2, "exp2($0)"},
00044 {SH_OP_FLR, "floor($0)"},
00045 {SH_OP_FRAC, "fract($0)"},
00046
00047 {SH_OP_LOG2, "log2($0)"},
00048 {SH_OP_LRP, "mix($2, $1, $0)"},
00049 {SH_OP_MAD, "$0 * $1 + $2"},
00050 {SH_OP_MAX, "max($0, $1)"},
00051 {SH_OP_MIN, "min($0, $1)"},
00052 {SH_OP_MOD, "mod($0, $1)"},
00053 {SH_OP_MUL, "$0 * $1"},
00054 {SH_OP_NEG, "-($0)"},
00055 {SH_OP_NORM, "normalize($0)"},
00056 {SH_OP_POW, "pow($0, $1)"},
00057 {SH_OP_RCP, "1.0 / $0"},
00058 {SH_OP_RND, "floor($0 + 0.5)"},
00059 {SH_OP_RSQ, "inversesqrt($0)"},
00060 {SH_OP_SGN, "sign($0)"},
00061 {SH_OP_SIN, "sin($0)"},
00062 {SH_OP_SQRT, "sqrt($0)"},
00063 {SH_OP_TAN, "tan($0)"},
00064 {SH_OP_XPD, "cross($0, $1)"},
00065
00066 {SH_OPERATION_END, 0}
00067 };
00068
00069 void GlslCode::table_substitution(const ShStatement& stmt, const char* code_ptr)
00070 {
00071
00072
00073
00074 string code = code_ptr;
00075 stringstream operation;
00076 int param_size=0;
00077
00078 {
00079
00080 string::size_type i = 0;
00081 for (string::size_type j=0; (j = code.find_first_of("$", i)) != string::npos; i = j) {
00082 i = j + 1;
00083 j = code.find_first_not_of("012345689", i);
00084 int index = atoi(code.substr(i, j - i).c_str());
00085 const ShVariable& src = stmt.src[index];
00086 if (src.size() > param_size) {
00087 param_size = src.size();
00088 }
00089 }
00090 }
00091
00092
00093
00094 {
00095 string::size_type i = 0;
00096 for (string::size_type j=0; (j = code.find_first_of("$", i)) != string::npos; i = j) {
00097
00098 operation << code.substr(i, j - i);
00099 i = j + 1;
00100 j = code.find_first_not_of("012345689", i);
00101
00102
00103 int index = atoi(code.substr(i, j - i).c_str());
00104 const ShVariable& src = stmt.src[index];
00105 operation << resolve(src, -1, param_size);
00106 }
00107
00108 if (i != string::npos) {
00109 operation << code.substr(i);
00110 }
00111 }
00112
00113
00114 stringstream line;
00115 line << resolve(stmt.dest) << " = ";
00116
00117 if (param_size != stmt.dest.size()) {
00118
00119 line << glsl_typename(stmt.dest.valueType(), stmt.dest.size());
00120 line << "(" << operation.str() << ")";
00121 } else {
00122 line << operation.str();
00123 }
00124
00125 append_line(line.str());
00126 }
00127
00128 bool GlslCode::handle_table_operation(const ShStatement& stmt)
00129 {
00130 const char* code = 0;
00131 {
00132 unsigned i = 0;
00133 for (ShOperation op = opCodeTable[i].op; op != SH_OPERATION_END; op = opCodeTable[++i].op) {
00134 if (stmt.op == op) {
00135 code = opCodeTable[i].code;
00136 }
00137 }
00138 }
00139
00140 if (code) {
00141 table_substitution(stmt, code);
00142 return true;
00143 } else {
00144 return false;
00145 }
00146 }
00147
00148 void GlslCode::emit(const ShStatement &stmt)
00149 {
00150 if (!handle_table_operation(stmt)) {
00151
00152 switch(stmt.op) {
00153 case SH_OP_CBRT:
00154 emit_cbrt(stmt);
00155 break;
00156 case SH_OP_CMUL:
00157 emit_prod(stmt);
00158 break;
00159 case SH_OP_CSUM:
00160 emit_sum(stmt);
00161 break;
00162 case SH_OP_COND:
00163 emit_cond(stmt);
00164 break;
00165 case SH_OP_EXP10:
00166 emit_exp10(stmt);
00167 break;
00168 case SH_OP_KIL:
00169 emit_discard(stmt, "discard");
00170 break;
00171 case SH_OP_LIT:
00172 emit_lit(stmt);
00173 break;
00174 case SH_OP_LOG:
00175 emit_log(stmt);
00176 break;
00177 case SH_OP_LOG10:
00178 emit_log10(stmt);
00179 break;
00180 case SH_OP_NOISE:
00181 emit_noise(stmt);
00182 break;
00183 case SH_OP_PAL:
00184 emit_pal(stmt);
00185 break;
00186 case SH_OP_RET:
00187 emit_discard(stmt, "return");
00188 break;
00189 case SH_OP_SEQ:
00190 case SH_OP_SGE:
00191 case SH_OP_SGT:
00192 case SH_OP_SLE:
00193 case SH_OP_SLT:
00194 case SH_OP_SNE:
00195 emit_logic(stmt);
00196 break;
00197 case SH_OP_TEX:
00198 case SH_OP_TEXI:
00199 case SH_OP_TEXLOD:
00200 emit_texture(stmt);
00201 break;
00202 case SH_OP_COSH:
00203 case SH_OP_SINH:
00204 case SH_OP_TANH:
00205 emit_hyperbolic(stmt);
00206 break;
00207 case SH_OP_COMMENT:
00208 emit_comment(stmt);
00209 break;
00210 default:
00211 shError(ShBackendException(string("Glsl Code: Unknown operation ") + opInfo[stmt.op].name));
00212 break;
00213 }
00214 }
00215 }
00216
00217 ShVariableNodePtr GlslCode::allocate_constant(const ShStatement& stmt, double constant, int size) const
00218 {
00219 if (size <= 0) size = stmt.dest.size();
00220
00221 const ShVariableNodePtr& dest_node = stmt.dest.node();
00222 ShVariableNode* node = new ShVariableNode(SH_CONST, size, dest_node->valueType(), dest_node->specialType());
00223
00224 ShDataVariant<double>* variant = new ShDataVariant<double>(size, constant);
00225 ShVariantCPtr variant_ptr = variant;
00226 node->setVariant(variant_ptr);
00227
00228 ShVariableNodePtr node_ptr = ShPointer<ShVariableNode>(node);
00229 return node_ptr;
00230 }
00231
00232 ShVariableNodePtr GlslCode::allocate_temp(const ShStatement& stmt, int size) const
00233 {
00234 if (size <= 0) size = stmt.dest.size();
00235
00236 const ShVariableNodePtr& dest_node = stmt.dest.node();
00237 ShVariableNode* node = new ShVariableNode(SH_TEMP, size, dest_node->valueType(), dest_node->specialType());
00238 ShVariableNodePtr node_ptr = ShPointer<ShVariableNode>(node);
00239 return node_ptr;
00240 }
00241
00242 string GlslCode::resolve_constant(double constant, const ShVariable& var, int size) const
00243 {
00244 if (size <= 0) size = var.size();
00245
00246 stringstream s;
00247 s.precision(16);
00248 s << glsl_typename(var.valueType(), size);
00249
00250 s << "(";
00251 for (int i=0; i < size; i++) {
00252 if (i > 0) s << ", ";
00253 s << constant;
00254 }
00255 s << ")";
00256
00257 return s.str();
00258 }
00259
00260 void GlslCode::emit_ati_workaround(const ShStatement& stmt, double real_answer, const char* code)
00261 {
00262 bool on_ati = false;
00263 const GLubyte* vendor = SH_GL_CHECK_ERROR(glGetString(GL_VENDOR));
00264 if (vendor) {
00265 std::string s(reinterpret_cast<const char*>(vendor));
00266 on_ati = s.find("ATI") != s.npos;
00267 }
00268
00269 if (on_ati) {
00270 ShVariable tmp(allocate_temp(stmt));
00271 ShVariable constant(allocate_constant(stmt, real_answer));
00272 table_substitution(ShStatement(tmp, stmt.src[0], stmt.op, stmt.src[1]), code);
00273 append_line(resolve(stmt.dest) + " = (" + resolve(stmt.src[0]) + " == " + resolve(stmt.src[1]) + ") ? " + resolve(constant) + " : " + resolve(tmp));
00274 } else {
00275 table_substitution(stmt, code);
00276 }
00277 }
00278
00279 void GlslCode::emit_cbrt(const ShStatement& stmt)
00280 {
00281 SH_DEBUG_ASSERT(SH_OP_CBRT == stmt.op);
00282
00283 ShVariable temp(allocate_constant(stmt, 1.0 / 3.0));
00284 emit_pow(stmt.dest, stmt.src[0], temp);
00285 }
00286
00287 void GlslCode::emit_comment(const ShStatement& stmt)
00288 {
00289 append_line("// " + stmt.get_info<ShInfoComment>()->comment, false);
00290 }
00291
00292 void GlslCode::emit_cond(const ShStatement& stmt)
00293 {
00294 SH_DEBUG_ASSERT(SH_OP_COND == stmt.op);
00295
00296 bool on_nvidia = false;
00297 const GLubyte* vendor = SH_GL_CHECK_ERROR(glGetString(GL_VENDOR));
00298 if (vendor) {
00299 string s(reinterpret_cast<const char*>(vendor));
00300 on_nvidia = s.find("NVIDIA") != s.npos;
00301 }
00302
00303 const int size = stmt.src[0].size();
00304 if (on_nvidia || (1 == size)) {
00305
00306 string code = string ("(") + resolve(stmt.src[0]) + " > " +
00307 resolve_constant(0, stmt.src[0]) + ") ? " + resolve(stmt.src[1]) +
00308 " : " + resolve(stmt.src[2]);
00309
00310 if (size != stmt.dest.size()) {
00311 code = glsl_typename(stmt.dest.valueType(), stmt.dest.size()) + "(" + code + ")";
00312 }
00313 append_line(resolve(stmt.dest) + " = " + code);
00314 } else {
00315
00316 for (int i=0; i < size; i++) {
00317 append_line(resolve(stmt.dest, i) + " = (" + resolve(stmt.src[0], i) + " > " +
00318 resolve_constant(0, stmt.src[0], 1) + ") ? " + resolve(stmt.src[1], i) +
00319 " : " + resolve(stmt.src[2], i));
00320 }
00321 }
00322 }
00323
00324 void GlslCode::emit_discard(const ShStatement& stmt, const string& function)
00325 {
00326 SH_DEBUG_ASSERT((SH_OP_KIL == stmt.op) || (SH_OP_RET == stmt.op));
00327
00328
00329 ostringstream oss;
00330 oss << "if (";
00331 if (stmt.src[0].size() > 1) {
00332
00333 oss << "any(bvec" << stmt.src[0].size() << "(";
00334 oss << resolve(stmt.src[0]);
00335 oss << "))";
00336 } else {
00337
00338 oss << "bool(";
00339 oss << resolve(stmt.src[0]);
00340 oss << ")";
00341 }
00342
00343 oss << ") " << function;
00344
00345
00346 append_line(oss.str());
00347 }
00348
00349 void GlslCode::emit_pow(const ShVariable& dest, const ShVariable& a, const ShVariable& b)
00350 {
00351
00352 const int size = std::max(a.size(), b.size());
00353 string pow_call = string("pow(") + resolve(a, -1, size) + ", " + resolve(b, -1, size) + ")";
00354
00355
00356 if (dest.size() != size) {
00357 pow_call = glsl_typename(dest.valueType(), dest.size()) + "(" + pow_call + ")";
00358 }
00359
00360 append_line(resolve(dest) + " = " + pow_call);
00361 }
00362
00363 void GlslCode::emit_exp10(const ShStatement& stmt)
00364 {
00365 SH_DEBUG_ASSERT(SH_OP_EXP10 == stmt.op);
00366 ShVariable c(allocate_constant(stmt, 1.0/std::log10(2.0)));
00367 append_line(resolve(stmt.dest) + " = exp2(" + resolve(c) + " * " + resolve(stmt.src[0]) + ")");
00368 }
00369
00370 void GlslCode::emit_hyperbolic(const ShStatement& stmt)
00371 {
00372 ShVariable two(allocate_constant(stmt, 2));
00373 ShVariable e(allocate_constant(stmt, M_E));
00374
00375 ShVariable e_plusX(allocate_temp(stmt));
00376 ShVariable e_minusX(allocate_temp(stmt));
00377 emit_pow(e_plusX, e, stmt.src[0]);
00378 append_line(resolve(e_minusX) + " = pow(" + resolve(e) + ", -(" + resolve(stmt.src[0]) + "))");
00379
00380 switch (stmt.op) {
00381 case SH_OP_COSH:
00382
00383 append_line(resolve(stmt.dest) + " = (" + resolve(e_plusX) + " + " + resolve(e_minusX) + ") / " + resolve(two));
00384 break;
00385 case SH_OP_SINH:
00386
00387 append_line(resolve(stmt.dest) + " = (" + resolve(e_plusX) + " - " + resolve(e_minusX) + ") / " + resolve(two));
00388 break;
00389 case SH_OP_TANH:
00390
00391 append_line(resolve(stmt.dest) + " = (" + resolve(e_plusX) + " - " + resolve(e_minusX) + ") / " +
00392 "(" + resolve(e_plusX) + " + " + resolve(e_minusX) + ")");
00393 break;
00394 default:
00395 SH_DEBUG_ASSERT(0);
00396 }
00397 }
00398
00399 void GlslCode::emit_lit(const ShStatement& stmt)
00400 {
00401 SH_DEBUG_ASSERT(SH_OP_LIT == stmt.op);
00402
00403
00404 append_line(resolve(stmt.dest, 0) + " = " + resolve_constant(1, stmt.dest, 1));
00405
00406 append_line(resolve(stmt.dest, 1) + " = max(" + resolve_constant(0, stmt.dest, 1) +
00407 ", " + resolve(stmt.src[0], 0) + ")");
00408
00409 append_line(resolve(stmt.dest, 2) + " = " + resolve(stmt.src[0], 0) +
00410 " > " + resolve_constant(0, stmt.src[0], 1) + " ? pow(max(" +
00411 resolve_constant(0, stmt.dest, 1) + ", " + resolve(stmt.src[0], 1) +
00412 "), clamp(" + resolve(stmt.src[0], 2) + ", " +
00413 resolve_constant(-128, stmt.dest, 1) + ", " +
00414 resolve_constant(128, stmt.dest, 1) + ")) : " + resolve_constant(0, stmt.dest, 1));
00415
00416 append_line(resolve(stmt.dest, 3) + " = " + resolve_constant(1, stmt.dest, 1));
00417 }
00418
00419 void GlslCode::emit_log(const ShStatement& stmt)
00420 {
00421 SH_DEBUG_ASSERT(SH_OP_LOG == stmt.op);
00422 bool on_ati = false;
00423 const GLubyte* vendor = SH_GL_CHECK_ERROR(glGetString(GL_VENDOR));
00424 if (vendor) {
00425 std::string s(reinterpret_cast<const char*>(vendor));
00426 on_ati = s.find("ATI") != s.npos;
00427 }
00428
00429 if (on_ati) {
00430 ShVariable tmp(allocate_temp(stmt));
00431 table_substitution(ShStatement(tmp, stmt.op, stmt.src[0]), "log($0)");
00432
00433 const int size = stmt.dest.size();
00434 if (1 == size) {
00435
00436 append_line(resolve(stmt.dest) + " = (" + resolve(stmt.src[0]) + " == " +
00437 resolve_constant(1, stmt.src[0], 1) + ") ? " + resolve_constant(0, stmt.src[0], 1) +
00438 " : " + resolve(tmp, 0));
00439 } else {
00440 for (int i=0; i < size; i++) {
00441 append_line(resolve(stmt.dest, i) + " = (" + resolve(stmt.src[0], i) + " == " +
00442 resolve_constant(1, stmt.src[0], 1) + ") ? " + resolve_constant(0, stmt.src[0], 1) +
00443 " : " + resolve(tmp, i));
00444 }
00445 }
00446 } else {
00447 table_substitution(stmt, "log($0)");
00448 }
00449 }
00450
00451 void GlslCode::emit_log10(const ShStatement& stmt)
00452 {
00453 SH_DEBUG_ASSERT(SH_OP_LOG10 == stmt.op);
00454 ShVariable c(allocate_constant(stmt, std::log10(2.0)));
00455 append_line(resolve(stmt.dest) + " = log2(" + resolve(stmt.src[0]) + ") * " + resolve(c) + "");
00456 }
00457
00458 void GlslCode::emit_logic(const ShStatement& stmt)
00459 {
00460 string code = "";
00461 if ((stmt.src[0].size() > 1) || (stmt.src[1].size() > 1) ) {
00462 switch (stmt.op) {
00463 case SH_OP_SEQ:
00464 code = "equal($0, $1)";
00465 break;
00466 case SH_OP_SGT:
00467 code = "greaterThan($0, $1)";
00468 break;
00469 case SH_OP_SGE:
00470 code = "greaterThanEqual($0, $1)";
00471 break;
00472 case SH_OP_SNE:
00473 code = "notEqual($0, $1)";
00474 break;
00475 case SH_OP_SLT:
00476 code = "lessThan($0, $1)";
00477 break;
00478 case SH_OP_SLE:
00479 code = "lessThanEqual($0, $1)";
00480 break;
00481 default:
00482 SH_DEBUG_ASSERT(0);
00483 }
00484 } else {
00485 switch (stmt.op) {
00486 case SH_OP_SEQ:
00487 code = "$0 == $1";
00488 break;
00489 case SH_OP_SGT:
00490 code = "$0 > $1";
00491 break;
00492 case SH_OP_SGE:
00493 code = "$0 >= $1";
00494 break;
00495 case SH_OP_SNE:
00496 code = "$0 != $1";
00497 break;
00498 case SH_OP_SLT:
00499 code = "$0 < $1";
00500 break;
00501 case SH_OP_SLE:
00502 code = "$0 <= $1";
00503 break;
00504 default:
00505 SH_DEBUG_ASSERT(0);
00506 }
00507 }
00508
00509
00510 code = glsl_typename(stmt.dest.valueType(), stmt.dest.size()) + "(" + code + ")";
00511
00512 table_substitution(stmt, code.c_str());
00513 }
00514
00515 void GlslCode::emit_noise(const ShStatement& stmt)
00516 {
00517 SH_DEBUG_ASSERT(SH_OP_NOISE == stmt.op);
00518
00519 int output_size = stmt.dest.size();
00520 SH_DEBUG_ASSERT((output_size <= 4) && (output_size >= 1));
00521
00522 stringstream line;
00523 line << resolve(stmt.dest) << " = " << "noise" << output_size << "("
00524 << resolve(stmt.src[0]) << ")";
00525 append_line(line.str());
00526 }
00527
00528 void GlslCode::emit_pal(const ShStatement& stmt)
00529 {
00530 SH_DEBUG_ASSERT(SH_OP_PAL == stmt.op);
00531
00532 append_line(resolve(stmt.dest) + " = " + resolve(stmt.src[0], stmt.src[1]));
00533 }
00534
00535 void GlslCode::emit_prod(const ShStatement& stmt)
00536 {
00537 SH_DEBUG_ASSERT(SH_OP_CMUL == stmt.op);
00538
00539 ShVariable temp(allocate_temp(stmt, 1));
00540 append_line(resolve(temp) + " = " + resolve(stmt.src[0], 0));
00541
00542 int size = stmt.src[0].size();
00543 for (int i=1; i < size; i++) {
00544 append_line(resolve(temp) + " *= " + resolve(stmt.src[0], i));
00545 }
00546
00547 append_line(resolve(stmt.dest) + " = " + resolve(temp));
00548 }
00549
00550 void GlslCode::emit_sum(const ShStatement& stmt)
00551 {
00552 SH_DEBUG_ASSERT(SH_OP_CSUM == stmt.op);
00553
00554 ShVariable temp(allocate_temp(stmt, 1));
00555 append_line(resolve(temp) + " = " + resolve(stmt.src[0], 0));
00556
00557 int size = stmt.src[0].size();
00558 for (int i=1; i < size; i++) {
00559 append_line(resolve(temp) + " += " + resolve(stmt.src[0], i));
00560 }
00561
00562 append_line(resolve(stmt.dest) + " = " + resolve(temp));
00563 }
00564
00565 void GlslCode::emit_texture(const ShStatement& stmt)
00566 {
00567 SH_DEBUG_ASSERT((SH_OP_TEX == stmt.op) || (SH_OP_TEXI == stmt.op) || (SH_OP_TEXLOD == stmt.op));
00568
00569 stringstream line;
00570 line << resolve(stmt.dest) << " = texture";
00571
00572 ShTextureNodePtr texture = shref_dynamic_cast<ShTextureNode>(stmt.src[0].node());
00573 switch (texture->dims()) {
00574 case SH_TEXTURE_1D:
00575 line << "1D";
00576 break;
00577 case SH_TEXTURE_2D:
00578 line << "2D";
00579 break;
00580 case SH_TEXTURE_3D:
00581 line << "3D";
00582 break;
00583 case SH_TEXTURE_CUBE:
00584 line << "Cube";
00585 break;
00586 case SH_TEXTURE_RECT:
00587 line << "2DRect";
00588 break;
00589 }
00590
00591 if (SH_OP_TEXLOD == stmt.op) {
00592 line << "Lod";
00593 }
00594 line << "(" << resolve(stmt.src[0]) << ", " << resolve(stmt.src[1]);
00595
00596 if (SH_OP_TEXLOD == stmt.op) {
00597 line << ", " << resolve(stmt.src[2]);
00598 }
00599
00600 line << ")";
00601
00602
00603 if ((2 == texture->size()) || (stmt.dest.size() != 4)) {
00604 string components = "xyzw";
00605 if (2 == texture->size()) {
00606 components = "xwyz";
00607 }
00608
00609 line << ".";
00610 const int swiz_length = stmt.dest.size();
00611 for (int i = 0; i < swiz_length; i++) {
00612 line << components[i];
00613 }
00614 }
00615
00616 append_line(line.str());
00617 }
00618
00619 }