1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL (ES) Module 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 Precision and range tests for GLSL builtins and types. 22 * 23 *//*--------------------------------------------------------------------*/ 24 25 #include "glsBuiltinPrecisionTests.hpp" 26 27 #include "deMath.h" 28 #include "deMemory.h" 29 #include "deDefs.hpp" 30 #include "deRandom.hpp" 31 #include "deSTLUtil.hpp" 32 #include "deStringUtil.hpp" 33 #include "deUniquePtr.hpp" 34 #include "deSharedPtr.hpp" 35 #include "deArrayUtil.hpp" 36 37 #include "tcuCommandLine.hpp" 38 #include "tcuFloatFormat.hpp" 39 #include "tcuInterval.hpp" 40 #include "tcuTestCase.hpp" 41 #include "tcuTestLog.hpp" 42 #include "tcuVector.hpp" 43 #include "tcuMatrix.hpp" 44 #include "tcuResultCollector.hpp" 45 46 #include "gluContextInfo.hpp" 47 #include "gluVarType.hpp" 48 #include "gluRenderContext.hpp" 49 #include "glwDefs.hpp" 50 51 #include "glsShaderExecUtil.hpp" 52 53 #include <cmath> 54 #include <string> 55 #include <sstream> 56 #include <iostream> 57 #include <map> 58 #include <utility> 59 60 // Uncomment this to get evaluation trace dumps to std::cerr 61 // #define GLS_ENABLE_TRACE 62 63 // set this to true to dump even passing results 64 #define GLS_LOG_ALL_RESULTS false 65 66 enum 67 { 68 // Computing reference intervals can take a non-trivial amount of time, especially on 69 // platforms where toggling floating-point rounding mode is slow (emulated arm on x86). 70 // As a workaround watchdog is kept happy by touching it periodically during reference 71 // interval computation. 72 TOUCH_WATCHDOG_VALUE_FREQUENCY = 4096 73 }; 74 75 namespace deqp 76 { 77 namespace gls 78 { 79 namespace BuiltinPrecisionTests 80 { 81 82 using std::string; 83 using std::map; 84 using std::ostream; 85 using std::ostringstream; 86 using std::pair; 87 using std::vector; 88 using std::set; 89 90 using de::MovePtr; 91 using de::Random; 92 using de::SharedPtr; 93 using de::UniquePtr; 94 using tcu::Interval; 95 using tcu::FloatFormat; 96 using tcu::MessageBuilder; 97 using tcu::TestCase; 98 using tcu::TestLog; 99 using tcu::Vector; 100 using tcu::Matrix; 101 namespace matrix = tcu::matrix; 102 using glu::Precision; 103 using glu::RenderContext; 104 using glu::VarType; 105 using glu::DataType; 106 using glu::ShaderType; 107 using glu::ContextInfo; 108 using gls::ShaderExecUtil::Symbol; 109 110 typedef TestCase::IterateResult IterateResult; 111 112 using namespace glw; 113 using namespace tcu; 114 115 /*--------------------------------------------------------------------*//*! 116 * \brief Generic singleton creator. 117 * 118 * instance<T>() returns a reference to a unique default-constructed instance 119 * of T. This is mainly used for our GLSL function implementations: each 120 * function is implemented by an object, and each of the objects has a 121 * distinct class. It would be extremely toilsome to maintain a separate 122 * context object that contained individual instances of the function classes, 123 * so we have to resort to global singleton instances. 124 * 125 *//*--------------------------------------------------------------------*/ 126 template <typename T> 127 const T& instance (void) 128 { 129 static const T s_instance = T(); 130 return s_instance; 131 } 132 133 /*--------------------------------------------------------------------*//*! 134 * \brief Dummy placeholder type for unused template parameters. 135 * 136 * In the precision tests we are dealing with functions of different arities. 137 * To minimize code duplication, we only define templates with the maximum 138 * number of arguments, currently four. If a function's arity is less than the 139 * maximum, Void us used as the type for unused arguments. 140 * 141 * Although Voids are not used at run-time, they still must be compilable, so 142 * they must support all operations that other types do. 143 * 144 *//*--------------------------------------------------------------------*/ 145 struct Void 146 { 147 typedef Void Element; 148 enum 149 { 150 SIZE = 0, 151 }; 152 153 template <typename T> 154 explicit Void (const T&) {} 155 Void (void) {} 156 operator double (void) const { return TCU_NAN; } 157 158 // These are used to make Voids usable as containers in container-generic code. 159 Void& operator[] (int) { return *this; } 160 const Void& operator[] (int) const { return *this; } 161 }; 162 163 ostream& operator<< (ostream& os, Void) { return os << "()"; } 164 165 //! Returns true for all other types except Void 166 template <typename T> bool isTypeValid (void) { return true; } 167 template <> bool isTypeValid<Void> (void) { return false; } 168 169 //! Utility function for getting the name of a data type. 170 //! This is used in vector and matrix constructors. 171 template <typename T> 172 const char* dataTypeNameOf (void) 173 { 174 return glu::getDataTypeName(glu::dataTypeOf<T>()); 175 } 176 177 template <> 178 const char* dataTypeNameOf<Void> (void) 179 { 180 DE_FATAL("Impossible"); 181 return DE_NULL; 182 } 183 184 //! A hack to get Void support for VarType. 185 template <typename T> 186 VarType getVarTypeOf (Precision prec = glu::PRECISION_LAST) 187 { 188 return glu::varTypeOf<T>(prec); 189 } 190 191 template <> 192 VarType getVarTypeOf<Void> (Precision) 193 { 194 DE_FATAL("Impossible"); 195 return VarType(); 196 } 197 198 /*--------------------------------------------------------------------*//*! 199 * \brief Type traits for generalized interval types. 200 * 201 * We are trying to compute sets of acceptable values not only for 202 * float-valued expressions but also for compound values: vectors and 203 * matrices. We approximate a set of vectors as a vector of intervals and 204 * likewise for matrices. 205 * 206 * We now need generalized operations for each type and its interval 207 * approximation. These are given in the type Traits<T>. 208 * 209 * The type Traits<T>::IVal is the approximation of T: it is `Interval` for 210 * scalar types, and a vector or matrix of intervals for container types. 211 * 212 * To allow template inference to take place, there are function wrappers for 213 * the actual operations in Traits<T>. Hence we can just use: 214 * 215 * makeIVal(someFloat) 216 * 217 * instead of: 218 * 219 * Traits<float>::doMakeIVal(value) 220 * 221 *//*--------------------------------------------------------------------*/ 222 223 template <typename T> struct Traits; 224 225 //! Create container from elementwise singleton values. 226 template <typename T> 227 typename Traits<T>::IVal makeIVal (const T& value) 228 { 229 return Traits<T>::doMakeIVal(value); 230 } 231 232 //! Elementwise union of intervals. 233 template <typename T> 234 typename Traits<T>::IVal unionIVal (const typename Traits<T>::IVal& a, 235 const typename Traits<T>::IVal& b) 236 { 237 return Traits<T>::doUnion(a, b); 238 } 239 240 //! Returns true iff every element of `ival` contains the corresponding element of `value`. 241 template <typename T> 242 bool contains (const typename Traits<T>::IVal& ival, const T& value) 243 { 244 return Traits<T>::doContains(ival, value); 245 } 246 247 //! Returns true iff every element of `ival` contains corresponding element of `value` within the warning interval 248 template <typename T> 249 bool containsWarning(const typename Traits<T>::IVal& ival, const T& value) 250 { 251 return Traits<T>::doContainsWarning(ival, value); 252 } 253 254 //! Print out an interval with the precision of `fmt`. 255 template <typename T> 256 void printIVal (const FloatFormat& fmt, const typename Traits<T>::IVal& ival, ostream& os) 257 { 258 Traits<T>::doPrintIVal(fmt, ival, os); 259 } 260 261 template <typename T> 262 string intervalToString (const FloatFormat& fmt, const typename Traits<T>::IVal& ival) 263 { 264 ostringstream oss; 265 printIVal<T>(fmt, ival, oss); 266 return oss.str(); 267 } 268 269 //! Print out a value with the precision of `fmt`. 270 template <typename T> 271 void printValue (const FloatFormat& fmt, const T& value, ostream& os) 272 { 273 Traits<T>::doPrintValue(fmt, value, os); 274 } 275 276 template <typename T> 277 string valueToString (const FloatFormat& fmt, const T& val) 278 { 279 ostringstream oss; 280 printValue(fmt, val, oss); 281 return oss.str(); 282 } 283 284 //! Approximate `value` elementwise to the float precision defined in `fmt`. 285 //! The resulting interval might not be a singleton if rounding in both 286 //! directions is allowed. 287 template <typename T> 288 typename Traits<T>::IVal round (const FloatFormat& fmt, const T& value) 289 { 290 return Traits<T>::doRound(fmt, value); 291 } 292 293 template <typename T> 294 typename Traits<T>::IVal convert (const FloatFormat& fmt, 295 const typename Traits<T>::IVal& value) 296 { 297 return Traits<T>::doConvert(fmt, value); 298 } 299 300 //! Common traits for scalar types. 301 template <typename T> 302 struct ScalarTraits 303 { 304 typedef Interval IVal; 305 306 static Interval doMakeIVal (const T& value) 307 { 308 // Thankfully all scalar types have a well-defined conversion to `double`, 309 // hence Interval can represent their ranges without problems. 310 return Interval(double(value)); 311 } 312 313 static Interval doUnion (const Interval& a, const Interval& b) 314 { 315 return a | b; 316 } 317 318 static bool doContains (const Interval& a, T value) 319 { 320 return a.contains(double(value)); 321 } 322 323 static bool doContainsWarning(const Interval& a, T value) 324 { 325 return a.containsWarning(double(value)); 326 } 327 328 static Interval doConvert (const FloatFormat& fmt, const IVal& ival) 329 { 330 return fmt.convert(ival); 331 } 332 333 static Interval doRound (const FloatFormat& fmt, T value) 334 { 335 return fmt.roundOut(double(value), false); 336 } 337 }; 338 339 template<> 340 struct Traits<float> : ScalarTraits<float> 341 { 342 static void doPrintIVal (const FloatFormat& fmt, 343 const Interval& ival, 344 ostream& os) 345 { 346 os << fmt.intervalToHex(ival); 347 } 348 349 static void doPrintValue (const FloatFormat& fmt, 350 const float& value, 351 ostream& os) 352 { 353 os << fmt.floatToHex(value); 354 } 355 }; 356 357 template<> 358 struct Traits<bool> : ScalarTraits<bool> 359 { 360 static void doPrintValue (const FloatFormat&, 361 const float& value, 362 ostream& os) 363 { 364 os << (value != 0.0f ? "true" : "false"); 365 } 366 367 static void doPrintIVal (const FloatFormat&, 368 const Interval& ival, 369 ostream& os) 370 { 371 os << "{"; 372 if (ival.contains(false)) 373 os << "false"; 374 if (ival.contains(false) && ival.contains(true)) 375 os << ", "; 376 if (ival.contains(true)) 377 os << "true"; 378 os << "}"; 379 } 380 }; 381 382 template<> 383 struct Traits<int> : ScalarTraits<int> 384 { 385 static void doPrintValue (const FloatFormat&, 386 const int& value, 387 ostream& os) 388 { 389 os << value; 390 } 391 392 static void doPrintIVal (const FloatFormat&, 393 const Interval& ival, 394 ostream& os) 395 { 396 os << "[" << int(ival.lo()) << ", " << int(ival.hi()) << "]"; 397 } 398 }; 399 400 //! Common traits for containers, i.e. vectors and matrices. 401 //! T is the container type itself, I is the same type with interval elements. 402 template <typename T, typename I> 403 struct ContainerTraits 404 { 405 typedef typename T::Element Element; 406 typedef I IVal; 407 408 static IVal doMakeIVal (const T& value) 409 { 410 IVal ret; 411 412 for (int ndx = 0; ndx < T::SIZE; ++ndx) 413 ret[ndx] = makeIVal(value[ndx]); 414 415 return ret; 416 } 417 418 static IVal doUnion (const IVal& a, const IVal& b) 419 { 420 IVal ret; 421 422 for (int ndx = 0; ndx < T::SIZE; ++ndx) 423 ret[ndx] = unionIVal<Element>(a[ndx], b[ndx]); 424 425 return ret; 426 } 427 428 static bool doContains (const IVal& ival, const T& value) 429 { 430 for (int ndx = 0; ndx < T::SIZE; ++ndx) 431 if (!contains(ival[ndx], value[ndx])) 432 return false; 433 434 return true; 435 } 436 437 static bool doContainsWarning(const IVal& ival, const T& value) 438 { 439 for (int ndx = 0; ndx < T::SIZE; ++ndx) 440 if (!containsWarning(ival[ndx], value[ndx])) 441 return false; 442 443 return true; 444 } 445 446 static void doPrintIVal (const FloatFormat& fmt, const IVal ival, ostream& os) 447 { 448 os << "("; 449 450 for (int ndx = 0; ndx < T::SIZE; ++ndx) 451 { 452 if (ndx > 0) 453 os << ", "; 454 455 printIVal<Element>(fmt, ival[ndx], os); 456 } 457 458 os << ")"; 459 } 460 461 static void doPrintValue (const FloatFormat& fmt, const T& value, ostream& os) 462 { 463 os << dataTypeNameOf<T>() << "("; 464 465 for (int ndx = 0; ndx < T::SIZE; ++ndx) 466 { 467 if (ndx > 0) 468 os << ", "; 469 470 printValue<Element>(fmt, value[ndx], os); 471 } 472 473 os << ")"; 474 } 475 476 static IVal doConvert (const FloatFormat& fmt, const IVal& value) 477 { 478 IVal ret; 479 480 for (int ndx = 0; ndx < T::SIZE; ++ndx) 481 ret[ndx] = convert<Element>(fmt, value[ndx]); 482 483 return ret; 484 } 485 486 static IVal doRound (const FloatFormat& fmt, T value) 487 { 488 IVal ret; 489 490 for (int ndx = 0; ndx < T::SIZE; ++ndx) 491 ret[ndx] = round(fmt, value[ndx]); 492 493 return ret; 494 } 495 }; 496 497 template <typename T, int Size> 498 struct Traits<Vector<T, Size> > : 499 ContainerTraits<Vector<T, Size>, Vector<typename Traits<T>::IVal, Size> > 500 { 501 }; 502 503 template <typename T, int Rows, int Cols> 504 struct Traits<Matrix<T, Rows, Cols> > : 505 ContainerTraits<Matrix<T, Rows, Cols>, Matrix<typename Traits<T>::IVal, Rows, Cols> > 506 { 507 }; 508 509 //! Void traits. These are just dummies, but technically valid: a Void is a 510 //! unit type with a single possible value. 511 template<> 512 struct Traits<Void> 513 { 514 typedef Void IVal; 515 516 static Void doMakeIVal (const Void& value) { return value; } 517 static Void doUnion (const Void&, const Void&) { return Void(); } 518 static bool doContains (const Void&, Void) { return true; } 519 static bool doContainsWarning (const Void&, Void) { return true; } 520 static Void doRound (const FloatFormat&, const Void& value) { return value; } 521 static Void doConvert (const FloatFormat&, const Void& value) { return value; } 522 523 static void doPrintValue (const FloatFormat&, const Void&, ostream& os) 524 { 525 os << "()"; 526 } 527 528 static void doPrintIVal (const FloatFormat&, const Void&, ostream& os) 529 { 530 os << "()"; 531 } 532 }; 533 534 //! This is needed for container-generic operations. 535 //! We want a scalar type T to be its own "one-element vector". 536 template <typename T, int Size> struct ContainerOf { typedef Vector<T, Size> Container; }; 537 538 template <typename T> struct ContainerOf<T, 1> { typedef T Container; }; 539 template <int Size> struct ContainerOf<Void, Size> { typedef Void Container; }; 540 541 // This is a kludge that is only needed to get the ExprP::operator[] syntactic sugar to work. 542 template <typename T> struct ElementOf { typedef typename T::Element Element; }; 543 template <> struct ElementOf<float> { typedef void Element; }; 544 template <> struct ElementOf<bool> { typedef void Element; }; 545 template <> struct ElementOf<int> { typedef void Element; }; 546 547 /*--------------------------------------------------------------------*//*! 548 * 549 * \name Abstract syntax for expressions and statements. 550 * 551 * We represent GLSL programs as syntax objects: an Expr<T> represents an 552 * expression whose GLSL type corresponds to the C++ type T, and a Statement 553 * represents a statement. 554 * 555 * To ease memory management, we use shared pointers to refer to expressions 556 * and statements. ExprP<T> is a shared pointer to an Expr<T>, and StatementP 557 * is a shared pointer to a Statement. 558 * 559 * \{ 560 * 561 *//*--------------------------------------------------------------------*/ 562 563 class ExprBase; 564 class ExpandContext; 565 class Statement; 566 class StatementP; 567 class FuncBase; 568 template <typename T> class ExprP; 569 template <typename T> class Variable; 570 template <typename T> class VariableP; 571 template <typename T> class DefaultSampling; 572 573 typedef set<const FuncBase*> FuncSet; 574 575 template <typename T> 576 VariableP<T> variable (const string& name); 577 StatementP compoundStatement (const vector<StatementP>& statements); 578 579 /*--------------------------------------------------------------------*//*! 580 * \brief A variable environment. 581 * 582 * An Environment object maintains the mapping between variables of the 583 * abstract syntax tree and their values. 584 * 585 * \todo [2014-03-28 lauri] At least run-time type safety. 586 * 587 *//*--------------------------------------------------------------------*/ 588 class Environment 589 { 590 public: 591 template<typename T> 592 void bind (const Variable<T>& variable, 593 const typename Traits<T>::IVal& value) 594 { 595 deUint8* const data = new deUint8[sizeof(value)]; 596 597 deMemcpy(data, &value, sizeof(value)); 598 de::insert(m_map, variable.getName(), SharedPtr<deUint8>(data, de::ArrayDeleter<deUint8>())); 599 } 600 601 template<typename T> 602 typename Traits<T>::IVal& lookup (const Variable<T>& variable) const 603 { 604 deUint8* const data = de::lookup(m_map, variable.getName()).get(); 605 606 return *reinterpret_cast<typename Traits<T>::IVal*>(data); 607 } 608 609 private: 610 map<string, SharedPtr<deUint8> > m_map; 611 }; 612 613 /*--------------------------------------------------------------------*//*! 614 * \brief Evaluation context. 615 * 616 * The evaluation context contains everything that separates one execution of 617 * an expression from the next. Currently this means the desired floating 618 * point precision and the current variable environment. 619 * 620 *//*--------------------------------------------------------------------*/ 621 struct EvalContext 622 { 623 EvalContext (const FloatFormat& format_, 624 Precision floatPrecision_, 625 Environment& env_, 626 int callDepth_ = 0) 627 : format (format_) 628 , floatPrecision (floatPrecision_) 629 , env (env_) 630 , callDepth (callDepth_) {} 631 632 FloatFormat format; 633 Precision floatPrecision; 634 Environment& env; 635 int callDepth; 636 }; 637 638 /*--------------------------------------------------------------------*//*! 639 * \brief Simple incremental counter. 640 * 641 * This is used to make sure that different ExpandContexts will not produce 642 * overlapping temporary names. 643 * 644 *//*--------------------------------------------------------------------*/ 645 class Counter 646 { 647 public: 648 Counter (int count = 0) : m_count(count) {} 649 int operator() (void) { return m_count++; } 650 651 private: 652 int m_count; 653 }; 654 655 class ExpandContext 656 { 657 public: 658 ExpandContext (Counter& symCounter) : m_symCounter(symCounter) {} 659 ExpandContext (const ExpandContext& parent) 660 : m_symCounter(parent.m_symCounter) {} 661 662 template<typename T> 663 VariableP<T> genSym (const string& baseName) 664 { 665 return variable<T>(baseName + de::toString(m_symCounter())); 666 } 667 668 void addStatement (const StatementP& stmt) 669 { 670 m_statements.push_back(stmt); 671 } 672 673 vector<StatementP> getStatements (void) const 674 { 675 return m_statements; 676 } 677 private: 678 Counter& m_symCounter; 679 vector<StatementP> m_statements; 680 }; 681 682 /*--------------------------------------------------------------------*//*! 683 * \brief A statement or declaration. 684 * 685 * Statements have no values. Instead, they are executed for their side 686 * effects only: the execute() method should modify at least one variable in 687 * the environment. 688 * 689 * As a bit of a kludge, a Statement object can also represent a declaration: 690 * when it is evaluated, it can add a variable binding to the environment 691 * instead of modifying a current one. 692 * 693 *//*--------------------------------------------------------------------*/ 694 class Statement 695 { 696 public: 697 virtual ~Statement (void) { } 698 //! Execute the statement, modifying the environment of `ctx` 699 void execute (EvalContext& ctx) const { this->doExecute(ctx); } 700 void print (ostream& os) const { this->doPrint(os); } 701 //! Add the functions used in this statement to `dst`. 702 void getUsedFuncs (FuncSet& dst) const { this->doGetUsedFuncs(dst); } 703 704 protected: 705 virtual void doPrint (ostream& os) const = 0; 706 virtual void doExecute (EvalContext& ctx) const = 0; 707 virtual void doGetUsedFuncs (FuncSet& dst) const = 0; 708 }; 709 710 ostream& operator<<(ostream& os, const Statement& stmt) 711 { 712 stmt.print(os); 713 return os; 714 } 715 716 /*--------------------------------------------------------------------*//*! 717 * \brief Smart pointer for statements (and declarations) 718 * 719 *//*--------------------------------------------------------------------*/ 720 class StatementP : public SharedPtr<const Statement> 721 { 722 public: 723 typedef SharedPtr<const Statement> Super; 724 725 StatementP (void) {} 726 explicit StatementP (const Statement* ptr) : Super(ptr) {} 727 StatementP (const Super& ptr) : Super(ptr) {} 728 }; 729 730 /*--------------------------------------------------------------------*//*! 731 * \brief 732 * 733 * A statement that modifies a variable or a declaration that binds a variable. 734 * 735 *//*--------------------------------------------------------------------*/ 736 template <typename T> 737 class VariableStatement : public Statement 738 { 739 public: 740 VariableStatement (const VariableP<T>& variable, const ExprP<T>& value, 741 bool isDeclaration) 742 : m_variable (variable) 743 , m_value (value) 744 , m_isDeclaration (isDeclaration) {} 745 746 protected: 747 void doPrint (ostream& os) const 748 { 749 if (m_isDeclaration) 750 os << glu::declare(getVarTypeOf<T>(), m_variable->getName()); 751 else 752 os << m_variable->getName(); 753 754 os << " = " << *m_value << ";\n"; 755 } 756 757 void doExecute (EvalContext& ctx) const 758 { 759 if (m_isDeclaration) 760 ctx.env.bind(*m_variable, m_value->evaluate(ctx)); 761 else 762 ctx.env.lookup(*m_variable) = m_value->evaluate(ctx); 763 } 764 765 void doGetUsedFuncs (FuncSet& dst) const 766 { 767 m_value->getUsedFuncs(dst); 768 } 769 770 VariableP<T> m_variable; 771 ExprP<T> m_value; 772 bool m_isDeclaration; 773 }; 774 775 template <typename T> 776 StatementP variableStatement (const VariableP<T>& variable, 777 const ExprP<T>& value, 778 bool isDeclaration) 779 { 780 return StatementP(new VariableStatement<T>(variable, value, isDeclaration)); 781 } 782 783 template <typename T> 784 StatementP variableDeclaration (const VariableP<T>& variable, const ExprP<T>& definiens) 785 { 786 return variableStatement(variable, definiens, true); 787 } 788 789 template <typename T> 790 StatementP variableAssignment (const VariableP<T>& variable, const ExprP<T>& value) 791 { 792 return variableStatement(variable, value, false); 793 } 794 795 /*--------------------------------------------------------------------*//*! 796 * \brief A compound statement, i.e. a block. 797 * 798 * A compound statement is executed by executing its constituent statements in 799 * sequence. 800 * 801 *//*--------------------------------------------------------------------*/ 802 class CompoundStatement : public Statement 803 { 804 public: 805 CompoundStatement (const vector<StatementP>& statements) 806 : m_statements (statements) {} 807 808 protected: 809 void doPrint (ostream& os) const 810 { 811 os << "{\n"; 812 813 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx) 814 os << *m_statements[ndx]; 815 816 os << "}\n"; 817 } 818 819 void doExecute (EvalContext& ctx) const 820 { 821 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx) 822 m_statements[ndx]->execute(ctx); 823 } 824 825 void doGetUsedFuncs (FuncSet& dst) const 826 { 827 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx) 828 m_statements[ndx]->getUsedFuncs(dst); 829 } 830 831 vector<StatementP> m_statements; 832 }; 833 834 StatementP compoundStatement(const vector<StatementP>& statements) 835 { 836 return StatementP(new CompoundStatement(statements)); 837 } 838 839 //! Common base class for all expressions regardless of their type. 840 class ExprBase 841 { 842 public: 843 virtual ~ExprBase (void) {} 844 void printExpr (ostream& os) const { this->doPrintExpr(os); } 845 846 //! Output the functions that this expression refers to 847 void getUsedFuncs (FuncSet& dst) const 848 { 849 this->doGetUsedFuncs(dst); 850 } 851 852 protected: 853 virtual void doPrintExpr (ostream&) const {} 854 virtual void doGetUsedFuncs (FuncSet&) const {} 855 }; 856 857 //! Type-specific operations for an expression representing type T. 858 template <typename T> 859 class Expr : public ExprBase 860 { 861 public: 862 typedef T Val; 863 typedef typename Traits<T>::IVal IVal; 864 865 IVal evaluate (const EvalContext& ctx) const; 866 867 protected: 868 virtual IVal doEvaluate (const EvalContext& ctx) const = 0; 869 }; 870 871 //! Evaluate an expression with the given context, optionally tracing the calls to stderr. 872 template <typename T> 873 typename Traits<T>::IVal Expr<T>::evaluate (const EvalContext& ctx) const 874 { 875 #ifdef GLS_ENABLE_TRACE 876 static const FloatFormat highpFmt (-126, 127, 23, true, 877 tcu::MAYBE, 878 tcu::YES, 879 tcu::MAYBE); 880 EvalContext newCtx (ctx.format, ctx.floatPrecision, 881 ctx.env, ctx.callDepth + 1); 882 const IVal ret = this->doEvaluate(newCtx); 883 884 if (isTypeValid<T>()) 885 { 886 std::cerr << string(ctx.callDepth, ' '); 887 this->printExpr(std::cerr); 888 std::cerr << " -> " << intervalToString<T>(highpFmt, ret) << std::endl; 889 } 890 return ret; 891 #else 892 return this->doEvaluate(ctx); 893 #endif 894 } 895 896 template <typename T> 897 class ExprPBase : public SharedPtr<const Expr<T> > 898 { 899 public: 900 }; 901 902 ostream& operator<< (ostream& os, const ExprBase& expr) 903 { 904 expr.printExpr(os); 905 return os; 906 } 907 908 /*--------------------------------------------------------------------*//*! 909 * \brief Shared pointer to an expression of a container type. 910 * 911 * Container types (i.e. vectors and matrices) support the subscription 912 * operator. This class provides a bit of syntactic sugar to allow us to use 913 * the C++ subscription operator to create a subscription expression. 914 *//*--------------------------------------------------------------------*/ 915 template <typename T> 916 class ContainerExprPBase : public ExprPBase<T> 917 { 918 public: 919 ExprP<typename T::Element> operator[] (int i) const; 920 }; 921 922 template <typename T> 923 class ExprP : public ExprPBase<T> {}; 924 925 // We treat Voids as containers since the dummy parameters in generalized 926 // vector functions are represented as Voids. 927 template <> 928 class ExprP<Void> : public ContainerExprPBase<Void> {}; 929 930 template <typename T, int Size> 931 class ExprP<Vector<T, Size> > : public ContainerExprPBase<Vector<T, Size> > {}; 932 933 template <typename T, int Rows, int Cols> 934 class ExprP<Matrix<T, Rows, Cols> > : public ContainerExprPBase<Matrix<T, Rows, Cols> > {}; 935 936 template <typename T> ExprP<T> exprP (void) 937 { 938 return ExprP<T>(); 939 } 940 941 template <typename T> 942 ExprP<T> exprP (const SharedPtr<const Expr<T> >& ptr) 943 { 944 ExprP<T> ret; 945 static_cast<SharedPtr<const Expr<T> >&>(ret) = ptr; 946 return ret; 947 } 948 949 template <typename T> 950 ExprP<T> exprP (const Expr<T>* ptr) 951 { 952 return exprP(SharedPtr<const Expr<T> >(ptr)); 953 } 954 955 /*--------------------------------------------------------------------*//*! 956 * \brief A shared pointer to a variable expression. 957 * 958 * This is just a narrowing of ExprP for the operations that require a variable 959 * instead of an arbitrary expression. 960 * 961 *//*--------------------------------------------------------------------*/ 962 template <typename T> 963 class VariableP : public SharedPtr<const Variable<T> > 964 { 965 public: 966 typedef SharedPtr<const Variable<T> > Super; 967 explicit VariableP (const Variable<T>* ptr) : Super(ptr) {} 968 VariableP (void) {} 969 VariableP (const Super& ptr) : Super(ptr) {} 970 971 operator ExprP<T> (void) const { return exprP(SharedPtr<const Expr<T> >(*this)); } 972 }; 973 974 /*--------------------------------------------------------------------*//*! 975 * \name Syntactic sugar operators for expressions. 976 * 977 * @{ 978 * 979 * These operators allow the use of C++ syntax to construct GLSL expressions 980 * containing operators: e.g. "a+b" creates an addition expression with 981 * operands a and b, and so on. 982 * 983 *//*--------------------------------------------------------------------*/ 984 ExprP<float> operator-(const ExprP<float>& arg0); 985 ExprP<float> operator+(const ExprP<float>& arg0, 986 const ExprP<float>& arg1); 987 ExprP<float> operator-(const ExprP<float>& arg0, 988 const ExprP<float>& arg1); 989 ExprP<float> operator*(const ExprP<float>& arg0, 990 const ExprP<float>& arg1); 991 ExprP<float> operator/(const ExprP<float>& arg0, 992 const ExprP<float>& arg1); 993 template<int Size> 994 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0); 995 template<int Size> 996 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0, 997 const ExprP<float>& arg1); 998 template<int Size> 999 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0, 1000 const ExprP<Vector<float, Size> >& arg1); 1001 template<int Size> 1002 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0, 1003 const ExprP<Vector<float, Size> >& arg1); 1004 template<int Left, int Mid, int Right> 1005 ExprP<Matrix<float, Left, Right> > operator* (const ExprP<Matrix<float, Left, Mid> >& left, 1006 const ExprP<Matrix<float, Mid, Right> >& right); 1007 template<int Rows, int Cols> 1008 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left, 1009 const ExprP<Matrix<float, Rows, Cols> >& right); 1010 template<int Rows, int Cols> 1011 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left, 1012 const ExprP<Vector<float, Rows> >& right); 1013 template<int Rows, int Cols> 1014 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left, 1015 const ExprP<float>& right); 1016 template<int Rows, int Cols> 1017 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left, 1018 const ExprP<Matrix<float, Rows, Cols> >& right); 1019 template<int Rows, int Cols> 1020 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat); 1021 1022 //! @} 1023 1024 /*--------------------------------------------------------------------*//*! 1025 * \brief Variable expression. 1026 * 1027 * A variable is evaluated by looking up its range of possible values from an 1028 * environment. 1029 *//*--------------------------------------------------------------------*/ 1030 template <typename T> 1031 class Variable : public Expr<T> 1032 { 1033 public: 1034 typedef typename Expr<T>::IVal IVal; 1035 1036 Variable (const string& name) : m_name (name) {} 1037 string getName (void) const { return m_name; } 1038 1039 protected: 1040 void doPrintExpr (ostream& os) const { os << m_name; } 1041 IVal doEvaluate (const EvalContext& ctx) const 1042 { 1043 return ctx.env.lookup<T>(*this); 1044 } 1045 1046 private: 1047 string m_name; 1048 }; 1049 1050 template <typename T> 1051 VariableP<T> variable (const string& name) 1052 { 1053 return VariableP<T>(new Variable<T>(name)); 1054 } 1055 1056 template <typename T> 1057 VariableP<T> bindExpression (const string& name, ExpandContext& ctx, const ExprP<T>& expr) 1058 { 1059 VariableP<T> var = ctx.genSym<T>(name); 1060 ctx.addStatement(variableDeclaration(var, expr)); 1061 return var; 1062 } 1063 1064 /*--------------------------------------------------------------------*//*! 1065 * \brief Constant expression. 1066 * 1067 * A constant is evaluated by rounding it to a set of possible values allowed 1068 * by the current floating point precision. 1069 *//*--------------------------------------------------------------------*/ 1070 template <typename T> 1071 class Constant : public Expr<T> 1072 { 1073 public: 1074 typedef typename Expr<T>::IVal IVal; 1075 1076 Constant (const T& value) : m_value(value) {} 1077 1078 protected: 1079 void doPrintExpr (ostream& os) const { os << m_value; } 1080 IVal doEvaluate (const EvalContext&) const { return makeIVal(m_value); } 1081 1082 private: 1083 T m_value; 1084 }; 1085 1086 template <typename T> 1087 ExprP<T> constant (const T& value) 1088 { 1089 return exprP(new Constant<T>(value)); 1090 } 1091 1092 //! Return a reference to a singleton void constant. 1093 const ExprP<Void>& voidP (void) 1094 { 1095 static const ExprP<Void> singleton = constant(Void()); 1096 1097 return singleton; 1098 } 1099 1100 /*--------------------------------------------------------------------*//*! 1101 * \brief Four-element tuple. 1102 * 1103 * This is used for various things where we need one thing for each possible 1104 * function parameter. Currently the maximum supported number of parameters is 1105 * four. 1106 *//*--------------------------------------------------------------------*/ 1107 template <typename T0 = Void, typename T1 = Void, typename T2 = Void, typename T3 = Void> 1108 struct Tuple4 1109 { 1110 explicit Tuple4 (const T0 e0 = T0(), 1111 const T1 e1 = T1(), 1112 const T2 e2 = T2(), 1113 const T3 e3 = T3()) 1114 : a (e0) 1115 , b (e1) 1116 , c (e2) 1117 , d (e3) 1118 { 1119 } 1120 1121 T0 a; 1122 T1 b; 1123 T2 c; 1124 T3 d; 1125 }; 1126 1127 /*--------------------------------------------------------------------*//*! 1128 * \brief Function signature. 1129 * 1130 * This is a purely compile-time structure used to bundle all types in a 1131 * function signature together. This makes passing the signature around in 1132 * templates easier, since we only need to take and pass a single Sig instead 1133 * of a bunch of parameter types and a return type. 1134 * 1135 *//*--------------------------------------------------------------------*/ 1136 template <typename R, 1137 typename P0 = Void, typename P1 = Void, 1138 typename P2 = Void, typename P3 = Void> 1139 struct Signature 1140 { 1141 typedef R Ret; 1142 typedef P0 Arg0; 1143 typedef P1 Arg1; 1144 typedef P2 Arg2; 1145 typedef P3 Arg3; 1146 typedef typename Traits<Ret>::IVal IRet; 1147 typedef typename Traits<Arg0>::IVal IArg0; 1148 typedef typename Traits<Arg1>::IVal IArg1; 1149 typedef typename Traits<Arg2>::IVal IArg2; 1150 typedef typename Traits<Arg3>::IVal IArg3; 1151 1152 typedef Tuple4< const Arg0&, const Arg1&, const Arg2&, const Arg3&> Args; 1153 typedef Tuple4< const IArg0&, const IArg1&, const IArg2&, const IArg3&> IArgs; 1154 typedef Tuple4< ExprP<Arg0>, ExprP<Arg1>, ExprP<Arg2>, ExprP<Arg3> > ArgExprs; 1155 }; 1156 1157 typedef vector<const ExprBase*> BaseArgExprs; 1158 1159 /*--------------------------------------------------------------------*//*! 1160 * \brief Type-independent operations for function objects. 1161 * 1162 *//*--------------------------------------------------------------------*/ 1163 class FuncBase 1164 { 1165 public: 1166 virtual ~FuncBase (void) {} 1167 virtual string getName (void) const = 0; 1168 //! Name of extension that this function requires, or empty. 1169 virtual string getRequiredExtension (void) const { return ""; } 1170 virtual void print (ostream&, 1171 const BaseArgExprs&) const = 0; 1172 //! Index of output parameter, or -1 if none of the parameters is output. 1173 virtual int getOutParamIndex (void) const { return -1; } 1174 1175 void printDefinition (ostream& os) const 1176 { 1177 doPrintDefinition(os); 1178 } 1179 1180 void getUsedFuncs (FuncSet& dst) const 1181 { 1182 this->doGetUsedFuncs(dst); 1183 } 1184 1185 protected: 1186 virtual void doPrintDefinition (ostream& os) const = 0; 1187 virtual void doGetUsedFuncs (FuncSet& dst) const = 0; 1188 }; 1189 1190 typedef Tuple4<string, string, string, string> ParamNames; 1191 1192 /*--------------------------------------------------------------------*//*! 1193 * \brief Function objects. 1194 * 1195 * Each Func object represents a GLSL function. It can be applied to interval 1196 * arguments, and it returns the an interval that is a conservative 1197 * approximation of the image of the GLSL function over the argument 1198 * intervals. That is, it is given a set of possible arguments and it returns 1199 * the set of possible values. 1200 * 1201 *//*--------------------------------------------------------------------*/ 1202 template <typename Sig_> 1203 class Func : public FuncBase 1204 { 1205 public: 1206 typedef Sig_ Sig; 1207 typedef typename Sig::Ret Ret; 1208 typedef typename Sig::Arg0 Arg0; 1209 typedef typename Sig::Arg1 Arg1; 1210 typedef typename Sig::Arg2 Arg2; 1211 typedef typename Sig::Arg3 Arg3; 1212 typedef typename Sig::IRet IRet; 1213 typedef typename Sig::IArg0 IArg0; 1214 typedef typename Sig::IArg1 IArg1; 1215 typedef typename Sig::IArg2 IArg2; 1216 typedef typename Sig::IArg3 IArg3; 1217 typedef typename Sig::Args Args; 1218 typedef typename Sig::IArgs IArgs; 1219 typedef typename Sig::ArgExprs ArgExprs; 1220 1221 void print (ostream& os, 1222 const BaseArgExprs& args) const 1223 { 1224 this->doPrint(os, args); 1225 } 1226 1227 IRet apply (const EvalContext& ctx, 1228 const IArg0& arg0 = IArg0(), 1229 const IArg1& arg1 = IArg1(), 1230 const IArg2& arg2 = IArg2(), 1231 const IArg3& arg3 = IArg3()) const 1232 { 1233 return this->applyArgs(ctx, IArgs(arg0, arg1, arg2, arg3)); 1234 } 1235 IRet applyArgs (const EvalContext& ctx, 1236 const IArgs& args) const 1237 { 1238 return this->doApply(ctx, args); 1239 } 1240 ExprP<Ret> operator() (const ExprP<Arg0>& arg0 = voidP(), 1241 const ExprP<Arg1>& arg1 = voidP(), 1242 const ExprP<Arg2>& arg2 = voidP(), 1243 const ExprP<Arg3>& arg3 = voidP()) const; 1244 1245 const ParamNames& getParamNames (void) const 1246 { 1247 return this->doGetParamNames(); 1248 } 1249 1250 protected: 1251 virtual IRet doApply (const EvalContext&, 1252 const IArgs&) const = 0; 1253 virtual void doPrint (ostream& os, const BaseArgExprs& args) const 1254 { 1255 os << getName() << "("; 1256 1257 if (isTypeValid<Arg0>()) 1258 os << *args[0]; 1259 1260 if (isTypeValid<Arg1>()) 1261 os << ", " << *args[1]; 1262 1263 if (isTypeValid<Arg2>()) 1264 os << ", " << *args[2]; 1265 1266 if (isTypeValid<Arg3>()) 1267 os << ", " << *args[3]; 1268 1269 os << ")"; 1270 } 1271 1272 virtual const ParamNames& doGetParamNames (void) const 1273 { 1274 static ParamNames names ("a", "b", "c", "d"); 1275 return names; 1276 } 1277 }; 1278 1279 template <typename Sig> 1280 class Apply : public Expr<typename Sig::Ret> 1281 { 1282 public: 1283 typedef typename Sig::Ret Ret; 1284 typedef typename Sig::Arg0 Arg0; 1285 typedef typename Sig::Arg1 Arg1; 1286 typedef typename Sig::Arg2 Arg2; 1287 typedef typename Sig::Arg3 Arg3; 1288 typedef typename Expr<Ret>::Val Val; 1289 typedef typename Expr<Ret>::IVal IVal; 1290 typedef Func<Sig> ApplyFunc; 1291 typedef typename ApplyFunc::ArgExprs ArgExprs; 1292 1293 Apply (const ApplyFunc& func, 1294 const ExprP<Arg0>& arg0 = voidP(), 1295 const ExprP<Arg1>& arg1 = voidP(), 1296 const ExprP<Arg2>& arg2 = voidP(), 1297 const ExprP<Arg3>& arg3 = voidP()) 1298 : m_func (func), 1299 m_args (arg0, arg1, arg2, arg3) {} 1300 1301 Apply (const ApplyFunc& func, 1302 const ArgExprs& args) 1303 : m_func (func), 1304 m_args (args) {} 1305 protected: 1306 void doPrintExpr (ostream& os) const 1307 { 1308 BaseArgExprs args; 1309 args.push_back(m_args.a.get()); 1310 args.push_back(m_args.b.get()); 1311 args.push_back(m_args.c.get()); 1312 args.push_back(m_args.d.get()); 1313 m_func.print(os, args); 1314 } 1315 1316 IVal doEvaluate (const EvalContext& ctx) const 1317 { 1318 return m_func.apply(ctx, 1319 m_args.a->evaluate(ctx), m_args.b->evaluate(ctx), 1320 m_args.c->evaluate(ctx), m_args.d->evaluate(ctx)); 1321 } 1322 1323 void doGetUsedFuncs (FuncSet& dst) const 1324 { 1325 m_func.getUsedFuncs(dst); 1326 m_args.a->getUsedFuncs(dst); 1327 m_args.b->getUsedFuncs(dst); 1328 m_args.c->getUsedFuncs(dst); 1329 m_args.d->getUsedFuncs(dst); 1330 } 1331 1332 const ApplyFunc& m_func; 1333 ArgExprs m_args; 1334 }; 1335 1336 template<typename T> 1337 class Alternatives : public Func<Signature<T, T, T> > 1338 { 1339 public: 1340 typedef typename Alternatives::Sig Sig; 1341 1342 protected: 1343 typedef typename Alternatives::IRet IRet; 1344 typedef typename Alternatives::IArgs IArgs; 1345 1346 virtual string getName (void) const { return "alternatives"; } 1347 virtual void doPrintDefinition (std::ostream&) const {} 1348 void doGetUsedFuncs (FuncSet&) const {} 1349 1350 virtual IRet doApply (const EvalContext&, const IArgs& args) const 1351 { 1352 return unionIVal<T>(args.a, args.b); 1353 } 1354 1355 virtual void doPrint (ostream& os, const BaseArgExprs& args) const 1356 { 1357 os << "{" << *args[0] << " | " << *args[1] << "}"; 1358 } 1359 }; 1360 1361 template <typename Sig> 1362 ExprP<typename Sig::Ret> createApply (const Func<Sig>& func, 1363 const typename Func<Sig>::ArgExprs& args) 1364 { 1365 return exprP(new Apply<Sig>(func, args)); 1366 } 1367 1368 template <typename Sig> 1369 ExprP<typename Sig::Ret> createApply ( 1370 const Func<Sig>& func, 1371 const ExprP<typename Sig::Arg0>& arg0 = voidP(), 1372 const ExprP<typename Sig::Arg1>& arg1 = voidP(), 1373 const ExprP<typename Sig::Arg2>& arg2 = voidP(), 1374 const ExprP<typename Sig::Arg3>& arg3 = voidP()) 1375 { 1376 return exprP(new Apply<Sig>(func, arg0, arg1, arg2, arg3)); 1377 } 1378 1379 template <typename Sig> 1380 ExprP<typename Sig::Ret> Func<Sig>::operator() (const ExprP<typename Sig::Arg0>& arg0, 1381 const ExprP<typename Sig::Arg1>& arg1, 1382 const ExprP<typename Sig::Arg2>& arg2, 1383 const ExprP<typename Sig::Arg3>& arg3) const 1384 { 1385 return createApply(*this, arg0, arg1, arg2, arg3); 1386 } 1387 1388 template <typename F> 1389 ExprP<typename F::Ret> app (const ExprP<typename F::Arg0>& arg0 = voidP(), 1390 const ExprP<typename F::Arg1>& arg1 = voidP(), 1391 const ExprP<typename F::Arg2>& arg2 = voidP(), 1392 const ExprP<typename F::Arg3>& arg3 = voidP()) 1393 { 1394 return createApply(instance<F>(), arg0, arg1, arg2, arg3); 1395 } 1396 1397 template <typename F> 1398 typename F::IRet call (const EvalContext& ctx, 1399 const typename F::IArg0& arg0 = Void(), 1400 const typename F::IArg1& arg1 = Void(), 1401 const typename F::IArg2& arg2 = Void(), 1402 const typename F::IArg3& arg3 = Void()) 1403 { 1404 return instance<F>().apply(ctx, arg0, arg1, arg2, arg3); 1405 } 1406 1407 template <typename T> 1408 ExprP<T> alternatives (const ExprP<T>& arg0, 1409 const ExprP<T>& arg1) 1410 { 1411 return createApply<typename Alternatives<T>::Sig>(instance<Alternatives<T> >(), arg0, arg1); 1412 } 1413 1414 template <typename Sig> 1415 class ApplyVar : public Apply<Sig> 1416 { 1417 public: 1418 typedef typename Sig::Ret Ret; 1419 typedef typename Sig::Arg0 Arg0; 1420 typedef typename Sig::Arg1 Arg1; 1421 typedef typename Sig::Arg2 Arg2; 1422 typedef typename Sig::Arg3 Arg3; 1423 typedef typename Expr<Ret>::Val Val; 1424 typedef typename Expr<Ret>::IVal IVal; 1425 typedef Func<Sig> ApplyFunc; 1426 typedef typename ApplyFunc::ArgExprs ArgExprs; 1427 1428 ApplyVar (const ApplyFunc& func, 1429 const VariableP<Arg0>& arg0, 1430 const VariableP<Arg1>& arg1, 1431 const VariableP<Arg2>& arg2, 1432 const VariableP<Arg3>& arg3) 1433 : Apply<Sig> (func, arg0, arg1, arg2, arg3) {} 1434 protected: 1435 IVal doEvaluate (const EvalContext& ctx) const 1436 { 1437 const Variable<Arg0>& var0 = static_cast<const Variable<Arg0>&>(*this->m_args.a); 1438 const Variable<Arg1>& var1 = static_cast<const Variable<Arg1>&>(*this->m_args.b); 1439 const Variable<Arg2>& var2 = static_cast<const Variable<Arg2>&>(*this->m_args.c); 1440 const Variable<Arg3>& var3 = static_cast<const Variable<Arg3>&>(*this->m_args.d); 1441 return this->m_func.apply(ctx, 1442 ctx.env.lookup(var0), ctx.env.lookup(var1), 1443 ctx.env.lookup(var2), ctx.env.lookup(var3)); 1444 } 1445 }; 1446 1447 template <typename Sig> 1448 ExprP<typename Sig::Ret> applyVar (const Func<Sig>& func, 1449 const VariableP<typename Sig::Arg0>& arg0, 1450 const VariableP<typename Sig::Arg1>& arg1, 1451 const VariableP<typename Sig::Arg2>& arg2, 1452 const VariableP<typename Sig::Arg3>& arg3) 1453 { 1454 return exprP(new ApplyVar<Sig>(func, arg0, arg1, arg2, arg3)); 1455 } 1456 1457 template <typename Sig_> 1458 class DerivedFunc : public Func<Sig_> 1459 { 1460 public: 1461 typedef typename DerivedFunc::ArgExprs ArgExprs; 1462 typedef typename DerivedFunc::IRet IRet; 1463 typedef typename DerivedFunc::IArgs IArgs; 1464 typedef typename DerivedFunc::Ret Ret; 1465 typedef typename DerivedFunc::Arg0 Arg0; 1466 typedef typename DerivedFunc::Arg1 Arg1; 1467 typedef typename DerivedFunc::Arg2 Arg2; 1468 typedef typename DerivedFunc::Arg3 Arg3; 1469 typedef typename DerivedFunc::IArg0 IArg0; 1470 typedef typename DerivedFunc::IArg1 IArg1; 1471 typedef typename DerivedFunc::IArg2 IArg2; 1472 typedef typename DerivedFunc::IArg3 IArg3; 1473 1474 protected: 1475 void doPrintDefinition (ostream& os) const 1476 { 1477 const ParamNames& paramNames = this->getParamNames(); 1478 1479 initialize(); 1480 1481 os << dataTypeNameOf<Ret>() << " " << this->getName() 1482 << "("; 1483 if (isTypeValid<Arg0>()) 1484 os << dataTypeNameOf<Arg0>() << " " << paramNames.a; 1485 if (isTypeValid<Arg1>()) 1486 os << ", " << dataTypeNameOf<Arg1>() << " " << paramNames.b; 1487 if (isTypeValid<Arg2>()) 1488 os << ", " << dataTypeNameOf<Arg2>() << " " << paramNames.c; 1489 if (isTypeValid<Arg3>()) 1490 os << ", " << dataTypeNameOf<Arg3>() << " " << paramNames.d; 1491 os << ")\n{\n"; 1492 1493 for (size_t ndx = 0; ndx < m_body.size(); ++ndx) 1494 os << *m_body[ndx]; 1495 os << "return " << *m_ret << ";\n"; 1496 os << "}\n"; 1497 } 1498 1499 IRet doApply (const EvalContext& ctx, 1500 const IArgs& args) const 1501 { 1502 Environment funEnv; 1503 IArgs& mutArgs = const_cast<IArgs&>(args); 1504 IRet ret; 1505 1506 initialize(); 1507 1508 funEnv.bind(*m_var0, args.a); 1509 funEnv.bind(*m_var1, args.b); 1510 funEnv.bind(*m_var2, args.c); 1511 funEnv.bind(*m_var3, args.d); 1512 1513 { 1514 EvalContext funCtx(ctx.format, ctx.floatPrecision, funEnv, ctx.callDepth); 1515 1516 for (size_t ndx = 0; ndx < m_body.size(); ++ndx) 1517 m_body[ndx]->execute(funCtx); 1518 1519 ret = m_ret->evaluate(funCtx); 1520 } 1521 1522 // \todo [lauri] Store references instead of values in environment 1523 const_cast<IArg0&>(mutArgs.a) = funEnv.lookup(*m_var0); 1524 const_cast<IArg1&>(mutArgs.b) = funEnv.lookup(*m_var1); 1525 const_cast<IArg2&>(mutArgs.c) = funEnv.lookup(*m_var2); 1526 const_cast<IArg3&>(mutArgs.d) = funEnv.lookup(*m_var3); 1527 1528 return ret; 1529 } 1530 1531 void doGetUsedFuncs (FuncSet& dst) const 1532 { 1533 initialize(); 1534 if (dst.insert(this).second) 1535 { 1536 for (size_t ndx = 0; ndx < m_body.size(); ++ndx) 1537 m_body[ndx]->getUsedFuncs(dst); 1538 m_ret->getUsedFuncs(dst); 1539 } 1540 } 1541 1542 virtual ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args_) const = 0; 1543 1544 // These are transparently initialized when first needed. They cannot be 1545 // initialized in the constructor because they depend on the doExpand 1546 // method of the subclass. 1547 1548 mutable VariableP<Arg0> m_var0; 1549 mutable VariableP<Arg1> m_var1; 1550 mutable VariableP<Arg2> m_var2; 1551 mutable VariableP<Arg3> m_var3; 1552 mutable vector<StatementP> m_body; 1553 mutable ExprP<Ret> m_ret; 1554 1555 private: 1556 1557 void initialize (void) const 1558 { 1559 if (!m_ret) 1560 { 1561 const ParamNames& paramNames = this->getParamNames(); 1562 Counter symCounter; 1563 ExpandContext ctx (symCounter); 1564 ArgExprs args; 1565 1566 args.a = m_var0 = variable<Arg0>(paramNames.a); 1567 args.b = m_var1 = variable<Arg1>(paramNames.b); 1568 args.c = m_var2 = variable<Arg2>(paramNames.c); 1569 args.d = m_var3 = variable<Arg3>(paramNames.d); 1570 1571 m_ret = this->doExpand(ctx, args); 1572 m_body = ctx.getStatements(); 1573 } 1574 } 1575 }; 1576 1577 template <typename Sig> 1578 class PrimitiveFunc : public Func<Sig> 1579 { 1580 public: 1581 typedef typename PrimitiveFunc::Ret Ret; 1582 typedef typename PrimitiveFunc::ArgExprs ArgExprs; 1583 1584 protected: 1585 void doPrintDefinition (ostream&) const {} 1586 void doGetUsedFuncs (FuncSet&) const {} 1587 }; 1588 1589 template <typename T> 1590 class Cond : public PrimitiveFunc<Signature<T, bool, T, T> > 1591 { 1592 public: 1593 typedef typename Cond::IArgs IArgs; 1594 typedef typename Cond::IRet IRet; 1595 1596 string getName (void) const 1597 { 1598 return "_cond"; 1599 } 1600 1601 protected: 1602 1603 void doPrint (ostream& os, const BaseArgExprs& args) const 1604 { 1605 os << "(" << *args[0] << " ? " << *args[1] << " : " << *args[2] << ")"; 1606 } 1607 1608 IRet doApply (const EvalContext&, const IArgs& iargs)const 1609 { 1610 IRet ret; 1611 1612 if (iargs.a.contains(true)) 1613 ret = unionIVal<T>(ret, iargs.b); 1614 1615 if (iargs.a.contains(false)) 1616 ret = unionIVal<T>(ret, iargs.c); 1617 1618 return ret; 1619 } 1620 }; 1621 1622 template <typename T> 1623 class CompareOperator : public PrimitiveFunc<Signature<bool, T, T> > 1624 { 1625 public: 1626 typedef typename CompareOperator::IArgs IArgs; 1627 typedef typename CompareOperator::IArg0 IArg0; 1628 typedef typename CompareOperator::IArg1 IArg1; 1629 typedef typename CompareOperator::IRet IRet; 1630 1631 protected: 1632 void doPrint (ostream& os, const BaseArgExprs& args) const 1633 { 1634 os << "(" << *args[0] << getSymbol() << *args[1] << ")"; 1635 } 1636 1637 Interval doApply (const EvalContext&, const IArgs& iargs) const 1638 { 1639 const IArg0& arg0 = iargs.a; 1640 const IArg1& arg1 = iargs.b; 1641 IRet ret; 1642 1643 if (canSucceed(arg0, arg1)) 1644 ret |= true; 1645 if (canFail(arg0, arg1)) 1646 ret |= false; 1647 1648 return ret; 1649 } 1650 1651 virtual string getSymbol (void) const = 0; 1652 virtual bool canSucceed (const IArg0&, const IArg1&) const = 0; 1653 virtual bool canFail (const IArg0&, const IArg1&) const = 0; 1654 }; 1655 1656 template <typename T> 1657 class LessThan : public CompareOperator<T> 1658 { 1659 public: 1660 string getName (void) const { return "lessThan"; } 1661 1662 protected: 1663 string getSymbol (void) const { return "<"; } 1664 1665 bool canSucceed (const Interval& a, const Interval& b) const 1666 { 1667 return (a.lo() < b.hi()); 1668 } 1669 1670 bool canFail (const Interval& a, const Interval& b) const 1671 { 1672 return !(a.hi() < b.lo()); 1673 } 1674 }; 1675 1676 template <typename T> 1677 ExprP<bool> operator< (const ExprP<T>& a, const ExprP<T>& b) 1678 { 1679 return app<LessThan<T> >(a, b); 1680 } 1681 1682 template <typename T> 1683 ExprP<T> cond (const ExprP<bool>& test, 1684 const ExprP<T>& consequent, 1685 const ExprP<T>& alternative) 1686 { 1687 return app<Cond<T> >(test, consequent, alternative); 1688 } 1689 1690 /*--------------------------------------------------------------------*//*! 1691 * 1692 * @} 1693 * 1694 *//*--------------------------------------------------------------------*/ 1695 1696 class FloatFunc1 : public PrimitiveFunc<Signature<float, float> > 1697 { 1698 protected: 1699 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const 1700 { 1701 return this->applyMonotone(ctx, iargs.a); 1702 } 1703 1704 Interval applyMonotone (const EvalContext& ctx, const Interval& iarg0) const 1705 { 1706 Interval ret; 1707 1708 TCU_INTERVAL_APPLY_MONOTONE1(ret, arg0, iarg0, val, 1709 TCU_SET_INTERVAL(val, point, 1710 point = this->applyPoint(ctx, arg0))); 1711 1712 ret |= innerExtrema(ctx, iarg0); 1713 ret &= (this->getCodomain() | TCU_NAN); 1714 1715 return ctx.format.convert(ret); 1716 } 1717 1718 virtual Interval innerExtrema (const EvalContext&, const Interval&) const 1719 { 1720 return Interval(); // empty interval, i.e. no extrema 1721 } 1722 1723 virtual Interval applyPoint (const EvalContext& ctx, double arg0) const 1724 { 1725 const double exact = this->applyExact(arg0); 1726 const double prec = this->precision(ctx, exact, arg0); 1727 const double wprec = this->warningPrecision(ctx, exact, arg0); 1728 Interval ioutput = exact + Interval(-prec, prec); 1729 ioutput.warning(exact - wprec, exact + wprec); 1730 return ioutput; 1731 } 1732 1733 virtual double applyExact (double) const 1734 { 1735 TCU_THROW(InternalError, "Cannot apply"); 1736 } 1737 1738 virtual Interval getCodomain (void) const 1739 { 1740 return Interval::unbounded(true); 1741 } 1742 1743 virtual double precision (const EvalContext& ctx, double, double) const = 0; 1744 1745 virtual double warningPrecision (const EvalContext& ctx, double exact, double arg0) const 1746 { 1747 return precision(ctx, exact, arg0); 1748 } 1749 1750 }; 1751 1752 class CFloatFunc1 : public FloatFunc1 1753 { 1754 public: 1755 CFloatFunc1 (const string& name, DoubleFunc1& func) 1756 : m_name(name), m_func(func) {} 1757 1758 string getName (void) const { return m_name; } 1759 1760 protected: 1761 double applyExact (double x) const { return m_func(x); } 1762 1763 const string m_name; 1764 DoubleFunc1& m_func; 1765 }; 1766 1767 class FloatFunc2 : public PrimitiveFunc<Signature<float, float, float> > 1768 { 1769 protected: 1770 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const 1771 { 1772 return this->applyMonotone(ctx, iargs.a, iargs.b); 1773 } 1774 1775 Interval applyMonotone (const EvalContext& ctx, 1776 const Interval& xi, 1777 const Interval& yi) const 1778 { 1779 Interval reti; 1780 1781 TCU_INTERVAL_APPLY_MONOTONE2(reti, x, xi, y, yi, ret, 1782 TCU_SET_INTERVAL(ret, point, 1783 point = this->applyPoint(ctx, x, y))); 1784 reti |= innerExtrema(ctx, xi, yi); 1785 reti &= (this->getCodomain() | TCU_NAN); 1786 1787 return ctx.format.convert(reti); 1788 } 1789 1790 virtual Interval innerExtrema (const EvalContext&, 1791 const Interval&, 1792 const Interval&) const 1793 { 1794 return Interval(); // empty interval, i.e. no extrema 1795 } 1796 1797 virtual Interval applyPoint (const EvalContext& ctx, 1798 double x, 1799 double y) const 1800 { 1801 const double exact = this->applyExact(x, y); 1802 const double prec = this->precision(ctx, exact, x, y); 1803 1804 return exact + Interval(-prec, prec); 1805 } 1806 1807 virtual double applyExact (double, double) const 1808 { 1809 TCU_THROW(InternalError, "Cannot apply"); 1810 } 1811 1812 virtual Interval getCodomain (void) const 1813 { 1814 return Interval::unbounded(true); 1815 } 1816 1817 virtual double precision (const EvalContext& ctx, 1818 double ret, 1819 double x, 1820 double y) const = 0; 1821 }; 1822 1823 class CFloatFunc2 : public FloatFunc2 1824 { 1825 public: 1826 CFloatFunc2 (const string& name, 1827 DoubleFunc2& func) 1828 : m_name(name) 1829 , m_func(func) 1830 { 1831 } 1832 1833 string getName (void) const { return m_name; } 1834 1835 protected: 1836 double applyExact (double x, double y) const { return m_func(x, y); } 1837 1838 const string m_name; 1839 DoubleFunc2& m_func; 1840 }; 1841 1842 class InfixOperator : public FloatFunc2 1843 { 1844 protected: 1845 virtual string getSymbol (void) const = 0; 1846 1847 void doPrint (ostream& os, const BaseArgExprs& args) const 1848 { 1849 os << "(" << *args[0] << " " << getSymbol() << " " << *args[1] << ")"; 1850 } 1851 1852 Interval applyPoint (const EvalContext& ctx, 1853 double x, 1854 double y) const 1855 { 1856 const double exact = this->applyExact(x, y); 1857 1858 // Allow either representable number on both sides of the exact value, 1859 // but require exactly representable values to be preserved. 1860 return ctx.format.roundOut(exact, !deIsInf(x) && !deIsInf(y)); 1861 } 1862 1863 double precision (const EvalContext&, double, double, double) const 1864 { 1865 return 0.0; 1866 } 1867 }; 1868 1869 class FloatFunc3 : public PrimitiveFunc<Signature<float, float, float, float> > 1870 { 1871 protected: 1872 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const 1873 { 1874 return this->applyMonotone(ctx, iargs.a, iargs.b, iargs.c); 1875 } 1876 1877 Interval applyMonotone (const EvalContext& ctx, 1878 const Interval& xi, 1879 const Interval& yi, 1880 const Interval& zi) const 1881 { 1882 Interval reti; 1883 TCU_INTERVAL_APPLY_MONOTONE3(reti, x, xi, y, yi, z, zi, ret, 1884 TCU_SET_INTERVAL(ret, point, 1885 point = this->applyPoint(ctx, x, y, z))); 1886 return ctx.format.convert(reti); 1887 } 1888 1889 virtual Interval applyPoint (const EvalContext& ctx, 1890 double x, 1891 double y, 1892 double z) const 1893 { 1894 const double exact = this->applyExact(x, y, z); 1895 const double prec = this->precision(ctx, exact, x, y, z); 1896 return exact + Interval(-prec, prec); 1897 } 1898 1899 virtual double applyExact (double, double, double) const 1900 { 1901 TCU_THROW(InternalError, "Cannot apply"); 1902 } 1903 1904 virtual double precision (const EvalContext& ctx, 1905 double result, 1906 double x, 1907 double y, 1908 double z) const = 0; 1909 }; 1910 1911 // We define syntactic sugar functions for expression constructors. Since 1912 // these have the same names as ordinary mathematical operations (sin, log 1913 // etc.), it's better to give them a dedicated namespace. 1914 namespace Functions 1915 { 1916 1917 using namespace tcu; 1918 1919 class Add : public InfixOperator 1920 { 1921 public: 1922 string getName (void) const { return "add"; } 1923 string getSymbol (void) const { return "+"; } 1924 1925 Interval doApply (const EvalContext& ctx, 1926 const IArgs& iargs) const 1927 { 1928 // Fast-path for common case 1929 if (iargs.a.isOrdinary() && iargs.b.isOrdinary()) 1930 { 1931 Interval ret; 1932 TCU_SET_INTERVAL_BOUNDS(ret, sum, 1933 sum = iargs.a.lo() + iargs.b.lo(), 1934 sum = iargs.a.hi() + iargs.b.hi()); 1935 return ctx.format.convert(ctx.format.roundOut(ret, true)); 1936 } 1937 return this->applyMonotone(ctx, iargs.a, iargs.b); 1938 } 1939 1940 protected: 1941 double applyExact (double x, double y) const { return x + y; } 1942 }; 1943 1944 class Mul : public InfixOperator 1945 { 1946 public: 1947 string getName (void) const { return "mul"; } 1948 string getSymbol (void) const { return "*"; } 1949 1950 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const 1951 { 1952 Interval a = iargs.a; 1953 Interval b = iargs.b; 1954 1955 // Fast-path for common case 1956 if (a.isOrdinary() && b.isOrdinary()) 1957 { 1958 Interval ret; 1959 if (a.hi() < 0) 1960 { 1961 a = -a; 1962 b = -b; 1963 } 1964 if (a.lo() >= 0 && b.lo() >= 0) 1965 { 1966 TCU_SET_INTERVAL_BOUNDS(ret, prod, 1967 prod = iargs.a.lo() * iargs.b.lo(), 1968 prod = iargs.a.hi() * iargs.b.hi()); 1969 return ctx.format.convert(ctx.format.roundOut(ret, true)); 1970 } 1971 if (a.lo() >= 0 && b.hi() <= 0) 1972 { 1973 TCU_SET_INTERVAL_BOUNDS(ret, prod, 1974 prod = iargs.a.hi() * iargs.b.lo(), 1975 prod = iargs.a.lo() * iargs.b.hi()); 1976 return ctx.format.convert(ctx.format.roundOut(ret, true)); 1977 } 1978 } 1979 return this->applyMonotone(ctx, iargs.a, iargs.b); 1980 } 1981 1982 protected: 1983 double applyExact (double x, double y) const { return x * y; } 1984 1985 Interval innerExtrema(const EvalContext&, const Interval& xi, const Interval& yi) const 1986 { 1987 if (((xi.contains(-TCU_INFINITY) || xi.contains(TCU_INFINITY)) && yi.contains(0.0)) || 1988 ((yi.contains(-TCU_INFINITY) || yi.contains(TCU_INFINITY)) && xi.contains(0.0))) 1989 return Interval(TCU_NAN); 1990 1991 return Interval(); 1992 } 1993 }; 1994 1995 class Sub : public InfixOperator 1996 { 1997 public: 1998 string getName (void) const { return "sub"; } 1999 string getSymbol (void) const { return "-"; } 2000 2001 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const 2002 { 2003 // Fast-path for common case 2004 if (iargs.a.isOrdinary() && iargs.b.isOrdinary()) 2005 { 2006 Interval ret; 2007 2008 TCU_SET_INTERVAL_BOUNDS(ret, diff, 2009 diff = iargs.a.lo() - iargs.b.hi(), 2010 diff = iargs.a.hi() - iargs.b.lo()); 2011 return ctx.format.convert(ctx.format.roundOut(ret, true)); 2012 2013 } 2014 else 2015 { 2016 return this->applyMonotone(ctx, iargs.a, iargs.b); 2017 } 2018 } 2019 2020 protected: 2021 double applyExact (double x, double y) const { return x - y; } 2022 }; 2023 2024 class Negate : public FloatFunc1 2025 { 2026 public: 2027 string getName (void) const { return "_negate"; } 2028 void doPrint (ostream& os, const BaseArgExprs& args) const { os << "-" << *args[0]; } 2029 2030 protected: 2031 double precision (const EvalContext&, double, double) const { return 0.0; } 2032 double applyExact (double x) const { return -x; } 2033 }; 2034 2035 class Div : public InfixOperator 2036 { 2037 public: 2038 string getName (void) const { return "div"; } 2039 2040 protected: 2041 string getSymbol (void) const { return "/"; } 2042 2043 Interval innerExtrema (const EvalContext&, 2044 const Interval& nom, 2045 const Interval& den) const 2046 { 2047 Interval ret; 2048 2049 if (den.contains(0.0)) 2050 { 2051 if (nom.contains(0.0)) 2052 ret |= TCU_NAN; 2053 2054 if (nom.lo() < 0.0 || nom.hi() > 0.0) 2055 ret |= Interval::unbounded(); 2056 } 2057 2058 return ret; 2059 } 2060 2061 double applyExact (double x, double y) const { return x / y; } 2062 2063 Interval applyPoint (const EvalContext& ctx, double x, double y) const 2064 { 2065 Interval ret = FloatFunc2::applyPoint(ctx, x, y); 2066 2067 if (!deIsInf(x) && !deIsInf(y) && y != 0.0) 2068 { 2069 const Interval dst = ctx.format.convert(ret); 2070 if (dst.contains(-TCU_INFINITY)) ret |= -ctx.format.getMaxValue(); 2071 if (dst.contains(+TCU_INFINITY)) ret |= +ctx.format.getMaxValue(); 2072 } 2073 2074 return ret; 2075 } 2076 2077 double precision (const EvalContext& ctx, double ret, double, double den) const 2078 { 2079 const FloatFormat& fmt = ctx.format; 2080 2081 // \todo [2014-03-05 lauri] Check that the limits in GLSL 3.10 are actually correct. 2082 // For now, we assume that division's precision is 2.5 ULP when the value is within 2083 // [2^MINEXP, 2^MAXEXP-1] 2084 2085 if (den == 0.0) 2086 return 0.0; // Result must be exactly inf 2087 else if (de::inBounds(deAbs(den), 2088 deLdExp(1.0, fmt.getMinExp()), 2089 deLdExp(1.0, fmt.getMaxExp() - 1))) 2090 return fmt.ulp(ret, 2.5); 2091 else 2092 return TCU_INFINITY; // Can be any number, but must be a number. 2093 } 2094 }; 2095 2096 class InverseSqrt : public FloatFunc1 2097 { 2098 public: 2099 string getName (void) const { return "inversesqrt"; } 2100 2101 protected: 2102 double applyExact (double x) const { return 1.0 / deSqrt(x); } 2103 2104 double precision (const EvalContext& ctx, double ret, double x) const 2105 { 2106 return x <= 0 ? TCU_NAN : ctx.format.ulp(ret, 2.0); 2107 } 2108 2109 Interval getCodomain (void) const 2110 { 2111 return Interval(0.0, TCU_INFINITY); 2112 } 2113 }; 2114 2115 class ExpFunc : public CFloatFunc1 2116 { 2117 public: 2118 ExpFunc (const string& name, DoubleFunc1& func) 2119 : CFloatFunc1(name, func) {} 2120 protected: 2121 double precision (const EvalContext& ctx, double ret, double x) const 2122 { 2123 switch (ctx.floatPrecision) 2124 { 2125 case glu::PRECISION_HIGHP: 2126 return ctx.format.ulp(ret, 3.0 + 2.0 * deAbs(x)); 2127 case glu::PRECISION_MEDIUMP: 2128 return ctx.format.ulp(ret, 2.0 + 2.0 * deAbs(x)); 2129 case glu::PRECISION_LOWP: 2130 return ctx.format.ulp(ret, 2.0); 2131 default: 2132 DE_FATAL("Impossible"); 2133 } 2134 return 0; 2135 } 2136 2137 Interval getCodomain (void) const 2138 { 2139 return Interval(0.0, TCU_INFINITY); 2140 } 2141 }; 2142 2143 class Exp2 : public ExpFunc { public: Exp2 (void) : ExpFunc("exp2", deExp2) {} }; 2144 class Exp : public ExpFunc { public: Exp (void) : ExpFunc("exp", deExp) {} }; 2145 2146 ExprP<float> exp2 (const ExprP<float>& x) { return app<Exp2>(x); } 2147 ExprP<float> exp (const ExprP<float>& x) { return app<Exp>(x); } 2148 2149 class LogFunc : public CFloatFunc1 2150 { 2151 public: 2152 LogFunc (const string& name, DoubleFunc1& func) 2153 : CFloatFunc1(name, func) {} 2154 2155 protected: 2156 double precision (const EvalContext& ctx, double ret, double x) const 2157 { 2158 if (x <= 0) 2159 return TCU_NAN; 2160 2161 switch (ctx.floatPrecision) 2162 { 2163 case glu::PRECISION_HIGHP: 2164 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -21) : ctx.format.ulp(ret, 3.0); 2165 case glu::PRECISION_MEDIUMP: 2166 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -7) : ctx.format.ulp(ret, 2.0); 2167 case glu::PRECISION_LOWP: 2168 return ctx.format.ulp(ret, 2.0); 2169 default: 2170 DE_FATAL("Impossible"); 2171 } 2172 2173 return 0; 2174 } 2175 2176 // OpenGL API Issue #57 "Clarifying the required ULP precision for GLSL built-in log()". Agreed that 2177 // implementations will be allowed 4 ULPs for HIGHP Log/Log2, but CTS should generate a quality warning. 2178 double warningPrecision(const EvalContext& ctx, double ret, double x) const 2179 { 2180 if (ctx.floatPrecision == glu::PRECISION_HIGHP && x > 0) 2181 { 2182 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -21) : ctx.format.ulp(ret, 4.0); 2183 } 2184 else 2185 { 2186 return precision(ctx, ret, x); 2187 } 2188 } 2189 2190 }; 2191 2192 class Log2 : public LogFunc { public: Log2 (void) : LogFunc("log2", deLog2) {} }; 2193 class Log : public LogFunc { public: Log (void) : LogFunc("log", deLog) {} }; 2194 2195 ExprP<float> log2 (const ExprP<float>& x) { return app<Log2>(x); } 2196 ExprP<float> log (const ExprP<float>& x) { return app<Log>(x); } 2197 2198 #define DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0) \ 2199 ExprP<TRET> NAME (const ExprP<T0>& arg0) { return app<CLASS>(arg0); } 2200 2201 #define DEFINE_DERIVED1(CLASS, TRET, NAME, T0, ARG0, EXPANSION) \ 2202 class CLASS : public DerivedFunc<Signature<TRET, T0> > /* NOLINT(CLASS) */ \ 2203 { \ 2204 public: \ 2205 string getName (void) const { return #NAME; } \ 2206 \ 2207 protected: \ 2208 ExprP<TRET> doExpand (ExpandContext&, \ 2209 const CLASS::ArgExprs& args_) const \ 2210 { \ 2211 const ExprP<float>& (ARG0) = args_.a; \ 2212 return EXPANSION; \ 2213 } \ 2214 }; \ 2215 DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0) 2216 2217 #define DEFINE_DERIVED_FLOAT1(CLASS, NAME, ARG0, EXPANSION) \ 2218 DEFINE_DERIVED1(CLASS, float, NAME, float, ARG0, EXPANSION) 2219 2220 #define DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1) \ 2221 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1) \ 2222 { \ 2223 return app<CLASS>(arg0, arg1); \ 2224 } 2225 2226 #define DEFINE_DERIVED2(CLASS, TRET, NAME, T0, Arg0, T1, Arg1, EXPANSION) \ 2227 class CLASS : public DerivedFunc<Signature<TRET, T0, T1> > /* NOLINT(CLASS) */ \ 2228 { \ 2229 public: \ 2230 string getName (void) const { return #NAME; } \ 2231 \ 2232 protected: \ 2233 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \ 2234 { \ 2235 const ExprP<T0>& (Arg0) = args_.a; \ 2236 const ExprP<T1>& (Arg1) = args_.b; \ 2237 return EXPANSION; \ 2238 } \ 2239 }; \ 2240 DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1) 2241 2242 #define DEFINE_DERIVED_FLOAT2(CLASS, NAME, Arg0, Arg1, EXPANSION) \ 2243 DEFINE_DERIVED2(CLASS, float, NAME, float, Arg0, float, Arg1, EXPANSION) 2244 2245 #define DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2) \ 2246 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, const ExprP<T2>& arg2) \ 2247 { \ 2248 return app<CLASS>(arg0, arg1, arg2); \ 2249 } 2250 2251 #define DEFINE_DERIVED3(CLASS, TRET, NAME, T0, ARG0, T1, ARG1, T2, ARG2, EXPANSION) \ 2252 class CLASS : public DerivedFunc<Signature<TRET, T0, T1, T2> > /* NOLINT(CLASS) */ \ 2253 { \ 2254 public: \ 2255 string getName (void) const { return #NAME; } \ 2256 \ 2257 protected: \ 2258 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \ 2259 { \ 2260 const ExprP<T0>& (ARG0) = args_.a; \ 2261 const ExprP<T1>& (ARG1) = args_.b; \ 2262 const ExprP<T2>& (ARG2) = args_.c; \ 2263 return EXPANSION; \ 2264 } \ 2265 }; \ 2266 DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2) 2267 2268 #define DEFINE_DERIVED_FLOAT3(CLASS, NAME, ARG0, ARG1, ARG2, EXPANSION) \ 2269 DEFINE_DERIVED3(CLASS, float, NAME, float, ARG0, float, ARG1, float, ARG2, EXPANSION) 2270 2271 #define DEFINE_CONSTRUCTOR4(CLASS, TRET, NAME, T0, T1, T2, T3) \ 2272 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, \ 2273 const ExprP<T2>& arg2, const ExprP<T3>& arg3) \ 2274 { \ 2275 return app<CLASS>(arg0, arg1, arg2, arg3); \ 2276 } 2277 2278 DEFINE_DERIVED_FLOAT1(Sqrt, sqrt, x, constant(1.0f) / app<InverseSqrt>(x)); 2279 DEFINE_DERIVED_FLOAT2(Pow, pow, x, y, exp2(y * log2(x))); 2280 DEFINE_DERIVED_FLOAT1(Radians, radians, d, (constant(DE_PI) / constant(180.0f)) * d); 2281 DEFINE_DERIVED_FLOAT1(Degrees, degrees, r, (constant(180.0f) / constant(DE_PI)) * r); 2282 2283 class TrigFunc : public CFloatFunc1 2284 { 2285 public: 2286 TrigFunc (const string& name, 2287 DoubleFunc1& func, 2288 const Interval& loEx, 2289 const Interval& hiEx) 2290 : CFloatFunc1 (name, func) 2291 , m_loExtremum (loEx) 2292 , m_hiExtremum (hiEx) {} 2293 2294 protected: 2295 Interval innerExtrema (const EvalContext&, const Interval& angle) const 2296 { 2297 const double lo = angle.lo(); 2298 const double hi = angle.hi(); 2299 const int loSlope = doGetSlope(lo); 2300 const int hiSlope = doGetSlope(hi); 2301 2302 // Detect the high and low values the function can take between the 2303 // interval endpoints. 2304 if (angle.length() >= 2.0 * DE_PI_DOUBLE) 2305 { 2306 // The interval is longer than a full cycle, so it must get all possible values. 2307 return m_hiExtremum | m_loExtremum; 2308 } 2309 else if (loSlope == 1 && hiSlope == -1) 2310 { 2311 // The slope can change from positive to negative only at the maximum value. 2312 return m_hiExtremum; 2313 } 2314 else if (loSlope == -1 && hiSlope == 1) 2315 { 2316 // The slope can change from negative to positive only at the maximum value. 2317 return m_loExtremum; 2318 } 2319 else if (loSlope == hiSlope && 2320 deIntSign(applyExact(hi) - applyExact(lo)) * loSlope == -1) 2321 { 2322 // The slope has changed twice between the endpoints, so both extrema are included. 2323 return m_hiExtremum | m_loExtremum; 2324 } 2325 2326 return Interval(); 2327 } 2328 2329 Interval getCodomain (void) const 2330 { 2331 // Ensure that result is always within [-1, 1], or NaN (for +-inf) 2332 return Interval(-1.0, 1.0) | TCU_NAN; 2333 } 2334 2335 double precision (const EvalContext& ctx, double ret, double arg) const 2336 { 2337 if (ctx.floatPrecision == glu::PRECISION_HIGHP) 2338 { 2339 // Use precision from OpenCL fast relaxed math 2340 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE) 2341 { 2342 return deLdExp(1.0, -11); 2343 } 2344 else 2345 { 2346 // "larger otherwise", let's pick |x| * 2^-12 , which is slightly over 2347 // 2^-11 at x == pi. 2348 return deLdExp(deAbs(arg), -12); 2349 } 2350 } 2351 else if (ctx.floatPrecision == glu::PRECISION_MEDIUMP) 2352 { 2353 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE) 2354 { 2355 // from OpenCL half-float extension specification 2356 return ctx.format.ulp(ret, 2.0); 2357 } 2358 else 2359 { 2360 // |x| * 2^-10, slightly larger than 2 ULP at x == pi 2361 return deLdExp(deAbs(arg), -10); 2362 } 2363 } 2364 else 2365 { 2366 DE_ASSERT(ctx.floatPrecision == glu::PRECISION_LOWP); 2367 2368 // from OpenCL half-float extension specification 2369 return ctx.format.ulp(ret, 2.0); 2370 } 2371 } 2372 2373 virtual int doGetSlope (double angle) const = 0; 2374 2375 Interval m_loExtremum; 2376 Interval m_hiExtremum; 2377 }; 2378 2379 class Sin : public TrigFunc 2380 { 2381 public: 2382 Sin (void) : TrigFunc("sin", deSin, -1.0, 1.0) {} 2383 2384 protected: 2385 int doGetSlope (double angle) const { return deIntSign(deCos(angle)); } 2386 }; 2387 2388 ExprP<float> sin (const ExprP<float>& x) { return app<Sin>(x); } 2389 2390 class Cos : public TrigFunc 2391 { 2392 public: 2393 Cos (void) : TrigFunc("cos", deCos, -1.0, 1.0) {} 2394 2395 protected: 2396 int doGetSlope (double angle) const { return -deIntSign(deSin(angle)); } 2397 }; 2398 2399 ExprP<float> cos (const ExprP<float>& x) { return app<Cos>(x); } 2400 2401 DEFINE_DERIVED_FLOAT1(Tan, tan, x, sin(x) * (constant(1.0f) / cos(x))); 2402 2403 class ASin : public CFloatFunc1 2404 { 2405 public: 2406 ASin (void) : CFloatFunc1("asin", deAsin) {} 2407 2408 protected: 2409 double precision (const EvalContext& ctx, double, double x) const 2410 { 2411 if (!de::inBounds(x, -1.0, 1.0)) 2412 return TCU_NAN; 2413 2414 if (ctx.floatPrecision == glu::PRECISION_HIGHP) 2415 { 2416 // Absolute error of 2^-11 2417 return deLdExp(1.0, -11); 2418 } 2419 else 2420 { 2421 // Absolute error of 2^-8 2422 return deLdExp(1.0, -8); 2423 } 2424 2425 } 2426 }; 2427 2428 class ArcTrigFunc : public CFloatFunc1 2429 { 2430 public: 2431 ArcTrigFunc (const string& name, 2432 DoubleFunc1& func, 2433 double precisionULPs, 2434 const Interval& domain, 2435 const Interval& codomain) 2436 : CFloatFunc1 (name, func) 2437 , m_precision (precisionULPs) 2438 , m_domain (domain) 2439 , m_codomain (codomain) {} 2440 2441 protected: 2442 double precision (const EvalContext& ctx, double ret, double x) const 2443 { 2444 if (!m_domain.contains(x)) 2445 return TCU_NAN; 2446 2447 if (ctx.floatPrecision == glu::PRECISION_HIGHP) 2448 { 2449 // Use OpenCL's fast relaxed math precision 2450 return ctx.format.ulp(ret, m_precision); 2451 } 2452 else 2453 { 2454 // Use OpenCL half-float spec 2455 return ctx.format.ulp(ret, 2.0); 2456 } 2457 } 2458 2459 // We could implement getCodomain with m_codomain, but choose not to, 2460 // because it seems too strict with trascendental constants like pi. 2461 2462 const double m_precision; 2463 const Interval m_domain; 2464 const Interval m_codomain; 2465 }; 2466 2467 class ACos : public ArcTrigFunc 2468 { 2469 public: 2470 ACos (void) : ArcTrigFunc("acos", deAcos, 4096.0, 2471 Interval(-1.0, 1.0), 2472 Interval(0.0, DE_PI_DOUBLE)) {} 2473 }; 2474 2475 class ATan : public ArcTrigFunc 2476 { 2477 public: 2478 ATan (void) : ArcTrigFunc("atan", deAtanOver, 4096.0, 2479 Interval::unbounded(), 2480 Interval(-DE_PI_DOUBLE * 0.5, DE_PI_DOUBLE * 0.5)) {} 2481 }; 2482 2483 class ATan2 : public CFloatFunc2 2484 { 2485 public: 2486 ATan2 (void) : CFloatFunc2 ("atan", deAtan2) {} 2487 2488 protected: 2489 Interval innerExtrema (const EvalContext& ctx, 2490 const Interval& yi, 2491 const Interval& xi) const 2492 { 2493 Interval ret; 2494 2495 if (yi.contains(0.0)) 2496 { 2497 if (xi.contains(0.0)) 2498 ret |= TCU_NAN; 2499 if (xi.intersects(Interval(-TCU_INFINITY, 0.0))) 2500 ret |= Interval(-DE_PI_DOUBLE, DE_PI_DOUBLE); 2501 } 2502 2503 if (ctx.format.hasInf() != YES && (!yi.isFinite() || !xi.isFinite())) 2504 { 2505 // Infinities may not be supported, allow anything, including NaN 2506 ret |= TCU_NAN; 2507 } 2508 2509 return ret; 2510 } 2511 2512 double precision (const EvalContext& ctx, double ret, double, double) const 2513 { 2514 if (ctx.floatPrecision == glu::PRECISION_HIGHP) 2515 return ctx.format.ulp(ret, 4096.0); 2516 else 2517 return ctx.format.ulp(ret, 2.0); 2518 } 2519 2520 // Codomain could be [-pi, pi], but that would probably be too strict. 2521 }; 2522 2523 DEFINE_DERIVED_FLOAT1(Sinh, sinh, x, (exp(x) - exp(-x)) / constant(2.0f)); 2524 DEFINE_DERIVED_FLOAT1(Cosh, cosh, x, (exp(x) + exp(-x)) / constant(2.0f)); 2525 DEFINE_DERIVED_FLOAT1(Tanh, tanh, x, sinh(x) / cosh(x)); 2526 2527 // These are not defined as derived forms in the GLSL ES spec, but 2528 // that gives us a reasonable precision. 2529 DEFINE_DERIVED_FLOAT1(ASinh, asinh, x, log(x + sqrt(x * x + constant(1.0f)))); 2530 DEFINE_DERIVED_FLOAT1(ACosh, acosh, x, log(x + sqrt(alternatives((x + constant(1.0f)) * (x - constant(1.0f)), 2531 (x*x - constant(1.0f)))))); 2532 DEFINE_DERIVED_FLOAT1(ATanh, atanh, x, constant(0.5f) * log((constant(1.0f) + x) / 2533 (constant(1.0f) - x))); 2534 2535 template <typename T> 2536 class GetComponent : public PrimitiveFunc<Signature<typename T::Element, T, int> > 2537 { 2538 public: 2539 typedef typename GetComponent::IRet IRet; 2540 2541 string getName (void) const { return "_getComponent"; } 2542 2543 void print (ostream& os, 2544 const BaseArgExprs& args) const 2545 { 2546 os << *args[0] << "[" << *args[1] << "]"; 2547 } 2548 2549 protected: 2550 IRet doApply (const EvalContext&, 2551 const typename GetComponent::IArgs& iargs) const 2552 { 2553 IRet ret; 2554 2555 for (int compNdx = 0; compNdx < T::SIZE; ++compNdx) 2556 { 2557 if (iargs.b.contains(compNdx)) 2558 ret = unionIVal<typename T::Element>(ret, iargs.a[compNdx]); 2559 } 2560 2561 return ret; 2562 } 2563 2564 }; 2565 2566 template <typename T> 2567 ExprP<typename T::Element> getComponent (const ExprP<T>& container, int ndx) 2568 { 2569 DE_ASSERT(0 <= ndx && ndx < T::SIZE); 2570 return app<GetComponent<T> >(container, constant(ndx)); 2571 } 2572 2573 template <typename T> string vecNamePrefix (void); 2574 template <> string vecNamePrefix<float> (void) { return ""; } 2575 template <> string vecNamePrefix<int> (void) { return "i"; } 2576 template <> string vecNamePrefix<bool> (void) { return "b"; } 2577 2578 template <typename T, int Size> 2579 string vecName (void) { return vecNamePrefix<T>() + "vec" + de::toString(Size); } 2580 2581 template <typename T, int Size> class GenVec; 2582 2583 template <typename T> 2584 class GenVec<T, 1> : public DerivedFunc<Signature<T, T> > 2585 { 2586 public: 2587 typedef typename GenVec<T, 1>::ArgExprs ArgExprs; 2588 2589 string getName (void) const 2590 { 2591 return "_" + vecName<T, 1>(); 2592 } 2593 2594 protected: 2595 2596 ExprP<T> doExpand (ExpandContext&, const ArgExprs& args) const { return args.a; } 2597 }; 2598 2599 template <typename T> 2600 class GenVec<T, 2> : public PrimitiveFunc<Signature<Vector<T, 2>, T, T> > 2601 { 2602 public: 2603 typedef typename GenVec::IRet IRet; 2604 typedef typename GenVec::IArgs IArgs; 2605 2606 string getName (void) const 2607 { 2608 return vecName<T, 2>(); 2609 } 2610 2611 protected: 2612 IRet doApply (const EvalContext&, const IArgs& iargs) const 2613 { 2614 return IRet(iargs.a, iargs.b); 2615 } 2616 }; 2617 2618 template <typename T> 2619 class GenVec<T, 3> : public PrimitiveFunc<Signature<Vector<T, 3>, T, T, T> > 2620 { 2621 public: 2622 typedef typename GenVec::IRet IRet; 2623 typedef typename GenVec::IArgs IArgs; 2624 2625 string getName (void) const 2626 { 2627 return vecName<T, 3>(); 2628 } 2629 2630 protected: 2631 IRet doApply (const EvalContext&, const IArgs& iargs) const 2632 { 2633 return IRet(iargs.a, iargs.b, iargs.c); 2634 } 2635 }; 2636 2637 template <typename T> 2638 class GenVec<T, 4> : public PrimitiveFunc<Signature<Vector<T, 4>, T, T, T, T> > 2639 { 2640 public: 2641 typedef typename GenVec::IRet IRet; 2642 typedef typename GenVec::IArgs IArgs; 2643 2644 string getName (void) const { return vecName<T, 4>(); } 2645 2646 protected: 2647 IRet doApply (const EvalContext&, const IArgs& iargs) const 2648 { 2649 return IRet(iargs.a, iargs.b, iargs.c, iargs.d); 2650 } 2651 }; 2652 2653 2654 2655 template <typename T, int Rows, int Columns> 2656 class GenMat; 2657 2658 template <typename T, int Rows> 2659 class GenMat<T, Rows, 2> : public PrimitiveFunc< 2660 Signature<Matrix<T, Rows, 2>, Vector<T, Rows>, Vector<T, Rows> > > 2661 { 2662 public: 2663 typedef typename GenMat::Ret Ret; 2664 typedef typename GenMat::IRet IRet; 2665 typedef typename GenMat::IArgs IArgs; 2666 2667 string getName (void) const 2668 { 2669 return dataTypeNameOf<Ret>(); 2670 } 2671 2672 protected: 2673 2674 IRet doApply (const EvalContext&, const IArgs& iargs) const 2675 { 2676 IRet ret; 2677 ret[0] = iargs.a; 2678 ret[1] = iargs.b; 2679 return ret; 2680 } 2681 }; 2682 2683 template <typename T, int Rows> 2684 class GenMat<T, Rows, 3> : public PrimitiveFunc< 2685 Signature<Matrix<T, Rows, 3>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > > 2686 { 2687 public: 2688 typedef typename GenMat::Ret Ret; 2689 typedef typename GenMat::IRet IRet; 2690 typedef typename GenMat::IArgs IArgs; 2691 2692 string getName (void) const 2693 { 2694 return dataTypeNameOf<Ret>(); 2695 } 2696 2697 protected: 2698 2699 IRet doApply (const EvalContext&, const IArgs& iargs) const 2700 { 2701 IRet ret; 2702 ret[0] = iargs.a; 2703 ret[1] = iargs.b; 2704 ret[2] = iargs.c; 2705 return ret; 2706 } 2707 }; 2708 2709 template <typename T, int Rows> 2710 class GenMat<T, Rows, 4> : public PrimitiveFunc< 2711 Signature<Matrix<T, Rows, 4>, 2712 Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > > 2713 { 2714 public: 2715 typedef typename GenMat::Ret Ret; 2716 typedef typename GenMat::IRet IRet; 2717 typedef typename GenMat::IArgs IArgs; 2718 2719 string getName (void) const 2720 { 2721 return dataTypeNameOf<Ret>(); 2722 } 2723 2724 protected: 2725 IRet doApply (const EvalContext&, const IArgs& iargs) const 2726 { 2727 IRet ret; 2728 ret[0] = iargs.a; 2729 ret[1] = iargs.b; 2730 ret[2] = iargs.c; 2731 ret[3] = iargs.d; 2732 return ret; 2733 } 2734 }; 2735 2736 template <typename T, int Rows> 2737 ExprP<Matrix<T, Rows, 2> > mat2 (const ExprP<Vector<T, Rows> >& arg0, 2738 const ExprP<Vector<T, Rows> >& arg1) 2739 { 2740 return app<GenMat<T, Rows, 2> >(arg0, arg1); 2741 } 2742 2743 template <typename T, int Rows> 2744 ExprP<Matrix<T, Rows, 3> > mat3 (const ExprP<Vector<T, Rows> >& arg0, 2745 const ExprP<Vector<T, Rows> >& arg1, 2746 const ExprP<Vector<T, Rows> >& arg2) 2747 { 2748 return app<GenMat<T, Rows, 3> >(arg0, arg1, arg2); 2749 } 2750 2751 template <typename T, int Rows> 2752 ExprP<Matrix<T, Rows, 4> > mat4 (const ExprP<Vector<T, Rows> >& arg0, 2753 const ExprP<Vector<T, Rows> >& arg1, 2754 const ExprP<Vector<T, Rows> >& arg2, 2755 const ExprP<Vector<T, Rows> >& arg3) 2756 { 2757 return app<GenMat<T, Rows, 4> >(arg0, arg1, arg2, arg3); 2758 } 2759 2760 2761 template <int Rows, int Cols> 2762 class MatNeg : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>, 2763 Matrix<float, Rows, Cols> > > 2764 { 2765 public: 2766 typedef typename MatNeg::IRet IRet; 2767 typedef typename MatNeg::IArgs IArgs; 2768 2769 string getName (void) const 2770 { 2771 return "_matNeg"; 2772 } 2773 2774 protected: 2775 void doPrint (ostream& os, const BaseArgExprs& args) const 2776 { 2777 os << "-(" << *args[0] << ")"; 2778 } 2779 2780 IRet doApply (const EvalContext&, const IArgs& iargs) const 2781 { 2782 IRet ret; 2783 2784 for (int col = 0; col < Cols; ++col) 2785 { 2786 for (int row = 0; row < Rows; ++row) 2787 ret[col][row] = -iargs.a[col][row]; 2788 } 2789 2790 return ret; 2791 } 2792 }; 2793 2794 template <typename T, typename Sig> 2795 class CompWiseFunc : public PrimitiveFunc<Sig> 2796 { 2797 public: 2798 typedef Func<Signature<T, T, T> > ScalarFunc; 2799 2800 string getName (void) const 2801 { 2802 return doGetScalarFunc().getName(); 2803 } 2804 protected: 2805 void doPrint (ostream& os, 2806 const BaseArgExprs& args) const 2807 { 2808 doGetScalarFunc().print(os, args); 2809 } 2810 2811 virtual 2812 const ScalarFunc& doGetScalarFunc (void) const = 0; 2813 }; 2814 2815 template <int Rows, int Cols> 2816 class CompMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>, 2817 Matrix<float, Rows, Cols>, 2818 Matrix<float, Rows, Cols> > > 2819 { 2820 public: 2821 typedef typename CompMatFuncBase::IRet IRet; 2822 typedef typename CompMatFuncBase::IArgs IArgs; 2823 2824 protected: 2825 2826 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const 2827 { 2828 IRet ret; 2829 2830 for (int col = 0; col < Cols; ++col) 2831 { 2832 for (int row = 0; row < Rows; ++row) 2833 ret[col][row] = this->doGetScalarFunc().apply(ctx, 2834 iargs.a[col][row], 2835 iargs.b[col][row]); 2836 } 2837 2838 return ret; 2839 } 2840 }; 2841 2842 template <typename F, int Rows, int Cols> 2843 class CompMatFunc : public CompMatFuncBase<Rows, Cols> 2844 { 2845 protected: 2846 const typename CompMatFunc::ScalarFunc& doGetScalarFunc (void) const 2847 { 2848 return instance<F>(); 2849 } 2850 }; 2851 2852 class ScalarMatrixCompMult : public Mul 2853 { 2854 public: 2855 string getName (void) const 2856 { 2857 return "matrixCompMult"; 2858 } 2859 2860 void doPrint (ostream& os, const BaseArgExprs& args) const 2861 { 2862 Func<Sig>::doPrint(os, args); 2863 } 2864 }; 2865 2866 template <int Rows, int Cols> 2867 class MatrixCompMult : public CompMatFunc<ScalarMatrixCompMult, Rows, Cols> 2868 { 2869 }; 2870 2871 template <int Rows, int Cols> 2872 class ScalarMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>, 2873 Matrix<float, Rows, Cols>, 2874 float> > 2875 { 2876 public: 2877 typedef typename ScalarMatFuncBase::IRet IRet; 2878 typedef typename ScalarMatFuncBase::IArgs IArgs; 2879 2880 protected: 2881 2882 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const 2883 { 2884 IRet ret; 2885 2886 for (int col = 0; col < Cols; ++col) 2887 { 2888 for (int row = 0; row < Rows; ++row) 2889 ret[col][row] = this->doGetScalarFunc().apply(ctx, iargs.a[col][row], iargs.b); 2890 } 2891 2892 return ret; 2893 } 2894 }; 2895 2896 template <typename F, int Rows, int Cols> 2897 class ScalarMatFunc : public ScalarMatFuncBase<Rows, Cols> 2898 { 2899 protected: 2900 const typename ScalarMatFunc::ScalarFunc& doGetScalarFunc (void) const 2901 { 2902 return instance<F>(); 2903 } 2904 }; 2905 2906 template<typename T, int Size> struct GenXType; 2907 2908 template<typename T> 2909 struct GenXType<T, 1> 2910 { 2911 static ExprP<T> genXType (const ExprP<T>& x) { return x; } 2912 }; 2913 2914 template<typename T> 2915 struct GenXType<T, 2> 2916 { 2917 static ExprP<Vector<T, 2> > genXType (const ExprP<T>& x) 2918 { 2919 return app<GenVec<T, 2> >(x, x); 2920 } 2921 }; 2922 2923 template<typename T> 2924 struct GenXType<T, 3> 2925 { 2926 static ExprP<Vector<T, 3> > genXType (const ExprP<T>& x) 2927 { 2928 return app<GenVec<T, 3> >(x, x, x); 2929 } 2930 }; 2931 2932 template<typename T> 2933 struct GenXType<T, 4> 2934 { 2935 static ExprP<Vector<T, 4> > genXType (const ExprP<T>& x) 2936 { 2937 return app<GenVec<T, 4> >(x, x, x, x); 2938 } 2939 }; 2940 2941 //! Returns an expression of vector of size `Size` (or scalar if Size == 1), 2942 //! with each element initialized with the expression `x`. 2943 template<typename T, int Size> 2944 ExprP<typename ContainerOf<T, Size>::Container> genXType (const ExprP<T>& x) 2945 { 2946 return GenXType<T, Size>::genXType(x); 2947 } 2948 2949 typedef GenVec<float, 2> FloatVec2; 2950 DEFINE_CONSTRUCTOR2(FloatVec2, Vec2, vec2, float, float) 2951 2952 typedef GenVec<float, 3> FloatVec3; 2953 DEFINE_CONSTRUCTOR3(FloatVec3, Vec3, vec3, float, float, float) 2954 2955 typedef GenVec<float, 4> FloatVec4; 2956 DEFINE_CONSTRUCTOR4(FloatVec4, Vec4, vec4, float, float, float, float) 2957 2958 template <int Size> 2959 class Dot : public DerivedFunc<Signature<float, Vector<float, Size>, Vector<float, Size> > > 2960 { 2961 public: 2962 typedef typename Dot::ArgExprs ArgExprs; 2963 2964 string getName (void) const 2965 { 2966 return "dot"; 2967 } 2968 2969 protected: 2970 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const 2971 { 2972 ExprP<float> op[Size]; 2973 // Precompute all products. 2974 for (int ndx = 0; ndx < Size; ++ndx) 2975 op[ndx] = args.a[ndx] * args.b[ndx]; 2976 2977 int idx[Size]; 2978 //Prepare an array of indices. 2979 for (int ndx = 0; ndx < Size; ++ndx) 2980 idx[ndx] = ndx; 2981 2982 ExprP<float> res = op[0]; 2983 // Compute the first dot alternative: SUM(a[i]*b[i]), i = 0 .. Size-1 2984 for (int ndx = 1; ndx < Size; ++ndx) 2985 res = res + op[ndx]; 2986 2987 // Generate all permutations of indices and 2988 // using a permutation compute a dot alternative. 2989 // Generates all possible variants fo summation of products in the dot product expansion expression. 2990 do { 2991 ExprP<float> alt = constant(0.0f); 2992 for (int ndx = 0; ndx < Size; ++ndx) 2993 alt = alt + op[idx[ndx]]; 2994 res = alternatives(res, alt); 2995 } while (std::next_permutation(idx, idx + Size)); 2996 2997 return res; 2998 } 2999 }; 3000 3001 template <> 3002 class Dot<1> : public DerivedFunc<Signature<float, float, float> > 3003 { 3004 public: 3005 string getName (void) const 3006 { 3007 return "dot"; 3008 } 3009 3010 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const 3011 { 3012 return args.a * args.b; 3013 } 3014 }; 3015 3016 template <int Size> 3017 ExprP<float> dot (const ExprP<Vector<float, Size> >& x, const ExprP<Vector<float, Size> >& y) 3018 { 3019 return app<Dot<Size> >(x, y); 3020 } 3021 3022 ExprP<float> dot (const ExprP<float>& x, const ExprP<float>& y) 3023 { 3024 return app<Dot<1> >(x, y); 3025 } 3026 3027 template <int Size> 3028 class Length : public DerivedFunc< 3029 Signature<float, typename ContainerOf<float, Size>::Container> > 3030 { 3031 public: 3032 typedef typename Length::ArgExprs ArgExprs; 3033 3034 string getName (void) const 3035 { 3036 return "length"; 3037 } 3038 3039 protected: 3040 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const 3041 { 3042 return sqrt(dot(args.a, args.a)); 3043 } 3044 }; 3045 3046 template <int Size> 3047 ExprP<float> length (const ExprP<typename ContainerOf<float, Size>::Container>& x) 3048 { 3049 return app<Length<Size> >(x); 3050 } 3051 3052 template <int Size> 3053 class Distance : public DerivedFunc< 3054 Signature<float, 3055 typename ContainerOf<float, Size>::Container, 3056 typename ContainerOf<float, Size>::Container> > 3057 { 3058 public: 3059 typedef typename Distance::Ret Ret; 3060 typedef typename Distance::ArgExprs ArgExprs; 3061 3062 string getName (void) const 3063 { 3064 return "distance"; 3065 } 3066 3067 protected: 3068 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const 3069 { 3070 return length<Size>(args.a - args.b); 3071 } 3072 }; 3073 3074 // cross 3075 3076 class Cross : public DerivedFunc<Signature<Vec3, Vec3, Vec3> > 3077 { 3078 public: 3079 string getName (void) const 3080 { 3081 return "cross"; 3082 } 3083 3084 protected: 3085 ExprP<Vec3> doExpand (ExpandContext&, const ArgExprs& x) const 3086 { 3087 return vec3(x.a[1] * x.b[2] - x.b[1] * x.a[2], 3088 x.a[2] * x.b[0] - x.b[2] * x.a[0], 3089 x.a[0] * x.b[1] - x.b[0] * x.a[1]); 3090 } 3091 }; 3092 3093 DEFINE_CONSTRUCTOR2(Cross, Vec3, cross, Vec3, Vec3) 3094 3095 template<int Size> 3096 class Normalize : public DerivedFunc< 3097 Signature<typename ContainerOf<float, Size>::Container, 3098 typename ContainerOf<float, Size>::Container> > 3099 { 3100 public: 3101 typedef typename Normalize::Ret Ret; 3102 typedef typename Normalize::ArgExprs ArgExprs; 3103 3104 string getName (void) const 3105 { 3106 return "normalize"; 3107 } 3108 3109 protected: 3110 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const 3111 { 3112 return args.a / length<Size>(args.a); 3113 } 3114 }; 3115 3116 template <int Size> 3117 class FaceForward : public DerivedFunc< 3118 Signature<typename ContainerOf<float, Size>::Container, 3119 typename ContainerOf<float, Size>::Container, 3120 typename ContainerOf<float, Size>::Container, 3121 typename ContainerOf<float, Size>::Container> > 3122 { 3123 public: 3124 typedef typename FaceForward::Ret Ret; 3125 typedef typename FaceForward::ArgExprs ArgExprs; 3126 3127 string getName (void) const 3128 { 3129 return "faceforward"; 3130 } 3131 3132 protected: 3133 3134 3135 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const 3136 { 3137 return cond(dot(args.c, args.b) < constant(0.0f), args.a, -args.a); 3138 } 3139 }; 3140 3141 template<int Size, typename Ret, typename Arg0, typename Arg1> 3142 struct ApplyReflect 3143 { 3144 static ExprP<Ret> apply (ExpandContext& ctx, 3145 const ExprP<Arg0>& i, 3146 const ExprP<Arg1>& n) 3147 { 3148 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i)); 3149 3150 return i - alternatives((n * dotNI) * constant(2.0f), 3151 n * (dotNI * constant(2.0f))); 3152 }; 3153 }; 3154 3155 template<typename Ret, typename Arg0, typename Arg1> 3156 struct ApplyReflect<1, Ret, Arg0, Arg1> 3157 { 3158 static ExprP<Ret> apply (ExpandContext&, 3159 const ExprP<Arg0>& i, 3160 const ExprP<Arg1>& n) 3161 { 3162 return i - alternatives(alternatives((n * (n*i)) * constant(2.0f), 3163 n * ((n*i) * constant(2.0f))), 3164 (n * n) * (i * constant(2.0f))); 3165 }; 3166 }; 3167 3168 template <int Size> 3169 class Reflect : public DerivedFunc< 3170 Signature<typename ContainerOf<float, Size>::Container, 3171 typename ContainerOf<float, Size>::Container, 3172 typename ContainerOf<float, Size>::Container> > 3173 { 3174 public: 3175 typedef typename Reflect::Ret Ret; 3176 typedef typename Reflect::Arg0 Arg0; 3177 typedef typename Reflect::Arg1 Arg1; 3178 typedef typename Reflect::ArgExprs ArgExprs; 3179 3180 string getName (void) const 3181 { 3182 return "reflect"; 3183 } 3184 3185 protected: 3186 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const 3187 { 3188 const ExprP<Arg0>& i = args.a; 3189 const ExprP<Arg1>& n = args.b; 3190 3191 return ApplyReflect<Size, Ret, Arg0, Arg1>::apply(ctx, i, n); 3192 } 3193 }; 3194 3195 template <int Size> 3196 class Refract : public DerivedFunc< 3197 Signature<typename ContainerOf<float, Size>::Container, 3198 typename ContainerOf<float, Size>::Container, 3199 typename ContainerOf<float, Size>::Container, 3200 float> > 3201 { 3202 public: 3203 typedef typename Refract::Ret Ret; 3204 typedef typename Refract::Arg0 Arg0; 3205 typedef typename Refract::Arg1 Arg1; 3206 typedef typename Refract::ArgExprs ArgExprs; 3207 3208 string getName (void) const 3209 { 3210 return "refract"; 3211 } 3212 3213 protected: 3214 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const 3215 { 3216 const ExprP<Arg0>& i = args.a; 3217 const ExprP<Arg1>& n = args.b; 3218 const ExprP<float>& eta = args.c; 3219 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i)); 3220 const ExprP<float> k1 = bindExpression("k1", ctx, constant(1.0f) - eta * eta * 3221 (constant(1.0f) - dotNI * dotNI)); 3222 3223 const ExprP<float> k2 = bindExpression("k2", ctx, 3224 (((dotNI * (-dotNI)) + constant(1.0f)) * eta) 3225 * (-eta) + constant(1.0f)); 3226 const ExprP<float> k = bindExpression("k", ctx, alternatives(k1, k2)); 3227 3228 return cond(k < constant(0.0f), 3229 genXType<float, Size>(constant(0.0f)), 3230 i * eta - n * (eta * dotNI + sqrt(k))); 3231 } 3232 }; 3233 3234 class PreciseFunc1 : public CFloatFunc1 3235 { 3236 public: 3237 PreciseFunc1 (const string& name, DoubleFunc1& func) : CFloatFunc1(name, func) {} 3238 protected: 3239 double precision (const EvalContext&, double, double) const { return 0.0; } 3240 }; 3241 3242 class Abs : public PreciseFunc1 3243 { 3244 public: 3245 Abs (void) : PreciseFunc1("abs", deAbs) {} 3246 }; 3247 3248 class Sign : public PreciseFunc1 3249 { 3250 public: 3251 Sign (void) : PreciseFunc1("sign", deSign) {} 3252 }; 3253 3254 class Floor : public PreciseFunc1 3255 { 3256 public: 3257 Floor (void) : PreciseFunc1("floor", deFloor) {} 3258 }; 3259 3260 class Trunc : public PreciseFunc1 3261 { 3262 public: 3263 Trunc (void) : PreciseFunc1("trunc", deTrunc) {} 3264 }; 3265 3266 class Round : public FloatFunc1 3267 { 3268 public: 3269 string getName (void) const { return "round"; } 3270 3271 protected: 3272 Interval applyPoint (const EvalContext&, double x) const 3273 { 3274 double truncated = 0.0; 3275 const double fract = deModf(x, &truncated); 3276 Interval ret; 3277 3278 if (fabs(fract) <= 0.5) 3279 ret |= truncated; 3280 if (fabs(fract) >= 0.5) 3281 ret |= truncated + deSign(fract); 3282 3283 return ret; 3284 } 3285 3286 double precision (const EvalContext&, double, double) const { return 0.0; } 3287 }; 3288 3289 class RoundEven : public PreciseFunc1 3290 { 3291 public: 3292 RoundEven (void) : PreciseFunc1("roundEven", deRoundEven) {} 3293 }; 3294 3295 class Ceil : public PreciseFunc1 3296 { 3297 public: 3298 Ceil (void) : PreciseFunc1("ceil", deCeil) {} 3299 }; 3300 3301 DEFINE_DERIVED_FLOAT1(Fract, fract, x, x - app<Floor>(x)); 3302 3303 class PreciseFunc2 : public CFloatFunc2 3304 { 3305 public: 3306 PreciseFunc2 (const string& name, DoubleFunc2& func) : CFloatFunc2(name, func) {} 3307 protected: 3308 double precision (const EvalContext&, double, double, double) const { return 0.0; } 3309 }; 3310 3311 DEFINE_DERIVED_FLOAT2(Mod, mod, x, y, x - y * app<Floor>(x / y)); 3312 3313 class Modf : public PrimitiveFunc<Signature<float, float, float> > 3314 { 3315 public: 3316 string getName (void) const 3317 { 3318 return "modf"; 3319 } 3320 3321 protected: 3322 IRet doApply (const EvalContext&, const IArgs& iargs) const 3323 { 3324 Interval fracIV; 3325 Interval& wholeIV = const_cast<Interval&>(iargs.b); 3326 double intPart = 0; 3327 3328 TCU_INTERVAL_APPLY_MONOTONE1(fracIV, x, iargs.a, frac, frac = deModf(x, &intPart)); 3329 TCU_INTERVAL_APPLY_MONOTONE1(wholeIV, x, iargs.a, whole, 3330 deModf(x, &intPart); whole = intPart); 3331 3332 if (!iargs.a.isFinite()) 3333 { 3334 // Behavior on modf(Inf) not well-defined, allow anything as a fractional part 3335 // See Khronos bug 13907 3336 fracIV |= TCU_NAN; 3337 } 3338 3339 return fracIV; 3340 } 3341 3342 int getOutParamIndex (void) const 3343 { 3344 return 1; 3345 } 3346 }; 3347 3348 class Min : public PreciseFunc2 { public: Min (void) : PreciseFunc2("min", deMin) {} }; 3349 class Max : public PreciseFunc2 { public: Max (void) : PreciseFunc2("max", deMax) {} }; 3350 3351 class Clamp : public FloatFunc3 3352 { 3353 public: 3354 string getName (void) const { return "clamp"; } 3355 3356 double applyExact (double x, double minVal, double maxVal) const 3357 { 3358 return de::min(de::max(x, minVal), maxVal); 3359 } 3360 3361 double precision (const EvalContext&, double, double, double minVal, double maxVal) const 3362 { 3363 return minVal > maxVal ? TCU_NAN : 0.0; 3364 } 3365 }; 3366 3367 ExprP<float> clamp(const ExprP<float>& x, const ExprP<float>& minVal, const ExprP<float>& maxVal) 3368 { 3369 return app<Clamp>(x, minVal, maxVal); 3370 } 3371 3372 DEFINE_DERIVED_FLOAT3(Mix, mix, x, y, a, alternatives((x * (constant(1.0f) - a)) + y * a, 3373 x + (y - x) * a)); 3374 3375 static double step (double edge, double x) 3376 { 3377 return x < edge ? 0.0 : 1.0; 3378 } 3379 3380 class Step : public PreciseFunc2 { public: Step (void) : PreciseFunc2("step", step) {} }; 3381 3382 class SmoothStep : public DerivedFunc<Signature<float, float, float, float> > 3383 { 3384 public: 3385 string getName (void) const 3386 { 3387 return "smoothstep"; 3388 } 3389 3390 protected: 3391 3392 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const 3393 { 3394 const ExprP<float>& edge0 = args.a; 3395 const ExprP<float>& edge1 = args.b; 3396 const ExprP<float>& x = args.c; 3397 const ExprP<float> tExpr = clamp((x - edge0) / (edge1 - edge0), 3398 constant(0.0f), constant(1.0f)); 3399 const ExprP<float> t = bindExpression("t", ctx, tExpr); 3400 3401 return (t * t * (constant(3.0f) - constant(2.0f) * t)); 3402 } 3403 }; 3404 3405 class FrExp : public PrimitiveFunc<Signature<float, float, int> > 3406 { 3407 public: 3408 string getName (void) const 3409 { 3410 return "frexp"; 3411 } 3412 3413 protected: 3414 IRet doApply (const EvalContext&, const IArgs& iargs) const 3415 { 3416 IRet ret; 3417 const IArg0& x = iargs.a; 3418 IArg1& exponent = const_cast<IArg1&>(iargs.b); 3419 3420 if (x.hasNaN() || x.contains(TCU_INFINITY) || x.contains(-TCU_INFINITY)) 3421 { 3422 // GLSL (in contrast to IEEE) says that result of applying frexp 3423 // to infinity is undefined 3424 ret = Interval::unbounded() | TCU_NAN; 3425 exponent = Interval(-deLdExp(1.0, 31), deLdExp(1.0, 31)-1); 3426 } 3427 else if (!x.empty()) 3428 { 3429 int loExp = 0; 3430 const double loFrac = deFrExp(x.lo(), &loExp); 3431 int hiExp = 0; 3432 const double hiFrac = deFrExp(x.hi(), &hiExp); 3433 3434 if (deSign(loFrac) != deSign(hiFrac)) 3435 { 3436 exponent = Interval(-TCU_INFINITY, de::max(loExp, hiExp)); 3437 ret = Interval(); 3438 if (deSign(loFrac) < 0) 3439 ret |= Interval(-1.0 + DBL_EPSILON*0.5, 0.0); 3440 if (deSign(hiFrac) > 0) 3441 ret |= Interval(0.0, 1.0 - DBL_EPSILON*0.5); 3442 } 3443 else 3444 { 3445 exponent = Interval(loExp, hiExp); 3446 if (loExp == hiExp) 3447 ret = Interval(loFrac, hiFrac); 3448 else 3449 ret = deSign(loFrac) * Interval(0.5, 1.0 - DBL_EPSILON*0.5); 3450 } 3451 } 3452 3453 return ret; 3454 } 3455 3456 int getOutParamIndex (void) const 3457 { 3458 return 1; 3459 } 3460 }; 3461 3462 class LdExp : public PrimitiveFunc<Signature<float, float, int> > 3463 { 3464 public: 3465 string getName (void) const 3466 { 3467 return "ldexp"; 3468 } 3469 3470 protected: 3471 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const 3472 { 3473 Interval ret = call<Exp2>(ctx, iargs.b); 3474 // Khronos bug 11180 consensus: if exp2(exponent) cannot be represented, 3475 // the result is undefined. 3476 3477 if (ret.contains(TCU_INFINITY) | ret.contains(-TCU_INFINITY)) 3478 ret |= TCU_NAN; 3479 3480 return call<Mul>(ctx, iargs.a, ret); 3481 } 3482 }; 3483 3484 template<int Rows, int Columns> 3485 class Transpose : public PrimitiveFunc<Signature<Matrix<float, Rows, Columns>, 3486 Matrix<float, Columns, Rows> > > 3487 { 3488 public: 3489 typedef typename Transpose::IRet IRet; 3490 typedef typename Transpose::IArgs IArgs; 3491 3492 string getName (void) const 3493 { 3494 return "transpose"; 3495 } 3496 3497 protected: 3498 IRet doApply (const EvalContext&, const IArgs& iargs) const 3499 { 3500 IRet ret; 3501 3502 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx) 3503 { 3504 for (int colNdx = 0; colNdx < Columns; ++colNdx) 3505 ret(rowNdx, colNdx) = iargs.a(colNdx, rowNdx); 3506 } 3507 3508 return ret; 3509 } 3510 }; 3511 3512 template<typename Ret, typename Arg0, typename Arg1> 3513 class MulFunc : public PrimitiveFunc<Signature<Ret, Arg0, Arg1> > 3514 { 3515 public: 3516 string getName (void) const { return "mul"; } 3517 3518 protected: 3519 void doPrint (ostream& os, const BaseArgExprs& args) const 3520 { 3521 os << "(" << *args[0] << " * " << *args[1] << ")"; 3522 } 3523 }; 3524 3525 template<int LeftRows, int Middle, int RightCols> 3526 class MatMul : public MulFunc<Matrix<float, LeftRows, RightCols>, 3527 Matrix<float, LeftRows, Middle>, 3528 Matrix<float, Middle, RightCols> > 3529 { 3530 protected: 3531 typedef typename MatMul::IRet IRet; 3532 typedef typename MatMul::IArgs IArgs; 3533 typedef typename MatMul::IArg0 IArg0; 3534 typedef typename MatMul::IArg1 IArg1; 3535 3536 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const 3537 { 3538 const IArg0& left = iargs.a; 3539 const IArg1& right = iargs.b; 3540 IRet ret; 3541 3542 for (int row = 0; row < LeftRows; ++row) 3543 { 3544 for (int col = 0; col < RightCols; ++col) 3545 { 3546 Interval element (0.0); 3547 3548 for (int ndx = 0; ndx < Middle; ++ndx) 3549 element = call<Add>(ctx, element, 3550 call<Mul>(ctx, left[ndx][row], right[col][ndx])); 3551 3552 ret[col][row] = element; 3553 } 3554 } 3555 3556 return ret; 3557 } 3558 }; 3559 3560 template<int Rows, int Cols> 3561 class VecMatMul : public MulFunc<Vector<float, Cols>, 3562 Vector<float, Rows>, 3563 Matrix<float, Rows, Cols> > 3564 { 3565 public: 3566 typedef typename VecMatMul::IRet IRet; 3567 typedef typename VecMatMul::IArgs IArgs; 3568 typedef typename VecMatMul::IArg0 IArg0; 3569 typedef typename VecMatMul::IArg1 IArg1; 3570 3571 protected: 3572 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const 3573 { 3574 const IArg0& left = iargs.a; 3575 const IArg1& right = iargs.b; 3576 IRet ret; 3577 3578 for (int col = 0; col < Cols; ++col) 3579 { 3580 Interval element (0.0); 3581 3582 for (int row = 0; row < Rows; ++row) 3583 element = call<Add>(ctx, element, call<Mul>(ctx, left[row], right[col][row])); 3584 3585 ret[col] = element; 3586 } 3587 3588 return ret; 3589 } 3590 }; 3591 3592 template<int Rows, int Cols> 3593 class MatVecMul : public MulFunc<Vector<float, Rows>, 3594 Matrix<float, Rows, Cols>, 3595 Vector<float, Cols> > 3596 { 3597 public: 3598 typedef typename MatVecMul::IRet IRet; 3599 typedef typename MatVecMul::IArgs IArgs; 3600 typedef typename MatVecMul::IArg0 IArg0; 3601 typedef typename MatVecMul::IArg1 IArg1; 3602 3603 protected: 3604 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const 3605 { 3606 const IArg0& left = iargs.a; 3607 const IArg1& right = iargs.b; 3608 3609 return call<VecMatMul<Cols, Rows> >(ctx, right, 3610 call<Transpose<Rows, Cols> >(ctx, left)); 3611 } 3612 }; 3613 3614 template<int Rows, int Cols> 3615 class OuterProduct : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>, 3616 Vector<float, Rows>, 3617 Vector<float, Cols> > > 3618 { 3619 public: 3620 typedef typename OuterProduct::IRet IRet; 3621 typedef typename OuterProduct::IArgs IArgs; 3622 3623 string getName (void) const 3624 { 3625 return "outerProduct"; 3626 } 3627 3628 protected: 3629 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const 3630 { 3631 IRet ret; 3632 3633 for (int row = 0; row < Rows; ++row) 3634 { 3635 for (int col = 0; col < Cols; ++col) 3636 ret[col][row] = call<Mul>(ctx, iargs.a[row], iargs.b[col]); 3637 } 3638 3639 return ret; 3640 } 3641 }; 3642 3643 template<int Rows, int Cols> 3644 ExprP<Matrix<float, Rows, Cols> > outerProduct (const ExprP<Vector<float, Rows> >& left, 3645 const ExprP<Vector<float, Cols> >& right) 3646 { 3647 return app<OuterProduct<Rows, Cols> >(left, right); 3648 } 3649 3650 template<int Size> 3651 class DeterminantBase : public DerivedFunc<Signature<float, Matrix<float, Size, Size> > > 3652 { 3653 public: 3654 string getName (void) const { return "determinant"; } 3655 }; 3656 3657 template<int Size> 3658 class Determinant; 3659 3660 template<int Size> 3661 ExprP<float> determinant (ExprP<Matrix<float, Size, Size> > mat) 3662 { 3663 return app<Determinant<Size> >(mat); 3664 } 3665 3666 template<> 3667 class Determinant<2> : public DeterminantBase<2> 3668 { 3669 protected: 3670 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const 3671 { 3672 ExprP<Mat2> mat = args.a; 3673 3674 return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1]; 3675 } 3676 }; 3677 3678 template<> 3679 class Determinant<3> : public DeterminantBase<3> 3680 { 3681 protected: 3682 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const 3683 { 3684 ExprP<Mat3> mat = args.a; 3685 3686 return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) + 3687 mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) + 3688 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0])); 3689 } 3690 }; 3691 3692 template<> 3693 class Determinant<4> : public DeterminantBase<4> 3694 { 3695 protected: 3696 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const 3697 { 3698 ExprP<Mat4> mat = args.a; 3699 ExprP<Mat3> minors[4]; 3700 3701 for (int ndx = 0; ndx < 4; ++ndx) 3702 { 3703 ExprP<Vec4> minorColumns[3]; 3704 ExprP<Vec3> columns[3]; 3705 3706 for (int col = 0; col < 3; ++col) 3707 minorColumns[col] = mat[col < ndx ? col : col + 1]; 3708 3709 for (int col = 0; col < 3; ++col) 3710 columns[col] = vec3(minorColumns[0][col+1], 3711 minorColumns[1][col+1], 3712 minorColumns[2][col+1]); 3713 3714 minors[ndx] = bindExpression("minor", ctx, 3715 mat3(columns[0], columns[1], columns[2])); 3716 } 3717 3718 return (mat[0][0] * determinant(minors[0]) - 3719 mat[1][0] * determinant(minors[1]) + 3720 mat[2][0] * determinant(minors[2]) - 3721 mat[3][0] * determinant(minors[3])); 3722 } 3723 }; 3724 3725 template<int Size> class Inverse; 3726 3727 template <int Size> 3728 ExprP<Matrix<float, Size, Size> > inverse (ExprP<Matrix<float, Size, Size> > mat) 3729 { 3730 return app<Inverse<Size> >(mat); 3731 } 3732 3733 template<> 3734 class Inverse<2> : public DerivedFunc<Signature<Mat2, Mat2> > 3735 { 3736 public: 3737 string getName (void) const 3738 { 3739 return "inverse"; 3740 } 3741 3742 protected: 3743 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const 3744 { 3745 ExprP<Mat2> mat = args.a; 3746 ExprP<float> det = bindExpression("det", ctx, determinant(mat)); 3747 3748 return mat2(vec2(mat[1][1] / det, -mat[0][1] / det), 3749 vec2(-mat[1][0] / det, mat[0][0] / det)); 3750 } 3751 }; 3752 3753 template<> 3754 class Inverse<3> : public DerivedFunc<Signature<Mat3, Mat3> > 3755 { 3756 public: 3757 string getName (void) const 3758 { 3759 return "inverse"; 3760 } 3761 3762 protected: 3763 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const 3764 { 3765 ExprP<Mat3> mat = args.a; 3766 ExprP<Mat2> invA = bindExpression("invA", ctx, 3767 inverse(mat2(vec2(mat[0][0], mat[0][1]), 3768 vec2(mat[1][0], mat[1][1])))); 3769 3770 ExprP<Vec2> matB = bindExpression("matB", ctx, vec2(mat[2][0], mat[2][1])); 3771 ExprP<Vec2> matC = bindExpression("matC", ctx, vec2(mat[0][2], mat[1][2])); 3772 ExprP<float> matD = bindExpression("matD", ctx, mat[2][2]); 3773 3774 ExprP<float> schur = bindExpression("schur", ctx, 3775 constant(1.0f) / 3776 (matD - dot(matC * invA, matB))); 3777 3778 ExprP<Vec2> t1 = invA * matB; 3779 ExprP<Vec2> t2 = t1 * schur; 3780 ExprP<Mat2> t3 = outerProduct(t2, matC); 3781 ExprP<Mat2> t4 = t3 * invA; 3782 ExprP<Mat2> t5 = invA + t4; 3783 ExprP<Mat2> blockA = bindExpression("blockA", ctx, t5); 3784 ExprP<Vec2> blockB = bindExpression("blockB", ctx, 3785 (invA * matB) * -schur); 3786 ExprP<Vec2> blockC = bindExpression("blockC", ctx, 3787 (matC * invA) * -schur); 3788 3789 return mat3(vec3(blockA[0][0], blockA[0][1], blockC[0]), 3790 vec3(blockA[1][0], blockA[1][1], blockC[1]), 3791 vec3(blockB[0], blockB[1], schur)); 3792 } 3793 }; 3794 3795 template<> 3796 class Inverse<4> : public DerivedFunc<Signature<Mat4, Mat4> > 3797 { 3798 public: 3799 string getName (void) const { return "inverse"; } 3800 3801 protected: 3802 ExprP<Ret> doExpand (ExpandContext& ctx, 3803 const ArgExprs& args) const 3804 { 3805 ExprP<Mat4> mat = args.a; 3806 ExprP<Mat2> invA = bindExpression("invA", ctx, 3807 inverse(mat2(vec2(mat[0][0], mat[0][1]), 3808 vec2(mat[1][0], mat[1][1])))); 3809 ExprP<Mat2> matB = bindExpression("matB", ctx, 3810 mat2(vec2(mat[2][0], mat[2][1]), 3811 vec2(mat[3][0], mat[3][1]))); 3812 ExprP<Mat2> matC = bindExpression("matC", ctx, 3813 mat2(vec2(mat[0][2], mat[0][3]), 3814 vec2(mat[1][2], mat[1][3]))); 3815 ExprP<Mat2> matD = bindExpression("matD", ctx, 3816 mat2(vec2(mat[2][2], mat[2][3]), 3817 vec2(mat[3][2], mat[3][3]))); 3818 ExprP<Mat2> schur = bindExpression("schur", ctx, 3819 inverse(matD + -(matC * invA * matB))); 3820 ExprP<Mat2> blockA = bindExpression("blockA", ctx, 3821 invA + (invA * matB * schur * matC * invA)); 3822 ExprP<Mat2> blockB = bindExpression("blockB", ctx, 3823 (-invA) * matB * schur); 3824 ExprP<Mat2> blockC = bindExpression("blockC", ctx, 3825 (-schur) * matC * invA); 3826 3827 return mat4(vec4(blockA[0][0], blockA[0][1], blockC[0][0], blockC[0][1]), 3828 vec4(blockA[1][0], blockA[1][1], blockC[1][0], blockC[1][1]), 3829 vec4(blockB[0][0], blockB[0][1], schur[0][0], schur[0][1]), 3830 vec4(blockB[1][0], blockB[1][1], schur[1][0], schur[1][1])); 3831 } 3832 }; 3833 3834 class Fma : public DerivedFunc<Signature<float, float, float, float> > 3835 { 3836 public: 3837 string getName (void) const 3838 { 3839 return "fma"; 3840 } 3841 3842 string getRequiredExtension (void) const 3843 { 3844 return "GL_EXT_gpu_shader5"; 3845 } 3846 3847 protected: 3848 ExprP<float> doExpand (ExpandContext&, const ArgExprs& x) const 3849 { 3850 return x.a * x.b + x.c; 3851 } 3852 }; 3853 3854 } // Functions 3855 3856 using namespace Functions; 3857 3858 template <typename T> 3859 ExprP<typename T::Element> ContainerExprPBase<T>::operator[] (int i) const 3860 { 3861 return Functions::getComponent(exprP<T>(*this), i); 3862 } 3863 3864 ExprP<float> operator+ (const ExprP<float>& arg0, const ExprP<float>& arg1) 3865 { 3866 return app<Add>(arg0, arg1); 3867 } 3868 3869 ExprP<float> operator- (const ExprP<float>& arg0, const ExprP<float>& arg1) 3870 { 3871 return app<Sub>(arg0, arg1); 3872 } 3873 3874 ExprP<float> operator- (const ExprP<float>& arg0) 3875 { 3876 return app<Negate>(arg0); 3877 } 3878 3879 ExprP<float> operator* (const ExprP<float>& arg0, const ExprP<float>& arg1) 3880 { 3881 return app<Mul>(arg0, arg1); 3882 } 3883 3884 ExprP<float> operator/ (const ExprP<float>& arg0, const ExprP<float>& arg1) 3885 { 3886 return app<Div>(arg0, arg1); 3887 } 3888 3889 template <typename Sig_, int Size> 3890 class GenFunc : public PrimitiveFunc<Signature< 3891 typename ContainerOf<typename Sig_::Ret, Size>::Container, 3892 typename ContainerOf<typename Sig_::Arg0, Size>::Container, 3893 typename ContainerOf<typename Sig_::Arg1, Size>::Container, 3894 typename ContainerOf<typename Sig_::Arg2, Size>::Container, 3895 typename ContainerOf<typename Sig_::Arg3, Size>::Container> > 3896 { 3897 public: 3898 typedef typename GenFunc::IArgs IArgs; 3899 typedef typename GenFunc::IRet IRet; 3900 3901 GenFunc (const Func<Sig_>& scalarFunc) : m_func (scalarFunc) {} 3902 3903 string getName (void) const 3904 { 3905 return m_func.getName(); 3906 } 3907 3908 int getOutParamIndex (void) const 3909 { 3910 return m_func.getOutParamIndex(); 3911 } 3912 3913 string getRequiredExtension (void) const 3914 { 3915 return m_func.getRequiredExtension(); 3916 } 3917 3918 protected: 3919 void doPrint (ostream& os, const BaseArgExprs& args) const 3920 { 3921 m_func.print(os, args); 3922 } 3923 3924 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const 3925 { 3926 IRet ret; 3927 3928 for (int ndx = 0; ndx < Size; ++ndx) 3929 { 3930 ret[ndx] = 3931 m_func.apply(ctx, iargs.a[ndx], iargs.b[ndx], iargs.c[ndx], iargs.d[ndx]); 3932 } 3933 3934 return ret; 3935 } 3936 3937 void doGetUsedFuncs (FuncSet& dst) const 3938 { 3939 m_func.getUsedFuncs(dst); 3940 } 3941 3942 const Func<Sig_>& m_func; 3943 }; 3944 3945 template <typename F, int Size> 3946 class VectorizedFunc : public GenFunc<typename F::Sig, Size> 3947 { 3948 public: 3949 VectorizedFunc (void) : GenFunc<typename F::Sig, Size>(instance<F>()) {} 3950 }; 3951 3952 3953 3954 template <typename Sig_, int Size> 3955 class FixedGenFunc : public PrimitiveFunc <Signature< 3956 typename ContainerOf<typename Sig_::Ret, Size>::Container, 3957 typename ContainerOf<typename Sig_::Arg0, Size>::Container, 3958 typename Sig_::Arg1, 3959 typename ContainerOf<typename Sig_::Arg2, Size>::Container, 3960 typename ContainerOf<typename Sig_::Arg3, Size>::Container> > 3961 { 3962 public: 3963 typedef typename FixedGenFunc::IArgs IArgs; 3964 typedef typename FixedGenFunc::IRet IRet; 3965 3966 string getName (void) const 3967 { 3968 return this->doGetScalarFunc().getName(); 3969 } 3970 3971 protected: 3972 void doPrint (ostream& os, const BaseArgExprs& args) const 3973 { 3974 this->doGetScalarFunc().print(os, args); 3975 } 3976 3977 IRet doApply (const EvalContext& ctx, 3978 const IArgs& iargs) const 3979 { 3980 IRet ret; 3981 const Func<Sig_>& func = this->doGetScalarFunc(); 3982 3983 for (int ndx = 0; ndx < Size; ++ndx) 3984 ret[ndx] = func.apply(ctx, iargs.a[ndx], iargs.b, iargs.c[ndx], iargs.d[ndx]); 3985 3986 return ret; 3987 } 3988 3989 virtual const Func<Sig_>& doGetScalarFunc (void) const = 0; 3990 }; 3991 3992 template <typename F, int Size> 3993 class FixedVecFunc : public FixedGenFunc<typename F::Sig, Size> 3994 { 3995 protected: 3996 const Func<typename F::Sig>& doGetScalarFunc (void) const { return instance<F>(); } 3997 }; 3998 3999 template<typename Sig> 4000 struct GenFuncs 4001 { 4002 GenFuncs (const Func<Sig>& func_, 4003 const GenFunc<Sig, 2>& func2_, 4004 const GenFunc<Sig, 3>& func3_, 4005 const GenFunc<Sig, 4>& func4_) 4006 : func (func_) 4007 , func2 (func2_) 4008 , func3 (func3_) 4009 , func4 (func4_) 4010 {} 4011 4012 const Func<Sig>& func; 4013 const GenFunc<Sig, 2>& func2; 4014 const GenFunc<Sig, 3>& func3; 4015 const GenFunc<Sig, 4>& func4; 4016 }; 4017 4018 template<typename F> 4019 GenFuncs<typename F::Sig> makeVectorizedFuncs (void) 4020 { 4021 return GenFuncs<typename F::Sig>(instance<F>(), 4022 instance<VectorizedFunc<F, 2> >(), 4023 instance<VectorizedFunc<F, 3> >(), 4024 instance<VectorizedFunc<F, 4> >()); 4025 } 4026 4027 template<int Size> 4028 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0, 4029 const ExprP<Vector<float, Size> >& arg1) 4030 { 4031 return app<VectorizedFunc<Mul, Size> >(arg0, arg1); 4032 } 4033 4034 template<int Size> 4035 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0, 4036 const ExprP<float>& arg1) 4037 { 4038 return app<FixedVecFunc<Mul, Size> >(arg0, arg1); 4039 } 4040 4041 template<int Size> 4042 ExprP<Vector<float, Size> > operator/(const ExprP<Vector<float, Size> >& arg0, 4043 const ExprP<float>& arg1) 4044 { 4045 return app<FixedVecFunc<Div, Size> >(arg0, arg1); 4046 } 4047 4048 template<int Size> 4049 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0) 4050 { 4051 return app<VectorizedFunc<Negate, Size> >(arg0); 4052 } 4053 4054 template<int Size> 4055 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0, 4056 const ExprP<Vector<float, Size> >& arg1) 4057 { 4058 return app<VectorizedFunc<Sub, Size> >(arg0, arg1); 4059 } 4060 4061 template<int LeftRows, int Middle, int RightCols> 4062 ExprP<Matrix<float, LeftRows, RightCols> > 4063 operator* (const ExprP<Matrix<float, LeftRows, Middle> >& left, 4064 const ExprP<Matrix<float, Middle, RightCols> >& right) 4065 { 4066 return app<MatMul<LeftRows, Middle, RightCols> >(left, right); 4067 } 4068 4069 template<int Rows, int Cols> 4070 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left, 4071 const ExprP<Matrix<float, Rows, Cols> >& right) 4072 { 4073 return app<VecMatMul<Rows, Cols> >(left, right); 4074 } 4075 4076 template<int Rows, int Cols> 4077 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left, 4078 const ExprP<Vector<float, Rows> >& right) 4079 { 4080 return app<MatVecMul<Rows, Cols> >(left, right); 4081 } 4082 4083 template<int Rows, int Cols> 4084 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left, 4085 const ExprP<float>& right) 4086 { 4087 return app<ScalarMatFunc<Mul, Rows, Cols> >(left, right); 4088 } 4089 4090 template<int Rows, int Cols> 4091 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left, 4092 const ExprP<Matrix<float, Rows, Cols> >& right) 4093 { 4094 return app<CompMatFunc<Add, Rows, Cols> >(left, right); 4095 } 4096 4097 template<int Rows, int Cols> 4098 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat) 4099 { 4100 return app<MatNeg<Rows, Cols> >(mat); 4101 } 4102 4103 template <typename T> 4104 class Sampling 4105 { 4106 public: 4107 virtual void genFixeds (const FloatFormat&, vector<T>&) const {} 4108 virtual T genRandom (const FloatFormat&, Precision, Random&) const { return T(); } 4109 virtual double getWeight (void) const { return 0.0; } 4110 }; 4111 4112 template <> 4113 class DefaultSampling<Void> : public Sampling<Void> 4114 { 4115 public: 4116 void genFixeds (const FloatFormat&, vector<Void>& dst) const { dst.push_back(Void()); } 4117 }; 4118 4119 template <> 4120 class DefaultSampling<bool> : public Sampling<bool> 4121 { 4122 public: 4123 void genFixeds (const FloatFormat&, vector<bool>& dst) const 4124 { 4125 dst.push_back(true); 4126 dst.push_back(false); 4127 } 4128 }; 4129 4130 template <> 4131 class DefaultSampling<int> : public Sampling<int> 4132 { 4133 public: 4134 int genRandom (const FloatFormat&, Precision prec, Random& rnd) const 4135 { 4136 const int exp = rnd.getInt(0, getNumBits(prec)-2); 4137 const int sign = rnd.getBool() ? -1 : 1; 4138 4139 return sign * rnd.getInt(0, (deInt32)1 << exp); 4140 } 4141 4142 void genFixeds (const FloatFormat&, vector<int>& dst) const 4143 { 4144 dst.push_back(0); 4145 dst.push_back(-1); 4146 dst.push_back(1); 4147 } 4148 double getWeight (void) const { return 1.0; } 4149 4150 private: 4151 static inline int getNumBits (Precision prec) 4152 { 4153 switch (prec) 4154 { 4155 case glu::PRECISION_LOWP: return 8; 4156 case glu::PRECISION_MEDIUMP: return 16; 4157 case glu::PRECISION_HIGHP: return 32; 4158 default: 4159 DE_ASSERT(false); 4160 return 0; 4161 } 4162 } 4163 }; 4164 4165 template <> 4166 class DefaultSampling<float> : public Sampling<float> 4167 { 4168 public: 4169 float genRandom (const FloatFormat& format, Precision prec, Random& rnd) const; 4170 void genFixeds (const FloatFormat& format, vector<float>& dst) const; 4171 double getWeight (void) const { return 1.0; } 4172 }; 4173 4174 //! Generate a random float from a reasonable general-purpose distribution. 4175 float DefaultSampling<float>::genRandom (const FloatFormat& format, 4176 Precision, 4177 Random& rnd) const 4178 { 4179 const int minExp = format.getMinExp(); 4180 const int maxExp = format.getMaxExp(); 4181 const bool haveSubnormal = format.hasSubnormal() != tcu::NO; 4182 4183 // Choose exponent so that the cumulative distribution is cubic. 4184 // This makes the probability distribution quadratic, with the peak centered on zero. 4185 const double minRoot = deCbrt(minExp - 0.5 - (haveSubnormal ? 1.0 : 0.0)); 4186 const double maxRoot = deCbrt(maxExp + 0.5); 4187 const int fractionBits = format.getFractionBits(); 4188 const int exp = int(deRoundEven(dePow(rnd.getDouble(minRoot, maxRoot), 4189 3.0))); 4190 float base = 0.0f; // integral power of two 4191 float quantum = 0.0f; // smallest representable difference in the binade 4192 float significand = 0.0f; // Significand. 4193 4194 DE_ASSERT(fractionBits < std::numeric_limits<float>::digits); 4195 4196 // Generate some occasional special numbers 4197 switch (rnd.getInt(0, 64)) 4198 { 4199 case 0: return 0; 4200 case 1: return TCU_INFINITY; 4201 case 2: return -TCU_INFINITY; 4202 case 3: return TCU_NAN; 4203 default: break; 4204 } 4205 4206 if (exp >= minExp) 4207 { 4208 // Normal number 4209 base = deFloatLdExp(1.0f, exp); 4210 quantum = deFloatLdExp(1.0f, exp - fractionBits); 4211 } 4212 else 4213 { 4214 // Subnormal 4215 base = 0.0f; 4216 quantum = deFloatLdExp(1.0f, minExp - fractionBits); 4217 } 4218 4219 switch (rnd.getInt(0, 16)) 4220 { 4221 case 0: // The highest number in this binade, significand is all bits one. 4222 significand = base - quantum; 4223 break; 4224 case 1: // Significand is one. 4225 significand = quantum; 4226 break; 4227 case 2: // Significand is zero. 4228 significand = 0.0; 4229 break; 4230 default: // Random (evenly distributed) significand. 4231 { 4232 deUint64 intFraction = rnd.getUint64() & ((1 << fractionBits) - 1); 4233 significand = float(intFraction) * quantum; 4234 } 4235 } 4236 4237 // Produce positive numbers more often than negative. 4238 return (rnd.getInt(0,3) == 0 ? -1.0f : 1.0f) * (base + significand); 4239 } 4240 4241 //! Generate a standard set of floats that should always be tested. 4242 void DefaultSampling<float>::genFixeds (const FloatFormat& format, vector<float>& dst) const 4243 { 4244 const int minExp = format.getMinExp(); 4245 const int maxExp = format.getMaxExp(); 4246 const int fractionBits = format.getFractionBits(); 4247 const float minQuantum = deFloatLdExp(1.0f, minExp - fractionBits); 4248 const float minNormalized = deFloatLdExp(1.0f, minExp); 4249 const float maxQuantum = deFloatLdExp(1.0f, maxExp - fractionBits); 4250 4251 // NaN 4252 dst.push_back(TCU_NAN); 4253 // Zero 4254 dst.push_back(0.0f); 4255 4256 for (int sign = -1; sign <= 1; sign += 2) 4257 { 4258 // Smallest subnormal 4259 dst.push_back((float)sign * minQuantum); 4260 4261 // Largest subnormal 4262 dst.push_back((float)sign * (minNormalized - minQuantum)); 4263 4264 // Smallest normalized 4265 dst.push_back((float)sign * minNormalized); 4266 4267 // Next smallest normalized 4268 dst.push_back((float)sign * (minNormalized + minQuantum)); 4269 4270 dst.push_back((float)sign * 0.5f); 4271 dst.push_back((float)sign * 1.0f); 4272 dst.push_back((float)sign * 2.0f); 4273 4274 // Largest number 4275 dst.push_back((float)sign * (deFloatLdExp(1.0f, maxExp) + 4276 (deFloatLdExp(1.0f, maxExp) - maxQuantum))); 4277 4278 dst.push_back((float)sign * TCU_INFINITY); 4279 } 4280 } 4281 4282 template <typename T, int Size> 4283 class DefaultSampling<Vector<T, Size> > : public Sampling<Vector<T, Size> > 4284 { 4285 public: 4286 typedef Vector<T, Size> Value; 4287 4288 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const 4289 { 4290 Value ret; 4291 4292 for (int ndx = 0; ndx < Size; ++ndx) 4293 ret[ndx] = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd); 4294 4295 return ret; 4296 } 4297 4298 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const 4299 { 4300 vector<T> scalars; 4301 4302 instance<DefaultSampling<T> >().genFixeds(fmt, scalars); 4303 4304 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx) 4305 dst.push_back(Value(scalars[scalarNdx])); 4306 } 4307 4308 double getWeight (void) const 4309 { 4310 return dePow(instance<DefaultSampling<T> >().getWeight(), Size); 4311 } 4312 }; 4313 4314 template <typename T, int Rows, int Columns> 4315 class DefaultSampling<Matrix<T, Rows, Columns> > : public Sampling<Matrix<T, Rows, Columns> > 4316 { 4317 public: 4318 typedef Matrix<T, Rows, Columns> Value; 4319 4320 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const 4321 { 4322 Value ret; 4323 4324 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx) 4325 for (int colNdx = 0; colNdx < Columns; ++colNdx) 4326 ret(rowNdx, colNdx) = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd); 4327 4328 return ret; 4329 } 4330 4331 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const 4332 { 4333 vector<T> scalars; 4334 4335 instance<DefaultSampling<T> >().genFixeds(fmt, scalars); 4336 4337 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx) 4338 dst.push_back(Value(scalars[scalarNdx])); 4339 4340 if (Columns == Rows) 4341 { 4342 Value mat (0.0); 4343 T x = T(1.0f); 4344 mat[0][0] = x; 4345 for (int ndx = 0; ndx < Columns; ++ndx) 4346 { 4347 mat[Columns-1-ndx][ndx] = x; 4348 x *= T(2.0f); 4349 } 4350 dst.push_back(mat); 4351 } 4352 } 4353 4354 double getWeight (void) const 4355 { 4356 return dePow(instance<DefaultSampling<T> >().getWeight(), Rows * Columns); 4357 } 4358 }; 4359 4360 struct Context 4361 { 4362 Context (const string& name_, 4363 TestContext& testContext_, 4364 RenderContext& renderContext_, 4365 const FloatFormat& floatFormat_, 4366 const FloatFormat& highpFormat_, 4367 Precision precision_, 4368 ShaderType shaderType_, 4369 size_t numRandoms_) 4370 : name (name_) 4371 , testContext (testContext_) 4372 , renderContext (renderContext_) 4373 , floatFormat (floatFormat_) 4374 , highpFormat (highpFormat_) 4375 , precision (precision_) 4376 , shaderType (shaderType_) 4377 , numRandoms (numRandoms_) {} 4378 4379 string name; 4380 TestContext& testContext; 4381 RenderContext& renderContext; 4382 FloatFormat floatFormat; 4383 FloatFormat highpFormat; 4384 Precision precision; 4385 ShaderType shaderType; 4386 size_t numRandoms; 4387 }; 4388 4389 template<typename In0_ = Void, typename In1_ = Void, typename In2_ = Void, typename In3_ = Void> 4390 struct InTypes 4391 { 4392 typedef In0_ In0; 4393 typedef In1_ In1; 4394 typedef In2_ In2; 4395 typedef In3_ In3; 4396 }; 4397 4398 template <typename In> 4399 int numInputs (void) 4400 { 4401 return (!isTypeValid<typename In::In0>() ? 0 : 4402 !isTypeValid<typename In::In1>() ? 1 : 4403 !isTypeValid<typename In::In2>() ? 2 : 4404 !isTypeValid<typename In::In3>() ? 3 : 4405 4); 4406 } 4407 4408 template<typename Out0_, typename Out1_ = Void> 4409 struct OutTypes 4410 { 4411 typedef Out0_ Out0; 4412 typedef Out1_ Out1; 4413 }; 4414 4415 template <typename Out> 4416 int numOutputs (void) 4417 { 4418 return (!isTypeValid<typename Out::Out0>() ? 0 : 4419 !isTypeValid<typename Out::Out1>() ? 1 : 4420 2); 4421 } 4422 4423 template<typename In> 4424 struct Inputs 4425 { 4426 vector<typename In::In0> in0; 4427 vector<typename In::In1> in1; 4428 vector<typename In::In2> in2; 4429 vector<typename In::In3> in3; 4430 }; 4431 4432 template<typename Out> 4433 struct Outputs 4434 { 4435 Outputs (size_t size) : out0(size), out1(size) {} 4436 4437 vector<typename Out::Out0> out0; 4438 vector<typename Out::Out1> out1; 4439 }; 4440 4441 template<typename In, typename Out> 4442 struct Variables 4443 { 4444 VariableP<typename In::In0> in0; 4445 VariableP<typename In::In1> in1; 4446 VariableP<typename In::In2> in2; 4447 VariableP<typename In::In3> in3; 4448 VariableP<typename Out::Out0> out0; 4449 VariableP<typename Out::Out1> out1; 4450 }; 4451 4452 template<typename In> 4453 struct Samplings 4454 { 4455 Samplings (const Sampling<typename In::In0>& in0_, 4456 const Sampling<typename In::In1>& in1_, 4457 const Sampling<typename In::In2>& in2_, 4458 const Sampling<typename In::In3>& in3_) 4459 : in0 (in0_), in1 (in1_), in2 (in2_), in3 (in3_) {} 4460 4461 const Sampling<typename In::In0>& in0; 4462 const Sampling<typename In::In1>& in1; 4463 const Sampling<typename In::In2>& in2; 4464 const Sampling<typename In::In3>& in3; 4465 }; 4466 4467 template<typename In> 4468 struct DefaultSamplings : Samplings<In> 4469 { 4470 DefaultSamplings (void) 4471 : Samplings<In>(instance<DefaultSampling<typename In::In0> >(), 4472 instance<DefaultSampling<typename In::In1> >(), 4473 instance<DefaultSampling<typename In::In2> >(), 4474 instance<DefaultSampling<typename In::In3> >()) {} 4475 }; 4476 4477 class PrecisionCase : public TestCase 4478 { 4479 public: 4480 IterateResult iterate (void); 4481 4482 protected: 4483 PrecisionCase (const Context& context, 4484 const string& name, 4485 const string& extension = "") 4486 : TestCase (context.testContext, 4487 name.c_str(), 4488 name.c_str()) 4489 , m_ctx (context) 4490 , m_status () 4491 , m_rnd (0xdeadbeefu + 4492 context.testContext.getCommandLine().getBaseSeed()) 4493 , m_extension (extension) 4494 { 4495 } 4496 4497 RenderContext& getRenderContext(void) const { return m_ctx.renderContext; } 4498 4499 const FloatFormat& getFormat (void) const { return m_ctx.floatFormat; } 4500 4501 TestLog& log (void) const { return m_testCtx.getLog(); } 4502 4503 virtual void runTest (void) = 0; 4504 4505 template <typename In, typename Out> 4506 void testStatement (const Variables<In, Out>& variables, 4507 const Inputs<In>& inputs, 4508 const Statement& stmt); 4509 4510 template<typename T> 4511 Symbol makeSymbol (const Variable<T>& variable) 4512 { 4513 return Symbol(variable.getName(), getVarTypeOf<T>(m_ctx.precision)); 4514 } 4515 4516 Context m_ctx; 4517 ResultCollector m_status; 4518 Random m_rnd; 4519 const string m_extension; 4520 }; 4521 4522 IterateResult PrecisionCase::iterate (void) 4523 { 4524 runTest(); 4525 m_status.setTestContextResult(m_testCtx); 4526 return STOP; 4527 } 4528 4529 template <typename In, typename Out> 4530 void PrecisionCase::testStatement (const Variables<In, Out>& variables, 4531 const Inputs<In>& inputs, 4532 const Statement& stmt) 4533 { 4534 using namespace ShaderExecUtil; 4535 4536 typedef typename In::In0 In0; 4537 typedef typename In::In1 In1; 4538 typedef typename In::In2 In2; 4539 typedef typename In::In3 In3; 4540 typedef typename Out::Out0 Out0; 4541 typedef typename Out::Out1 Out1; 4542 4543 const FloatFormat& fmt = getFormat(); 4544 const int inCount = numInputs<In>(); 4545 const int outCount = numOutputs<Out>(); 4546 const size_t numValues = (inCount > 0) ? inputs.in0.size() : 1; 4547 Outputs<Out> outputs (numValues); 4548 ShaderSpec spec; 4549 const FloatFormat highpFmt = m_ctx.highpFormat; 4550 const int maxMsgs = 100; 4551 int numErrors = 0; 4552 Environment env; // Hoisted out of the inner loop for optimization. 4553 4554 switch (inCount) 4555 { 4556 case 4: DE_ASSERT(inputs.in3.size() == numValues); 4557 case 3: DE_ASSERT(inputs.in2.size() == numValues); 4558 case 2: DE_ASSERT(inputs.in1.size() == numValues); 4559 case 1: DE_ASSERT(inputs.in0.size() == numValues); 4560 default: break; 4561 } 4562 4563 // Print out the statement and its definitions 4564 log() << TestLog::Message << "Statement: " << stmt << TestLog::EndMessage; 4565 { 4566 ostringstream oss; 4567 FuncSet funcs; 4568 4569 stmt.getUsedFuncs(funcs); 4570 for (FuncSet::const_iterator it = funcs.begin(); it != funcs.end(); ++it) 4571 { 4572 (*it)->printDefinition(oss); 4573 } 4574 if (!funcs.empty()) 4575 log() << TestLog::Message << "Reference definitions:\n" << oss.str() 4576 << TestLog::EndMessage; 4577 } 4578 4579 // Initialize ShaderSpec from precision, variables and statement. 4580 { 4581 ostringstream os; 4582 os << "precision " << glu::getPrecisionName(m_ctx.precision) << " float;\n"; 4583 spec.globalDeclarations = os.str(); 4584 } 4585 4586 spec.version = getContextTypeGLSLVersion(getRenderContext().getType()); 4587 4588 if (!m_extension.empty()) 4589 spec.globalDeclarations = "#extension " + m_extension + " : require\n"; 4590 4591 spec.inputs.resize(inCount); 4592 4593 switch (inCount) 4594 { 4595 case 4: spec.inputs[3] = makeSymbol(*variables.in3); 4596 case 3: spec.inputs[2] = makeSymbol(*variables.in2); 4597 case 2: spec.inputs[1] = makeSymbol(*variables.in1); 4598 case 1: spec.inputs[0] = makeSymbol(*variables.in0); 4599 default: break; 4600 } 4601 4602 spec.outputs.resize(outCount); 4603 4604 switch (outCount) 4605 { 4606 case 2: spec.outputs[1] = makeSymbol(*variables.out1); 4607 case 1: spec.outputs[0] = makeSymbol(*variables.out0); 4608 default: break; 4609 } 4610 4611 spec.source = de::toString(stmt); 4612 4613 // Run the shader with inputs. 4614 { 4615 UniquePtr<ShaderExecutor> executor (createExecutor(getRenderContext(), 4616 m_ctx.shaderType, 4617 spec)); 4618 const void* inputArr[] = 4619 { 4620 &inputs.in0.front(), &inputs.in1.front(), &inputs.in2.front(), &inputs.in3.front(), 4621 }; 4622 void* outputArr[] = 4623 { 4624 &outputs.out0.front(), &outputs.out1.front(), 4625 }; 4626 4627 executor->log(log()); 4628 if (!executor->isOk()) 4629 TCU_FAIL("Shader compilation failed"); 4630 4631 executor->useProgram(); 4632 executor->execute(int(numValues), inputArr, outputArr); 4633 } 4634 4635 // Initialize environment with dummy values so we don't need to bind in inner loop. 4636 { 4637 const typename Traits<In0>::IVal in0; 4638 const typename Traits<In1>::IVal in1; 4639 const typename Traits<In2>::IVal in2; 4640 const typename Traits<In3>::IVal in3; 4641 const typename Traits<Out0>::IVal reference0; 4642 const typename Traits<Out1>::IVal reference1; 4643 4644 env.bind(*variables.in0, in0); 4645 env.bind(*variables.in1, in1); 4646 env.bind(*variables.in2, in2); 4647 env.bind(*variables.in3, in3); 4648 env.bind(*variables.out0, reference0); 4649 env.bind(*variables.out1, reference1); 4650 } 4651 4652 // For each input tuple, compute output reference interval and compare 4653 // shader output to the reference. 4654 for (size_t valueNdx = 0; valueNdx < numValues; valueNdx++) 4655 { 4656 bool result = true; 4657 bool inExpectedRange; 4658 bool inWarningRange; 4659 const char* failStr = "Fail"; 4660 typename Traits<Out0>::IVal reference0; 4661 typename Traits<Out1>::IVal reference1; 4662 4663 if (valueNdx % (size_t)TOUCH_WATCHDOG_VALUE_FREQUENCY == 0) 4664 m_testCtx.touchWatchdog(); 4665 4666 env.lookup(*variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx])); 4667 env.lookup(*variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx])); 4668 env.lookup(*variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx])); 4669 env.lookup(*variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx])); 4670 4671 { 4672 EvalContext ctx (fmt, m_ctx.precision, env); 4673 stmt.execute(ctx); 4674 } 4675 4676 switch (outCount) 4677 { 4678 case 2: 4679 reference1 = convert<Out1>(highpFmt, env.lookup(*variables.out1)); 4680 inExpectedRange = contains(reference1, outputs.out1[valueNdx]); 4681 inWarningRange = containsWarning(reference1, outputs.out1[valueNdx]); 4682 if (!inExpectedRange && inWarningRange) 4683 { 4684 m_status.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Shader output 1 has low-quality shader precision"); 4685 failStr = "QualityWarning"; 4686 result = false; 4687 } 4688 else if (!inExpectedRange) 4689 { 4690 m_status.addResult(QP_TEST_RESULT_FAIL, "Shader output 1 is outside acceptable range"); 4691 failStr = "Fail"; 4692 result = false; 4693 } 4694 4695 case 1: 4696 reference0 = convert<Out0>(highpFmt, env.lookup(*variables.out0)); 4697 inExpectedRange = contains(reference0, outputs.out0[valueNdx]); 4698 inWarningRange = containsWarning(reference0, outputs.out0[valueNdx]); 4699 if (!inExpectedRange && inWarningRange) 4700 { 4701 m_status.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Shader output 0 has low-quality shader precision"); 4702 failStr = "QualityWarning"; 4703 result = false; 4704 } 4705 else if (!inExpectedRange) 4706 { 4707 m_status.addResult(QP_TEST_RESULT_FAIL, "Shader output 0 is outside acceptable range"); 4708 failStr = "Fail"; 4709 result = false; 4710 } 4711 4712 default: break; 4713 } 4714 4715 if (!result) 4716 ++numErrors; 4717 4718 if ((!result && numErrors <= maxMsgs) || GLS_LOG_ALL_RESULTS) 4719 { 4720 MessageBuilder builder = log().message(); 4721 4722 builder << (result ? "Passed" : failStr) << " sample:\n"; 4723 4724 if (inCount > 0) 4725 { 4726 builder << "\t" << variables.in0->getName() << " = " 4727 << valueToString(highpFmt, inputs.in0[valueNdx]) << "\n"; 4728 } 4729 4730 if (inCount > 1) 4731 { 4732 builder << "\t" << variables.in1->getName() << " = " 4733 << valueToString(highpFmt, inputs.in1[valueNdx]) << "\n"; 4734 } 4735 4736 if (inCount > 2) 4737 { 4738 builder << "\t" << variables.in2->getName() << " = " 4739 << valueToString(highpFmt, inputs.in2[valueNdx]) << "\n"; 4740 } 4741 4742 if (inCount > 3) 4743 { 4744 builder << "\t" << variables.in3->getName() << " = " 4745 << valueToString(highpFmt, inputs.in3[valueNdx]) << "\n"; 4746 } 4747 4748 if (outCount > 0) 4749 { 4750 builder << "\t" << variables.out0->getName() << " = " 4751 << valueToString(highpFmt, outputs.out0[valueNdx]) << "\n" 4752 << "\tExpected range: " 4753 << intervalToString<typename Out::Out0>(highpFmt, reference0) << "\n"; 4754 } 4755 4756 if (outCount > 1) 4757 { 4758 builder << "\t" << variables.out1->getName() << " = " 4759 << valueToString(highpFmt, outputs.out1[valueNdx]) << "\n" 4760 << "\tExpected range: " 4761 << intervalToString<typename Out::Out1>(highpFmt, reference1) << "\n"; 4762 } 4763 4764 builder << TestLog::EndMessage; 4765 } 4766 } 4767 4768 if (numErrors > maxMsgs) 4769 { 4770 log() << TestLog::Message << "(Skipped " << (numErrors - maxMsgs) << " messages.)" 4771 << TestLog::EndMessage; 4772 } 4773 4774 if (numErrors == 0) 4775 { 4776 log() << TestLog::Message << "All " << numValues << " inputs passed." 4777 << TestLog::EndMessage; 4778 } 4779 else 4780 { 4781 log() << TestLog::Message << numErrors << "/" << numValues << " inputs failed or had quality warnings." 4782 << TestLog::EndMessage; 4783 } 4784 } 4785 4786 4787 4788 template <typename T> 4789 struct InputLess 4790 { 4791 bool operator() (const T& val1, const T& val2) const 4792 { 4793 return val1 < val2; 4794 } 4795 }; 4796 4797 template <typename T> 4798 bool inputLess (const T& val1, const T& val2) 4799 { 4800 return InputLess<T>()(val1, val2); 4801 } 4802 4803 template <> 4804 struct InputLess<float> 4805 { 4806 bool operator() (const float& val1, const float& val2) const 4807 { 4808 if (deIsNaN(val1)) 4809 return false; 4810 if (deIsNaN(val2)) 4811 return true; 4812 return val1 < val2; 4813 } 4814 }; 4815 4816 template <typename T, int Size> 4817 struct InputLess<Vector<T, Size> > 4818 { 4819 bool operator() (const Vector<T, Size>& vec1, const Vector<T, Size>& vec2) const 4820 { 4821 for (int ndx = 0; ndx < Size; ++ndx) 4822 { 4823 if (inputLess(vec1[ndx], vec2[ndx])) 4824 return true; 4825 if (inputLess(vec2[ndx], vec1[ndx])) 4826 return false; 4827 } 4828 4829 return false; 4830 } 4831 }; 4832 4833 template <typename T, int Rows, int Cols> 4834 struct InputLess<Matrix<T, Rows, Cols> > 4835 { 4836 bool operator() (const Matrix<T, Rows, Cols>& mat1, 4837 const Matrix<T, Rows, Cols>& mat2) const 4838 { 4839 for (int col = 0; col < Cols; ++col) 4840 { 4841 if (inputLess(mat1[col], mat2[col])) 4842 return true; 4843 if (inputLess(mat2[col], mat1[col])) 4844 return false; 4845 } 4846 4847 return false; 4848 } 4849 }; 4850 4851 template <typename In> 4852 struct InTuple : 4853 public Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3> 4854 { 4855 InTuple (const typename In::In0& in0, 4856 const typename In::In1& in1, 4857 const typename In::In2& in2, 4858 const typename In::In3& in3) 4859 : Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3> 4860 (in0, in1, in2, in3) {} 4861 }; 4862 4863 template <typename In> 4864 struct InputLess<InTuple<In> > 4865 { 4866 bool operator() (const InTuple<In>& in1, const InTuple<In>& in2) const 4867 { 4868 if (inputLess(in1.a, in2.a)) 4869 return true; 4870 if (inputLess(in2.a, in1.a)) 4871 return false; 4872 if (inputLess(in1.b, in2.b)) 4873 return true; 4874 if (inputLess(in2.b, in1.b)) 4875 return false; 4876 if (inputLess(in1.c, in2.c)) 4877 return true; 4878 if (inputLess(in2.c, in1.c)) 4879 return false; 4880 if (inputLess(in1.d, in2.d)) 4881 return true; 4882 return false; 4883 }; 4884 }; 4885 4886 template<typename In> 4887 Inputs<In> generateInputs (const Samplings<In>& samplings, 4888 const FloatFormat& floatFormat, 4889 Precision intPrecision, 4890 size_t numSamples, 4891 Random& rnd) 4892 { 4893 Inputs<In> ret; 4894 Inputs<In> fixedInputs; 4895 set<InTuple<In>, InputLess<InTuple<In> > > seenInputs; 4896 4897 samplings.in0.genFixeds(floatFormat, fixedInputs.in0); 4898 samplings.in1.genFixeds(floatFormat, fixedInputs.in1); 4899 samplings.in2.genFixeds(floatFormat, fixedInputs.in2); 4900 samplings.in3.genFixeds(floatFormat, fixedInputs.in3); 4901 4902 for (size_t ndx0 = 0; ndx0 < fixedInputs.in0.size(); ++ndx0) 4903 { 4904 for (size_t ndx1 = 0; ndx1 < fixedInputs.in1.size(); ++ndx1) 4905 { 4906 for (size_t ndx2 = 0; ndx2 < fixedInputs.in2.size(); ++ndx2) 4907 { 4908 for (size_t ndx3 = 0; ndx3 < fixedInputs.in3.size(); ++ndx3) 4909 { 4910 const InTuple<In> tuple (fixedInputs.in0[ndx0], 4911 fixedInputs.in1[ndx1], 4912 fixedInputs.in2[ndx2], 4913 fixedInputs.in3[ndx3]); 4914 4915 seenInputs.insert(tuple); 4916 ret.in0.push_back(tuple.a); 4917 ret.in1.push_back(tuple.b); 4918 ret.in2.push_back(tuple.c); 4919 ret.in3.push_back(tuple.d); 4920 } 4921 } 4922 } 4923 } 4924 4925 for (size_t ndx = 0; ndx < numSamples; ++ndx) 4926 { 4927 const typename In::In0 in0 = samplings.in0.genRandom(floatFormat, intPrecision, rnd); 4928 const typename In::In1 in1 = samplings.in1.genRandom(floatFormat, intPrecision, rnd); 4929 const typename In::In2 in2 = samplings.in2.genRandom(floatFormat, intPrecision, rnd); 4930 const typename In::In3 in3 = samplings.in3.genRandom(floatFormat, intPrecision, rnd); 4931 const InTuple<In> tuple (in0, in1, in2, in3); 4932 4933 if (de::contains(seenInputs, tuple)) 4934 continue; 4935 4936 seenInputs.insert(tuple); 4937 ret.in0.push_back(in0); 4938 ret.in1.push_back(in1); 4939 ret.in2.push_back(in2); 4940 ret.in3.push_back(in3); 4941 } 4942 4943 return ret; 4944 } 4945 4946 class FuncCaseBase : public PrecisionCase 4947 { 4948 public: 4949 IterateResult iterate (void); 4950 4951 protected: 4952 FuncCaseBase (const Context& context, 4953 const string& name, 4954 const FuncBase& func) 4955 : PrecisionCase (context, name, func.getRequiredExtension()) {} 4956 }; 4957 4958 IterateResult FuncCaseBase::iterate (void) 4959 { 4960 MovePtr<ContextInfo> info (ContextInfo::create(getRenderContext())); 4961 4962 if (!m_extension.empty() && !info->isExtensionSupported(m_extension.c_str())) 4963 throw NotSupportedError("Unsupported extension: " + m_extension); 4964 4965 runTest(); 4966 4967 m_status.setTestContextResult(m_testCtx); 4968 return STOP; 4969 } 4970 4971 template <typename Sig> 4972 class FuncCase : public FuncCaseBase 4973 { 4974 public: 4975 typedef Func<Sig> CaseFunc; 4976 typedef typename Sig::Ret Ret; 4977 typedef typename Sig::Arg0 Arg0; 4978 typedef typename Sig::Arg1 Arg1; 4979 typedef typename Sig::Arg2 Arg2; 4980 typedef typename Sig::Arg3 Arg3; 4981 typedef InTypes<Arg0, Arg1, Arg2, Arg3> In; 4982 typedef OutTypes<Ret> Out; 4983 4984 FuncCase (const Context& context, 4985 const string& name, 4986 const CaseFunc& func) 4987 : FuncCaseBase (context, name, func) 4988 , m_func (func) {} 4989 4990 protected: 4991 void runTest (void); 4992 4993 virtual const Samplings<In>& getSamplings (void) 4994 { 4995 return instance<DefaultSamplings<In> >(); 4996 } 4997 4998 private: 4999 const CaseFunc& m_func; 5000 }; 5001 5002 template <typename Sig> 5003 void FuncCase<Sig>::runTest (void) 5004 { 5005 const Inputs<In> inputs (generateInputs(getSamplings(), 5006 m_ctx.floatFormat, 5007 m_ctx.precision, 5008 m_ctx.numRandoms, 5009 m_rnd)); 5010 Variables<In, Out> variables; 5011 5012 variables.out0 = variable<Ret>("out0"); 5013 variables.out1 = variable<Void>("out1"); 5014 variables.in0 = variable<Arg0>("in0"); 5015 variables.in1 = variable<Arg1>("in1"); 5016 variables.in2 = variable<Arg2>("in2"); 5017 variables.in3 = variable<Arg3>("in3"); 5018 5019 { 5020 ExprP<Ret> expr = applyVar(m_func, 5021 variables.in0, variables.in1, 5022 variables.in2, variables.in3); 5023 StatementP stmt = variableAssignment(variables.out0, expr); 5024 5025 this->testStatement(variables, inputs, *stmt); 5026 } 5027 } 5028 5029 template <typename Sig> 5030 class InOutFuncCase : public FuncCaseBase 5031 { 5032 public: 5033 typedef Func<Sig> CaseFunc; 5034 typedef typename Sig::Ret Ret; 5035 typedef typename Sig::Arg0 Arg0; 5036 typedef typename Sig::Arg1 Arg1; 5037 typedef typename Sig::Arg2 Arg2; 5038 typedef typename Sig::Arg3 Arg3; 5039 typedef InTypes<Arg0, Arg2, Arg3> In; 5040 typedef OutTypes<Ret, Arg1> Out; 5041 5042 InOutFuncCase (const Context& context, 5043 const string& name, 5044 const CaseFunc& func) 5045 : FuncCaseBase (context, name, func) 5046 , m_func (func) {} 5047 5048 protected: 5049 void runTest (void); 5050 5051 virtual const Samplings<In>& getSamplings (void) 5052 { 5053 return instance<DefaultSamplings<In> >(); 5054 } 5055 5056 private: 5057 const CaseFunc& m_func; 5058 }; 5059 5060 template <typename Sig> 5061 void InOutFuncCase<Sig>::runTest (void) 5062 { 5063 const Inputs<In> inputs (generateInputs(getSamplings(), 5064 m_ctx.floatFormat, 5065 m_ctx.precision, 5066 m_ctx.numRandoms, 5067 m_rnd)); 5068 Variables<In, Out> variables; 5069 5070 variables.out0 = variable<Ret>("out0"); 5071 variables.out1 = variable<Arg1>("out1"); 5072 variables.in0 = variable<Arg0>("in0"); 5073 variables.in1 = variable<Arg2>("in1"); 5074 variables.in2 = variable<Arg3>("in2"); 5075 variables.in3 = variable<Void>("in3"); 5076 5077 { 5078 ExprP<Ret> expr = applyVar(m_func, 5079 variables.in0, variables.out1, 5080 variables.in1, variables.in2); 5081 StatementP stmt = variableAssignment(variables.out0, expr); 5082 5083 this->testStatement(variables, inputs, *stmt); 5084 } 5085 } 5086 5087 template <typename Sig> 5088 PrecisionCase* createFuncCase (const Context& context, 5089 const string& name, 5090 const Func<Sig>& func) 5091 { 5092 switch (func.getOutParamIndex()) 5093 { 5094 case -1: 5095 return new FuncCase<Sig>(context, name, func); 5096 case 1: 5097 return new InOutFuncCase<Sig>(context, name, func); 5098 default: 5099 DE_FATAL("Impossible"); 5100 } 5101 return DE_NULL; 5102 } 5103 5104 class CaseFactory 5105 { 5106 public: 5107 virtual ~CaseFactory (void) {} 5108 virtual MovePtr<TestNode> createCase (const Context& ctx) const = 0; 5109 virtual string getName (void) const = 0; 5110 virtual string getDesc (void) const = 0; 5111 }; 5112 5113 class FuncCaseFactory : public CaseFactory 5114 { 5115 public: 5116 virtual const FuncBase& getFunc (void) const = 0; 5117 5118 string getName (void) const 5119 { 5120 return de::toLower(getFunc().getName()); 5121 } 5122 5123 string getDesc (void) const 5124 { 5125 return "Function '" + getFunc().getName() + "'"; 5126 } 5127 }; 5128 5129 template <typename Sig> 5130 class GenFuncCaseFactory : public CaseFactory 5131 { 5132 public: 5133 5134 GenFuncCaseFactory (const GenFuncs<Sig>& funcs, 5135 const string& name) 5136 : m_funcs (funcs) 5137 , m_name (de::toLower(name)) {} 5138 5139 MovePtr<TestNode> createCase (const Context& ctx) const 5140 { 5141 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, 5142 ctx.name.c_str(), ctx.name.c_str()); 5143 5144 group->addChild(createFuncCase(ctx, "scalar", m_funcs.func)); 5145 group->addChild(createFuncCase(ctx, "vec2", m_funcs.func2)); 5146 group->addChild(createFuncCase(ctx, "vec3", m_funcs.func3)); 5147 group->addChild(createFuncCase(ctx, "vec4", m_funcs.func4)); 5148 5149 return MovePtr<TestNode>(group); 5150 } 5151 5152 string getName (void) const 5153 { 5154 return m_name; 5155 } 5156 5157 string getDesc (void) const 5158 { 5159 return "Function '" + m_funcs.func.getName() + "'"; 5160 } 5161 5162 private: 5163 const GenFuncs<Sig> m_funcs; 5164 string m_name; 5165 }; 5166 5167 template <template <int> class GenF> 5168 class TemplateFuncCaseFactory : public FuncCaseFactory 5169 { 5170 public: 5171 MovePtr<TestNode> createCase (const Context& ctx) const 5172 { 5173 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, 5174 ctx.name.c_str(), ctx.name.c_str()); 5175 group->addChild(createFuncCase(ctx, "scalar", instance<GenF<1> >())); 5176 group->addChild(createFuncCase(ctx, "vec2", instance<GenF<2> >())); 5177 group->addChild(createFuncCase(ctx, "vec3", instance<GenF<3> >())); 5178 group->addChild(createFuncCase(ctx, "vec4", instance<GenF<4> >())); 5179 5180 return MovePtr<TestNode>(group); 5181 } 5182 5183 const FuncBase& getFunc (void) const { return instance<GenF<1> >(); } 5184 }; 5185 5186 template <template <int> class GenF> 5187 class SquareMatrixFuncCaseFactory : public FuncCaseFactory 5188 { 5189 public: 5190 MovePtr<TestNode> createCase (const Context& ctx) const 5191 { 5192 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, 5193 ctx.name.c_str(), ctx.name.c_str()); 5194 group->addChild(createFuncCase(ctx, "mat2", instance<GenF<2> >())); 5195 #if 0 5196 // disabled until we get reasonable results 5197 group->addChild(createFuncCase(ctx, "mat3", instance<GenF<3> >())); 5198 group->addChild(createFuncCase(ctx, "mat4", instance<GenF<4> >())); 5199 #endif 5200 5201 return MovePtr<TestNode>(group); 5202 } 5203 5204 const FuncBase& getFunc (void) const { return instance<GenF<2> >(); } 5205 }; 5206 5207 template <template <int, int> class GenF> 5208 class MatrixFuncCaseFactory : public FuncCaseFactory 5209 { 5210 public: 5211 MovePtr<TestNode> createCase (const Context& ctx) const 5212 { 5213 TestCaseGroup* const group = new TestCaseGroup(ctx.testContext, 5214 ctx.name.c_str(), ctx.name.c_str()); 5215 5216 this->addCase<2, 2>(ctx, group); 5217 this->addCase<3, 2>(ctx, group); 5218 this->addCase<4, 2>(ctx, group); 5219 this->addCase<2, 3>(ctx, group); 5220 this->addCase<3, 3>(ctx, group); 5221 this->addCase<4, 3>(ctx, group); 5222 this->addCase<2, 4>(ctx, group); 5223 this->addCase<3, 4>(ctx, group); 5224 this->addCase<4, 4>(ctx, group); 5225 5226 return MovePtr<TestNode>(group); 5227 } 5228 5229 const FuncBase& getFunc (void) const { return instance<GenF<2,2> >(); } 5230 5231 private: 5232 template <int Rows, int Cols> 5233 void addCase (const Context& ctx, TestCaseGroup* group) const 5234 { 5235 const char* const name = dataTypeNameOf<Matrix<float, Rows, Cols> >(); 5236 5237 group->addChild(createFuncCase(ctx, name, instance<GenF<Rows, Cols> >())); 5238 } 5239 }; 5240 5241 template <typename Sig> 5242 class SimpleFuncCaseFactory : public CaseFactory 5243 { 5244 public: 5245 SimpleFuncCaseFactory (const Func<Sig>& func) : m_func(func) {} 5246 5247 MovePtr<TestNode> createCase (const Context& ctx) const 5248 { 5249 return MovePtr<TestNode>(createFuncCase(ctx, ctx.name.c_str(), m_func)); 5250 } 5251 5252 string getName (void) const 5253 { 5254 return de::toLower(m_func.getName()); 5255 } 5256 5257 string getDesc (void) const 5258 { 5259 return "Function '" + getName() + "'"; 5260 } 5261 5262 private: 5263 const Func<Sig>& m_func; 5264 }; 5265 5266 template <typename F> 5267 SharedPtr<SimpleFuncCaseFactory<typename F::Sig> > createSimpleFuncCaseFactory (void) 5268 { 5269 return SharedPtr<SimpleFuncCaseFactory<typename F::Sig> >( 5270 new SimpleFuncCaseFactory<typename F::Sig>(instance<F>())); 5271 } 5272 5273 class BuiltinFuncs : public CaseFactories 5274 { 5275 public: 5276 const vector<const CaseFactory*> getFactories (void) const 5277 { 5278 vector<const CaseFactory*> ret; 5279 5280 for (size_t ndx = 0; ndx < m_factories.size(); ++ndx) 5281 ret.push_back(m_factories[ndx].get()); 5282 5283 return ret; 5284 } 5285 5286 void addFactory (SharedPtr<const CaseFactory> fact) 5287 { 5288 m_factories.push_back(fact); 5289 } 5290 5291 private: 5292 vector<SharedPtr<const CaseFactory> > m_factories; 5293 }; 5294 5295 template <typename F> 5296 void addScalarFactory(BuiltinFuncs& funcs, string name = "") 5297 { 5298 if (name.empty()) 5299 name = instance<F>().getName(); 5300 5301 funcs.addFactory(SharedPtr<const CaseFactory>(new GenFuncCaseFactory<typename F::Sig>( 5302 makeVectorizedFuncs<F>(), name))); 5303 } 5304 5305 MovePtr<const CaseFactories> createES3BuiltinCases (void) 5306 { 5307 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs()); 5308 5309 addScalarFactory<Add>(*funcs); 5310 addScalarFactory<Sub>(*funcs); 5311 addScalarFactory<Mul>(*funcs); 5312 addScalarFactory<Div>(*funcs); 5313 5314 addScalarFactory<Radians>(*funcs); 5315 addScalarFactory<Degrees>(*funcs); 5316 addScalarFactory<Sin>(*funcs); 5317 addScalarFactory<Cos>(*funcs); 5318 addScalarFactory<Tan>(*funcs); 5319 addScalarFactory<ASin>(*funcs); 5320 addScalarFactory<ACos>(*funcs); 5321 addScalarFactory<ATan2>(*funcs, "atan2"); 5322 addScalarFactory<ATan>(*funcs); 5323 addScalarFactory<Sinh>(*funcs); 5324 addScalarFactory<Cosh>(*funcs); 5325 addScalarFactory<Tanh>(*funcs); 5326 addScalarFactory<ASinh>(*funcs); 5327 addScalarFactory<ACosh>(*funcs); 5328 addScalarFactory<ATanh>(*funcs); 5329 5330 addScalarFactory<Pow>(*funcs); 5331 addScalarFactory<Exp>(*funcs); 5332 addScalarFactory<Log>(*funcs); 5333 addScalarFactory<Exp2>(*funcs); 5334 addScalarFactory<Log2>(*funcs); 5335 addScalarFactory<Sqrt>(*funcs); 5336 addScalarFactory<InverseSqrt>(*funcs); 5337 5338 addScalarFactory<Abs>(*funcs); 5339 addScalarFactory<Sign>(*funcs); 5340 addScalarFactory<Floor>(*funcs); 5341 addScalarFactory<Trunc>(*funcs); 5342 addScalarFactory<Round>(*funcs); 5343 addScalarFactory<RoundEven>(*funcs); 5344 addScalarFactory<Ceil>(*funcs); 5345 addScalarFactory<Fract>(*funcs); 5346 addScalarFactory<Mod>(*funcs); 5347 funcs->addFactory(createSimpleFuncCaseFactory<Modf>()); 5348 addScalarFactory<Min>(*funcs); 5349 addScalarFactory<Max>(*funcs); 5350 addScalarFactory<Clamp>(*funcs); 5351 addScalarFactory<Mix>(*funcs); 5352 addScalarFactory<Step>(*funcs); 5353 addScalarFactory<SmoothStep>(*funcs); 5354 5355 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length>())); 5356 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance>())); 5357 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot>())); 5358 funcs->addFactory(createSimpleFuncCaseFactory<Cross>()); 5359 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize>())); 5360 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward>())); 5361 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect>())); 5362 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract>())); 5363 5364 5365 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<MatrixCompMult>())); 5366 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct>())); 5367 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose>())); 5368 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant>())); 5369 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse>())); 5370 5371 return MovePtr<const CaseFactories>(funcs.release()); 5372 } 5373 5374 MovePtr<const CaseFactories> createES31BuiltinCases (void) 5375 { 5376 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs()); 5377 5378 addScalarFactory<FrExp>(*funcs); 5379 addScalarFactory<LdExp>(*funcs); 5380 addScalarFactory<Fma>(*funcs); 5381 5382 return MovePtr<const CaseFactories>(funcs.release()); 5383 } 5384 5385 struct PrecisionTestContext 5386 { 5387 PrecisionTestContext (TestContext& testCtx_, 5388 RenderContext& renderCtx_, 5389 const FloatFormat& highp_, 5390 const FloatFormat& mediump_, 5391 const FloatFormat& lowp_, 5392 const vector<ShaderType>& shaderTypes_, 5393 int numRandoms_) 5394 : testCtx (testCtx_) 5395 , renderCtx (renderCtx_) 5396 , shaderTypes (shaderTypes_) 5397 , numRandoms (numRandoms_) 5398 { 5399 formats[glu::PRECISION_HIGHP] = &highp_; 5400 formats[glu::PRECISION_MEDIUMP] = &mediump_; 5401 formats[glu::PRECISION_LOWP] = &lowp_; 5402 } 5403 5404 TestContext& testCtx; 5405 RenderContext& renderCtx; 5406 const FloatFormat* formats[glu::PRECISION_LAST]; 5407 vector<ShaderType> shaderTypes; 5408 int numRandoms; 5409 }; 5410 5411 TestCaseGroup* createFuncGroup (const PrecisionTestContext& ctx, 5412 const CaseFactory& factory) 5413 { 5414 TestCaseGroup* const group = new TestCaseGroup(ctx.testCtx, 5415 factory.getName().c_str(), 5416 factory.getDesc().c_str()); 5417 5418 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; ++precNdx) 5419 { 5420 const Precision precision = Precision(precNdx); 5421 const string precName (glu::getPrecisionName(precision)); 5422 const FloatFormat& fmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats, precNdx); 5423 const FloatFormat& highpFmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats, 5424 glu::PRECISION_HIGHP); 5425 5426 for (size_t shaderNdx = 0; shaderNdx < ctx.shaderTypes.size(); ++shaderNdx) 5427 { 5428 const ShaderType shaderType = ctx.shaderTypes[shaderNdx]; 5429 const string shaderName (glu::getShaderTypeName(shaderType)); 5430 const string name = precName + "_" + shaderName; 5431 const Context caseCtx (name, ctx.testCtx, ctx.renderCtx, fmt, highpFmt, 5432 precision, shaderType, ctx.numRandoms); 5433 5434 group->addChild(factory.createCase(caseCtx).release()); 5435 } 5436 } 5437 5438 return group; 5439 } 5440 5441 void addBuiltinPrecisionTests (TestContext& testCtx, 5442 RenderContext& renderCtx, 5443 const CaseFactories& cases, 5444 const vector<ShaderType>& shaderTypes, 5445 TestCaseGroup& dstGroup) 5446 { 5447 const int userRandoms = testCtx.getCommandLine().getTestIterationCount(); 5448 const int defRandoms = 16384; 5449 const int numRandoms = userRandoms > 0 ? userRandoms : defRandoms; 5450 const FloatFormat highp (-126, 127, 23, true, 5451 tcu::MAYBE, // subnormals 5452 tcu::YES, // infinities 5453 tcu::MAYBE); // NaN 5454 // \todo [2014-04-01 lauri] Check these once Khronos bug 11840 is resolved. 5455 const FloatFormat mediump (-13, 13, 9, false); 5456 // A fixed-point format is just a floating point format with a fixed 5457 // exponent and support for subnormals. 5458 const FloatFormat lowp (0, 0, 7, false, tcu::YES); 5459 const PrecisionTestContext ctx (testCtx, renderCtx, highp, mediump, lowp, 5460 shaderTypes, numRandoms); 5461 5462 for (size_t ndx = 0; ndx < cases.getFactories().size(); ++ndx) 5463 dstGroup.addChild(createFuncGroup(ctx, *cases.getFactories()[ndx])); 5464 } 5465 5466 } // BuiltinPrecisionTests 5467 } // gls 5468 } // deqp 5469