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