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