virtual bool isInSameIndependentArray(const OperationNode<Base>& indep1,
                                          const OperationNode<Base>& indep2) override {
        size_t index1 = indep1.getVariableID() - 1;
        size_t index2 = indep2.getVariableID() - 1;

        return (index1 > indepNames_.size() || indepNames_[index1].empty()) &&
                (index2 > indepNames_.size() || indepNames_[index2].empty());
    }
    inline const IndexDclrOperationNode<Base>& getIndex() const {
        const std::vector<Argument<Base> >& args = this->getArguments();
        CPPADCG_ASSERT_KNOWN(!args.empty(), "Invalid number of arguments");

        OperationNode<Base>* aNode = args[0].getOperation();
        CPPADCG_ASSERT_KNOWN(aNode != nullptr && aNode->getOperationType() == CGOpCode::IndexDeclaration, "Invalid argument operation type");

        return static_cast<const IndexDclrOperationNode<Base>&> (*aNode);
    }
    virtual bool isConsecutiveInIndepArray(const OperationNode<Base>& indepFirst,
                                           const OperationNode<Base>& indepSecond) override {
        size_t index1 = indepFirst.getVariableID() - 1;
        size_t index2 = indepSecond.getVariableID() - 1;

        if ((index1 > indepNames_.size() || indepNames_[index1].empty()) &&
                (index2 > indepNames_.size() || indepNames_[index2].empty())) {
            return index1 + 1 == index2;
        } else {
            return false; // individual names used (not elements of arrays)
        }
    }
    virtual bool isConsecutiveInIndepArray(const OperationNode<Base>& indepFirst,
                                           const OperationNode<Base>& indepSecond) override {
        size_t id1 = indepFirst.getVariableID();
        size_t id2 = indepSecond.getVariableID();

        if ((id1 < _minMultiplierID) != (id2 < _minMultiplierID))
            return false;

        if (id1 < _minMultiplierID && id2 < _minMultiplierID)
            return _nameGen->isConsecutiveInIndepArray(indepFirst, indepSecond);
        else
            return id1 + 1 == id2;
    }
    /**
     * @note overrides the default processActiveOut() even though this method
     *        is not virtual (hides a method in EvaluatorOperations)
     */
    void processActiveOut(const OperationNode<ScalarIn>& node,
                          ActiveOut& a) {
        if (node.getName() != nullptr) {
            if(adcgName_ && CppAD::Variable(a)) {
                ScalarOut a2(CppAD::Value(CppAD::Var2Par(a)));
                if (a2.getOperationNode() != nullptr) {
                    a2.getOperationNode()->setName(*node.getName());
                }
            }

            if (printFor_) {
                CppAD::PrintFor(printForPos_, "", a, node.getName()->c_str());
            }
        }
    }
inline std::string LanguageLatex<Base>::linearIndexPattern2String(const LinearIndexPattern& lip,
                                                                  const OperationNode<Base>& index) {
    long dy = lip.getLinearSlopeDy();
    long dx = lip.getLinearSlopeDx();
    long b = lip.getLinearConstantTerm();
    long xOffset = lip.getXOffset();

    std::stringstream ss;
    if (dy != 0) {
        if (xOffset != 0) {
            ss << "\\left(";
        }
        ss << (*index.getName());
        if (xOffset != 0) {
            ss << " - " << xOffset << "\\right)";
        }

        if (dx != 1) {
            ss << " / " << dx;
        }
        if (dy != 1) {
            ss << " \\cdot " << dy;
        }
    } else if (b == 0) {
        ss << "0"; // when dy == 0 and b == 0
    }

    if (b != 0) {
        if (dy != 0)
            ss << " + ";
        ss << b;
    }
    return ss.str();
}
    inline void addFreeArraySpace(const OperationNode<Base>& released) {
        size_t arrayStart = _varId[released] - 1;
        const size_t arraySize = released.getArguments().size();
        if (arraySize == 0)
            return; // nothing to do (no free space)
        size_t arrayEnd = arrayStart + arraySize - 1;

        std::map<size_t, size_t>::iterator it;
        if (arrayStart > 0) {
            // try to merge with previous free space
            it = _freeArrayEndSpace.find(arrayStart - 1); // previous
            if (it != _freeArrayEndSpace.end()) {
                arrayStart = it->second; // merge space
                _freeArrayEndSpace.erase(it);
                _freeArrayStartSpace.erase(arrayStart);
            }
        }

        // try to merge with the next free space
        it = _freeArrayStartSpace.find(arrayEnd + 1); // next
        if (it != _freeArrayStartSpace.end()) {
            arrayEnd = it->second; // merge space 
            _freeArrayStartSpace.erase(it);
            _freeArrayEndSpace.erase(arrayEnd);
        }

        _freeArrayStartSpace[arrayStart] = arrayEnd;
        _freeArrayEndSpace[arrayEnd] = arrayStart;

        CPPADCG_ASSERT_UNKNOWN(_freeArrayStartSpace.size() == _freeArrayEndSpace.size());
    }
 virtual std::string generateIndependent(const OperationNode<Base>& independent) override {
     size_t index = independent.getVariableID() - 1;
     if (index < indepNames_.size() && !indepNames_[index].empty()) {
         return indepNames_[index];
     } else {
         return Super::generateIndependent(independent);
     }
 }
    virtual std::string generateIndependent(const OperationNode<Base>& independent) override {
        size_t id = independent.getVariableID();
        if (id < _minMultiplierID) {
            return _nameGen->generateIndependent(independent);
        }

        _ss.clear();
        _ss.str("");
        _ss << _multName << "[" << (id - _minMultiplierID) << "]";
        return _ss.str();
    }
    virtual std::string generateIndexedIndependent(const OperationNode<Base>& indexedIndep,
            const IndexPattern& ip) override {
        bool isX = indexedIndep.getInfo()[0] == 0;
        if (isX) {
            return _nameGen->generateIndexedIndependent(indexedIndep, ip);
        }

        size_t nIndex = indexedIndep.getArguments().size();

        CPPADCG_ASSERT_KNOWN(indexedIndep.getOperationType() == CGOpCode::LoopIndexedIndep, "Invalid node type");
        CPPADCG_ASSERT_KNOWN(nIndex > 0, "Invalid number of arguments");

        std::vector<const IndexDclrOperationNode<Base>*> indices(nIndex);
        for (size_t i = 0; i < nIndex; ++i) {// typically there is only one index but there may be more
            CPPADCG_ASSERT_KNOWN(indexedIndep.getArguments()[i].getOperation() != nullptr, "Invalid argument");
            CPPADCG_ASSERT_KNOWN(indexedIndep.getArguments()[i].getOperation()->getOperationType() == CGOpCode::Index, "Invalid argument");
            indices[i] = &static_cast<const IndexOperationNode<Base>&> (*indexedIndep.getArguments()[i].getOperation()).getIndex();
        }

        _ss.clear();
        _ss.str("");

        _ss << _multName << "[" << LanguageC<Base>::indexPattern2String(ip, indices) << "]";
        return _ss.str();
    }
    virtual bool isInSameIndependentArray(const OperationNode<Base>& indep1,
                                          const OperationNode<Base>& indep2) override {
        size_t l1;
        if (indep1.getOperationType() == CGOpCode::Inv) {
            l1 = indep1.getVariableID() < _minMultiplierID ? 0 : 1;
        } else {
            l1 = indep1.getInfo()[0]; //CGLoopIndexedIndepOp
        }

        size_t l2;
        if (indep2.getOperationType() == CGOpCode::Inv) {
            l2 = indep2.getVariableID() < _minMultiplierID ? 0 : 1;
        } else {
            l2 = indep2.getInfo()[0]; //CGLoopIndexedIndepOp
        }

        return l1 == l2;
    }
Beispiel #12
0
ptr<ShaderSource> Hlsl11GeneratorInstance::Generate()
{
	// first stage: register all nodes
	RegisterNode(rootNode);

	// find out if we need instance id
	for(size_t i = 0; i < nodeInits.size(); ++i)
	{
		Node* node = nodeInits[i];
		if(node->GetType() == Node::typeOperation)
		{
			OperationNode* operationNode = fast_cast<OperationNode*>(node);
			if(operationNode->GetOperation() == OperationNode::operationGetInstanceID)
				needInstanceID = true;
		}
	}

	// выборы в зависимости от типа шейдера
	const char* mainFunctionName;
	const char* inputTypeName;
	const char* inputName;
	const char* outputTypeName;
	const char* outputName;
	const char* profile;
	switch(shaderType)
	{
	case ShaderTypes::vertex:
		mainFunctionName = "VS";
		inputTypeName = "A";
		inputName = "a";
		outputTypeName = "V";
		outputName = "v";
		profile = "vs_4_0";
		break;
	case ShaderTypes::pixel:
		mainFunctionName = "PS";
		inputTypeName = "V";
		inputName = "v";
		outputTypeName = "R";
		outputName = "r";
		profile = "ps_4_0";
		break;
	default:
		THROW("Unknown shader type");
	}

	// вывести атрибуты, если вершинный шейдер
	if(shaderType == ShaderTypes::vertex)
	{
		text << "struct A\n{\n";

		struct IndexSorter
		{
			bool operator()(AttributeNode* a, AttributeNode* b) const
			{
				return a->GetElementIndex() < b->GetElementIndex();
			}
		};

		std::sort(attributes.begin(), attributes.end(), IndexSorter());
		for(size_t i = 0; i < attributes.size(); ++i)
		{
			AttributeNode* node = attributes[i];
			text << '\t';
			PrintDataType(node->GetValueType());
			int index = node->GetElementIndex();
			text << " a" << index << " : " << Dx11System::GetSemanticString(index) << ";\n";
		}
		text << "};\n";
	}

	// print transformed nodes
	if(shaderType == ShaderTypes::pixel)
	{
		text << "struct V\n{\n";

		struct SemanticSorter
		{
			bool operator()(TransformedNode* a, TransformedNode* b) const
			{
				return a->GetSemantic() < b->GetSemantic();
			}
		};

		std::sort(transformedNodes.begin(), transformedNodes.end(), SemanticSorter());

		for(size_t i = 0; i < transformedNodes.size(); ++i)
		{
			TransformedNode* node = transformedNodes[i];
			text << '\t';
			PrintDataType(node->GetValueType());
			int semantic = node->GetSemantic();
			text << " v" << semantic << " : " << Dx11System::GetSemanticString(semantic) << ";\n";
		}

		text << "};\n";
	}

	// print interpolate nodes
	if(shaderType == ShaderTypes::vertex)
	{
		text << "struct V\n{\n";

		struct SemanticSorter
		{
			bool operator()(InterpolateNode* a, InterpolateNode* b) const
			{
				return a->GetSemantic() < b->GetSemantic();
			}
		};

		std::sort(interpolateNodes.begin(), interpolateNodes.end(), SemanticSorter());

		for(size_t i = 0; i < interpolateNodes.size(); ++i)
		{
			InterpolateNode* node = interpolateNodes[i];
			text << '\t';
			PrintDataType(node->GetValueType());
			int semantic = node->GetSemantic();
			text << " v" << semantic << " : " << Dx11System::GetSemanticString(semantic) << ";\n";
		}

		// вывести SV_Position
		text << "\tfloat4 vTP : SV_Position;\n";

		text << "};\n";
	}

	// вывести пиксельные переменные, если это пиксельный шейдер
	if(shaderType == ShaderTypes::pixel)
	{
		text << "struct R\n{\n";

		for(int i = 0; i < fragmentTargetsCount; ++i)
		{
			text << '\t';
			PrintDataType(DataTypes::_vec4);
			text << " r" << i << " : SV_Target" << i << ";\n";
		}

		text << "};\n";
	}

	// вывести uniform-буферы
	PrintUniforms();

	// семплеры
	struct SamplerSlotSorter
	{
		bool operator()(SamplerNode* a, SamplerNode* b) const
		{
			return a->GetSlot() < b->GetSlot();
		}
	};
	std::sort(samplers.begin(), samplers.end(), SamplerSlotSorter());
	for(size_t i = 0; i < samplers.size(); ++i)
	{
		SamplerNode* samplerNode = samplers[i];
		const char* textureStr;
		switch(samplerNode->GetCoordType())
		{
		case SamplerNode::_1D:
			textureStr = "Texture1D";
			break;
		case SamplerNode::_2D:
			textureStr = "Texture2D";
			break;
		case SamplerNode::_3D:
			textureStr = "Texture3D";
			break;
		case SamplerNode::_Cube:
			textureStr = "TextureCube";
			break;
		default:
			THROW("Invalid sampler coord type");
		}
		// текстура
		text << textureStr << '<';
		PrintDataType(samplerNode->GetValueType());
		int slot = samplerNode->GetSlot();
		text << "> t" << slot << " : register(t" << slot << ");\n";
		// семплер
		text << "SamplerState s" << slot << " : register(s" << slot << ");\n";
	}

	//** заголовок функции шейдера

	text << outputTypeName << ' ' << mainFunctionName << '(' << inputTypeName << ' ' << inputName;

	// если шейдер использует instance ID, добавить аргумент
	if(needInstanceID)
		text << ", uint sI : SV_InstanceID";

	// завершить заголовок
	text << ")\n{\n\t" << outputTypeName << ' ' << outputName << ";\n";

	// shader code
	for(size_t i = 0; i < nodeInits.size(); ++i)
		PrintNodeInit(i);

	// завершение шейдера
	text << "\treturn " << outputName << ";\n}\n";

	// получить маски ресурсов
	int uniformBuffersMask = 0;
	for(size_t i = 0; i < uniforms.size(); ++i)
		uniformBuffersMask |= 1 << uniforms[i].first->GetSlot();
	int samplersMask = 0;
	for(size_t i = 0; i < samplers.size(); ++i)
		samplersMask |= 1 << samplers[i]->GetSlot();
	Dx11ShaderResources resources(uniformBuffersMask, samplersMask);

	return NEW(Hlsl11Source(Strings::String2File(text.str()), mainFunctionName, profile, resources));
}
Beispiel #13
0
bool Parser::Parse(const std::vector<Token>& inTokens, Node **outParseTree)
{
    Node* rootNode = new Node(kNodeType_Root);
    unsigned int tokenCount = inTokens.size();

    int scopeLevel = 0;
    bool inComment = false;
    TextureNode* currentTextureNode = nullptr;
    OperationNode* currentOperationNode = nullptr;

    for(unsigned int index = 0; index < tokenCount; ++index)
    {
        const Token& currentToken = inTokens[index];
        switch(currentToken.GetType())
        {
            case kToken_ScopeBegin:
            {
                if( !inComment )
                {
                    // We're opening a new texture scope so it shouldn't be null
                    assert( currentTextureNode != nullptr );

                    scopeLevel++;
                }
                break;
            }
            case kToken_ScopeEnd:
            {
                if( !inComment )
                {
                    // We're closing a texture scope so it shouldn't be null
                    assert( currentTextureNode != nullptr );
                    scopeLevel--;

                    rootNode->InsertNode( currentTextureNode );
                    currentTextureNode = nullptr;
                }
                break;
            }
            case kToken_CommentBegin:
            {
                assert( !inComment );
                inComment = true;
                break;
            }
            case kToken_CommentEnd:
            {
                assert( inComment );
                inComment = false;
                break;
            }
            case kToken_Terminator:
            {
                if( !inComment )
                {
                    // Terminate the operation
                    assert( currentOperationNode != nullptr );
                    assert( currentTextureNode != nullptr );

                    currentTextureNode->InsertNode( currentOperationNode );
                    currentOperationNode = nullptr;
                }
                break;
            }
            case kToken_Identifier:
            {
                if( !inComment )
                {
                    // Start a new texture if we're not in one
                    if( currentTextureNode == nullptr )
                    {
                        IdentifierTokenData* tokenData = static_cast<IdentifierTokenData*>(currentToken.GetData());

                        assert( tokenData->GetValue().compare( "Texture" ) == 0 );

                        // Free the data here. This means the tokens are one time use
                        delete tokenData;

                        currentTextureNode = new TextureNode( "Undefined" );
                    }
                    else
                    {
                        // We're still looking for a name
                        if( currentTextureNode->GetName().compare( "Undefined") == 0 )
                        {
                            IdentifierTokenData* tokenData = static_cast<IdentifierTokenData*>(currentToken.GetData());

                            // Make sure no one tries to name it "Undefined"
                            assert( tokenData->GetValue().compare( "Undefined" ) != 0 );

                            currentTextureNode->SetName( tokenData->GetValue() );

                            // Free the data here. This means the tokens are one time use
                            delete tokenData;

                            // We also need width height and pixel depth
                            assert( index + 3 < tokenCount );
                            assert( inTokens[index+1].GetType() == kToken_Number );
                            assert( inTokens[index+2].GetType() == kToken_Number );
                            assert( inTokens[index+3].GetType() == kToken_Number );

                            NumberTokenData* widthData = static_cast<NumberTokenData*>(inTokens[index+1].GetData());
                            NumberTokenData* heightData = static_cast<NumberTokenData*>(inTokens[index+2].GetData());
                            NumberTokenData* pixelDepthData = static_cast<NumberTokenData*>(inTokens[index+3].GetData());

                            currentTextureNode->SetWidth( widthData->GetValue() );
                            currentTextureNode->SetHeight( heightData->GetValue() );
                            currentTextureNode->SetPixelDepth( pixelDepthData->GetValue() );

                            delete widthData;
                            delete heightData;
                            delete pixelDepthData;
                        }
                        else
                        {
                            // We're looking for operations now.
                            assert( currentOperationNode == nullptr );

                            IdentifierTokenData* tokenData = static_cast<IdentifierTokenData*>(currentToken.GetData());
                            currentOperationNode = new OperationNode( tokenData->GetValue() );

                            // Free the data here. This means the tokens are one time use
                            delete tokenData;
                        }
                    }
                }
                break;
            }
            case kToken_Number:
            {
                if( !inComment )
                {
                    // Add arguments to the operation
                    if( currentOperationNode != nullptr )
                    {
                        NumberTokenData* tokenData = static_cast<NumberTokenData*>(currentToken.GetData());
                        currentOperationNode->AddArgument( tokenData->GetValue() );

                        // Free the data here. This means the tokens are one time use
                        delete tokenData;
                    }
                }
                break;
            }

            case kToken_Undefined:
            default:
            {
                std::cout << "Error! Undefined token encountered!" << std::endl;
                delete rootNode;
                return false;
            }
        }
    }

    *outParseTree = rootNode;
    return true;
}
 virtual size_t getIndependentArrayIndex(const OperationNode<Base>& indep) override {
     if (indep.getVariableID() < _minMultiplierID)
         return _nameGen->getIndependentArrayIndex(indep);
     else
         return indep.getVariableID() - _minMultiplierID;
 }
Beispiel #15
0
void GlslGeneratorInstance::PrintNodeInit(size_t nodeIndex)
{
	Node* node = nodeInits[nodeIndex];

	switch(node->GetType())
	{
	case Node::typeFloatConst:
		PrintNodeInitBegin(nodeIndex);
		text << std::fixed << std::setprecision(10) << fast_cast<FloatConstNode*>(node)->GetValue();// << 'f';
		PrintNodeInitEnd();
		break;
	case Node::typeIntConst:
		PrintNodeInitBegin(nodeIndex);
		text << fast_cast<IntConstNode*>(node)->GetValue();
		PrintNodeInitEnd();
		break;
	case Node::typeAttribute:
		{
			AttributeNode* attributeNode = fast_cast<AttributeNode*>(node);
			PrintNodeInitBegin(nodeIndex);
			// WebGL hack for integer attributes
			// (only for case of using another hack - changing integer attributes to float)
			bool intConversion = false;
			if(glslVersion == GlslVersions::webgl)
				intConversion = PrintWebGLConversionToIntegerBegin(attributeNode->GetValueType());

			text << "a" << attributeNode->GetElementIndex();

			if(intConversion)
				PrintWebGLConversionToIntegerEnd();
			PrintNodeInitEnd();
		}
		break;
	case Node::typeUniform:
		// uniform doesn't have initialization
		break;
	case Node::typeSampler:
		// sampler doesn't have initialization
		break;
	case Node::typeReadUniform:
		{
			PrintNodeInitBegin(nodeIndex);
			ReadUniformNode* readUniformNode = fast_cast<ReadUniformNode*>(node);
			PrintUniform(readUniformNode->GetUniformNode());
			PrintNodeInitEnd();
		}
		break;
	case Node::typeIndexUniformArray:
		{
			PrintNodeInitBegin(nodeIndex);
			IndexUniformArrayNode* indexUniformArrayNode = fast_cast<IndexUniformArrayNode*>(node);
			PrintUniform(indexUniformArrayNode->GetUniformNode());
			text << '[';
			PrintNode(indexUniformArrayNode->GetIndexNode());
			text << ']';
			PrintNodeInitEnd();
		}
		break;
	case Node::typeTransformed:
		PrintNodeInitBegin(nodeIndex);
		text << "v" << fast_cast<TransformedNode*>(node)->GetSemantic();
		PrintNodeInitEnd();
		break;
	case Node::typeInterpolate:
		{
			InterpolateNode* interpolateNode = fast_cast<InterpolateNode*>(node);
			text << "\tv" << interpolateNode->GetSemantic() << " = ";
			PrintNode(interpolateNode->GetNode());
			PrintNodeInitEnd();
		}
		break;
	case Node::typeSequence:
		// sequence node doesn't have initialization
		break;
	case Node::typeSwizzle:
		{
			PrintNodeInitBegin(nodeIndex);
			SwizzleNode* swizzleNode = fast_cast<SwizzleNode*>(node);
			PrintNode(swizzleNode->GetA());
			text << '.' << swizzleNode->GetMap();
			PrintNodeInitEnd();
		}
		break;
	case Node::typeOperation:
		PrintNodeInitBegin(nodeIndex);
		PrintOperationNodeInit(fast_cast<OperationNode*>(node));
		PrintNodeInitEnd();
		break;
	case Node::typeAction:
		PrintActionNodeInit(fast_cast<ActionNode*>(node));
		break;
	case Node::typeSample:
		{
			PrintNodeInitBegin(nodeIndex);

			SampleNode* sampleNode = fast_cast<SampleNode*>(node);

			int slot = sampleNode->GetSamplerNode()->GetSlot();

			ValueNode* coordsNode = sampleNode->GetCoordsNode();
			ValueNode* offsetNode = sampleNode->GetOffsetNode();
			ValueNode* lodNode = sampleNode->GetLodNode();
			ValueNode* biasNode = sampleNode->GetBiasNode();
			ValueNode* gradXNode = sampleNode->GetGradXNode();
			ValueNode* gradYNode = sampleNode->GetGradYNode();

			auto printOffsetNode = [&]()
			{
				// offset node is required to be constant expression,
				// but AMD driver requires it also to be compile-time expression
				// so HACK: print value inline, only for known node
				// PrintNode(offsetNode);
				if(offsetNode->GetType() != Node::typeOperation)
					THROW("wrong offset node");
				OperationNode* offsetOperationNode = fast_cast<OperationNode*>(offsetNode);
				if(
					offsetOperationNode->GetOperation() != OperationNode::operationInt11to2 ||
					offsetOperationNode->GetA()->GetType() != Node::typeIntConst ||
					offsetOperationNode->GetB()->GetType() != Node::typeIntConst
					)
					THROW("wrong offset node");
				text << "ivec2("
					<< offsetOperationNode->GetA().FastCast<IntConstNode>()->GetValue() << ", "
					<< offsetOperationNode->GetB().FastCast<IntConstNode>()->GetValue() << ")";
			};

			if(lodNode)
			{
				text << "textureLod";
				if(offsetNode)
					text << "Offset";
				text << '(' << samplerPrefix << slot << ", ";
				PrintNode(coordsNode);
				text << ", ";
				PrintNode(lodNode);
				if(offsetNode)
				{
					text << ", ";
					printOffsetNode();
				}
			}
			else if(biasNode)
			{
				text << "texture";
				if(offsetNode)
					text << "Offset";
				text << '(' << samplerPrefix << slot << ", ";
				PrintNode(coordsNode);
				if(offsetNode)
				{
					text << ", ";
					printOffsetNode();
				}
				text << ", ";
				PrintNode(biasNode);
			}
			else if(gradXNode && gradYNode)
			{
				text << "textureGrad";
				if(offsetNode)
					text << "Offset";
				text << '(' << samplerPrefix << slot << ", ";
				PrintNode(coordsNode);
				text << ", ";
				PrintNode(gradXNode);
				text << ", ";
				PrintNode(gradYNode);
				if(offsetNode)
				{
					text << ", ";
					printOffsetNode();
				}
			}
			else
			{
				text << (glslVersion == GlslVersions::webgl ? "texture2D" : "texture");
				if(offsetNode && glslVersion != GlslVersions::webgl)
					text << "Offset";
				text << '(' << samplerPrefix << slot << ", ";
				PrintNode(coordsNode);
				if(offsetNode && glslVersion != GlslVersions::webgl)
				{
					text << ", ";
					printOffsetNode();
				}
			}

			// close sample call
			text << ')';

			// sample always returns four-component vector, so make some swizzle if needed
			int valueSize = GetVectorDataTypeDimensions(sampleNode->GetValueType());
			if(valueSize < 4)
			{
				text << '.';
				for(int i = 0; i < valueSize; ++i)
					text << "xyzw"[i];
			}

			PrintNodeInitEnd();
		}
		break;
	case Node::typeFragment:
		{
			FragmentNode* fragmentNode = fast_cast<FragmentNode*>(node);
			switch(glslVersion)
			{
			case GlslVersions::opengl33: text << "\tr" << fragmentNode->GetTarget(); break;
			case GlslVersions::webgl:
				if(fragmentTargetsCount > 1)
					text << "gl_FragData[" << fragmentNode->GetTarget() << ']';
				else
					text << "gl_FragColor";
				break;
			}
			text << " = ";
			PrintNode(fragmentNode->GetNode());
			PrintNodeInitEnd();
		}
		break;
	case Node::typeDualFragment:
		{
			DualFragmentNode* dualFragmentNode = fast_cast<DualFragmentNode*>(node);
			switch(glslVersion)
			{
			case GlslVersions::opengl33:
				text << "\tr0 = ";
				PrintNode(dualFragmentNode->GetNode0());
				PrintNodeInitEnd();
				text << "\tr1 = ";
				PrintNode(dualFragmentNode->GetNode1());
				PrintNodeInitEnd();
				break;
			case GlslVersions::webgl:
				text << "\tgl_FragData[0] = ";
				PrintNode(dualFragmentNode->GetNode0());
				PrintNodeInitEnd();
				text << "\tgl_FragData[1] = ";
				PrintNode(dualFragmentNode->GetNode1());
				PrintNodeInitEnd();
				break;
			}
		}
		break;
	case Node::typeCast:
		{
			PrintNodeInitBegin(nodeIndex);
			CastNode* castNode = fast_cast<CastNode*>(node);
			PrintDataType(castNode->GetValueType());
			text << '(';
			PrintNode(castNode->GetA());
			text << ')';
			PrintNodeInitEnd();
		}
		break;
	default:
		THROW("Unknown node type");
	}
}
inline std::vector<size_t> ifBranchIterationRanges(const OperationNode<Base>* bScope,
                                                   IndexOperationNode<Base>*& iterationIndexOp) {
    CGOpCode bOp = bScope->getOperationType();

    if (bOp == CGOpCode::StartIf || bOp == CGOpCode::ElseIf) {
        OperationNode<Base>* cond = bScope->getArguments()[bOp == CGOpCode::StartIf ? 0 : 1].getOperation();
        CPPADCG_ASSERT_UNKNOWN(cond->getOperationType() == CGOpCode::IndexCondExpr);
        CPPADCG_ASSERT_UNKNOWN(cond->getArguments().size() == 1);
        CPPADCG_ASSERT_UNKNOWN(cond->getArguments()[0].getOperation() != nullptr);
        CPPADCG_ASSERT_UNKNOWN(cond->getArguments()[0].getOperation()->getOperationType() == CGOpCode::Index);
        iterationIndexOp = static_cast<IndexOperationNode<Base>*> (cond->getArguments()[0].getOperation());
        return cond->getInfo();

    } else {
        // else
        CPPADCG_ASSERT_UNKNOWN(bOp == CGOpCode::Else);

        std::vector<size_t> nonIterationRegions;
        OperationNode<Base>* ifBranch = bScope->getArguments()[0].getOperation();
        do {
            CGOpCode bbOp = ifBranch->getOperationType();
            OperationNode<Base>* cond = ifBranch->getArguments()[bbOp == CGOpCode::StartIf ? 0 : 1].getOperation();
            CPPADCG_ASSERT_UNKNOWN(cond->getOperationType() == CGOpCode::IndexCondExpr);
            CPPADCG_ASSERT_UNKNOWN(cond->getArguments().size() == 1);
            CPPADCG_ASSERT_UNKNOWN(cond->getArguments()[0].getOperation() != nullptr);
            CPPADCG_ASSERT_UNKNOWN(cond->getArguments()[0].getOperation()->getOperationType() == CGOpCode::Index);
            IndexOperationNode<Base>* indexOp = static_cast<IndexOperationNode<Base>*> (cond->getArguments()[0].getOperation());
            CPPADCG_ASSERT_UNKNOWN(iterationIndexOp == nullptr || iterationIndexOp == indexOp);
            iterationIndexOp = indexOp;

            combineOverlapingIterationRanges(nonIterationRegions, cond->getInfo());

            ifBranch = ifBranch->getArguments()[0].getOperation();
        } while (ifBranch->getOperationType() == CGOpCode::ElseIf);

        CPPADCG_ASSERT_UNKNOWN(iterationIndexOp != nullptr);

        // invert
        return invertIterationRanges(nonIterationRegions);
    }

}
Beispiel #17
0
void SlGeneratorInstance::RegisterNode(Node* node)
{
	// if registration of node already began
	if(registeredNodes.find(node) != registeredNodes.end())
	{
		// if node is not registered yet
		if(nodeInitIndices.find(node) == nodeInitIndices.end())
			// than it's a loop
			THROW("Node cyclic dependency");
		// else it's ok, it's just another use of node
		return;
	}
	// register node
	registeredNodes.insert(node);

	switch(node->GetType())
	{
	case Node::typeFloatConst:
	case Node::typeIntConst:
		break;
	case Node::typeAttribute:
		{
			if(shaderType != ShaderTypes::vertex)
				THROW("Only vertex shader can have attribute nodes");

			attributes.push_back(fast_cast<AttributeNode*>(node));
		}
		break;
	case Node::typeUniform:
		{
			UniformNode* uniformNode = fast_cast<UniformNode*>(node);
			uniforms.push_back(std::make_pair(uniformNode->GetGroup(), uniformNode));
		}
		break;
	case Node::typeSampler:
		samplers.push_back(fast_cast<SamplerNode*>(node));
		break;
	case Node::typeReadUniform:
		RegisterNode(fast_cast<ReadUniformNode*>(node)->GetUniformNode());
		break;
	case Node::typeIndexUniformArray:
		{
			IndexUniformArrayNode* indexUniformArrayNode = fast_cast<IndexUniformArrayNode*>(node);
			RegisterNode(indexUniformArrayNode->GetUniformNode());
			RegisterNode(indexUniformArrayNode->GetIndexNode());
		}
		break;
	case Node::typeTransformed:
		transformedNodes.push_back(fast_cast<TransformedNode*>(node));
		break;
	case Node::typeInterpolate:
		{
			InterpolateNode* interpolateNode = fast_cast<InterpolateNode*>(node);
			interpolateNodes.push_back(interpolateNode);
			RegisterNode(interpolateNode->GetNode());
		}
		break;
	case Node::typeSequence:
		{
			SequenceNode* sequenceNode = fast_cast<SequenceNode*>(node);
			RegisterNode(sequenceNode->GetA());
			RegisterNode(sequenceNode->GetB());
		}
		break;
	case Node::typeSwizzle:
		RegisterNode(fast_cast<SwizzleNode*>(node)->GetA());
		break;
	case Node::typeOperation:
		{
			OperationNode* operationNode = fast_cast<OperationNode*>(node);
			int argumentsCount = operationNode->GetArgumentsCount();
			for(int i = 0; i < argumentsCount; ++i)
				RegisterNode(operationNode->GetArgument(i));
		}
		break;
	case Node::typeAction:
		{
			ActionNode* actionNode = fast_cast<ActionNode*>(node);
			int argumentsCount = actionNode->GetArgumentsCount();
			for(int i = 0; i < argumentsCount; ++i)
				RegisterNode(actionNode->GetArgument(i));
		}
		break;
	case Node::typeSample:
		{
			SampleNode* sampleNode = fast_cast<SampleNode*>(node);

			RegisterNode(sampleNode->GetSamplerNode());
			RegisterNode(sampleNode->GetCoordsNode());

			ValueNode* lodNode = sampleNode->GetLodNode();
			if(lodNode)
				RegisterNode(lodNode);

			ValueNode* biasNode = sampleNode->GetBiasNode();
			if(biasNode)
				RegisterNode(biasNode);

			ValueNode* gradXNode = sampleNode->GetGradXNode();
			if(gradXNode)
				RegisterNode(gradXNode);
			ValueNode* gradYNode = sampleNode->GetGradYNode();
			if(gradYNode)
				RegisterNode(gradYNode);

			ValueNode* offsetNode = sampleNode->GetOffsetNode();
			if(offsetNode)
				RegisterNode(offsetNode);
		}
		break;
	case Node::typeFragment:
		{
			if(shaderType != ShaderTypes::pixel)
				THROW("Only pixel shader can do fragment output");
			FragmentNode* fragmentNode = fast_cast<FragmentNode*>(node);

			// register maximum number of fragment outputs
			fragmentTargetsCount = std::max(fragmentTargetsCount, fragmentNode->GetTarget() + 1);
			RegisterNode(fragmentNode->GetNode());
		}
		break;
	case Node::typeDualFragment:
		{
			if(shaderType != ShaderTypes::pixel)
				THROW("Only pixel shader can do dual fragment output");
			DualFragmentNode* dualFragmentNode = fast_cast<DualFragmentNode*>(node);

			dualFragmentTarget = true;

			// register maximum number of fragment outputs
			fragmentTargetsCount = std::max(fragmentTargetsCount, 2);
			RegisterNode(dualFragmentNode->GetNode0());
			RegisterNode(dualFragmentNode->GetNode1());
		}
		break;
	case Node::typeCast:
		RegisterNode(fast_cast<CastNode*>(node)->GetA());
		break;
	default:
		THROW("Unknown node type");
	}

	// add initialization of node
	THROW_ASSERT(nodeInitIndices.find(node) == nodeInitIndices.end());
	nodeInitIndices[node] = (int)nodeInits.size();
	nodeInits.push_back(node);
}
    inline size_t reserveArraySpace(const OperationNode<Base>& newArray) {
        size_t arraySize = newArray.getArguments().size();

        if (arraySize == 0)
            return 0; // nothing to do (no space required)

        std::set<size_t> blackList;
        const std::vector<Argument<Base> >& args = newArray.getArguments();
        for (size_t i = 0; i < args.size(); i++) {
            const OperationNode<Base>* argOp = args[i].getOperation();
            if (argOp != nullptr && argOp->getOperationType() == CGOpCode::ArrayElement) {
                const OperationNode<Base>& otherArray = *argOp->getArguments()[0].getOperation();
                CPPADCG_ASSERT_UNKNOWN(_varId[otherArray] > 0); // make sure it had already been assigned space
                size_t otherArrayStart = _varId[otherArray] - 1;
                size_t index = argOp->getInfo()[0];
                blackList.insert(otherArrayStart + index);
            }
        }

        /**
         * Find the best location for the new array
         */
        std::map<size_t, size_t>::reverse_iterator it;
        std::map<size_t, size_t>::reverse_iterator itBestFit = _freeArrayStartSpace.rend();
        size_t bestCommonValues = 0; // the number of values likely to be the same
        for (it = _freeArrayStartSpace.rbegin(); it != _freeArrayStartSpace.rend(); ++it) {
            size_t start = it->first;
            size_t end = it->second;
            size_t space = end - start + 1;
            if (space < arraySize) {
                continue;
            }

            std::set<size_t>::const_iterator itBlack = blackList.lower_bound(start);
            if (itBlack != blackList.end() && *itBlack <= end) {
                continue; // cannot use this space
            }

            //possible candidate
            if (itBestFit == _freeArrayStartSpace.rend()) {
                itBestFit = it;
            } else {
                size_t bestSpace = itBestFit->second - itBestFit->first + 1;

                size_t commonVals = 0;
                for (size_t i = 0; i < arraySize; i++) {
                    if (isSameArrayElement(_tmpArrayValues[start + i], args[i])) {
                        commonVals++;
                    }
                }

                if (space < bestSpace || commonVals > bestCommonValues) {
                    // better fit
                    itBestFit = it;
                    bestCommonValues = commonVals;
                    if (bestCommonValues == arraySize) {
                        break; // jackpot
                    }
                }
            }
        }

        size_t bestStart = std::numeric_limits<size_t>::max();
        if (itBestFit != _freeArrayStartSpace.rend()) {
            /**
             * Use available space
             */
            bestStart = itBestFit->first;
            size_t bestEnd = itBestFit->second;
            size_t bestSpace = bestEnd - bestStart + 1;
            _freeArrayStartSpace.erase(bestStart);
            if (bestSpace == arraySize) {
                // entire space 
                _freeArrayEndSpace.erase(bestEnd);
            } else {
                // some space left
                size_t newFreeStart = bestStart + arraySize;
                _freeArrayStartSpace[newFreeStart] = bestEnd;
                _freeArrayEndSpace.at(bestEnd) = newFreeStart;
            }

        } else {
            /**
             * no space available, need more
             */
            // check if there is some free space at the end
            std::map<size_t, size_t>::iterator itEnd;
            itEnd = _freeArrayEndSpace.find(_idArrayCount - 1 - 1); // IDcount - initialID - 1
            if (itEnd != _freeArrayEndSpace.end()) {
                // check if it can be used
                size_t lastSpotStart = itEnd->second;
                size_t lastSpotEnd = itEnd->first;
                size_t lastSpotSize = lastSpotEnd - lastSpotStart + 1;
                std::set<size_t>::const_iterator itBlack = blackList.lower_bound(lastSpotStart);
                if (itBlack == blackList.end()) {
                    // can use this space
                    _freeArrayEndSpace.erase(itEnd);
                    _freeArrayStartSpace.erase(lastSpotStart);

                    _idArrayCount += arraySize - lastSpotSize;
                    bestStart = lastSpotStart;
                }
            }

            if (bestStart == std::numeric_limits<size_t>::max()) {
                // brand new space
                size_t id = _idArrayCount;
                _idArrayCount += arraySize;
                bestStart = id - 1;
            }
        }

        for (size_t i = 0; i < arraySize; i++) {
            _tmpArrayValues[bestStart + i] = &args[i];
        }

        CPPADCG_ASSERT_UNKNOWN(_freeArrayStartSpace.size() == _freeArrayEndSpace.size());

        return bestStart;
    }