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 31using std::vector; 32 33namespace rsg 34{ 35 36namespace 37{ 38 39class IsReadableEntry 40{ 41public: 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 57private: 58 deUint32 m_exprFlags; 59}; 60 61class IsReadableIntersectingEntry : public IsReadableEntry 62{ 63public: 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 86private: 87 ConstValueRangeAccess m_valueRange; 88}; 89 90class IsWritableIntersectingEntry : public IsWritableEntry 91{ 92public: 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 107private: 108 ConstValueRangeAccess m_valueRange; 109}; 110 111class IsWritableSupersetEntry : public IsWritableEntry 112{ 113public: 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 128private: 129 ConstValueRangeAccess m_valueRange; 130}; 131 132class IsSamplerEntry 133{ 134public: 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 154private: 155 VariableType::Type m_type; 156}; 157 158inline 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 164void 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 223void 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 259bool 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 272template <class T> float getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) { return T::getWeight(state, valueRange); } 273template <class T> Expression* create (GeneratorState& state, ConstValueRangeAccess valueRange) { return new T(state, valueRange); } 274 275struct ExpressionSpec 276{ 277 float (*getWeight) (const GeneratorState& state, ConstValueRangeAccess valueRange); 278 Expression* (*create) (GeneratorState& state, ConstValueRangeAccess valueRange); 279}; 280 281static 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 315static 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 324enum 325{ 326 MAX_EXPRESSION_SPECS = (int)DE_MAX(DE_LENGTH_OF_ARRAY(s_expressionSpecs), DE_LENGTH_OF_ARRAY(s_lvalueSpecs)) 327}; 328 329const 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 345Expression::~Expression (void) 346{ 347} 348 349Expression* 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 354Expression* 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 359FloatLiteral::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 387FloatLiteral::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 399float 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 423void 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 429IntLiteral::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 454float 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 477void 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 483BoolLiteral::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 502BoolLiteral::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 515float 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 527void 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 533namespace 534{ 535 536// \note int-bool and float-bool conversions handled in a special way. 537template <typename SrcType, typename DstType> 538inline 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. 549template <> inline bool convert<float, bool> (float src) { return src != 0.0f; } 550template <> inline bool convert<int, bool> (int src) { return src != 0; } 551template <> inline bool convert<bool, bool> (bool src) { return src; } 552template <> inline float convert<bool, float> (bool src) { return src ? 1.0f : 0.0f; } 553template <> inline int convert<bool, int> (bool src) { return src ? 1 : 0; } 554 555template <> 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 567template <typename SrcType, typename DstType> 568inline 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 574template <> 575inline 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 588template <> 589inline 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 598template <typename SrcType, typename DstType> 599bool 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 609template <> bool isConversionOk<float, float> (float, float) { return true; } 610 611// \todo [2011-03-26 pyry] Provide this in ValueAccess? 612template <typename T> T getValueAccessValue (ConstValueAccess access); 613template<> inline float getValueAccessValue<float> (ConstValueAccess access) { return access.asFloat(); } 614template<> inline int getValueAccessValue<int> (ConstValueAccess access) { return access.asInt(); } 615template<> inline bool getValueAccessValue<bool> (ConstValueAccess access) { return access.asBool(); } 616 617template <typename T> T& getValueAccessValue (ValueAccess access); 618template<> inline float& getValueAccessValue<float> (ValueAccess access) { return access.asFloat(); } 619template<> inline int& getValueAccessValue<int> (ValueAccess access) { return access.asInt(); } 620template<> inline bool& getValueAccessValue<bool> (ValueAccess access) { return access.asBool(); } 621 622template <typename SrcType, typename DstType> 623bool isConversionOk (ConstValueRangeAccess valueRange) 624{ 625 return isConversionOk<SrcType>(getValueAccessValue<DstType>(valueRange.getMin()), getValueAccessValue<DstType>(valueRange.getMax())); 626} 627 628template <typename SrcType, typename DstType> 629void 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 637template <typename SrcType, typename DstType> 638void 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 644typedef bool (*IsConversionOkFunc) (ConstValueRangeAccess); 645typedef void (*ConvertValueRangeFunc) (ConstValueRangeAccess, ValueRangeAccess); 646typedef void (*ConvertExecValueFunc) (ExecConstValueAccess, ExecValueAccess); 647 648inline 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 659bool 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 671void 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 684void 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 699ConstructorOp::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 756ConstructorOp::~ConstructorOp (void) 757{ 758 for (vector<Expression*>::iterator i = m_inputExpressions.begin(); i != m_inputExpressions.end(); i++) 759 delete *i; 760} 761 762Expression* 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 786float 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 800void 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 818void 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 840AssignOp::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 904AssignOp::~AssignOp (void) 905{ 906 delete m_lvalueExpr; 907 delete m_rvalueExpr; 908} 909 910float 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 931Expression* 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 954void 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 961void 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 975namespace 976{ 977 978inline bool isShaderInOutSupportedType (const VariableType& type) 979{ 980 // \todo [2011-03-11 pyry] Float arrays, structs? 981 return type.getBaseType() == VariableType::TYPE_FLOAT; 982} 983 984Variable* 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 1018inline float combineWeight (float curCombinedWeight, float partialWeight) 1019{ 1020 return curCombinedWeight * partialWeight; 1021} 1022 1023float 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 1107VariableRead::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 1168VariableRead::VariableRead (const Variable* variable) 1169{ 1170 m_variable = variable; 1171} 1172 1173float 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 1191VariableWrite::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 1234float 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 1243void VariableAccess::evaluate (ExecutionContext& evalCtx) 1244{ 1245 m_valueAccess = evalCtx.getValue(m_variable); 1246} 1247 1248ParenOp::ParenOp (GeneratorState& state, ConstValueRangeAccess valueRange) 1249 : m_valueRange (valueRange) 1250 , m_child (DE_NULL) 1251{ 1252 DE_UNREF(state); 1253} 1254 1255ParenOp::~ParenOp (void) 1256{ 1257 delete m_child; 1258} 1259 1260Expression* 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 1271void 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 1278void ParenOp::setChild(Expression* expression) 1279{ 1280 m_child = expression; 1281} 1282 1283float 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 1294const int swizzlePrecedence = 2; 1295 1296SwizzleOp::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 1332SwizzleOp::~SwizzleOp (void) 1333{ 1334 delete m_child; 1335} 1336 1337Expression* 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 1365void 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 1388float 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 1410void 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 1424static 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 1437TexLookup::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 1502TexLookup::~TexLookup (void) 1503{ 1504 delete m_coordExpr; 1505 delete m_lodBiasExpr; 1506} 1507 1508Expression* 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 1575void 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 1622float 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 1652void 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