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 Expressions. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "rsgExpression.hpp" 25 #include "rsgVariableManager.hpp" 26 #include "rsgBinaryOps.hpp" 27 #include "rsgBuiltinFunctions.hpp" 28 #include "rsgUtils.hpp" 29 #include "deMath.h" 30 31 using std::vector; 32 33 namespace rsg 34 { 35 36 namespace 37 { 38 39 class IsReadableEntry 40 { 41 public: 42 typedef ValueEntryIterator<IsReadableEntry> Iterator; 43 44 IsReadableEntry (deUint32 exprFlags) 45 : m_exprFlags(exprFlags) 46 { 47 } 48 49 bool operator() (const ValueEntry* entry) const 50 { 51 if ((m_exprFlags & CONST_EXPR) && (entry->getVariable()->getStorage() != Variable::STORAGE_CONST)) 52 return false; 53 54 return true; 55 } 56 57 private: 58 deUint32 m_exprFlags; 59 }; 60 61 class IsReadableIntersectingEntry : public IsReadableEntry 62 { 63 public: 64 typedef ValueEntryIterator<IsReadableIntersectingEntry> Iterator; 65 66 IsReadableIntersectingEntry (ConstValueRangeAccess valueRange, deUint32 exprFlags) 67 : IsReadableEntry (exprFlags) 68 , m_valueRange (valueRange) 69 { 70 } 71 72 bool operator() (const ValueEntry* entry) const 73 { 74 if (!IsReadableEntry::operator()(entry)) 75 return false; 76 77 if (entry->getValueRange().getType() != m_valueRange.getType()) 78 return false; 79 80 if (!entry->getValueRange().intersects(m_valueRange)) 81 return false; 82 83 return true; 84 } 85 86 private: 87 ConstValueRangeAccess m_valueRange; 88 }; 89 90 class IsWritableIntersectingEntry : public IsWritableEntry 91 { 92 public: 93 typedef ValueEntryIterator<IsWritableIntersectingEntry> Iterator; 94 95 IsWritableIntersectingEntry (ConstValueRangeAccess valueRange) 96 : m_valueRange(valueRange) 97 { 98 } 99 100 bool operator() (const ValueEntry* entry) const 101 { 102 return IsWritableEntry::operator()(entry) && 103 entry->getVariable()->getType() == m_valueRange.getType() && 104 entry->getValueRange().intersects(m_valueRange); 105 } 106 107 private: 108 ConstValueRangeAccess m_valueRange; 109 }; 110 111 class IsWritableSupersetEntry : public IsWritableEntry 112 { 113 public: 114 typedef ValueEntryIterator<IsWritableSupersetEntry> Iterator; 115 116 IsWritableSupersetEntry (ConstValueRangeAccess valueRange) 117 : m_valueRange(valueRange) 118 { 119 } 120 121 bool operator() (const ValueEntry* entry) const 122 { 123 return IsWritableEntry()(entry) && 124 entry->getVariable()->getType() == m_valueRange.getType() && 125 entry->getValueRange().isSupersetOf(m_valueRange); 126 } 127 128 private: 129 ConstValueRangeAccess m_valueRange; 130 }; 131 132 class IsSamplerEntry 133 { 134 public: 135 typedef ValueEntryIterator<IsSamplerEntry> Iterator; 136 137 IsSamplerEntry (VariableType::Type type) 138 : m_type(type) 139 { 140 DE_ASSERT(m_type == VariableType::TYPE_SAMPLER_2D || m_type == VariableType::TYPE_SAMPLER_CUBE); 141 } 142 143 bool operator() (const ValueEntry* entry) const 144 { 145 if (entry->getVariable()->getType() == VariableType(m_type, 1)) 146 { 147 DE_ASSERT(entry->getVariable()->getStorage() == Variable::STORAGE_UNIFORM); 148 return true; 149 } 150 else 151 return false; 152 } 153 154 private: 155 VariableType::Type m_type; 156 }; 157 158 inline bool getWeightedBool (de::Random& random, float trueWeight) 159 { 160 DE_ASSERT(de::inRange<float>(trueWeight, 0.0f, 1.0f)); 161 return (random.getFloat() < trueWeight); 162 } 163 164 void computeRandomValueRangeForInfElements (GeneratorState& state, ValueRangeAccess valueRange) 165 { 166 const VariableType& type = valueRange.getType(); 167 de::Random& rnd = state.getRandom(); 168 169 switch (type.getBaseType()) 170 { 171 case VariableType::TYPE_BOOL: 172 // No need to handle bool as it will be false, true 173 break; 174 175 case VariableType::TYPE_INT: 176 for (int ndx = 0; ndx < type.getNumElements(); ndx++) 177 { 178 if (valueRange.getMin().component(ndx).asScalar() != Scalar::min<int>() || 179 valueRange.getMax().component(ndx).asScalar() != Scalar::max<int>()) 180 continue; 181 182 const int minIntVal = -16; 183 const int maxIntVal = 16; 184 const int maxRangeLen = maxIntVal - minIntVal; 185 186 int rangeLen = rnd.getInt(0, maxRangeLen); 187 int minVal = minIntVal + rnd.getInt(0, maxRangeLen-rangeLen); 188 int maxVal = minVal + rangeLen; 189 190 valueRange.getMin().component(ndx).asInt() = minVal; 191 valueRange.getMax().component(ndx).asInt() = maxVal; 192 } 193 break; 194 195 case VariableType::TYPE_FLOAT: 196 for (int ndx = 0; ndx < type.getNumElements(); ndx++) 197 { 198 if (valueRange.getMin().component(ndx).asScalar() != Scalar::min<float>() || 199 valueRange.getMax().component(ndx).asScalar() != Scalar::max<float>()) 200 continue; 201 202 const float step = 0.1f; 203 const int maxSteps = 320; 204 const float minFloatVal = -16.0f; 205 206 int rangeLen = rnd.getInt(0, maxSteps); 207 int minStep = rnd.getInt(0, maxSteps-rangeLen); 208 209 float minVal = minFloatVal + step*(float)minStep; 210 float maxVal = minVal + step*(float)rangeLen; 211 212 valueRange.getMin().component(ndx).asFloat() = minVal; 213 valueRange.getMax().component(ndx).asFloat() = maxVal; 214 } 215 break; 216 217 default: 218 DE_ASSERT(DE_FALSE); 219 throw Exception("computeRandomValueRangeForInfElements(): unsupported type"); 220 } 221 } 222 223 void setInfiniteRange (ValueRangeAccess valueRange) 224 { 225 const VariableType& type = valueRange.getType(); 226 227 switch (type.getBaseType()) 228 { 229 case VariableType::TYPE_BOOL: 230 for (int ndx = 0; ndx < type.getNumElements(); ndx++) 231 { 232 valueRange.getMin().component(ndx) = Scalar::min<bool>(); 233 valueRange.getMax().component(ndx) = Scalar::max<bool>(); 234 } 235 break; 236 237 case VariableType::TYPE_INT: 238 for (int ndx = 0; ndx < type.getNumElements(); ndx++) 239 { 240 valueRange.getMin().component(ndx) = Scalar::min<int>(); 241 valueRange.getMax().component(ndx) = Scalar::max<int>(); 242 } 243 break; 244 245 case VariableType::TYPE_FLOAT: 246 for (int ndx = 0; ndx < type.getNumElements(); ndx++) 247 { 248 valueRange.getMin().component(ndx) = Scalar::min<float>(); 249 valueRange.getMax().component(ndx) = Scalar::max<float>(); 250 } 251 break; 252 253 default: 254 DE_ASSERT(DE_FALSE); 255 throw Exception("setInfiniteRange(): unsupported type"); 256 } 257 } 258 259 bool canAllocateVariable (const GeneratorState& state, const VariableType& type) 260 { 261 DE_ASSERT(!type.isVoid()); 262 263 if (state.getExpressionFlags() & NO_VAR_ALLOCATION) 264 return false; 265 266 if (state.getVariableManager().getNumAllocatedScalars() + type.getScalarSize() > state.getShaderParameters().maxCombinedVariableScalars) 267 return false; 268 269 return true; 270 } 271 272 template <class T> float getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) { return T::getWeight(state, valueRange); } 273 template <class T> Expression* create (GeneratorState& state, ConstValueRangeAccess valueRange) { return new T(state, valueRange); } 274 275 struct ExpressionSpec 276 { 277 float (*getWeight) (const GeneratorState& state, ConstValueRangeAccess valueRange); 278 Expression* (*create) (GeneratorState& state, ConstValueRangeAccess valueRange); 279 }; 280 281 static const ExpressionSpec s_expressionSpecs[] = 282 { 283 { getWeight<FloatLiteral>, create<FloatLiteral> }, 284 { getWeight<IntLiteral>, create<IntLiteral> }, 285 { getWeight<BoolLiteral>, create<BoolLiteral> }, 286 { getWeight<ConstructorOp>, create<ConstructorOp> }, 287 { getWeight<AssignOp>, create<AssignOp> }, 288 { getWeight<VariableRead>, create<VariableRead> }, 289 { getWeight<MulOp>, create<MulOp> }, 290 { getWeight<AddOp>, create<AddOp> }, 291 { getWeight<SubOp>, create<SubOp> }, 292 { getWeight<LessThanOp>, create<LessThanOp> }, 293 { getWeight<LessOrEqualOp>, create<LessOrEqualOp> }, 294 { getWeight<GreaterThanOp>, create<GreaterThanOp> }, 295 { getWeight<GreaterOrEqualOp>, create<GreaterOrEqualOp> }, 296 { getWeight<EqualOp>, create<EqualOp> }, 297 { getWeight<NotEqualOp>, create<NotEqualOp> }, 298 { getWeight<SwizzleOp>, create<SwizzleOp> }, 299 { getWeight<SinOp>, create<SinOp> }, 300 { getWeight<CosOp>, create<CosOp> }, 301 { getWeight<TanOp>, create<TanOp> }, 302 { getWeight<AsinOp>, create<AsinOp> }, 303 { getWeight<AcosOp>, create<AcosOp> }, 304 { getWeight<AtanOp>, create<AtanOp> }, 305 { getWeight<ExpOp>, create<ExpOp> }, 306 { getWeight<LogOp>, create<LogOp> }, 307 { getWeight<Exp2Op>, create<Exp2Op> }, 308 { getWeight<Log2Op>, create<Log2Op> }, 309 { getWeight<SqrtOp>, create<SqrtOp> }, 310 { getWeight<InvSqrtOp>, create<InvSqrtOp> }, 311 { getWeight<ParenOp>, create<ParenOp> }, 312 { getWeight<TexLookup>, create<TexLookup> } 313 }; 314 315 static const ExpressionSpec s_lvalueSpecs[] = 316 { 317 { getWeight<VariableWrite>, create<VariableWrite> } 318 }; 319 320 #if !defined(DE_MAX) 321 # define DE_MAX(a, b) ((b) > (a) ? (b) : (a)) 322 #endif 323 324 enum 325 { 326 MAX_EXPRESSION_SPECS = (int)DE_MAX(DE_LENGTH_OF_ARRAY(s_expressionSpecs), DE_LENGTH_OF_ARRAY(s_lvalueSpecs)) 327 }; 328 329 const ExpressionSpec* chooseExpression (GeneratorState& state, const ExpressionSpec* specs, int numSpecs, ConstValueRangeAccess valueRange) 330 { 331 float weights[MAX_EXPRESSION_SPECS]; 332 333 DE_ASSERT(numSpecs <= (int)DE_LENGTH_OF_ARRAY(weights)); 334 335 // Compute weights 336 for (int ndx = 0; ndx < numSpecs; ndx++) 337 weights[ndx] = specs[ndx].getWeight(state, valueRange); 338 339 // Choose 340 return &state.getRandom().chooseWeighted<const ExpressionSpec&>(specs, specs+numSpecs, weights); 341 } 342 343 } // anonymous 344 345 Expression::~Expression (void) 346 { 347 } 348 349 Expression* Expression::createRandom (GeneratorState& state, ConstValueRangeAccess valueRange) 350 { 351 return chooseExpression(state, s_expressionSpecs, (int)DE_LENGTH_OF_ARRAY(s_expressionSpecs), valueRange)->create(state, valueRange); 352 } 353 354 Expression* Expression::createRandomLValue (GeneratorState& state, ConstValueRangeAccess valueRange) 355 { 356 return chooseExpression(state, s_lvalueSpecs, (int)DE_LENGTH_OF_ARRAY(s_lvalueSpecs), valueRange)->create(state, valueRange); 357 } 358 359 FloatLiteral::FloatLiteral (GeneratorState& state, ConstValueRangeAccess valueRange) 360 : m_value(VariableType::getScalarType(VariableType::TYPE_FLOAT)) 361 { 362 float minVal = -10.0f; 363 float maxVal = +10.0f; 364 float step = 0.25f; 365 366 if (valueRange.getType() == VariableType(VariableType::TYPE_FLOAT, 1)) 367 { 368 minVal = valueRange.getMin().component(0).asFloat(); 369 maxVal = valueRange.getMax().component(0).asFloat(); 370 371 if (Scalar::min<float>() == minVal) 372 minVal = -10.0f; 373 374 if (Scalar::max<float>() == maxVal) 375 maxVal = +10.0f; 376 } 377 378 int numSteps = (int)((maxVal-minVal)/step) + 1; 379 380 const float value = deFloatClamp(minVal + step*(float)state.getRandom().getInt(0, numSteps), minVal, maxVal); 381 ExecValueAccess access = m_value.getValue(VariableType::getScalarType(VariableType::TYPE_FLOAT)); 382 383 for (int ndx = 0; ndx < EXEC_VEC_WIDTH; ndx++) 384 access.asFloat(ndx) = value; 385 } 386 387 FloatLiteral::FloatLiteral (float customValue) 388 : m_value(VariableType::getScalarType(VariableType::TYPE_FLOAT)) 389 { 390 // This constructor is required to handle corner case in which comparision 391 // of two same floats produced different results - this was resolved by 392 // adding FloatLiteral containing epsilon to one of values 393 ExecValueAccess access = m_value.getValue(VariableType::getScalarType(VariableType::TYPE_FLOAT)); 394 395 for (int ndx = 0; ndx < EXEC_VEC_WIDTH; ndx++) 396 access.asFloat(ndx) = customValue; 397 } 398 399 float FloatLiteral::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 400 { 401 DE_UNREF(state); 402 const VariableType& type = valueRange.getType(); 403 if (type == VariableType(VariableType::TYPE_FLOAT, 1)) 404 { 405 float minVal = valueRange.getMin().asFloat(); 406 float maxVal = valueRange.getMax().asFloat(); 407 408 if (Scalar::min<float>() == minVal && Scalar::max<float>() == maxVal) 409 return 0.1f; 410 411 // Weight based on value range length 412 float rangeLength = maxVal - minVal; 413 414 DE_ASSERT(rangeLength >= 0.0f); 415 return deFloatMax(0.1f, 1.0f - rangeLength); 416 } 417 else if (type.isVoid()) 418 return unusedValueWeight; 419 else 420 return 0.0f; 421 } 422 423 void FloatLiteral::tokenize (GeneratorState& state, TokenStream& str) const 424 { 425 DE_UNREF(state); 426 str << Token(m_value.getValue(VariableType::getScalarType(VariableType::TYPE_FLOAT)).asFloat(0)); 427 } 428 429 IntLiteral::IntLiteral (GeneratorState& state, ConstValueRangeAccess valueRange) 430 : m_value(VariableType::getScalarType(VariableType::TYPE_INT)) 431 { 432 int minVal = -16; 433 int maxVal = +16; 434 435 if (valueRange.getType() == VariableType(VariableType::TYPE_INT, 1)) 436 { 437 minVal = valueRange.getMin().component(0).asInt(); 438 maxVal = valueRange.getMax().component(0).asInt(); 439 440 if (Scalar::min<int>() == minVal) 441 minVal = -16; 442 443 if (Scalar::max<int>() == maxVal) 444 maxVal = 16; 445 } 446 447 int value = state.getRandom().getInt(minVal, maxVal); 448 ExecValueAccess access = m_value.getValue(VariableType::getScalarType(VariableType::TYPE_INT)); 449 450 for (int ndx = 0; ndx < EXEC_VEC_WIDTH; ndx++) 451 access.asInt(ndx) = value; 452 } 453 454 float IntLiteral::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 455 { 456 DE_UNREF(state); 457 const VariableType& type = valueRange.getType(); 458 if (type == VariableType(VariableType::TYPE_INT, 1)) 459 { 460 int minVal = valueRange.getMin().asInt(); 461 int maxVal = valueRange.getMax().asInt(); 462 463 if (Scalar::min<int>() == minVal && Scalar::max<int>() == maxVal) 464 return 0.1f; 465 466 int rangeLength = maxVal - minVal; 467 468 DE_ASSERT(rangeLength >= 0); 469 return deFloatMax(0.1f, 1.0f - (float)rangeLength/4.0f); 470 } 471 else if (type.isVoid()) 472 return unusedValueWeight; 473 else 474 return 0.0f; 475 } 476 477 void IntLiteral::tokenize (GeneratorState& state, TokenStream& str) const 478 { 479 DE_UNREF(state); 480 str << Token(m_value.getValue(VariableType::getScalarType(VariableType::TYPE_INT)).asInt(0)); 481 } 482 483 BoolLiteral::BoolLiteral (GeneratorState& state, ConstValueRangeAccess valueRange) 484 : m_value(VariableType::getScalarType(VariableType::TYPE_BOOL)) 485 { 486 int minVal = 0; 487 int maxVal = 1; 488 489 if (valueRange.getType() == VariableType(VariableType::TYPE_BOOL, 1)) 490 { 491 minVal = valueRange.getMin().component(0).asBool() ? 1 : 0; 492 maxVal = valueRange.getMax().component(0).asBool() ? 1 : 0; 493 } 494 495 bool value = state.getRandom().getInt(minVal, maxVal) == 1; 496 ExecValueAccess access = m_value.getValue(VariableType::getScalarType(VariableType::TYPE_BOOL)); 497 498 for (int ndx = 0; ndx < EXEC_VEC_WIDTH; ndx++) 499 access.asBool(ndx) = value; 500 } 501 502 BoolLiteral::BoolLiteral (bool customValue) 503 : m_value(VariableType::getScalarType(VariableType::TYPE_BOOL)) 504 { 505 // This constructor is required to handle corner case in which comparision 506 // of two same floats produced different results - this was resolved by 507 // adding FloatLiteral containing epsilon to one of values 508 ExecValueAccess access = m_value.getValue(VariableType::getScalarType(VariableType::TYPE_BOOL)); 509 510 for (int ndx = 0; ndx < EXEC_VEC_WIDTH; ndx++) 511 access.asBool(ndx) = customValue; 512 } 513 514 515 float BoolLiteral::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 516 { 517 DE_UNREF(state); 518 const VariableType& type = valueRange.getType(); 519 if (type == VariableType(VariableType::TYPE_BOOL, 1)) 520 return 0.5f; 521 else if (type.isVoid()) 522 return unusedValueWeight; 523 else 524 return 0.0f; 525 } 526 527 void BoolLiteral::tokenize (GeneratorState& state, TokenStream& str) const 528 { 529 DE_UNREF(state); 530 str << Token(m_value.getValue(VariableType::getScalarType(VariableType::TYPE_BOOL)).asBool(0)); 531 } 532 533 namespace 534 { 535 536 // \note int-bool and float-bool conversions handled in a special way. 537 template <typename SrcType, typename DstType> 538 inline DstType convert (SrcType src) 539 { 540 if (Scalar::min<SrcType>() == src) 541 return Scalar::min<DstType>().template as<DstType>(); 542 else if (Scalar::max<SrcType>() == src) 543 return Scalar::max<DstType>().template as<DstType>(); 544 else 545 return DstType(src); 546 } 547 548 // According to GLSL ES spec. 549 template <> inline bool convert<float, bool> (float src) { return src != 0.0f; } 550 template <> inline bool convert<int, bool> (int src) { return src != 0; } 551 template <> inline bool convert<bool, bool> (bool src) { return src; } 552 template <> inline float convert<bool, float> (bool src) { return src ? 1.0f : 0.0f; } 553 template <> inline int convert<bool, int> (bool src) { return src ? 1 : 0; } 554 555 template <> inline int convert<float, int> (float src) 556 { 557 if (Scalar::min<float>() == src) 558 return Scalar::min<int>().as<int>(); 559 else if (Scalar::max<float>() == src) 560 return Scalar::max<int>().as<int>(); 561 else if (src > 0.0f) 562 return (int)deFloatFloor(src); 563 else 564 return (int)deFloatCeil(src); 565 } 566 567 template <typename SrcType, typename DstType> 568 inline void convertValueRange (SrcType srcMin, SrcType srcMax, DstType& dstMin, DstType& dstMax) 569 { 570 dstMin = convert<SrcType, DstType>(srcMin); 571 dstMax = convert<SrcType, DstType>(srcMax); 572 } 573 574 template <> 575 inline void convertValueRange<float, int> (float srcMin, float srcMax, int& dstMin, int& dstMax) 576 { 577 if (Scalar::min<float>() == srcMin) 578 dstMin = Scalar::min<int>().as<int>(); 579 else 580 dstMin = (int)deFloatCeil(srcMin); 581 582 if (Scalar::max<float>() == srcMax) 583 dstMax = Scalar::max<int>().as<int>(); 584 else 585 dstMax = (int)deFloatFloor(srcMax); 586 } 587 588 template <> 589 inline void convertValueRange<float, bool> (float srcMin, float srcMax, bool& dstMin, bool& dstMax) 590 { 591 dstMin = srcMin > 0.0f; 592 dstMax = srcMax > 0.0f; 593 } 594 595 // \todo [pyry] More special cases? 596 597 // Returns whether it is possible to convert some SrcType value range to given DstType valueRange 598 template <typename SrcType, typename DstType> 599 bool isConversionOk (DstType min, DstType max) 600 { 601 SrcType sMin, sMax; 602 convertValueRange(min, max, sMin, sMax); 603 return sMin <= sMax && 604 de::inRange(convert<SrcType, DstType>(sMin), min, max) && 605 de::inRange(convert<SrcType, DstType>(sMax), min, max); 606 } 607 608 // Work-around for non-deterministic float behavior 609 template <> bool isConversionOk<float, float> (float, float) { return true; } 610 611 // \todo [2011-03-26 pyry] Provide this in ValueAccess? 612 template <typename T> T getValueAccessValue (ConstValueAccess access); 613 template<> inline float getValueAccessValue<float> (ConstValueAccess access) { return access.asFloat(); } 614 template<> inline int getValueAccessValue<int> (ConstValueAccess access) { return access.asInt(); } 615 template<> inline bool getValueAccessValue<bool> (ConstValueAccess access) { return access.asBool(); } 616 617 template <typename T> T& getValueAccessValue (ValueAccess access); 618 template<> inline float& getValueAccessValue<float> (ValueAccess access) { return access.asFloat(); } 619 template<> inline int& getValueAccessValue<int> (ValueAccess access) { return access.asInt(); } 620 template<> inline bool& getValueAccessValue<bool> (ValueAccess access) { return access.asBool(); } 621 622 template <typename SrcType, typename DstType> 623 bool isConversionOk (ConstValueRangeAccess valueRange) 624 { 625 return isConversionOk<SrcType>(getValueAccessValue<DstType>(valueRange.getMin()), getValueAccessValue<DstType>(valueRange.getMax())); 626 } 627 628 template <typename SrcType, typename DstType> 629 void convertValueRangeTempl (ConstValueRangeAccess src, ValueRangeAccess dst) 630 { 631 DstType dMin, dMax; 632 convertValueRange(getValueAccessValue<SrcType>(src.getMin()), getValueAccessValue<SrcType>(src.getMax()), dMin, dMax); 633 getValueAccessValue<DstType>(dst.getMin()) = dMin; 634 getValueAccessValue<DstType>(dst.getMax()) = dMax; 635 } 636 637 template <typename SrcType, typename DstType> 638 void convertExecValueTempl (ExecConstValueAccess src, ExecValueAccess dst) 639 { 640 for (int ndx = 0; ndx < EXEC_VEC_WIDTH; ndx++) 641 dst.as<DstType>(ndx) = convert<SrcType, DstType>(src.as<SrcType>(ndx)); 642 } 643 644 typedef bool (*IsConversionOkFunc) (ConstValueRangeAccess); 645 typedef void (*ConvertValueRangeFunc) (ConstValueRangeAccess, ValueRangeAccess); 646 typedef void (*ConvertExecValueFunc) (ExecConstValueAccess, ExecValueAccess); 647 648 inline int getBaseTypeConvNdx (VariableType::Type type) 649 { 650 switch (type) 651 { 652 case VariableType::TYPE_FLOAT: return 0; 653 case VariableType::TYPE_INT: return 1; 654 case VariableType::TYPE_BOOL: return 2; 655 default: return -1; 656 } 657 } 658 659 bool isConversionOk (VariableType::Type srcType, VariableType::Type dstType, ConstValueRangeAccess valueRange) 660 { 661 // [src][dst] 662 static const IsConversionOkFunc convTable[3][3] = 663 { 664 { isConversionOk<float, float>, isConversionOk<float, int>, isConversionOk<float, bool> }, 665 { isConversionOk<int, float>, isConversionOk<int, int>, isConversionOk<int, bool> }, 666 { isConversionOk<bool, float>, isConversionOk<bool, int>, isConversionOk<bool, bool> } 667 }; 668 return convTable[getBaseTypeConvNdx(srcType)][getBaseTypeConvNdx(dstType)](valueRange); 669 } 670 671 void convertValueRange (ConstValueRangeAccess src, ValueRangeAccess dst) 672 { 673 // [src][dst] 674 static const ConvertValueRangeFunc convTable[3][3] = 675 { 676 { convertValueRangeTempl<float, float>, convertValueRangeTempl<float, int>, convertValueRangeTempl<float, bool> }, 677 { convertValueRangeTempl<int, float>, convertValueRangeTempl<int, int>, convertValueRangeTempl<int, bool> }, 678 { convertValueRangeTempl<bool, float>, convertValueRangeTempl<bool, int>, convertValueRangeTempl<bool, bool> } 679 }; 680 681 convTable[getBaseTypeConvNdx(src.getType().getBaseType())][getBaseTypeConvNdx(dst.getType().getBaseType())](src, dst); 682 } 683 684 void convertExecValue (ExecConstValueAccess src, ExecValueAccess dst) 685 { 686 // [src][dst] 687 static const ConvertExecValueFunc convTable[3][3] = 688 { 689 { convertExecValueTempl<float, float>, convertExecValueTempl<float, int>, convertExecValueTempl<float, bool> }, 690 { convertExecValueTempl<int, float>, convertExecValueTempl<int, int>, convertExecValueTempl<int, bool> }, 691 { convertExecValueTempl<bool, float>, convertExecValueTempl<bool, int>, convertExecValueTempl<bool, bool> } 692 }; 693 694 convTable[getBaseTypeConvNdx(src.getType().getBaseType())][getBaseTypeConvNdx(dst.getType().getBaseType())](src, dst); 695 } 696 697 } // anonymous 698 699 ConstructorOp::ConstructorOp (GeneratorState& state, ConstValueRangeAccess valueRange) 700 : m_valueRange(valueRange) 701 { 702 if (valueRange.getType().isVoid()) 703 { 704 // Use random range 705 const int maxScalars = 4; // We don't have to be able to assign this value to anywhere 706 m_valueRange = ValueRange(computeRandomType(state, maxScalars)); 707 computeRandomValueRange(state, m_valueRange.asAccess()); 708 } 709 710 // \todo [2011-03-26 pyry] Vector conversions 711 // int remainingDepth = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth(); 712 713 const VariableType& type = m_valueRange.getType(); 714 VariableType::Type baseType = type.getBaseType(); 715 int numScalars = type.getNumElements(); 716 int curScalarNdx = 0; 717 718 // \todo [2011-03-26 pyry] Separate op for struct constructors! 719 DE_ASSERT(type.isFloatOrVec() || type.isIntOrVec() || type.isBoolOrVec()); 720 721 bool scalarConversions = state.getProgramParameters().useScalarConversions; 722 723 while (curScalarNdx < numScalars) 724 { 725 ConstValueRangeAccess comp = m_valueRange.asAccess().component(curScalarNdx); 726 727 if (scalarConversions) 728 { 729 int numInTypes = 0; 730 VariableType::Type inTypes[3]; 731 732 if (isConversionOk(VariableType::TYPE_FLOAT, baseType, comp)) inTypes[numInTypes++] = VariableType::TYPE_FLOAT; 733 if (isConversionOk(VariableType::TYPE_INT, baseType, comp)) inTypes[numInTypes++] = VariableType::TYPE_INT; 734 if (isConversionOk(VariableType::TYPE_BOOL, baseType, comp)) inTypes[numInTypes++] = VariableType::TYPE_BOOL; 735 736 DE_ASSERT(numInTypes > 0); // At least nop conversion should be ok 737 738 // Choose random 739 VariableType::Type inType = state.getRandom().choose<VariableType::Type>(&inTypes[0], &inTypes[0] + numInTypes); 740 741 // Compute converted value range 742 ValueRange inValueRange(VariableType(inType, 1)); 743 convertValueRange(comp, inValueRange); 744 m_inputValueRanges.push_back(inValueRange); 745 746 curScalarNdx += 1; 747 } 748 else 749 { 750 m_inputValueRanges.push_back(ValueRange(comp)); 751 curScalarNdx += 1; 752 } 753 } 754 } 755 756 ConstructorOp::~ConstructorOp (void) 757 { 758 for (vector<Expression*>::iterator i = m_inputExpressions.begin(); i != m_inputExpressions.end(); i++) 759 delete *i; 760 } 761 762 Expression* ConstructorOp::createNextChild (GeneratorState& state) 763 { 764 int numChildren = (int)m_inputExpressions.size(); 765 Expression* child = DE_NULL; 766 767 // \note Created in reverse order! 768 if (numChildren < (int)m_inputValueRanges.size()) 769 { 770 const ValueRange& inValueRange = m_inputValueRanges[m_inputValueRanges.size()-1-numChildren]; 771 child = Expression::createRandom(state, inValueRange); 772 try 773 { 774 m_inputExpressions.push_back(child); 775 } 776 catch (const std::exception&) 777 { 778 delete child; 779 throw; 780 } 781 } 782 783 return child; 784 } 785 786 float ConstructorOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 787 { 788 if (valueRange.getType().isVoid()) 789 return unusedValueWeight; 790 791 if (!valueRange.getType().isFloatOrVec() && !valueRange.getType().isIntOrVec() && !valueRange.getType().isBoolOrVec()) 792 return 0.0f; 793 794 if (state.getExpressionDepth() + getTypeConstructorDepth(valueRange.getType()) > state.getShaderParameters().maxExpressionDepth) 795 return 0.0f; 796 797 return 1.0f; 798 } 799 800 void ConstructorOp::tokenize (GeneratorState& state, TokenStream& str) const 801 { 802 const VariableType& type = m_valueRange.getType(); 803 DE_ASSERT(type.getPrecision() == VariableType::PRECISION_NONE); 804 type.tokenizeShortType(str); 805 806 str << Token::LEFT_PAREN; 807 808 for (vector<Expression*>::const_reverse_iterator i = m_inputExpressions.rbegin(); i != m_inputExpressions.rend(); i++) 809 { 810 if (i != m_inputExpressions.rbegin()) 811 str << Token::COMMA; 812 (*i)->tokenize(state, str); 813 } 814 815 str << Token::RIGHT_PAREN; 816 } 817 818 void ConstructorOp::evaluate (ExecutionContext& evalCtx) 819 { 820 // Evaluate children 821 for (vector<Expression*>::reverse_iterator i = m_inputExpressions.rbegin(); i != m_inputExpressions.rend(); i++) 822 (*i)->evaluate(evalCtx); 823 824 // Compute value 825 const VariableType& type = m_valueRange.getType(); 826 m_value.setStorage(type); 827 828 ExecValueAccess dst = m_value.getValue(type); 829 int curScalarNdx = 0; 830 831 for (vector<Expression*>::reverse_iterator i = m_inputExpressions.rbegin(); i != m_inputExpressions.rend(); i++) 832 { 833 ExecConstValueAccess src = (*i)->getValue(); 834 835 for (int elemNdx = 0; elemNdx < src.getType().getNumElements(); elemNdx++) 836 convertExecValue(src.component(elemNdx), dst.component(curScalarNdx++)); 837 } 838 } 839 840 AssignOp::AssignOp (GeneratorState& state, ConstValueRangeAccess valueRange) 841 : m_valueRange (valueRange) 842 , m_lvalueExpr (DE_NULL) 843 , m_rvalueExpr (DE_NULL) 844 { 845 if (m_valueRange.getType().isVoid()) 846 { 847 // Compute random value range 848 int maxScalars = state.getShaderParameters().maxCombinedVariableScalars - state.getVariableManager().getNumAllocatedScalars(); 849 bool useRandomRange = !state.getVariableManager().hasEntry<IsWritableEntry>() || ((maxScalars > 0) && getWeightedBool(state.getRandom(), 0.1f)); 850 851 if (useRandomRange) 852 { 853 DE_ASSERT(maxScalars > 0); 854 m_valueRange = ValueRange(computeRandomType(state, maxScalars)); 855 computeRandomValueRange(state, m_valueRange.asAccess()); 856 } 857 else 858 { 859 // Use value range from random entry 860 // \todo [2011-02-28 pyry] Give lower weight to entries without range? Choose subtype range? 861 const ValueEntry* entry = state.getRandom().choose<const ValueEntry*>(state.getVariableManager().getBegin<IsWritableEntry>(), state.getVariableManager().getEnd<IsWritableEntry>()); 862 m_valueRange = ValueRange(entry->getValueRange()); 863 864 computeRandomValueRangeForInfElements(state, m_valueRange.asAccess()); 865 866 DE_ASSERT(state.getVariableManager().hasEntry(IsWritableIntersectingEntry(m_valueRange.asAccess()))); 867 } 868 } 869 870 IsWritableIntersectingEntry::Iterator first = state.getVariableManager().getBegin(IsWritableIntersectingEntry(m_valueRange.asAccess())); 871 IsWritableIntersectingEntry::Iterator end = state.getVariableManager().getEnd(IsWritableIntersectingEntry(m_valueRange.asAccess())); 872 873 bool possiblyCreateVar = canAllocateVariable(state, m_valueRange.getType()) && 874 (first == end || getWeightedBool(state.getRandom(), 0.5f)); 875 876 if (!possiblyCreateVar) 877 { 878 // Find all possible valueranges matching given type and intersecting with valuerange 879 // \todo [pyry] Actually collect all ValueRanges, currently operates only on whole variables 880 DE_ASSERT(first != end); 881 882 // Try to select one closest to given range but bigger (eg. superset) 883 bool supersetExists = false; 884 for (IsWritableIntersectingEntry::Iterator i = first; i != end; i++) 885 { 886 if ((*i)->getValueRange().isSupersetOf(m_valueRange.asAccess())) 887 { 888 supersetExists = true; 889 break; 890 } 891 } 892 893 if (!supersetExists) 894 { 895 // Select some other range and compute intersection 896 // \todo [2011-02-03 pyry] Use some heuristics to select the range? 897 ConstValueRangeAccess selectedRange = state.getRandom().choose<const ValueEntry*>(first, end)->getValueRange(); 898 899 ValueRange::computeIntersection(m_valueRange.asAccess(), m_valueRange.asAccess(), selectedRange); 900 } 901 } 902 } 903 904 AssignOp::~AssignOp (void) 905 { 906 delete m_lvalueExpr; 907 delete m_rvalueExpr; 908 } 909 910 float AssignOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 911 { 912 if (!valueRange.getType().isVoid() && 913 !canAllocateVariable(state, valueRange.getType()) && 914 !state.getVariableManager().hasEntry(IsWritableIntersectingEntry(valueRange))) 915 return 0.0f; // Would require creating a new variable 916 917 if (!valueRange.getType().isVoid() && state.getExpressionDepth() + getTypeConstructorDepth(valueRange.getType()) + 1 >= state.getShaderParameters().maxExpressionDepth) 918 return 0.0f; 919 920 if (valueRange.getType().isVoid() && 921 !state.getVariableManager().hasEntry<IsWritableEntry>() && 922 state.getVariableManager().getNumAllocatedScalars() >= state.getShaderParameters().maxCombinedVariableScalars) 923 return 0.0f; // Can not allocate a new entry 924 925 if (state.getExpressionDepth() == 0) 926 return 4.0f; 927 else 928 return 0.0f; // \todo [pyry] Fix assign ops 929 } 930 931 Expression* AssignOp::createNextChild (GeneratorState& state) 932 { 933 if (m_lvalueExpr == DE_NULL) 934 { 935 // Construct lvalue 936 // \todo [2011-03-14 pyry] Proper l-value generation: 937 // - pure L-value part is generated first 938 // - variable valuerange is made unbound 939 // - R-value is generated 940 // - R-values in L-value are generated 941 m_lvalueExpr = Expression::createRandomLValue(state, m_valueRange.asAccess()); 942 return m_lvalueExpr; 943 } 944 else if (m_rvalueExpr == DE_NULL) 945 { 946 // Construct value expr 947 m_rvalueExpr = Expression::createRandom(state, m_valueRange.asAccess()); 948 return m_rvalueExpr; 949 } 950 else 951 return DE_NULL; 952 } 953 954 void AssignOp::tokenize (GeneratorState& state, TokenStream& str) const 955 { 956 m_lvalueExpr->tokenize(state, str); 957 str << Token::EQUAL; 958 m_rvalueExpr->tokenize(state, str); 959 } 960 961 void AssignOp::evaluate (ExecutionContext& evalCtx) 962 { 963 // Evaluate l-value 964 m_lvalueExpr->evaluate(evalCtx); 965 966 // Evaluate value 967 m_rvalueExpr->evaluate(evalCtx); 968 m_value.setStorage(m_valueRange.getType()); 969 m_value.getValue(m_valueRange.getType()) = m_rvalueExpr->getValue().value(); 970 971 // Assign 972 assignMasked(m_lvalueExpr->getLValue(), m_value.getValue(m_valueRange.getType()), evalCtx.getExecutionMask()); 973 } 974 975 namespace 976 { 977 978 inline bool isShaderInOutSupportedType (const VariableType& type) 979 { 980 // \todo [2011-03-11 pyry] Float arrays, structs? 981 return type.getBaseType() == VariableType::TYPE_FLOAT; 982 } 983 984 Variable* allocateNewVariable (GeneratorState& state, ConstValueRangeAccess valueRange) 985 { 986 Variable* variable = state.getVariableManager().allocate(valueRange.getType()); 987 988 // Update value range 989 state.getVariableManager().setValue(variable, valueRange); 990 991 // Random storage \todo [pyry] Check that scalar count in uniform/input classes is not exceeded 992 static const Variable::Storage storages[] = 993 { 994 Variable::STORAGE_CONST, 995 Variable::STORAGE_UNIFORM, 996 Variable::STORAGE_LOCAL, 997 Variable::STORAGE_SHADER_IN 998 }; 999 float weights[DE_LENGTH_OF_ARRAY(storages)]; 1000 1001 // Dynamic vs. constant weight. 1002 float dynWeight = computeDynamicRangeWeight(valueRange); 1003 int numScalars = valueRange.getType().getScalarSize(); 1004 bool uniformOk = state.getVariableManager().getNumAllocatedUniformScalars() + numScalars <= state.getShaderParameters().maxUniformScalars; 1005 bool shaderInOk = isShaderInOutSupportedType(valueRange.getType()) && 1006 (state.getVariableManager().getNumAllocatedShaderInVariables() + NUM_RESERVED_SHADER_INPUTS < state.getShaderParameters().maxInputVariables); 1007 1008 weights[0] = de::max(1.0f-dynWeight, 0.1f); 1009 weights[1] = uniformOk ? dynWeight*0.5f : 0.0f; 1010 weights[2] = dynWeight; 1011 weights[3] = shaderInOk ? dynWeight*2.0f : 0.0f; 1012 1013 state.getVariableManager().setStorage(variable, state.getRandom().chooseWeighted<Variable::Storage>(&storages[0], &storages[DE_LENGTH_OF_ARRAY(storages)], &weights[0])); 1014 1015 return variable; 1016 } 1017 1018 inline float combineWeight (float curCombinedWeight, float partialWeight) 1019 { 1020 return curCombinedWeight * partialWeight; 1021 } 1022 1023 float computeEntryReadWeight (ConstValueRangeAccess entryValueRange, ConstValueRangeAccess readValueRange) 1024 { 1025 const VariableType& type = entryValueRange.getType(); 1026 DE_ASSERT(type == readValueRange.getType()); 1027 1028 float weight = 1.0f; 1029 1030 switch (type.getBaseType()) 1031 { 1032 case VariableType::TYPE_FLOAT: 1033 { 1034 for (int elemNdx = 0; elemNdx < type.getNumElements(); elemNdx++) 1035 { 1036 float entryMin = entryValueRange.component(elemNdx).getMin().asFloat(); 1037 float entryMax = entryValueRange.component(elemNdx).getMax().asFloat(); 1038 float readMin = readValueRange.component(elemNdx).getMin().asFloat(); 1039 float readMax = readValueRange.component(elemNdx).getMax().asFloat(); 1040 1041 // Check for -inf..inf ranges - they don't bring down the weight. 1042 if (Scalar::min<float>() == entryMin && Scalar::max<float>() == entryMax) 1043 continue; 1044 1045 // Intersection to entry value range length ratio. 1046 float intersectionMin = deFloatMax(entryMin, readMin); 1047 float intersectionMax = deFloatMin(entryMax, readMax); 1048 float entryRangeLen = entryMax - entryMin; 1049 float readRangeLen = readMax - readMin; 1050 float intersectionLen = intersectionMax - intersectionMin; 1051 float entryRatio = (entryRangeLen > 0.0f) ? (intersectionLen / entryRangeLen) : 1.0f; 1052 float readRatio = (readRangeLen > 0.0f) ? (intersectionLen / readRangeLen) : 1.0f; 1053 float elementWeight = 0.5f*readRatio + 0.5f*entryRatio; 1054 1055 weight = combineWeight(weight, elementWeight); 1056 } 1057 break; 1058 } 1059 1060 case VariableType::TYPE_INT: 1061 { 1062 for (int elemNdx = 0; elemNdx < type.getNumElements(); elemNdx++) 1063 { 1064 int entryMin = entryValueRange.component(elemNdx).getMin().asInt(); 1065 int entryMax = entryValueRange.component(elemNdx).getMax().asInt(); 1066 int readMin = readValueRange.component(elemNdx).getMin().asInt(); 1067 int readMax = readValueRange.component(elemNdx).getMax().asInt(); 1068 1069 // Check for -inf..inf ranges - they don't bring down the weight. 1070 if (Scalar::min<int>() == entryMin && Scalar::max<int>() == entryMax) 1071 continue; 1072 1073 // Intersection to entry value range length ratio. 1074 int intersectionMin = deMax32(entryMin, readMin); 1075 int intersectionMax = deMin32(entryMax, readMax); 1076 deInt64 entryRangeLen = (deInt64)entryMax - (deInt64)entryMin; 1077 deInt64 readRangeLen = (deInt64)readMax - (deInt64)readMin; 1078 deInt64 intersectionLen = (deInt64)intersectionMax - (deInt64)intersectionMin; 1079 float entryRatio = (entryRangeLen > 0) ? ((float)intersectionLen / (float)entryRangeLen) : 1.0f; 1080 float readRatio = (readRangeLen > 0) ? ((float)intersectionLen / (float)readRangeLen) : 1.0f; 1081 float elementWeight = 0.5f*readRatio + 0.5f*entryRatio; 1082 1083 weight = combineWeight(weight, elementWeight); 1084 } 1085 break; 1086 } 1087 1088 case VariableType::TYPE_BOOL: 1089 { 1090 // \todo 1091 break; 1092 } 1093 1094 1095 case VariableType::TYPE_ARRAY: 1096 case VariableType::TYPE_STRUCT: 1097 1098 default: 1099 TCU_FAIL("Unsupported type"); 1100 } 1101 1102 return deFloatMax(weight, 0.01f); 1103 } 1104 1105 } // anonymous 1106 1107 VariableRead::VariableRead (GeneratorState& state, ConstValueRangeAccess valueRange) 1108 { 1109 if (valueRange.getType().isVoid()) 1110 { 1111 IsReadableEntry filter = IsReadableEntry(state.getExpressionFlags()); 1112 int maxScalars = state.getShaderParameters().maxCombinedVariableScalars - state.getVariableManager().getNumAllocatedScalars(); 1113 bool useRandomRange = !state.getVariableManager().hasEntry(filter) || ((maxScalars > 0) && getWeightedBool(state.getRandom(), 0.5f)); 1114 1115 if (useRandomRange) 1116 { 1117 // Allocate a new variable 1118 DE_ASSERT(maxScalars > 0); 1119 ValueRange newVarRange(computeRandomType(state, maxScalars)); 1120 computeRandomValueRange(state, newVarRange.asAccess()); 1121 1122 m_variable = allocateNewVariable(state, newVarRange.asAccess()); 1123 } 1124 else 1125 { 1126 // Use random entry \todo [pyry] Handle -inf..inf ranges? 1127 m_variable = state.getRandom().choose<const ValueEntry*>(state.getVariableManager().getBegin(filter), state.getVariableManager().getEnd(filter))->getVariable(); 1128 } 1129 } 1130 else 1131 { 1132 // Find variable that has value range that intersects with given range 1133 IsReadableIntersectingEntry::Iterator first = state.getVariableManager().getBegin(IsReadableIntersectingEntry(valueRange, state.getExpressionFlags())); 1134 IsReadableIntersectingEntry::Iterator end = state.getVariableManager().getEnd(IsReadableIntersectingEntry(valueRange, state.getExpressionFlags())); 1135 1136 const float createOnReadWeight = 0.5f; 1137 bool createVar = canAllocateVariable(state, valueRange.getType()) && (first == end || getWeightedBool(state.getRandom(), createOnReadWeight)); 1138 1139 if (createVar) 1140 { 1141 m_variable = allocateNewVariable(state, valueRange); 1142 } 1143 else 1144 { 1145 // Copy value entries for computing weights. 1146 std::vector<const ValueEntry*> availableVars; 1147 std::vector<float> weights; 1148 1149 std::copy(first, end, std::inserter(availableVars, availableVars.begin())); 1150 1151 // Compute weights. 1152 weights.resize(availableVars.size()); 1153 for (int ndx = 0; ndx < (int)availableVars.size(); ndx++) 1154 weights[ndx] = computeEntryReadWeight(availableVars[ndx]->getValueRange(), valueRange); 1155 1156 // Select. 1157 const ValueEntry* entry = state.getRandom().chooseWeighted<const ValueEntry*>(availableVars.begin(), availableVars.end(), weights.begin()); 1158 m_variable = entry->getVariable(); 1159 1160 // Compute intersection 1161 ValueRange intersection(m_variable->getType()); 1162 ValueRange::computeIntersection(intersection, entry->getValueRange(), valueRange); 1163 state.getVariableManager().setValue(m_variable, intersection.asAccess()); 1164 } 1165 } 1166 } 1167 1168 VariableRead::VariableRead (const Variable* variable) 1169 { 1170 m_variable = variable; 1171 } 1172 1173 float VariableRead::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 1174 { 1175 if (valueRange.getType().isVoid()) 1176 { 1177 if (state.getVariableManager().hasEntry(IsReadableEntry(state.getExpressionFlags())) || 1178 state.getVariableManager().getNumAllocatedScalars() < state.getShaderParameters().maxCombinedVariableScalars) 1179 return unusedValueWeight; 1180 else 1181 return 0.0f; 1182 } 1183 1184 if (!canAllocateVariable(state, valueRange.getType()) && 1185 !state.getVariableManager().hasEntry(IsReadableIntersectingEntry(valueRange, state.getExpressionFlags()))) 1186 return 0.0f; 1187 else 1188 return 1.0f; 1189 } 1190 1191 VariableWrite::VariableWrite (GeneratorState& state, ConstValueRangeAccess valueRange) 1192 { 1193 DE_ASSERT(!valueRange.getType().isVoid()); 1194 1195 // Find variable with range that is superset of given range 1196 IsWritableSupersetEntry::Iterator first = state.getVariableManager().getBegin(IsWritableSupersetEntry(valueRange)); 1197 IsWritableSupersetEntry::Iterator end = state.getVariableManager().getEnd(IsWritableSupersetEntry(valueRange)); 1198 1199 const float createOnAssignWeight = 0.1f; // Will essentially create an unused variable 1200 bool createVar = canAllocateVariable(state, valueRange.getType()) && (first == end || getWeightedBool(state.getRandom(), createOnAssignWeight)); 1201 1202 if (createVar) 1203 { 1204 m_variable = state.getVariableManager().allocate(valueRange.getType()); 1205 // \note Storage will be LOCAL 1206 } 1207 else 1208 { 1209 // Choose random 1210 DE_ASSERT(first != end); 1211 const ValueEntry* entry = state.getRandom().choose<const ValueEntry*>(first, end); 1212 m_variable = entry->getVariable(); 1213 } 1214 1215 DE_ASSERT(m_variable); 1216 1217 // Reset value range. 1218 const ValueEntry* parentEntry = state.getVariableManager().getParentValue(m_variable); 1219 if (parentEntry) 1220 { 1221 // Use parent value range. 1222 state.getVariableManager().setValue(m_variable, parentEntry->getValueRange()); 1223 } 1224 else 1225 { 1226 // Use infinite range. 1227 ValueRange infRange(m_variable->getType()); 1228 setInfiniteRange(infRange); 1229 1230 state.getVariableManager().setValue(m_variable, infRange.asAccess()); 1231 } 1232 } 1233 1234 float VariableWrite::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 1235 { 1236 if (!canAllocateVariable(state, valueRange.getType()) && 1237 !state.getVariableManager().hasEntry(IsWritableSupersetEntry(valueRange))) 1238 return 0.0f; 1239 else 1240 return 1.0f; 1241 } 1242 1243 void VariableAccess::evaluate (ExecutionContext& evalCtx) 1244 { 1245 m_valueAccess = evalCtx.getValue(m_variable); 1246 } 1247 1248 ParenOp::ParenOp (GeneratorState& state, ConstValueRangeAccess valueRange) 1249 : m_valueRange (valueRange) 1250 , m_child (DE_NULL) 1251 { 1252 DE_UNREF(state); 1253 } 1254 1255 ParenOp::~ParenOp (void) 1256 { 1257 delete m_child; 1258 } 1259 1260 Expression* ParenOp::createNextChild (GeneratorState& state) 1261 { 1262 if (m_child == DE_NULL) 1263 { 1264 m_child = Expression::createRandom(state, m_valueRange.asAccess()); 1265 return m_child; 1266 } 1267 else 1268 return DE_NULL; 1269 } 1270 1271 void ParenOp::tokenize (GeneratorState& state, TokenStream& str) const 1272 { 1273 str << Token::LEFT_PAREN; 1274 m_child->tokenize(state, str); 1275 str << Token::RIGHT_PAREN; 1276 } 1277 1278 void ParenOp::setChild(Expression* expression) 1279 { 1280 m_child = expression; 1281 } 1282 1283 float ParenOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 1284 { 1285 if (valueRange.getType().isVoid()) 1286 return state.getExpressionDepth() + 2 <= state.getShaderParameters().maxExpressionDepth ? unusedValueWeight : 0.0f; 1287 else 1288 { 1289 int requiredDepth = 1 + getConservativeValueExprDepth(state, valueRange); 1290 return state.getExpressionDepth() + requiredDepth <= state.getShaderParameters().maxExpressionDepth ? 1.0f : 0.0f; 1291 } 1292 } 1293 1294 const int swizzlePrecedence = 2; 1295 1296 SwizzleOp::SwizzleOp (GeneratorState& state, ConstValueRangeAccess valueRange) 1297 : m_outValueRange (valueRange) 1298 , m_numInputElements (0) 1299 , m_child (DE_NULL) 1300 { 1301 DE_ASSERT(!m_outValueRange.getType().isVoid()); // \todo [2011-06-13 pyry] Void support 1302 DE_ASSERT(m_outValueRange.getType().isFloatOrVec() || 1303 m_outValueRange.getType().isIntOrVec() || 1304 m_outValueRange.getType().isBoolOrVec()); 1305 1306 m_value.setStorage(m_outValueRange.getType()); 1307 1308 int numOutputElements = m_outValueRange.getType().getNumElements(); 1309 1310 // \note Swizzle works for vector types only. 1311 // \todo [2011-06-13 pyry] Use components multiple times. 1312 m_numInputElements = state.getRandom().getInt(deMax32(numOutputElements, 2), 4); 1313 1314 std::set<int> availableElements; 1315 for (int ndx = 0; ndx < m_numInputElements; ndx++) 1316 availableElements.insert(ndx); 1317 1318 // Randomize swizzle. 1319 for (int elemNdx = 0; elemNdx < (int)DE_LENGTH_OF_ARRAY(m_swizzle); elemNdx++) 1320 { 1321 if (elemNdx < numOutputElements) 1322 { 1323 int inElemNdx = state.getRandom().choose<int>(availableElements.begin(), availableElements.end()); 1324 availableElements.erase(inElemNdx); 1325 m_swizzle[elemNdx] = (deUint8)inElemNdx; 1326 } 1327 else 1328 m_swizzle[elemNdx] = 0; 1329 } 1330 } 1331 1332 SwizzleOp::~SwizzleOp (void) 1333 { 1334 delete m_child; 1335 } 1336 1337 Expression* SwizzleOp::createNextChild (GeneratorState& state) 1338 { 1339 if (m_child) 1340 return DE_NULL; 1341 1342 // Compute input value range. 1343 VariableType inVarType = VariableType(m_outValueRange.getType().getBaseType(), m_numInputElements); 1344 ValueRange inValueRange = ValueRange(inVarType); 1345 1346 // Initialize all inputs to -inf..inf 1347 setInfiniteRange(inValueRange); 1348 1349 // Compute intersections. 1350 int numOutputElements = m_outValueRange.getType().getNumElements(); 1351 for (int outElemNdx = 0; outElemNdx < numOutputElements; outElemNdx++) 1352 { 1353 int inElemNdx = m_swizzle[outElemNdx]; 1354 ValueRange::computeIntersection(inValueRange.asAccess().component(inElemNdx), inValueRange.asAccess().component(inElemNdx), m_outValueRange.asAccess().component(outElemNdx)); 1355 } 1356 1357 // Create child. 1358 state.pushPrecedence(swizzlePrecedence); 1359 m_child = Expression::createRandom(state, inValueRange.asAccess()); 1360 state.popPrecedence(); 1361 1362 return m_child; 1363 } 1364 1365 void SwizzleOp::tokenize (GeneratorState& state, TokenStream& str) const 1366 { 1367 const char* rgbaSet[] = { "r", "g", "b", "a" }; 1368 const char* xyzwSet[] = { "x", "y", "z", "w" }; 1369 const char* stpqSet[] = { "s", "t", "p", "q" }; 1370 const char** swizzleSet = DE_NULL; 1371 1372 switch (state.getRandom().getInt(0, 2)) 1373 { 1374 case 0: swizzleSet = rgbaSet; break; 1375 case 1: swizzleSet = xyzwSet; break; 1376 case 2: swizzleSet = stpqSet; break; 1377 default: DE_ASSERT(DE_FALSE); 1378 } 1379 1380 std::string swizzleStr; 1381 for (int elemNdx = 0; elemNdx < m_outValueRange.getType().getNumElements(); elemNdx++) 1382 swizzleStr += swizzleSet[m_swizzle[elemNdx]]; 1383 1384 m_child->tokenize(state, str); 1385 str << Token::DOT << Token(swizzleStr.c_str()); 1386 } 1387 1388 float SwizzleOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 1389 { 1390 if (!state.getProgramParameters().useSwizzle) 1391 return 0.0f; 1392 1393 if (state.getPrecedence() < swizzlePrecedence) 1394 return 0.0f; 1395 1396 if (!valueRange.getType().isFloatOrVec() && 1397 !valueRange.getType().isIntOrVec() && 1398 !valueRange.getType().isBoolOrVec()) 1399 return 0.0f; 1400 1401 int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth(); 1402 1403 // Swizzle + Constructor + Values 1404 if (availableLevels < 3) 1405 return 0.0f; 1406 1407 return 1.0f; 1408 } 1409 1410 void SwizzleOp::evaluate (ExecutionContext& execCtx) 1411 { 1412 m_child->evaluate(execCtx); 1413 1414 ExecConstValueAccess inValue = m_child->getValue(); 1415 ExecValueAccess outValue = m_value.getValue(m_outValueRange.getType()); 1416 1417 for (int outElemNdx = 0; outElemNdx < outValue.getType().getNumElements(); outElemNdx++) 1418 { 1419 int inElemNdx = m_swizzle[outElemNdx]; 1420 outValue.component(outElemNdx) = inValue.component(inElemNdx).value(); 1421 } 1422 } 1423 1424 static int countSamplers (const VariableManager& varManager, VariableType::Type samplerType) 1425 { 1426 int numSamplers = 0; 1427 1428 IsSamplerEntry::Iterator i = varManager.getBegin(IsSamplerEntry(samplerType)); 1429 IsSamplerEntry::Iterator end = varManager.getEnd(IsSamplerEntry(samplerType)); 1430 1431 for (; i != end; i++) 1432 numSamplers += 1; 1433 1434 return numSamplers; 1435 } 1436 1437 TexLookup::TexLookup (GeneratorState& state, ConstValueRangeAccess valueRange) 1438 : m_type (TYPE_LAST) 1439 , m_coordExpr (DE_NULL) 1440 , m_lodBiasExpr (DE_NULL) 1441 , m_valueType (VariableType::TYPE_FLOAT, 4) 1442 , m_value (m_valueType) 1443 { 1444 DE_ASSERT(valueRange.getType() == VariableType(VariableType::TYPE_FLOAT, 4)); 1445 DE_UNREF(valueRange); // Texture output value range is constant. 1446 1447 // Select type. 1448 vector<Type> typeCandidates; 1449 if (state.getShaderParameters().useTexture2D) 1450 { 1451 typeCandidates.push_back(TYPE_TEXTURE2D); 1452 typeCandidates.push_back(TYPE_TEXTURE2D_LOD); 1453 typeCandidates.push_back(TYPE_TEXTURE2D_PROJ); 1454 typeCandidates.push_back(TYPE_TEXTURE2D_PROJ_LOD); 1455 } 1456 1457 if (state.getShaderParameters().useTextureCube) 1458 { 1459 typeCandidates.push_back(TYPE_TEXTURECUBE); 1460 typeCandidates.push_back(TYPE_TEXTURECUBE_LOD); 1461 } 1462 1463 m_type = state.getRandom().choose<Type>(typeCandidates.begin(), typeCandidates.end()); 1464 1465 // Select or allocate sampler. 1466 VariableType::Type samplerType = VariableType::TYPE_LAST; 1467 switch (m_type) 1468 { 1469 case TYPE_TEXTURE2D: 1470 case TYPE_TEXTURE2D_LOD: 1471 case TYPE_TEXTURE2D_PROJ: 1472 case TYPE_TEXTURE2D_PROJ_LOD: 1473 samplerType = VariableType::TYPE_SAMPLER_2D; 1474 break; 1475 1476 case TYPE_TEXTURECUBE: 1477 case TYPE_TEXTURECUBE_LOD: 1478 samplerType = VariableType::TYPE_SAMPLER_CUBE; 1479 break; 1480 1481 default: 1482 DE_ASSERT(DE_FALSE); 1483 } 1484 1485 int sampler2DCount = countSamplers(state.getVariableManager(), VariableType::TYPE_SAMPLER_2D); 1486 int samplerCubeCount = countSamplers(state.getVariableManager(), VariableType::TYPE_SAMPLER_CUBE); 1487 bool canAllocSampler = sampler2DCount + samplerCubeCount < state.getShaderParameters().maxSamplers; 1488 bool hasSampler = samplerType == VariableType::TYPE_SAMPLER_2D ? (sampler2DCount > 0) : (samplerCubeCount > 0); 1489 bool allocSampler = !hasSampler || (canAllocSampler && state.getRandom().getBool()); 1490 1491 if (allocSampler) 1492 { 1493 Variable* sampler = state.getVariableManager().allocate(VariableType(samplerType, 1)); 1494 state.getVariableManager().setStorage(sampler, Variable::STORAGE_UNIFORM); // Samplers are always uniforms. 1495 m_sampler = sampler; 1496 } 1497 else 1498 m_sampler = state.getRandom().choose<const ValueEntry*>(state.getVariableManager().getBegin(IsSamplerEntry(samplerType)), 1499 state.getVariableManager().getEnd(IsSamplerEntry(samplerType)))->getVariable(); 1500 } 1501 1502 TexLookup::~TexLookup (void) 1503 { 1504 delete m_coordExpr; 1505 delete m_lodBiasExpr; 1506 } 1507 1508 Expression* TexLookup::createNextChild (GeneratorState& state) 1509 { 1510 bool hasLodBias = m_type == TYPE_TEXTURE2D_LOD || 1511 m_type == TYPE_TEXTURE2D_PROJ_LOD || 1512 m_type == TYPE_TEXTURECUBE_LOD; 1513 1514 if (hasLodBias && !m_lodBiasExpr) 1515 { 1516 ValueRange lodRange(VariableType(VariableType::TYPE_FLOAT, 1)); 1517 setInfiniteRange(lodRange); // Any value is valid. 1518 1519 m_lodBiasExpr = Expression::createRandom(state, lodRange.asAccess()); 1520 return m_lodBiasExpr; 1521 } 1522 1523 if (!m_coordExpr) 1524 { 1525 if (m_type == TYPE_TEXTURECUBE || m_type == TYPE_TEXTURECUBE_LOD) 1526 { 1527 // Make sure major axis selection can be done. 1528 int majorAxisNdx = state.getRandom().getInt(0, 2); 1529 1530 ValueRange coordRange(VariableType(VariableType::TYPE_FLOAT, 3)); 1531 1532 for (int ndx = 0; ndx < 3; ndx++) 1533 { 1534 if (ndx == majorAxisNdx) 1535 { 1536 bool neg = state.getRandom().getBool(); 1537 coordRange.getMin().component(ndx) = neg ? -4.0f : 2.25f; 1538 coordRange.getMax().component(ndx) = neg ? -2.25f : 4.0f; 1539 } 1540 else 1541 { 1542 coordRange.getMin().component(ndx) = -2.0f; 1543 coordRange.getMax().component(ndx) = 2.0f; 1544 } 1545 } 1546 1547 m_coordExpr = Expression::createRandom(state, coordRange.asAccess()); 1548 } 1549 else 1550 { 1551 bool isProj = m_type == TYPE_TEXTURE2D_PROJ || m_type == TYPE_TEXTURE2D_PROJ_LOD; 1552 int coordScalarSize = isProj ? 3 : 2; 1553 1554 ValueRange coordRange(VariableType(VariableType::TYPE_FLOAT, coordScalarSize)); 1555 setInfiniteRange(coordRange); // Initialize base range with -inf..inf 1556 1557 if (isProj) 1558 { 1559 // w coordinate must be something sane, and not 0. 1560 bool neg = state.getRandom().getBool(); 1561 coordRange.getMin().component(2) = neg ? -4.0f : 0.25f; 1562 coordRange.getMax().component(2) = neg ? -0.25f : 4.0f; 1563 } 1564 1565 m_coordExpr = Expression::createRandom(state, coordRange.asAccess()); 1566 } 1567 1568 DE_ASSERT(m_coordExpr); 1569 return m_coordExpr; 1570 } 1571 1572 return DE_NULL; // Done. 1573 } 1574 1575 void TexLookup::tokenize (GeneratorState& state, TokenStream& str) const 1576 { 1577 bool isVertex = state.getShader().getType() == Shader::TYPE_VERTEX; 1578 1579 if (state.getProgramParameters().version == VERSION_300) 1580 { 1581 switch (m_type) 1582 { 1583 case TYPE_TEXTURE2D: str << "texture"; break; 1584 case TYPE_TEXTURE2D_LOD: str << (isVertex ? "textureLod" : "texture"); break; 1585 case TYPE_TEXTURE2D_PROJ: str << "textureProj"; break; 1586 case TYPE_TEXTURE2D_PROJ_LOD: str << (isVertex ? "textureProjLod" : "textureProj"); break; 1587 case TYPE_TEXTURECUBE: str << "texture"; break; 1588 case TYPE_TEXTURECUBE_LOD: str << (isVertex ? "textureLod" : "texture"); break; 1589 default: 1590 DE_ASSERT(DE_FALSE); 1591 } 1592 } 1593 else 1594 { 1595 switch (m_type) 1596 { 1597 case TYPE_TEXTURE2D: str << "texture2D"; break; 1598 case TYPE_TEXTURE2D_LOD: str << (isVertex ? "texture2DLod" : "texture2D"); break; 1599 case TYPE_TEXTURE2D_PROJ: str << "texture2DProj"; break; 1600 case TYPE_TEXTURE2D_PROJ_LOD: str << (isVertex ? "texture2DProjLod" : "texture2DProj"); break; 1601 case TYPE_TEXTURECUBE: str << "textureCube"; break; 1602 case TYPE_TEXTURECUBE_LOD: str << (isVertex ? "textureCubeLod" : "textureCube"); break; 1603 default: 1604 DE_ASSERT(DE_FALSE); 1605 } 1606 } 1607 1608 str << Token::LEFT_PAREN; 1609 str << m_sampler->getName(); 1610 str << Token::COMMA; 1611 m_coordExpr->tokenize(state, str); 1612 1613 if (m_lodBiasExpr) 1614 { 1615 str << Token::COMMA; 1616 m_lodBiasExpr->tokenize(state, str); 1617 } 1618 1619 str << Token::RIGHT_PAREN; 1620 } 1621 1622 float TexLookup::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 1623 { 1624 if (state.getShaderParameters().texLookupBaseWeight <= 0.0f) 1625 return 0.0f; 1626 1627 int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth(); 1628 1629 // Lookup + Constructor + Values 1630 if (availableLevels < 3) 1631 return 0.0f; 1632 1633 if (state.getExpressionFlags() & (CONST_EXPR|NO_VAR_ALLOCATION)) 1634 return 0.0f; 1635 1636 if (valueRange.getType() != VariableType(VariableType::TYPE_FLOAT, 4)) 1637 return 0.0f; 1638 1639 ValueRange texOutputRange(VariableType(VariableType::TYPE_FLOAT, 4)); 1640 for (int ndx = 0; ndx < 4; ndx++) 1641 { 1642 texOutputRange.getMin().component(ndx) = 0.0f; 1643 texOutputRange.getMax().component(ndx) = 1.0f; 1644 } 1645 1646 if (!valueRange.isSupersetOf(texOutputRange.asAccess())) 1647 return 0.0f; 1648 1649 return state.getShaderParameters().texLookupBaseWeight; 1650 } 1651 1652 void TexLookup::evaluate (ExecutionContext& execCtx) 1653 { 1654 // Evaluate coord and bias. 1655 m_coordExpr->evaluate(execCtx); 1656 if (m_lodBiasExpr) 1657 m_lodBiasExpr->evaluate(execCtx); 1658 1659 ExecConstValueAccess coords = m_coordExpr->getValue(); 1660 ExecValueAccess dst = m_value.getValue(m_valueType); 1661 1662 switch (m_type) 1663 { 1664 case TYPE_TEXTURE2D: 1665 { 1666 const Sampler2D& tex = execCtx.getSampler2D(m_sampler); 1667 for (int i = 0; i < EXEC_VEC_WIDTH; i++) 1668 { 1669 float s = coords.component(0).asFloat(i); 1670 float t = coords.component(1).asFloat(i); 1671 tcu::Vec4 p = tex.sample(s, t, 0.0f); 1672 1673 for (int comp = 0; comp < 4; comp++) 1674 dst.component(comp).asFloat(i) = p[comp]; 1675 } 1676 break; 1677 } 1678 1679 case TYPE_TEXTURE2D_LOD: 1680 { 1681 ExecConstValueAccess lod = m_lodBiasExpr->getValue(); 1682 const Sampler2D& tex = execCtx.getSampler2D(m_sampler); 1683 for (int i = 0; i < EXEC_VEC_WIDTH; i++) 1684 { 1685 float s = coords.component(0).asFloat(i); 1686 float t = coords.component(1).asFloat(i); 1687 float l = lod.component(0).asFloat(i); 1688 tcu::Vec4 p = tex.sample(s, t, l); 1689 1690 for (int comp = 0; comp < 4; comp++) 1691 dst.component(comp).asFloat(i) = p[comp]; 1692 } 1693 break; 1694 } 1695 1696 case TYPE_TEXTURE2D_PROJ: 1697 { 1698 const Sampler2D& tex = execCtx.getSampler2D(m_sampler); 1699 for (int i = 0; i < EXEC_VEC_WIDTH; i++) 1700 { 1701 float s = coords.component(0).asFloat(i); 1702 float t = coords.component(1).asFloat(i); 1703 float w = coords.component(2).asFloat(i); 1704 tcu::Vec4 p = tex.sample(s/w, t/w, 0.0f); 1705 1706 for (int comp = 0; comp < 4; comp++) 1707 dst.component(comp).asFloat(i) = p[comp]; 1708 } 1709 break; 1710 } 1711 1712 case TYPE_TEXTURE2D_PROJ_LOD: 1713 { 1714 ExecConstValueAccess lod = m_lodBiasExpr->getValue(); 1715 const Sampler2D& tex = execCtx.getSampler2D(m_sampler); 1716 for (int i = 0; i < EXEC_VEC_WIDTH; i++) 1717 { 1718 float s = coords.component(0).asFloat(i); 1719 float t = coords.component(1).asFloat(i); 1720 float w = coords.component(2).asFloat(i); 1721 float l = lod.component(0).asFloat(i); 1722 tcu::Vec4 p = tex.sample(s/w, t/w, l); 1723 1724 for (int comp = 0; comp < 4; comp++) 1725 dst.component(comp).asFloat(i) = p[comp]; 1726 } 1727 break; 1728 } 1729 1730 case TYPE_TEXTURECUBE: 1731 { 1732 const SamplerCube& tex = execCtx.getSamplerCube(m_sampler); 1733 for (int i = 0; i < EXEC_VEC_WIDTH; i++) 1734 { 1735 float s = coords.component(0).asFloat(i); 1736 float t = coords.component(1).asFloat(i); 1737 float r = coords.component(2).asFloat(i); 1738 tcu::Vec4 p = tex.sample(s, t, r, 0.0f); 1739 1740 for (int comp = 0; comp < 4; comp++) 1741 dst.component(comp).asFloat(i) = p[comp]; 1742 } 1743 break; 1744 } 1745 1746 case TYPE_TEXTURECUBE_LOD: 1747 { 1748 ExecConstValueAccess lod = m_lodBiasExpr->getValue(); 1749 const SamplerCube& tex = execCtx.getSamplerCube(m_sampler); 1750 for (int i = 0; i < EXEC_VEC_WIDTH; i++) 1751 { 1752 float s = coords.component(0).asFloat(i); 1753 float t = coords.component(1).asFloat(i); 1754 float r = coords.component(2).asFloat(i); 1755 float l = lod.component(0).asFloat(i); 1756 tcu::Vec4 p = tex.sample(s, t, r, l); 1757 1758 for (int comp = 0; comp < 4; comp++) 1759 dst.component(comp).asFloat(i) = p[comp]; 1760 } 1761 break; 1762 } 1763 1764 default: 1765 DE_ASSERT(DE_FALSE); 1766 } 1767 } 1768 1769 } // rsg 1770