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