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