Example #1
0
void writeFuncCall( const TString &name, TIntermAggregate *node, TGlslOutputTraverser* goit, bool bGenMatrix = false )
{
   TIntermSequence::iterator sit;
   TIntermSequence &sequence = node->getSequence(); 
   GlslFunction *current = goit->current;
   std::stringstream& out = current->getActiveOutput();

   current->beginStatement();
   
   if ( bGenMatrix )
   {
      if ( node->isMatrix () )
      {
         out << "xll_";
         current->addLibFunction ( node->getOp() );
      }
   }      

   out << name << "(";

	for (sit = sequence.begin(); sit != sequence.end(); ++sit)
	{
		if (sit !=sequence.begin())
			out << ", ";
		(*sit)->traverse(goit);
	}
	
   out << ")";
}
Example #2
0
static bool sortFunctionsTopologically (std::vector<GlslFunction*>& dst, const std::vector<GlslFunction*>& src)
{
	dst.clear();

	// Build function use counts.
	FunctionUseCounts useCounts;
	for (std::vector<GlslFunction*>::const_iterator funcIter = src.begin(); funcIter != src.end(); ++funcIter)
		useCounts[(*funcIter)->getMangledName()] = 0;

	for (std::vector<GlslFunction*>::const_iterator funcIter = src.begin(); funcIter != src.end(); ++funcIter)
	{
		std::set<std::string> calledNames = (*funcIter)->getCalledFunctions();
		for (std::set<std::string>::const_iterator callIter = calledNames.begin(); callIter != calledNames.end(); ++callIter)
			useCounts[*callIter] += 1;
	}

	std::vector<GlslFunction*> liveSet;

	// Init live set with functions that have use count 0 (should be only main())
	for (std::vector<GlslFunction*>::const_iterator funcIter = src.begin(); funcIter != src.end(); ++funcIter)
	{
		if (useCounts[(*funcIter)->getMangledName()] == 0)
			liveSet.push_back(*funcIter);
	}

	// Process until live set is empty.
	while (!liveSet.empty())
	{
		GlslFunction* curFunction = liveSet.back();
		liveSet.pop_back();

		dst.push_back(curFunction);

		// Decrement use counts and add to live set if reaches zero.
		std::set<std::string> calledNames = curFunction->getCalledFunctions();
		for (std::set<std::string>::const_iterator callIter = calledNames.begin(); callIter != calledNames.end(); ++callIter)
		{
			int& useCount = useCounts[*callIter];
			useCount -= 1;
			if (useCount == 0)
			{
				GlslFunction* newLiveFunc = resolveFunctionByMangledName(src, *callIter);
				if (!newLiveFunc)
					return false; // Not found - why?
				liveSet.push_back(newLiveFunc);
			}
		}
	}

	// If dependency graph contains cycles, some functions will never end up in live set and from there
	// to sorted list. This checks if sort succeeded.
	return dst.size() == src.size();
}
Example #3
0
bool TGlslOutputTraverser::traverseLoop( bool preVisit, TIntermLoop *node, TIntermTraverser *it )
{
   TGlslOutputTraverser* goit = static_cast<TGlslOutputTraverser*>(it);
   GlslFunction *current = goit->current;
   std::stringstream& out = current->getActiveOutput();

   current->beginStatement();

   if ( node->getTerminal())
   {
      // Process for loop, initial statement was promoted outside the loop
      out << "for ( ; ";
      node->getTest()->traverse(goit);
      out << "; ";
      node->getTerminal()->traverse(goit);
      out << ") ";
      current->beginBlock();
      if (node->getBody())
         node->getBody()->traverse(goit);
      current->endBlock();
   }
   else
   {
      if ( node->testFirst())
      {
         // Process while loop
         out << "while ( ";
         node->getTest()->traverse(goit);
         out << " ) ";
         current->beginBlock();
         if (node->getBody())
            node->getBody()->traverse(goit);
         current->endBlock();
      }
      else
      {
         // Process do loop
         out << "do ";
         current->beginBlock();
         if (node->getBody())
            node->getBody()->traverse(goit);
         current->endBlock();
         current->indent();
         out << "while ( ";
         node->getTest()->traverse(goit);
         out << " )\n";
      }
   }
   return false;
}
Example #4
0
void setupUnaryBuiltInFuncCall( const TString &name, TIntermUnary *node, TString &opStr, bool &funcStyle, bool &prefix,
                                TGlslOutputTraverser* goit )
{
   GlslFunction *current = goit->current;   

   funcStyle = true;
   prefix = true;
   if ( node->isMatrix() )
   {
      current->addLibFunction( node->getOp() );
      opStr = "xll_" + name;
   }
   else
   {
      opStr = name;
   }   
}
Example #5
0
void TGlslOutputTraverser::traverseConstantUnion( TIntermConstant *node, TIntermTraverser *it )
{
   TGlslOutputTraverser* goit = static_cast<TGlslOutputTraverser*>(it);
   GlslFunction *current = goit->current;
   std::stringstream& out = current->getActiveOutput();
   EGlslSymbolType type = translateType( node->getTypePointer());
   GlslStruct *str = 0;


   current->beginStatement();

   if (type == EgstStruct)
   {
      str = goit->createStructFromType( node->getTypePointer());
   }

   writeConstantConstructor (out, type, goit->m_UsePrecision?node->getPrecision():EbpUndefined, node, str);
}
Example #6
0
void TGlslOutputTraverser::traverseParameterSymbol(TIntermSymbol *node, TIntermTraverser *it)
{
   TGlslOutputTraverser* goit = static_cast<TGlslOutputTraverser*>(it);
   GlslFunction *current = goit->current;

   int array = node->getTypePointer()->isArray() ? node->getTypePointer()->getArraySize() : 0;
   const char* semantic = "";
   if (node->getInfo())
      semantic = node->getInfo()->getSemantic().c_str();
   GlslSymbol * sym = new GlslSymbol( node->getSymbol().c_str(), semantic, node->getId(),
                                      translateType(node->getTypePointer()), goit->m_UsePrecision?node->getPrecision():EbpUndefined, translateQualifier(node->getQualifier()), array);
   current->addParameter(sym);

   if (sym->getType() == EgstStruct)
   {
      GlslStruct *s = goit->createStructFromType( node->getTypePointer());
      sym->setStruct(s);
   }
}
Example #7
0
bool TGlslOutputTraverser::traverseBranch( bool preVisit, TIntermBranch *node,  TIntermTraverser *it )
{
   TGlslOutputTraverser* goit = static_cast<TGlslOutputTraverser*>(it);
   GlslFunction *current = goit->current;
   std::stringstream& out = current->getActiveOutput();

   current->beginStatement();

   switch (node->getFlowOp())
   {
   case EOpKill:      out << "discard";           break;
   case EOpBreak:     out << "break";          break;
   case EOpContinue:  out << "continue";       break;
   case EOpReturn:    out << "return ";         break;
   default:           assert(0); break;
   }

   if (node->getExpression())
   {
      node->getExpression()->traverse(it);
   }

   return false;
}
Example #8
0
void TGlslOutputTraverser::traverseSymbol(TIntermSymbol *node, TIntermTraverser *it)
{
	TGlslOutputTraverser* goit = static_cast<TGlslOutputTraverser*>(it);
	GlslFunction *current = goit->current;
	std::stringstream& out = current->getActiveOutput();

	current->beginStatement();

	if ( ! current->hasSymbol( node->getId()))
	{

		//check to see if it is a global we can share
		if ( goit->global->hasSymbol( node->getId()))
		{
			current->addSymbol( &goit->global->getSymbol( node->getId()));
		}
		else
		{
			int array = node->getTypePointer()->isArray() ? node->getTypePointer()->getArraySize() : 0;
			const char* semantic = "";
			if (node->getInfo())
				semantic = node->getInfo()->getSemantic().c_str();
			
			GlslSymbol * sym = new GlslSymbol( node->getSymbol().c_str(), semantic, node->getId(),
				translateType(node->getTypePointer()), goit->m_UsePrecision?node->getPrecision():EbpUndefined, translateQualifier(node->getQualifier()), array);
			sym->setIsGlobal(node->isGlobal());

			current->addSymbol(sym);
			if (sym->getType() == EgstStruct)
			{
				GlslStruct *s = goit->createStructFromType( node->getTypePointer());
				sym->setStruct(s);
			}
		}
	}

	// If we're at the global scope, emit the non-mutable names of uniforms.
	bool globalScope = current == goit->global;
	out << current->getSymbol(node->getId()).getName(!globalScope);
}
Example #9
0
bool TGlslOutputTraverser::traverseUnary( bool preVisit, TIntermUnary *node, TIntermTraverser *it )
{
   TString op("??");
   TGlslOutputTraverser* goit = static_cast<TGlslOutputTraverser*>(it);
   GlslFunction *current = goit->current;
   std::stringstream& out = current->getActiveOutput();
   bool funcStyle = false;
   bool prefix = true;
   char zero[] = "0";

   current->beginStatement();

   switch (node->getOp())
   {
   case EOpNegative:       op = "-";  funcStyle = false; prefix = true; break;
   case EOpVectorLogicalNot:
   case EOpLogicalNot:     op = "!";  funcStyle = false; prefix = true; break;
   case EOpBitwiseNot:     op = "-";  funcStyle = false; prefix = true; break;

   case EOpPostIncrement:  op = "++"; funcStyle = false; prefix = false; break;
   case EOpPostDecrement:  op = "--"; funcStyle = false; prefix = false; break;
   case EOpPreIncrement:   op = "++"; funcStyle = false; prefix = true; break;
   case EOpPreDecrement:   op = "--"; funcStyle = false; prefix = true; break;

   case EOpConvIntToBool:
   case EOpConvFloatToBool:
      op = "bool";
      if ( node->getTypePointer()->getNominalSize() > 1)
      {
         zero[0] += node->getTypePointer()->getNominalSize();
         op = TString("bvec") + zero; 
      }
      funcStyle = true;
      prefix = true;
      break;

   case EOpConvBoolToFloat:
   case EOpConvIntToFloat:
      op = "float";
      if ( node->getTypePointer()->getNominalSize() > 1)
      {
         zero[0] += node->getTypePointer()->getNominalSize();
         op = TString("vec") + zero; 
      }
      funcStyle = true;
      prefix = true;
      break;

   case EOpConvFloatToInt: 
   case EOpConvBoolToInt:
      op = "int";
      if ( node->getTypePointer()->getNominalSize() > 1)
      {
         zero[0] += node->getTypePointer()->getNominalSize();
         op = TString("ivec") + zero; 
      }
      funcStyle = true;
      prefix = true;
      break;

   case EOpRadians:        setupUnaryBuiltInFuncCall ( "radians", node, op, funcStyle, prefix, goit );  break;
   case EOpDegrees:        setupUnaryBuiltInFuncCall ( "degrees", node, op, funcStyle, prefix, goit ); break;
   case EOpSin:            setupUnaryBuiltInFuncCall ( "sin", node, op, funcStyle, prefix, goit ); break;
   case EOpCos:            setupUnaryBuiltInFuncCall ( "cos", node, op, funcStyle, prefix, goit ); break;
   case EOpTan:            setupUnaryBuiltInFuncCall ( "tan", node, op, funcStyle, prefix, goit ); break;
   case EOpAsin:           setupUnaryBuiltInFuncCall ( "asin", node, op, funcStyle, prefix, goit ); break;
   case EOpAcos:           setupUnaryBuiltInFuncCall ( "acos", node, op, funcStyle, prefix, goit ); break;
   case EOpAtan:           setupUnaryBuiltInFuncCall ( "atan", node, op, funcStyle, prefix, goit ); break;
   
   case EOpExp:            setupUnaryBuiltInFuncCall ( "exp", node, op, funcStyle, prefix, goit ); break;
   case EOpLog:            setupUnaryBuiltInFuncCall ( "log", node, op, funcStyle, prefix, goit ); break;
   case EOpExp2:           setupUnaryBuiltInFuncCall ( "exp2", node, op, funcStyle, prefix, goit ); break;
   case EOpLog2:           setupUnaryBuiltInFuncCall ( "log2", node, op, funcStyle, prefix, goit ); break;
   case EOpSqrt:           setupUnaryBuiltInFuncCall ( "sqrt", node, op, funcStyle, prefix, goit ); break;
   case EOpInverseSqrt:    setupUnaryBuiltInFuncCall ( "inversesqrt", node, op, funcStyle, prefix, goit ); break;

   case EOpAbs:            setupUnaryBuiltInFuncCall ( "abs", node, op, funcStyle, prefix, goit ); break;
   case EOpSign:           setupUnaryBuiltInFuncCall ( "sign", node, op, funcStyle, prefix, goit ); break;
   case EOpFloor:          setupUnaryBuiltInFuncCall ( "floor", node, op, funcStyle, prefix, goit ); break;
   case EOpCeil:           setupUnaryBuiltInFuncCall ( "ceil", node, op, funcStyle, prefix, goit ); break;
   case EOpFract:          setupUnaryBuiltInFuncCall ( "fract", node, op, funcStyle, prefix, goit ); break;

   case EOpLength:         op = "length";  funcStyle = true; prefix = true; break;
   case EOpNormalize:      op = "normalize";  funcStyle = true; prefix = true; break;
   case EOpDPdx:           
	   current->addLibFunction(EOpDPdx);
	   op = "xll_dFdx";
	   funcStyle = true;
	   prefix = true;
	   break;
   case EOpDPdy:
	   current->addLibFunction(EOpDPdy);
	   op = "xll_dFdy";
	   funcStyle = true;
	   prefix = true;
	   break;
   case EOpFwidth:
	   current->addLibFunction(EOpFwidth);
	   op = "xll_fwidth";
	   funcStyle = true;
	   prefix = true;
	   break;
   case EOpFclip:		   
	  current->addLibFunction(EOpFclip);
      op = "xll_clip";
      funcStyle = true;
      prefix = true;
      break;    

   case EOpAny:            op = "any";  funcStyle = true; prefix = true; break;
   case EOpAll:            op = "all";  funcStyle = true; prefix = true; break;

      //these are HLSL specific and they map to the lib functions
   case EOpSaturate:
      current->addLibFunction(EOpSaturate);
      op = "xll_saturate";
      funcStyle = true;
      prefix = true;
      break;    

   case EOpTranspose:
      current->addLibFunction(EOpTranspose);
      op = "xll_transpose";
      funcStyle = true;
      prefix = true;
      break;

   case EOpDeterminant:
      current->addLibFunction(EOpDeterminant);
      op = "xll_determinant";
      funcStyle = true;
      prefix = true;
      break;

   case EOpLog10:        
      current->addLibFunction(EOpLog10);
      op = "xll_log10";
      funcStyle = true;
      prefix = true;
      break;       

   case EOpD3DCOLORtoUBYTE4:
      current->addLibFunction(EOpD3DCOLORtoUBYTE4);
      op = "xll_D3DCOLORtoUBYTE4";
      funcStyle = true;
      prefix = true;
      break;

   default:
      assert(0);
   }

   if (funcStyle)
      out << op << '(';
   else
   {
      out << '(';
      if (prefix)
         out << op;
   }

   node->getOperand()->traverse(goit);

   if (! funcStyle && !prefix)
      out << op;

   out << ')';

   return false;
}
Example #10
0
bool TGlslOutputTraverser::traverseBinary( bool preVisit, TIntermBinary *node, TIntermTraverser *it )
{
   TString op = "??";
   TGlslOutputTraverser* goit = static_cast<TGlslOutputTraverser*>(it);
   GlslFunction *current = goit->current;
   std::stringstream& out = current->getActiveOutput();
   bool infix = true;
   bool assign = false;
   bool needsParens = true;

   switch (node->getOp())
   {
   case EOpAssign:                   op = "=";   infix = true; needsParens = false; break;
   case EOpAddAssign:                op = "+=";  infix = true; needsParens = false; break;
   case EOpSubAssign:                op = "-=";  infix = true; needsParens = false; break;
   case EOpMulAssign:                op = "*=";  infix = true; needsParens = false; break;
   case EOpVectorTimesMatrixAssign:  op = "*=";  infix = true; needsParens = false; break;
   case EOpVectorTimesScalarAssign:  op = "*=";  infix = true; needsParens = false; break;
   case EOpMatrixTimesScalarAssign:  op = "*=";  infix = true; needsParens = false; break;
   case EOpMatrixTimesMatrixAssign:  op = "*=";  infix = true; needsParens = false; break;
   case EOpDivAssign:                op = "/=";  infix = true; needsParens = false; break;
   case EOpModAssign:                op = "%=";  infix = true; needsParens = false; break;
   case EOpAndAssign:                op = "&=";  infix = true; needsParens = false; break;
   case EOpInclusiveOrAssign:        op = "|=";  infix = true; needsParens = false; break;
   case EOpExclusiveOrAssign:        op = "^=";  infix = true; needsParens = false; break;
   case EOpLeftShiftAssign:          op = "<<="; infix = true; needsParens = false; break;
   case EOpRightShiftAssign:         op = "??="; infix = true; needsParens = false; break;

   case EOpIndexDirect:
      {
         TIntermTyped *left = node->getLeft();
         TIntermTyped *right = node->getRight();
         assert( left && right);

         current->beginStatement();

		 if (Check2DMatrixIndex (goit, out, left, right))
			 return false;

		 if (left->isMatrix() && !left->isArray())
		 {
			 if (right->getAsConstant())
			 {
				 current->addLibFunction (EOpMatrixIndex);
				 out << "xll_matrixindex (";
				 left->traverse(goit);
				 out << ", ";
				 right->traverse(goit);
				 out << ")";
				 return false;
			 }
			 else
			 {
				 current->addLibFunction (EOpTranspose);
				 current->addLibFunction (EOpMatrixIndex);
				 current->addLibFunction (EOpMatrixIndexDynamic);
				 out << "xll_matrixindexdynamic (";
				 left->traverse(goit);
				 out << ", ";
				 right->traverse(goit);
				 out << ")";
				 return false;
			 }
		 }

         left->traverse(goit);

         // Special code for handling a vector component select (this improves readability)
         if (left->isVector() && !left->isArray() && right->getAsConstant())
         {
            char swiz[] = "xyzw";
            goit->visitConstantUnion = TGlslOutputTraverser::traverseImmediateConstant;
            goit->generatingCode = false;
            right->traverse(goit);
            assert( goit->indexList.size() == 1);
            assert( goit->indexList[0] < 4);
            out << "." << swiz[goit->indexList[0]];
            goit->indexList.clear();
            goit->visitConstantUnion = TGlslOutputTraverser::traverseConstantUnion;
            goit->generatingCode = true;
         }
         else
         {
            out << "[";
            right->traverse(goit);
            out << "]";
         }
         return false;
      }
   case EOpIndexIndirect:
      {
      TIntermTyped *left = node->getLeft();
      TIntermTyped *right = node->getRight();
      current->beginStatement();

	  if (Check2DMatrixIndex (goit, out, left, right))
		  return false;

	  if (left && right && left->isMatrix() && !left->isArray())
	  {
		  if (right->getAsConstant())
		  {
			  current->addLibFunction (EOpMatrixIndex);
			  out << "xll_matrixindex (";
			  left->traverse(goit);
			  out << ", ";
			  right->traverse(goit);
			  out << ")";
			  return false;
		  }
		  else
		  {
			  current->addLibFunction (EOpTranspose);
			  current->addLibFunction (EOpMatrixIndex);
			  current->addLibFunction (EOpMatrixIndexDynamic);
			  out << "xll_matrixindexdynamic (";
			  left->traverse(goit);
			  out << ", ";
			  right->traverse(goit);
			  out << ")";
			  return false;
		  }
	  }

      if (left)
         left->traverse(goit);
      out << "[";
      if (right)
         right->traverse(goit);
      out << "]";
      return false;
	  }

   case EOpIndexDirectStruct:
      {
         current->beginStatement();
         GlslStruct *s = goit->createStructFromType(node->getLeft()->getTypePointer());
         if (node->getLeft())
            node->getLeft()->traverse(goit);

         // The right child is always an offset into the struct, switch to get an
         // immediate constant, and put it back afterwords
         goit->visitConstantUnion = TGlslOutputTraverser::traverseImmediateConstant;
         goit->generatingCode = false;

         if (node->getRight())
         {
            node->getRight()->traverse(goit);
            assert( goit->indexList.size() == 1);
            assert( goit->indexList[0] < s->memberCount());
            out << "." << s->getMember(goit->indexList[0]).name;

         }

         goit->indexList.clear();
         goit->visitConstantUnion = TGlslOutputTraverser::traverseConstantUnion;
         goit->generatingCode = true;
      }
      return false;

   case EOpVectorSwizzle:
      current->beginStatement();
      if (node->getLeft())
         node->getLeft()->traverse(goit);
      goit->visitConstantUnion = TGlslOutputTraverser::traverseImmediateConstant;
      goit->generatingCode = false;
      if (node->getRight())
      {
         node->getRight()->traverse(goit);
         assert( goit->indexList.size() <= 4);
         out << '.';
         const char fields[] = "xyzw";
         for (int ii = 0; ii < (int)goit->indexList.size(); ii++)
         {
            int val = goit->indexList[ii];
            assert( val >= 0);
            assert( val < 4);
            out << fields[val];
         }
      }
      goit->indexList.clear();
      goit->visitConstantUnion = TGlslOutputTraverser::traverseConstantUnion;
      goit->generatingCode = true;
      return false;

	case EOpMatrixSwizzle:		   
		// This presently only works for swizzles as rhs operators
		if (node->getRight())
		{
			goit->visitConstantUnion = TGlslOutputTraverser::traverseImmediateConstant;
			goit->generatingCode = false;

			node->getRight()->traverse(goit);

			goit->visitConstantUnion = TGlslOutputTraverser::traverseConstantUnion;
			goit->generatingCode = true;

			std::vector<int> elements = goit->indexList;
			goit->indexList.clear();
			
			if (elements.size() > 4 || elements.size() < 1) {
				goit->infoSink.info << "Matrix swizzle operations can must contain at least 1 and at most 4 element selectors.";
				return true;
			}

			unsigned column[4] = {0}, row[4] = {0};
			for (unsigned i = 0; i != elements.size(); ++i)
			{
				unsigned val = elements[i];
				column[i] = val % 4;
				row[i] = val / 4;
			}

			bool sameColumn = true;
			for (unsigned i = 1; i != elements.size(); ++i)
				sameColumn &= column[i] == column[i-1];

			static const char* fields = "xyzw";
			
			if (sameColumn)
			{				
				//select column, then swizzle row
				if (node->getLeft())
					node->getLeft()->traverse(goit);
				out << "[" << column[0] << "].";
				
				for (unsigned i = 0; i < elements.size(); ++i)
					out << fields[row[i]];
			}
			else
			{
				// Insert constructor, and dereference individually

				// Might need to account for different types here 
				assert( elements.size() != 1); //should have hit same collumn case
				out << "vec" << elements.size() << "(";
				if (node->getLeft())
					node->getLeft()->traverse(goit);
				out << "[" << column[0] << "].";
				out << fields[row[0]];
				
				for (unsigned i = 1; i < elements.size(); ++i)
				{
					out << ", ";
					if (node->getLeft())
						node->getLeft()->traverse(goit);
					out << "[" << column[i] << "].";
					out << fields[row[i]];
				}
				out << ")";
			}
		}
		return false;

   case EOpAdd:    op = "+"; infix = true; break;
   case EOpSub:    op = "-"; infix = true; break;
   case EOpMul:    op = "*"; infix = true; break;
   case EOpDiv:    op = "/"; infix = true; break;
   case EOpMod:    op = "mod"; infix = false; break;
   case EOpRightShift:  op = "<<"; infix = true;
		   break;
   case EOpLeftShift:   op = ">>"; infix = true; break;
   case EOpAnd:         op = "&"; infix = true; break;
   case EOpInclusiveOr: op = "|"; infix = true; break;
   case EOpExclusiveOr: op = "^"; infix = true; break;
   case EOpEqual:       
      writeComparison ( "==", "equal", node, goit );
      return false;        

   case EOpNotEqual:        
      writeComparison ( "!=", "notEqual", node, goit );
      return false;               

   case EOpLessThan: 
      writeComparison ( "<", "lessThan", node, goit );
      return false;               

   case EOpGreaterThan:
      writeComparison ( ">", "greaterThan", node, goit );
      return false;               

   case EOpLessThanEqual:    
      writeComparison ( "<=", "lessThanEqual", node, goit );
      return false;               


   case EOpGreaterThanEqual: 
      writeComparison ( ">=", "greaterThanEqual", node, goit );
      return false;               


   case EOpVectorTimesScalar: op = "*"; infix = true; break;
   case EOpVectorTimesMatrix: op = "*"; infix = true; break;
   case EOpMatrixTimesVector: op = "*"; infix = true; break;
   case EOpMatrixTimesScalar: op = "*"; infix = true; break;
   case EOpMatrixTimesMatrix: op = "*"; infix = true; break;

   case EOpLogicalOr:  op = "||"; infix = true; break;
   case EOpLogicalXor: op = "^^"; infix = true; break;
   case EOpLogicalAnd: op = "&&"; infix = true; break;
   default: assert(0);
   }

   current->beginStatement();

   if (infix)
   {
	   // special case for swizzled matrix assignment
	   if (node->getOp() == EOpAssign && node->getLeft() && node->getRight()) {
		   TIntermBinary* lval = node->getLeft()->getAsBinaryNode();
		   
		   if (lval && lval->getOp() == EOpMatrixSwizzle) {
			   static const char* vec_swizzles = "xyzw";
			   TIntermTyped* rval = node->getRight();
			   TIntermTyped* lexp = lval->getLeft();
			   
			   goit->visitConstantUnion = TGlslOutputTraverser::traverseImmediateConstant;
			   goit->generatingCode = false;
			   
			   lval->getRight()->traverse(goit);
			   
			   goit->visitConstantUnion = TGlslOutputTraverser::traverseConstantUnion;
			   goit->generatingCode = true;
			   
			   std::vector<int> swizzles = goit->indexList;
			   goit->indexList.clear();
			   
			   char temp_rval[128];
			   unsigned n_swizzles = swizzles.size();
			   
			   if (n_swizzles > 1) {
				   snprintf(temp_rval, 128, "xlat_swiztemp%d", goit->swizzleAssignTempCounter++);
				   
				   current->beginStatement();
				   out << "vec" << n_swizzles << " " << temp_rval << " = ";
				   rval->traverse(goit);			   
				   current->endStatement();
			   }
			   
			   for (unsigned i = 0; i != n_swizzles; ++i) {
				   unsigned col = swizzles[i] / 4;
				   unsigned row = swizzles[i] % 4;
				   
				   current->beginStatement();
				   lexp->traverse(goit);
				   out << "[" << row << "][" << col << "] = ";
				   if (n_swizzles > 1)
					   out << temp_rval << "." << vec_swizzles[i];
				   else
					   rval->traverse(goit);
				   
				   current->endStatement();
			   }

			   return false;
		   }
	   }

      if (needsParens)
         out << '(';

      if (node->getLeft())
         node->getLeft()->traverse(goit);
      out << ' ' << op << ' ';
      if (node->getRight())
         node->getRight()->traverse(goit);

      if (needsParens)
         out << ')';
   }
   else
   {
      if (assign)
      {		  
         // Need to traverse the left child twice to allow for the assign and the op
         // This is OK, because we know it is an lvalue
         if (node->getLeft())
            node->getLeft()->traverse(goit);

         out << " = " << op << '(';

         if (node->getLeft())
            node->getLeft()->traverse(goit);
         out << ", ";
         if (node->getRight())
            node->getRight()->traverse(goit);

         out << ')';
      }
      else
      {
         out << op << '(';

         if (node->getLeft())
            node->getLeft()->traverse(goit);
         out << ", ";
         if (node->getRight())
            node->getRight()->traverse(goit);

         out << ')';
      }
   }

   return false;
}
Example #11
0
bool TGlslOutputTraverser::traverseDeclaration(bool preVisit, TIntermDeclaration* decl, TIntermTraverser* it) {
	TGlslOutputTraverser* goit = static_cast<TGlslOutputTraverser*>(it);
	GlslFunction *current = goit->current;
	std::stringstream& out = current->getActiveOutput();
	EGlslSymbolType symbol_type = translateType(decl->getTypePointer());
	TType& type = *decl->getTypePointer();
	
	
	bool emit_osx10_6_arrays = goit->m_EmitSnowLeopardCompatibleArrayInitializers
		&& decl->containsArrayInitialization();
	
	if (emit_osx10_6_arrays) {
		assert(decl->isSingleInitialization() && "Emission of multiple in-line array declarations isn't supported when running in OS X 10.6 compatible mode.");
		
		current->indent(out);
		out << "#if defined(OSX_SNOW_LEOPARD)" << std::endl;
		current->increaseDepth();
		
		TQualifier q = type.getQualifier();
		if (q == EvqConst)
			q = EvqTemporary;
		
		current->beginStatement();
		if (q != EvqTemporary && q != EvqGlobal)
			out << type.getQualifierString() << " ";
		
		TIntermBinary* assign = decl->getDeclaration()->getAsBinaryNode();
		TIntermSymbol* sym = assign->getLeft()->getAsSymbolNode();
		TIntermSequence& init = assign->getRight()->getAsAggregate()->getSequence();
		
		writeType(out, symbol_type, NULL, goit->m_UsePrecision ? decl->getPrecision() : EbpUndefined);
		out << "[" << type.getArraySize() << "] " << sym->getSymbol();
		current->endStatement();
		
		unsigned n_vals = init.size();
		for (unsigned i = 0; i != n_vals; ++i) {
			current->beginStatement();
			sym->traverse(goit);
			out << "[" << i << "]" << " = ";
			init[i]->traverse(goit);
			current->endStatement();
		}
		
		current->decreaseDepth();
		current->indent(out);
		out << "#else" << std::endl;
		current->increaseDepth();
	}
	
	current->beginStatement();
	
	if (type.getQualifier() != EvqTemporary && type.getQualifier() != EvqGlobal)
		out << type.getQualifierString() << " ";
	
	if (type.getBasicType() == EbtStruct)
		out << type.getTypeName();
	else
		writeType(out, symbol_type, NULL, goit->m_UsePrecision ? decl->getPrecision() : EbpUndefined);
	
	if (type.isArray())
		out << "[" << type.getArraySize() << "]";
	
	out << " ";
	
	decl->getDeclaration()->traverse(goit);
	
	current->endStatement();
	
	if (emit_osx10_6_arrays) {
		current->decreaseDepth();
		current->indent(out);
		out << "#endif" << std::endl;
	}
	
	return false;
}
Example #12
0
bool TGlslOutputTraverser::traverseAggregate( bool preVisit, TIntermAggregate *node, TIntermTraverser *it )
{
   TGlslOutputTraverser* goit = static_cast<TGlslOutputTraverser*>(it);
   GlslFunction *current = goit->current;
   std::stringstream& out = current->getActiveOutput();
   int argCount = (int) node->getSequence().size();

   if (node->getOp() == EOpNull)
   {
      goit->infoSink.info << "node is still EOpNull!\n";
      return true;
   }


   switch (node->getOp())
   {
   case EOpSequence:
      if (goit->generatingCode)
      {
		  goit->outputLineDirective (node->getLine());
         TIntermSequence::iterator sit;
         TIntermSequence &sequence = node->getSequence(); 
		 for (sit = sequence.begin(); sit != sequence.end(); ++sit)
		 {
		   goit->outputLineDirective((*sit)->getLine());
		   (*sit)->traverse(it);
		   //out << ";\n";
		   current->endStatement();
		 }
      }
      else
      {
         TIntermSequence::iterator sit;
         TIntermSequence &sequence = node->getSequence(); 
		  for (sit = sequence.begin(); sit != sequence.end(); ++sit)
		  {
		    (*sit)->traverse(it);
		  }
      }

      return false;

   case EOpFunction:
      {
         GlslFunction *func = new GlslFunction( node->getPlainName().c_str(), node->getName().c_str(),
                                                translateType(node->getTypePointer()), goit->m_UsePrecision?node->getPrecision():EbpUndefined,
											   node->getSemantic().c_str(), node->getLine()); 
         if (func->getReturnType() == EgstStruct)
         {
            GlslStruct *s = goit->createStructFromType( node->getTypePointer());
            func->setStruct(s);
         }
         goit->functionList.push_back( func);
         goit->current = func;
         goit->current->beginBlock( false);
         TIntermSequence::iterator sit;
         TIntermSequence &sequence = node->getSequence(); 
		 for (sit = sequence.begin(); sit != sequence.end(); ++sit)
		 {
			 (*sit)->traverse(it);
		 }
         goit->current->endBlock();
         goit->current = goit->global;
         return false;
      }

   case EOpParameters:
      it->visitSymbol = traverseParameterSymbol;
      {
         TIntermSequence::iterator sit;
         TIntermSequence &sequence = node->getSequence(); 
		 for (sit = sequence.begin(); sit != sequence.end(); ++sit)
           (*sit)->traverse(it);
      }
      it->visitSymbol = traverseSymbol;
      return false;

   case EOpConstructFloat: writeFuncCall( "float", node, goit); return false;
   case EOpConstructVec2:  writeFuncCall( "vec2", node, goit); return false;
   case EOpConstructVec3:  writeFuncCall( "vec3", node, goit); return false;
   case EOpConstructVec4:  writeFuncCall( "vec4", node, goit); return false;
   case EOpConstructBool:  writeFuncCall( "bool", node, goit); return false;
   case EOpConstructBVec2: writeFuncCall( "bvec2", node, goit); return false;
   case EOpConstructBVec3: writeFuncCall( "bvec3", node, goit); return false;
   case EOpConstructBVec4: writeFuncCall( "bvec4", node, goit); return false;
   case EOpConstructInt:   writeFuncCall( "int", node, goit); return false;
   case EOpConstructIVec2: writeFuncCall( "ivec2", node, goit); return false;
   case EOpConstructIVec3: writeFuncCall( "ivec3", node, goit); return false;
   case EOpConstructIVec4: writeFuncCall( "ivec4", node, goit); return false;
		   
   case EOpConstructMat2FromMat:
   case EOpConstructMat2:  writeFuncCall( "mat2", node, goit); return false;
		   
   case EOpConstructMat3FromMat:
   case EOpConstructMat3:  writeFuncCall( "mat3", node, goit); return false;
		   
   case EOpConstructMat4:  writeFuncCall( "mat4", node, goit); return false;
   case EOpConstructStruct:  writeFuncCall( node->getTypePointer()->getTypeName(), node, goit); return false;
   case EOpConstructArray:  writeFuncCall( buildArrayConstructorString(*node->getTypePointer()), node, goit); return false;

   case EOpComma:
      {
         TIntermSequence::iterator sit;
         TIntermSequence &sequence = node->getSequence(); 
         for (sit = sequence.begin(); sit != sequence.end(); ++sit)
         {
            (*sit)->traverse(it);
            if ( sit+1 != sequence.end())
               out << ", ";
         }
      }
      return false;

   case EOpFunctionCall:
      current->addCalledFunction(node->getName().c_str());
      writeFuncCall( node->getPlainName(), node, goit);
      return false; 

   case EOpLessThan:         writeFuncCall( "lessThan", node, goit); return false;
   case EOpGreaterThan:      writeFuncCall( "greaterThan", node, goit); return false;
   case EOpLessThanEqual:    writeFuncCall( "lessThanEqual", node, goit); return false;
   case EOpGreaterThanEqual: writeFuncCall( "greaterThanEqual", node, goit); return false;
   case EOpVectorEqual:      writeFuncCall( "equal", node, goit); return false;
   case EOpVectorNotEqual:   writeFuncCall( "notEqual", node, goit); return false;

   case EOpMod:			  writeFuncCall( "mod", node, goit, true); return false;

   case EOpPow:           writeFuncCall( "pow", node, goit, true); return false;

   case EOpAtan2:         writeFuncCall( "atan", node, goit, true); return false;

   case EOpMin:           writeFuncCall( "min", node, goit, true); return false;
   case EOpMax:           writeFuncCall( "max", node, goit, true); return false;
   case EOpClamp:         writeFuncCall( "clamp", node, goit, true); return false;
   case EOpMix:           writeFuncCall( "mix", node, goit, true); return false;
   case EOpStep:          writeFuncCall( "step", node, goit, true); return false;
   case EOpSmoothStep:    writeFuncCall( "smoothstep", node, goit, true); return false;

   case EOpDistance:      writeFuncCall( "distance", node, goit); return false;
   case EOpDot:           writeFuncCall( "dot", node, goit); return false;
   case EOpCross:         writeFuncCall( "cross", node, goit); return false;
   case EOpFaceForward:   writeFuncCall( "faceforward", node, goit); return false;
   case EOpReflect:       writeFuncCall( "reflect", node, goit); return false;
   case EOpRefract:       writeFuncCall( "refract", node, goit); return false;
   case EOpMul:
      {
         //This should always have two arguments
         assert(node->getSequence().size() == 2);
         current->beginStatement();                     

         out << '(';
         node->getSequence()[0]->traverse(goit);
         out << " * ";
         node->getSequence()[1]->traverse(goit);
         out << ')';

         return false;
      }

      //HLSL texture functions
   case EOpTex1D:
      if (argCount == 2)
         writeTex( "texture1D", node, goit);
      else
      {
         current->addLibFunction(EOpTex1DGrad);
         writeTex( "xll_tex1Dgrad", node, goit);
      }
      return false;

   case EOpTex1DProj:     
      writeTex( "texture1DProj", node, goit); 
      return false;

   case EOpTex1DLod:
      current->addLibFunction(EOpTex1DLod);
      writeTex( "xll_tex1Dlod", node, goit); 
      return false;

   case EOpTex1DBias:
      current->addLibFunction(EOpTex1DBias);
      writeTex( "xll_tex1Dbias", node, goit); 
      return false;

   case EOpTex1DGrad:     
      current->addLibFunction(EOpTex1DGrad);
      writeTex( "xll_tex1Dgrad", node, goit); 
      return false;

   case EOpTex2D:
      if (argCount == 2)
         writeTex( "texture2D", node, goit);
      else
      {
         current->addLibFunction(EOpTex2DGrad);
         writeTex( "xll_tex2Dgrad", node, goit);
      }
      return false;

   case EOpTex2DProj:     
      writeTex( "texture2DProj", node, goit);
      return false;

   case EOpTex2DLod:      
      current->addLibFunction(EOpTex2DLod);
      writeTex( "xll_tex2Dlod", node, goit); 
      return false;

   case EOpTex2DBias:  
      current->addLibFunction(EOpTex2DBias);
      writeTex( "xll_tex2Dbias", node, goit); 
      return false;

   case EOpTex2DGrad:  
      current->addLibFunction(EOpTex2DGrad);
      writeTex( "xll_tex2Dgrad", node, goit); 
      return false;

   case EOpTex3D:
      if (argCount == 2)
         writeTex( "texture3D", node, goit);
      else
      {
         current->addLibFunction(EOpTex3DGrad);
         writeTex( "xll_tex3Dgrad", node, goit);            
      }
      return false;

   case EOpTex3DProj:    
      writeTex( "texture3DProj", node, goit); 
      return false;

   case EOpTex3DLod:     
      current->addLibFunction(EOpTex3DLod);
      writeTex( "xll_tex3Dlod", node, goit); 
      return false;

   case EOpTex3DBias:     
      current->addLibFunction(EOpTex3DBias);
      writeTex( "xll_tex3Dbias", node, goit); 
      return false;

   case EOpTex3DGrad:    
      current->addLibFunction(EOpTex3DGrad);
      writeTex( "xll_tex3Dgrad", node, goit); 
      return false;

   case EOpTexCube:
      if (argCount == 2)
         writeTex( "textureCube", node, goit);
      else
      {
         current->addLibFunction(EOpTexCubeGrad);
         writeTex( "xll_texCUBEgrad", node, goit);
      }
      return false;
   case EOpTexCubeProj:   
      writeTex( "textureCubeProj", node, goit); 
      return false;

   case EOpTexCubeLod:    
      current->addLibFunction(EOpTexCubeLod); 
      writeTex( "xll_texCUBElod", node, goit); 
      return false;

   case EOpTexCubeBias:   
      current->addLibFunction(EOpTexCubeBias); 
      writeTex( "xll_texCUBEbias", node, goit); 
      return false;

   case EOpTexCubeGrad:   
      current->addLibFunction(EOpTexCubeGrad);
      writeTex( "xll_texCUBEgrad", node, goit); 
      return false;

   case EOpTexRect:
	   writeTex( "texture2DRect", node, goit);
	   return false;
	   
   case EOpTexRectProj:
	   writeTex( "texture2DRectProj", node, goit);
	   return false;
		   
   case EOpModf:
      current->addLibFunction(EOpModf);
      writeFuncCall( "xll_modf", node, goit);
      break;

   case EOpLdexp:
      current->addLibFunction(EOpLdexp);
      writeFuncCall( "xll_ldexp", node, goit);
      break;

   case EOpSinCos:        
      current->addLibFunction(EOpSinCos);
      writeFuncCall ( "xll_sincos", node, goit);
      break;

   case EOpLit:
      current->addLibFunction(EOpLit);
      writeFuncCall( "xll_lit", node, goit);
      break;

   default: goit->infoSink.info << "Bad aggregation op\n";
   }


   return false;
}
Example #13
0
void writeComparison( const TString &compareOp, const TString &compareCall, TIntermBinary *node, TGlslOutputTraverser* goit ) 
{
   GlslFunction *current = goit->current;    
   std::stringstream& out = current->getActiveOutput();
   bool bUseCompareCall = false;

   // Determine whether we need the vector or scalar comparison function
   if ( ( node->getLeft() && node->getLeft()->getNominalSize() > 1 ) ||
        ( node->getRight() && node->getRight()->getNominalSize() > 1 ) )
   {
      bUseCompareCall = true;
   }

   current->beginStatement ();

   // Output vector comparison
   if ( bUseCompareCall )
   {
      out << compareCall << "( ";

      if (node->getLeft())
      {
         // If it is a float, need to smear to the size of the right hand side
         if ( node->getLeft()->getNominalSize() == 1 )
         {
            out << "vec" <<  node->getRight()->getNominalSize() << "( ";

            node->getLeft()->traverse(goit);

            out << " )";                
         }
         else
         {
            node->getLeft()->traverse(goit);
         }         
      }
      out << ", ";

      if (node->getRight())
      {
         // If it is a float, need to smear to the size of the left hand side
         if ( node->getRight()->getNominalSize() == 1 )
         {
            out << "vec" <<  node->getLeft()->getNominalSize() << "( ";

            node->getRight()->traverse(goit);

            out << " )";             
         }
         else
         {
            node->getRight()->traverse(goit);
         }         
      }
      out << ")";
   }
   // Output scalar comparison
   else
   {
      out << "(";

      if (node->getLeft())
         node->getLeft()->traverse(goit);
      out << " " << compareOp << " ";
      if (node->getRight())
         node->getRight()->traverse(goit);

      out << ")";
   }
}
Example #14
0
bool TGlslOutputTraverser::traverseSelection( bool preVisit, TIntermSelection *node, TIntermTraverser *it )
{
	TGlslOutputTraverser* goit = static_cast<TGlslOutputTraverser*>(it);
	GlslFunction *current = goit->current;
	std::stringstream& out = current->getActiveOutput();

	current->beginStatement();

	if (node->getBasicType() == EbtVoid)
	{
		// if/else selection
		out << "if (";
		node->getCondition()->traverse(goit);
		out << ')';
		current->beginBlock();
		node->getTrueBlock()->traverse(goit);
		current->endBlock();
		if (node->getFalseBlock())
		{
			current->indent();
			out << "else";
			current->beginBlock();
			node->getFalseBlock()->traverse(goit);
			current->endBlock();
		}
	}
	else if (node->isVector() && node->getCondition()->getAsTyped()->isVector())
	{
		// ?: selection on vectors, e.g. bvec4 ? vec4 : vec4
		// emulate HLSL's component-wise selection here
		current->addLibFunction(EOpVecTernarySel);
		out << "xll_vecTSel (";
		node->getCondition()->traverse(goit);
		out << ", ";
		node->getTrueBlock()->traverse(goit);
		out << ", ";
		if (node->getFalseBlock())
		{
			node->getFalseBlock()->traverse(goit);
		}
		else
			assert(0);
		out << ")";
	}
	else
	{
		// simple ?: selection
		out << "(( ";
		node->getCondition()->traverse(goit);
		out << " ) ? ( ";
		node->getTrueBlock()->traverse(goit);
		out << " ) : ( ";
		if (node->getFalseBlock())
		{
			node->getFalseBlock()->traverse(goit);
		}
		else
			assert(0);
		out << " ))";
	}

	return false;
}
Example #15
0
bool HlslLinker::link(HlslCrossCompiler* compiler, const char* entryFunc, bool usePrecision)
{
	std::vector<GlslFunction*> globalList;
	std::vector<GlslFunction*> functionList;
	std::string entryPoint;
	GlslFunction* funcMain = NULL;
	FunctionSet calledFunctions;
	std::set<TOperator> libFunctions;
	std::map<std::string,GlslSymbol*> globalSymMap;
	std::map<std::string,GlslStruct*> structMap;

	if (!compiler)
	{
		infoSink.info << "No shader compiler provided\n";
		return false;
	}

	EShLanguage lang = compiler->getLanguage();

	if (!entryFunc)
	{
		infoSink.info << "No shader entry function provided\n";
		return false;
	}

	entryPoint = GetEntryName (entryFunc);

	//build the list of functions
	HlslCrossCompiler *comp = static_cast<HlslCrossCompiler*>(compiler);

	std::vector<GlslFunction*> &fl = comp->functionList;

	for ( std::vector<GlslFunction*>::iterator fit = fl.begin(); fit < fl.end(); fit++)
	{
		if ( (*fit)->getName() == "__global__")
			globalList.push_back( *fit);
		else
			functionList.push_back( *fit);

		if ((*fit)->getName() == entryPoint)
		{
			if (funcMain)
			{
				infoSink.info << kShaderTypeNames[lang] << " entry function cannot be overloaded\n";
				return false;
			}
			funcMain = *fit;
		}
	}

	// check to ensure that we found the entry function
	if (!funcMain)
	{
		infoSink.info << "Failed to find entry function: '" << entryPoint <<"'\n";
		return false;
	}

	//add all the called functions to the list
	calledFunctions.push_back (funcMain);
	if (!addCalledFunctions (funcMain, calledFunctions, functionList))
	{
		infoSink.info << "Failed to resolve all called functions in the " << kShaderTypeNames[lang] << " shader\n";
	}

	//iterate over the functions, building a global list of structure declaractions and symbols
	// assume a single compilation unit for expediency (eliminates name clashes, as type checking
	// withing a single compilation unit has been performed)
	for (FunctionSet::iterator it=calledFunctions.begin(); it != calledFunctions.end(); it++)
	{
		//get each symbol and each structure, and add them to the map
		// checking that any previous entries are equivalent
		const std::vector<GlslSymbol*> &symList = (*it)->getSymbols();

		for (std::vector<GlslSymbol*>::const_iterator cit = symList.begin(); cit < symList.end(); cit++)
		{
			if ( (*cit)->getIsGlobal())
			{
				//should check for already added ones here
				globalSymMap[(*cit)->getName()] = *cit;
			}
		}

		//take each referenced library function, and add it to the set
		const std::set<TOperator> &libSet = (*it)->getLibFunctions();

		libFunctions.insert( libSet.begin(), libSet.end());
	}


	// The following code is what is used to generate the actual shader and "main"
	// function. The process is to take all the components collected above, and
	// write them to the appropriate code stream. Finally, a main function is
	// generated that calls the specified entrypoint. That main function uses
	// semantics on the arguments and return values to connect items appropriately.

	//
	// Write Library Functions & required extensions
	std::string shaderExtensions, shaderLibFunctions;
	if (!libFunctions.empty())
	{
		for (std::set<TOperator>::iterator it = libFunctions.begin(); it != libFunctions.end(); it++)
		{
			const std::string &func = getHLSLSupportCode(*it, shaderExtensions, lang==EShLangVertex);
			if (!func.empty())
			{
				shaderLibFunctions += func;
				shaderLibFunctions += '\n';
			}
		}
	}
	shader << shaderExtensions;
	shader << shaderLibFunctions;

	//
	//Structure addition hack
	// Presently, structures are not tracked per function, just dump them all
	// This could be improved by building a complete list of structures for the
	// shaders based on the variables in each function
	//
	{
		HlslCrossCompiler *comp = static_cast<HlslCrossCompiler*>(compiler);
		std::vector<GlslStruct*> &sList = comp->structList;

		if (!sList.empty())
		{
			for (std::vector<GlslStruct*>::iterator it = sList.begin(); it < sList.end(); it++)
			{
				shader << (*it)->getDecl() << "\n";
			}
		}
	}

	//
	// Write global variables
	//

	if (!globalSymMap.empty())
	{
		for (std::map<std::string,GlslSymbol*>::iterator sit = globalSymMap.begin(); sit != globalSymMap.end(); sit++)
		{
			sit->second->writeDecl(shader,false,false);
			shader << ";\n";

			if ( sit->second->getIsMutable() )
			{
				sit->second->writeDecl(shader, true, false);
				shader << ";\n";
			}         
		}
	}

	//
	// Write function declarations and definitions
	//
	EmitCalledFunctions (shader, calledFunctions);

	// 
	// Gather the uniforms into the uniform list
	//
	for (std::map<std::string, GlslSymbol*>::iterator it = globalSymMap.begin(); it != globalSymMap.end(); it++)
	{
		if (it->second->getQualifier() != EqtUniform)
			continue;

		ShUniformInfo infoStruct;
		infoStruct.name = new char[it->first.size()+1];
		strcpy( infoStruct.name, it->first.c_str());
		if (it->second->getSemantic() != "")
		{
			infoStruct.semantic = new char[it->second->getSemantic().size()+1];
			strcpy( infoStruct.semantic, it->second->getSemantic().c_str());
		}
		else
			infoStruct.semantic = 0;

		//gigantic hack, the enumerations are kept in alignment
		infoStruct.type = (EShType)it->second->getType();
		infoStruct.arraySize = it->second->getArraySize();

		if ( it->second->hasInitializer() )
		{
			int initSize = it->second->initializerSize();
			infoStruct.init = new float[initSize];
			memcpy( infoStruct.init, it->second->getInitializer(), sizeof(float) * initSize);
		}
		else
			infoStruct.init = 0;

		//TODO: need to add annotation

		uniforms.push_back( infoStruct);
	}

	//
	// Generate the main function
	//

		std::stringstream attrib;
		std::stringstream uniform;
		std::stringstream preamble;
		std::stringstream postamble;
		std::stringstream varying;
		std::stringstream call;
		const int pCount = funcMain->getParameterCount();

		preamble << "void main() {\n";
		const EGlslSymbolType retType = funcMain->getReturnType();
		GlslStruct *retStruct = funcMain->getStruct();
		if (  retType == EgstStruct)
		{
			assert(retStruct);
			preamble << "    " << retStruct->getName() << " xl_retval;\n";
		}
		else
		{
			if ( retType != EgstVoid)
			{
				preamble << "    ";
				writeType (preamble, retType, NULL, usePrecision?funcMain->getPrecision():EbpUndefined);
				preamble << " xl_retval;\n";
			}
		}

		// Write all mutable initializations
		if ( calledFunctions.size() > 0 )
		{
			for (FunctionSet::iterator fit = calledFunctions.begin(); fit != calledFunctions.end(); fit++)
			{
				std::string mutableDecls = (*fit)->getMutableDecls(1, calledFunctions.begin(), fit);

				if ( mutableDecls.size() > 0 )
				{
					preamble << mutableDecls;
				}
			}
		}

		call << "    ";
		if (retType != EgstVoid)
			call << "xl_retval = " << funcMain->getName() << "( ";
		else
			call << funcMain->getName() << "( ";

		// pass main function parameters
		for (int ii=0; ii<pCount; ii++)
		{
			GlslSymbol *sym = funcMain->getParameter(ii);
			EAttribSemantic attrSem = parseAttributeSemantic( sym->getSemantic());

			switch (sym->getQualifier())
			{

			// -------- IN & OUT parameters
			case EqtIn:
			case EqtInOut:
				if ( sym->getType() != EgstStruct)
				{
					std::string name, ctor;
					int pad;

					if ( getArgumentData( sym, lang==EShLangVertex ? EClassAttrib : EClassVarIn, name, ctor, pad) )
					{
						// In fragment shader, pass zero for POSITION inputs
						bool ignoredPositionInFragment = false;
						if (lang == EShLangFragment && attrSem == EAttrSemPosition)
						{
							call << ctor << "(0.0)";
							ignoredPositionInFragment = true;
						}
						// For "in" parameters, just call directly to the main
						else if ( sym->getQualifier() != EqtInOut )
						{
							call << ctor << "(" << name;
							for (int ii = 0; ii<pad; ii++)
								call << ", 0.0";
							call << ")";
						}
						// For "inout" parameters, declare a temp and initialize the temp
						else
						{
							preamble << "    ";
							writeType (preamble, sym->getType(), NULL, usePrecision?sym->getPrecision():EbpUndefined);
							preamble << " xlt_" << sym->getName() << " = ";
							preamble << ctor << "(" << name;
							for (int ii = 0; ii<pad; ii++)
								preamble << ", 0.0";
							preamble << ");\n";
						}

						if (lang == EShLangVertex) // vertex shader: deal with gl_ attributes
						{
							if ( strncmp( name.c_str(), "gl_", 3))
							{
								int typeOffset = 0;

								// If the type is integer or bool based, we must convert to a float based
								// type.  This is because GLSL does not allow int or bool based vertex attributes.
								if ( sym->getType() >= EgstInt && sym->getType() <= EgstInt4)
								{
									typeOffset += 4;
								}

								if ( sym->getType() >= EgstBool && sym->getType() <= EgstBool4)
								{
									typeOffset += 8;
								}

								// This is an undefined attribute
								attrib << "attribute " << getTypeString((EGlslSymbolType)(sym->getType() + typeOffset)) << " " << name << ";\n";
							}
						}

						if (lang == EShLangFragment) // deal with varyings
						{
							if (!ignoredPositionInFragment)
								AddToVaryings (varying, sym->getPrecision(), ctor, name);
						}
					}
					else
					{
						//should deal with fall through cases here
						assert(0);
						infoSink.info << "Unsupported type for shader entry parameter (";
						infoSink.info << getTypeString(sym->getType()) << ")\n";
					}
				}
				else
				{
					//structs must pass the struct, then process per element
					GlslStruct *Struct = sym->getStruct();
					assert(Struct);

					//first create the temp
					std::string tempVar = "xlt_" + sym->getName();
					preamble << "    " << Struct->getName() << " ";
					preamble << tempVar <<";\n";
					call << tempVar;

					const int elem = Struct->memberCount();
					for (int jj=0; jj<elem; jj++)
					{
						const GlslStruct::member &current = Struct->getMember(jj);
						EAttribSemantic memberSem = parseAttributeSemantic (current.semantic);
						std::string name, ctor;
						int pad;
						int numArrayElements = 1;
						bool bIsArray = false;

						// If it is an array, loop over each member
						if ( current.arraySize > 0 )
						{
							numArrayElements = current.arraySize;
							bIsArray = true;
						}

						for ( int arrayIndex = 0; arrayIndex <  numArrayElements; arrayIndex++ )
						{
							if ( getArgumentData2( current.name, current.semantic, current.type,
								lang==EShLangVertex ? EClassAttrib : EClassVarIn, name, ctor, pad, arrayIndex ) )
							{

								preamble << "    ";
								preamble << tempVar << "." << current.name;

								if ( bIsArray )
									preamble << "[" << arrayIndex << "]";

								// In fragment shader, pass zero for POSITION inputs
								bool ignoredPositionInFragment = false;
								if (lang == EShLangFragment && memberSem == EAttrSemPosition)
								{
									preamble << " = " << ctor << "(0.0);\n";
									ignoredPositionInFragment = true;
								}
								else
								{
									preamble << " = " << ctor << "( " << name;
									for (int ii = 0; ii<pad; ii++)
										preamble << ", 0.0";
									preamble << ");\n";
								}

								if (lang == EShLangVertex) // vertex shader: gl_ attributes
								{
									if ( strncmp( name.c_str(), "gl_", 3))
									{

										int typeOffset = 0;

										// If the type is integer or bool based, we must convert to a float based
										// type.  This is because GLSL does not allow int or bool based vertex attributes.
										if ( current.type >= EgstInt && current.type <= EgstInt4)
										{
											typeOffset += 4;
										}

										if ( current.type >= EgstBool && current.type <= EgstBool4)
										{
											typeOffset += 8;
										}

										// This is an undefined attribute
										attrib << "attribute " << getTypeString((EGlslSymbolType)(current.type + typeOffset)) << " " << name << ";\n";

									}
								}
								
								if (lang == EShLangFragment) // deal with varyings
								{
									if (!ignoredPositionInFragment)
										AddToVaryings (varying, current.precision, ctor, name);
								}
							}
							else
							{
								//should deal with fall through cases here
								assert(0);
								infoSink.info << "Unsupported type for struct element in shader entry parameter (";
								infoSink.info << getTypeString(current.type) << ")\n";
							}
						}
					}
				}

				//
				// NOTE: This check only breaks out of the case if we have an "in" parameter, for
				//       "inout" it will fallthrough to the next case
				//
				if ( sym->getQualifier() != EqtInOut )
				{
					break;
				}


			// -------- OUT parameters; also fall-through for INOUT (see the check above)
			case EqtOut:

				if ( sym->getType() != EgstStruct)
				{
					std::string name, ctor;
					int pad;

					if ( getArgumentData( sym, lang==EShLangVertex ? EClassVarOut : EClassRes, name, ctor, pad) )
					{
						// For "inout" parameters, the preamble was already written so no need to do it here.
						if ( sym->getQualifier() != EqtInOut )
						{
							preamble << "    ";
							writeType (preamble, sym->getType(), NULL, usePrecision?sym->getPrecision():EbpUndefined);
							preamble << " xlt_" << sym->getName() << ";\n";                     
						}
						
						if (lang == EShLangVertex) // deal with varyings
						{
							AddToVaryings (varying, sym->getPrecision(), ctor, name);
						}

						call << "xlt_" << sym->getName();

						postamble << "    ";
						postamble << name << " = " << ctor << "( xlt_" <<sym->getName();
						for (int ii = 0; ii<pad; ii++)
							postamble << ", 0.0";

						postamble << ");\n";
					}
					else
					{
						//should deal with fall through cases here
						assert(0);
						infoSink.info << "Unsupported type for shader entry parameter (";
						infoSink.info << getTypeString(sym->getType()) << ")\n";
					}
				}
				else
				{
					//structs must pass the struct, then process per element
					GlslStruct *Struct = sym->getStruct();
					assert(Struct);

					//first create the temp
					std::string tempVar = "xlt_" + sym->getName();

					// For "inout" parmaeters the preamble and call were already written, no need to do it here
					if ( sym->getQualifier() != EqtInOut )
					{
						preamble << "    " << Struct->getName() << " ";
						preamble << tempVar <<";\n";
						call << tempVar;
					}

					const int elem = Struct->memberCount();
					for (int ii=0; ii<elem; ii++)
					{
						const GlslStruct::member &current = Struct->getMember(ii);
						std::string name, ctor;
						int pad;

						if ( getArgumentData2( current.name, current.semantic, current.type, lang==EShLangVertex ? EClassVarOut : EClassRes, name, ctor, pad, 0) )
						{
							postamble << "    ";
							postamble << name << " = " << ctor;
							postamble << "( " << tempVar << "." << current.name;
							for (int ii = 0; ii<pad; ii++)
								postamble << ", 0.0";

							postamble << ");\n";

							if (lang == EShLangVertex) // deal with varyings
							{
								AddToVaryings (varying, current.precision, ctor, name);
							}
						}
						else
						{
							//should deal with fall through cases here
							assert(0);
							infoSink.info << "Unsupported type in struct element for shader entry parameter (";
							infoSink.info << getTypeString(current.type) << ")\n";
						}
					}
				}
				break;

			case EqtUniform:
				uniform << "uniform ";
				writeType (uniform, sym->getType(), NULL, usePrecision?sym->getPrecision():EbpUndefined);
				uniform << " xlu_" << sym->getName() << ";\n";
				call << "xlu_" << sym->getName();
				break;

			default:
				assert(0);
			};
			if (ii != pCount -1)
				call << ", ";
		}

		call << ");\n";


		// -------- return value of main entry point
		if (retType != EgstVoid)
		{

			if (retType != EgstStruct)
			{
				std::string name, ctor;
				int pad;

				if ( getArgumentData2( "", funcMain->getSemantic(), retType, lang==EShLangVertex ? EClassVarOut : EClassRes,
					name, ctor, pad, 0) )
				{

					postamble << "    ";
					postamble << name << " = " << ctor << "( xl_retval";
					for (int ii = 0; ii<pad; ii++)
						postamble << ", 0.0";

					postamble << ");\n";

					if (lang == EShLangVertex) // deal with varyings
					{
						AddToVaryings (varying, funcMain->getPrecision(), ctor, name);
					}
				}
				else
				{
					//should deal with fall through cases here
					assert(0);
					infoSink.info << (lang==EShLangVertex ? "Unsupported type for shader return value (" : "Unsupported return type for shader entry function (");
					infoSink.info << getTypeString(retType) << ")\n";
				}
			}
			else
			{
				const int elem = retStruct->memberCount();
				for (int ii=0; ii<elem; ii++)
				{
					const GlslStruct::member &current = retStruct->getMember(ii);
					std::string name, ctor;
					int pad;
					int numArrayElements = 1;
					bool bIsArray = false;

					if (lang == EShLangVertex) // vertex shader
					{
						// If it is an array, loop over each member
						if ( current.arraySize > 0 )
						{
							numArrayElements = current.arraySize;
							bIsArray = true;
						}
					}

					for ( int arrayIndex = 0; arrayIndex < numArrayElements; arrayIndex++ )
					{

						if ( getArgumentData2( current.name, current.semantic, current.type, lang==EShLangVertex ? EClassVarOut : EClassRes, name, ctor, pad, arrayIndex) )
						{
							postamble << "    ";
							postamble << name;                                                            
							postamble << " = " << ctor;
							postamble << "( xl_retval." << current.name;
							if ( bIsArray )
							{
								postamble << "[" << arrayIndex << "]";
							}
							for (int ii = 0; ii<pad; ii++)
								postamble << ", 0.0";

							postamble << ");\n";

							if (lang == EShLangVertex) // deal with varyings
							{
								AddToVaryings (varying, current.precision, ctor, name);
							}
						}
						else
						{
							//should deal with fall through cases here
							//assert(0);
							infoSink.info << (lang==EShLangVertex ? "Unsupported element type in struct for shader return value (" : "Unsupported struct element type in return type for shader entry function (");
							infoSink.info << getTypeString(current.type) << ")\n";
							return false;
						}
					}
				}
			}
		}
		else
		{
			if (lang == EShLangFragment) // fragment shader
			{
				// If no return type, close off the output
				postamble << ";\n";
			}
		}

		postamble << "}\n\n";

		EmitIfNotEmpty (shader, uniform);
		EmitIfNotEmpty (shader, attrib);
		EmitIfNotEmpty (shader, varying);

		shader << preamble.str() << "\n";
		shader << call.str() << "\n";
		shader << postamble.str() << "\n";

	return true;
}
Example #16
0
bool HlslLinker::link(HlslCrossCompiler* compiler, const char* entryFunc, ETargetVersion targetVersion, unsigned options)
{
	m_Target = targetVersion;
	m_Options = options;
	m_Extensions.clear();
	if (!linkerSanityCheck(compiler, entryFunc))
		return false;
	
	const bool usePrecision = Hlsl2Glsl_VersionUsesPrecision(targetVersion);
	
	EShLanguage lang = compiler->getLanguage();
	std::string entryPoint = GetEntryName (entryFunc);
	
	
	// figure out all relevant functions
	GlslFunction* globalFunction = NULL;
	std::vector<GlslFunction*> functionList;
	FunctionSet calledFunctions;
	GlslFunction* funcMain = NULL;
	if (!buildFunctionLists(compiler, lang, entryPoint, globalFunction, functionList, calledFunctions, funcMain))
		return false;
	assert(globalFunction);
	assert(funcMain);
	
	// uniforms and used built-in functions
	std::vector<GlslSymbol*> constants;
	std::set<TOperator> libFunctions;
	buildUniformsAndLibFunctions(calledFunctions, constants, libFunctions);
	// add built-in functions possibly used by uniform initializers
	const std::set<TOperator>& referencedGlobalFunctions = globalFunction->getLibFunctions();
	libFunctions.insert (referencedGlobalFunctions.begin(), referencedGlobalFunctions.end());
	
	buildUniformReflection (constants);


	// print all the components collected above.

	emitLibraryFunctions (libFunctions, lang, usePrecision);
	emitStructs(compiler);
	emitGlobals (globalFunction, constants);
	EmitCalledFunctions (shader, calledFunctions);

	
	// Generate a main function that calls the specified entrypoint.
	// That main function uses semantics on the arguments and return values to
	// connect items appropriately.	
	
	std::stringstream attrib;
	std::stringstream uniform;
	std::stringstream preamble;
	std::stringstream postamble;
	std::stringstream varying;
	std::stringstream call;

	markDuplicatedInSemantics(funcMain);

	// Declare return value
	const EGlslSymbolType retType = funcMain->getReturnType();
	emitMainStart(compiler, retType, funcMain, m_Options, usePrecision, preamble, constants);
	

	// Call the entry point
	call << "    ";
	if (retType != EgstVoid)
		call << "xl_retval = ";
	call << funcMain->getName() << "( ";
	

	// Entry point parameters
	const int pCount = funcMain->getParameterCount();
	for (int ii=0; ii<pCount; ii++)
	{
		GlslSymbol *sym = funcMain->getParameter(ii);
		EAttribSemantic attrSem = parseAttributeSemantic( sym->getSemantic());
		
		add_extension_from_semantic(attrSem, m_Target, m_Extensions);

		switch (sym->getQualifier())
		{

		// -------- IN & OUT parameters
		case EqtIn:
		case EqtInOut:
		case EqtConst:
			if (sym->getType() != EgstStruct)
			{
				emitInputNonStructParam(sym, lang, usePrecision, attrSem, attrib, varying, preamble, call);
			}
			else
			{
				emitInputStructParam(sym, lang, attrib, varying, preamble, call);
			}

			// NOTE: for "inout" parameters need to fallthrough to the next case
			if (sym->getQualifier() != EqtInOut)
			{
				break;
			}


		// -------- OUT parameters; also fall-through for INOUT (see the check above)
		case EqtOut:

			if ( sym->getType() != EgstStruct)
			{
				emitOutputNonStructParam(sym, lang, usePrecision, attrSem, varying, preamble, postamble, call);
			}
			else
			{
				emitOutputStructParam(sym, lang, usePrecision, attrSem, varying, preamble, postamble, call);
			}
			break;

		case EqtUniform:
			uniform << "uniform ";
			writeType (uniform, sym->getType(), NULL, usePrecision?sym->getPrecision():EbpUndefined);
			uniform << " xlu_" << sym->getName();
			if(sym->getArraySize())
				uniform << "[" << sym->getArraySize() << "]";
			uniform << ";\n";
			call << "xlu_" << sym->getName();
			break;

		default:
			assert(0);
		};
		if (ii != pCount -1)
			call << ", ";
	}

	call << ");\n";


	// Entry point return value
	if (!emitReturnValue(retType, funcMain, lang, varying, postamble))
		return false;

	postamble << "}\n\n";
	
	
	// Generate final code of the pieces above.
	{
		shaderPrefix << kTargetVersionStrings[targetVersion];
		ExtensionSet::const_iterator it = m_Extensions.begin(), end = m_Extensions.end();
		for (; it != end; ++it)
			shaderPrefix << "#extension " << *it << " : require" << std::endl;
	}

	EmitIfNotEmpty (shader, uniform);
	EmitIfNotEmpty (shader, attrib);
	EmitIfNotEmpty (shader, varying);

	shader << preamble.str() << "\n";
	shader << call.str() << "\n";
	shader << postamble.str() << "\n";

	return true;
}