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