/*------------------------------------------------------------------------- * drawElements Quality Program Random Shader Generator * ---------------------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Statements. *//*--------------------------------------------------------------------*/ #include "rsgStatement.hpp" #include "rsgExpressionGenerator.hpp" #include "rsgUtils.hpp" #include <typeinfo> using std::vector; namespace rsg { namespace { inline bool isCurrentTopStatementBlock (const GeneratorState& state) { int stackDepth = state.getStatementDepth(); return dynamic_cast<const BlockStatement*>(state.getStatementStackEntry(stackDepth-1)) != DE_NULL; } template <class T> float getWeight (const GeneratorState& state) { return T::getWeight(state); } template <class T> Statement* create (GeneratorState& state) { return new T(state); } struct StatementSpec { float (*getWeight) (const GeneratorState& state); Statement* (*create) (GeneratorState& state); }; const StatementSpec* chooseStatement (GeneratorState& state) { static const StatementSpec statementSpecs[] = { { getWeight<BlockStatement>, create<BlockStatement> }, { getWeight<ExpressionStatement>, create<ExpressionStatement> }, { getWeight<DeclarationStatement>, create<DeclarationStatement> }, { getWeight<ConditionalStatement>, create<ConditionalStatement> } }; float weights[DE_LENGTH_OF_ARRAY(statementSpecs)]; // Compute weights float sum = 0.0f; for (int ndx = 0; ndx < (int)DE_LENGTH_OF_ARRAY(statementSpecs); ndx++) { weights[ndx] = statementSpecs[ndx].getWeight(state); sum += weights[ndx]; } DE_ASSERT(sum > 0.0f); // Random number in range float p = state.getRandom().getFloat(0.0f, sum); const StatementSpec* spec = DE_NULL; const StatementSpec* lastNonZero = DE_NULL; // Find element in that point sum = 0.0f; for (int ndx = 0; ndx < (int)DE_LENGTH_OF_ARRAY(statementSpecs); ndx++) { sum += weights[ndx]; if (p < sum) { spec = &statementSpecs[ndx]; break; } else if (weights[ndx] > 0.0f) lastNonZero = &statementSpecs[ndx]; } if (!spec) spec = lastNonZero; return spec; } Statement* createStatement (GeneratorState& state) { return chooseStatement(state)->create(state); } } // anonymous Statement::Statement (void) { } Statement::~Statement (void) { } ExpressionStatement::ExpressionStatement (GeneratorState& state) : m_expression(DE_NULL) { ExpressionGenerator generator(state); m_expression = generator.generate(ValueRange(VariableType(VariableType::TYPE_VOID))); } ExpressionStatement::~ExpressionStatement (void) { delete m_expression; } float ExpressionStatement::getWeight (const GeneratorState& state) { DE_UNREF(state); return 1.0f; } void ExpressionStatement::execute (ExecutionContext& execCtx) const { m_expression->evaluate(execCtx); } BlockStatement::BlockStatement (GeneratorState& state) { init(state); } void BlockStatement::init (GeneratorState& state) { // Select number of children statements to construct m_numChildrenToCreate = state.getRandom().getInt(0, state.getShaderParameters().maxStatementsPerBlock); // Push scope state.getVariableManager().pushVariableScope(m_scope); } BlockStatement::~BlockStatement (void) { for (vector<Statement*>::iterator i = m_children.begin(); i != m_children.end(); i++) delete *i; m_children.clear(); } void BlockStatement::addChild (Statement* statement) { try { m_children.push_back(statement); } catch (const std::exception&) { delete statement; throw; } } Statement* BlockStatement::createNextChild (GeneratorState& state) { if ((int)m_children.size() < m_numChildrenToCreate) { // Select and create a new child Statement* child = createStatement(state); addChild(child); return child; } else { // Done, pop scope state.getVariableManager().popVariableScope(); return DE_NULL; } } float BlockStatement::getWeight (const GeneratorState& state) { if (state.getStatementDepth()+1 < state.getShaderParameters().maxStatementDepth) { if (isCurrentTopStatementBlock(state)) return 0.2f; // Low probability for anonymous blocks. else return 1.0f; } else return 0.0f; } void BlockStatement::tokenize (GeneratorState& state, TokenStream& str) const { str << Token::LEFT_BRACE << Token::NEWLINE << Token::INDENT_INC; for (vector<Statement*>::const_reverse_iterator i = m_children.rbegin(); i != m_children.rend(); i++) (*i)->tokenize(state, str); str << Token::INDENT_DEC << Token::RIGHT_BRACE << Token::NEWLINE; } void BlockStatement::execute (ExecutionContext& execCtx) const { for (vector<Statement*>::const_reverse_iterator i = m_children.rbegin(); i != m_children.rend(); i++) (*i)->execute(execCtx); } void ExpressionStatement::tokenize (GeneratorState& state, TokenStream& str) const { DE_ASSERT(m_expression); m_expression->tokenize(state, str); str << Token::SEMICOLON << Token::NEWLINE; } namespace { inline bool canDeclareVariable (const Variable* variable) { return variable->getStorage() == Variable::STORAGE_LOCAL; } bool hasDeclarableVars (const VariableManager& varMgr) { const vector<Variable*>& liveVars = varMgr.getLiveVariables(); for (vector<Variable*>::const_iterator i = liveVars.begin(); i != liveVars.end(); i++) { if (canDeclareVariable(*i)) return true; } return false; } } // anonymous DeclarationStatement::DeclarationStatement (GeneratorState& state, Variable* variable) : m_variable (DE_NULL) , m_expression (DE_NULL) { if (variable == DE_NULL) { // Choose random // \todo [2011-02-03 pyry] Allocate a new here? // \todo [2011-05-26 pyry] Weights? const vector<Variable*>& liveVars = state.getVariableManager().getLiveVariables(); vector<Variable*> candidates; for (vector<Variable*>::const_iterator i = liveVars.begin(); i != liveVars.end(); i++) { if (canDeclareVariable(*i)) candidates.push_back(*i); } variable = state.getRandom().choose<Variable*>(candidates.begin(), candidates.end()); } DE_ASSERT(variable); m_variable = variable; const ValueEntry* value = state.getVariableManager().getValue(variable); bool createInitializer = false; switch (m_variable->getStorage()) { case Variable::STORAGE_CONST: DE_ASSERT(value); createInitializer = true; break; case Variable::STORAGE_LOCAL: // \note Currently booleans are always treated as not having undefined range and thus // initializer is always created. createInitializer = value && !isUndefinedValueRange(value->getValueRange()); break; default: createInitializer = false; break; } if (createInitializer) { ExpressionGenerator generator(state); // Take copy of value range for generating initializer expression ValueRange valueRange = value->getValueRange(); // Declare (removes value entry) state.getVariableManager().declareVariable(variable); bool isConst = m_variable->getStorage() == Variable::STORAGE_CONST; if (isConst) state.pushExpressionFlags(state.getExpressionFlags() | CONST_EXPR); m_expression = generator.generate(valueRange, 1); if (isConst) state.popExpressionFlags(); } else state.getVariableManager().declareVariable(variable); } DeclarationStatement::~DeclarationStatement (void) { delete m_expression; } float DeclarationStatement::getWeight (const GeneratorState& state) { if (!hasDeclarableVars(state.getVariableManager())) return 0.0f; if (!isCurrentTopStatementBlock(state)) return 0.0f; return state.getProgramParameters().declarationStatementBaseWeight; } void DeclarationStatement::tokenize (GeneratorState& state, TokenStream& str) const { m_variable->tokenizeDeclaration(state, str); if (m_expression) { str << Token::EQUAL; m_expression->tokenize(state, str); } str << Token::SEMICOLON << Token::NEWLINE; } void DeclarationStatement::execute (ExecutionContext& execCtx) const { if (m_expression) { m_expression->evaluate(execCtx); execCtx.getValue(m_variable) = m_expression->getValue().value(); } } ConditionalStatement::ConditionalStatement (GeneratorState&) : m_condition (DE_NULL) , m_trueStatement (DE_NULL) , m_falseStatement (DE_NULL) { } ConditionalStatement::~ConditionalStatement (void) { delete m_condition; delete m_trueStatement; delete m_falseStatement; } bool ConditionalStatement::isElseBlockRequired (const GeneratorState& state) const { // If parent is conditional statement with else block and this is the true statement, // else block must be generated or otherwise parent "else" will end up parsed as else statement for this if. const ConditionalStatement* curChild = this; int curStackNdx = state.getStatementDepth()-2; while (curStackNdx >= 0) { const ConditionalStatement* curParent = dynamic_cast<const ConditionalStatement*>(state.getStatementStackEntry(curStackNdx)); if (!curParent) break; // Not a conditional statement - can end search here. if (curChild == curParent->m_trueStatement && curParent->m_falseStatement) return true; // Else block is mandatory. // Continue search. curChild = curParent; curStackNdx -= 1; } return false; } Statement* ConditionalStatement::createNextChild (GeneratorState& state) { // If has neither true or false statements, choose randomly whether to create false block. if (!m_falseStatement && !m_trueStatement && (isElseBlockRequired(state) || state.getRandom().getBool())) { // Construct false statement state.getVariableManager().pushValueScope(m_conditionalScope); m_falseStatement = createStatement(state); return m_falseStatement; } else if (!m_trueStatement) { if (m_falseStatement) { // Pop previous value scope. state.getVariableManager().popValueScope(); m_conditionalScope.clear(); } // Construct true statement state.getVariableManager().pushValueScope(m_conditionalScope); m_trueStatement = createStatement(state); return m_trueStatement; } else { // Pop conditional scope. state.getVariableManager().popValueScope(); m_conditionalScope.clear(); // Create condition DE_ASSERT(!m_condition); ExpressionGenerator generator(state); ValueRange range = ValueRange(VariableType::getScalarType(VariableType::TYPE_BOOL)); range.getMin().asBool() = false; range.getMax().asBool() = true; m_condition = generator.generate(range, 1); return DE_NULL; // Done with this statement } } namespace { bool isBlockStatement (const Statement* statement) { return dynamic_cast<const BlockStatement*>(statement) != DE_NULL; } bool isConditionalStatement (const Statement* statement) { return dynamic_cast<const ConditionalStatement*>(statement) != DE_NULL; } } // anonymous void ConditionalStatement::tokenize (GeneratorState& state, TokenStream& str) const { DE_ASSERT(m_condition && m_trueStatement); // if (condition) str << Token::IF << Token::LEFT_PAREN; m_condition->tokenize(state, str); str << Token::RIGHT_PAREN << Token::NEWLINE; // Statement executed if true if (!isBlockStatement(m_trueStatement)) { str << Token::INDENT_INC; m_trueStatement->tokenize(state, str); str << Token::INDENT_DEC; } else m_trueStatement->tokenize(state, str); if (m_falseStatement) { str << Token::ELSE; if (isConditionalStatement(m_falseStatement)) { m_falseStatement->tokenize(state, str); } else if (isBlockStatement(m_falseStatement)) { str << Token::NEWLINE; m_falseStatement->tokenize(state, str); } else { str << Token::NEWLINE << Token::INDENT_INC; m_falseStatement->tokenize(state, str); str << Token::INDENT_DEC; } } } void ConditionalStatement::execute (ExecutionContext& execCtx) const { // Evaluate condition m_condition->evaluate(execCtx); ExecMaskStorage maskStorage; // Value might change when we are evaluating true block so we have to take a copy. ExecValueAccess trueMask = maskStorage.getValue(); trueMask = m_condition->getValue().value(); // And mask, execute true statement and pop execCtx.andExecutionMask(trueMask); m_trueStatement->execute(execCtx); execCtx.popExecutionMask(); if (m_falseStatement) { // Construct negated mask, execute false statement and pop ExecMaskStorage tmp; ExecValueAccess falseMask = tmp.getValue(); for (int i = 0; i < EXEC_VEC_WIDTH; i++) falseMask.asBool(i) = !trueMask.asBool(i); execCtx.andExecutionMask(falseMask); m_falseStatement->execute(execCtx); execCtx.popExecutionMask(); } } float ConditionalStatement::getWeight (const GeneratorState& state) { if (!state.getProgramParameters().useConditionals) return 0.0f; int availableLevels = state.getShaderParameters().maxStatementDepth - state.getStatementDepth(); return (availableLevels > 1) ? 1.0f : 0.0f; } AssignStatement::AssignStatement (const Variable* variable, Expression* value) : m_variable (variable) , m_valueExpr (value) // \note Takes ownership of value { } AssignStatement::AssignStatement (GeneratorState& state, const Variable* variable, ConstValueRangeAccess valueRange) : m_variable (variable) , m_valueExpr (DE_NULL) { // Generate random value ExpressionGenerator generator(state); m_valueExpr = generator.generate(valueRange, 1); } AssignStatement::~AssignStatement (void) { delete m_valueExpr; } void AssignStatement::tokenize (GeneratorState& state, TokenStream& str) const { str << Token(m_variable->getName()) << Token::EQUAL; m_valueExpr->tokenize(state, str); str << Token::SEMICOLON << Token::NEWLINE; } void AssignStatement::execute (ExecutionContext& execCtx) const { m_valueExpr->evaluate(execCtx); assignMasked(execCtx.getValue(m_variable), m_valueExpr->getValue(), execCtx.getExecutionMask()); } } // rsg