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 // CustomAbsOp and CustomBinaryOp are used to resolve float comparision corner case. 35 // This error happened when two floats with the same value were compared 36 // without using epsilon. If result of this comparisment influenced the 37 // output color then result and reference images could differ. 38 class CustomAbsOp : public Expression 39 { 40 public: 41 CustomAbsOp (void); 42 virtual ~CustomAbsOp (void); 43 44 void setChild (Expression* expression); 45 Expression* createNextChild (GeneratorState& state); 46 void tokenize (GeneratorState& state, TokenStream& str) const; 47 48 void evaluate (ExecutionContext& execCtx); 49 ExecConstValueAccess getValue (void) const { return m_value.getValue(m_type); } 50 51 private: 52 std::string m_function; 53 VariableType m_type; 54 ExecValueStorage m_value; 55 Expression* m_child; 56 }; 57 58 CustomAbsOp::CustomAbsOp (void) 59 : m_function ("abs") 60 , m_type (VariableType::TYPE_FLOAT, 1) 61 , m_child (DE_NULL) 62 { 63 m_value.setStorage(m_type); 64 } 65 66 CustomAbsOp::~CustomAbsOp (void) 67 { 68 delete m_child; 69 } 70 71 void CustomAbsOp::setChild(Expression* expression) 72 { 73 m_child = expression; 74 } 75 76 Expression* CustomAbsOp::createNextChild (GeneratorState&) 77 { 78 DE_ASSERT(0); 79 return DE_NULL; 80 } 81 82 void CustomAbsOp::tokenize (GeneratorState& state, TokenStream& str) const 83 { 84 str << Token(m_function.c_str()) << Token::LEFT_PAREN; 85 m_child->tokenize(state, str); 86 str << Token::RIGHT_PAREN; 87 } 88 89 void CustomAbsOp::evaluate (ExecutionContext& execCtx) 90 { 91 m_child->evaluate(execCtx); 92 93 ExecConstValueAccess srcValue = m_child->getValue(); 94 ExecValueAccess dstValue = m_value.getValue(m_type); 95 96 for (int elemNdx = 0; elemNdx < m_type.getNumElements(); elemNdx++) 97 { 98 ExecConstValueAccess srcComp = srcValue.component(elemNdx); 99 ExecValueAccess dstComp = dstValue.component(elemNdx); 100 101 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) 102 dstComp.asFloat(compNdx) = deFloatAbs(srcComp.asFloat(compNdx)); 103 } 104 } 105 106 typedef BinaryOp<5, ASSOCIATIVITY_LEFT> CustomBinaryBase; 107 108 // CustomBinaryOp and CustomAbsOp are used to resolve float comparision corner case. 109 // CustomBinaryOp supports addition and substraction as only those functionalities 110 // were needed. 111 template <typename ComputeValue> 112 class CustomBinaryOp: public CustomBinaryBase 113 { 114 public: 115 CustomBinaryOp (); 116 virtual ~CustomBinaryOp (void) {} 117 118 void setLeftValue (Expression* expression); 119 void setRightValue (Expression* expression); 120 121 void evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b); 122 }; 123 124 template <typename ComputeValue> 125 CustomBinaryOp<ComputeValue>::CustomBinaryOp () 126 : CustomBinaryBase(Token::PLUS) 127 { 128 // By default add operation is assumed, for every other operation 129 // separate constructor specialization should be implemented 130 m_type = VariableType(VariableType::TYPE_FLOAT, 1); 131 m_value.setStorage(m_type); 132 } 133 134 template <> 135 CustomBinaryOp<EvaluateSub>::CustomBinaryOp () 136 : CustomBinaryBase(Token::MINUS) 137 { 138 // Specialization for substraction 139 m_type = VariableType(VariableType::TYPE_FLOAT, 1); 140 m_leftValueRange = ValueRange(m_type); 141 m_rightValueRange = ValueRange(m_type); 142 m_value.setStorage(m_type); 143 } 144 145 template <> 146 CustomBinaryOp<EvaluateLessThan>::CustomBinaryOp () 147 : CustomBinaryBase(Token::CMP_LT) 148 { 149 // Specialization for less_then comparision 150 m_type = VariableType(VariableType::TYPE_BOOL, 1); 151 VariableType floatType = VariableType(VariableType::TYPE_FLOAT, 1); 152 m_leftValueRange = ValueRange(floatType); 153 m_rightValueRange = ValueRange(floatType); 154 m_value.setStorage(m_type); 155 } 156 157 template <typename ComputeValue> 158 void CustomBinaryOp<ComputeValue>::setLeftValue(Expression* expression) 159 { 160 m_leftValueExpr = expression; 161 } 162 163 template <typename ComputeValue> 164 void CustomBinaryOp<ComputeValue>::setRightValue(Expression* expression) 165 { 166 m_rightValueExpr = expression; 167 } 168 169 template <typename ComputeValue> 170 void CustomBinaryOp<ComputeValue>::evaluate(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b) 171 { 172 DE_ASSERT(dst.getType() == a.getType()); 173 DE_ASSERT(dst.getType() == b.getType()); 174 DE_ASSERT(dst.getType().getBaseType() == VariableType::TYPE_FLOAT); 175 176 for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++) 177 { 178 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) 179 dst.component(elemNdx).asFloat(compNdx) = ComputeValue()(a.component(elemNdx).asFloat(compNdx),b.component(elemNdx).asFloat(compNdx)); 180 } 181 } 182 183 template <> 184 void CustomBinaryOp<EvaluateLessThan>::evaluate(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b) 185 { 186 DE_ASSERT(a.getType() == b.getType()); 187 DE_ASSERT(dst.getType().getBaseType() == VariableType::TYPE_BOOL); 188 189 for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++) 190 { 191 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) 192 dst.component(elemNdx).asBool(compNdx) = EvaluateLessThan()(a.component(elemNdx).asFloat(compNdx),b.component(elemNdx).asFloat(compNdx)); 193 } 194 } 195 196 template <int Precedence, Associativity Assoc> 197 BinaryOp<Precedence, Assoc>::BinaryOp (Token::Type operatorToken) 198 : m_operator (operatorToken) 199 , m_leftValueRange (m_type) 200 , m_rightValueRange (m_type) 201 , m_leftValueExpr (DE_NULL) 202 , m_rightValueExpr (DE_NULL) 203 { 204 } 205 206 template <int Precedence, Associativity Assoc> 207 BinaryOp<Precedence, Assoc>::~BinaryOp (void) 208 { 209 delete m_leftValueExpr; 210 delete m_rightValueExpr; 211 } 212 213 template <int Precedence, Associativity Assoc> 214 Expression* BinaryOp<Precedence, Assoc>::createNextChild (GeneratorState& state) 215 { 216 int leftPrec = Assoc == ASSOCIATIVITY_LEFT ? Precedence : Precedence-1; 217 int rightPrec = Assoc == ASSOCIATIVITY_LEFT ? Precedence-1 : Precedence; 218 219 if (m_rightValueExpr == DE_NULL) 220 { 221 state.pushPrecedence(rightPrec); 222 m_rightValueExpr = Expression::createRandom(state, m_rightValueRange.asAccess()); 223 state.popPrecedence(); 224 return m_rightValueExpr; 225 } 226 else if (m_leftValueExpr == DE_NULL) 227 { 228 state.pushPrecedence(leftPrec); 229 m_leftValueExpr = Expression::createRandom(state, m_leftValueRange.asAccess()); 230 state.popPrecedence(); 231 return m_leftValueExpr; 232 } 233 else 234 { 235 // Check for corrner cases 236 switch (m_operator) 237 { 238 case Token::CMP_LE: 239 { 240 // When comparing two floats epsilon should be included 241 // to eliminate the risk that we get different results 242 // because of precission error 243 VariableType floatType(VariableType::TYPE_FLOAT, 1); 244 if (m_rightValueRange.getType() == floatType) 245 { 246 FloatLiteral* epsilonLiteral = new FloatLiteral(0.001f); 247 248 typedef CustomBinaryOp<EvaluateAdd> CustomAddOp; 249 CustomAddOp* addOperation = new CustomAddOp(); 250 addOperation->setLeftValue(m_rightValueExpr); 251 addOperation->setRightValue(epsilonLiteral); 252 253 // add epsilon to right-hand side 254 m_rightValueExpr = addOperation; 255 } 256 break; 257 } 258 case Token::CMP_GE: 259 { 260 // When comparing two floats epsilon should be included 261 // to eliminate the risk that we get different results 262 // because of precission error 263 VariableType floatType(VariableType::TYPE_FLOAT, 1); 264 if (m_leftValueRange.getType() == floatType) 265 { 266 FloatLiteral* epsilonLiteral = new FloatLiteral(0.001f); 267 268 typedef CustomBinaryOp<EvaluateAdd> CustomAddOp; 269 CustomAddOp* addOperation = new CustomAddOp(); 270 addOperation->setLeftValue(m_leftValueExpr); 271 addOperation->setRightValue(epsilonLiteral); 272 273 // add epsilon to left-hand side 274 m_leftValueExpr = addOperation; 275 } 276 break; 277 } 278 case Token::CMP_EQ: 279 { 280 // When comparing two floats epsilon should be included 281 // to eliminate the risk that we get different results 282 // because of precission error 283 VariableType floatType(VariableType::TYPE_FLOAT, 1); 284 if (m_leftValueRange.getType() == floatType) 285 { 286 VariableType boolType(VariableType::TYPE_BOOL, 1); 287 const ValueRange boolRange(boolType); 288 289 ParenOp* parenRight = new ParenOp(state, boolRange); 290 parenRight->setChild(m_rightValueExpr); 291 292 typedef CustomBinaryOp<EvaluateSub> CustomSubOp; 293 CustomSubOp* subOperation = new CustomSubOp(); 294 subOperation->setLeftValue(m_leftValueExpr); 295 subOperation->setRightValue(parenRight); 296 297 CustomAbsOp* absOperation = new CustomAbsOp(); 298 absOperation->setChild(subOperation); 299 FloatLiteral* epsilonLiteral = new FloatLiteral(0.001f); 300 301 typedef CustomBinaryOp<EvaluateLessThan> CustomLessThanOp; 302 CustomLessThanOp* lessOperation = new CustomLessThanOp(); 303 lessOperation->setLeftValue(absOperation); 304 lessOperation->setRightValue(epsilonLiteral); 305 306 ParenOp* parenOperation = new ParenOp(state, boolRange); 307 parenOperation->setChild(lessOperation); 308 BoolLiteral* trueLiteral = new BoolLiteral(true); 309 310 // EQ operation cant be removed so it is replaced with: 311 // ((abs(lhs-rhs) < epsilon) == true). 312 m_leftValueExpr = parenOperation; 313 m_rightValueExpr = trueLiteral; 314 } 315 break; 316 } 317 default: 318 break; 319 } 320 321 return DE_NULL; 322 } 323 } 324 325 template <int Precedence, Associativity Assoc> 326 float BinaryOp<Precedence, Assoc>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 327 { 328 if (state.getPrecedence() < Precedence) 329 return 0.0f; 330 331 int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth(); 332 333 if (valueRange.getType().isVoid()) 334 return availableLevels >= 2 ? unusedValueWeight : 0.0f; 335 336 if (availableLevels < getConservativeValueExprDepth(state, valueRange) + 1) 337 return 0.0f; 338 339 return 1.0f; 340 } 341 342 template <int Precedence, Associativity Assoc> 343 void BinaryOp<Precedence, Assoc>::tokenize (GeneratorState& state, TokenStream& str) const 344 { 345 m_leftValueExpr->tokenize(state, str); 346 str << m_operator; 347 m_rightValueExpr->tokenize(state, str); 348 } 349 350 template <int Precedence, Associativity Assoc> 351 void BinaryOp<Precedence, Assoc>::evaluate (ExecutionContext& execCtx) 352 { 353 m_leftValueExpr->evaluate(execCtx); 354 m_rightValueExpr->evaluate(execCtx); 355 356 ExecConstValueAccess leftVal = m_leftValueExpr->getValue(); 357 ExecConstValueAccess rightVal = m_rightValueExpr->getValue(); 358 ExecValueAccess dst = m_value.getValue(m_type); 359 360 evaluate(dst, leftVal, rightVal); 361 } 362 363 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp> 364 BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::BinaryVecOp (GeneratorState& state, Token::Type operatorToken, ConstValueRangeAccess inValueRange) 365 : BinaryOp<Precedence, ASSOCIATIVITY_LEFT>(operatorToken) 366 { 367 ValueRange valueRange = inValueRange; 368 369 if (valueRange.getType().isVoid()) 370 { 371 int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth(); 372 vector<VariableType::Type> baseTypes; 373 374 if (Float) baseTypes.push_back(VariableType::TYPE_FLOAT); 375 if (Int) baseTypes.push_back(VariableType::TYPE_INT); 376 if (Bool) baseTypes.push_back(VariableType::TYPE_BOOL); 377 378 VariableType::Type baseType = state.getRandom().choose<VariableType::Type>(baseTypes.begin(), baseTypes.end()); 379 int numElements = state.getRandom().getInt(1, availableLevels >= 3 ? 4 : 1); 380 381 valueRange = ValueRange(VariableType(baseType, numElements)); 382 computeRandomValueRange(state, valueRange.asAccess()); 383 } 384 385 // Choose type, allocate storage for execution 386 this->m_type = valueRange.getType(); 387 this->m_value.setStorage(this->m_type); 388 389 // Initialize storage for value ranges 390 this->m_rightValueRange = ValueRange(this->m_type); 391 this->m_leftValueRange = ValueRange(this->m_type); 392 393 VariableType::Type baseType = this->m_type.getBaseType(); 394 395 // Compute range for b that satisfies requested value range 396 for (int elemNdx = 0; elemNdx < this->m_type.getNumElements(); elemNdx++) 397 { 398 ConstValueRangeAccess dst = valueRange.asAccess().component(elemNdx); 399 ValueRangeAccess a = this->m_leftValueRange.asAccess().component(elemNdx); // \todo [2011-03-25 pyry] Commutative: randomize inputs 400 ValueRangeAccess b = this->m_rightValueRange.asAccess().component(elemNdx); 401 402 // Just pass undefined ranges 403 if ((baseType == VariableType::TYPE_FLOAT || baseType == VariableType::TYPE_INT) && isUndefinedValueRange(dst)) 404 { 405 a.getMin() = dst.getMin().value(); 406 b.getMin() = dst.getMin().value(); 407 a.getMax() = dst.getMax().value(); 408 b.getMax() = dst.getMax().value(); 409 continue; 410 } 411 412 if (baseType == VariableType::TYPE_FLOAT) 413 ComputeValueRange()(state.getRandom(), dst.getMin().asFloat(), dst.getMax().asFloat(), 414 a.getMin().asFloat(), a.getMax().asFloat(), 415 b.getMin().asFloat(), b.getMax().asFloat()); 416 else if (baseType == VariableType::TYPE_INT) 417 ComputeValueRange()(state.getRandom(), dst.getMin().asInt(), dst.getMax().asInt(), 418 a.getMin().asInt(), a.getMax().asInt(), 419 b.getMin().asInt(), b.getMax().asInt()); 420 else 421 { 422 DE_ASSERT(baseType == VariableType::TYPE_BOOL); 423 ComputeValueRange()(state.getRandom(), dst.getMin().asBool(), dst.getMax().asBool(), 424 a.getMin().asBool(), a.getMax().asBool(), 425 b.getMin().asBool(), b.getMax().asBool()); 426 } 427 } 428 } 429 430 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp> 431 BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::~BinaryVecOp (void) 432 { 433 } 434 435 template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp> 436 void BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b) 437 { 438 DE_ASSERT(dst.getType() == a.getType()); 439 DE_ASSERT(dst.getType() == b.getType()); 440 switch (dst.getType().getBaseType()) 441 { 442 case VariableType::TYPE_FLOAT: 443 for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++) 444 { 445 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) 446 dst.component(elemNdx).asFloat(compNdx) = EvaluateComp()(a.component(elemNdx).asFloat(compNdx), b.component(elemNdx).asFloat(compNdx)); 447 } 448 break; 449 450 case VariableType::TYPE_INT: 451 for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++) 452 { 453 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) 454 dst.component(elemNdx).asInt(compNdx) = EvaluateComp()(a.component(elemNdx).asInt(compNdx), b.component(elemNdx).asInt(compNdx)); 455 } 456 break; 457 458 default: 459 DE_ASSERT(DE_FALSE); // Invalid type for multiplication 460 } 461 } 462 463 void ComputeMulRange::operator() (de::Random& rnd, float dstMin, float dstMax, float& aMin, float& aMax, float& bMin, float& bMax) const 464 { 465 const float minScale = 0.25f; 466 const float maxScale = 2.0f; 467 const float subRangeStep = 0.25f; 468 const float scaleStep = 0.25f; 469 470 float scale = getQuantizedFloat(rnd, minScale, maxScale, scaleStep); 471 float scaledMin = dstMin/scale; 472 float scaledMax = dstMax/scale; 473 474 // Quantize scaled value range if possible 475 if (!quantizeFloatRange(scaledMin, scaledMax)) 476 { 477 // Fall back to 1.0 as a scale 478 scale = 1.0f; 479 scaledMin = dstMin; 480 scaledMax = dstMax; 481 } 482 483 float subRangeLen = getQuantizedFloat(rnd, 0.0f, scaledMax-scaledMin, subRangeStep); 484 aMin = scaledMin + getQuantizedFloat(rnd, 0.0f, (scaledMax-scaledMin)-subRangeLen, subRangeStep); 485 aMax = aMin + subRangeLen; 486 487 // Find scale range 488 bMin = scale; 489 bMax = scale; 490 for (int i = 0; i < 5; i++) 491 { 492 if (de::inBounds(aMin*(scale-(float)i*scaleStep), dstMin, dstMax) && 493 de::inBounds(aMax*(scale-(float)i*scaleStep), dstMin, dstMax)) 494 bMin = scale-(float)i*scaleStep; 495 496 if (de::inBounds(aMin*(scale+(float)i*scaleStep), dstMin, dstMax) && 497 de::inBounds(aMax*(scale+(float)i*scaleStep), dstMin, dstMax)) 498 bMax = scale+(float)i*scaleStep; 499 } 500 501 // Negative scale? 502 if (rnd.getBool()) 503 { 504 std::swap(aMin, aMax); 505 std::swap(bMin, bMax); 506 aMin *= -1.0f; 507 aMax *= -1.0f; 508 bMin *= -1.0f; 509 bMax *= -1.0f; 510 } 511 512 #if defined(DE_DEBUG) 513 const float eps = 0.001f; 514 DE_ASSERT(aMin <= aMax && bMin <= bMax); 515 DE_ASSERT(de::inRange(aMin*bMin, dstMin-eps, dstMax+eps)); 516 DE_ASSERT(de::inRange(aMin*bMax, dstMin-eps, dstMax+eps)); 517 DE_ASSERT(de::inRange(aMax*bMin, dstMin-eps, dstMax+eps)); 518 DE_ASSERT(de::inRange(aMax*bMax, dstMin-eps, dstMax+eps)); 519 #endif 520 } 521 522 void ComputeMulRange::operator() (de::Random& rnd, int dstMin, int dstMax, int& aMin, int& aMax, int& bMin, int& bMax) const 523 { 524 DE_UNREF(rnd); 525 aMin = dstMin; 526 aMax = dstMax; 527 bMin = 1; 528 bMax = 1; 529 } 530 531 MulOp::MulOp (GeneratorState& state, ConstValueRangeAccess valueRange) 532 : MulBase(state, Token::MUL, valueRange) 533 { 534 } 535 536 float MulOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 537 { 538 if (valueRange.getType().isVoid() || 539 valueRange.getType().isFloatOrVec() || 540 valueRange.getType().isIntOrVec()) 541 return MulBase::getWeight(state, valueRange); 542 else 543 return 0.0f; 544 } 545 546 template <typename T> 547 void ComputeAddRange::operator() (de::Random& random, T dstMin, T dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const 548 { 549 struct GetRandom 550 { 551 int operator() (de::Random& rnd, int min, int max) const { return rnd.getInt(min, max); } 552 float operator() (de::Random& rnd, float min, float max) const { return getQuantizedFloat(rnd, min, max, 0.5f); } 553 }; 554 555 T rangeLen = dstMax-dstMin; 556 T subRangeLen = GetRandom()(random, T(0), rangeLen); 557 T aOffset = GetRandom()(random, T(-8), T(8)); 558 559 aMin = dstMin+aOffset; 560 aMax = aMin+subRangeLen; 561 562 bMin = -aOffset; 563 bMax = -aOffset+(rangeLen-subRangeLen); 564 565 #if defined(DE_DEBUG) 566 T eps = T(0.001); 567 DE_ASSERT(aMin <= aMax && bMin <= bMax); 568 DE_ASSERT(de::inRange(aMin+bMin, dstMin-eps, dstMax+eps)); 569 DE_ASSERT(de::inRange(aMin+bMax, dstMin-eps, dstMax+eps)); 570 DE_ASSERT(de::inRange(aMax+bMin, dstMin-eps, dstMax+eps)); 571 DE_ASSERT(de::inRange(aMax+bMax, dstMin-eps, dstMax+eps)); 572 #endif 573 } 574 575 template <> 576 void ComputeAddRange::operator()<bool> (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const 577 { 578 DE_ASSERT(DE_FALSE); 579 } 580 581 AddOp::AddOp (GeneratorState& state, ConstValueRangeAccess valueRange) 582 : AddBase(state, Token::PLUS, valueRange) 583 { 584 } 585 586 float AddOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 587 { 588 if (valueRange.getType().isVoid() || 589 valueRange.getType().isFloatOrVec() || 590 valueRange.getType().isIntOrVec()) 591 return AddBase::getWeight(state, valueRange); 592 else 593 return 0.0f; 594 } 595 596 template <typename T> 597 void ComputeSubRange::operator() (de::Random& random, T dstMin, T dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const 598 { 599 struct GetRandom 600 { 601 int operator() (de::Random& rnd, int min, int max) const { return rnd.getInt(min, max); } 602 float operator() (de::Random& rnd, float min, float max) const { return getQuantizedFloat(rnd, min, max, 0.5f); } 603 }; 604 605 T rangeLen = dstMax-dstMin; 606 T subRangeLen = GetRandom()(random, T(0), rangeLen); 607 T aOffset = GetRandom()(random, T(-8), T(8)); 608 609 aMin = dstMin+aOffset; 610 aMax = aMin+subRangeLen; 611 612 bMin = aOffset-(rangeLen-subRangeLen); 613 bMax = aOffset; 614 615 #if defined(DE_DEBUG) 616 T eps = T(0.001); 617 DE_ASSERT(aMin <= aMax && bMin <= bMax); 618 DE_ASSERT(de::inRange(aMin-bMin, dstMin-eps, dstMax+eps)); 619 DE_ASSERT(de::inRange(aMin-bMax, dstMin-eps, dstMax+eps)); 620 DE_ASSERT(de::inRange(aMax-bMin, dstMin-eps, dstMax+eps)); 621 DE_ASSERT(de::inRange(aMax-bMax, dstMin-eps, dstMax+eps)); 622 #endif 623 } 624 625 template <> 626 void ComputeSubRange::operator()<bool> (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const 627 { 628 DE_ASSERT(DE_FALSE); 629 } 630 631 SubOp::SubOp (GeneratorState& state, ConstValueRangeAccess valueRange) 632 : SubBase(state, Token::MINUS, valueRange) 633 { 634 } 635 636 float SubOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 637 { 638 if (valueRange.getType().isVoid() || 639 valueRange.getType().isFloatOrVec() || 640 valueRange.getType().isIntOrVec()) 641 return SubBase::getWeight(state, valueRange); 642 else 643 return 0.0f; 644 } 645 646 template <class ComputeValueRange, class EvaluateComp> 647 RelationalOp<ComputeValueRange, EvaluateComp>::RelationalOp (GeneratorState& state, Token::Type operatorToken, ConstValueRangeAccess inValueRange) 648 : BinaryOp<7, ASSOCIATIVITY_LEFT>(operatorToken) 649 { 650 ValueRange valueRange = inValueRange; 651 652 if (valueRange.getType().isVoid()) 653 { 654 valueRange = ValueRange(VariableType(VariableType::TYPE_BOOL, 1)); 655 computeRandomValueRange(state, valueRange.asAccess()); 656 } 657 658 // Choose type, allocate storage for execution 659 this->m_type = valueRange.getType(); 660 this->m_value.setStorage(this->m_type); 661 662 // Choose random input type 663 VariableType::Type inBaseTypes[] = { VariableType::TYPE_FLOAT, VariableType::TYPE_INT }; 664 VariableType::Type inBaseType = state.getRandom().choose<VariableType::Type>(&inBaseTypes[0], &inBaseTypes[DE_LENGTH_OF_ARRAY(inBaseTypes)]); 665 666 // Initialize storage for input value ranges 667 this->m_rightValueRange = ValueRange(VariableType(inBaseType, 1)); 668 this->m_leftValueRange = ValueRange(VariableType(inBaseType, 1)); 669 670 // Compute range for b that satisfies requested value range 671 { 672 bool dstMin = valueRange.getMin().asBool(); 673 bool dstMax = valueRange.getMax().asBool(); 674 ValueRangeAccess a = this->m_leftValueRange.asAccess(); 675 ValueRangeAccess b = this->m_rightValueRange.asAccess(); 676 677 if (inBaseType == VariableType::TYPE_FLOAT) 678 ComputeValueRange()(state.getRandom(), dstMin, dstMax, 679 a.getMin().asFloat(), a.getMax().asFloat(), 680 b.getMin().asFloat(), b.getMax().asFloat()); 681 else if (inBaseType == VariableType::TYPE_INT) 682 ComputeValueRange()(state.getRandom(), dstMin, dstMax, 683 a.getMin().asInt(), a.getMax().asInt(), 684 b.getMin().asInt(), b.getMax().asInt()); 685 } 686 } 687 688 template <class ComputeValueRange, class EvaluateComp> 689 RelationalOp<ComputeValueRange, EvaluateComp>::~RelationalOp (void) 690 { 691 } 692 693 template <class ComputeValueRange, class EvaluateComp> 694 void RelationalOp<ComputeValueRange, EvaluateComp>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b) 695 { 696 DE_ASSERT(a.getType() == b.getType()); 697 switch (a.getType().getBaseType()) 698 { 699 case VariableType::TYPE_FLOAT: 700 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) 701 dst.asBool(compNdx) = EvaluateComp()(a.asFloat(compNdx), b.asFloat(compNdx)); 702 break; 703 704 case VariableType::TYPE_INT: 705 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) 706 dst.asBool(compNdx) = EvaluateComp()(a.asInt(compNdx), b.asInt(compNdx)); 707 break; 708 709 default: 710 DE_ASSERT(DE_FALSE); 711 } 712 } 713 714 template <class ComputeValueRange, class EvaluateComp> 715 float RelationalOp<ComputeValueRange, EvaluateComp>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 716 { 717 if (!state.getProgramParameters().useComparisonOps) 718 return 0.0f; 719 720 if (valueRange.getType().isVoid() || 721 (valueRange.getType().getBaseType() == VariableType::TYPE_BOOL && valueRange.getType().getNumElements() == 1)) 722 return BinaryOp<7, ASSOCIATIVITY_LEFT>::getWeight(state, valueRange); 723 else 724 return 0.0f; 725 } 726 727 namespace 728 { 729 730 template <typename T> T getStep (void); 731 template <> inline float getStep (void) { return 0.25f; } 732 template <> inline int getStep (void) { return 1; } 733 734 } // anonymous 735 736 template <typename T> 737 void ComputeLessThanRange::operator () (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const 738 { 739 struct GetRandom 740 { 741 int operator() (de::Random& random, int min, int max) const { return random.getInt(min, max); } 742 float operator() (de::Random& random, float min, float max) const { return getQuantizedFloat(random, min, max, getStep<float>()); } 743 }; 744 745 // One random range 746 T rLen = GetRandom()(rnd, T(0), T(8)); 747 T rMin = GetRandom()(rnd, T(-4), T(4)); 748 T rMax = rMin+rLen; 749 750 if (dstMin == false && dstMax == true) 751 { 752 // Both values are possible, use same range for both inputs 753 aMin = rMin; 754 aMax = rMax; 755 bMin = rMin; 756 bMax = rMax; 757 } 758 else if (dstMin == true && dstMax == true) 759 { 760 // Compute range that is less than rMin..rMax 761 T aLen = GetRandom()(rnd, T(0), T(8)-rLen); 762 763 aMax = rMin - getStep<T>(); 764 aMin = aMax - aLen; 765 766 bMin = rMin; 767 bMax = rMax; 768 } 769 else 770 { 771 // Compute range that is greater than or equal to rMin..rMax 772 T aLen = GetRandom()(rnd, T(0), T(8)-rLen); 773 774 aMin = rMax; 775 aMax = aMin + aLen; 776 777 bMin = rMin; 778 bMax = rMax; 779 } 780 } 781 782 LessThanOp::LessThanOp (GeneratorState& state, ConstValueRangeAccess valueRange) 783 : LessThanBase(state, Token::CMP_LT, valueRange) 784 { 785 } 786 787 float LessThanOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 788 { 789 return LessThanBase::getWeight(state, valueRange); 790 } 791 792 template <typename T> 793 void ComputeLessOrEqualRange::operator () (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const 794 { 795 struct GetRandom 796 { 797 int operator() (de::Random& random, int min, int max) const { return random.getInt(min, max); } 798 float operator() (de::Random& random, float min, float max) const { return getQuantizedFloat(random, min, max, getStep<float>()); } 799 }; 800 801 // One random range 802 T rLen = GetRandom()(rnd, T(0), T(8)); 803 T rMin = GetRandom()(rnd, T(-4), T(4)); 804 T rMax = rMin+rLen; 805 806 if (dstMin == false && dstMax == true) 807 { 808 // Both values are possible, use same range for both inputs 809 aMin = rMin; 810 aMax = rMax; 811 bMin = rMin; 812 bMax = rMax; 813 } 814 else if (dstMin == true && dstMax == true) 815 { 816 // Compute range that is less than or equal to rMin..rMax 817 T aLen = GetRandom()(rnd, T(0), T(8)-rLen); 818 819 aMax = rMin; 820 aMin = aMax - aLen; 821 822 bMin = rMin; 823 bMax = rMax; 824 } 825 else 826 { 827 // Compute range that is greater than rMin..rMax 828 T aLen = GetRandom()(rnd, T(0), T(8)-rLen); 829 830 aMin = rMax + getStep<T>(); 831 aMax = aMin + aLen; 832 833 bMin = rMin; 834 bMax = rMax; 835 } 836 } 837 838 LessOrEqualOp::LessOrEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange) 839 : LessOrEqualBase(state, Token::CMP_LE, valueRange) 840 { 841 } 842 843 float LessOrEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 844 { 845 return LessOrEqualBase::getWeight(state, valueRange); 846 } 847 848 GreaterThanOp::GreaterThanOp (GeneratorState& state, ConstValueRangeAccess valueRange) 849 : GreaterThanBase(state, Token::CMP_GT, valueRange) 850 { 851 } 852 853 float GreaterThanOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 854 { 855 return GreaterThanBase::getWeight(state, valueRange); 856 } 857 858 GreaterOrEqualOp::GreaterOrEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange) 859 : GreaterOrEqualBase(state, Token::CMP_GE, valueRange) 860 { 861 } 862 863 float GreaterOrEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 864 { 865 return GreaterOrEqualBase::getWeight(state, valueRange); 866 } 867 868 namespace 869 { 870 871 template <bool IsEqual, typename T> 872 void computeEqualityValueRange (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) 873 { 874 if (dstMin == false && dstMax == true) 875 ComputeLessThanRange()(rnd, false, true, aMin, aMax, bMin, bMax); 876 else if (IsEqual && dstMin == false) 877 ComputeLessThanRange()(rnd, true, true, aMin, aMax, bMin, bMax); 878 else if (!IsEqual && dstMin == true) 879 ComputeLessThanRange()(rnd, true, true, aMin, aMax, bMin, bMax); 880 else 881 { 882 // Must have exactly same values. 883 struct GetRandom 884 { 885 int operator() (de::Random& random, int min, int max) const { return random.getInt(min, max); } 886 float operator() (de::Random& random, float min, float max) const { return getQuantizedFloat(random, min, max, 0.5f); } 887 }; 888 889 T val = GetRandom()(rnd, T(-1), T(1)); 890 891 aMin = val; 892 aMax = val; 893 bMin = val; 894 bMax = val; 895 } 896 } 897 898 template <> 899 void computeEqualityValueRange<true, bool> (de::Random& rnd, bool dstMin, bool dstMax, bool& aMin, bool& aMax, bool& bMin, bool& bMax) 900 { 901 if (dstMin == false && dstMax == true) 902 { 903 aMin = false; 904 aMax = true; 905 bMin = false; 906 bMax = true; 907 } 908 else if (dstMin == false) 909 { 910 DE_ASSERT(dstMax == false); 911 bool val = rnd.getBool(); 912 913 aMin = val; 914 aMax = val; 915 bMin = !val; 916 bMax = !val; 917 } 918 else 919 { 920 DE_ASSERT(dstMin == true && dstMax == true); 921 bool val = rnd.getBool(); 922 923 aMin = val; 924 aMax = val; 925 bMin = val; 926 bMax = val; 927 } 928 } 929 930 template <> 931 void computeEqualityValueRange<false, bool> (de::Random& rnd, bool dstMin, bool dstMax, bool& aMin, bool& aMax, bool& bMin, bool& bMax) 932 { 933 if (dstMin == false && dstMax == true) 934 computeEqualityValueRange<true>(rnd, dstMin, dstMax, aMin, aMax, bMin, bMax); 935 else 936 computeEqualityValueRange<true>(rnd, !dstMin, !dstMax, aMin, aMax, bMin, bMax); 937 } 938 939 } // anonymous 940 941 template <bool IsEqual> 942 EqualityComparisonOp<IsEqual>::EqualityComparisonOp (GeneratorState& state, ConstValueRangeAccess inValueRange) 943 : BinaryOp<8, ASSOCIATIVITY_LEFT>(IsEqual ? Token::CMP_EQ : Token::CMP_NE) 944 { 945 ValueRange valueRange = inValueRange; 946 947 if (valueRange.getType().isVoid()) 948 { 949 valueRange = ValueRange(VariableType(VariableType::TYPE_BOOL, 1)); 950 computeRandomValueRange(state, valueRange.asAccess()); 951 } 952 953 // Choose type, allocate storage for execution 954 this->m_type = valueRange.getType(); 955 this->m_value.setStorage(this->m_type); 956 957 // Choose random input type 958 VariableType::Type inBaseTypes[] = { VariableType::TYPE_FLOAT, VariableType::TYPE_INT }; 959 VariableType::Type inBaseType = state.getRandom().choose<VariableType::Type>(&inBaseTypes[0], &inBaseTypes[DE_LENGTH_OF_ARRAY(inBaseTypes)]); 960 int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth(); 961 int numElements = state.getRandom().getInt(1, availableLevels >= 3 ? 4 : 1); 962 963 // Initialize storage for input value ranges 964 this->m_rightValueRange = ValueRange(VariableType(inBaseType, numElements)); 965 this->m_leftValueRange = ValueRange(VariableType(inBaseType, numElements)); 966 967 // Compute range for b that satisfies requested value range 968 for (int elementNdx = 0; elementNdx < numElements; elementNdx++) 969 { 970 bool dstMin = valueRange.getMin().asBool(); 971 bool dstMax = valueRange.getMax().asBool(); 972 973 ValueRangeAccess a = this->m_leftValueRange.asAccess().component(elementNdx); 974 ValueRangeAccess b = this->m_rightValueRange.asAccess().component(elementNdx); 975 976 if (inBaseType == VariableType::TYPE_FLOAT) 977 computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax, 978 a.getMin().asFloat(), a.getMax().asFloat(), 979 b.getMin().asFloat(), b.getMax().asFloat()); 980 else if (inBaseType == VariableType::TYPE_INT) 981 computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax, 982 a.getMin().asInt(), a.getMax().asInt(), 983 b.getMin().asInt(), b.getMax().asInt()); 984 else 985 { 986 DE_ASSERT(inBaseType == VariableType::TYPE_BOOL); 987 computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax, 988 a.getMin().asBool(), a.getMax().asBool(), 989 b.getMin().asBool(), b.getMax().asBool()); 990 } 991 } 992 } 993 994 template <bool IsEqual> 995 float EqualityComparisonOp<IsEqual>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 996 { 997 if (!state.getProgramParameters().useComparisonOps) 998 return 0.0f; 999 1000 // \todo [2011-06-13 pyry] Weight down cases that would force constant inputs. 1001 1002 if (valueRange.getType().isVoid() || 1003 (valueRange.getType().getBaseType() == VariableType::TYPE_BOOL && valueRange.getType().getNumElements() == 1)) 1004 return BinaryOp<8, ASSOCIATIVITY_LEFT>::getWeight(state, valueRange); 1005 else 1006 return 0.0f; 1007 } 1008 1009 namespace 1010 { 1011 1012 template <bool IsEqual> 1013 struct EqualityCompare 1014 { 1015 template <typename T> 1016 static bool compare (T a, T b); 1017 static bool combine (bool a, bool b); 1018 }; 1019 1020 template <> 1021 template <typename T> 1022 inline bool EqualityCompare<true>::compare (T a, T b) { return a == b; } 1023 1024 template <> 1025 inline bool EqualityCompare<true>::combine (bool a, bool b) { return a && b; } 1026 1027 template <> 1028 template <typename T> 1029 inline bool EqualityCompare<false>::compare (T a, T b) { return a != b; } 1030 1031 template <> 1032 inline bool EqualityCompare<false>::combine (bool a, bool b) { return a || b; } 1033 1034 } // anonymous 1035 1036 template <bool IsEqual> 1037 void EqualityComparisonOp<IsEqual>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b) 1038 { 1039 DE_ASSERT(a.getType() == b.getType()); 1040 1041 1042 switch (a.getType().getBaseType()) 1043 { 1044 case VariableType::TYPE_FLOAT: 1045 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) 1046 { 1047 bool result = IsEqual ? true : false; 1048 1049 for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++) 1050 result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asFloat(compNdx), b.component(elemNdx).asFloat(compNdx))); 1051 1052 dst.asBool(compNdx) = result; 1053 } 1054 break; 1055 1056 case VariableType::TYPE_INT: 1057 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) 1058 { 1059 bool result = IsEqual ? true : false; 1060 1061 for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++) 1062 result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asInt(compNdx), b.component(elemNdx).asInt(compNdx))); 1063 1064 dst.asBool(compNdx) = result; 1065 } 1066 break; 1067 1068 case VariableType::TYPE_BOOL: 1069 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) 1070 { 1071 bool result = IsEqual ? true : false; 1072 1073 for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++) 1074 result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asBool(compNdx), b.component(elemNdx).asBool(compNdx))); 1075 1076 dst.asBool(compNdx) = result; 1077 } 1078 break; 1079 1080 default: 1081 DE_ASSERT(DE_FALSE); 1082 } 1083 } 1084 1085 EqualOp::EqualOp (GeneratorState& state, ConstValueRangeAccess valueRange) 1086 : EqualityComparisonOp<true>(state, valueRange) 1087 { 1088 } 1089 1090 float EqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 1091 { 1092 return EqualityComparisonOp<true>::getWeight(state, valueRange); 1093 } 1094 1095 NotEqualOp::NotEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange) 1096 : EqualityComparisonOp<false>(state, valueRange) 1097 { 1098 } 1099 1100 float NotEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 1101 { 1102 return EqualityComparisonOp<false>::getWeight(state, valueRange); 1103 } 1104 1105 } // rsg 1106