glsBuiltinPrecisionTests.cpp revision 8852c82a1ffa4760985c17cc6875d5d521daf343
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 64namespace deqp 65{ 66namespace gls 67{ 68namespace BuiltinPrecisionTests 69{ 70 71using std::string; 72using std::map; 73using std::ostream; 74using std::ostringstream; 75using std::pair; 76using std::vector; 77using std::set; 78 79using de::MovePtr; 80using de::Random; 81using de::SharedPtr; 82using de::UniquePtr; 83using tcu::Interval; 84using tcu::FloatFormat; 85using tcu::MessageBuilder; 86using tcu::TestCase; 87using tcu::TestLog; 88using tcu::Vector; 89using tcu::Matrix; 90namespace matrix = tcu::matrix; 91using glu::Precision; 92using glu::RenderContext; 93using glu::VarType; 94using glu::DataType; 95using glu::ShaderType; 96using glu::ContextInfo; 97using gls::ShaderExecUtil::Symbol; 98 99typedef TestCase::IterateResult IterateResult; 100 101using namespace glw; 102using 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 *//*--------------------------------------------------------------------*/ 115template <typename T> 116const 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 *//*--------------------------------------------------------------------*/ 134struct 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 152ostream& operator<< (ostream& os, Void) { return os << "()"; } 153 154//! Returns true for all other types except Void 155template <typename T> bool isTypeValid (void) { return true; } 156template <> 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. 160template <typename T> 161const char* dataTypeNameOf (void) 162{ 163 return glu::getDataTypeName(glu::dataTypeOf<T>()); 164} 165 166template <> 167const char* dataTypeNameOf<Void> (void) 168{ 169 DE_ASSERT(!"Impossible"); 170 return DE_NULL; 171} 172 173//! A hack to get Void support for VarType. 174template <typename T> 175VarType getVarTypeOf (Precision prec = glu::PRECISION_LAST) 176{ 177 return glu::varTypeOf<T>(prec); 178} 179 180template <> 181VarType 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 212template <typename T> struct Traits; 213 214//! Create container from elementwise singleton values. 215template <typename T> 216typename Traits<T>::IVal makeIVal (const T& value) 217{ 218 return Traits<T>::doMakeIVal(value); 219} 220 221//! Elementwise union of intervals. 222template <typename T> 223typename 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`. 230template <typename T> 231bool 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`. 237template <typename T> 238void printIVal (const FloatFormat& fmt, const typename Traits<T>::IVal& ival, ostream& os) 239{ 240 Traits<T>::doPrintIVal(fmt, ival, os); 241} 242 243template <typename T> 244string 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`. 252template <typename T> 253void printValue (const FloatFormat& fmt, const T& value, ostream& os) 254{ 255 Traits<T>::doPrintValue(fmt, value, os); 256} 257 258template <typename T> 259string 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. 269template <typename T> 270typename Traits<T>::IVal round (const FloatFormat& fmt, const T& value) 271{ 272 return Traits<T>::doRound(fmt, value); 273} 274 275template <typename T> 276typename 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. 283template <typename T> 284struct 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)); 313 } 314}; 315 316template<> 317struct 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 334template<> 335struct 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 359template<> 360struct 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. 379template <typename T, typename I> 380struct 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 465template <typename T, int Size> 466struct Traits<Vector<T, Size> > : 467 ContainerTraits<Vector<T, Size>, Vector<typename Traits<T>::IVal, Size> > 468{ 469}; 470 471template <typename T, int Rows, int Cols> 472struct 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. 479template<> 480struct 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". 503template <typename T, int Size> struct ContainerOf { typedef Vector<T, Size> Container; }; 504 505template <typename T> struct ContainerOf<T, 1> { typedef T Container; }; 506template <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. 509template <typename T> struct ElementOf { typedef typename T::Element Element; }; 510template <> struct ElementOf<float> { typedef void Element; }; 511template <> struct ElementOf<bool> { typedef void Element; }; 512template <> 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 530class ExprBase; 531class ExpandContext; 532class Statement; 533class StatementP; 534class FuncBase; 535template <typename T> class ExprP; 536template <typename T> class Variable; 537template <typename T> class VariableP; 538template <typename T> class DefaultSampling; 539 540typedef set<const FuncBase*> FuncSet; 541 542template <typename T> 543VariableP<T> variable (const string& name); 544StatementP 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 *//*--------------------------------------------------------------------*/ 555class Environment 556{ 557public: 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 576private: 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 *//*--------------------------------------------------------------------*/ 588struct 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 *//*--------------------------------------------------------------------*/ 612class Counter 613{ 614public: 615 Counter (int count = 0) : m_count(count) {} 616 int operator() (void) { return m_count++; } 617 618private: 619 int m_count; 620}; 621 622class ExpandContext 623{ 624public: 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 } 644private: 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 *//*--------------------------------------------------------------------*/ 661class Statement 662{ 663public: 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 671protected: 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 677ostream& 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 *//*--------------------------------------------------------------------*/ 687class StatementP : public SharedPtr<const Statement> 688{ 689public: 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 *//*--------------------------------------------------------------------*/ 703template <typename T> 704class VariableStatement : public Statement 705{ 706public: 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 713protected: 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 742template <typename T> 743StatementP 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 750template <typename T> 751StatementP variableDeclaration (const VariableP<T>& variable, const ExprP<T>& definiens) 752{ 753 return variableStatement(variable, definiens, true); 754} 755 756template <typename T> 757StatementP 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 *//*--------------------------------------------------------------------*/ 769class CompoundStatement : public Statement 770{ 771public: 772 CompoundStatement (const vector<StatementP>& statements) 773 : m_statements (statements) {} 774 775protected: 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 801StatementP 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. 807class ExprBase 808{ 809public: 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 819protected: 820 virtual void doPrintExpr (ostream&) const {} 821 virtual void doGetUsedFuncs (FuncSet&) const {} 822}; 823 824//! Type-specific operations for an expression representing type T. 825template <typename T> 826class Expr : public ExprBase 827{ 828public: 829 typedef T Val; 830 typedef typename Traits<T>::IVal IVal; 831 832 IVal evaluate (const EvalContext& ctx) const; 833 834protected: 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. 839template <typename T> 840typename 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 863template <typename T> 864class ExprPBase : public SharedPtr<const Expr<T> > 865{ 866public: 867}; 868 869ostream& 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 *//*--------------------------------------------------------------------*/ 882template <typename T> 883class ContainerExprPBase : public ExprPBase<T> 884{ 885public: 886 ExprP<typename T::Element> operator[] (int i) const; 887}; 888 889template <typename T> 890class ExprP : public ExprPBase<T> {}; 891 892// We treat Voids as containers since the dummy parameters in generalized 893// vector functions are represented as Voids. 894template <> 895class ExprP<Void> : public ContainerExprPBase<Void> {}; 896 897template <typename T, int Size> 898class ExprP<Vector<T, Size> > : public ContainerExprPBase<Vector<T, Size> > {}; 899 900template <typename T, int Rows, int Cols> 901class ExprP<Matrix<T, Rows, Cols> > : public ContainerExprPBase<Matrix<T, Rows, Cols> > {}; 902 903template <typename T> ExprP<T> exprP (void) 904{ 905 return ExprP<T>(); 906} 907 908template <typename T> 909ExprP<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 916template <typename T> 917ExprP<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 *//*--------------------------------------------------------------------*/ 929template <typename T> 930class VariableP : public SharedPtr<const Variable<T> > 931{ 932public: 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 *//*--------------------------------------------------------------------*/ 951ExprP<float> operator-(const ExprP<float>& arg0); 952ExprP<float> operator+(const ExprP<float>& arg0, 953 const ExprP<float>& arg1); 954ExprP<float> operator-(const ExprP<float>& arg0, 955 const ExprP<float>& arg1); 956ExprP<float> operator*(const ExprP<float>& arg0, 957 const ExprP<float>& arg1); 958ExprP<float> operator/(const ExprP<float>& arg0, 959 const ExprP<float>& arg1); 960template<int Size> 961ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0); 962template<int Size> 963ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0, 964 const ExprP<float>& arg1); 965template<int Size> 966ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0, 967 const ExprP<Vector<float, Size> >& arg1); 968template<int Size> 969ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0, 970 const ExprP<Vector<float, Size> >& arg1); 971template<int Left, int Mid, int Right> 972ExprP<Matrix<float, Left, Right> > operator* (const ExprP<Matrix<float, Left, Mid> >& left, 973 const ExprP<Matrix<float, Mid, Right> >& right); 974template<int Rows, int Cols> 975ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left, 976 const ExprP<Matrix<float, Rows, Cols> >& right); 977template<int Rows, int Cols> 978ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left, 979 const ExprP<Vector<float, Rows> >& right); 980template<int Rows, int Cols> 981ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left, 982 const ExprP<float>& right); 983template<int Rows, int Cols> 984ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left, 985 const ExprP<Matrix<float, Rows, Cols> >& right); 986template<int Rows, int Cols> 987ExprP<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 *//*--------------------------------------------------------------------*/ 997template <typename T> 998class Variable : public Expr<T> 999{ 1000public: 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 1006protected: 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 1013private: 1014 string m_name; 1015}; 1016 1017template <typename T> 1018VariableP<T> variable (const string& name) 1019{ 1020 return VariableP<T>(new Variable<T>(name)); 1021} 1022 1023template <typename T> 1024VariableP<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 *//*--------------------------------------------------------------------*/ 1037template <typename T> 1038class Constant : public Expr<T> 1039{ 1040public: 1041 typedef typename Expr<T>::IVal IVal; 1042 1043 Constant (const T& value) : m_value(value) {} 1044 1045protected: 1046 void doPrintExpr (ostream& os) const { os << m_value; } 1047 IVal doEvaluate (const EvalContext&) const { return makeIVal(m_value); } 1048 1049private: 1050 T m_value; 1051}; 1052 1053template <typename T> 1054ExprP<T> constant (const T& value) 1055{ 1056 return exprP(new Constant<T>(value)); 1057} 1058 1059//! Return a reference to a singleton void constant. 1060const 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 *//*--------------------------------------------------------------------*/ 1074template <typename T0 = Void, typename T1 = Void, typename T2 = Void, typename T3 = Void> 1075struct 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 *//*--------------------------------------------------------------------*/ 1103template <typename R, 1104 typename P0 = Void, typename P1 = Void, 1105 typename P2 = Void, typename P3 = Void> 1106struct 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 1124typedef vector<const ExprBase*> BaseArgExprs; 1125 1126/*--------------------------------------------------------------------*//*! 1127 * \brief Type-independent operations for function objects. 1128 * 1129 *//*--------------------------------------------------------------------*/ 1130class FuncBase 1131{ 1132public: 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 1152protected: 1153 virtual void doPrintDefinition (ostream& os) const = 0; 1154 virtual void doGetUsedFuncs (FuncSet& dst) const = 0; 1155}; 1156 1157typedef 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 *//*--------------------------------------------------------------------*/ 1169template <typename Sig_> 1170class Func : public FuncBase 1171{ 1172public: 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 1217protected: 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 1246template <typename Sig> 1247class Apply : public Expr<typename Sig::Ret> 1248{ 1249public: 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) {} 1272protected: 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 1303template <typename Sig> 1304ExprP<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 1310template <typename Sig> 1311ExprP<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 1321template <typename Sig> 1322ExprP<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 1330template <typename F> 1331ExprP<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 1339template <typename F> 1340typename 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 1349template <typename Sig> 1350class ApplyVar : public Apply<Sig> 1351{ 1352public: 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) {} 1369protected: 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 1382template <typename Sig> 1383ExprP<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 1392template <typename Sig_> 1393class DerivedFunc : public Func<Sig_> 1394{ 1395public: 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 1409protected: 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 1490private: 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 1512template <typename Sig> 1513class PrimitiveFunc : public Func<Sig> 1514{ 1515public: 1516 typedef typename PrimitiveFunc::Ret Ret; 1517 typedef typename PrimitiveFunc::ArgExprs ArgExprs; 1518 1519protected: 1520 void doPrintDefinition (ostream&) const {} 1521 void doGetUsedFuncs (FuncSet&) const {} 1522}; 1523 1524template <typename T> 1525class Cond : public PrimitiveFunc<Signature<T, bool, T, T> > 1526{ 1527public: 1528 typedef typename Cond::IArgs IArgs; 1529 typedef typename Cond::IRet IRet; 1530 1531 string getName (void) const 1532 { 1533 return "_cond"; 1534 } 1535 1536protected: 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 1557template <typename T> 1558class CompareOperator : public PrimitiveFunc<Signature<bool, T, T> > 1559{ 1560public: 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 1566protected: 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 1591template <typename T> 1592class LessThan : public CompareOperator<T> 1593{ 1594public: 1595 string getName (void) const { return "lessThan"; } 1596 1597protected: 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 1611template <typename T> 1612ExprP<bool> operator< (const ExprP<T>& a, const ExprP<T>& b) 1613{ 1614 return app<LessThan<T> >(a, b); 1615} 1616 1617template <typename T> 1618ExprP<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 1631class FloatFunc1 : public PrimitiveFunc<Signature<float, float> > 1632{ 1633protected: 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 1679class CFloatFunc1 : public FloatFunc1 1680{ 1681public: 1682 CFloatFunc1 (const string& name, DoubleFunc1& func) 1683 : m_name(name), m_func(func) {} 1684 1685 string getName (void) const { return m_name; } 1686 1687protected: 1688 double applyExact (double x) const { return m_func(x); } 1689 1690 const string m_name; 1691 DoubleFunc1& m_func; 1692}; 1693 1694class FloatFunc2 : public PrimitiveFunc<Signature<float, float, float> > 1695{ 1696protected: 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 1750class CFloatFunc2 : public FloatFunc2 1751{ 1752public: 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 1762protected: 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 1769class InfixOperator : public FloatFunc2 1770{ 1771protected: 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); 1788 } 1789 1790 double precision (const EvalContext&, double, double, double) const 1791 { 1792 return 0.0; 1793 } 1794}; 1795 1796class FloatFunc3 : public PrimitiveFunc<Signature<float, float, float, float> > 1797{ 1798protected: 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. 1841namespace Functions 1842{ 1843 1844using namespace tcu; 1845 1846class Add : public InfixOperator 1847{ 1848public: 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)); 1863 } 1864 return this->applyMonotone(ctx, iargs.a, iargs.b); 1865 } 1866 1867protected: 1868 double applyExact (double x, double y) const { return x + y; } 1869}; 1870 1871class Mul : public InfixOperator 1872{ 1873public: 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)); 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)); 1904 } 1905 } 1906 return this->applyMonotone(ctx, iargs.a, iargs.b); 1907 } 1908 1909protected: 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 1922class Sub : public InfixOperator 1923{ 1924public: 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)); 1939 1940 } 1941 else 1942 { 1943 return this->applyMonotone(ctx, iargs.a, iargs.b); 1944 } 1945 } 1946 1947protected: 1948 double applyExact (double x, double y) const { return x - y; } 1949}; 1950 1951class Negate : public FloatFunc1 1952{ 1953public: 1954 string getName (void) const { return "_negate"; } 1955 void doPrint (ostream& os, const BaseArgExprs& args) const { os << "-" << *args[0]; } 1956 1957protected: 1958 double precision (const EvalContext&, double, double) const { return 0.0; } 1959 double applyExact (double x) const { return -x; } 1960}; 1961 1962class Div : public InfixOperator 1963{ 1964public: 1965 string getName (void) const { return "div"; } 1966 1967protected: 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 1988protected: 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 2016class InverseSqrt : public FloatFunc1 2017{ 2018public: 2019 string getName (void) const { return "inversesqrt"; } 2020 2021protected: 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 2035class ExpFunc : public CFloatFunc1 2036{ 2037public: 2038 ExpFunc (const string& name, DoubleFunc1& func) 2039 : CFloatFunc1(name, func) {} 2040protected: 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 2063class Exp2 : public ExpFunc { public: Exp2 (void) : ExpFunc("exp2", deExp2) {} }; 2064class Exp : public ExpFunc { public: Exp (void) : ExpFunc("exp", deExp) {} }; 2065 2066ExprP<float> exp2 (const ExprP<float>& x) { return app<Exp2>(x); } 2067ExprP<float> exp (const ExprP<float>& x) { return app<Exp>(x); } 2068 2069class LogFunc : public CFloatFunc1 2070{ 2071public: 2072 LogFunc (const string& name, DoubleFunc1& func) 2073 : CFloatFunc1(name, func) {} 2074 2075protected: 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 2097class Log2 : public LogFunc { public: Log2 (void) : LogFunc("log2", deLog2) {} }; 2098class Log : public LogFunc { public: Log (void) : LogFunc("log", deLog) {} }; 2099 2100ExprP<float> log2 (const ExprP<float>& x) { return app<Log2>(x); } 2101ExprP<float> log (const ExprP<float>& x) { return app<Log>(x); } 2102 2103#define DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0) \ 2104ExprP<TRET> NAME (const ExprP<T0>& arg0) { return app<CLASS>(arg0); } 2105 2106#define DEFINE_DERIVED1(CLASS, TRET, NAME, T0, ARG0, EXPANSION) \ 2107class CLASS : public DerivedFunc<Signature<TRET, T0> > \ 2108{ \ 2109public: \ 2110 string getName (void) const { return #NAME; } \ 2111 \ 2112protected: \ 2113 ExprP<TRET> doExpand (ExpandContext&, \ 2114 const CLASS::ArgExprs& args_) const \ 2115 { \ 2116 const ExprP<float>& ARG0 = args_.a; \ 2117 return EXPANSION; \ 2118 } \ 2119}; \ 2120DEFINE_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) \ 2126ExprP<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) \ 2132class CLASS : public DerivedFunc<Signature<TRET, T0, T1> > \ 2133{ \ 2134public: \ 2135 string getName (void) const { return #NAME; } \ 2136 \ 2137protected: \ 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}; \ 2145DEFINE_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) \ 2151ExprP<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) \ 2157class CLASS : public DerivedFunc<Signature<TRET, T0, T1, T2> > \ 2158{ \ 2159public: \ 2160 string getName (void) const { return #NAME; } \ 2161 \ 2162protected: \ 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}; \ 2171DEFINE_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) \ 2177ExprP<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 2183DEFINE_DERIVED_FLOAT1(Sqrt, sqrt, x, constant(1.0f) / app<InverseSqrt>(x)); 2184DEFINE_DERIVED_FLOAT2(Pow, pow, x, y, exp2(y * log2(x))); 2185DEFINE_DERIVED_FLOAT1(Radians, radians, d, (constant(DE_PI) / constant(180.0f)) * d); 2186DEFINE_DERIVED_FLOAT1(Degrees, degrees, r, (constant(180.0f) / constant(DE_PI)) * r); 2187 2188class TrigFunc : public CFloatFunc1 2189{ 2190public: 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 2199protected: 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 2269class Sin : public TrigFunc 2270{ 2271public: 2272 Sin (void) : TrigFunc("sin", deSin, -1.0, 1.0) {} 2273 2274protected: 2275 int doGetSlope (double angle) const { return deIntSign(deCos(angle)); } 2276}; 2277 2278ExprP<float> sin (const ExprP<float>& x) { return app<Sin>(x); } 2279 2280class Cos : public TrigFunc 2281{ 2282public: 2283 Cos (void) : TrigFunc("cos", deCos, -1.0, 1.0) {} 2284 2285protected: 2286 int doGetSlope (double angle) const { return -deIntSign(deSin(angle)); } 2287}; 2288 2289ExprP<float> cos (const ExprP<float>& x) { return app<Cos>(x); } 2290 2291DEFINE_DERIVED_FLOAT1(Tan, tan, x, sin(x) * (constant(1.0f) / cos(x))); 2292 2293class ArcTrigFunc : public CFloatFunc1 2294{ 2295public: 2296 ArcTrigFunc (const string& name, 2297 DoubleFunc1& func, 2298 double precisionULPs, 2299 const Interval& domain, 2300 const Interval& codomain) 2301 : CFloatFunc1 (name, func) 2302 , m_precision (precisionULPs) 2303 , m_domain (domain) 2304 , m_codomain (codomain) {} 2305 2306protected: 2307 double precision (const EvalContext& ctx, double ret, double x) const 2308 { 2309 if (!m_domain.contains(x)) 2310 return TCU_NAN; 2311 2312 if (ctx.floatPrecision == glu::PRECISION_HIGHP) 2313 { 2314 // Use OpenCL's precision 2315 return ctx.format.ulp(ret, m_precision); 2316 } 2317 else 2318 { 2319 // Use OpenCL half-float spec 2320 return ctx.format.ulp(ret, 2.0); 2321 } 2322 } 2323 2324 // We could implement getCodomain with m_codomain, but choose not to, 2325 // because it seems too strict with trascendental constants like pi. 2326 2327 const double m_precision; 2328 const Interval m_domain; 2329 const Interval m_codomain; 2330}; 2331 2332class ASin : public ArcTrigFunc 2333{ 2334public: 2335 ASin (void) : ArcTrigFunc("asin", deAsin, 4.0, 2336 Interval(-1.0, 1.0), 2337 Interval(-DE_PI_DOUBLE * 0.5, DE_PI_DOUBLE * 0.5)) {} 2338}; 2339 2340class ACos : public ArcTrigFunc 2341{ 2342public: 2343 ACos (void) : ArcTrigFunc("acos", deAcos, 4.0, 2344 Interval(-1.0, 1.0), 2345 Interval(0.0, DE_PI_DOUBLE)) {} 2346}; 2347 2348class ATan : public ArcTrigFunc 2349{ 2350public: 2351 ATan (void) : ArcTrigFunc("atan", deAtanOver, 5.0, 2352 Interval::unbounded(), 2353 Interval(-DE_PI_DOUBLE * 0.5, DE_PI_DOUBLE * 0.5)) {} 2354}; 2355 2356class ATan2 : public CFloatFunc2 2357{ 2358public: 2359 ATan2 (void) : CFloatFunc2 ("atan", deAtan2) {} 2360 2361protected: 2362 Interval innerExtrema (const EvalContext&, 2363 const Interval& yi, 2364 const Interval& xi) const 2365 { 2366 Interval ret; 2367 2368 if (yi.contains(0.0)) 2369 { 2370 if (xi.contains(0.0)) 2371 ret |= TCU_NAN; 2372 if (xi.intersects(Interval(-TCU_INFINITY, 0.0))) 2373 ret |= Interval(-DE_PI_DOUBLE, DE_PI_DOUBLE); 2374 } 2375 2376 return ret; 2377 } 2378 2379 double precision (const EvalContext& ctx, double ret, double, double) const 2380 { 2381 if (ctx.floatPrecision == glu::PRECISION_HIGHP) 2382 return ctx.format.ulp(ret, 6.0); 2383 else 2384 return ctx.format.ulp(ret, 2.0); 2385 } 2386 2387 // Codomain could be [-pi, pi], but that would probably be too strict. 2388}; 2389 2390DEFINE_DERIVED_FLOAT1(Sinh, sinh, x, (exp(x) - exp(-x)) / constant(2.0f)); 2391DEFINE_DERIVED_FLOAT1(Cosh, cosh, x, (exp(x) + exp(-x)) / constant(2.0f)); 2392DEFINE_DERIVED_FLOAT1(Tanh, tanh, x, sinh(x) / cosh(x)); 2393 2394// These are not defined as derived forms in the GLSL ES spec, but 2395// that gives us a reasonable precision. 2396DEFINE_DERIVED_FLOAT1(ASinh, asinh, x, log(x + sqrt(x * x + constant(1.0f)))); 2397DEFINE_DERIVED_FLOAT1(ACosh, acosh, x, log(x + sqrt((x + constant(1.0f)) * 2398 (x - constant(1.0f))))); 2399DEFINE_DERIVED_FLOAT1(ATanh, atanh, x, constant(0.5f) * log((constant(1.0f) + x) / 2400 (constant(1.0f) - x))); 2401 2402template <typename T> 2403class GetComponent : public PrimitiveFunc<Signature<typename T::Element, T, int> > 2404{ 2405public: 2406 typedef typename GetComponent::IRet IRet; 2407 2408 string getName (void) const { return "_getComponent"; } 2409 2410 void print (ostream& os, 2411 const BaseArgExprs& args) const 2412 { 2413 os << *args[0] << "[" << *args[1] << "]"; 2414 } 2415 2416protected: 2417 IRet doApply (const EvalContext&, 2418 const typename GetComponent::IArgs& iargs) const 2419 { 2420 IRet ret; 2421 2422 for (int compNdx = 0; compNdx < T::SIZE; ++compNdx) 2423 { 2424 if (iargs.b.contains(compNdx)) 2425 ret = unionIVal<typename T::Element>(ret, iargs.a[compNdx]); 2426 } 2427 2428 return ret; 2429 } 2430 2431}; 2432 2433template <typename T> 2434ExprP<typename T::Element> getComponent (const ExprP<T>& container, int ndx) 2435{ 2436 DE_ASSERT(0 <= ndx && ndx < T::SIZE); 2437 return app<GetComponent<T> >(container, constant(ndx)); 2438} 2439 2440template <typename T> string vecNamePrefix (void); 2441template <> string vecNamePrefix<float> (void) { return ""; } 2442template <> string vecNamePrefix<int> (void) { return "i"; } 2443template <> string vecNamePrefix<bool> (void) { return "b"; } 2444 2445template <typename T, int Size> 2446string vecName (void) { return vecNamePrefix<T>() + "vec" + de::toString(Size); } 2447 2448template <typename T, int Size> class GenVec; 2449 2450template <typename T> 2451class GenVec<T, 1> : public DerivedFunc<Signature<T, T> > 2452{ 2453public: 2454 typedef typename GenVec<T, 1>::ArgExprs ArgExprs; 2455 2456 string getName (void) const 2457 { 2458 return "_" + vecName<T, 1>(); 2459 } 2460 2461protected: 2462 2463 ExprP<T> doExpand (ExpandContext&, const ArgExprs& args) const { return args.a; } 2464}; 2465 2466template <typename T> 2467class GenVec<T, 2> : public PrimitiveFunc<Signature<Vector<T, 2>, T, T> > 2468{ 2469public: 2470 typedef typename GenVec::IRet IRet; 2471 typedef typename GenVec::IArgs IArgs; 2472 2473 string getName (void) const 2474 { 2475 return vecName<T, 2>(); 2476 } 2477 2478protected: 2479 IRet doApply (const EvalContext&, const IArgs& iargs) const 2480 { 2481 return IRet(iargs.a, iargs.b); 2482 } 2483}; 2484 2485template <typename T> 2486class GenVec<T, 3> : public PrimitiveFunc<Signature<Vector<T, 3>, T, T, T> > 2487{ 2488public: 2489 typedef typename GenVec::IRet IRet; 2490 typedef typename GenVec::IArgs IArgs; 2491 2492 string getName (void) const 2493 { 2494 return vecName<T, 3>(); 2495 } 2496 2497protected: 2498 IRet doApply (const EvalContext&, const IArgs& iargs) const 2499 { 2500 return IRet(iargs.a, iargs.b, iargs.c); 2501 } 2502}; 2503 2504template <typename T> 2505class GenVec<T, 4> : public PrimitiveFunc<Signature<Vector<T, 4>, T, T, T, T> > 2506{ 2507public: 2508 typedef typename GenVec::IRet IRet; 2509 typedef typename GenVec::IArgs IArgs; 2510 2511 string getName (void) const { return vecName<T, 4>(); } 2512 2513protected: 2514 IRet doApply (const EvalContext&, const IArgs& iargs) const 2515 { 2516 return IRet(iargs.a, iargs.b, iargs.c, iargs.d); 2517 } 2518}; 2519 2520 2521 2522template <typename T, int Rows, int Columns> 2523class GenMat; 2524 2525template <typename T, int Rows> 2526class GenMat<T, Rows, 2> : public PrimitiveFunc< 2527 Signature<Matrix<T, Rows, 2>, Vector<T, Rows>, Vector<T, Rows> > > 2528{ 2529public: 2530 typedef typename GenMat::Ret Ret; 2531 typedef typename GenMat::IRet IRet; 2532 typedef typename GenMat::IArgs IArgs; 2533 2534 string getName (void) const 2535 { 2536 return dataTypeNameOf<Ret>(); 2537 } 2538 2539protected: 2540 2541 IRet doApply (const EvalContext&, const IArgs& iargs) const 2542 { 2543 IRet ret; 2544 ret[0] = iargs.a; 2545 ret[1] = iargs.b; 2546 return ret; 2547 } 2548}; 2549 2550template <typename T, int Rows> 2551class GenMat<T, Rows, 3> : public PrimitiveFunc< 2552 Signature<Matrix<T, Rows, 3>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > > 2553{ 2554public: 2555 typedef typename GenMat::Ret Ret; 2556 typedef typename GenMat::IRet IRet; 2557 typedef typename GenMat::IArgs IArgs; 2558 2559 string getName (void) const 2560 { 2561 return dataTypeNameOf<Ret>(); 2562 } 2563 2564protected: 2565 2566 IRet doApply (const EvalContext&, const IArgs& iargs) const 2567 { 2568 IRet ret; 2569 ret[0] = iargs.a; 2570 ret[1] = iargs.b; 2571 ret[2] = iargs.c; 2572 return ret; 2573 } 2574}; 2575 2576template <typename T, int Rows> 2577class GenMat<T, Rows, 4> : public PrimitiveFunc< 2578 Signature<Matrix<T, Rows, 4>, 2579 Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > > 2580{ 2581public: 2582 typedef typename GenMat::Ret Ret; 2583 typedef typename GenMat::IRet IRet; 2584 typedef typename GenMat::IArgs IArgs; 2585 2586 string getName (void) const 2587 { 2588 return dataTypeNameOf<Ret>(); 2589 } 2590 2591protected: 2592 IRet doApply (const EvalContext&, const IArgs& iargs) const 2593 { 2594 IRet ret; 2595 ret[0] = iargs.a; 2596 ret[1] = iargs.b; 2597 ret[2] = iargs.c; 2598 ret[3] = iargs.d; 2599 return ret; 2600 } 2601}; 2602 2603template <typename T, int Rows> 2604ExprP<Matrix<T, Rows, 2> > mat2 (const ExprP<Vector<T, Rows> >& arg0, 2605 const ExprP<Vector<T, Rows> >& arg1) 2606{ 2607 return app<GenMat<T, Rows, 2> >(arg0, arg1); 2608} 2609 2610template <typename T, int Rows> 2611ExprP<Matrix<T, Rows, 3> > mat3 (const ExprP<Vector<T, Rows> >& arg0, 2612 const ExprP<Vector<T, Rows> >& arg1, 2613 const ExprP<Vector<T, Rows> >& arg2) 2614{ 2615 return app<GenMat<T, Rows, 3> >(arg0, arg1, arg2); 2616} 2617 2618template <typename T, int Rows> 2619ExprP<Matrix<T, Rows, 4> > mat4 (const ExprP<Vector<T, Rows> >& arg0, 2620 const ExprP<Vector<T, Rows> >& arg1, 2621 const ExprP<Vector<T, Rows> >& arg2, 2622 const ExprP<Vector<T, Rows> >& arg3) 2623{ 2624 return app<GenMat<T, Rows, 4> >(arg0, arg1, arg2, arg3); 2625} 2626 2627 2628template <int Rows, int Cols> 2629class MatNeg : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>, 2630 Matrix<float, Rows, Cols> > > 2631{ 2632public: 2633 typedef typename MatNeg::IRet IRet; 2634 typedef typename MatNeg::IArgs IArgs; 2635 2636 string getName (void) const 2637 { 2638 return "_matNeg"; 2639 } 2640 2641protected: 2642 void doPrint (ostream& os, const BaseArgExprs& args) const 2643 { 2644 os << "-(" << *args[0] << ")"; 2645 } 2646 2647 IRet doApply (const EvalContext&, const IArgs& iargs) const 2648 { 2649 IRet ret; 2650 2651 for (int col = 0; col < Cols; ++col) 2652 { 2653 for (int row = 0; row < Rows; ++row) 2654 ret[col][row] = -iargs.a[col][row]; 2655 } 2656 2657 return ret; 2658 } 2659}; 2660 2661template <typename T, typename Sig> 2662class CompWiseFunc : public PrimitiveFunc<Sig> 2663{ 2664public: 2665 typedef Func<Signature<T, T, T> > ScalarFunc; 2666 2667 string getName (void) const 2668 { 2669 return doGetScalarFunc().getName(); 2670 } 2671protected: 2672 void doPrint (ostream& os, 2673 const BaseArgExprs& args) const 2674 { 2675 doGetScalarFunc().print(os, args); 2676 } 2677 2678 virtual 2679 const ScalarFunc& doGetScalarFunc (void) const = 0; 2680}; 2681 2682template <int Rows, int Cols> 2683class CompMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>, 2684 Matrix<float, Rows, Cols>, 2685 Matrix<float, Rows, Cols> > > 2686{ 2687public: 2688 typedef typename CompMatFuncBase::IRet IRet; 2689 typedef typename CompMatFuncBase::IArgs IArgs; 2690 2691protected: 2692 2693 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const 2694 { 2695 IRet ret; 2696 2697 for (int col = 0; col < Cols; ++col) 2698 { 2699 for (int row = 0; row < Rows; ++row) 2700 ret[col][row] = this->doGetScalarFunc().apply(ctx, 2701 iargs.a[col][row], 2702 iargs.b[col][row]); 2703 } 2704 2705 return ret; 2706 } 2707}; 2708 2709template <typename F, int Rows, int Cols> 2710class CompMatFunc : public CompMatFuncBase<Rows, Cols> 2711{ 2712protected: 2713 const typename CompMatFunc::ScalarFunc& doGetScalarFunc (void) const 2714 { 2715 return instance<F>(); 2716 } 2717}; 2718 2719class ScalarMatrixCompMult : public Mul 2720{ 2721public: 2722 string getName (void) const 2723 { 2724 return "matrixCompMult"; 2725 } 2726 2727 void doPrint (ostream& os, const BaseArgExprs& args) const 2728 { 2729 Func<Sig>::doPrint(os, args); 2730 } 2731}; 2732 2733template <int Rows, int Cols> 2734class MatrixCompMult : public CompMatFunc<ScalarMatrixCompMult, Rows, Cols> 2735{ 2736}; 2737 2738template <int Rows, int Cols> 2739class ScalarMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>, 2740 Matrix<float, Rows, Cols>, 2741 float> > 2742{ 2743public: 2744 typedef typename ScalarMatFuncBase::IRet IRet; 2745 typedef typename ScalarMatFuncBase::IArgs IArgs; 2746 2747protected: 2748 2749 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const 2750 { 2751 IRet ret; 2752 2753 for (int col = 0; col < Cols; ++col) 2754 { 2755 for (int row = 0; row < Rows; ++row) 2756 ret[col][row] = this->doGetScalarFunc().apply(ctx, iargs.a[col][row], iargs.b); 2757 } 2758 2759 return ret; 2760 } 2761}; 2762 2763template <typename F, int Rows, int Cols> 2764class ScalarMatFunc : public ScalarMatFuncBase<Rows, Cols> 2765{ 2766protected: 2767 const typename ScalarMatFunc::ScalarFunc& doGetScalarFunc (void) const 2768 { 2769 return instance<F>(); 2770 } 2771}; 2772 2773template<typename T, int Size> struct GenXType; 2774 2775template<typename T> 2776struct GenXType<T, 1> 2777{ 2778 static ExprP<T> genXType (const ExprP<T>& x) { return x; } 2779}; 2780 2781template<typename T> 2782struct GenXType<T, 2> 2783{ 2784 static ExprP<Vector<T, 2> > genXType (const ExprP<T>& x) 2785 { 2786 return app<GenVec<T, 2> >(x, x); 2787 } 2788}; 2789 2790template<typename T> 2791struct GenXType<T, 3> 2792{ 2793 static ExprP<Vector<T, 3> > genXType (const ExprP<T>& x) 2794 { 2795 return app<GenVec<T, 3> >(x, x, x); 2796 } 2797}; 2798 2799template<typename T> 2800struct GenXType<T, 4> 2801{ 2802 static ExprP<Vector<T, 4> > genXType (const ExprP<T>& x) 2803 { 2804 return app<GenVec<T, 4> >(x, x, x, x); 2805 } 2806}; 2807 2808//! Returns an expression of vector of size `Size` (or scalar if Size == 1), 2809//! with each element initialized with the expression `x`. 2810template<typename T, int Size> 2811ExprP<typename ContainerOf<T, Size>::Container> genXType (const ExprP<T>& x) 2812{ 2813 return GenXType<T, Size>::genXType(x); 2814} 2815 2816typedef GenVec<float, 2> FloatVec2; 2817DEFINE_CONSTRUCTOR2(FloatVec2, Vec2, vec2, float, float) 2818 2819typedef GenVec<float, 3> FloatVec3; 2820DEFINE_CONSTRUCTOR3(FloatVec3, Vec3, vec3, float, float, float) 2821 2822typedef GenVec<float, 4> FloatVec4; 2823DEFINE_CONSTRUCTOR4(FloatVec4, Vec4, vec4, float, float, float, float) 2824 2825template <int Size> 2826class Dot : public DerivedFunc<Signature<float, Vector<float, Size>, Vector<float, Size> > > 2827{ 2828public: 2829 typedef typename Dot::ArgExprs ArgExprs; 2830 2831 string getName (void) const 2832 { 2833 return "dot"; 2834 } 2835 2836protected: 2837 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const 2838 { 2839 ExprP<float> val = args.a[0] * args.b[0]; 2840 2841 for (int ndx = 1; ndx < Size; ++ndx) 2842 val = val + args.a[ndx] * args.b[ndx]; 2843 2844 return val; 2845 } 2846}; 2847 2848template <> 2849class Dot<1> : public DerivedFunc<Signature<float, float, float> > 2850{ 2851public: 2852 string getName (void) const 2853 { 2854 return "dot"; 2855 } 2856 2857 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const 2858 { 2859 return args.a * args.b; 2860 } 2861}; 2862 2863template <int Size> 2864ExprP<float> dot (const ExprP<Vector<float, Size> >& x, const ExprP<Vector<float, Size> >& y) 2865{ 2866 return app<Dot<Size> >(x, y); 2867} 2868 2869ExprP<float> dot (const ExprP<float>& x, const ExprP<float>& y) 2870{ 2871 return app<Dot<1> >(x, y); 2872} 2873 2874template <int Size> 2875class Length : public DerivedFunc< 2876 Signature<float, typename ContainerOf<float, Size>::Container> > 2877{ 2878public: 2879 typedef typename Length::ArgExprs ArgExprs; 2880 2881 string getName (void) const 2882 { 2883 return "length"; 2884 } 2885 2886protected: 2887 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const 2888 { 2889 return sqrt(dot(args.a, args.a)); 2890 } 2891}; 2892 2893template <int Size> 2894ExprP<float> length (const ExprP<typename ContainerOf<float, Size>::Container>& x) 2895{ 2896 return app<Length<Size> >(x); 2897} 2898 2899template <int Size> 2900class Distance : public DerivedFunc< 2901 Signature<float, 2902 typename ContainerOf<float, Size>::Container, 2903 typename ContainerOf<float, Size>::Container> > 2904{ 2905public: 2906 typedef typename Distance::Ret Ret; 2907 typedef typename Distance::ArgExprs ArgExprs; 2908 2909 string getName (void) const 2910 { 2911 return "distance"; 2912 } 2913 2914protected: 2915 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const 2916 { 2917 return length<Size>(args.a - args.b); 2918 } 2919}; 2920 2921// cross 2922 2923class Cross : public DerivedFunc<Signature<Vec3, Vec3, Vec3> > 2924{ 2925public: 2926 string getName (void) const 2927 { 2928 return "cross"; 2929 } 2930 2931protected: 2932 ExprP<Vec3> doExpand (ExpandContext&, const ArgExprs& x) const 2933 { 2934 return vec3(x.a[1] * x.b[2] - x.b[1] * x.a[2], 2935 x.a[2] * x.b[0] - x.b[2] * x.a[0], 2936 x.a[0] * x.b[1] - x.b[0] * x.a[1]); 2937 } 2938}; 2939 2940DEFINE_CONSTRUCTOR2(Cross, Vec3, cross, Vec3, Vec3) 2941 2942template<int Size> 2943class Normalize : public DerivedFunc< 2944 Signature<typename ContainerOf<float, Size>::Container, 2945 typename ContainerOf<float, Size>::Container> > 2946{ 2947public: 2948 typedef typename Normalize::Ret Ret; 2949 typedef typename Normalize::ArgExprs ArgExprs; 2950 2951 string getName (void) const 2952 { 2953 return "normalize"; 2954 } 2955 2956protected: 2957 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const 2958 { 2959 return args.a / length<Size>(args.a); 2960 } 2961}; 2962 2963template <int Size> 2964class FaceForward : public DerivedFunc< 2965 Signature<typename ContainerOf<float, Size>::Container, 2966 typename ContainerOf<float, Size>::Container, 2967 typename ContainerOf<float, Size>::Container, 2968 typename ContainerOf<float, Size>::Container> > 2969{ 2970public: 2971 typedef typename FaceForward::Ret Ret; 2972 typedef typename FaceForward::ArgExprs ArgExprs; 2973 2974 string getName (void) const 2975 { 2976 return "faceforward"; 2977 } 2978 2979protected: 2980 2981 2982 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const 2983 { 2984 return cond(dot(args.c, args.b) < constant(0.0f), args.a, -args.a); 2985 } 2986}; 2987 2988template <int Size> 2989class Reflect : public DerivedFunc< 2990 Signature<typename ContainerOf<float, Size>::Container, 2991 typename ContainerOf<float, Size>::Container, 2992 typename ContainerOf<float, Size>::Container> > 2993{ 2994public: 2995 typedef typename Reflect::Ret Ret; 2996 typedef typename Reflect::ArgExprs ArgExprs; 2997 2998 string getName (void) const 2999 { 3000 return "reflect"; 3001 } 3002 3003protected: 3004 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const 3005 { 3006 return args.a - (args.b * dot(args.b, args.a) * constant(2.0f)); 3007 } 3008}; 3009 3010template <int Size> 3011class Refract : public DerivedFunc< 3012 Signature<typename ContainerOf<float, Size>::Container, 3013 typename ContainerOf<float, Size>::Container, 3014 typename ContainerOf<float, Size>::Container, 3015 float> > 3016{ 3017public: 3018 typedef typename Refract::Ret Ret; 3019 typedef typename Refract::Arg0 Arg0; 3020 typedef typename Refract::Arg1 Arg1; 3021 typedef typename Refract::ArgExprs ArgExprs; 3022 3023 string getName (void) const 3024 { 3025 return "refract"; 3026 } 3027 3028protected: 3029 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const 3030 { 3031 const ExprP<Arg0>& i = args.a; 3032 const ExprP<Arg1>& n = args.b; 3033 const ExprP<float>& eta = args.c; 3034 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i)); 3035 const ExprP<float> k = bindExpression("k", ctx, constant(1.0f) - eta * eta * 3036 (constant(1.0f) - dotNI * dotNI)); 3037 3038 return cond(k < constant(0.0f), 3039 genXType<float, Size>(constant(0.0f)), 3040 i * eta - n * (eta * dotNI + sqrt(k))); 3041 } 3042}; 3043 3044class PreciseFunc1 : public CFloatFunc1 3045{ 3046public: 3047 PreciseFunc1 (const string& name, DoubleFunc1& func) : CFloatFunc1(name, func) {} 3048protected: 3049 double precision (const EvalContext&, double, double) const { return 0.0; } 3050}; 3051 3052class Abs : public PreciseFunc1 3053{ 3054public: 3055 Abs (void) : PreciseFunc1("abs", deAbs) {} 3056}; 3057 3058class Sign : public PreciseFunc1 3059{ 3060public: 3061 Sign (void) : PreciseFunc1("sign", deSign) {} 3062}; 3063 3064class Floor : public PreciseFunc1 3065{ 3066public: 3067 Floor (void) : PreciseFunc1("floor", deFloor) {} 3068}; 3069 3070class Trunc : public PreciseFunc1 3071{ 3072public: 3073 Trunc (void) : PreciseFunc1("trunc", deTrunc) {} 3074}; 3075 3076class Round : public FloatFunc1 3077{ 3078public: 3079 string getName (void) const { return "round"; } 3080 3081protected: 3082 Interval applyPoint (const EvalContext&, double x) const 3083 { 3084 double truncated = 0.0; 3085 const double fract = deModf(x, &truncated); 3086 Interval ret; 3087 3088 if (fabs(fract) <= 0.5) 3089 ret |= truncated; 3090 if (fabs(fract) >= 0.5) 3091 ret |= truncated + deSign(fract); 3092 3093 return ret; 3094 } 3095 3096 double precision (const EvalContext&, double, double) const { return 0.0; } 3097}; 3098 3099class RoundEven : public PreciseFunc1 3100{ 3101public: 3102 RoundEven (void) : PreciseFunc1("roundEven", deRoundEven) {} 3103}; 3104 3105class Ceil : public PreciseFunc1 3106{ 3107public: 3108 Ceil (void) : PreciseFunc1("ceil", deCeil) {} 3109}; 3110 3111DEFINE_DERIVED_FLOAT1(Fract, fract, x, x - app<Floor>(x)); 3112 3113class PreciseFunc2 : public CFloatFunc2 3114{ 3115public: 3116 PreciseFunc2 (const string& name, DoubleFunc2& func) : CFloatFunc2(name, func) {} 3117protected: 3118 double precision (const EvalContext&, double, double, double) const { return 0.0; } 3119}; 3120 3121DEFINE_DERIVED_FLOAT2(Mod, mod, x, y, x - y * app<Floor>(x / y)); 3122 3123class Modf : public PrimitiveFunc<Signature<float, float, float> > 3124{ 3125public: 3126 string getName (void) const 3127 { 3128 return "modf"; 3129 } 3130 3131protected: 3132 IRet doApply (const EvalContext&, const IArgs& iargs) const 3133 { 3134 Interval fracIV; 3135 Interval& wholeIV = const_cast<Interval&>(iargs.b); 3136 double intPart = 0; 3137 3138 TCU_INTERVAL_APPLY_MONOTONE1(fracIV, x, iargs.a, frac, frac = deModf(x, &intPart)); 3139 TCU_INTERVAL_APPLY_MONOTONE1(wholeIV, x, iargs.a, whole, 3140 deModf(x, &intPart); whole = intPart); 3141 return fracIV; 3142 } 3143 3144 int getOutParamIndex (void) const 3145 { 3146 return 1; 3147 } 3148}; 3149 3150class Min : public PreciseFunc2 { public: Min (void) : PreciseFunc2("min", deMin) {} }; 3151class Max : public PreciseFunc2 { public: Max (void) : PreciseFunc2("max", deMax) {} }; 3152 3153class Clamp : public FloatFunc3 3154{ 3155public: 3156 string getName (void) const { return "clamp"; } 3157 3158 double applyExact (double x, double minVal, double maxVal) const 3159 { 3160 return de::min(de::max(x, minVal), maxVal); 3161 } 3162 3163 double precision (const EvalContext&, double, double, double minVal, double maxVal) const 3164 { 3165 return minVal > maxVal ? TCU_NAN : 0.0; 3166 } 3167}; 3168 3169ExprP<float> clamp(const ExprP<float>& x, const ExprP<float>& minVal, const ExprP<float>& maxVal) 3170{ 3171 return app<Clamp>(x, minVal, maxVal); 3172} 3173 3174DEFINE_DERIVED_FLOAT3(Mix, mix, x, y, a, (x * (constant(1.0f) - a)) + y * a); 3175 3176static double step (double edge, double x) 3177{ 3178 return x < edge ? 0.0 : 1.0; 3179} 3180 3181class Step : public PreciseFunc2 { public: Step (void) : PreciseFunc2("step", step) {} }; 3182 3183class SmoothStep : public DerivedFunc<Signature<float, float, float, float> > 3184{ 3185public: 3186 string getName (void) const 3187 { 3188 return "smoothstep"; 3189 } 3190 3191protected: 3192 3193 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const 3194 { 3195 const ExprP<float>& edge0 = args.a; 3196 const ExprP<float>& edge1 = args.b; 3197 const ExprP<float>& x = args.c; 3198 const ExprP<float> tExpr = clamp((x - edge0) / (edge1 - edge0), 3199 constant(0.0f), constant(1.0f)); 3200 const ExprP<float> t = bindExpression("t", ctx, tExpr); 3201 3202 return (t * t * (constant(3.0f) - constant(2.0f) * t)); 3203 } 3204}; 3205 3206class FrExp : public PrimitiveFunc<Signature<float, float, int> > 3207{ 3208public: 3209 string getName (void) const 3210 { 3211 return "frexp"; 3212 } 3213 3214protected: 3215 IRet doApply (const EvalContext&, const IArgs& iargs) const 3216 { 3217 IRet ret; 3218 const IArg0& x = iargs.a; 3219 IArg1& exponent = const_cast<IArg1&>(iargs.b); 3220 3221 if (x.hasNaN() || x.contains(TCU_INFINITY) || x.contains(-TCU_INFINITY)) 3222 { 3223 // GLSL (in contrast to IEEE) says that result of applying frexp 3224 // to infinity is undefined 3225 ret = Interval::unbounded() | TCU_NAN; 3226 exponent = Interval(-deLdExp(1.0, 31), deLdExp(1.0, 31)-1); 3227 } 3228 else if (!x.empty()) 3229 { 3230 int loExp = 0; 3231 const double loFrac = deFrExp(x.lo(), &loExp); 3232 int hiExp = 0; 3233 const double hiFrac = deFrExp(x.hi(), &hiExp); 3234 3235 if (deSign(loFrac) != deSign(hiFrac)) 3236 { 3237 exponent = Interval(-TCU_INFINITY, de::max(loExp, hiExp)); 3238 ret = Interval(); 3239 if (deSign(loFrac) < 0) 3240 ret |= Interval(-1.0 + DBL_EPSILON*0.5, 0.0); 3241 if (deSign(hiFrac) > 0) 3242 ret |= Interval(0.0, 1.0 - DBL_EPSILON*0.5); 3243 } 3244 else 3245 { 3246 exponent = Interval(loExp, hiExp); 3247 if (loExp == hiExp) 3248 ret = Interval(loFrac, hiFrac); 3249 else 3250 ret = deSign(loFrac) * Interval(0.5, 1.0 - DBL_EPSILON*0.5); 3251 } 3252 } 3253 3254 return ret; 3255 } 3256 3257 int getOutParamIndex (void) const 3258 { 3259 return 1; 3260 } 3261}; 3262 3263class LdExp : public PrimitiveFunc<Signature<float, float, int> > 3264{ 3265public: 3266 string getName (void) const 3267 { 3268 return "ldexp"; 3269 } 3270 3271protected: 3272 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const 3273 { 3274 Interval ret = call<Exp2>(ctx, iargs.b); 3275 // Khronos bug 11180 consensus: if exp2(exponent) cannot be represented, 3276 // the result is undefined. 3277 3278 if (ret.contains(TCU_INFINITY) | ret.contains(-TCU_INFINITY)) 3279 ret |= TCU_NAN; 3280 3281 return call<Mul>(ctx, iargs.a, ret); 3282 } 3283}; 3284 3285template<int Rows, int Columns> 3286class Transpose : public PrimitiveFunc<Signature<Matrix<float, Rows, Columns>, 3287 Matrix<float, Columns, Rows> > > 3288{ 3289public: 3290 typedef typename Transpose::IRet IRet; 3291 typedef typename Transpose::IArgs IArgs; 3292 3293 string getName (void) const 3294 { 3295 return "transpose"; 3296 } 3297 3298protected: 3299 IRet doApply (const EvalContext&, const IArgs& iargs) const 3300 { 3301 IRet ret; 3302 3303 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx) 3304 { 3305 for (int colNdx = 0; colNdx < Columns; ++colNdx) 3306 ret(rowNdx, colNdx) = iargs.a(colNdx, rowNdx); 3307 } 3308 3309 return ret; 3310 } 3311}; 3312 3313template<typename Ret, typename Arg0, typename Arg1> 3314class MulFunc : public PrimitiveFunc<Signature<Ret, Arg0, Arg1> > 3315{ 3316public: 3317 string getName (void) const { return "mul"; } 3318 3319protected: 3320 void doPrint (ostream& os, const BaseArgExprs& args) const 3321 { 3322 os << "(" << *args[0] << " * " << *args[1] << ")"; 3323 } 3324}; 3325 3326template<int LeftRows, int Middle, int RightCols> 3327class MatMul : public MulFunc<Matrix<float, LeftRows, RightCols>, 3328 Matrix<float, LeftRows, Middle>, 3329 Matrix<float, Middle, RightCols> > 3330{ 3331protected: 3332 typedef typename MatMul::IRet IRet; 3333 typedef typename MatMul::IArgs IArgs; 3334 typedef typename MatMul::IArg0 IArg0; 3335 typedef typename MatMul::IArg1 IArg1; 3336 3337 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const 3338 { 3339 const IArg0& left = iargs.a; 3340 const IArg1& right = iargs.b; 3341 IRet ret; 3342 3343 for (int row = 0; row < LeftRows; ++row) 3344 { 3345 for (int col = 0; col < RightCols; ++col) 3346 { 3347 Interval element (0.0); 3348 3349 for (int ndx = 0; ndx < Middle; ++ndx) 3350 element = call<Add>(ctx, element, 3351 call<Mul>(ctx, left[ndx][row], right[col][ndx])); 3352 3353 ret[col][row] = element; 3354 } 3355 } 3356 3357 return ret; 3358 } 3359}; 3360 3361template<int Rows, int Cols> 3362class VecMatMul : public MulFunc<Vector<float, Cols>, 3363 Vector<float, Rows>, 3364 Matrix<float, Rows, Cols> > 3365{ 3366public: 3367 typedef typename VecMatMul::IRet IRet; 3368 typedef typename VecMatMul::IArgs IArgs; 3369 typedef typename VecMatMul::IArg0 IArg0; 3370 typedef typename VecMatMul::IArg1 IArg1; 3371 3372protected: 3373 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const 3374 { 3375 const IArg0& left = iargs.a; 3376 const IArg1& right = iargs.b; 3377 IRet ret; 3378 3379 for (int col = 0; col < Cols; ++col) 3380 { 3381 Interval element (0.0); 3382 3383 for (int row = 0; row < Rows; ++row) 3384 element = call<Add>(ctx, element, call<Mul>(ctx, left[row], right[col][row])); 3385 3386 ret[col] = element; 3387 } 3388 3389 return ret; 3390 } 3391}; 3392 3393template<int Rows, int Cols> 3394class MatVecMul : public MulFunc<Vector<float, Rows>, 3395 Matrix<float, Rows, Cols>, 3396 Vector<float, Cols> > 3397{ 3398public: 3399 typedef typename MatVecMul::IRet IRet; 3400 typedef typename MatVecMul::IArgs IArgs; 3401 typedef typename MatVecMul::IArg0 IArg0; 3402 typedef typename MatVecMul::IArg1 IArg1; 3403 3404protected: 3405 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const 3406 { 3407 const IArg0& left = iargs.a; 3408 const IArg1& right = iargs.b; 3409 3410 return call<VecMatMul<Cols, Rows> >(ctx, right, 3411 call<Transpose<Rows, Cols> >(ctx, left)); 3412 } 3413}; 3414 3415template<int Rows, int Cols> 3416class OuterProduct : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>, 3417 Vector<float, Rows>, 3418 Vector<float, Cols> > > 3419{ 3420public: 3421 typedef typename OuterProduct::IRet IRet; 3422 typedef typename OuterProduct::IArgs IArgs; 3423 3424 string getName (void) const 3425 { 3426 return "outerProduct"; 3427 } 3428 3429protected: 3430 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const 3431 { 3432 IRet ret; 3433 3434 for (int row = 0; row < Rows; ++row) 3435 { 3436 for (int col = 0; col < Cols; ++col) 3437 ret[col][row] = call<Mul>(ctx, iargs.a[row], iargs.b[col]); 3438 } 3439 3440 return ret; 3441 } 3442}; 3443 3444template<int Rows, int Cols> 3445ExprP<Matrix<float, Rows, Cols> > outerProduct (const ExprP<Vector<float, Rows> >& left, 3446 const ExprP<Vector<float, Cols> >& right) 3447{ 3448 return app<OuterProduct<Rows, Cols> >(left, right); 3449} 3450 3451template<int Size> 3452class DeterminantBase : public DerivedFunc<Signature<float, Matrix<float, Size, Size> > > 3453{ 3454public: 3455 string getName (void) const { return "determinant"; } 3456}; 3457 3458template<int Size> 3459class Determinant; 3460 3461template<int Size> 3462ExprP<float> determinant (ExprP<Matrix<float, Size, Size> > mat) 3463{ 3464 return app<Determinant<Size> >(mat); 3465} 3466 3467template<> 3468class Determinant<2> : public DeterminantBase<2> 3469{ 3470protected: 3471 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const 3472 { 3473 ExprP<Mat2> mat = args.a; 3474 3475 return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1]; 3476 } 3477}; 3478 3479template<> 3480class Determinant<3> : public DeterminantBase<3> 3481{ 3482protected: 3483 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const 3484 { 3485 ExprP<Mat3> mat = args.a; 3486 3487 return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) + 3488 mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) + 3489 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0])); 3490 } 3491}; 3492 3493template<> 3494class Determinant<4> : public DeterminantBase<4> 3495{ 3496protected: 3497 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const 3498 { 3499 ExprP<Mat4> mat = args.a; 3500 ExprP<Mat3> minors[4]; 3501 3502 for (int ndx = 0; ndx < 4; ++ndx) 3503 { 3504 ExprP<Vec4> minorColumns[3]; 3505 ExprP<Vec3> columns[3]; 3506 3507 for (int col = 0; col < 3; ++col) 3508 minorColumns[col] = mat[col < ndx ? col : col + 1]; 3509 3510 for (int col = 0; col < 3; ++col) 3511 columns[col] = vec3(minorColumns[0][col+1], 3512 minorColumns[1][col+1], 3513 minorColumns[2][col+1]); 3514 3515 minors[ndx] = bindExpression("minor", ctx, 3516 mat3(columns[0], columns[1], columns[2])); 3517 } 3518 3519 return (mat[0][0] * determinant(minors[0]) - 3520 mat[1][0] * determinant(minors[1]) + 3521 mat[2][0] * determinant(minors[2]) - 3522 mat[3][0] * determinant(minors[3])); 3523 } 3524}; 3525 3526template<int Size> class Inverse; 3527 3528template <int Size> 3529ExprP<Matrix<float, Size, Size> > inverse (ExprP<Matrix<float, Size, Size> > mat) 3530{ 3531 return app<Inverse<Size> >(mat); 3532} 3533 3534template<> 3535class Inverse<2> : public DerivedFunc<Signature<Mat2, Mat2> > 3536{ 3537public: 3538 string getName (void) const 3539 { 3540 return "inverse"; 3541 } 3542 3543protected: 3544 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const 3545 { 3546 ExprP<Mat2> mat = args.a; 3547 ExprP<float> det = bindExpression("det", ctx, determinant(mat)); 3548 3549 return mat2(vec2(mat[1][1] / det, -mat[0][1] / det), 3550 vec2(-mat[1][0] / det, mat[0][0] / det)); 3551 } 3552}; 3553 3554template<> 3555class Inverse<3> : public DerivedFunc<Signature<Mat3, Mat3> > 3556{ 3557public: 3558 string getName (void) const 3559 { 3560 return "inverse"; 3561 } 3562 3563protected: 3564 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const 3565 { 3566 ExprP<Mat3> mat = args.a; 3567 ExprP<Mat2> invA = bindExpression("invA", ctx, 3568 inverse(mat2(vec2(mat[0][0], mat[0][1]), 3569 vec2(mat[1][0], mat[1][1])))); 3570 3571 ExprP<Vec2> matB = bindExpression("matB", ctx, vec2(mat[2][0], mat[2][1])); 3572 ExprP<Vec2> matC = bindExpression("matC", ctx, vec2(mat[0][2], mat[1][2])); 3573 ExprP<float> matD = bindExpression("matD", ctx, mat[2][2]); 3574 3575 ExprP<float> schur = bindExpression("schur", ctx, 3576 constant(1.0f) / 3577 (matD - dot(matC * invA, matB))); 3578 3579 ExprP<Vec2> t1 = invA * matB; 3580 ExprP<Vec2> t2 = t1 * schur; 3581 ExprP<Mat2> t3 = outerProduct(t2, matC); 3582 ExprP<Mat2> t4 = t3 * invA; 3583 ExprP<Mat2> t5 = invA + t4; 3584 ExprP<Mat2> blockA = bindExpression("blockA", ctx, t5); 3585 ExprP<Vec2> blockB = bindExpression("blockB", ctx, 3586 (invA * matB) * -schur); 3587 ExprP<Vec2> blockC = bindExpression("blockC", ctx, 3588 (matC * invA) * -schur); 3589 3590 return mat3(vec3(blockA[0][0], blockA[0][1], blockC[0]), 3591 vec3(blockA[1][0], blockA[1][1], blockC[1]), 3592 vec3(blockB[0], blockB[1], schur)); 3593 } 3594}; 3595 3596template<> 3597class Inverse<4> : public DerivedFunc<Signature<Mat4, Mat4> > 3598{ 3599public: 3600 string getName (void) const { return "inverse"; } 3601 3602protected: 3603 ExprP<Ret> doExpand (ExpandContext& ctx, 3604 const ArgExprs& args) const 3605 { 3606 ExprP<Mat4> mat = args.a; 3607 ExprP<Mat2> invA = bindExpression("invA", ctx, 3608 inverse(mat2(vec2(mat[0][0], mat[0][1]), 3609 vec2(mat[1][0], mat[1][1])))); 3610 ExprP<Mat2> matB = bindExpression("matB", ctx, 3611 mat2(vec2(mat[2][0], mat[2][1]), 3612 vec2(mat[3][0], mat[3][1]))); 3613 ExprP<Mat2> matC = bindExpression("matC", ctx, 3614 mat2(vec2(mat[0][2], mat[0][3]), 3615 vec2(mat[1][2], mat[1][3]))); 3616 ExprP<Mat2> matD = bindExpression("matD", ctx, 3617 mat2(vec2(mat[2][2], mat[2][3]), 3618 vec2(mat[3][2], mat[3][3]))); 3619 ExprP<Mat2> schur = bindExpression("schur", ctx, 3620 inverse(matD + -(matC * invA * matB))); 3621 ExprP<Mat2> blockA = bindExpression("blockA", ctx, 3622 invA + (invA * matB * schur * matC * invA)); 3623 ExprP<Mat2> blockB = bindExpression("blockB", ctx, 3624 (-invA) * matB * schur); 3625 ExprP<Mat2> blockC = bindExpression("blockC", ctx, 3626 (-schur) * matC * invA); 3627 3628 return mat4(vec4(blockA[0][0], blockA[0][1], blockC[0][0], blockC[0][1]), 3629 vec4(blockA[1][0], blockA[1][1], blockC[1][0], blockC[1][1]), 3630 vec4(blockB[0][0], blockB[0][1], schur[0][0], schur[0][1]), 3631 vec4(blockB[1][0], blockB[1][1], schur[1][0], schur[1][1])); 3632 } 3633}; 3634 3635class Fma : public DerivedFunc<Signature<float, float, float, float> > 3636{ 3637public: 3638 string getName (void) const 3639 { 3640 return "fma"; 3641 } 3642 3643 string getRequiredExtension (void) const 3644 { 3645 return "GL_EXT_gpu_shader5"; 3646 } 3647 3648protected: 3649 ExprP<float> doExpand (ExpandContext&, const ArgExprs& x) const 3650 { 3651 return x.a * x.b + x.c; 3652 } 3653}; 3654 3655} // Functions 3656 3657using namespace Functions; 3658 3659template <typename T> 3660ExprP<typename T::Element> ContainerExprPBase<T>::operator[] (int i) const 3661{ 3662 return Functions::getComponent(exprP<T>(*this), i); 3663} 3664 3665ExprP<float> operator+ (const ExprP<float>& arg0, const ExprP<float>& arg1) 3666{ 3667 return app<Add>(arg0, arg1); 3668} 3669 3670ExprP<float> operator- (const ExprP<float>& arg0, const ExprP<float>& arg1) 3671{ 3672 return app<Sub>(arg0, arg1); 3673} 3674 3675ExprP<float> operator- (const ExprP<float>& arg0) 3676{ 3677 return app<Negate>(arg0); 3678} 3679 3680ExprP<float> operator* (const ExprP<float>& arg0, const ExprP<float>& arg1) 3681{ 3682 return app<Mul>(arg0, arg1); 3683} 3684 3685ExprP<float> operator/ (const ExprP<float>& arg0, const ExprP<float>& arg1) 3686{ 3687 return app<Div>(arg0, arg1); 3688} 3689 3690template <typename Sig_, int Size> 3691class GenFunc : public PrimitiveFunc<Signature< 3692 typename ContainerOf<typename Sig_::Ret, Size>::Container, 3693 typename ContainerOf<typename Sig_::Arg0, Size>::Container, 3694 typename ContainerOf<typename Sig_::Arg1, Size>::Container, 3695 typename ContainerOf<typename Sig_::Arg2, Size>::Container, 3696 typename ContainerOf<typename Sig_::Arg3, Size>::Container> > 3697{ 3698public: 3699 typedef typename GenFunc::IArgs IArgs; 3700 typedef typename GenFunc::IRet IRet; 3701 3702 GenFunc (const Func<Sig_>& scalarFunc) : m_func (scalarFunc) {} 3703 3704 string getName (void) const 3705 { 3706 return m_func.getName(); 3707 } 3708 3709 int getOutParamIndex (void) const 3710 { 3711 return m_func.getOutParamIndex(); 3712 } 3713 3714 string getRequiredExtension (void) const 3715 { 3716 return m_func.getRequiredExtension(); 3717 } 3718 3719protected: 3720 void doPrint (ostream& os, const BaseArgExprs& args) const 3721 { 3722 m_func.print(os, args); 3723 } 3724 3725 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const 3726 { 3727 IRet ret; 3728 3729 for (int ndx = 0; ndx < Size; ++ndx) 3730 { 3731 ret[ndx] = 3732 m_func.apply(ctx, iargs.a[ndx], iargs.b[ndx], iargs.c[ndx], iargs.d[ndx]); 3733 } 3734 3735 return ret; 3736 } 3737 3738 void doGetUsedFuncs (FuncSet& dst) const 3739 { 3740 m_func.getUsedFuncs(dst); 3741 } 3742 3743 const Func<Sig_>& m_func; 3744}; 3745 3746template <typename F, int Size> 3747class VectorizedFunc : public GenFunc<typename F::Sig, Size> 3748{ 3749public: 3750 VectorizedFunc (void) : GenFunc<typename F::Sig, Size>(instance<F>()) {} 3751}; 3752 3753 3754 3755template <typename Sig_, int Size> 3756class FixedGenFunc : public PrimitiveFunc <Signature< 3757 typename ContainerOf<typename Sig_::Ret, Size>::Container, 3758 typename ContainerOf<typename Sig_::Arg0, Size>::Container, 3759 typename Sig_::Arg1, 3760 typename ContainerOf<typename Sig_::Arg2, Size>::Container, 3761 typename ContainerOf<typename Sig_::Arg3, Size>::Container> > 3762{ 3763public: 3764 typedef typename FixedGenFunc::IArgs IArgs; 3765 typedef typename FixedGenFunc::IRet IRet; 3766 3767 string getName (void) const 3768 { 3769 return this->doGetScalarFunc().getName(); 3770 } 3771 3772protected: 3773 void doPrint (ostream& os, const BaseArgExprs& args) const 3774 { 3775 this->doGetScalarFunc().print(os, args); 3776 } 3777 3778 IRet doApply (const EvalContext& ctx, 3779 const IArgs& iargs) const 3780 { 3781 IRet ret; 3782 const Func<Sig_>& func = this->doGetScalarFunc(); 3783 3784 for (int ndx = 0; ndx < Size; ++ndx) 3785 ret[ndx] = func.apply(ctx, iargs.a[ndx], iargs.b, iargs.c[ndx], iargs.d[ndx]); 3786 3787 return ret; 3788 } 3789 3790 virtual const Func<Sig_>& doGetScalarFunc (void) const = 0; 3791}; 3792 3793template <typename F, int Size> 3794class FixedVecFunc : public FixedGenFunc<typename F::Sig, Size> 3795{ 3796protected: 3797 const Func<typename F::Sig>& doGetScalarFunc (void) const { return instance<F>(); } 3798}; 3799 3800template<typename Sig> 3801struct GenFuncs 3802{ 3803 GenFuncs (const Func<Sig>& func_, 3804 const GenFunc<Sig, 2>& func2_, 3805 const GenFunc<Sig, 3>& func3_, 3806 const GenFunc<Sig, 4>& func4_) 3807 : func (func_) 3808 , func2 (func2_) 3809 , func3 (func3_) 3810 , func4 (func4_) 3811 {} 3812 3813 const Func<Sig>& func; 3814 const GenFunc<Sig, 2>& func2; 3815 const GenFunc<Sig, 3>& func3; 3816 const GenFunc<Sig, 4>& func4; 3817}; 3818 3819template<typename F> 3820GenFuncs<typename F::Sig> makeVectorizedFuncs (void) 3821{ 3822 return GenFuncs<typename F::Sig>(instance<F>(), 3823 instance<VectorizedFunc<F, 2> >(), 3824 instance<VectorizedFunc<F, 3> >(), 3825 instance<VectorizedFunc<F, 4> >()); 3826} 3827 3828template<int Size> 3829ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0, 3830 const ExprP<Vector<float, Size> >& arg1) 3831{ 3832 return app<VectorizedFunc<Mul, Size> >(arg0, arg1); 3833} 3834 3835template<int Size> 3836ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0, 3837 const ExprP<float>& arg1) 3838{ 3839 return app<FixedVecFunc<Mul, Size> >(arg0, arg1); 3840} 3841 3842template<int Size> 3843ExprP<Vector<float, Size> > operator/(const ExprP<Vector<float, Size> >& arg0, 3844 const ExprP<float>& arg1) 3845{ 3846 return app<FixedVecFunc<Div, Size> >(arg0, arg1); 3847} 3848 3849template<int Size> 3850ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0) 3851{ 3852 return app<VectorizedFunc<Negate, Size> >(arg0); 3853} 3854 3855template<int Size> 3856ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0, 3857 const ExprP<Vector<float, Size> >& arg1) 3858{ 3859 return app<VectorizedFunc<Sub, Size> >(arg0, arg1); 3860} 3861 3862template<int LeftRows, int Middle, int RightCols> 3863ExprP<Matrix<float, LeftRows, RightCols> > 3864operator* (const ExprP<Matrix<float, LeftRows, Middle> >& left, 3865 const ExprP<Matrix<float, Middle, RightCols> >& right) 3866{ 3867 return app<MatMul<LeftRows, Middle, RightCols> >(left, right); 3868} 3869 3870template<int Rows, int Cols> 3871ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left, 3872 const ExprP<Matrix<float, Rows, Cols> >& right) 3873{ 3874 return app<VecMatMul<Rows, Cols> >(left, right); 3875} 3876 3877template<int Rows, int Cols> 3878ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left, 3879 const ExprP<Vector<float, Rows> >& right) 3880{ 3881 return app<MatVecMul<Rows, Cols> >(left, right); 3882} 3883 3884template<int Rows, int Cols> 3885ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left, 3886 const ExprP<float>& right) 3887{ 3888 return app<ScalarMatFunc<Mul, Rows, Cols> >(left, right); 3889} 3890 3891template<int Rows, int Cols> 3892ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left, 3893 const ExprP<Matrix<float, Rows, Cols> >& right) 3894{ 3895 return app<CompMatFunc<Add, Rows, Cols> >(left, right); 3896} 3897 3898template<int Rows, int Cols> 3899ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat) 3900{ 3901 return app<MatNeg<Rows, Cols> >(mat); 3902} 3903 3904template <typename T> 3905class Sampling 3906{ 3907public: 3908 virtual void genFixeds (const FloatFormat&, vector<T>&) const {} 3909 virtual T genRandom (const FloatFormat&, Precision, Random&) const { return T(); } 3910 virtual double getWeight (void) const { return 0.0; } 3911}; 3912 3913template <> 3914class DefaultSampling<Void> : public Sampling<Void> 3915{ 3916public: 3917 void genFixeds (const FloatFormat&, vector<Void>& dst) const { dst.push_back(Void()); } 3918}; 3919 3920template <> 3921class DefaultSampling<bool> : public Sampling<bool> 3922{ 3923public: 3924 void genFixeds (const FloatFormat&, vector<bool>& dst) const 3925 { 3926 dst.push_back(true); 3927 dst.push_back(false); 3928 } 3929}; 3930 3931template <> 3932class DefaultSampling<int> : public Sampling<int> 3933{ 3934public: 3935 int genRandom (const FloatFormat&, Precision prec, Random& rnd) const 3936 { 3937 const int exp = rnd.getInt(0, getNumBits(prec)-2); 3938 const int sign = rnd.getBool() ? -1 : 1; 3939 3940 return sign * rnd.getInt(0, 1L << exp); 3941 } 3942 3943 void genFixeds (const FloatFormat&, vector<int>& dst) const 3944 { 3945 dst.push_back(0); 3946 dst.push_back(-1); 3947 dst.push_back(1); 3948 } 3949 double getWeight (void) const { return 1.0; } 3950 3951private: 3952 static inline int getNumBits (Precision prec) 3953 { 3954 switch (prec) 3955 { 3956 case glu::PRECISION_LOWP: return 8; 3957 case glu::PRECISION_MEDIUMP: return 16; 3958 case glu::PRECISION_HIGHP: return 32; 3959 default: 3960 DE_ASSERT(false); 3961 return 0; 3962 } 3963 } 3964}; 3965 3966template <> 3967class DefaultSampling<float> : public Sampling<float> 3968{ 3969public: 3970 float genRandom (const FloatFormat& format, Precision prec, Random& rnd) const; 3971 void genFixeds (const FloatFormat& format, vector<float>& dst) const; 3972 double getWeight (void) const { return 1.0; } 3973}; 3974 3975//! Generate a random float from a reasonable general-purpose distribution. 3976float DefaultSampling<float>::genRandom (const FloatFormat& format, 3977 Precision, 3978 Random& rnd) const 3979{ 3980 const int minExp = format.getMinExp(); 3981 const int maxExp = format.getMaxExp(); 3982 const bool haveSubnormal = format.hasSubnormal() != tcu::NO; 3983 3984 // Choose exponent so that the cumulative distribution is cubic. 3985 // This makes the probability distribution quadratic, with the peak centered on zero. 3986 const double minRoot = deCbrt(minExp - 0.5 - (haveSubnormal ? 1.0 : 0.0)); 3987 const double maxRoot = deCbrt(maxExp + 0.5); 3988 const int fractionBits = format.getFractionBits(); 3989 const int exp = int(deRoundEven(dePow(rnd.getDouble(minRoot, maxRoot), 3990 3.0))); 3991 float base = 0.0f; // integral power of two 3992 float quantum = 0.0f; // smallest representable difference in the binade 3993 float significand = 0.0f; // Significand. 3994 3995 DE_ASSERT(fractionBits < std::numeric_limits<float>::digits); 3996 3997 // Generate some occasional special numbers 3998 switch (rnd.getInt(0, 64)) 3999 { 4000 case 0: return 0; 4001 case 1: return TCU_INFINITY; 4002 case 2: return -TCU_INFINITY; 4003 case 3: return TCU_NAN; 4004 default: break; 4005 } 4006 4007 if (exp >= minExp) 4008 { 4009 // Normal number 4010 base = deFloatLdExp(1.0f, exp); 4011 quantum = deFloatLdExp(1.0f, exp - fractionBits); 4012 } 4013 else 4014 { 4015 // Subnormal 4016 base = 0.0f; 4017 quantum = deFloatLdExp(1.0f, minExp - fractionBits); 4018 } 4019 4020 switch (rnd.getInt(0, 16)) 4021 { 4022 case 0: // The highest number in this binade, significand is all bits one. 4023 significand = base - quantum; 4024 break; 4025 case 1: // Significand is one. 4026 significand = quantum; 4027 break; 4028 case 2: // Significand is zero. 4029 significand = 0.0; 4030 break; 4031 default: // Random (evenly distributed) significand. 4032 { 4033 deUint64 intFraction = rnd.getUint64() & ((1 << fractionBits) - 1); 4034 significand = float(intFraction) * quantum; 4035 } 4036 } 4037 4038 // Produce positive numbers more often than negative. 4039 return (rnd.getInt(0,3) == 0 ? -1.0f : 1.0f) * (base + significand); 4040} 4041 4042//! Generate a standard set of floats that should always be tested. 4043void DefaultSampling<float>::genFixeds (const FloatFormat& format, vector<float>& dst) const 4044{ 4045 const int minExp = format.getMinExp(); 4046 const int maxExp = format.getMaxExp(); 4047 const int fractionBits = format.getFractionBits(); 4048 const float minQuantum = deFloatLdExp(1.0f, minExp - fractionBits); 4049 const float minNormalized = deFloatLdExp(1.0f, minExp); 4050 const float maxQuantum = deFloatLdExp(1.0f, maxExp - fractionBits); 4051 4052 // NaN 4053 dst.push_back(TCU_NAN); 4054 // Zero 4055 dst.push_back(0.0f); 4056 4057 for (int sign = -1; sign <= 1; sign += 2) 4058 { 4059 // Smallest subnormal 4060 dst.push_back(sign * minQuantum); 4061 4062 // Largest subnormal 4063 dst.push_back(sign * (minNormalized - minQuantum)); 4064 4065 // Smallest normalized 4066 dst.push_back(sign * minNormalized); 4067 4068 // Next smallest normalized 4069 dst.push_back(sign * (minNormalized + minQuantum)); 4070 4071 dst.push_back(sign * 0.5f); 4072 dst.push_back(sign * 1.0f); 4073 dst.push_back(sign * 2.0f); 4074 4075 // Largest number 4076 dst.push_back(sign * (deFloatLdExp(1.0f, maxExp) + 4077 (deFloatLdExp(1.0f, maxExp) - maxQuantum))); 4078 4079 dst.push_back(sign * TCU_INFINITY); 4080 } 4081} 4082 4083template <typename T, int Size> 4084class DefaultSampling<Vector<T, Size> > : public Sampling<Vector<T, Size> > 4085{ 4086public: 4087 typedef Vector<T, Size> Value; 4088 4089 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const 4090 { 4091 Value ret; 4092 4093 for (int ndx = 0; ndx < Size; ++ndx) 4094 ret[ndx] = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd); 4095 4096 return ret; 4097 } 4098 4099 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const 4100 { 4101 vector<T> scalars; 4102 4103 instance<DefaultSampling<T> >().genFixeds(fmt, scalars); 4104 4105 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx) 4106 dst.push_back(Value(scalars[scalarNdx])); 4107 } 4108 4109 double getWeight (void) const 4110 { 4111 return dePow(instance<DefaultSampling<T> >().getWeight(), Size); 4112 } 4113}; 4114 4115template <typename T, int Rows, int Columns> 4116class DefaultSampling<Matrix<T, Rows, Columns> > : public Sampling<Matrix<T, Rows, Columns> > 4117{ 4118public: 4119 typedef Matrix<T, Rows, Columns> Value; 4120 4121 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const 4122 { 4123 Value ret; 4124 4125 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx) 4126 for (int colNdx = 0; colNdx < Columns; ++colNdx) 4127 ret(rowNdx, colNdx) = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd); 4128 4129 return ret; 4130 } 4131 4132 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const 4133 { 4134 vector<T> scalars; 4135 4136 instance<DefaultSampling<T> >().genFixeds(fmt, scalars); 4137 4138 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx) 4139 dst.push_back(Value(scalars[scalarNdx])); 4140 4141 if (Columns == Rows) 4142 { 4143 Value mat (0.0); 4144 T x = T(1.0f); 4145 mat[0][0] = x; 4146 for (int ndx = 0; ndx < Columns; ++ndx) 4147 { 4148 mat[Columns-1-ndx][ndx] = x; 4149 x *= T(2.0f); 4150 } 4151 dst.push_back(mat); 4152 } 4153 } 4154 4155 double getWeight (void) const 4156 { 4157 return dePow(instance<DefaultSampling<T> >().getWeight(), Rows * Columns); 4158 } 4159}; 4160 4161struct Context 4162{ 4163 Context (const string& name_, 4164 TestContext& testContext_, 4165 RenderContext& renderContext_, 4166 const FloatFormat& floatFormat_, 4167 const FloatFormat& highpFormat_, 4168 Precision precision_, 4169 ShaderType shaderType_, 4170 size_t numRandoms_) 4171 : name (name_) 4172 , testContext (testContext_) 4173 , renderContext (renderContext_) 4174 , floatFormat (floatFormat_) 4175 , highpFormat (highpFormat_) 4176 , precision (precision_) 4177 , shaderType (shaderType_) 4178 , numRandoms (numRandoms_) {} 4179 4180 string name; 4181 TestContext& testContext; 4182 RenderContext& renderContext; 4183 FloatFormat floatFormat; 4184 FloatFormat highpFormat; 4185 Precision precision; 4186 ShaderType shaderType; 4187 size_t numRandoms; 4188}; 4189 4190template<typename In0_ = Void, typename In1_ = Void, typename In2_ = Void, typename In3_ = Void> 4191struct InTypes 4192{ 4193 typedef In0_ In0; 4194 typedef In1_ In1; 4195 typedef In2_ In2; 4196 typedef In3_ In3; 4197}; 4198 4199template <typename In> 4200int numInputs (void) 4201{ 4202 return (!isTypeValid<typename In::In0>() ? 0 : 4203 !isTypeValid<typename In::In1>() ? 1 : 4204 !isTypeValid<typename In::In2>() ? 2 : 4205 !isTypeValid<typename In::In3>() ? 3 : 4206 4); 4207} 4208 4209template<typename Out0_, typename Out1_ = Void> 4210struct OutTypes 4211{ 4212 typedef Out0_ Out0; 4213 typedef Out1_ Out1; 4214}; 4215 4216template <typename Out> 4217int numOutputs (void) 4218{ 4219 return (!isTypeValid<typename Out::Out0>() ? 0 : 4220 !isTypeValid<typename Out::Out1>() ? 1 : 4221 2); 4222} 4223 4224template<typename In> 4225struct Inputs 4226{ 4227 vector<typename In::In0> in0; 4228 vector<typename In::In1> in1; 4229 vector<typename In::In2> in2; 4230 vector<typename In::In3> in3; 4231}; 4232 4233template<typename Out> 4234struct Outputs 4235{ 4236 Outputs (size_t size) : out0(size), out1(size) {} 4237 4238 vector<typename Out::Out0> out0; 4239 vector<typename Out::Out1> out1; 4240}; 4241 4242template<typename In, typename Out> 4243struct Variables 4244{ 4245 VariableP<typename In::In0> in0; 4246 VariableP<typename In::In1> in1; 4247 VariableP<typename In::In2> in2; 4248 VariableP<typename In::In3> in3; 4249 VariableP<typename Out::Out0> out0; 4250 VariableP<typename Out::Out1> out1; 4251}; 4252 4253template<typename In> 4254struct Samplings 4255{ 4256 Samplings (const Sampling<typename In::In0>& in0_, 4257 const Sampling<typename In::In1>& in1_, 4258 const Sampling<typename In::In2>& in2_, 4259 const Sampling<typename In::In3>& in3_) 4260 : in0 (in0_), in1 (in1_), in2 (in2_), in3 (in3_) {} 4261 4262 const Sampling<typename In::In0>& in0; 4263 const Sampling<typename In::In1>& in1; 4264 const Sampling<typename In::In2>& in2; 4265 const Sampling<typename In::In3>& in3; 4266}; 4267 4268template<typename In> 4269struct DefaultSamplings : Samplings<In> 4270{ 4271 DefaultSamplings (void) 4272 : Samplings<In>(instance<DefaultSampling<typename In::In0> >(), 4273 instance<DefaultSampling<typename In::In1> >(), 4274 instance<DefaultSampling<typename In::In2> >(), 4275 instance<DefaultSampling<typename In::In3> >()) {} 4276}; 4277 4278class PrecisionCase : public TestCase 4279{ 4280public: 4281 IterateResult iterate (void); 4282 4283protected: 4284 PrecisionCase (const Context& context, 4285 const string& name, 4286 const string& extension = "") 4287 : TestCase (context.testContext, 4288 name.c_str(), 4289 name.c_str()) 4290 , m_ctx (context) 4291 , m_status () 4292 , m_rnd (0xdeadbeefu + 4293 context.testContext.getCommandLine().getBaseSeed()) 4294 , m_extension (extension) 4295 { 4296 } 4297 4298 RenderContext& getRenderContext(void) const { return m_ctx.renderContext; } 4299 4300 const FloatFormat& getFormat (void) const { return m_ctx.floatFormat; } 4301 4302 TestLog& log (void) const { return m_testCtx.getLog(); } 4303 4304 virtual void runTest (void) = 0; 4305 4306 template <typename In, typename Out> 4307 void testStatement (const Variables<In, Out>& variables, 4308 const Inputs<In>& inputs, 4309 const Statement& stmt); 4310 4311 template<typename T> 4312 Symbol makeSymbol (const Variable<T>& variable) 4313 { 4314 return Symbol(variable.getName(), getVarTypeOf<T>(m_ctx.precision)); 4315 } 4316 4317 Context m_ctx; 4318 ResultCollector m_status; 4319 Random m_rnd; 4320 const string m_extension; 4321}; 4322 4323IterateResult PrecisionCase::iterate (void) 4324{ 4325 runTest(); 4326 m_status.setTestContextResult(m_testCtx); 4327 return STOP; 4328} 4329 4330template <typename In, typename Out> 4331void PrecisionCase::testStatement (const Variables<In, Out>& variables, 4332 const Inputs<In>& inputs, 4333 const Statement& stmt) 4334{ 4335 using namespace ShaderExecUtil; 4336 4337 typedef typename In::In0 In0; 4338 typedef typename In::In1 In1; 4339 typedef typename In::In2 In2; 4340 typedef typename In::In3 In3; 4341 typedef typename Out::Out0 Out0; 4342 typedef typename Out::Out1 Out1; 4343 4344 const FloatFormat& fmt = getFormat(); 4345 const int inCount = numInputs<In>(); 4346 const int outCount = numOutputs<Out>(); 4347 const size_t numValues = (inCount > 0) ? inputs.in0.size() : 1; 4348 Outputs<Out> outputs (numValues); 4349 ShaderSpec spec; 4350 const FloatFormat highpFmt = m_ctx.highpFormat; 4351 const int maxMsgs = 100; 4352 int numErrors = 0; 4353 Environment env; // Hoisted out of the inner loop for optimization. 4354 4355 switch (inCount) 4356 { 4357 case 4: DE_ASSERT(inputs.in3.size() == numValues); 4358 case 3: DE_ASSERT(inputs.in2.size() == numValues); 4359 case 2: DE_ASSERT(inputs.in1.size() == numValues); 4360 case 1: DE_ASSERT(inputs.in0.size() == numValues); 4361 default: break; 4362 } 4363 4364 // Print out the statement and its definitions 4365 log() << TestLog::Message << "Statement: " << stmt << TestLog::EndMessage; 4366 { 4367 ostringstream oss; 4368 FuncSet funcs; 4369 4370 stmt.getUsedFuncs(funcs); 4371 for (FuncSet::const_iterator it = funcs.begin(); it != funcs.end(); ++it) 4372 { 4373 (*it)->printDefinition(oss); 4374 } 4375 if (!funcs.empty()) 4376 log() << TestLog::Message << "Reference definitions:\n" << oss.str() 4377 << TestLog::EndMessage; 4378 } 4379 4380 // Initialize ShaderSpec from precision, variables and statement. 4381 { 4382 ostringstream os; 4383 os << "precision " << glu::getPrecisionName(m_ctx.precision) << " float;\n"; 4384 spec.globalDeclarations = os.str(); 4385 } 4386 4387 spec.version = getContextTypeGLSLVersion(getRenderContext().getType()); 4388 4389 if (!m_extension.empty()) 4390 spec.globalDeclarations = "#extension " + m_extension + " : require\n"; 4391 4392 spec.inputs.resize(inCount); 4393 4394 switch (inCount) 4395 { 4396 case 4: spec.inputs[3] = makeSymbol(*variables.in3); 4397 case 3: spec.inputs[2] = makeSymbol(*variables.in2); 4398 case 2: spec.inputs[1] = makeSymbol(*variables.in1); 4399 case 1: spec.inputs[0] = makeSymbol(*variables.in0); 4400 default: break; 4401 } 4402 4403 spec.outputs.resize(outCount); 4404 4405 switch (outCount) 4406 { 4407 case 2: spec.outputs[1] = makeSymbol(*variables.out1); 4408 case 1: spec.outputs[0] = makeSymbol(*variables.out0); 4409 default: break; 4410 } 4411 4412 spec.source = de::toString(stmt); 4413 4414 // Run the shader with inputs. 4415 { 4416 UniquePtr<ShaderExecutor> executor (createExecutor(getRenderContext(), 4417 m_ctx.shaderType, 4418 spec)); 4419 const void* inputArr[] = 4420 { 4421 &inputs.in0.front(), &inputs.in1.front(), &inputs.in2.front(), &inputs.in3.front(), 4422 }; 4423 void* outputArr[] = 4424 { 4425 &outputs.out0.front(), &outputs.out1.front(), 4426 }; 4427 4428 executor->log(log()); 4429 if (!executor->isOk()) 4430 TCU_FAIL("Shader compilation failed"); 4431 4432 executor->useProgram(); 4433 executor->execute(int(numValues), inputArr, outputArr); 4434 } 4435 4436 // Initialize environment with dummy values so we don't need to bind in inner loop. 4437 { 4438 const typename Traits<In0>::IVal in0; 4439 const typename Traits<In1>::IVal in1; 4440 const typename Traits<In2>::IVal in2; 4441 const typename Traits<In3>::IVal in3; 4442 const typename Traits<Out0>::IVal reference0; 4443 const typename Traits<Out1>::IVal reference1; 4444 4445 env.bind(*variables.in0, in0); 4446 env.bind(*variables.in1, in1); 4447 env.bind(*variables.in2, in2); 4448 env.bind(*variables.in3, in3); 4449 env.bind(*variables.out0, reference0); 4450 env.bind(*variables.out1, reference1); 4451 } 4452 4453 // For each input tuple, compute output reference interval and compare 4454 // shader output to the reference. 4455 for (size_t valueNdx = 0; valueNdx < numValues; valueNdx++) 4456 { 4457 bool result = true; 4458 typename Traits<Out0>::IVal reference0; 4459 typename Traits<Out1>::IVal reference1; 4460 4461 env.lookup(*variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx])); 4462 env.lookup(*variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx])); 4463 env.lookup(*variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx])); 4464 env.lookup(*variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx])); 4465 4466 { 4467 EvalContext ctx (fmt, m_ctx.precision, env); 4468 stmt.execute(ctx); 4469 } 4470 4471 switch (outCount) 4472 { 4473 case 2: 4474 reference1 = convert<Out1>(highpFmt, env.lookup(*variables.out1)); 4475 if (!m_status.check(contains(reference1, outputs.out1[valueNdx]), 4476 "Shader output 1 is outside acceptable range")) 4477 result = false; 4478 case 1: 4479 reference0 = convert<Out0>(highpFmt, env.lookup(*variables.out0)); 4480 if (!m_status.check(contains(reference0, outputs.out0[valueNdx]), 4481 "Shader output 0 is outside acceptable range")) 4482 result = false; 4483 default: break; 4484 } 4485 4486 if (!result) 4487 ++numErrors; 4488 4489 if ((!result && numErrors <= maxMsgs) || GLS_LOG_ALL_RESULTS) 4490 { 4491 MessageBuilder builder = log().message(); 4492 4493 builder << (result ? "Passed" : "Failed") << " sample:\n"; 4494 4495 if (inCount > 0) 4496 { 4497 builder << "\t" << variables.in0->getName() << " = " 4498 << valueToString(highpFmt, inputs.in0[valueNdx]) << "\n"; 4499 } 4500 4501 if (inCount > 1) 4502 { 4503 builder << "\t" << variables.in1->getName() << " = " 4504 << valueToString(highpFmt, inputs.in1[valueNdx]) << "\n"; 4505 } 4506 4507 if (inCount > 2) 4508 { 4509 builder << "\t" << variables.in2->getName() << " = " 4510 << valueToString(highpFmt, inputs.in2[valueNdx]) << "\n"; 4511 } 4512 4513 if (inCount > 3) 4514 { 4515 builder << "\t" << variables.in3->getName() << " = " 4516 << valueToString(highpFmt, inputs.in3[valueNdx]) << "\n"; 4517 } 4518 4519 if (outCount > 0) 4520 { 4521 builder << "\t" << variables.out0->getName() << " = " 4522 << valueToString(highpFmt, outputs.out0[valueNdx]) << "\n" 4523 << "\tExpected range: " 4524 << intervalToString<typename Out::Out0>(highpFmt, reference0) << "\n"; 4525 } 4526 4527 if (outCount > 1) 4528 { 4529 builder << "\t" << variables.out1->getName() << " = " 4530 << valueToString(highpFmt, outputs.out1[valueNdx]) << "\n" 4531 << "\tExpected range: " 4532 << intervalToString<typename Out::Out1>(highpFmt, reference1) << "\n"; 4533 } 4534 4535 builder << TestLog::EndMessage; 4536 } 4537 } 4538 4539 if (numErrors > maxMsgs) 4540 { 4541 log() << TestLog::Message << "(Skipped " << (numErrors - maxMsgs) << " messages.)" 4542 << TestLog::EndMessage; 4543 } 4544 4545 if (numErrors == 0) 4546 { 4547 log() << TestLog::Message << "All " << numValues << " inputs passed." 4548 << TestLog::EndMessage; 4549 } 4550 else 4551 { 4552 log() << TestLog::Message << numErrors << "/" << numValues << " inputs failed." 4553 << TestLog::EndMessage; 4554 } 4555} 4556 4557 4558 4559template <typename T> 4560struct InputLess 4561{ 4562 bool operator() (const T& val1, const T& val2) const 4563 { 4564 return val1 < val2; 4565 } 4566}; 4567 4568template <typename T> 4569bool inputLess (const T& val1, const T& val2) 4570{ 4571 return InputLess<T>()(val1, val2); 4572} 4573 4574template <> 4575struct InputLess<float> 4576{ 4577 bool operator() (const float& val1, const float& val2) const 4578 { 4579 if (deIsNaN(val1)) 4580 return false; 4581 if (deIsNaN(val2)) 4582 return true; 4583 return val1 < val2; 4584 } 4585}; 4586 4587template <typename T, int Size> 4588struct InputLess<Vector<T, Size> > 4589{ 4590 bool operator() (const Vector<T, Size>& vec1, const Vector<T, Size>& vec2) const 4591 { 4592 for (int ndx = 0; ndx < Size; ++ndx) 4593 { 4594 if (inputLess(vec1[ndx], vec2[ndx])) 4595 return true; 4596 if (inputLess(vec2[ndx], vec1[ndx])) 4597 return false; 4598 } 4599 4600 return false; 4601 } 4602}; 4603 4604template <typename T, int Rows, int Cols> 4605struct InputLess<Matrix<T, Rows, Cols> > 4606{ 4607 bool operator() (const Matrix<T, Rows, Cols>& mat1, 4608 const Matrix<T, Rows, Cols>& mat2) const 4609 { 4610 for (int col = 0; col < Cols; ++col) 4611 { 4612 if (inputLess(mat1[col], mat2[col])) 4613 return true; 4614 if (inputLess(mat2[col], mat1[col])) 4615 return false; 4616 } 4617 4618 return false; 4619 } 4620}; 4621 4622template <typename In> 4623struct InTuple : 4624 public Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3> 4625{ 4626 InTuple (const typename In::In0& in0, 4627 const typename In::In1& in1, 4628 const typename In::In2& in2, 4629 const typename In::In3& in3) 4630 : Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3> 4631 (in0, in1, in2, in3) {} 4632}; 4633 4634template <typename In> 4635struct InputLess<InTuple<In> > 4636{ 4637 bool operator() (const InTuple<In>& in1, const InTuple<In>& in2) const 4638 { 4639 if (inputLess(in1.a, in2.a)) 4640 return true; 4641 if (inputLess(in2.a, in1.a)) 4642 return false; 4643 if (inputLess(in1.b, in2.b)) 4644 return true; 4645 if (inputLess(in2.b, in1.b)) 4646 return false; 4647 if (inputLess(in1.c, in2.c)) 4648 return true; 4649 if (inputLess(in2.c, in1.c)) 4650 return false; 4651 if (inputLess(in1.d, in2.d)) 4652 return true; 4653 return false; 4654 }; 4655}; 4656 4657template<typename In> 4658Inputs<In> generateInputs (const Samplings<In>& samplings, 4659 const FloatFormat& floatFormat, 4660 Precision intPrecision, 4661 size_t numSamples, 4662 Random& rnd) 4663{ 4664 Inputs<In> ret; 4665 Inputs<In> fixedInputs; 4666 set<InTuple<In>, InputLess<InTuple<In> > > seenInputs; 4667 4668 samplings.in0.genFixeds(floatFormat, fixedInputs.in0); 4669 samplings.in1.genFixeds(floatFormat, fixedInputs.in1); 4670 samplings.in2.genFixeds(floatFormat, fixedInputs.in2); 4671 samplings.in3.genFixeds(floatFormat, fixedInputs.in3); 4672 4673 for (size_t ndx0 = 0; ndx0 < fixedInputs.in0.size(); ++ndx0) 4674 { 4675 for (size_t ndx1 = 0; ndx1 < fixedInputs.in1.size(); ++ndx1) 4676 { 4677 for (size_t ndx2 = 0; ndx2 < fixedInputs.in2.size(); ++ndx2) 4678 { 4679 for (size_t ndx3 = 0; ndx3 < fixedInputs.in3.size(); ++ndx3) 4680 { 4681 const InTuple<In> tuple (fixedInputs.in0[ndx0], 4682 fixedInputs.in1[ndx1], 4683 fixedInputs.in2[ndx2], 4684 fixedInputs.in3[ndx3]); 4685 4686 seenInputs.insert(tuple); 4687 ret.in0.push_back(tuple.a); 4688 ret.in1.push_back(tuple.b); 4689 ret.in2.push_back(tuple.c); 4690 ret.in3.push_back(tuple.d); 4691 } 4692 } 4693 } 4694 } 4695 4696 for (size_t ndx = 0; ndx < numSamples; ++ndx) 4697 { 4698 const typename In::In0 in0 = samplings.in0.genRandom(floatFormat, intPrecision, rnd); 4699 const typename In::In1 in1 = samplings.in1.genRandom(floatFormat, intPrecision, rnd); 4700 const typename In::In2 in2 = samplings.in2.genRandom(floatFormat, intPrecision, rnd); 4701 const typename In::In3 in3 = samplings.in3.genRandom(floatFormat, intPrecision, rnd); 4702 const InTuple<In> tuple (in0, in1, in2, in3); 4703 4704 if (de::contains(seenInputs, tuple)) 4705 continue; 4706 4707 seenInputs.insert(tuple); 4708 ret.in0.push_back(in0); 4709 ret.in1.push_back(in1); 4710 ret.in2.push_back(in2); 4711 ret.in3.push_back(in3); 4712 } 4713 4714 return ret; 4715} 4716 4717class FuncCaseBase : public PrecisionCase 4718{ 4719public: 4720 IterateResult iterate (void); 4721 4722protected: 4723 FuncCaseBase (const Context& context, 4724 const string& name, 4725 const FuncBase& func) 4726 : PrecisionCase (context, name, func.getRequiredExtension()) {} 4727}; 4728 4729IterateResult FuncCaseBase::iterate (void) 4730{ 4731 MovePtr<ContextInfo> info (ContextInfo::create(getRenderContext())); 4732 4733 if (!m_extension.empty() && !info->isExtensionSupported(m_extension.c_str())) 4734 throw NotSupportedError("Unsupported extension: " + m_extension); 4735 4736 runTest(); 4737 4738 m_status.setTestContextResult(m_testCtx); 4739 return STOP; 4740} 4741 4742template <typename Sig> 4743class FuncCase : public FuncCaseBase 4744{ 4745public: 4746 typedef Func<Sig> CaseFunc; 4747 typedef typename Sig::Ret Ret; 4748 typedef typename Sig::Arg0 Arg0; 4749 typedef typename Sig::Arg1 Arg1; 4750 typedef typename Sig::Arg2 Arg2; 4751 typedef typename Sig::Arg3 Arg3; 4752 typedef InTypes<Arg0, Arg1, Arg2, Arg3> In; 4753 typedef OutTypes<Ret> Out; 4754 4755 FuncCase (const Context& context, 4756 const string& name, 4757 const CaseFunc& func) 4758 : FuncCaseBase (context, name, func) 4759 , m_func (func) {} 4760 4761protected: 4762 void runTest (void); 4763 4764 virtual const Samplings<In>& getSamplings (void) 4765 { 4766 return instance<DefaultSamplings<In> >(); 4767 } 4768 4769private: 4770 const CaseFunc& m_func; 4771}; 4772 4773template <typename Sig> 4774void FuncCase<Sig>::runTest (void) 4775{ 4776 const Inputs<In> inputs (generateInputs(getSamplings(), 4777 m_ctx.floatFormat, 4778 m_ctx.precision, 4779 m_ctx.numRandoms, 4780 m_rnd)); 4781 Variables<In, Out> variables; 4782 4783 variables.out0 = variable<Ret>("out0"); 4784 variables.out1 = variable<Void>("out1"); 4785 variables.in0 = variable<Arg0>("in0"); 4786 variables.in1 = variable<Arg1>("in1"); 4787 variables.in2 = variable<Arg2>("in2"); 4788 variables.in3 = variable<Arg3>("in3"); 4789 4790 { 4791 ExprP<Ret> expr = applyVar(m_func, 4792 variables.in0, variables.in1, 4793 variables.in2, variables.in3); 4794 StatementP stmt = variableAssignment(variables.out0, expr); 4795 4796 this->testStatement(variables, inputs, *stmt); 4797 } 4798} 4799 4800template <typename Sig> 4801class InOutFuncCase : public FuncCaseBase 4802{ 4803public: 4804 typedef Func<Sig> CaseFunc; 4805 typedef typename Sig::Ret Ret; 4806 typedef typename Sig::Arg0 Arg0; 4807 typedef typename Sig::Arg1 Arg1; 4808 typedef typename Sig::Arg2 Arg2; 4809 typedef typename Sig::Arg3 Arg3; 4810 typedef InTypes<Arg0, Arg2, Arg3> In; 4811 typedef OutTypes<Ret, Arg1> Out; 4812 4813 InOutFuncCase (const Context& context, 4814 const string& name, 4815 const CaseFunc& func) 4816 : FuncCaseBase (context, name, func) 4817 , m_func (func) {} 4818 4819protected: 4820 void runTest (void); 4821 4822 virtual const Samplings<In>& getSamplings (void) 4823 { 4824 return instance<DefaultSamplings<In> >(); 4825 } 4826 4827private: 4828 const CaseFunc& m_func; 4829}; 4830 4831template <typename Sig> 4832void InOutFuncCase<Sig>::runTest (void) 4833{ 4834 const Inputs<In> inputs (generateInputs(getSamplings(), 4835 m_ctx.floatFormat, 4836 m_ctx.precision, 4837 m_ctx.numRandoms, 4838 m_rnd)); 4839 Variables<In, Out> variables; 4840 4841 variables.out0 = variable<Ret>("out0"); 4842 variables.out1 = variable<Arg1>("out1"); 4843 variables.in0 = variable<Arg0>("in0"); 4844 variables.in1 = variable<Arg2>("in1"); 4845 variables.in2 = variable<Arg3>("in2"); 4846 variables.in3 = variable<Void>("in3"); 4847 4848 { 4849 ExprP<Ret> expr = applyVar(m_func, 4850 variables.in0, variables.out1, 4851 variables.in1, variables.in2); 4852 StatementP stmt = variableAssignment(variables.out0, expr); 4853 4854 this->testStatement(variables, inputs, *stmt); 4855 } 4856} 4857 4858template <typename Sig> 4859PrecisionCase* createFuncCase (const Context& context, 4860 const string& name, 4861 const Func<Sig>& func) 4862{ 4863 switch (func.getOutParamIndex()) 4864 { 4865 case -1: 4866 return new FuncCase<Sig>(context, name, func); 4867 case 1: 4868 return new InOutFuncCase<Sig>(context, name, func); 4869 default: 4870 DE_ASSERT(!"Impossible"); 4871 } 4872 return DE_NULL; 4873} 4874 4875class CaseFactory 4876{ 4877public: 4878 virtual ~CaseFactory (void) {} 4879 virtual MovePtr<TestNode> createCase (const Context& ctx) const = 0; 4880 virtual string getName (void) const = 0; 4881 virtual string getDesc (void) const = 0; 4882}; 4883 4884class FuncCaseFactory : public CaseFactory 4885{ 4886public: 4887 virtual const FuncBase& getFunc (void) const = 0; 4888 4889 string getName (void) const 4890 { 4891 return de::toLower(getFunc().getName()); 4892 } 4893 4894 string getDesc (void) const 4895 { 4896 return "Function '" + getFunc().getName() + "'"; 4897 } 4898}; 4899 4900template <typename Sig> 4901class GenFuncCaseFactory : public CaseFactory 4902{ 4903public: 4904 4905 GenFuncCaseFactory (const GenFuncs<Sig>& funcs, 4906 const string& name) 4907 : m_funcs (funcs) 4908 , m_name (de::toLower(name)) {} 4909 4910 MovePtr<TestNode> createCase (const Context& ctx) const 4911 { 4912 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, 4913 ctx.name.c_str(), ctx.name.c_str()); 4914 4915 group->addChild(createFuncCase(ctx, "scalar", m_funcs.func)); 4916 group->addChild(createFuncCase(ctx, "vec2", m_funcs.func2)); 4917 group->addChild(createFuncCase(ctx, "vec3", m_funcs.func3)); 4918 group->addChild(createFuncCase(ctx, "vec4", m_funcs.func4)); 4919 4920 return MovePtr<TestNode>(group); 4921 } 4922 4923 string getName (void) const 4924 { 4925 return m_name; 4926 } 4927 4928 string getDesc (void) const 4929 { 4930 return "Function '" + m_funcs.func.getName() + "'"; 4931 } 4932 4933private: 4934 const GenFuncs<Sig> m_funcs; 4935 string m_name; 4936}; 4937 4938template <template <int> class GenF> 4939class TemplateFuncCaseFactory : public FuncCaseFactory 4940{ 4941public: 4942 MovePtr<TestNode> createCase (const Context& ctx) const 4943 { 4944 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, 4945 ctx.name.c_str(), ctx.name.c_str()); 4946 group->addChild(createFuncCase(ctx, "scalar", instance<GenF<1> >())); 4947 group->addChild(createFuncCase(ctx, "vec2", instance<GenF<2> >())); 4948 group->addChild(createFuncCase(ctx, "vec3", instance<GenF<3> >())); 4949 group->addChild(createFuncCase(ctx, "vec4", instance<GenF<4> >())); 4950 4951 return MovePtr<TestNode>(group); 4952 } 4953 4954 const FuncBase& getFunc (void) const { return instance<GenF<1> >(); } 4955}; 4956 4957template <template <int> class GenF> 4958class SquareMatrixFuncCaseFactory : public FuncCaseFactory 4959{ 4960public: 4961 MovePtr<TestNode> createCase (const Context& ctx) const 4962 { 4963 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, 4964 ctx.name.c_str(), ctx.name.c_str()); 4965 group->addChild(createFuncCase(ctx, "mat2", instance<GenF<2> >())); 4966#if 0 4967 // disabled until we get reasonable results 4968 group->addChild(createFuncCase(ctx, "mat3", instance<GenF<3> >())); 4969 group->addChild(createFuncCase(ctx, "mat4", instance<GenF<4> >())); 4970#endif 4971 4972 return MovePtr<TestNode>(group); 4973 } 4974 4975 const FuncBase& getFunc (void) const { return instance<GenF<2> >(); } 4976}; 4977 4978template <template <int, int> class GenF> 4979class MatrixFuncCaseFactory : public FuncCaseFactory 4980{ 4981public: 4982 MovePtr<TestNode> createCase (const Context& ctx) const 4983 { 4984 TestCaseGroup* const group = new TestCaseGroup(ctx.testContext, 4985 ctx.name.c_str(), ctx.name.c_str()); 4986 4987 this->addCase<2, 2>(ctx, group); 4988 this->addCase<3, 2>(ctx, group); 4989 this->addCase<4, 2>(ctx, group); 4990 this->addCase<2, 3>(ctx, group); 4991 this->addCase<3, 3>(ctx, group); 4992 this->addCase<4, 3>(ctx, group); 4993 this->addCase<2, 4>(ctx, group); 4994 this->addCase<3, 4>(ctx, group); 4995 this->addCase<4, 4>(ctx, group); 4996 4997 return MovePtr<TestNode>(group); 4998 } 4999 5000 const FuncBase& getFunc (void) const { return instance<GenF<2,2> >(); } 5001 5002private: 5003 template <int Rows, int Cols> 5004 void addCase (const Context& ctx, TestCaseGroup* group) const 5005 { 5006 const char* const name = dataTypeNameOf<Matrix<float, Rows, Cols> >(); 5007 5008 group->addChild(createFuncCase(ctx, name, instance<GenF<Rows, Cols> >())); 5009 } 5010}; 5011 5012template <typename Sig> 5013class SimpleFuncCaseFactory : public CaseFactory 5014{ 5015public: 5016 SimpleFuncCaseFactory (const Func<Sig>& func) : m_func(func) {} 5017 5018 MovePtr<TestNode> createCase (const Context& ctx) const 5019 { 5020 return MovePtr<TestNode>(createFuncCase(ctx, ctx.name.c_str(), m_func)); 5021 } 5022 5023 string getName (void) const 5024 { 5025 return de::toLower(m_func.getName()); 5026 } 5027 5028 string getDesc (void) const 5029 { 5030 return "Function '" + getName() + "'"; 5031 } 5032 5033private: 5034 const Func<Sig>& m_func; 5035}; 5036 5037template <typename F> 5038SharedPtr<SimpleFuncCaseFactory<typename F::Sig> > createSimpleFuncCaseFactory (void) 5039{ 5040 return SharedPtr<SimpleFuncCaseFactory<typename F::Sig> >( 5041 new SimpleFuncCaseFactory<typename F::Sig>(instance<F>())); 5042} 5043 5044class BuiltinFuncs : public CaseFactories 5045{ 5046public: 5047 const vector<const CaseFactory*> getFactories (void) const 5048 { 5049 vector<const CaseFactory*> ret; 5050 5051 for (size_t ndx = 0; ndx < m_factories.size(); ++ndx) 5052 ret.push_back(m_factories[ndx].get()); 5053 5054 return ret; 5055 } 5056 5057 void addFactory (SharedPtr<const CaseFactory> fact) 5058 { 5059 m_factories.push_back(fact); 5060 } 5061 5062private: 5063 vector<SharedPtr<const CaseFactory> > m_factories; 5064}; 5065 5066template <typename F> 5067void addScalarFactory(BuiltinFuncs& funcs, string name = "") 5068{ 5069 if (name.empty()) 5070 name = instance<F>().getName(); 5071 5072 funcs.addFactory(SharedPtr<const CaseFactory>(new GenFuncCaseFactory<typename F::Sig>( 5073 makeVectorizedFuncs<F>(), name))); 5074} 5075 5076MovePtr<const CaseFactories> createES3BuiltinCases (void) 5077{ 5078 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs()); 5079 5080 addScalarFactory<Add>(*funcs); 5081 addScalarFactory<Sub>(*funcs); 5082 addScalarFactory<Mul>(*funcs); 5083 addScalarFactory<Div>(*funcs); 5084 5085 addScalarFactory<Radians>(*funcs); 5086 addScalarFactory<Degrees>(*funcs); 5087 addScalarFactory<Sin>(*funcs); 5088 addScalarFactory<Cos>(*funcs); 5089 addScalarFactory<Tan>(*funcs); 5090 addScalarFactory<ASin>(*funcs); 5091 addScalarFactory<ACos>(*funcs); 5092 addScalarFactory<ATan2>(*funcs, "atan2"); 5093 addScalarFactory<ATan>(*funcs); 5094 addScalarFactory<Sinh>(*funcs); 5095 addScalarFactory<Cosh>(*funcs); 5096 addScalarFactory<Tanh>(*funcs); 5097 addScalarFactory<ASinh>(*funcs); 5098 addScalarFactory<ACosh>(*funcs); 5099 addScalarFactory<ATanh>(*funcs); 5100 5101 addScalarFactory<Pow>(*funcs); 5102 addScalarFactory<Exp>(*funcs); 5103 addScalarFactory<Log>(*funcs); 5104 addScalarFactory<Exp2>(*funcs); 5105 addScalarFactory<Log2>(*funcs); 5106 addScalarFactory<Sqrt>(*funcs); 5107 addScalarFactory<InverseSqrt>(*funcs); 5108 5109 addScalarFactory<Abs>(*funcs); 5110 addScalarFactory<Sign>(*funcs); 5111 addScalarFactory<Floor>(*funcs); 5112 addScalarFactory<Trunc>(*funcs); 5113 addScalarFactory<Round>(*funcs); 5114 addScalarFactory<RoundEven>(*funcs); 5115 addScalarFactory<Ceil>(*funcs); 5116 addScalarFactory<Fract>(*funcs); 5117 addScalarFactory<Mod>(*funcs); 5118 funcs->addFactory(createSimpleFuncCaseFactory<Modf>()); 5119 addScalarFactory<Min>(*funcs); 5120 addScalarFactory<Max>(*funcs); 5121 addScalarFactory<Clamp>(*funcs); 5122 addScalarFactory<Mix>(*funcs); 5123 addScalarFactory<Step>(*funcs); 5124 addScalarFactory<SmoothStep>(*funcs); 5125 5126 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length>())); 5127 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance>())); 5128 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot>())); 5129 funcs->addFactory(createSimpleFuncCaseFactory<Cross>()); 5130 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize>())); 5131 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward>())); 5132 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect>())); 5133 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract>())); 5134 5135 5136 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<MatrixCompMult>())); 5137 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct>())); 5138 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose>())); 5139 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant>())); 5140 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse>())); 5141 5142 return MovePtr<const CaseFactories>(funcs.release()); 5143} 5144 5145MovePtr<const CaseFactories> createES31BuiltinCases (void) 5146{ 5147 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs()); 5148 5149 addScalarFactory<FrExp>(*funcs); 5150 addScalarFactory<LdExp>(*funcs); 5151 addScalarFactory<Fma>(*funcs); 5152 5153 return MovePtr<const CaseFactories>(funcs.release()); 5154} 5155 5156struct PrecisionTestContext 5157{ 5158 PrecisionTestContext (TestContext& testCtx_, 5159 RenderContext& renderCtx_, 5160 const FloatFormat& highp_, 5161 const FloatFormat& mediump_, 5162 const FloatFormat& lowp_, 5163 const vector<ShaderType>& shaderTypes_, 5164 int numRandoms_) 5165 : testCtx (testCtx_) 5166 , renderCtx (renderCtx_) 5167 , shaderTypes (shaderTypes_) 5168 , numRandoms (numRandoms_) 5169 { 5170 formats[glu::PRECISION_HIGHP] = &highp_; 5171 formats[glu::PRECISION_MEDIUMP] = &mediump_; 5172 formats[glu::PRECISION_LOWP] = &lowp_; 5173 } 5174 5175 TestContext& testCtx; 5176 RenderContext& renderCtx; 5177 const FloatFormat* formats[glu::PRECISION_LAST]; 5178 vector<ShaderType> shaderTypes; 5179 int numRandoms; 5180}; 5181 5182TestCaseGroup* createFuncGroup (const PrecisionTestContext& ctx, 5183 const CaseFactory& factory) 5184{ 5185 TestCaseGroup* const group = new TestCaseGroup(ctx.testCtx, 5186 factory.getName().c_str(), 5187 factory.getDesc().c_str()); 5188 5189 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; ++precNdx) 5190 { 5191 const Precision precision = Precision(precNdx); 5192 const string precName (glu::getPrecisionName(precision)); 5193 const FloatFormat& fmt = *de::getSizedArrayElement(ctx.formats, precNdx); 5194 const FloatFormat& highpFmt = *de::getSizedArrayElement(ctx.formats, 5195 glu::PRECISION_HIGHP); 5196 5197 for (size_t shaderNdx = 0; shaderNdx < ctx.shaderTypes.size(); ++shaderNdx) 5198 { 5199 const ShaderType shaderType = ctx.shaderTypes[shaderNdx]; 5200 const string shaderName (glu::getShaderTypeName(shaderType)); 5201 const string name = precName + "_" + shaderName; 5202 const Context caseCtx (name, ctx.testCtx, ctx.renderCtx, fmt, highpFmt, 5203 precision, shaderType, ctx.numRandoms); 5204 5205 group->addChild(factory.createCase(caseCtx).release()); 5206 } 5207 } 5208 5209 return group; 5210} 5211 5212void addBuiltinPrecisionTests (TestContext& testCtx, 5213 RenderContext& renderCtx, 5214 const CaseFactories& cases, 5215 const vector<ShaderType>& shaderTypes, 5216 TestCaseGroup& dstGroup) 5217{ 5218 const FloatFormat highp (-126, 127, 23, true, 5219 tcu::MAYBE, // subnormals 5220 tcu::YES, // infinities 5221 tcu::MAYBE); // NaN 5222 // \todo [2014-04-01 lauri] Check these once Khronos bug 11840 is resolved. 5223 const FloatFormat mediump (-13, 13, 9, false); 5224 // A fixed-point format is just a floating point format with a fixed 5225 // exponent and support for subnormals. 5226 const FloatFormat lowp (0, 0, 7, false, tcu::YES); 5227 const PrecisionTestContext ctx (testCtx, renderCtx, highp, mediump, lowp, 5228 shaderTypes, 16384); 5229 5230 for (size_t ndx = 0; ndx < cases.getFactories().size(); ++ndx) 5231 dstGroup.addChild(createFuncGroup(ctx, *cases.getFactories()[ndx])); 5232} 5233 5234} // BuiltinPrecisionTests 5235} // gls 5236} // deqp 5237