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
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);
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
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	{
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
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
856