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