Added GLSL backend for ESSL translator.
Review URL: http://codereview.appspot.com/698041
git-svn-id: https://angleproject.googlecode.com/svn/trunk@69 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/compiler/OutputGLSL.cpp b/src/compiler/OutputGLSL.cpp
new file mode 100644
index 0000000..de29b54
--- /dev/null
+++ b/src/compiler/OutputGLSL.cpp
@@ -0,0 +1,469 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "OutputGLSL.h"
+#include "common/debug.h"
+
+namespace
+{
+TString getTypeName(const TType& type)
+{
+ TInfoSinkBase out;
+ if (type.isMatrix())
+ {
+ out << "mat";
+ out << type.getNominalSize();
+ }
+ else if (type.isArray())
+ {
+ UNIMPLEMENTED();
+ }
+ else if (type.isVector())
+ {
+ switch (type.getBasicType())
+ {
+ case EbtFloat: out << "vec"; break;
+ case EbtInt: out << "ivec"; break;
+ case EbtBool: out << "bvec"; break;
+ default: UNREACHABLE(); break;
+ }
+ out << type.getNominalSize();
+ }
+ else
+ {
+ if (type.getBasicType() == EbtStruct)
+ out << type.getTypeName();
+ else
+ out << type.getBasicString();
+ }
+ return TString(out.c_str());
+}
+
+TString getUnmangledFunctionName(const TString& mangledName)
+{
+ return TString(mangledName.c_str(), mangledName.find_first_of('('));
+}
+
+TString getIndentationString(int depth)
+{
+ TString indentation(depth, ' ');
+ return indentation;
+}
+} // namespace
+
+TOutputGLSL::TOutputGLSL(TParseContext &context)
+ : TIntermTraverser(true, true, true),
+ writeFullSymbol(false),
+ parseContext(context)
+{
+}
+
+void TOutputGLSL::header()
+{
+ TInfoSinkBase& out = objSink();
+
+ TSymbolTableLevel* symbols = parseContext.symbolTable.getGlobalLevel();
+ for (TSymbolTableLevel::const_iterator symbolIter = symbols->begin(); symbolIter != symbols->end(); ++symbolIter)
+ {
+ const TSymbol* symbol = symbolIter->second;
+ if (!symbol->isVariable())
+ continue;
+
+ const TVariable* variable = static_cast<const TVariable*>(symbol);
+ const TString& name = variable->getName();
+ const TType& type = variable->getType();
+ TQualifier qualifier = type.getQualifier();
+
+ //symbol->dump(parseContext.infoSink);
+ }
+}
+
+void TOutputGLSL::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
+{
+ TInfoSinkBase& out = objSink();
+ if (visit == PreVisit && preStr)
+ {
+ out << preStr;
+ }
+ else if (visit == InVisit && inStr)
+ {
+ out << inStr;
+ }
+ else if (visit == PostVisit && postStr)
+ {
+ out << postStr;
+ }
+}
+
+void TOutputGLSL::visitSymbol(TIntermSymbol* node)
+{
+ TInfoSinkBase& out = objSink();
+ if (writeFullSymbol)
+ {
+ TQualifier qualifier = node->getQualifier();
+ if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
+ out << node->getQualifierString() << " ";
+
+ out << getTypeName(node->getType()) << " ";
+ }
+ out << node->getSymbol();
+}
+
+void TOutputGLSL::visitConstantUnion(TIntermConstantUnion* node)
+{
+ TInfoSinkBase& out = objSink();
+
+ TType type = node->getType();
+ int size = type.getObjectSize();
+ if (size > 1)
+ out << getTypeName(type) << "(";
+ for (int i = 0; i < size; ++i) {
+ const constUnion& data = node->getUnionArrayPointer()[i];
+ switch (data.getType())
+ {
+ case EbtFloat: out << data.getFConst(); break;
+ case EbtInt: out << data.getIConst(); break;
+ case EbtBool: out << data.getBConst(); break;
+ default: UNREACHABLE(); break;
+ }
+ if (i != size - 1)
+ out << ", ";
+ }
+ if (size > 1)
+ out << ")";
+}
+
+bool TOutputGLSL::visitBinary(Visit visit, TIntermBinary* node)
+{
+ bool visitChildren = true;
+ TInfoSinkBase& out = objSink();
+ switch (node->getOp())
+ {
+ case EOpAssign: writeTriplet(visit, NULL, " = ", NULL); break;
+ case EOpInitialize:
+ if (visit == InVisit) {
+ out << " = ";
+ writeFullSymbol= false;
+ }
+ break;
+ case EOpAddAssign: writeTriplet(visit, NULL, " += ", NULL); break;
+ case EOpSubAssign: UNIMPLEMENTED(); break;
+ case EOpMulAssign: UNIMPLEMENTED(); break;
+ case EOpVectorTimesMatrixAssign: UNIMPLEMENTED(); break;
+ case EOpVectorTimesScalarAssign: UNIMPLEMENTED(); break;
+ case EOpMatrixTimesScalarAssign: UNIMPLEMENTED(); break;
+ case EOpMatrixTimesMatrixAssign: UNIMPLEMENTED(); break;
+ case EOpDivAssign: UNIMPLEMENTED(); break;
+
+ case EOpIndexDirect: writeTriplet(visit, NULL, "[", "]"); break;
+ case EOpIndexIndirect: UNIMPLEMENTED(); break;
+ case EOpIndexDirectStruct:
+ if (visit == InVisit)
+ {
+ out << ".";
+ // TODO(alokp): ASSERT
+ out << node->getType().getFieldName();
+ visitChildren = false;
+ }
+ break;
+ case EOpVectorSwizzle:
+ if (visit == InVisit)
+ {
+ out << ".";
+ TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
+ TIntermSequence& sequence = rightChild->getSequence();
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
+ {
+ TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
+ ASSERT(element->getBasicType() == EbtInt);
+ ASSERT(element->getNominalSize() == 1);
+ const constUnion& data = element->getUnionArrayPointer()[0];
+ ASSERT(data.getType() == EbtInt);
+ switch (data.getIConst())
+ {
+ case 0: out << "x"; break;
+ case 1: out << "y"; break;
+ case 2: out << "z"; break;
+ case 3: out << "w"; break;
+ default: UNREACHABLE(); break;
+ }
+ }
+ visitChildren = false;
+ }
+ break;
+
+ case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
+ case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
+ case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
+ case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
+ case EOpMod: UNIMPLEMENTED(); break;
+ case EOpEqual: UNIMPLEMENTED(); break;
+ case EOpNotEqual: UNIMPLEMENTED(); break;
+ case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
+ case EOpGreaterThan: writeTriplet(visit, NULL, " > ", NULL); break;
+ case EOpLessThanEqual: UNIMPLEMENTED(); break;
+ case EOpGreaterThanEqual: UNIMPLEMENTED(); break;
+
+ // Notice the fall-through.
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesMatrix:
+ writeTriplet(visit, "(", " * ", ")");
+ break;
+
+ case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
+ case EOpLogicalXor: UNIMPLEMENTED(); break;
+ case EOpLogicalAnd: UNIMPLEMENTED(); break;
+ default: UNREACHABLE(); break;
+ }
+
+ return visitChildren;
+}
+
+bool TOutputGLSL::visitUnary(Visit visit, TIntermUnary* node)
+{
+ TInfoSinkBase& out = objSink();
+
+ switch (node->getOp())
+ {
+ case EOpNegative: writeTriplet(visit, "(-", NULL, ")"); break;
+ case EOpVectorLogicalNot: UNIMPLEMENTED(); break;
+ case EOpLogicalNot: UNIMPLEMENTED(); break;
+
+ case EOpPostIncrement: UNIMPLEMENTED(); break;
+ case EOpPostDecrement: UNIMPLEMENTED(); break;
+ case EOpPreIncrement: UNIMPLEMENTED(); break;
+ case EOpPreDecrement: UNIMPLEMENTED(); break;
+
+ case EOpConvIntToBool: UNIMPLEMENTED(); break;
+ case EOpConvFloatToBool: UNIMPLEMENTED(); break;
+ case EOpConvBoolToFloat: UNIMPLEMENTED(); break;
+ case EOpConvIntToFloat: writeTriplet(visit, "float(", NULL, ")"); break;
+ case EOpConvFloatToInt: UNIMPLEMENTED(); break;
+ case EOpConvBoolToInt: UNIMPLEMENTED(); break;
+
+ case EOpRadians: UNIMPLEMENTED(); break;
+ case EOpDegrees: UNIMPLEMENTED(); break;
+ case EOpSin: writeTriplet(visit, "sin(", NULL, ")"); break;
+ case EOpCos: writeTriplet(visit, "cos(", NULL, ")"); break;
+ case EOpTan: UNIMPLEMENTED(); break;
+ case EOpAsin: UNIMPLEMENTED(); break;
+ case EOpAcos: UNIMPLEMENTED(); break;
+ case EOpAtan: UNIMPLEMENTED(); break;
+
+ case EOpExp: UNIMPLEMENTED(); break;
+ case EOpLog: UNIMPLEMENTED(); break;
+ case EOpExp2: UNIMPLEMENTED(); break;
+ case EOpLog2: UNIMPLEMENTED(); break;
+ case EOpSqrt: UNIMPLEMENTED(); break;
+ case EOpInverseSqrt: UNIMPLEMENTED(); break;
+
+ case EOpAbs: UNIMPLEMENTED(); break;
+ case EOpSign: UNIMPLEMENTED(); break;
+ case EOpFloor: writeTriplet(visit, "floor(", NULL, ")"); break;
+ case EOpCeil: UNIMPLEMENTED(); break;
+ case EOpFract: UNIMPLEMENTED(); break;
+
+ case EOpLength: UNIMPLEMENTED(); break;
+ case EOpNormalize: writeTriplet(visit, "normalize(", NULL, ")"); break;
+
+ case EOpAny: UNIMPLEMENTED(); break;
+ case EOpAll: UNIMPLEMENTED(); break;
+
+ default: UNREACHABLE(); break;
+ }
+
+ return true;
+}
+
+bool TOutputGLSL::visitSelection(Visit visit, TIntermSelection* node)
+{
+ TInfoSinkBase& out = objSink();
+
+ out << "if (";
+ node->getCondition()->traverse(this);
+ out << ") {\n";
+
+ incrementDepth();
+ node->getTrueBlock()->traverse(this);
+ out << getIndentationString(depth - 2) << "}";
+
+ if (node->getFalseBlock())
+ {
+ out << " else {\n";
+ node->getFalseBlock()->traverse(this);
+ out << getIndentationString(depth - 2) << "}";
+ }
+ decrementDepth();
+
+ out << "\n";
+ return false;
+}
+
+bool TOutputGLSL::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ TInfoSinkBase& out = objSink();
+ switch (node->getOp())
+ {
+ case EOpSequence:
+ if (visit == PreVisit)
+ {
+ out << getIndentationString(depth);
+ }
+ else if (visit == InVisit)
+ {
+ out << ";\n";
+ out << getIndentationString(depth - 1);
+ }
+ else
+ {
+ out << ";\n";
+ }
+ break;
+ case EOpComma:
+ UNIMPLEMENTED();
+ return true;
+ case EOpFunction:
+ if (visit == PreVisit)
+ {
+ TString returnType = node->getBasicString();
+ TString functionName = getUnmangledFunctionName(node->getName());
+ out << returnType << " " << functionName;
+ }
+ else if (visit == InVisit)
+ {
+ // Called after traversing function arguments (EOpParameters)
+ // but before traversing function body (EOpSequence).
+ out << "{\n";
+ }
+ else if (visit == PostVisit)
+ {
+ // Called after traversing function body (EOpSequence).
+ out << "}\n";
+ }
+ break;
+ case EOpFunctionCall:
+ if (visit == PreVisit)
+ {
+ TString functionName = getUnmangledFunctionName(node->getName());
+ out << functionName << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ else
+ {
+ out << ")";
+ }
+ break;
+ case EOpParameters:
+ if (visit == PreVisit)
+ {
+ out << "(";
+ writeFullSymbol = true;
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ else
+ {
+ out << ")";
+ writeFullSymbol = false;
+ }
+ break;
+ case EOpDeclaration:
+ if (visit == PreVisit)
+ {
+ writeFullSymbol = true;
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ writeFullSymbol = false;
+ }
+ else
+ {
+ writeFullSymbol = false;
+ }
+ break;
+
+ case EOpConstructFloat: UNIMPLEMENTED(); break;
+ case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
+ case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
+ case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
+ case EOpConstructBool: UNIMPLEMENTED(); break;
+ case EOpConstructBVec2: UNIMPLEMENTED(); break;
+ case EOpConstructBVec3: UNIMPLEMENTED(); break;
+ case EOpConstructBVec4: UNIMPLEMENTED(); break;
+ case EOpConstructInt: UNIMPLEMENTED(); break;
+ case EOpConstructIVec2: UNIMPLEMENTED(); break;
+ case EOpConstructIVec3: UNIMPLEMENTED(); break;
+ case EOpConstructIVec4: UNIMPLEMENTED(); break;
+ case EOpConstructMat2: UNIMPLEMENTED(); break;
+ case EOpConstructMat3: UNIMPLEMENTED(); break;
+ case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
+ case EOpConstructStruct: UNIMPLEMENTED(); break;
+
+ case EOpLessThan: UNIMPLEMENTED(); break;
+ case EOpGreaterThan: UNIMPLEMENTED(); break;
+ case EOpLessThanEqual: UNIMPLEMENTED(); break;
+ case EOpGreaterThanEqual: UNIMPLEMENTED(); break;
+ case EOpVectorEqual: UNIMPLEMENTED(); break;
+ case EOpVectorNotEqual: UNIMPLEMENTED(); break;
+
+ case EOpMod: writeTriplet(visit, "mod(", ", ", ")"); break;
+ case EOpPow: writeTriplet(visit, "pow(", ", ", ")"); break;
+
+ case EOpAtan: UNIMPLEMENTED(); break;
+
+ case EOpMin: writeTriplet(visit, "min(", ", ", ")"); break;
+ case EOpMax: writeTriplet(visit, "max(", ", ", ")"); break;
+ case EOpClamp: writeTriplet(visit, "clamp(", ", ", ")"); break;
+ case EOpMix: writeTriplet(visit, "mix(", ", ", ")"); break;
+ case EOpStep: UNIMPLEMENTED(); break;
+ case EOpSmoothStep: UNIMPLEMENTED(); break;
+
+ case EOpDistance: UNIMPLEMENTED(); break;
+ case EOpDot: writeTriplet(visit, "dot(", ", ", ")"); break;
+ case EOpCross: UNIMPLEMENTED(); break;
+ case EOpFaceForward: UNIMPLEMENTED(); break;
+ case EOpReflect: writeTriplet(visit, "reflect(", ", ", ")"); break;
+ case EOpRefract: UNIMPLEMENTED(); break;
+ case EOpMul: UNIMPLEMENTED(); break;
+
+ default: UNREACHABLE(); break;
+ }
+ return true;
+}
+
+bool TOutputGLSL::visitLoop(Visit visit, TIntermLoop* node)
+{
+ UNIMPLEMENTED();
+ return true;
+}
+
+bool TOutputGLSL::visitBranch(Visit visit, TIntermBranch* node)
+{
+ TInfoSinkBase &out = objSink();
+
+ switch (node->getFlowOp())
+ {
+ case EOpKill: UNIMPLEMENTED(); break;
+ case EOpBreak: UNIMPLEMENTED(); break;
+ case EOpContinue: UNIMPLEMENTED(); break;
+ case EOpReturn:
+ if (visit == PreVisit)
+ out << "return ";
+ break;
+ default: UNREACHABLE(); break;
+ }
+
+ return true;
+}