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