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