1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Random Shader Generator
3 * ----------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Statements.
22 *//*--------------------------------------------------------------------*/
23
24 #include "rsgStatement.hpp"
25 #include "rsgExpressionGenerator.hpp"
26 #include "rsgUtils.hpp"
27
28 #include <typeinfo>
29
30 using std::vector;
31
32 namespace rsg
33 {
34
35 namespace
36 {
37
isCurrentTopStatementBlock(const GeneratorState & state)38 inline bool isCurrentTopStatementBlock(const GeneratorState &state)
39 {
40 int stackDepth = state.getStatementDepth();
41 return dynamic_cast<const BlockStatement *>(state.getStatementStackEntry(stackDepth - 1)) != DE_NULL;
42 }
43
44 template <class T>
getWeight(const GeneratorState & state)45 float getWeight(const GeneratorState &state)
46 {
47 return T::getWeight(state);
48 }
49 template <class T>
create(GeneratorState & state)50 Statement *create(GeneratorState &state)
51 {
52 return new T(state);
53 }
54
55 struct StatementSpec
56 {
57 float (*getWeight)(const GeneratorState &state);
58 Statement *(*create)(GeneratorState &state);
59 };
60
chooseStatement(GeneratorState & state)61 const StatementSpec *chooseStatement(GeneratorState &state)
62 {
63 static const StatementSpec statementSpecs[] = {{getWeight<BlockStatement>, create<BlockStatement>},
64 {getWeight<ExpressionStatement>, create<ExpressionStatement>},
65 {getWeight<DeclarationStatement>, create<DeclarationStatement>},
66 {getWeight<ConditionalStatement>, create<ConditionalStatement>}};
67
68 float weights[DE_LENGTH_OF_ARRAY(statementSpecs)];
69
70 // Compute weights
71 float sum = 0.0f;
72 for (int ndx = 0; ndx < (int)DE_LENGTH_OF_ARRAY(statementSpecs); ndx++)
73 {
74 weights[ndx] = statementSpecs[ndx].getWeight(state);
75 sum += weights[ndx];
76 }
77
78 DE_ASSERT(sum > 0.0f);
79
80 // Random number in range
81 float p = state.getRandom().getFloat(0.0f, sum);
82
83 const StatementSpec *spec = DE_NULL;
84 const StatementSpec *lastNonZero = DE_NULL;
85
86 // Find element in that point
87 sum = 0.0f;
88 for (int ndx = 0; ndx < (int)DE_LENGTH_OF_ARRAY(statementSpecs); ndx++)
89 {
90 sum += weights[ndx];
91 if (p < sum)
92 {
93 spec = &statementSpecs[ndx];
94 break;
95 }
96 else if (weights[ndx] > 0.0f)
97 lastNonZero = &statementSpecs[ndx];
98 }
99
100 if (!spec)
101 spec = lastNonZero;
102
103 return spec;
104 }
105
createStatement(GeneratorState & state)106 Statement *createStatement(GeneratorState &state)
107 {
108 return chooseStatement(state)->create(state);
109 }
110
111 } // namespace
112
Statement(void)113 Statement::Statement(void)
114 {
115 }
116
~Statement(void)117 Statement::~Statement(void)
118 {
119 }
120
ExpressionStatement(GeneratorState & state)121 ExpressionStatement::ExpressionStatement(GeneratorState &state) : m_expression(DE_NULL)
122 {
123 ExpressionGenerator generator(state);
124 m_expression = generator.generate(ValueRange(VariableType(VariableType::TYPE_VOID)));
125 }
126
~ExpressionStatement(void)127 ExpressionStatement::~ExpressionStatement(void)
128 {
129 delete m_expression;
130 }
131
getWeight(const GeneratorState & state)132 float ExpressionStatement::getWeight(const GeneratorState &state)
133 {
134 DE_UNREF(state);
135 return 1.0f;
136 }
137
execute(ExecutionContext & execCtx) const138 void ExpressionStatement::execute(ExecutionContext &execCtx) const
139 {
140 m_expression->evaluate(execCtx);
141 }
142
BlockStatement(GeneratorState & state)143 BlockStatement::BlockStatement(GeneratorState &state)
144 {
145 init(state);
146 }
147
init(GeneratorState & state)148 void BlockStatement::init(GeneratorState &state)
149 {
150 // Select number of children statements to construct
151 m_numChildrenToCreate = state.getRandom().getInt(0, state.getShaderParameters().maxStatementsPerBlock);
152
153 // Push scope
154 state.getVariableManager().pushVariableScope(m_scope);
155 }
156
~BlockStatement(void)157 BlockStatement::~BlockStatement(void)
158 {
159 for (vector<Statement *>::iterator i = m_children.begin(); i != m_children.end(); i++)
160 delete *i;
161 m_children.clear();
162 }
163
addChild(Statement * statement)164 void BlockStatement::addChild(Statement *statement)
165 {
166 try
167 {
168 m_children.push_back(statement);
169 }
170 catch (const std::exception &)
171 {
172 delete statement;
173 throw;
174 }
175 }
176
createNextChild(GeneratorState & state)177 Statement *BlockStatement::createNextChild(GeneratorState &state)
178 {
179 if ((int)m_children.size() < m_numChildrenToCreate)
180 {
181 // Select and create a new child
182 Statement *child = createStatement(state);
183 addChild(child);
184 return child;
185 }
186 else
187 {
188 // Done, pop scope
189 state.getVariableManager().popVariableScope();
190 return DE_NULL;
191 }
192 }
193
getWeight(const GeneratorState & state)194 float BlockStatement::getWeight(const GeneratorState &state)
195 {
196 if (state.getStatementDepth() + 1 < state.getShaderParameters().maxStatementDepth)
197 {
198 if (isCurrentTopStatementBlock(state))
199 return 0.2f; // Low probability for anonymous blocks.
200 else
201 return 1.0f;
202 }
203 else
204 return 0.0f;
205 }
206
tokenize(GeneratorState & state,TokenStream & str) const207 void BlockStatement::tokenize(GeneratorState &state, TokenStream &str) const
208 {
209 str << Token::LEFT_BRACE << Token::NEWLINE << Token::INDENT_INC;
210
211 for (vector<Statement *>::const_reverse_iterator i = m_children.rbegin(); i != m_children.rend(); i++)
212 (*i)->tokenize(state, str);
213
214 str << Token::INDENT_DEC << Token::RIGHT_BRACE << Token::NEWLINE;
215 }
216
execute(ExecutionContext & execCtx) const217 void BlockStatement::execute(ExecutionContext &execCtx) const
218 {
219 for (vector<Statement *>::const_reverse_iterator i = m_children.rbegin(); i != m_children.rend(); i++)
220 (*i)->execute(execCtx);
221 }
222
tokenize(GeneratorState & state,TokenStream & str) const223 void ExpressionStatement::tokenize(GeneratorState &state, TokenStream &str) const
224 {
225 DE_ASSERT(m_expression);
226 m_expression->tokenize(state, str);
227 str << Token::SEMICOLON << Token::NEWLINE;
228 }
229
230 namespace
231 {
232
canDeclareVariable(const Variable * variable)233 inline bool canDeclareVariable(const Variable *variable)
234 {
235 return variable->getStorage() == Variable::STORAGE_LOCAL;
236 }
237
hasDeclarableVars(const VariableManager & varMgr)238 bool hasDeclarableVars(const VariableManager &varMgr)
239 {
240 const vector<Variable *> &liveVars = varMgr.getLiveVariables();
241 for (vector<Variable *>::const_iterator i = liveVars.begin(); i != liveVars.end(); i++)
242 {
243 if (canDeclareVariable(*i))
244 return true;
245 }
246 return false;
247 }
248
249 } // namespace
250
DeclarationStatement(GeneratorState & state,Variable * variable)251 DeclarationStatement::DeclarationStatement(GeneratorState &state, Variable *variable)
252 : m_variable(DE_NULL)
253 , m_expression(DE_NULL)
254 {
255 if (variable == DE_NULL)
256 {
257 // Choose random
258 // \todo [2011-02-03 pyry] Allocate a new here?
259 // \todo [2011-05-26 pyry] Weights?
260 const vector<Variable *> &liveVars = state.getVariableManager().getLiveVariables();
261 vector<Variable *> candidates;
262
263 for (vector<Variable *>::const_iterator i = liveVars.begin(); i != liveVars.end(); i++)
264 {
265 if (canDeclareVariable(*i))
266 candidates.push_back(*i);
267 }
268
269 variable = state.getRandom().choose<Variable *>(candidates.begin(), candidates.end());
270 }
271
272 DE_ASSERT(variable);
273 m_variable = variable;
274
275 const ValueEntry *value = state.getVariableManager().getValue(variable);
276
277 bool createInitializer = false;
278
279 switch (m_variable->getStorage())
280 {
281 case Variable::STORAGE_CONST:
282 DE_ASSERT(value);
283 createInitializer = true;
284 break;
285
286 case Variable::STORAGE_LOCAL:
287 // initializer is always created if value isn't null.
288 createInitializer = value;
289 break;
290
291 default:
292 createInitializer = false;
293 break;
294 }
295
296 if (createInitializer)
297 {
298 ExpressionGenerator generator(state);
299
300 // Take copy of value range for generating initializer expression
301 ValueRange valueRange = value->getValueRange();
302
303 // Declare (removes value entry)
304 state.getVariableManager().declareVariable(variable);
305
306 bool isConst = m_variable->getStorage() == Variable::STORAGE_CONST;
307
308 if (isConst)
309 state.pushExpressionFlags(state.getExpressionFlags() | CONST_EXPR);
310
311 m_expression = generator.generate(valueRange, 1);
312
313 if (isConst)
314 state.popExpressionFlags();
315 }
316 else
317 state.getVariableManager().declareVariable(variable);
318 }
319
~DeclarationStatement(void)320 DeclarationStatement::~DeclarationStatement(void)
321 {
322 delete m_expression;
323 }
324
getWeight(const GeneratorState & state)325 float DeclarationStatement::getWeight(const GeneratorState &state)
326 {
327 if (!hasDeclarableVars(state.getVariableManager()))
328 return 0.0f;
329
330 if (!isCurrentTopStatementBlock(state))
331 return 0.0f;
332
333 return state.getProgramParameters().declarationStatementBaseWeight;
334 }
335
tokenize(GeneratorState & state,TokenStream & str) const336 void DeclarationStatement::tokenize(GeneratorState &state, TokenStream &str) const
337 {
338 m_variable->tokenizeDeclaration(state, str);
339
340 if (m_expression)
341 {
342 str << Token::EQUAL;
343 m_expression->tokenize(state, str);
344 }
345
346 str << Token::SEMICOLON << Token::NEWLINE;
347 }
348
execute(ExecutionContext & execCtx) const349 void DeclarationStatement::execute(ExecutionContext &execCtx) const
350 {
351 if (m_expression)
352 {
353 m_expression->evaluate(execCtx);
354 execCtx.getValue(m_variable) = m_expression->getValue().value();
355 }
356 }
357
ConditionalStatement(GeneratorState &)358 ConditionalStatement::ConditionalStatement(GeneratorState &)
359 : m_condition(DE_NULL)
360 , m_trueStatement(DE_NULL)
361 , m_falseStatement(DE_NULL)
362 {
363 }
364
~ConditionalStatement(void)365 ConditionalStatement::~ConditionalStatement(void)
366 {
367 delete m_condition;
368 delete m_trueStatement;
369 delete m_falseStatement;
370 }
371
isElseBlockRequired(const GeneratorState & state) const372 bool ConditionalStatement::isElseBlockRequired(const GeneratorState &state) const
373 {
374 // If parent is conditional statement with else block and this is the true statement,
375 // else block must be generated or otherwise parent "else" will end up parsed as else statement for this if.
376 const ConditionalStatement *curChild = this;
377 int curStackNdx = state.getStatementDepth() - 2;
378
379 while (curStackNdx >= 0)
380 {
381 const ConditionalStatement *curParent =
382 dynamic_cast<const ConditionalStatement *>(state.getStatementStackEntry(curStackNdx));
383
384 if (!curParent)
385 break; // Not a conditional statement - can end search here.
386
387 if (curChild == curParent->m_trueStatement && curParent->m_falseStatement)
388 return true; // Else block is mandatory.
389
390 // Continue search.
391 curChild = curParent;
392 curStackNdx -= 1;
393 }
394
395 return false;
396 }
397
createNextChild(GeneratorState & state)398 Statement *ConditionalStatement::createNextChild(GeneratorState &state)
399 {
400 // If has neither true or false statements, choose randomly whether to create false block.
401 if (!m_falseStatement && !m_trueStatement && (isElseBlockRequired(state) || state.getRandom().getBool()))
402 {
403 // Construct false statement
404 state.getVariableManager().pushValueScope(m_conditionalScope);
405 m_falseStatement = createStatement(state);
406
407 return m_falseStatement;
408 }
409 else if (!m_trueStatement)
410 {
411 if (m_falseStatement)
412 {
413 // Pop previous value scope.
414 state.getVariableManager().popValueScope();
415 m_conditionalScope.clear();
416 }
417
418 // Construct true statement
419 state.getVariableManager().pushValueScope(m_conditionalScope);
420 m_trueStatement = createStatement(state);
421
422 return m_trueStatement;
423 }
424 else
425 {
426 // Pop conditional scope.
427 state.getVariableManager().popValueScope();
428 m_conditionalScope.clear();
429
430 // Create condition
431 DE_ASSERT(!m_condition);
432
433 ExpressionGenerator generator(state);
434
435 ValueRange range = ValueRange(VariableType::getScalarType(VariableType::TYPE_BOOL));
436 range.getMin().asBool() = false;
437 range.getMax().asBool() = true;
438
439 m_condition = generator.generate(range, 1);
440
441 return DE_NULL; // Done with this statement
442 }
443 }
444
445 namespace
446 {
447
isBlockStatement(const Statement * statement)448 bool isBlockStatement(const Statement *statement)
449 {
450 return dynamic_cast<const BlockStatement *>(statement) != DE_NULL;
451 }
452
isConditionalStatement(const Statement * statement)453 bool isConditionalStatement(const Statement *statement)
454 {
455 return dynamic_cast<const ConditionalStatement *>(statement) != DE_NULL;
456 }
457
458 } // namespace
459
tokenize(GeneratorState & state,TokenStream & str) const460 void ConditionalStatement::tokenize(GeneratorState &state, TokenStream &str) const
461 {
462 DE_ASSERT(m_condition && m_trueStatement);
463
464 // if (condition)
465 str << Token::IF << Token::LEFT_PAREN;
466 m_condition->tokenize(state, str);
467 str << Token::RIGHT_PAREN << Token::NEWLINE;
468
469 // Statement executed if true
470 if (!isBlockStatement(m_trueStatement))
471 {
472 str << Token::INDENT_INC;
473 m_trueStatement->tokenize(state, str);
474 str << Token::INDENT_DEC;
475 }
476 else
477 m_trueStatement->tokenize(state, str);
478
479 if (m_falseStatement)
480 {
481 str << Token::ELSE;
482
483 if (isConditionalStatement(m_falseStatement))
484 {
485 m_falseStatement->tokenize(state, str);
486 }
487 else if (isBlockStatement(m_falseStatement))
488 {
489 str << Token::NEWLINE;
490 m_falseStatement->tokenize(state, str);
491 }
492 else
493 {
494 str << Token::NEWLINE << Token::INDENT_INC;
495 m_falseStatement->tokenize(state, str);
496 str << Token::INDENT_DEC;
497 }
498 }
499 }
500
execute(ExecutionContext & execCtx) const501 void ConditionalStatement::execute(ExecutionContext &execCtx) const
502 {
503 // Evaluate condition
504 m_condition->evaluate(execCtx);
505
506 ExecMaskStorage maskStorage; // Value might change when we are evaluating true block so we have to take a copy.
507 ExecValueAccess trueMask = maskStorage.getValue();
508
509 trueMask = m_condition->getValue().value();
510
511 // And mask, execute true statement and pop
512 execCtx.andExecutionMask(trueMask);
513 m_trueStatement->execute(execCtx);
514 execCtx.popExecutionMask();
515
516 if (m_falseStatement)
517 {
518 // Construct negated mask, execute false statement and pop
519 ExecMaskStorage tmp;
520 ExecValueAccess falseMask = tmp.getValue();
521
522 for (int i = 0; i < EXEC_VEC_WIDTH; i++)
523 falseMask.asBool(i) = !trueMask.asBool(i);
524
525 execCtx.andExecutionMask(falseMask);
526 m_falseStatement->execute(execCtx);
527 execCtx.popExecutionMask();
528 }
529 }
530
getWeight(const GeneratorState & state)531 float ConditionalStatement::getWeight(const GeneratorState &state)
532 {
533 if (!state.getProgramParameters().useConditionals)
534 return 0.0f;
535
536 int availableLevels = state.getShaderParameters().maxStatementDepth - state.getStatementDepth();
537 return (availableLevels > 1) ? 1.0f : 0.0f;
538 }
539
AssignStatement(const Variable * variable,Expression * value)540 AssignStatement::AssignStatement(const Variable *variable, Expression *value)
541 : m_variable(variable)
542 , m_valueExpr(value) // \note Takes ownership of value
543 {
544 }
545
AssignStatement(GeneratorState & state,const Variable * variable,ConstValueRangeAccess valueRange)546 AssignStatement::AssignStatement(GeneratorState &state, const Variable *variable, ConstValueRangeAccess valueRange)
547 : m_variable(variable)
548 , m_valueExpr(DE_NULL)
549 {
550 // Generate random value
551 ExpressionGenerator generator(state);
552 m_valueExpr = generator.generate(valueRange, 1);
553 }
554
~AssignStatement(void)555 AssignStatement::~AssignStatement(void)
556 {
557 delete m_valueExpr;
558 }
559
tokenize(GeneratorState & state,TokenStream & str) const560 void AssignStatement::tokenize(GeneratorState &state, TokenStream &str) const
561 {
562 str << Token(m_variable->getName()) << Token::EQUAL;
563 m_valueExpr->tokenize(state, str);
564 str << Token::SEMICOLON << Token::NEWLINE;
565 }
566
execute(ExecutionContext & execCtx) const567 void AssignStatement::execute(ExecutionContext &execCtx) const
568 {
569 m_valueExpr->evaluate(execCtx);
570 assignMasked(execCtx.getValue(m_variable), m_valueExpr->getValue(), execCtx.getExecutionMask());
571 }
572
573 } // namespace rsg
574