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