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