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