Home | History | Annotate | Download | only in randomshaders
      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>
     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>
     45 BinaryOp<Precedence, Assoc>::~BinaryOp (void)
     46 {
     47 	delete m_leftValueExpr;
     48 	delete m_rightValueExpr;
     49 }
     50 
     51 template <int Precedence, Associativity Assoc>
     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>
     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>
     93 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>
    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>
    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>
    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>
    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 
    213 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 
    272 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 
    281 MulOp::MulOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    282 	: MulBase(state, Token::MUL, valueRange)
    283 {
    284 }
    285 
    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>
    297 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 <>
    326 void ComputeAddRange::operator()<bool> (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const
    327 {
    328 	DE_ASSERT(DE_FALSE);
    329 }
    330 
    331 AddOp::AddOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    332 	: AddBase(state, Token::PLUS, valueRange)
    333 {
    334 }
    335 
    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>
    347 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 <>
    376 void ComputeSubRange::operator()<bool> (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const
    377 {
    378 	DE_ASSERT(DE_FALSE);
    379 }
    380 
    381 SubOp::SubOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    382 	: SubBase(state, Token::MINUS, valueRange)
    383 {
    384 }
    385 
    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>
    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>
    439 RelationalOp<ComputeValueRange, EvaluateComp>::~RelationalOp (void)
    440 {
    441 }
    442 
    443 template <class ComputeValueRange, class EvaluateComp>
    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>
    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);
    481 template <> inline		float	getStep (void) { return 0.25f;	}
    482 template <> inline		int		getStep (void) { return 1;		}
    483 
    484 } // anonymous
    485 
    486 template <typename T>
    487 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 
    532 LessThanOp::LessThanOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    533 	: LessThanBase(state, Token::CMP_LT, valueRange)
    534 {
    535 }
    536 
    537 float LessThanOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
    538 {
    539 	return LessThanBase::getWeight(state, valueRange);
    540 }
    541 
    542 template <typename T>
    543 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 
    588 LessOrEqualOp::LessOrEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    589 	: LessOrEqualBase(state, Token::CMP_LE, valueRange)
    590 {
    591 }
    592 
    593 float LessOrEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
    594 {
    595 	return LessOrEqualBase::getWeight(state, valueRange);
    596 }
    597 
    598 GreaterThanOp::GreaterThanOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    599 	: GreaterThanBase(state, Token::CMP_GT, valueRange)
    600 {
    601 }
    602 
    603 float GreaterThanOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
    604 {
    605 	return GreaterThanBase::getWeight(state, valueRange);
    606 }
    607 
    608 GreaterOrEqualOp::GreaterOrEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    609 	: GreaterOrEqualBase(state, Token::CMP_GE, valueRange)
    610 {
    611 }
    612 
    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>
    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 <>
    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 <>
    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>
    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>
    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>
    772 inline bool EqualityCompare<true>::compare	(T a, T b)			{ return a == b; }
    773 
    774 template <>
    775 inline bool EqualityCompare<true>::combine	(bool a, bool b)	{ return a && b; }
    776 
    777 template <>
    778 template <typename T>
    779 inline bool EqualityCompare<false>::compare	(T a, T b)			{ return a != b; }
    780 
    781 template <>
    782 inline bool EqualityCompare<false>::combine	(bool a, bool b)	{ return a || b; }
    783 
    784 } // anonymous
    785 
    786 template <bool IsEqual>
    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 
    835 EqualOp::EqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    836 	: EqualityComparisonOp<true>(state, valueRange)
    837 {
    838 }
    839 
    840 float EqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
    841 {
    842 	return EqualityComparisonOp<true>::getWeight(state, valueRange);
    843 }
    844 
    845 NotEqualOp::NotEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange)
    846 	: EqualityComparisonOp<false>(state, valueRange)
    847 {
    848 }
    849 
    850 float NotEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange)
    851 {
    852 	return EqualityComparisonOp<false>::getWeight(state, valueRange);
    853 }
    854 
    855 } // rsg
    856