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