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 Binary ops.
22 *//*--------------------------------------------------------------------*/
23
24 #include "rsgBinaryOps.hpp"
25 #include "rsgVariableManager.hpp"
26 #include "rsgUtils.hpp"
27 #include "deMath.h"
28
29 using std::vector;
30
31 namespace rsg
32 {
33
34 template <int Precedence, Associativity Assoc>
BinaryOp(Token::Type operatorToken)35 BinaryOp<Precedence, Assoc>::BinaryOp (Token::Type operatorToken)
36 : m_operator (operatorToken)
37 , m_leftValueRange (m_type)
38 , m_rightValueRange (m_type)
39 , m_leftValueExpr (DE_NULL)
40 , m_rightValueExpr (DE_NULL)
41 {
42 }
43
44 template <int Precedence, Associativity Assoc>
~BinaryOp(void)45 BinaryOp<Precedence, Assoc>::~BinaryOp (void)
46 {
47 delete m_leftValueExpr;
48 delete m_rightValueExpr;
49 }
50
51 template <int Precedence, Associativity Assoc>
createNextChild(GeneratorState & state)52 Expression* BinaryOp<Precedence, Assoc>::createNextChild (GeneratorState& state)
53 {
54 int leftPrec = Assoc == ASSOCIATIVITY_LEFT ? Precedence : Precedence-1;
55 int rightPrec = Assoc == ASSOCIATIVITY_LEFT ? Precedence-1 : Precedence;
56
57 if (m_rightValueExpr == DE_NULL)
58 {
59 state.pushPrecedence(rightPrec);
60 m_rightValueExpr = Expression::createRandom(state, m_rightValueRange.asAccess());
61 state.popPrecedence();
62 return m_rightValueExpr;
63 }
64 else if (m_leftValueExpr == DE_NULL)
65 {
66 state.pushPrecedence(leftPrec);
67 m_leftValueExpr = Expression::createRandom(state, m_leftValueRange.asAccess());
68 state.popPrecedence();
69 return m_leftValueExpr;
70 }
71 else
72 return DE_NULL;
73 }
74
75 template <int Precedence, Associativity Assoc>
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)76 float BinaryOp<Precedence, Assoc>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
77 {
78 if (state.getPrecedence() < Precedence)
79 return 0.0f;
80
81 int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
82
83 if (valueRange.getType().isVoid())
84 return availableLevels >= 2 ? unusedValueWeight : 0.0f;
85
86 if (availableLevels < getConservativeValueExprDepth(state, valueRange) + 1)
87 return 0.0f;
88
89 return 1.0f;
90 }
91
92 template <int Precedence, Associativity Assoc>
tokenize(GeneratorState & state,TokenStream & str) const93 void BinaryOp<Precedence, Assoc>::tokenize (GeneratorState& state, TokenStream& str) const
94 {
95 m_leftValueExpr->tokenize(state, str);
96 str << m_operator;
97 m_rightValueExpr->tokenize(state, str);
98 }
99
100 template <int Precedence, Associativity Assoc>
evaluate(ExecutionContext & execCtx)101 void BinaryOp<Precedence, Assoc>::evaluate (ExecutionContext& execCtx)
102 {
103 m_leftValueExpr->evaluate(execCtx);
104 m_rightValueExpr->evaluate(execCtx);
105
106 ExecConstValueAccess leftVal = m_leftValueExpr->getValue();
107 ExecConstValueAccess rightVal = m_rightValueExpr->getValue();
108 ExecValueAccess dst = m_value.getValue(m_type);
109
110 evaluate(dst, leftVal, rightVal);
111 }
112
113 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp>
BinaryVecOp(GeneratorState & state,Token::Type operatorToken,ConstValueRangeAccess inValueRange)114 BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::BinaryVecOp (GeneratorState& state, Token::Type operatorToken, ConstValueRangeAccess inValueRange)
115 : BinaryOp<Precedence, ASSOCIATIVITY_LEFT>(operatorToken)
116 {
117 ValueRange valueRange = inValueRange;
118
119 if (valueRange.getType().isVoid())
120 {
121 int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
122 vector<VariableType::Type> baseTypes;
123
124 if (Float) baseTypes.push_back(VariableType::TYPE_FLOAT);
125 if (Int) baseTypes.push_back(VariableType::TYPE_INT);
126 if (Bool) baseTypes.push_back(VariableType::TYPE_BOOL);
127
128 VariableType::Type baseType = state.getRandom().choose<VariableType::Type>(baseTypes.begin(), baseTypes.end());
129 int numElements = state.getRandom().getInt(1, availableLevels >= 3 ? 4 : 1);
130
131 valueRange = ValueRange(VariableType(baseType, numElements));
132 computeRandomValueRange(state, valueRange.asAccess());
133 }
134
135 // Choose type, allocate storage for execution
136 this->m_type = valueRange.getType();
137 this->m_value.setStorage(this->m_type);
138
139 // Initialize storage for value ranges
140 this->m_rightValueRange = ValueRange(this->m_type);
141 this->m_leftValueRange = ValueRange(this->m_type);
142
143 VariableType::Type baseType = this->m_type.getBaseType();
144
145 // Compute range for b that satisfies requested value range
146 for (int elemNdx = 0; elemNdx < this->m_type.getNumElements(); elemNdx++)
147 {
148 ConstValueRangeAccess dst = valueRange.asAccess().component(elemNdx);
149 ValueRangeAccess a = this->m_leftValueRange.asAccess().component(elemNdx); // \todo [2011-03-25 pyry] Commutative: randomize inputs
150 ValueRangeAccess b = this->m_rightValueRange.asAccess().component(elemNdx);
151
152 // Just pass undefined ranges
153 if ((baseType == VariableType::TYPE_FLOAT || baseType == VariableType::TYPE_INT) && isUndefinedValueRange(dst))
154 {
155 a.getMin() = dst.getMin().value();
156 b.getMin() = dst.getMin().value();
157 a.getMax() = dst.getMax().value();
158 b.getMax() = dst.getMax().value();
159 continue;
160 }
161
162 if (baseType == VariableType::TYPE_FLOAT)
163 ComputeValueRange()(state.getRandom(), dst.getMin().asFloat(), dst.getMax().asFloat(),
164 a.getMin().asFloat(), a.getMax().asFloat(),
165 b.getMin().asFloat(), b.getMax().asFloat());
166 else if (baseType == VariableType::TYPE_INT)
167 ComputeValueRange()(state.getRandom(), dst.getMin().asInt(), dst.getMax().asInt(),
168 a.getMin().asInt(), a.getMax().asInt(),
169 b.getMin().asInt(), b.getMax().asInt());
170 else
171 {
172 DE_ASSERT(baseType == VariableType::TYPE_BOOL);
173 ComputeValueRange()(state.getRandom(), dst.getMin().asBool(), dst.getMax().asBool(),
174 a.getMin().asBool(), a.getMax().asBool(),
175 b.getMin().asBool(), b.getMax().asBool());
176 }
177 }
178 }
179
180 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp>
~BinaryVecOp(void)181 BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::~BinaryVecOp (void)
182 {
183 }
184
185 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp>
evaluate(ExecValueAccess dst,ExecConstValueAccess a,ExecConstValueAccess b)186 void BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
187 {
188 DE_ASSERT(dst.getType() == a.getType());
189 DE_ASSERT(dst.getType() == b.getType());
190 switch (dst.getType().getBaseType())
191 {
192 case VariableType::TYPE_FLOAT:
193 for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
194 {
195 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
196 dst.component(elemNdx).asFloat(compNdx) = EvaluateComp()(a.component(elemNdx).asFloat(compNdx), b.component(elemNdx).asFloat(compNdx));
197 }
198 break;
199
200 case VariableType::TYPE_INT:
201 for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
202 {
203 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
204 dst.component(elemNdx).asInt(compNdx) = EvaluateComp()(a.component(elemNdx).asInt(compNdx), b.component(elemNdx).asInt(compNdx));
205 }
206 break;
207
208 default:
209 DE_ASSERT(DE_FALSE); // Invalid type for multiplication
210 }
211 }
212
operator ()(de::Random & rnd,float dstMin,float dstMax,float & aMin,float & aMax,float & bMin,float & bMax) const213 void ComputeMulRange::operator() (de::Random& rnd, float dstMin, float dstMax, float& aMin, float& aMax, float& bMin, float& bMax) const
214 {
215 const float minScale = 0.25f;
216 const float maxScale = 2.0f;
217 const float subRangeStep = 0.25f;
218 const float scaleStep = 0.25f;
219
220 float scale = getQuantizedFloat(rnd, minScale, maxScale, scaleStep);
221 float scaledMin = dstMin/scale;
222 float scaledMax = dstMax/scale;
223
224 // Quantize scaled value range if possible
225 if (!quantizeFloatRange(scaledMin, scaledMax))
226 {
227 // Fall back to 1.0 as a scale
228 scale = 1.0f;
229 scaledMin = dstMin;
230 scaledMax = dstMax;
231 }
232
233 float subRangeLen = getQuantizedFloat(rnd, 0.0f, scaledMax-scaledMin, subRangeStep);
234 aMin = scaledMin + getQuantizedFloat(rnd, 0.0f, (scaledMax-scaledMin)-subRangeLen, subRangeStep);
235 aMax = aMin + subRangeLen;
236
237 // Find scale range
238 bMin = scale;
239 bMax = scale;
240 for (int i = 0; i < 5; i++)
241 {
242 if (de::inBounds(aMin*(scale-(float)i*scaleStep), dstMin, dstMax) &&
243 de::inBounds(aMax*(scale-(float)i*scaleStep), dstMin, dstMax))
244 bMin = scale-(float)i*scaleStep;
245
246 if (de::inBounds(aMin*(scale+(float)i*scaleStep), dstMin, dstMax) &&
247 de::inBounds(aMax*(scale+(float)i*scaleStep), dstMin, dstMax))
248 bMax = scale+(float)i*scaleStep;
249 }
250
251 // Negative scale?
252 if (rnd.getBool())
253 {
254 std::swap(aMin, aMax);
255 std::swap(bMin, bMax);
256 aMin *= -1.0f;
257 aMax *= -1.0f;
258 bMin *= -1.0f;
259 bMax *= -1.0f;
260 }
261
262 #if defined(DE_DEBUG)
263 const float eps = 0.001f;
264 DE_ASSERT(aMin <= aMax && bMin <= bMax);
265 DE_ASSERT(de::inRange(aMin*bMin, dstMin-eps, dstMax+eps));
266 DE_ASSERT(de::inRange(aMin*bMax, dstMin-eps, dstMax+eps));
267 DE_ASSERT(de::inRange(aMax*bMin, dstMin-eps, dstMax+eps));
268 DE_ASSERT(de::inRange(aMax*bMax, dstMin-eps, dstMax+eps));
269 #endif
270 }
271
operator ()(de::Random & rnd,int dstMin,int dstMax,int & aMin,int & aMax,int & bMin,int & bMax) const272 void ComputeMulRange::operator() (de::Random& rnd, int dstMin, int dstMax, int& aMin, int& aMax, int& bMin, int& bMax) const
273 {
274 DE_UNREF(rnd);
275 aMin = dstMin;
276 aMax = dstMax;
277 bMin = 1;
278 bMax = 1;
279 }
280
MulOp(GeneratorState & state,ConstValueRangeAccess valueRange)281 MulOp::MulOp (GeneratorState& state, ConstValueRangeAccess valueRange)
282 : MulBase(state, Token::MUL, valueRange)
283 {
284 }
285
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)286 float MulOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
287 {
288 if (valueRange.getType().isVoid() ||
289 valueRange.getType().isFloatOrVec() ||
290 valueRange.getType().isIntOrVec())
291 return MulBase::getWeight(state, valueRange);
292 else
293 return 0.0f;
294 }
295
296 template <typename T>
operator ()(de::Random & random,T dstMin,T dstMax,T & aMin,T & aMax,T & bMin,T & bMax) const297 void ComputeAddRange::operator() (de::Random& random, T dstMin, T dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const
298 {
299 struct GetRandom
300 {
301 int operator() (de::Random& rnd, int min, int max) const { return rnd.getInt(min, max); }
302 float operator() (de::Random& rnd, float min, float max) const { return getQuantizedFloat(rnd, min, max, 0.5f); }
303 };
304
305 T rangeLen = dstMax-dstMin;
306 T subRangeLen = GetRandom()(random, T(0), rangeLen);
307 T aOffset = GetRandom()(random, T(-8), T(8));
308
309 aMin = dstMin+aOffset;
310 aMax = aMin+subRangeLen;
311
312 bMin = -aOffset;
313 bMax = -aOffset+(rangeLen-subRangeLen);
314
315 #if defined(DE_DEBUG)
316 T eps = T(0.001);
317 DE_ASSERT(aMin <= aMax && bMin <= bMax);
318 DE_ASSERT(de::inRange(aMin+bMin, dstMin-eps, dstMax+eps));
319 DE_ASSERT(de::inRange(aMin+bMax, dstMin-eps, dstMax+eps));
320 DE_ASSERT(de::inRange(aMax+bMin, dstMin-eps, dstMax+eps));
321 DE_ASSERT(de::inRange(aMax+bMax, dstMin-eps, dstMax+eps));
322 #endif
323 }
324
325 template <>
operator()326 void ComputeAddRange::operator()<bool> (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const
327 {
328 DE_ASSERT(DE_FALSE);
329 }
330
AddOp(GeneratorState & state,ConstValueRangeAccess valueRange)331 AddOp::AddOp (GeneratorState& state, ConstValueRangeAccess valueRange)
332 : AddBase(state, Token::PLUS, valueRange)
333 {
334 }
335
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)336 float AddOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
337 {
338 if (valueRange.getType().isVoid() ||
339 valueRange.getType().isFloatOrVec() ||
340 valueRange.getType().isIntOrVec())
341 return AddBase::getWeight(state, valueRange);
342 else
343 return 0.0f;
344 }
345
346 template <typename T>
operator ()(de::Random & random,T dstMin,T dstMax,T & aMin,T & aMax,T & bMin,T & bMax) const347 void ComputeSubRange::operator() (de::Random& random, T dstMin, T dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const
348 {
349 struct GetRandom
350 {
351 int operator() (de::Random& rnd, int min, int max) const { return rnd.getInt(min, max); }
352 float operator() (de::Random& rnd, float min, float max) const { return getQuantizedFloat(rnd, min, max, 0.5f); }
353 };
354
355 T rangeLen = dstMax-dstMin;
356 T subRangeLen = GetRandom()(random, T(0), rangeLen);
357 T aOffset = GetRandom()(random, T(-8), T(8));
358
359 aMin = dstMin+aOffset;
360 aMax = aMin+subRangeLen;
361
362 bMin = aOffset-(rangeLen-subRangeLen);
363 bMax = aOffset;
364
365 #if defined(DE_DEBUG)
366 T eps = T(0.001);
367 DE_ASSERT(aMin <= aMax && bMin <= bMax);
368 DE_ASSERT(de::inRange(aMin-bMin, dstMin-eps, dstMax+eps));
369 DE_ASSERT(de::inRange(aMin-bMax, dstMin-eps, dstMax+eps));
370 DE_ASSERT(de::inRange(aMax-bMin, dstMin-eps, dstMax+eps));
371 DE_ASSERT(de::inRange(aMax-bMax, dstMin-eps, dstMax+eps));
372 #endif
373 }
374
375 template <>
operator()376 void ComputeSubRange::operator()<bool> (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const
377 {
378 DE_ASSERT(DE_FALSE);
379 }
380
SubOp(GeneratorState & state,ConstValueRangeAccess valueRange)381 SubOp::SubOp (GeneratorState& state, ConstValueRangeAccess valueRange)
382 : SubBase(state, Token::MINUS, valueRange)
383 {
384 }
385
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)386 float SubOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
387 {
388 if (valueRange.getType().isVoid() ||
389 valueRange.getType().isFloatOrVec() ||
390 valueRange.getType().isIntOrVec())
391 return SubBase::getWeight(state, valueRange);
392 else
393 return 0.0f;
394 }
395
396 template <class ComputeValueRange, class EvaluateComp>
RelationalOp(GeneratorState & state,Token::Type operatorToken,ConstValueRangeAccess inValueRange)397 RelationalOp<ComputeValueRange, EvaluateComp>::RelationalOp (GeneratorState& state, Token::Type operatorToken, ConstValueRangeAccess inValueRange)
398 : BinaryOp<7, ASSOCIATIVITY_LEFT>(operatorToken)
399 {
400 ValueRange valueRange = inValueRange;
401
402 if (valueRange.getType().isVoid())
403 {
404 valueRange = ValueRange(VariableType(VariableType::TYPE_BOOL, 1));
405 computeRandomValueRange(state, valueRange.asAccess());
406 }
407
408 // Choose type, allocate storage for execution
409 this->m_type = valueRange.getType();
410 this->m_value.setStorage(this->m_type);
411
412 // Choose random input type
413 VariableType::Type inBaseTypes[] = { VariableType::TYPE_FLOAT, VariableType::TYPE_INT };
414 VariableType::Type inBaseType = state.getRandom().choose<VariableType::Type>(&inBaseTypes[0], &inBaseTypes[DE_LENGTH_OF_ARRAY(inBaseTypes)]);
415
416 // Initialize storage for input value ranges
417 this->m_rightValueRange = ValueRange(VariableType(inBaseType, 1));
418 this->m_leftValueRange = ValueRange(VariableType(inBaseType, 1));
419
420 // Compute range for b that satisfies requested value range
421 {
422 bool dstMin = valueRange.getMin().asBool();
423 bool dstMax = valueRange.getMax().asBool();
424 ValueRangeAccess a = this->m_leftValueRange.asAccess();
425 ValueRangeAccess b = this->m_rightValueRange.asAccess();
426
427 if (inBaseType == VariableType::TYPE_FLOAT)
428 ComputeValueRange()(state.getRandom(), dstMin, dstMax,
429 a.getMin().asFloat(), a.getMax().asFloat(),
430 b.getMin().asFloat(), b.getMax().asFloat());
431 else if (inBaseType == VariableType::TYPE_INT)
432 ComputeValueRange()(state.getRandom(), dstMin, dstMax,
433 a.getMin().asInt(), a.getMax().asInt(),
434 b.getMin().asInt(), b.getMax().asInt());
435 }
436 }
437
438 template <class ComputeValueRange, class EvaluateComp>
~RelationalOp(void)439 RelationalOp<ComputeValueRange, EvaluateComp>::~RelationalOp (void)
440 {
441 }
442
443 template <class ComputeValueRange, class EvaluateComp>
evaluate(ExecValueAccess dst,ExecConstValueAccess a,ExecConstValueAccess b)444 void RelationalOp<ComputeValueRange, EvaluateComp>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
445 {
446 DE_ASSERT(a.getType() == b.getType());
447 switch (a.getType().getBaseType())
448 {
449 case VariableType::TYPE_FLOAT:
450 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
451 dst.asBool(compNdx) = EvaluateComp()(a.asFloat(compNdx), b.asFloat(compNdx));
452 break;
453
454 case VariableType::TYPE_INT:
455 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
456 dst.asBool(compNdx) = EvaluateComp()(a.asInt(compNdx), b.asInt(compNdx));
457 break;
458
459 default:
460 DE_ASSERT(DE_FALSE);
461 }
462 }
463
464 template <class ComputeValueRange, class EvaluateComp>
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)465 float RelationalOp<ComputeValueRange, EvaluateComp>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
466 {
467 if (!state.getProgramParameters().useComparisonOps)
468 return 0.0f;
469
470 if (valueRange.getType().isVoid() ||
471 (valueRange.getType().getBaseType() == VariableType::TYPE_BOOL && valueRange.getType().getNumElements() == 1))
472 return BinaryOp<7, ASSOCIATIVITY_LEFT>::getWeight(state, valueRange);
473 else
474 return 0.0f;
475 }
476
477 namespace
478 {
479
480 template <typename T> T getStep (void);
getStep(void)481 template <> inline float getStep (void) { return 0.25f; }
getStep(void)482 template <> inline int getStep (void) { return 1; }
483
484 } // anonymous
485
486 template <typename T>
operator ()(de::Random & rnd,bool dstMin,bool dstMax,T & aMin,T & aMax,T & bMin,T & bMax) const487 void ComputeLessThanRange::operator () (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const
488 {
489 struct GetRandom
490 {
491 int operator() (de::Random& random, int min, int max) const { return random.getInt(min, max); }
492 float operator() (de::Random& random, float min, float max) const { return getQuantizedFloat(random, min, max, getStep<float>()); }
493 };
494
495 // One random range
496 T rLen = GetRandom()(rnd, T(0), T(8));
497 T rMin = GetRandom()(rnd, T(-4), T(4));
498 T rMax = rMin+rLen;
499
500 if (dstMin == false && dstMax == true)
501 {
502 // Both values are possible, use same range for both inputs
503 aMin = rMin;
504 aMax = rMax;
505 bMin = rMin;
506 bMax = rMax;
507 }
508 else if (dstMin == true && dstMax == true)
509 {
510 // Compute range that is less than rMin..rMax
511 T aLen = GetRandom()(rnd, T(0), T(8)-rLen);
512
513 aMax = rMin - getStep<T>();
514 aMin = aMax - aLen;
515
516 bMin = rMin;
517 bMax = rMax;
518 }
519 else
520 {
521 // Compute range that is greater than or equal to rMin..rMax
522 T aLen = GetRandom()(rnd, T(0), T(8)-rLen);
523
524 aMin = rMax;
525 aMax = aMin + aLen;
526
527 bMin = rMin;
528 bMax = rMax;
529 }
530 }
531
LessThanOp(GeneratorState & state,ConstValueRangeAccess valueRange)532 LessThanOp::LessThanOp (GeneratorState& state, ConstValueRangeAccess valueRange)
533 : LessThanBase(state, Token::CMP_LT, valueRange)
534 {
535 }
536
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)537 float LessThanOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
538 {
539 return LessThanBase::getWeight(state, valueRange);
540 }
541
542 template <typename T>
operator ()(de::Random & rnd,bool dstMin,bool dstMax,T & aMin,T & aMax,T & bMin,T & bMax) const543 void ComputeLessOrEqualRange::operator () (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const
544 {
545 struct GetRandom
546 {
547 int operator() (de::Random& random, int min, int max) const { return random.getInt(min, max); }
548 float operator() (de::Random& random, float min, float max) const { return getQuantizedFloat(random, min, max, getStep<float>()); }
549 };
550
551 // One random range
552 T rLen = GetRandom()(rnd, T(0), T(8));
553 T rMin = GetRandom()(rnd, T(-4), T(4));
554 T rMax = rMin+rLen;
555
556 if (dstMin == false && dstMax == true)
557 {
558 // Both values are possible, use same range for both inputs
559 aMin = rMin;
560 aMax = rMax;
561 bMin = rMin;
562 bMax = rMax;
563 }
564 else if (dstMin == true && dstMax == true)
565 {
566 // Compute range that is less than or equal to rMin..rMax
567 T aLen = GetRandom()(rnd, T(0), T(8)-rLen);
568
569 aMax = rMin;
570 aMin = aMax - aLen;
571
572 bMin = rMin;
573 bMax = rMax;
574 }
575 else
576 {
577 // Compute range that is greater than rMin..rMax
578 T aLen = GetRandom()(rnd, T(0), T(8)-rLen);
579
580 aMin = rMax + getStep<T>();
581 aMax = aMin + aLen;
582
583 bMin = rMin;
584 bMax = rMax;
585 }
586 }
587
LessOrEqualOp(GeneratorState & state,ConstValueRangeAccess valueRange)588 LessOrEqualOp::LessOrEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
589 : LessOrEqualBase(state, Token::CMP_LE, valueRange)
590 {
591 }
592
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)593 float LessOrEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
594 {
595 return LessOrEqualBase::getWeight(state, valueRange);
596 }
597
GreaterThanOp(GeneratorState & state,ConstValueRangeAccess valueRange)598 GreaterThanOp::GreaterThanOp (GeneratorState& state, ConstValueRangeAccess valueRange)
599 : GreaterThanBase(state, Token::CMP_GT, valueRange)
600 {
601 }
602
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)603 float GreaterThanOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
604 {
605 return GreaterThanBase::getWeight(state, valueRange);
606 }
607
GreaterOrEqualOp(GeneratorState & state,ConstValueRangeAccess valueRange)608 GreaterOrEqualOp::GreaterOrEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
609 : GreaterOrEqualBase(state, Token::CMP_GE, valueRange)
610 {
611 }
612
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)613 float GreaterOrEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
614 {
615 return GreaterOrEqualBase::getWeight(state, valueRange);
616 }
617
618 namespace
619 {
620
621 template <bool IsEqual, typename T>
computeEqualityValueRange(de::Random & rnd,bool dstMin,bool dstMax,T & aMin,T & aMax,T & bMin,T & bMax)622 void computeEqualityValueRange (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax)
623 {
624 if (dstMin == false && dstMax == true)
625 ComputeLessThanRange()(rnd, false, true, aMin, aMax, bMin, bMax);
626 else if (IsEqual && dstMin == false)
627 ComputeLessThanRange()(rnd, true, true, aMin, aMax, bMin, bMax);
628 else if (!IsEqual && dstMin == true)
629 ComputeLessThanRange()(rnd, true, true, aMin, aMax, bMin, bMax);
630 else
631 {
632 // Must have exactly same values.
633 struct GetRandom
634 {
635 int operator() (de::Random& random, int min, int max) const { return random.getInt(min, max); }
636 float operator() (de::Random& random, float min, float max) const { return getQuantizedFloat(random, min, max, 0.5f); }
637 };
638
639 T val = GetRandom()(rnd, T(-1), T(1));
640
641 aMin = val;
642 aMax = val;
643 bMin = val;
644 bMax = val;
645 }
646 }
647
648 template <>
computeEqualityValueRange(de::Random & rnd,bool dstMin,bool dstMax,bool & aMin,bool & aMax,bool & bMin,bool & bMax)649 void computeEqualityValueRange<true, bool> (de::Random& rnd, bool dstMin, bool dstMax, bool& aMin, bool& aMax, bool& bMin, bool& bMax)
650 {
651 if (dstMin == false && dstMax == true)
652 {
653 aMin = false;
654 aMax = true;
655 bMin = false;
656 bMax = true;
657 }
658 else if (dstMin == false)
659 {
660 DE_ASSERT(dstMax == false);
661 bool val = rnd.getBool();
662
663 aMin = val;
664 aMax = val;
665 bMin = !val;
666 bMax = !val;
667 }
668 else
669 {
670 DE_ASSERT(dstMin == true && dstMax == true);
671 bool val = rnd.getBool();
672
673 aMin = val;
674 aMax = val;
675 bMin = val;
676 bMax = val;
677 }
678 }
679
680 template <>
computeEqualityValueRange(de::Random & rnd,bool dstMin,bool dstMax,bool & aMin,bool & aMax,bool & bMin,bool & bMax)681 void computeEqualityValueRange<false, bool> (de::Random& rnd, bool dstMin, bool dstMax, bool& aMin, bool& aMax, bool& bMin, bool& bMax)
682 {
683 if (dstMin == false && dstMax == true)
684 computeEqualityValueRange<true>(rnd, dstMin, dstMax, aMin, aMax, bMin, bMax);
685 else
686 computeEqualityValueRange<true>(rnd, !dstMin, !dstMax, aMin, aMax, bMin, bMax);
687 }
688
689 } // anonymous
690
691 template <bool IsEqual>
EqualityComparisonOp(GeneratorState & state,ConstValueRangeAccess inValueRange)692 EqualityComparisonOp<IsEqual>::EqualityComparisonOp (GeneratorState& state, ConstValueRangeAccess inValueRange)
693 : BinaryOp<8, ASSOCIATIVITY_LEFT>(IsEqual ? Token::CMP_EQ : Token::CMP_NE)
694 {
695 ValueRange valueRange = inValueRange;
696
697 if (valueRange.getType().isVoid())
698 {
699 valueRange = ValueRange(VariableType(VariableType::TYPE_BOOL, 1));
700 computeRandomValueRange(state, valueRange.asAccess());
701 }
702
703 // Choose type, allocate storage for execution
704 this->m_type = valueRange.getType();
705 this->m_value.setStorage(this->m_type);
706
707 // Choose random input type
708 VariableType::Type inBaseTypes[] = { VariableType::TYPE_FLOAT, VariableType::TYPE_INT };
709 VariableType::Type inBaseType = state.getRandom().choose<VariableType::Type>(&inBaseTypes[0], &inBaseTypes[DE_LENGTH_OF_ARRAY(inBaseTypes)]);
710 int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
711 int numElements = state.getRandom().getInt(1, availableLevels >= 3 ? 4 : 1);
712
713 // Initialize storage for input value ranges
714 this->m_rightValueRange = ValueRange(VariableType(inBaseType, numElements));
715 this->m_leftValueRange = ValueRange(VariableType(inBaseType, numElements));
716
717 // Compute range for b that satisfies requested value range
718 for (int elementNdx = 0; elementNdx < numElements; elementNdx++)
719 {
720 bool dstMin = valueRange.getMin().asBool();
721 bool dstMax = valueRange.getMax().asBool();
722
723 ValueRangeAccess a = this->m_leftValueRange.asAccess().component(elementNdx);
724 ValueRangeAccess b = this->m_rightValueRange.asAccess().component(elementNdx);
725
726 if (inBaseType == VariableType::TYPE_FLOAT)
727 computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax,
728 a.getMin().asFloat(), a.getMax().asFloat(),
729 b.getMin().asFloat(), b.getMax().asFloat());
730 else if (inBaseType == VariableType::TYPE_INT)
731 computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax,
732 a.getMin().asInt(), a.getMax().asInt(),
733 b.getMin().asInt(), b.getMax().asInt());
734 else
735 {
736 DE_ASSERT(inBaseType == VariableType::TYPE_BOOL);
737 computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax,
738 a.getMin().asBool(), a.getMax().asBool(),
739 b.getMin().asBool(), b.getMax().asBool());
740 }
741 }
742 }
743
744 template <bool IsEqual>
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)745 float EqualityComparisonOp<IsEqual>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
746 {
747 if (!state.getProgramParameters().useComparisonOps)
748 return 0.0f;
749
750 // \todo [2011-06-13 pyry] Weight down cases that would force constant inputs.
751
752 if (valueRange.getType().isVoid() ||
753 (valueRange.getType().getBaseType() == VariableType::TYPE_BOOL && valueRange.getType().getNumElements() == 1))
754 return BinaryOp<8, ASSOCIATIVITY_LEFT>::getWeight(state, valueRange);
755 else
756 return 0.0f;
757 }
758
759 namespace
760 {
761
762 template <bool IsEqual>
763 struct EqualityCompare
764 {
765 template <typename T>
766 static bool compare (T a, T b);
767 static bool combine (bool a, bool b);
768 };
769
770 template <>
771 template <typename T>
compare(T a,T b)772 inline bool EqualityCompare<true>::compare (T a, T b) { return a == b; }
773
774 template <>
combine(bool a,bool b)775 inline bool EqualityCompare<true>::combine (bool a, bool b) { return a && b; }
776
777 template <>
778 template <typename T>
compare(T a,T b)779 inline bool EqualityCompare<false>::compare (T a, T b) { return a != b; }
780
781 template <>
combine(bool a,bool b)782 inline bool EqualityCompare<false>::combine (bool a, bool b) { return a || b; }
783
784 } // anonymous
785
786 template <bool IsEqual>
evaluate(ExecValueAccess dst,ExecConstValueAccess a,ExecConstValueAccess b)787 void EqualityComparisonOp<IsEqual>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
788 {
789 DE_ASSERT(a.getType() == b.getType());
790
791
792 switch (a.getType().getBaseType())
793 {
794 case VariableType::TYPE_FLOAT:
795 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
796 {
797 bool result = IsEqual ? true : false;
798
799 for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++)
800 result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asFloat(compNdx), b.component(elemNdx).asFloat(compNdx)));
801
802 dst.asBool(compNdx) = result;
803 }
804 break;
805
806 case VariableType::TYPE_INT:
807 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
808 {
809 bool result = IsEqual ? true : false;
810
811 for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++)
812 result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asInt(compNdx), b.component(elemNdx).asInt(compNdx)));
813
814 dst.asBool(compNdx) = result;
815 }
816 break;
817
818 case VariableType::TYPE_BOOL:
819 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
820 {
821 bool result = IsEqual ? true : false;
822
823 for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++)
824 result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asBool(compNdx), b.component(elemNdx).asBool(compNdx)));
825
826 dst.asBool(compNdx) = result;
827 }
828 break;
829
830 default:
831 DE_ASSERT(DE_FALSE);
832 }
833 }
834
EqualOp(GeneratorState & state,ConstValueRangeAccess valueRange)835 EqualOp::EqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
836 : EqualityComparisonOp<true>(state, valueRange)
837 {
838 }
839
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)840 float EqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
841 {
842 return EqualityComparisonOp<true>::getWeight(state, valueRange);
843 }
844
NotEqualOp(GeneratorState & state,ConstValueRangeAccess valueRange)845 NotEqualOp::NotEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
846 : EqualityComparisonOp<false>(state, valueRange)
847 {
848 }
849
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)850 float NotEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
851 {
852 return EqualityComparisonOp<false>::getWeight(state, valueRange);
853 }
854
855 } // rsg
856