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 // CustomAbsOp and CustomBinaryOp are used to resolve float comparision corner case.
35 // This error happened when two floats with the same value were compared
36 // without using epsilon. If result of this comparisment influenced the
37 // output color then result and reference images could differ.
38 class CustomAbsOp : public Expression
39 {
40 public:
41 CustomAbsOp(void);
42 virtual ~CustomAbsOp(void);
43
44 void setChild(Expression *expression);
45 Expression *createNextChild(GeneratorState &state);
46 void tokenize(GeneratorState &state, TokenStream &str) const;
47
48 void evaluate(ExecutionContext &execCtx);
getValue(void) const49 ExecConstValueAccess getValue(void) const
50 {
51 return m_value.getValue(m_type);
52 }
53
54 private:
55 std::string m_function;
56 VariableType m_type;
57 ExecValueStorage m_value;
58 Expression *m_child;
59 };
60
CustomAbsOp(void)61 CustomAbsOp::CustomAbsOp(void) : m_function("abs"), m_type(VariableType::TYPE_FLOAT, 1), m_child(DE_NULL)
62 {
63 m_value.setStorage(m_type);
64 }
65
~CustomAbsOp(void)66 CustomAbsOp::~CustomAbsOp(void)
67 {
68 delete m_child;
69 }
70
setChild(Expression * expression)71 void CustomAbsOp::setChild(Expression *expression)
72 {
73 m_child = expression;
74 }
75
createNextChild(GeneratorState &)76 Expression *CustomAbsOp::createNextChild(GeneratorState &)
77 {
78 DE_ASSERT(0);
79 return DE_NULL;
80 }
81
tokenize(GeneratorState & state,TokenStream & str) const82 void CustomAbsOp::tokenize(GeneratorState &state, TokenStream &str) const
83 {
84 str << Token(m_function.c_str()) << Token::LEFT_PAREN;
85 m_child->tokenize(state, str);
86 str << Token::RIGHT_PAREN;
87 }
88
evaluate(ExecutionContext & execCtx)89 void CustomAbsOp::evaluate(ExecutionContext &execCtx)
90 {
91 m_child->evaluate(execCtx);
92
93 ExecConstValueAccess srcValue = m_child->getValue();
94 ExecValueAccess dstValue = m_value.getValue(m_type);
95
96 for (int elemNdx = 0; elemNdx < m_type.getNumElements(); elemNdx++)
97 {
98 ExecConstValueAccess srcComp = srcValue.component(elemNdx);
99 ExecValueAccess dstComp = dstValue.component(elemNdx);
100
101 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
102 dstComp.asFloat(compNdx) = deFloatAbs(srcComp.asFloat(compNdx));
103 }
104 }
105
106 typedef BinaryOp<5, ASSOCIATIVITY_LEFT> CustomBinaryBase;
107
108 // CustomBinaryOp and CustomAbsOp are used to resolve float comparision corner case.
109 // CustomBinaryOp supports addition and substraction as only those functionalities
110 // were needed.
111 template <typename ComputeValue>
112 class CustomBinaryOp : public CustomBinaryBase
113 {
114 public:
115 CustomBinaryOp();
~CustomBinaryOp(void)116 virtual ~CustomBinaryOp(void)
117 {
118 }
119
120 void setLeftValue(Expression *expression);
121 void setRightValue(Expression *expression);
122
123 void evaluate(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b);
124 };
125
126 template <typename ComputeValue>
CustomBinaryOp()127 CustomBinaryOp<ComputeValue>::CustomBinaryOp() : CustomBinaryBase(Token::PLUS)
128 {
129 // By default add operation is assumed, for every other operation
130 // separate constructor specialization should be implemented
131 m_type = VariableType(VariableType::TYPE_FLOAT, 1);
132 m_value.setStorage(m_type);
133 }
134
135 template <>
CustomBinaryOp()136 CustomBinaryOp<EvaluateSub>::CustomBinaryOp() : CustomBinaryBase(Token::MINUS)
137 {
138 // Specialization for substraction
139 m_type = VariableType(VariableType::TYPE_FLOAT, 1);
140 m_leftValueRange = ValueRange(m_type);
141 m_rightValueRange = ValueRange(m_type);
142 m_value.setStorage(m_type);
143 }
144
145 template <>
CustomBinaryOp()146 CustomBinaryOp<EvaluateLessThan>::CustomBinaryOp() : CustomBinaryBase(Token::CMP_LT)
147 {
148 // Specialization for less_then comparision
149 m_type = VariableType(VariableType::TYPE_BOOL, 1);
150 VariableType floatType = VariableType(VariableType::TYPE_FLOAT, 1);
151 m_leftValueRange = ValueRange(floatType);
152 m_rightValueRange = ValueRange(floatType);
153 m_value.setStorage(m_type);
154 }
155
156 template <typename ComputeValue>
setLeftValue(Expression * expression)157 void CustomBinaryOp<ComputeValue>::setLeftValue(Expression *expression)
158 {
159 m_leftValueExpr = expression;
160 }
161
162 template <typename ComputeValue>
setRightValue(Expression * expression)163 void CustomBinaryOp<ComputeValue>::setRightValue(Expression *expression)
164 {
165 m_rightValueExpr = expression;
166 }
167
168 template <typename ComputeValue>
evaluate(ExecValueAccess dst,ExecConstValueAccess a,ExecConstValueAccess b)169 void CustomBinaryOp<ComputeValue>::evaluate(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
170 {
171 DE_ASSERT(dst.getType() == a.getType());
172 DE_ASSERT(dst.getType() == b.getType());
173 DE_ASSERT(dst.getType().getBaseType() == VariableType::TYPE_FLOAT);
174
175 for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
176 {
177 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
178 dst.component(elemNdx).asFloat(compNdx) =
179 ComputeValue()(a.component(elemNdx).asFloat(compNdx), b.component(elemNdx).asFloat(compNdx));
180 }
181 }
182
183 template <>
evaluate(ExecValueAccess dst,ExecConstValueAccess a,ExecConstValueAccess b)184 void CustomBinaryOp<EvaluateLessThan>::evaluate(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
185 {
186 DE_ASSERT(a.getType() == b.getType());
187 DE_ASSERT(dst.getType().getBaseType() == VariableType::TYPE_BOOL);
188
189 for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
190 {
191 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
192 dst.component(elemNdx).asBool(compNdx) =
193 EvaluateLessThan()(a.component(elemNdx).asFloat(compNdx), b.component(elemNdx).asFloat(compNdx));
194 }
195 }
196
197 template <int Precedence, Associativity Assoc>
BinaryOp(Token::Type operatorToken)198 BinaryOp<Precedence, Assoc>::BinaryOp(Token::Type operatorToken)
199 : m_operator(operatorToken)
200 , m_leftValueRange(m_type)
201 , m_rightValueRange(m_type)
202 , m_leftValueExpr(DE_NULL)
203 , m_rightValueExpr(DE_NULL)
204 {
205 }
206
207 template <int Precedence, Associativity Assoc>
~BinaryOp(void)208 BinaryOp<Precedence, Assoc>::~BinaryOp(void)
209 {
210 delete m_leftValueExpr;
211 delete m_rightValueExpr;
212 }
213
214 template <int Precedence, Associativity Assoc>
createNextChild(GeneratorState & state)215 Expression *BinaryOp<Precedence, Assoc>::createNextChild(GeneratorState &state)
216 {
217 int leftPrec = Assoc == ASSOCIATIVITY_LEFT ? Precedence : Precedence - 1;
218 int rightPrec = Assoc == ASSOCIATIVITY_LEFT ? Precedence - 1 : Precedence;
219
220 if (m_rightValueExpr == DE_NULL)
221 {
222 state.pushPrecedence(rightPrec);
223 m_rightValueExpr = Expression::createRandom(state, m_rightValueRange.asAccess());
224 state.popPrecedence();
225 return m_rightValueExpr;
226 }
227 else if (m_leftValueExpr == DE_NULL)
228 {
229 state.pushPrecedence(leftPrec);
230 m_leftValueExpr = Expression::createRandom(state, m_leftValueRange.asAccess());
231 state.popPrecedence();
232 return m_leftValueExpr;
233 }
234 else
235 {
236 // Check for corrner cases
237 switch (m_operator)
238 {
239 case Token::CMP_LE:
240 {
241 // When comparing two floats epsilon should be included
242 // to eliminate the risk that we get different results
243 // because of precission error
244 VariableType floatType(VariableType::TYPE_FLOAT, 1);
245 if (m_rightValueRange.getType() == floatType)
246 {
247 FloatLiteral *epsilonLiteral = new FloatLiteral(0.001f);
248
249 typedef CustomBinaryOp<EvaluateAdd> CustomAddOp;
250 CustomAddOp *addOperation = new CustomAddOp();
251 addOperation->setLeftValue(m_rightValueExpr);
252 addOperation->setRightValue(epsilonLiteral);
253
254 // add epsilon to right-hand side
255 m_rightValueExpr = addOperation;
256 }
257 break;
258 }
259 case Token::CMP_GE:
260 {
261 // When comparing two floats epsilon should be included
262 // to eliminate the risk that we get different results
263 // because of precission error
264 VariableType floatType(VariableType::TYPE_FLOAT, 1);
265 if (m_leftValueRange.getType() == floatType)
266 {
267 FloatLiteral *epsilonLiteral = new FloatLiteral(0.001f);
268
269 typedef CustomBinaryOp<EvaluateAdd> CustomAddOp;
270 CustomAddOp *addOperation = new CustomAddOp();
271 addOperation->setLeftValue(m_leftValueExpr);
272 addOperation->setRightValue(epsilonLiteral);
273
274 // add epsilon to left-hand side
275 m_leftValueExpr = addOperation;
276 }
277 break;
278 }
279 case Token::CMP_EQ:
280 {
281 // When comparing two floats epsilon should be included
282 // to eliminate the risk that we get different results
283 // because of precission error
284 VariableType floatType(VariableType::TYPE_FLOAT, 1);
285 if (m_leftValueRange.getType() == floatType)
286 {
287 VariableType boolType(VariableType::TYPE_BOOL, 1);
288 const ValueRange boolRange(boolType);
289
290 ParenOp *parenRight = new ParenOp(state, boolRange);
291 parenRight->setChild(m_rightValueExpr);
292
293 typedef CustomBinaryOp<EvaluateSub> CustomSubOp;
294 CustomSubOp *subOperation = new CustomSubOp();
295 subOperation->setLeftValue(m_leftValueExpr);
296 subOperation->setRightValue(parenRight);
297
298 CustomAbsOp *absOperation = new CustomAbsOp();
299 absOperation->setChild(subOperation);
300 FloatLiteral *epsilonLiteral = new FloatLiteral(0.001f);
301
302 typedef CustomBinaryOp<EvaluateLessThan> CustomLessThanOp;
303 CustomLessThanOp *lessOperation = new CustomLessThanOp();
304 lessOperation->setLeftValue(absOperation);
305 lessOperation->setRightValue(epsilonLiteral);
306
307 ParenOp *parenOperation = new ParenOp(state, boolRange);
308 parenOperation->setChild(lessOperation);
309 BoolLiteral *trueLiteral = new BoolLiteral(true);
310
311 // EQ operation cant be removed so it is replaced with:
312 // ((abs(lhs-rhs) < epsilon) == true).
313 m_leftValueExpr = parenOperation;
314 m_rightValueExpr = trueLiteral;
315 }
316 break;
317 }
318 default:
319 break;
320 }
321
322 return DE_NULL;
323 }
324 }
325
326 template <int Precedence, Associativity Assoc>
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)327 float BinaryOp<Precedence, Assoc>::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
328 {
329 if (state.getPrecedence() < Precedence)
330 return 0.0f;
331
332 int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
333
334 if (valueRange.getType().isVoid())
335 return availableLevels >= 2 ? unusedValueWeight : 0.0f;
336
337 if (availableLevels < getConservativeValueExprDepth(state, valueRange) + 1)
338 return 0.0f;
339
340 return 1.0f;
341 }
342
343 template <int Precedence, Associativity Assoc>
tokenize(GeneratorState & state,TokenStream & str) const344 void BinaryOp<Precedence, Assoc>::tokenize(GeneratorState &state, TokenStream &str) const
345 {
346 m_leftValueExpr->tokenize(state, str);
347 str << m_operator;
348 m_rightValueExpr->tokenize(state, str);
349 }
350
351 template <int Precedence, Associativity Assoc>
evaluate(ExecutionContext & execCtx)352 void BinaryOp<Precedence, Assoc>::evaluate(ExecutionContext &execCtx)
353 {
354 m_leftValueExpr->evaluate(execCtx);
355 m_rightValueExpr->evaluate(execCtx);
356
357 ExecConstValueAccess leftVal = m_leftValueExpr->getValue();
358 ExecConstValueAccess rightVal = m_rightValueExpr->getValue();
359 ExecValueAccess dst = m_value.getValue(m_type);
360
361 evaluate(dst, leftVal, rightVal);
362 }
363
364 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp>
BinaryVecOp(GeneratorState & state,Token::Type operatorToken,ConstValueRangeAccess inValueRange)365 BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::BinaryVecOp(
366 GeneratorState &state, Token::Type operatorToken, ConstValueRangeAccess inValueRange)
367 : BinaryOp<Precedence, ASSOCIATIVITY_LEFT>(operatorToken)
368 {
369 ValueRange valueRange = inValueRange;
370
371 if (valueRange.getType().isVoid())
372 {
373 int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
374 vector<VariableType::Type> baseTypes;
375
376 if (Float)
377 baseTypes.push_back(VariableType::TYPE_FLOAT);
378 if (Int)
379 baseTypes.push_back(VariableType::TYPE_INT);
380 if (Bool)
381 baseTypes.push_back(VariableType::TYPE_BOOL);
382
383 VariableType::Type baseType = state.getRandom().choose<VariableType::Type>(baseTypes.begin(), baseTypes.end());
384 int numElements = state.getRandom().getInt(1, availableLevels >= 3 ? 4 : 1);
385
386 valueRange = ValueRange(VariableType(baseType, numElements));
387 computeRandomValueRange(state, valueRange.asAccess());
388 }
389
390 // Choose type, allocate storage for execution
391 this->m_type = valueRange.getType();
392 this->m_value.setStorage(this->m_type);
393
394 // Initialize storage for value ranges
395 this->m_rightValueRange = ValueRange(this->m_type);
396 this->m_leftValueRange = ValueRange(this->m_type);
397
398 VariableType::Type baseType = this->m_type.getBaseType();
399
400 // Compute range for b that satisfies requested value range
401 for (int elemNdx = 0; elemNdx < this->m_type.getNumElements(); elemNdx++)
402 {
403 ConstValueRangeAccess dst = valueRange.asAccess().component(elemNdx);
404 ValueRangeAccess a = this->m_leftValueRange.asAccess().component(
405 elemNdx); // \todo [2011-03-25 pyry] Commutative: randomize inputs
406 ValueRangeAccess b = this->m_rightValueRange.asAccess().component(elemNdx);
407
408 // Just pass undefined ranges
409 if ((baseType == VariableType::TYPE_FLOAT || baseType == VariableType::TYPE_INT) && isUndefinedValueRange(dst))
410 {
411 a.getMin() = dst.getMin().value();
412 b.getMin() = dst.getMin().value();
413 a.getMax() = dst.getMax().value();
414 b.getMax() = dst.getMax().value();
415 continue;
416 }
417
418 if (baseType == VariableType::TYPE_FLOAT)
419 ComputeValueRange()(state.getRandom(), dst.getMin().asFloat(), dst.getMax().asFloat(), a.getMin().asFloat(),
420 a.getMax().asFloat(), b.getMin().asFloat(), b.getMax().asFloat());
421 else if (baseType == VariableType::TYPE_INT)
422 ComputeValueRange()(state.getRandom(), dst.getMin().asInt(), dst.getMax().asInt(), a.getMin().asInt(),
423 a.getMax().asInt(), b.getMin().asInt(), b.getMax().asInt());
424 else
425 {
426 DE_ASSERT(baseType == VariableType::TYPE_BOOL);
427 ComputeValueRange()(state.getRandom(), dst.getMin().asBool(), dst.getMax().asBool(), a.getMin().asBool(),
428 a.getMax().asBool(), b.getMin().asBool(), b.getMax().asBool());
429 }
430 }
431 }
432
433 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp>
~BinaryVecOp(void)434 BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::~BinaryVecOp(void)
435 {
436 }
437
438 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp>
evaluate(ExecValueAccess dst,ExecConstValueAccess a,ExecConstValueAccess b)439 void BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::evaluate(ExecValueAccess dst,
440 ExecConstValueAccess a,
441 ExecConstValueAccess b)
442 {
443 DE_ASSERT(dst.getType() == a.getType());
444 DE_ASSERT(dst.getType() == b.getType());
445 switch (dst.getType().getBaseType())
446 {
447 case VariableType::TYPE_FLOAT:
448 for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
449 {
450 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
451 dst.component(elemNdx).asFloat(compNdx) =
452 EvaluateComp()(a.component(elemNdx).asFloat(compNdx), b.component(elemNdx).asFloat(compNdx));
453 }
454 break;
455
456 case VariableType::TYPE_INT:
457 for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
458 {
459 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
460 dst.component(elemNdx).asInt(compNdx) =
461 EvaluateComp()(a.component(elemNdx).asInt(compNdx), b.component(elemNdx).asInt(compNdx));
462 }
463 break;
464
465 default:
466 DE_ASSERT(false); // Invalid type for multiplication
467 }
468 }
469
operator ()(de::Random & rnd,float dstMin,float dstMax,float & aMin,float & aMax,float & bMin,float & bMax) const470 void ComputeMulRange::operator()(de::Random &rnd, float dstMin, float dstMax, float &aMin, float &aMax, float &bMin,
471 float &bMax) const
472 {
473 const float minScale = 0.25f;
474 const float maxScale = 2.0f;
475 const float subRangeStep = 0.25f;
476 const float scaleStep = 0.25f;
477
478 float scale = getQuantizedFloat(rnd, minScale, maxScale, scaleStep);
479 float scaledMin = dstMin / scale;
480 float scaledMax = dstMax / scale;
481
482 // Quantize scaled value range if possible
483 if (!quantizeFloatRange(scaledMin, scaledMax))
484 {
485 // Fall back to 1.0 as a scale
486 scale = 1.0f;
487 scaledMin = dstMin;
488 scaledMax = dstMax;
489 }
490
491 float subRangeLen = getQuantizedFloat(rnd, 0.0f, scaledMax - scaledMin, subRangeStep);
492 aMin = scaledMin + getQuantizedFloat(rnd, 0.0f, (scaledMax - scaledMin) - subRangeLen, subRangeStep);
493 aMax = aMin + subRangeLen;
494
495 // Find scale range
496 bMin = scale;
497 bMax = scale;
498 for (int i = 0; i < 5; i++)
499 {
500 if (de::inBounds(aMin * (scale - (float)i * scaleStep), dstMin, dstMax) &&
501 de::inBounds(aMax * (scale - (float)i * scaleStep), dstMin, dstMax))
502 bMin = scale - (float)i * scaleStep;
503
504 if (de::inBounds(aMin * (scale + (float)i * scaleStep), dstMin, dstMax) &&
505 de::inBounds(aMax * (scale + (float)i * scaleStep), dstMin, dstMax))
506 bMax = scale + (float)i * scaleStep;
507 }
508
509 // Negative scale?
510 if (rnd.getBool())
511 {
512 std::swap(aMin, aMax);
513 std::swap(bMin, bMax);
514 aMin *= -1.0f;
515 aMax *= -1.0f;
516 bMin *= -1.0f;
517 bMax *= -1.0f;
518 }
519
520 #if defined(DE_DEBUG)
521 const float eps = 0.001f;
522 DE_ASSERT(aMin <= aMax && bMin <= bMax);
523 DE_ASSERT(de::inRange(aMin * bMin, dstMin - eps, dstMax + eps));
524 DE_ASSERT(de::inRange(aMin * bMax, dstMin - eps, dstMax + eps));
525 DE_ASSERT(de::inRange(aMax * bMin, dstMin - eps, dstMax + eps));
526 DE_ASSERT(de::inRange(aMax * bMax, dstMin - eps, dstMax + eps));
527 #endif
528 }
529
operator ()(de::Random & rnd,int dstMin,int dstMax,int & aMin,int & aMax,int & bMin,int & bMax) const530 void ComputeMulRange::operator()(de::Random &rnd, int dstMin, int dstMax, int &aMin, int &aMax, int &bMin,
531 int &bMax) const
532 {
533 DE_UNREF(rnd);
534 aMin = dstMin;
535 aMax = dstMax;
536 bMin = 1;
537 bMax = 1;
538 }
539
MulOp(GeneratorState & state,ConstValueRangeAccess valueRange)540 MulOp::MulOp(GeneratorState &state, ConstValueRangeAccess valueRange) : MulBase(state, Token::MUL, valueRange)
541 {
542 }
543
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)544 float MulOp::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
545 {
546 if (valueRange.getType().isVoid() || valueRange.getType().isFloatOrVec() || valueRange.getType().isIntOrVec())
547 return MulBase::getWeight(state, valueRange);
548 else
549 return 0.0f;
550 }
551
552 template <typename T>
operator ()(de::Random & random,T dstMin,T dstMax,T & aMin,T & aMax,T & bMin,T & bMax) const553 void ComputeAddRange::operator()(de::Random &random, T dstMin, T dstMax, T &aMin, T &aMax, T &bMin, T &bMax) const
554 {
555 struct GetRandom
556 {
557 int operator()(de::Random &rnd, int min, int max) const
558 {
559 return rnd.getInt(min, max);
560 }
561 float operator()(de::Random &rnd, float min, float max) const
562 {
563 return getQuantizedFloat(rnd, min, max, 0.5f);
564 }
565 };
566
567 T rangeLen = dstMax - dstMin;
568 T subRangeLen = GetRandom()(random, T(0), rangeLen);
569 T aOffset = GetRandom()(random, T(-8), T(8));
570
571 aMin = dstMin + aOffset;
572 aMax = aMin + subRangeLen;
573
574 bMin = -aOffset;
575 bMax = -aOffset + (rangeLen - subRangeLen);
576
577 #if defined(DE_DEBUG)
578 T eps = T(0.001);
579 DE_ASSERT(aMin <= aMax && bMin <= bMax);
580 DE_ASSERT(de::inRange(aMin + bMin, dstMin - eps, dstMax + eps));
581 DE_ASSERT(de::inRange(aMin + bMax, dstMin - eps, dstMax + eps));
582 DE_ASSERT(de::inRange(aMax + bMin, dstMin - eps, dstMax + eps));
583 DE_ASSERT(de::inRange(aMax + bMax, dstMin - eps, dstMax + eps));
584 #endif
585 }
586
587 template <>
operator()588 void ComputeAddRange::operator()<bool>(de::Random &, bool, bool, bool &, bool &, bool &, bool &) const
589 {
590 DE_ASSERT(false);
591 }
592
AddOp(GeneratorState & state,ConstValueRangeAccess valueRange)593 AddOp::AddOp(GeneratorState &state, ConstValueRangeAccess valueRange) : AddBase(state, Token::PLUS, valueRange)
594 {
595 }
596
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)597 float AddOp::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
598 {
599 if (valueRange.getType().isVoid() || valueRange.getType().isFloatOrVec() || valueRange.getType().isIntOrVec())
600 return AddBase::getWeight(state, valueRange);
601 else
602 return 0.0f;
603 }
604
605 template <typename T>
operator ()(de::Random & random,T dstMin,T dstMax,T & aMin,T & aMax,T & bMin,T & bMax) const606 void ComputeSubRange::operator()(de::Random &random, T dstMin, T dstMax, T &aMin, T &aMax, T &bMin, T &bMax) const
607 {
608 struct GetRandom
609 {
610 int operator()(de::Random &rnd, int min, int max) const
611 {
612 return rnd.getInt(min, max);
613 }
614 float operator()(de::Random &rnd, float min, float max) const
615 {
616 return getQuantizedFloat(rnd, min, max, 0.5f);
617 }
618 };
619
620 T rangeLen = dstMax - dstMin;
621 T subRangeLen = GetRandom()(random, T(0), rangeLen);
622 T aOffset = GetRandom()(random, T(-8), T(8));
623
624 aMin = dstMin + aOffset;
625 aMax = aMin + subRangeLen;
626
627 bMin = aOffset - (rangeLen - subRangeLen);
628 bMax = aOffset;
629
630 #if defined(DE_DEBUG)
631 T eps = T(0.001);
632 DE_ASSERT(aMin <= aMax && bMin <= bMax);
633 DE_ASSERT(de::inRange(aMin - bMin, dstMin - eps, dstMax + eps));
634 DE_ASSERT(de::inRange(aMin - bMax, dstMin - eps, dstMax + eps));
635 DE_ASSERT(de::inRange(aMax - bMin, dstMin - eps, dstMax + eps));
636 DE_ASSERT(de::inRange(aMax - bMax, dstMin - eps, dstMax + eps));
637 #endif
638 }
639
640 template <>
operator()641 void ComputeSubRange::operator()<bool>(de::Random &, bool, bool, bool &, bool &, bool &, bool &) const
642 {
643 DE_ASSERT(false);
644 }
645
SubOp(GeneratorState & state,ConstValueRangeAccess valueRange)646 SubOp::SubOp(GeneratorState &state, ConstValueRangeAccess valueRange) : SubBase(state, Token::MINUS, valueRange)
647 {
648 }
649
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)650 float SubOp::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
651 {
652 if (valueRange.getType().isVoid() || valueRange.getType().isFloatOrVec() || valueRange.getType().isIntOrVec())
653 return SubBase::getWeight(state, valueRange);
654 else
655 return 0.0f;
656 }
657
658 template <class ComputeValueRange, class EvaluateComp>
RelationalOp(GeneratorState & state,Token::Type operatorToken,ConstValueRangeAccess inValueRange)659 RelationalOp<ComputeValueRange, EvaluateComp>::RelationalOp(GeneratorState &state, Token::Type operatorToken,
660 ConstValueRangeAccess inValueRange)
661 : BinaryOp<7, ASSOCIATIVITY_LEFT>(operatorToken)
662 {
663 ValueRange valueRange = inValueRange;
664
665 if (valueRange.getType().isVoid())
666 {
667 valueRange = ValueRange(VariableType(VariableType::TYPE_BOOL, 1));
668 computeRandomValueRange(state, valueRange.asAccess());
669 }
670
671 // Choose type, allocate storage for execution
672 this->m_type = valueRange.getType();
673 this->m_value.setStorage(this->m_type);
674
675 // Choose random input type
676 VariableType::Type inBaseTypes[] = {VariableType::TYPE_FLOAT, VariableType::TYPE_INT};
677 VariableType::Type inBaseType =
678 state.getRandom().choose<VariableType::Type>(&inBaseTypes[0], &inBaseTypes[DE_LENGTH_OF_ARRAY(inBaseTypes)]);
679
680 // Initialize storage for input value ranges
681 this->m_rightValueRange = ValueRange(VariableType(inBaseType, 1));
682 this->m_leftValueRange = ValueRange(VariableType(inBaseType, 1));
683
684 // Compute range for b that satisfies requested value range
685 {
686 bool dstMin = valueRange.getMin().asBool();
687 bool dstMax = valueRange.getMax().asBool();
688 ValueRangeAccess a = this->m_leftValueRange.asAccess();
689 ValueRangeAccess b = this->m_rightValueRange.asAccess();
690
691 if (inBaseType == VariableType::TYPE_FLOAT)
692 ComputeValueRange()(state.getRandom(), dstMin, dstMax, a.getMin().asFloat(), a.getMax().asFloat(),
693 b.getMin().asFloat(), b.getMax().asFloat());
694 else if (inBaseType == VariableType::TYPE_INT)
695 ComputeValueRange()(state.getRandom(), dstMin, dstMax, a.getMin().asInt(), a.getMax().asInt(),
696 b.getMin().asInt(), b.getMax().asInt());
697 }
698 }
699
700 template <class ComputeValueRange, class EvaluateComp>
~RelationalOp(void)701 RelationalOp<ComputeValueRange, EvaluateComp>::~RelationalOp(void)
702 {
703 }
704
705 template <class ComputeValueRange, class EvaluateComp>
evaluate(ExecValueAccess dst,ExecConstValueAccess a,ExecConstValueAccess b)706 void RelationalOp<ComputeValueRange, EvaluateComp>::evaluate(ExecValueAccess dst, ExecConstValueAccess a,
707 ExecConstValueAccess b)
708 {
709 DE_ASSERT(a.getType() == b.getType());
710 switch (a.getType().getBaseType())
711 {
712 case VariableType::TYPE_FLOAT:
713 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
714 dst.asBool(compNdx) = EvaluateComp()(a.asFloat(compNdx), b.asFloat(compNdx));
715 break;
716
717 case VariableType::TYPE_INT:
718 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
719 dst.asBool(compNdx) = EvaluateComp()(a.asInt(compNdx), b.asInt(compNdx));
720 break;
721
722 default:
723 DE_ASSERT(false);
724 }
725 }
726
727 template <class ComputeValueRange, class EvaluateComp>
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)728 float RelationalOp<ComputeValueRange, EvaluateComp>::getWeight(const GeneratorState &state,
729 ConstValueRangeAccess valueRange)
730 {
731 if (!state.getProgramParameters().useComparisonOps)
732 return 0.0f;
733
734 if (valueRange.getType().isVoid() ||
735 (valueRange.getType().getBaseType() == VariableType::TYPE_BOOL && valueRange.getType().getNumElements() == 1))
736 return BinaryOp<7, ASSOCIATIVITY_LEFT>::getWeight(state, valueRange);
737 else
738 return 0.0f;
739 }
740
741 namespace
742 {
743
744 template <typename T>
745 T getStep(void);
746 template <>
getStep(void)747 inline float getStep(void)
748 {
749 return 0.25f;
750 }
751 template <>
getStep(void)752 inline int getStep(void)
753 {
754 return 1;
755 }
756
757 } // namespace
758
759 template <typename T>
operator ()(de::Random & rnd,bool dstMin,bool dstMax,T & aMin,T & aMax,T & bMin,T & bMax) const760 void ComputeLessThanRange::operator()(de::Random &rnd, bool dstMin, bool dstMax, T &aMin, T &aMax, T &bMin,
761 T &bMax) const
762 {
763 struct GetRandom
764 {
765 int operator()(de::Random &random, int min, int max) const
766 {
767 return random.getInt(min, max);
768 }
769 float operator()(de::Random &random, float min, float max) const
770 {
771 return getQuantizedFloat(random, min, max, getStep<float>());
772 }
773 };
774
775 // One random range
776 T rLen = GetRandom()(rnd, T(0), T(8));
777 T rMin = GetRandom()(rnd, T(-4), T(4));
778 T rMax = rMin + rLen;
779
780 if (dstMin == false && dstMax == true)
781 {
782 // Both values are possible, use same range for both inputs
783 aMin = rMin;
784 aMax = rMax;
785 bMin = rMin;
786 bMax = rMax;
787 }
788 else if (dstMin == true && dstMax == true)
789 {
790 // Compute range that is less than rMin..rMax
791 T aLen = GetRandom()(rnd, T(0), T(8) - rLen);
792
793 aMax = rMin - getStep<T>();
794 aMin = aMax - aLen;
795
796 bMin = rMin;
797 bMax = rMax;
798 }
799 else
800 {
801 // Compute range that is greater than or equal to rMin..rMax
802 T aLen = GetRandom()(rnd, T(0), T(8) - rLen);
803
804 aMin = rMax;
805 aMax = aMin + aLen;
806
807 bMin = rMin;
808 bMax = rMax;
809 }
810 }
811
LessThanOp(GeneratorState & state,ConstValueRangeAccess valueRange)812 LessThanOp::LessThanOp(GeneratorState &state, ConstValueRangeAccess valueRange)
813 : LessThanBase(state, Token::CMP_LT, valueRange)
814 {
815 }
816
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)817 float LessThanOp::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
818 {
819 return LessThanBase::getWeight(state, valueRange);
820 }
821
822 template <typename T>
operator ()(de::Random & rnd,bool dstMin,bool dstMax,T & aMin,T & aMax,T & bMin,T & bMax) const823 void ComputeLessOrEqualRange::operator()(de::Random &rnd, bool dstMin, bool dstMax, T &aMin, T &aMax, T &bMin,
824 T &bMax) const
825 {
826 struct GetRandom
827 {
828 int operator()(de::Random &random, int min, int max) const
829 {
830 return random.getInt(min, max);
831 }
832 float operator()(de::Random &random, float min, float max) const
833 {
834 return getQuantizedFloat(random, min, max, getStep<float>());
835 }
836 };
837
838 // One random range
839 T rLen = GetRandom()(rnd, T(0), T(8));
840 T rMin = GetRandom()(rnd, T(-4), T(4));
841 T rMax = rMin + rLen;
842
843 if (dstMin == false && dstMax == true)
844 {
845 // Both values are possible, use same range for both inputs
846 aMin = rMin;
847 aMax = rMax;
848 bMin = rMin;
849 bMax = rMax;
850 }
851 else if (dstMin == true && dstMax == true)
852 {
853 // Compute range that is less than or equal to rMin..rMax
854 T aLen = GetRandom()(rnd, T(0), T(8) - rLen);
855
856 aMax = rMin;
857 aMin = aMax - aLen;
858
859 bMin = rMin;
860 bMax = rMax;
861 }
862 else
863 {
864 // Compute range that is greater than rMin..rMax
865 T aLen = GetRandom()(rnd, T(0), T(8) - rLen);
866
867 aMin = rMax + getStep<T>();
868 aMax = aMin + aLen;
869
870 bMin = rMin;
871 bMax = rMax;
872 }
873 }
874
LessOrEqualOp(GeneratorState & state,ConstValueRangeAccess valueRange)875 LessOrEqualOp::LessOrEqualOp(GeneratorState &state, ConstValueRangeAccess valueRange)
876 : LessOrEqualBase(state, Token::CMP_LE, valueRange)
877 {
878 }
879
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)880 float LessOrEqualOp::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
881 {
882 return LessOrEqualBase::getWeight(state, valueRange);
883 }
884
GreaterThanOp(GeneratorState & state,ConstValueRangeAccess valueRange)885 GreaterThanOp::GreaterThanOp(GeneratorState &state, ConstValueRangeAccess valueRange)
886 : GreaterThanBase(state, Token::CMP_GT, valueRange)
887 {
888 }
889
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)890 float GreaterThanOp::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
891 {
892 return GreaterThanBase::getWeight(state, valueRange);
893 }
894
GreaterOrEqualOp(GeneratorState & state,ConstValueRangeAccess valueRange)895 GreaterOrEqualOp::GreaterOrEqualOp(GeneratorState &state, ConstValueRangeAccess valueRange)
896 : GreaterOrEqualBase(state, Token::CMP_GE, valueRange)
897 {
898 }
899
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)900 float GreaterOrEqualOp::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
901 {
902 return GreaterOrEqualBase::getWeight(state, valueRange);
903 }
904
905 namespace
906 {
907
908 template <bool IsEqual, typename T>
computeEqualityValueRange(de::Random & rnd,bool dstMin,bool dstMax,T & aMin,T & aMax,T & bMin,T & bMax)909 void computeEqualityValueRange(de::Random &rnd, bool dstMin, bool dstMax, T &aMin, T &aMax, T &bMin, T &bMax)
910 {
911 if (dstMin == false && dstMax == true)
912 ComputeLessThanRange()(rnd, false, true, aMin, aMax, bMin, bMax);
913 else if (IsEqual && dstMin == false)
914 ComputeLessThanRange()(rnd, true, true, aMin, aMax, bMin, bMax);
915 else if (!IsEqual && dstMin == true)
916 ComputeLessThanRange()(rnd, true, true, aMin, aMax, bMin, bMax);
917 else
918 {
919 // Must have exactly same values.
920 struct GetRandom
921 {
922 int operator()(de::Random &random, int min, int max) const
923 {
924 return random.getInt(min, max);
925 }
926 float operator()(de::Random &random, float min, float max) const
927 {
928 return getQuantizedFloat(random, min, max, 0.5f);
929 }
930 };
931
932 T val = GetRandom()(rnd, T(-1), T(1));
933
934 aMin = val;
935 aMax = val;
936 bMin = val;
937 bMax = val;
938 }
939 }
940
941 template <>
computeEqualityValueRange(de::Random & rnd,bool dstMin,bool dstMax,bool & aMin,bool & aMax,bool & bMin,bool & bMax)942 void computeEqualityValueRange<true, bool>(de::Random &rnd, bool dstMin, bool dstMax, bool &aMin, bool &aMax,
943 bool &bMin, bool &bMax)
944 {
945 if (dstMin == false && dstMax == true)
946 {
947 aMin = false;
948 aMax = true;
949 bMin = false;
950 bMax = true;
951 }
952 else if (dstMin == false)
953 {
954 DE_ASSERT(dstMax == false);
955 bool val = rnd.getBool();
956
957 aMin = val;
958 aMax = val;
959 bMin = !val;
960 bMax = !val;
961 }
962 else
963 {
964 DE_ASSERT(dstMin == true && dstMax == true);
965 bool val = rnd.getBool();
966
967 aMin = val;
968 aMax = val;
969 bMin = val;
970 bMax = val;
971 }
972 }
973
974 template <>
computeEqualityValueRange(de::Random & rnd,bool dstMin,bool dstMax,bool & aMin,bool & aMax,bool & bMin,bool & bMax)975 void computeEqualityValueRange<false, bool>(de::Random &rnd, bool dstMin, bool dstMax, bool &aMin, bool &aMax,
976 bool &bMin, bool &bMax)
977 {
978 if (dstMin == false && dstMax == true)
979 computeEqualityValueRange<true>(rnd, dstMin, dstMax, aMin, aMax, bMin, bMax);
980 else
981 computeEqualityValueRange<true>(rnd, !dstMin, !dstMax, aMin, aMax, bMin, bMax);
982 }
983
984 } // namespace
985
986 template <bool IsEqual>
EqualityComparisonOp(GeneratorState & state,ConstValueRangeAccess inValueRange)987 EqualityComparisonOp<IsEqual>::EqualityComparisonOp(GeneratorState &state, ConstValueRangeAccess inValueRange)
988 : BinaryOp<8, ASSOCIATIVITY_LEFT>(IsEqual ? Token::CMP_EQ : Token::CMP_NE)
989 {
990 ValueRange valueRange = inValueRange;
991
992 if (valueRange.getType().isVoid())
993 {
994 valueRange = ValueRange(VariableType(VariableType::TYPE_BOOL, 1));
995 computeRandomValueRange(state, valueRange.asAccess());
996 }
997
998 // Choose type, allocate storage for execution
999 this->m_type = valueRange.getType();
1000 this->m_value.setStorage(this->m_type);
1001
1002 // Choose random input type
1003 VariableType::Type inBaseTypes[] = {VariableType::TYPE_FLOAT, VariableType::TYPE_INT};
1004 VariableType::Type inBaseType =
1005 state.getRandom().choose<VariableType::Type>(&inBaseTypes[0], &inBaseTypes[DE_LENGTH_OF_ARRAY(inBaseTypes)]);
1006 int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
1007 int numElements = state.getRandom().getInt(1, availableLevels >= 3 ? 4 : 1);
1008
1009 // Initialize storage for input value ranges
1010 this->m_rightValueRange = ValueRange(VariableType(inBaseType, numElements));
1011 this->m_leftValueRange = ValueRange(VariableType(inBaseType, numElements));
1012
1013 // Compute range for b that satisfies requested value range
1014 for (int elementNdx = 0; elementNdx < numElements; elementNdx++)
1015 {
1016 bool dstMin = valueRange.getMin().asBool();
1017 bool dstMax = valueRange.getMax().asBool();
1018
1019 ValueRangeAccess a = this->m_leftValueRange.asAccess().component(elementNdx);
1020 ValueRangeAccess b = this->m_rightValueRange.asAccess().component(elementNdx);
1021
1022 if (inBaseType == VariableType::TYPE_FLOAT)
1023 computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax, a.getMin().asFloat(),
1024 a.getMax().asFloat(), b.getMin().asFloat(), b.getMax().asFloat());
1025 else if (inBaseType == VariableType::TYPE_INT)
1026 computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax, a.getMin().asInt(),
1027 a.getMax().asInt(), b.getMin().asInt(), b.getMax().asInt());
1028 else
1029 {
1030 DE_ASSERT(inBaseType == VariableType::TYPE_BOOL);
1031 computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax, a.getMin().asBool(),
1032 a.getMax().asBool(), b.getMin().asBool(), b.getMax().asBool());
1033 }
1034 }
1035 }
1036
1037 template <bool IsEqual>
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)1038 float EqualityComparisonOp<IsEqual>::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
1039 {
1040 if (!state.getProgramParameters().useComparisonOps)
1041 return 0.0f;
1042
1043 // \todo [2011-06-13 pyry] Weight down cases that would force constant inputs.
1044
1045 if (valueRange.getType().isVoid() ||
1046 (valueRange.getType().getBaseType() == VariableType::TYPE_BOOL && valueRange.getType().getNumElements() == 1))
1047 return BinaryOp<8, ASSOCIATIVITY_LEFT>::getWeight(state, valueRange);
1048 else
1049 return 0.0f;
1050 }
1051
1052 namespace
1053 {
1054
1055 template <bool IsEqual>
1056 struct EqualityCompare
1057 {
1058 template <typename T>
1059 static bool compare(T a, T b);
1060 static bool combine(bool a, bool b);
1061 };
1062
1063 template <>
1064 template <typename T>
compare(T a,T b)1065 inline bool EqualityCompare<true>::compare(T a, T b)
1066 {
1067 return a == b;
1068 }
1069
1070 template <>
combine(bool a,bool b)1071 inline bool EqualityCompare<true>::combine(bool a, bool b)
1072 {
1073 return a && b;
1074 }
1075
1076 template <>
1077 template <typename T>
compare(T a,T b)1078 inline bool EqualityCompare<false>::compare(T a, T b)
1079 {
1080 return a != b;
1081 }
1082
1083 template <>
combine(bool a,bool b)1084 inline bool EqualityCompare<false>::combine(bool a, bool b)
1085 {
1086 return a || b;
1087 }
1088
1089 } // namespace
1090
1091 template <bool IsEqual>
evaluate(ExecValueAccess dst,ExecConstValueAccess a,ExecConstValueAccess b)1092 void EqualityComparisonOp<IsEqual>::evaluate(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
1093 {
1094 DE_ASSERT(a.getType() == b.getType());
1095
1096 switch (a.getType().getBaseType())
1097 {
1098 case VariableType::TYPE_FLOAT:
1099 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
1100 {
1101 bool result = IsEqual ? true : false;
1102
1103 for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++)
1104 result = EqualityCompare<IsEqual>::combine(
1105 result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asFloat(compNdx),
1106 b.component(elemNdx).asFloat(compNdx)));
1107
1108 dst.asBool(compNdx) = result;
1109 }
1110 break;
1111
1112 case VariableType::TYPE_INT:
1113 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
1114 {
1115 bool result = IsEqual ? true : false;
1116
1117 for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++)
1118 result = EqualityCompare<IsEqual>::combine(
1119 result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asInt(compNdx),
1120 b.component(elemNdx).asInt(compNdx)));
1121
1122 dst.asBool(compNdx) = result;
1123 }
1124 break;
1125
1126 case VariableType::TYPE_BOOL:
1127 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
1128 {
1129 bool result = IsEqual ? true : false;
1130
1131 for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++)
1132 result = EqualityCompare<IsEqual>::combine(
1133 result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asBool(compNdx),
1134 b.component(elemNdx).asBool(compNdx)));
1135
1136 dst.asBool(compNdx) = result;
1137 }
1138 break;
1139
1140 default:
1141 DE_ASSERT(false);
1142 }
1143 }
1144
EqualOp(GeneratorState & state,ConstValueRangeAccess valueRange)1145 EqualOp::EqualOp(GeneratorState &state, ConstValueRangeAccess valueRange)
1146 : EqualityComparisonOp<true>(state, valueRange)
1147 {
1148 }
1149
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)1150 float EqualOp::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
1151 {
1152 return EqualityComparisonOp<true>::getWeight(state, valueRange);
1153 }
1154
NotEqualOp(GeneratorState & state,ConstValueRangeAccess valueRange)1155 NotEqualOp::NotEqualOp(GeneratorState &state, ConstValueRangeAccess valueRange)
1156 : EqualityComparisonOp<false>(state, valueRange)
1157 {
1158 }
1159
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)1160 float NotEqualOp::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
1161 {
1162 return EqualityComparisonOp<false>::getWeight(state, valueRange);
1163 }
1164
1165 } // namespace rsg
1166