xref: /aosp_15_r20/external/deqp/framework/randomshaders/rsgBinaryOps.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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