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