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; }
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)); }
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; }
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); } }
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; }