1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) Module
3 * -----------------------------------------------
5 * Copyright 2014 The Android Open Source Project
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 * \brief Precision and range tests for GLSL builtins and types.
23 *//*--------------------------------------------------------------------*/
25 #include "glsBuiltinPrecisionTests.hpp"
30 #include "deRandom.hpp"
31 #include "deSTLUtil.hpp"
32 #include "deStringUtil.hpp"
33 #include "deUniquePtr.hpp"
34 #include "deSharedPtr.hpp"
35 #include "deArrayUtil.hpp"
37 #include "tcuCommandLine.hpp"
38 #include "tcuFloatFormat.hpp"
39 #include "tcuInterval.hpp"
40 #include "tcuTestCase.hpp"
41 #include "tcuTestLog.hpp"
42 #include "tcuVector.hpp"
43 #include "tcuMatrix.hpp"
44 #include "tcuResultCollector.hpp"
46 #include "gluContextInfo.hpp"
47 #include "gluVarType.hpp"
48 #include "gluRenderContext.hpp"
49 #include "glwDefs.hpp"
51 #include "glsShaderExecUtil.hpp"
60 // Uncomment this to get evaluation trace dumps to std::cerr
61 // #define GLS_ENABLE_TRACE
63 // set this to true to dump even passing results
64 #define GLS_LOG_ALL_RESULTS false
68 // Computing reference intervals can take a non-trivial amount of time, especially on
69 // platforms where toggling floating-point rounding mode is slow (emulated arm on x86).
70 // As a workaround watchdog is kept happy by touching it periodically during reference
71 // interval computation.
72 TOUCH_WATCHDOG_VALUE_FREQUENCY = 4096
79 namespace BuiltinPrecisionTests
85 using std::ostringstream;
95 using tcu::FloatFormat;
96 using tcu::MessageBuilder;
101 namespace matrix = tcu::matrix;
102 using glu::Precision;
103 using glu::RenderContext;
106 using glu::ShaderType;
107 using glu::ContextInfo;
108 using gls::ShaderExecUtil::Symbol;
110 typedef TestCase::IterateResult IterateResult;
115 /*--------------------------------------------------------------------*//*!
116 * \brief Generic singleton creator.
118 * instance<T>() returns a reference to a unique default-constructed instance
119 * of T. This is mainly used for our GLSL function implementations: each
120 * function is implemented by an object, and each of the objects has a
121 * distinct class. It would be extremely toilsome to maintain a separate
122 * context object that contained individual instances of the function classes,
123 * so we have to resort to global singleton instances.
125 *//*--------------------------------------------------------------------*/
126 template <typename T>
127 const T& instance (void)
129 static const T s_instance = T();
133 /*--------------------------------------------------------------------*//*!
134 * \brief Dummy placeholder type for unused template parameters.
136 * In the precision tests we are dealing with functions of different arities.
137 * To minimize code duplication, we only define templates with the maximum
138 * number of arguments, currently four. If a function's arity is less than the
139 * maximum, Void us used as the type for unused arguments.
141 * Although Voids are not used at run-time, they still must be compilable, so
142 * they must support all operations that other types do.
144 *//*--------------------------------------------------------------------*/
147 typedef Void Element;
153 template <typename T>
154 explicit Void (const T&) {}
156 operator double (void) const { return TCU_NAN; }
158 // These are used to make Voids usable as containers in container-generic code.
159 Void& operator[] (int) { return *this; }
160 const Void& operator[] (int) const { return *this; }
163 ostream& operator<< (ostream& os, Void) { return os << "()"; }
165 //! Returns true for all other types except Void
166 template <typename T> bool isTypeValid (void) { return true; }
167 template <> bool isTypeValid<Void> (void) { return false; }
169 //! Utility function for getting the name of a data type.
170 //! This is used in vector and matrix constructors.
171 template <typename T>
172 const char* dataTypeNameOf (void)
174 return glu::getDataTypeName(glu::dataTypeOf<T>());
178 const char* dataTypeNameOf<Void> (void)
180 DE_FATAL("Impossible");
184 //! A hack to get Void support for VarType.
185 template <typename T>
186 VarType getVarTypeOf (Precision prec = glu::PRECISION_LAST)
188 return glu::varTypeOf<T>(prec);
192 VarType getVarTypeOf<Void> (Precision)
194 DE_FATAL("Impossible");
198 /*--------------------------------------------------------------------*//*!
199 * \brief Type traits for generalized interval types.
201 * We are trying to compute sets of acceptable values not only for
202 * float-valued expressions but also for compound values: vectors and
203 * matrices. We approximate a set of vectors as a vector of intervals and
204 * likewise for matrices.
206 * We now need generalized operations for each type and its interval
207 * approximation. These are given in the type Traits<T>.
209 * The type Traits<T>::IVal is the approximation of T: it is `Interval` for
210 * scalar types, and a vector or matrix of intervals for container types.
212 * To allow template inference to take place, there are function wrappers for
213 * the actual operations in Traits<T>. Hence we can just use:
215 * makeIVal(someFloat)
219 * Traits<float>::doMakeIVal(value)
221 *//*--------------------------------------------------------------------*/
223 template <typename T> struct Traits;
225 //! Create container from elementwise singleton values.
226 template <typename T>
227 typename Traits<T>::IVal makeIVal (const T& value)
229 return Traits<T>::doMakeIVal(value);
232 //! Elementwise union of intervals.
233 template <typename T>
234 typename Traits<T>::IVal unionIVal (const typename Traits<T>::IVal& a,
235 const typename Traits<T>::IVal& b)
237 return Traits<T>::doUnion(a, b);
240 //! Returns true iff every element of `ival` contains the corresponding element of `value`.
241 template <typename T>
242 bool contains (const typename Traits<T>::IVal& ival, const T& value)
244 return Traits<T>::doContains(ival, value);
247 //! Print out an interval with the precision of `fmt`.
248 template <typename T>
249 void printIVal (const FloatFormat& fmt, const typename Traits<T>::IVal& ival, ostream& os)
251 Traits<T>::doPrintIVal(fmt, ival, os);
254 template <typename T>
255 string intervalToString (const FloatFormat& fmt, const typename Traits<T>::IVal& ival)
258 printIVal<T>(fmt, ival, oss);
262 //! Print out a value with the precision of `fmt`.
263 template <typename T>
264 void printValue (const FloatFormat& fmt, const T& value, ostream& os)
266 Traits<T>::doPrintValue(fmt, value, os);
269 template <typename T>
270 string valueToString (const FloatFormat& fmt, const T& val)
273 printValue(fmt, val, oss);
277 //! Approximate `value` elementwise to the float precision defined in `fmt`.
278 //! The resulting interval might not be a singleton if rounding in both
279 //! directions is allowed.
280 template <typename T>
281 typename Traits<T>::IVal round (const FloatFormat& fmt, const T& value)
283 return Traits<T>::doRound(fmt, value);
286 template <typename T>
287 typename Traits<T>::IVal convert (const FloatFormat& fmt,
288 const typename Traits<T>::IVal& value)
290 return Traits<T>::doConvert(fmt, value);
293 //! Common traits for scalar types.
294 template <typename T>
297 typedef Interval IVal;
299 static Interval doMakeIVal (const T& value)
301 // Thankfully all scalar types have a well-defined conversion to `double`,
302 // hence Interval can represent their ranges without problems.
303 return Interval(double(value));
306 static Interval doUnion (const Interval& a, const Interval& b)
311 static bool doContains (const Interval& a, T value)
313 return a.contains(double(value));
316 static Interval doConvert (const FloatFormat& fmt, const IVal& ival)
318 return fmt.convert(ival);
321 static Interval doRound (const FloatFormat& fmt, T value)
323 return fmt.roundOut(double(value), false);
328 struct Traits<float> : ScalarTraits<float>
330 static void doPrintIVal (const FloatFormat& fmt,
331 const Interval& ival,
334 os << fmt.intervalToHex(ival);
337 static void doPrintValue (const FloatFormat& fmt,
341 os << fmt.floatToHex(value);
346 struct Traits<bool> : ScalarTraits<bool>
348 static void doPrintValue (const FloatFormat&,
352 os << (value != 0.0f ? "true" : "false");
355 static void doPrintIVal (const FloatFormat&,
356 const Interval& ival,
360 if (ival.contains(false))
362 if (ival.contains(false) && ival.contains(true))
364 if (ival.contains(true))
371 struct Traits<int> : ScalarTraits<int>
373 static void doPrintValue (const FloatFormat&,
380 static void doPrintIVal (const FloatFormat&,
381 const Interval& ival,
384 os << "[" << int(ival.lo()) << ", " << int(ival.hi()) << "]";
388 //! Common traits for containers, i.e. vectors and matrices.
389 //! T is the container type itself, I is the same type with interval elements.
390 template <typename T, typename I>
391 struct ContainerTraits
393 typedef typename T::Element Element;
396 static IVal doMakeIVal (const T& value)
400 for (int ndx = 0; ndx < T::SIZE; ++ndx)
401 ret[ndx] = makeIVal(value[ndx]);
406 static IVal doUnion (const IVal& a, const IVal& b)
410 for (int ndx = 0; ndx < T::SIZE; ++ndx)
411 ret[ndx] = unionIVal<Element>(a[ndx], b[ndx]);
416 static bool doContains (const IVal& ival, const T& value)
418 for (int ndx = 0; ndx < T::SIZE; ++ndx)
419 if (!contains(ival[ndx], value[ndx]))
425 static void doPrintIVal (const FloatFormat& fmt, const IVal ival, ostream& os)
429 for (int ndx = 0; ndx < T::SIZE; ++ndx)
434 printIVal<Element>(fmt, ival[ndx], os);
440 static void doPrintValue (const FloatFormat& fmt, const T& value, ostream& os)
442 os << dataTypeNameOf<T>() << "(";
444 for (int ndx = 0; ndx < T::SIZE; ++ndx)
449 printValue<Element>(fmt, value[ndx], os);
455 static IVal doConvert (const FloatFormat& fmt, const IVal& value)
459 for (int ndx = 0; ndx < T::SIZE; ++ndx)
460 ret[ndx] = convert<Element>(fmt, value[ndx]);
465 static IVal doRound (const FloatFormat& fmt, T value)
469 for (int ndx = 0; ndx < T::SIZE; ++ndx)
470 ret[ndx] = round(fmt, value[ndx]);
476 template <typename T, int Size>
477 struct Traits<Vector<T, Size> > :
478 ContainerTraits<Vector<T, Size>, Vector<typename Traits<T>::IVal, Size> >
482 template <typename T, int Rows, int Cols>
483 struct Traits<Matrix<T, Rows, Cols> > :
484 ContainerTraits<Matrix<T, Rows, Cols>, Matrix<typename Traits<T>::IVal, Rows, Cols> >
488 //! Void traits. These are just dummies, but technically valid: a Void is a
489 //! unit type with a single possible value.
495 static Void doMakeIVal (const Void& value) { return value; }
496 static Void doUnion (const Void&, const Void&) { return Void(); }
497 static bool doContains (const Void&, Void) { return true; }
498 static Void doRound (const FloatFormat&, const Void& value) { return value; }
499 static Void doConvert (const FloatFormat&, const Void& value) { return value; }
501 static void doPrintValue (const FloatFormat&, const Void&, ostream& os)
506 static void doPrintIVal (const FloatFormat&, const Void&, ostream& os)
512 //! This is needed for container-generic operations.
513 //! We want a scalar type T to be its own "one-element vector".
514 template <typename T, int Size> struct ContainerOf { typedef Vector<T, Size> Container; };
516 template <typename T> struct ContainerOf<T, 1> { typedef T Container; };
517 template <int Size> struct ContainerOf<Void, Size> { typedef Void Container; };
519 // This is a kludge that is only needed to get the ExprP::operator[] syntactic sugar to work.
520 template <typename T> struct ElementOf { typedef typename T::Element Element; };
521 template <> struct ElementOf<float> { typedef void Element; };
522 template <> struct ElementOf<bool> { typedef void Element; };
523 template <> struct ElementOf<int> { typedef void Element; };
525 /*--------------------------------------------------------------------*//*!
527 * \name Abstract syntax for expressions and statements.
529 * We represent GLSL programs as syntax objects: an Expr<T> represents an
530 * expression whose GLSL type corresponds to the C++ type T, and a Statement
531 * represents a statement.
533 * To ease memory management, we use shared pointers to refer to expressions
534 * and statements. ExprP<T> is a shared pointer to an Expr<T>, and StatementP
535 * is a shared pointer to a Statement.
539 *//*--------------------------------------------------------------------*/
546 template <typename T> class ExprP;
547 template <typename T> class Variable;
548 template <typename T> class VariableP;
549 template <typename T> class DefaultSampling;
551 typedef set<const FuncBase*> FuncSet;
553 template <typename T>
554 VariableP<T> variable (const string& name);
555 StatementP compoundStatement (const vector<StatementP>& statements);
557 /*--------------------------------------------------------------------*//*!
558 * \brief A variable environment.
560 * An Environment object maintains the mapping between variables of the
561 * abstract syntax tree and their values.
563 * \todo [2014-03-28 lauri] At least run-time type safety.
565 *//*--------------------------------------------------------------------*/
570 void bind (const Variable<T>& variable,
571 const typename Traits<T>::IVal& value)
573 deUint8* const data = new deUint8[sizeof(value)];
575 deMemcpy(data, &value, sizeof(value));
576 de::insert(m_map, variable.getName(), SharedPtr<deUint8>(data, de::ArrayDeleter<deUint8>()));
580 typename Traits<T>::IVal& lookup (const Variable<T>& variable) const
582 deUint8* const data = de::lookup(m_map, variable.getName()).get();
584 return *reinterpret_cast<typename Traits<T>::IVal*>(data);
588 map<string, SharedPtr<deUint8> > m_map;
591 /*--------------------------------------------------------------------*//*!
592 * \brief Evaluation context.
594 * The evaluation context contains everything that separates one execution of
595 * an expression from the next. Currently this means the desired floating
596 * point precision and the current variable environment.
598 *//*--------------------------------------------------------------------*/
601 EvalContext (const FloatFormat& format_,
602 Precision floatPrecision_,
606 , floatPrecision (floatPrecision_)
608 , callDepth (callDepth_) {}
611 Precision floatPrecision;
616 /*--------------------------------------------------------------------*//*!
617 * \brief Simple incremental counter.
619 * This is used to make sure that different ExpandContexts will not produce
620 * overlapping temporary names.
622 *//*--------------------------------------------------------------------*/
626 Counter (int count = 0) : m_count(count) {}
627 int operator() (void) { return m_count++; }
636 ExpandContext (Counter& symCounter) : m_symCounter(symCounter) {}
637 ExpandContext (const ExpandContext& parent)
638 : m_symCounter(parent.m_symCounter) {}
641 VariableP<T> genSym (const string& baseName)
643 return variable<T>(baseName + de::toString(m_symCounter()));
646 void addStatement (const StatementP& stmt)
648 m_statements.push_back(stmt);
651 vector<StatementP> getStatements (void) const
656 Counter& m_symCounter;
657 vector<StatementP> m_statements;
660 /*--------------------------------------------------------------------*//*!
661 * \brief A statement or declaration.
663 * Statements have no values. Instead, they are executed for their side
664 * effects only: the execute() method should modify at least one variable in
667 * As a bit of a kludge, a Statement object can also represent a declaration:
668 * when it is evaluated, it can add a variable binding to the environment
669 * instead of modifying a current one.
671 *//*--------------------------------------------------------------------*/
675 virtual ~Statement (void) { }
676 //! Execute the statement, modifying the environment of `ctx`
677 void execute (EvalContext& ctx) const { this->doExecute(ctx); }
678 void print (ostream& os) const { this->doPrint(os); }
679 //! Add the functions used in this statement to `dst`.
680 void getUsedFuncs (FuncSet& dst) const { this->doGetUsedFuncs(dst); }
683 virtual void doPrint (ostream& os) const = 0;
684 virtual void doExecute (EvalContext& ctx) const = 0;
685 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
688 ostream& operator<<(ostream& os, const Statement& stmt)
694 /*--------------------------------------------------------------------*//*!
695 * \brief Smart pointer for statements (and declarations)
697 *//*--------------------------------------------------------------------*/
698 class StatementP : public SharedPtr<const Statement>
701 typedef SharedPtr<const Statement> Super;
704 explicit StatementP (const Statement* ptr) : Super(ptr) {}
705 StatementP (const Super& ptr) : Super(ptr) {}
708 /*--------------------------------------------------------------------*//*!
711 * A statement that modifies a variable or a declaration that binds a variable.
713 *//*--------------------------------------------------------------------*/
714 template <typename T>
715 class VariableStatement : public Statement
718 VariableStatement (const VariableP<T>& variable, const ExprP<T>& value,
720 : m_variable (variable)
722 , m_isDeclaration (isDeclaration) {}
725 void doPrint (ostream& os) const
728 os << glu::declare(getVarTypeOf<T>(), m_variable->getName());
730 os << m_variable->getName();
732 os << " = " << *m_value << ";\n";
735 void doExecute (EvalContext& ctx) const
738 ctx.env.bind(*m_variable, m_value->evaluate(ctx));
740 ctx.env.lookup(*m_variable) = m_value->evaluate(ctx);
743 void doGetUsedFuncs (FuncSet& dst) const
745 m_value->getUsedFuncs(dst);
748 VariableP<T> m_variable;
750 bool m_isDeclaration;
753 template <typename T>
754 StatementP variableStatement (const VariableP<T>& variable,
755 const ExprP<T>& value,
758 return StatementP(new VariableStatement<T>(variable, value, isDeclaration));
761 template <typename T>
762 StatementP variableDeclaration (const VariableP<T>& variable, const ExprP<T>& definiens)
764 return variableStatement(variable, definiens, true);
767 template <typename T>
768 StatementP variableAssignment (const VariableP<T>& variable, const ExprP<T>& value)
770 return variableStatement(variable, value, false);
773 /*--------------------------------------------------------------------*//*!
774 * \brief A compound statement, i.e. a block.
776 * A compound statement is executed by executing its constituent statements in
779 *//*--------------------------------------------------------------------*/
780 class CompoundStatement : public Statement
783 CompoundStatement (const vector<StatementP>& statements)
784 : m_statements (statements) {}
787 void doPrint (ostream& os) const
791 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
792 os << *m_statements[ndx];
797 void doExecute (EvalContext& ctx) const
799 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
800 m_statements[ndx]->execute(ctx);
803 void doGetUsedFuncs (FuncSet& dst) const
805 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
806 m_statements[ndx]->getUsedFuncs(dst);
809 vector<StatementP> m_statements;
812 StatementP compoundStatement(const vector<StatementP>& statements)
814 return StatementP(new CompoundStatement(statements));
817 //! Common base class for all expressions regardless of their type.
821 virtual ~ExprBase (void) {}
822 void printExpr (ostream& os) const { this->doPrintExpr(os); }
824 //! Output the functions that this expression refers to
825 void getUsedFuncs (FuncSet& dst) const
827 this->doGetUsedFuncs(dst);
831 virtual void doPrintExpr (ostream&) const {}
832 virtual void doGetUsedFuncs (FuncSet&) const {}
835 //! Type-specific operations for an expression representing type T.
836 template <typename T>
837 class Expr : public ExprBase
841 typedef typename Traits<T>::IVal IVal;
843 IVal evaluate (const EvalContext& ctx) const;
846 virtual IVal doEvaluate (const EvalContext& ctx) const = 0;
849 //! Evaluate an expression with the given context, optionally tracing the calls to stderr.
850 template <typename T>
851 typename Traits<T>::IVal Expr<T>::evaluate (const EvalContext& ctx) const
853 #ifdef GLS_ENABLE_TRACE
854 static const FloatFormat highpFmt (-126, 127, 23, true,
858 EvalContext newCtx (ctx.format, ctx.floatPrecision,
859 ctx.env, ctx.callDepth + 1);
860 const IVal ret = this->doEvaluate(newCtx);
862 if (isTypeValid<T>())
864 std::cerr << string(ctx.callDepth, ' ');
865 this->printExpr(std::cerr);
866 std::cerr << " -> " << intervalToString<T>(highpFmt, ret) << std::endl;
870 return this->doEvaluate(ctx);
874 template <typename T>
875 class ExprPBase : public SharedPtr<const Expr<T> >
880 ostream& operator<< (ostream& os, const ExprBase& expr)
886 /*--------------------------------------------------------------------*//*!
887 * \brief Shared pointer to an expression of a container type.
889 * Container types (i.e. vectors and matrices) support the subscription
890 * operator. This class provides a bit of syntactic sugar to allow us to use
891 * the C++ subscription operator to create a subscription expression.
892 *//*--------------------------------------------------------------------*/
893 template <typename T>
894 class ContainerExprPBase : public ExprPBase<T>
897 ExprP<typename T::Element> operator[] (int i) const;
900 template <typename T>
901 class ExprP : public ExprPBase<T> {};
903 // We treat Voids as containers since the dummy parameters in generalized
904 // vector functions are represented as Voids.
906 class ExprP<Void> : public ContainerExprPBase<Void> {};
908 template <typename T, int Size>
909 class ExprP<Vector<T, Size> > : public ContainerExprPBase<Vector<T, Size> > {};
911 template <typename T, int Rows, int Cols>
912 class ExprP<Matrix<T, Rows, Cols> > : public ContainerExprPBase<Matrix<T, Rows, Cols> > {};
914 template <typename T> ExprP<T> exprP (void)
919 template <typename T>
920 ExprP<T> exprP (const SharedPtr<const Expr<T> >& ptr)
923 static_cast<SharedPtr<const Expr<T> >&>(ret) = ptr;
927 template <typename T>
928 ExprP<T> exprP (const Expr<T>* ptr)
930 return exprP(SharedPtr<const Expr<T> >(ptr));
933 /*--------------------------------------------------------------------*//*!
934 * \brief A shared pointer to a variable expression.
936 * This is just a narrowing of ExprP for the operations that require a variable
937 * instead of an arbitrary expression.
939 *//*--------------------------------------------------------------------*/
940 template <typename T>
941 class VariableP : public SharedPtr<const Variable<T> >
944 typedef SharedPtr<const Variable<T> > Super;
945 explicit VariableP (const Variable<T>* ptr) : Super(ptr) {}
947 VariableP (const Super& ptr) : Super(ptr) {}
949 operator ExprP<T> (void) const { return exprP(SharedPtr<const Expr<T> >(*this)); }
952 /*--------------------------------------------------------------------*//*!
953 * \name Syntactic sugar operators for expressions.
957 * These operators allow the use of C++ syntax to construct GLSL expressions
958 * containing operators: e.g. "a+b" creates an addition expression with
959 * operands a and b, and so on.
961 *//*--------------------------------------------------------------------*/
962 ExprP<float> operator-(const ExprP<float>& arg0);
963 ExprP<float> operator+(const ExprP<float>& arg0,
964 const ExprP<float>& arg1);
965 ExprP<float> operator-(const ExprP<float>& arg0,
966 const ExprP<float>& arg1);
967 ExprP<float> operator*(const ExprP<float>& arg0,
968 const ExprP<float>& arg1);
969 ExprP<float> operator/(const ExprP<float>& arg0,
970 const ExprP<float>& arg1);
972 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0);
974 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
975 const ExprP<float>& arg1);
977 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
978 const ExprP<Vector<float, Size> >& arg1);
980 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
981 const ExprP<Vector<float, Size> >& arg1);
982 template<int Left, int Mid, int Right>
983 ExprP<Matrix<float, Left, Right> > operator* (const ExprP<Matrix<float, Left, Mid> >& left,
984 const ExprP<Matrix<float, Mid, Right> >& right);
985 template<int Rows, int Cols>
986 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
987 const ExprP<Matrix<float, Rows, Cols> >& right);
988 template<int Rows, int Cols>
989 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
990 const ExprP<Vector<float, Rows> >& right);
991 template<int Rows, int Cols>
992 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
993 const ExprP<float>& right);
994 template<int Rows, int Cols>
995 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
996 const ExprP<Matrix<float, Rows, Cols> >& right);
997 template<int Rows, int Cols>
998 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat);
1002 /*--------------------------------------------------------------------*//*!
1003 * \brief Variable expression.
1005 * A variable is evaluated by looking up its range of possible values from an
1007 *//*--------------------------------------------------------------------*/
1008 template <typename T>
1009 class Variable : public Expr<T>
1012 typedef typename Expr<T>::IVal IVal;
1014 Variable (const string& name) : m_name (name) {}
1015 string getName (void) const { return m_name; }
1018 void doPrintExpr (ostream& os) const { os << m_name; }
1019 IVal doEvaluate (const EvalContext& ctx) const
1021 return ctx.env.lookup<T>(*this);
1028 template <typename T>
1029 VariableP<T> variable (const string& name)
1031 return VariableP<T>(new Variable<T>(name));
1034 template <typename T>
1035 VariableP<T> bindExpression (const string& name, ExpandContext& ctx, const ExprP<T>& expr)
1037 VariableP<T> var = ctx.genSym<T>(name);
1038 ctx.addStatement(variableDeclaration(var, expr));
1042 /*--------------------------------------------------------------------*//*!
1043 * \brief Constant expression.
1045 * A constant is evaluated by rounding it to a set of possible values allowed
1046 * by the current floating point precision.
1047 *//*--------------------------------------------------------------------*/
1048 template <typename T>
1049 class Constant : public Expr<T>
1052 typedef typename Expr<T>::IVal IVal;
1054 Constant (const T& value) : m_value(value) {}
1057 void doPrintExpr (ostream& os) const { os << m_value; }
1058 IVal doEvaluate (const EvalContext&) const { return makeIVal(m_value); }
1064 template <typename T>
1065 ExprP<T> constant (const T& value)
1067 return exprP(new Constant<T>(value));
1070 //! Return a reference to a singleton void constant.
1071 const ExprP<Void>& voidP (void)
1073 static const ExprP<Void> singleton = constant(Void());
1078 /*--------------------------------------------------------------------*//*!
1079 * \brief Four-element tuple.
1081 * This is used for various things where we need one thing for each possible
1082 * function parameter. Currently the maximum supported number of parameters is
1084 *//*--------------------------------------------------------------------*/
1085 template <typename T0 = Void, typename T1 = Void, typename T2 = Void, typename T3 = Void>
1088 explicit Tuple4 (const T0 e0 = T0(),
1105 /*--------------------------------------------------------------------*//*!
1106 * \brief Function signature.
1108 * This is a purely compile-time structure used to bundle all types in a
1109 * function signature together. This makes passing the signature around in
1110 * templates easier, since we only need to take and pass a single Sig instead
1111 * of a bunch of parameter types and a return type.
1113 *//*--------------------------------------------------------------------*/
1114 template <typename R,
1115 typename P0 = Void, typename P1 = Void,
1116 typename P2 = Void, typename P3 = Void>
1124 typedef typename Traits<Ret>::IVal IRet;
1125 typedef typename Traits<Arg0>::IVal IArg0;
1126 typedef typename Traits<Arg1>::IVal IArg1;
1127 typedef typename Traits<Arg2>::IVal IArg2;
1128 typedef typename Traits<Arg3>::IVal IArg3;
1130 typedef Tuple4< const Arg0&, const Arg1&, const Arg2&, const Arg3&> Args;
1131 typedef Tuple4< const IArg0&, const IArg1&, const IArg2&, const IArg3&> IArgs;
1132 typedef Tuple4< ExprP<Arg0>, ExprP<Arg1>, ExprP<Arg2>, ExprP<Arg3> > ArgExprs;
1135 typedef vector<const ExprBase*> BaseArgExprs;
1137 /*--------------------------------------------------------------------*//*!
1138 * \brief Type-independent operations for function objects.
1140 *//*--------------------------------------------------------------------*/
1144 virtual ~FuncBase (void) {}
1145 virtual string getName (void) const = 0;
1146 //! Name of extension that this function requires, or empty.
1147 virtual string getRequiredExtension (void) const { return ""; }
1148 virtual void print (ostream&,
1149 const BaseArgExprs&) const = 0;
1150 //! Index of output parameter, or -1 if none of the parameters is output.
1151 virtual int getOutParamIndex (void) const { return -1; }
1153 void printDefinition (ostream& os) const
1155 doPrintDefinition(os);
1158 void getUsedFuncs (FuncSet& dst) const
1160 this->doGetUsedFuncs(dst);
1164 virtual void doPrintDefinition (ostream& os) const = 0;
1165 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
1168 typedef Tuple4<string, string, string, string> ParamNames;
1170 /*--------------------------------------------------------------------*//*!
1171 * \brief Function objects.
1173 * Each Func object represents a GLSL function. It can be applied to interval
1174 * arguments, and it returns the an interval that is a conservative
1175 * approximation of the image of the GLSL function over the argument
1176 * intervals. That is, it is given a set of possible arguments and it returns
1177 * the set of possible values.
1179 *//*--------------------------------------------------------------------*/
1180 template <typename Sig_>
1181 class Func : public FuncBase
1185 typedef typename Sig::Ret Ret;
1186 typedef typename Sig::Arg0 Arg0;
1187 typedef typename Sig::Arg1 Arg1;
1188 typedef typename Sig::Arg2 Arg2;
1189 typedef typename Sig::Arg3 Arg3;
1190 typedef typename Sig::IRet IRet;
1191 typedef typename Sig::IArg0 IArg0;
1192 typedef typename Sig::IArg1 IArg1;
1193 typedef typename Sig::IArg2 IArg2;
1194 typedef typename Sig::IArg3 IArg3;
1195 typedef typename Sig::Args Args;
1196 typedef typename Sig::IArgs IArgs;
1197 typedef typename Sig::ArgExprs ArgExprs;
1199 void print (ostream& os,
1200 const BaseArgExprs& args) const
1202 this->doPrint(os, args);
1205 IRet apply (const EvalContext& ctx,
1206 const IArg0& arg0 = IArg0(),
1207 const IArg1& arg1 = IArg1(),
1208 const IArg2& arg2 = IArg2(),
1209 const IArg3& arg3 = IArg3()) const
1211 return this->applyArgs(ctx, IArgs(arg0, arg1, arg2, arg3));
1213 IRet applyArgs (const EvalContext& ctx,
1214 const IArgs& args) const
1216 return this->doApply(ctx, args);
1218 ExprP<Ret> operator() (const ExprP<Arg0>& arg0 = voidP(),
1219 const ExprP<Arg1>& arg1 = voidP(),
1220 const ExprP<Arg2>& arg2 = voidP(),
1221 const ExprP<Arg3>& arg3 = voidP()) const;
1223 const ParamNames& getParamNames (void) const
1225 return this->doGetParamNames();
1229 virtual IRet doApply (const EvalContext&,
1230 const IArgs&) const = 0;
1231 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1233 os << getName() << "(";
1235 if (isTypeValid<Arg0>())
1238 if (isTypeValid<Arg1>())
1239 os << ", " << *args[1];
1241 if (isTypeValid<Arg2>())
1242 os << ", " << *args[2];
1244 if (isTypeValid<Arg3>())
1245 os << ", " << *args[3];
1250 virtual const ParamNames& doGetParamNames (void) const
1252 static ParamNames names ("a", "b", "c", "d");
1257 template <typename Sig>
1258 class Apply : public Expr<typename Sig::Ret>
1261 typedef typename Sig::Ret Ret;
1262 typedef typename Sig::Arg0 Arg0;
1263 typedef typename Sig::Arg1 Arg1;
1264 typedef typename Sig::Arg2 Arg2;
1265 typedef typename Sig::Arg3 Arg3;
1266 typedef typename Expr<Ret>::Val Val;
1267 typedef typename Expr<Ret>::IVal IVal;
1268 typedef Func<Sig> ApplyFunc;
1269 typedef typename ApplyFunc::ArgExprs ArgExprs;
1271 Apply (const ApplyFunc& func,
1272 const ExprP<Arg0>& arg0 = voidP(),
1273 const ExprP<Arg1>& arg1 = voidP(),
1274 const ExprP<Arg2>& arg2 = voidP(),
1275 const ExprP<Arg3>& arg3 = voidP())
1277 m_args (arg0, arg1, arg2, arg3) {}
1279 Apply (const ApplyFunc& func,
1280 const ArgExprs& args)
1284 void doPrintExpr (ostream& os) const
1287 args.push_back(m_args.a.get());
1288 args.push_back(m_args.b.get());
1289 args.push_back(m_args.c.get());
1290 args.push_back(m_args.d.get());
1291 m_func.print(os, args);
1294 IVal doEvaluate (const EvalContext& ctx) const
1296 return m_func.apply(ctx,
1297 m_args.a->evaluate(ctx), m_args.b->evaluate(ctx),
1298 m_args.c->evaluate(ctx), m_args.d->evaluate(ctx));
1301 void doGetUsedFuncs (FuncSet& dst) const
1303 m_func.getUsedFuncs(dst);
1304 m_args.a->getUsedFuncs(dst);
1305 m_args.b->getUsedFuncs(dst);
1306 m_args.c->getUsedFuncs(dst);
1307 m_args.d->getUsedFuncs(dst);
1310 const ApplyFunc& m_func;
1314 template<typename T>
1315 class Alternatives : public Func<Signature<T, T, T> >
1318 typedef typename Alternatives::Sig Sig;
1321 typedef typename Alternatives::IRet IRet;
1322 typedef typename Alternatives::IArgs IArgs;
1324 virtual string getName (void) const { return "alternatives"; }
1325 virtual void doPrintDefinition (std::ostream&) const {}
1326 void doGetUsedFuncs (FuncSet&) const {}
1328 virtual IRet doApply (const EvalContext&, const IArgs& args) const
1330 return unionIVal<T>(args.a, args.b);
1333 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1335 os << "{" << *args[0] << " | " << *args[1] << "}";
1339 template <typename Sig>
1340 ExprP<typename Sig::Ret> createApply (const Func<Sig>& func,
1341 const typename Func<Sig>::ArgExprs& args)
1343 return exprP(new Apply<Sig>(func, args));
1346 template <typename Sig>
1347 ExprP<typename Sig::Ret> createApply (
1348 const Func<Sig>& func,
1349 const ExprP<typename Sig::Arg0>& arg0 = voidP(),
1350 const ExprP<typename Sig::Arg1>& arg1 = voidP(),
1351 const ExprP<typename Sig::Arg2>& arg2 = voidP(),
1352 const ExprP<typename Sig::Arg3>& arg3 = voidP())
1354 return exprP(new Apply<Sig>(func, arg0, arg1, arg2, arg3));
1357 template <typename Sig>
1358 ExprP<typename Sig::Ret> Func<Sig>::operator() (const ExprP<typename Sig::Arg0>& arg0,
1359 const ExprP<typename Sig::Arg1>& arg1,
1360 const ExprP<typename Sig::Arg2>& arg2,
1361 const ExprP<typename Sig::Arg3>& arg3) const
1363 return createApply(*this, arg0, arg1, arg2, arg3);
1366 template <typename F>
1367 ExprP<typename F::Ret> app (const ExprP<typename F::Arg0>& arg0 = voidP(),
1368 const ExprP<typename F::Arg1>& arg1 = voidP(),
1369 const ExprP<typename F::Arg2>& arg2 = voidP(),
1370 const ExprP<typename F::Arg3>& arg3 = voidP())
1372 return createApply(instance<F>(), arg0, arg1, arg2, arg3);
1375 template <typename F>
1376 typename F::IRet call (const EvalContext& ctx,
1377 const typename F::IArg0& arg0 = Void(),
1378 const typename F::IArg1& arg1 = Void(),
1379 const typename F::IArg2& arg2 = Void(),
1380 const typename F::IArg3& arg3 = Void())
1382 return instance<F>().apply(ctx, arg0, arg1, arg2, arg3);
1385 template <typename T>
1386 ExprP<T> alternatives (const ExprP<T>& arg0,
1387 const ExprP<T>& arg1)
1389 return createApply<typename Alternatives<T>::Sig>(instance<Alternatives<T> >(), arg0, arg1);
1392 template <typename Sig>
1393 class ApplyVar : public Apply<Sig>
1396 typedef typename Sig::Ret Ret;
1397 typedef typename Sig::Arg0 Arg0;
1398 typedef typename Sig::Arg1 Arg1;
1399 typedef typename Sig::Arg2 Arg2;
1400 typedef typename Sig::Arg3 Arg3;
1401 typedef typename Expr<Ret>::Val Val;
1402 typedef typename Expr<Ret>::IVal IVal;
1403 typedef Func<Sig> ApplyFunc;
1404 typedef typename ApplyFunc::ArgExprs ArgExprs;
1406 ApplyVar (const ApplyFunc& func,
1407 const VariableP<Arg0>& arg0,
1408 const VariableP<Arg1>& arg1,
1409 const VariableP<Arg2>& arg2,
1410 const VariableP<Arg3>& arg3)
1411 : Apply<Sig> (func, arg0, arg1, arg2, arg3) {}
1413 IVal doEvaluate (const EvalContext& ctx) const
1415 const Variable<Arg0>& var0 = static_cast<const Variable<Arg0>&>(*this->m_args.a);
1416 const Variable<Arg1>& var1 = static_cast<const Variable<Arg1>&>(*this->m_args.b);
1417 const Variable<Arg2>& var2 = static_cast<const Variable<Arg2>&>(*this->m_args.c);
1418 const Variable<Arg3>& var3 = static_cast<const Variable<Arg3>&>(*this->m_args.d);
1419 return this->m_func.apply(ctx,
1420 ctx.env.lookup(var0), ctx.env.lookup(var1),
1421 ctx.env.lookup(var2), ctx.env.lookup(var3));
1425 template <typename Sig>
1426 ExprP<typename Sig::Ret> applyVar (const Func<Sig>& func,
1427 const VariableP<typename Sig::Arg0>& arg0,
1428 const VariableP<typename Sig::Arg1>& arg1,
1429 const VariableP<typename Sig::Arg2>& arg2,
1430 const VariableP<typename Sig::Arg3>& arg3)
1432 return exprP(new ApplyVar<Sig>(func, arg0, arg1, arg2, arg3));
1435 template <typename Sig_>
1436 class DerivedFunc : public Func<Sig_>
1439 typedef typename DerivedFunc::ArgExprs ArgExprs;
1440 typedef typename DerivedFunc::IRet IRet;
1441 typedef typename DerivedFunc::IArgs IArgs;
1442 typedef typename DerivedFunc::Ret Ret;
1443 typedef typename DerivedFunc::Arg0 Arg0;
1444 typedef typename DerivedFunc::Arg1 Arg1;
1445 typedef typename DerivedFunc::Arg2 Arg2;
1446 typedef typename DerivedFunc::Arg3 Arg3;
1447 typedef typename DerivedFunc::IArg0 IArg0;
1448 typedef typename DerivedFunc::IArg1 IArg1;
1449 typedef typename DerivedFunc::IArg2 IArg2;
1450 typedef typename DerivedFunc::IArg3 IArg3;
1453 void doPrintDefinition (ostream& os) const
1455 const ParamNames& paramNames = this->getParamNames();
1459 os << dataTypeNameOf<Ret>() << " " << this->getName()
1461 if (isTypeValid<Arg0>())
1462 os << dataTypeNameOf<Arg0>() << " " << paramNames.a;
1463 if (isTypeValid<Arg1>())
1464 os << ", " << dataTypeNameOf<Arg1>() << " " << paramNames.b;
1465 if (isTypeValid<Arg2>())
1466 os << ", " << dataTypeNameOf<Arg2>() << " " << paramNames.c;
1467 if (isTypeValid<Arg3>())
1468 os << ", " << dataTypeNameOf<Arg3>() << " " << paramNames.d;
1471 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1473 os << "return " << *m_ret << ";\n";
1477 IRet doApply (const EvalContext& ctx,
1478 const IArgs& args) const
1481 IArgs& mutArgs = const_cast<IArgs&>(args);
1486 funEnv.bind(*m_var0, args.a);
1487 funEnv.bind(*m_var1, args.b);
1488 funEnv.bind(*m_var2, args.c);
1489 funEnv.bind(*m_var3, args.d);
1492 EvalContext funCtx(ctx.format, ctx.floatPrecision, funEnv, ctx.callDepth);
1494 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1495 m_body[ndx]->execute(funCtx);
1497 ret = m_ret->evaluate(funCtx);
1500 // \todo [lauri] Store references instead of values in environment
1501 const_cast<IArg0&>(mutArgs.a) = funEnv.lookup(*m_var0);
1502 const_cast<IArg1&>(mutArgs.b) = funEnv.lookup(*m_var1);
1503 const_cast<IArg2&>(mutArgs.c) = funEnv.lookup(*m_var2);
1504 const_cast<IArg3&>(mutArgs.d) = funEnv.lookup(*m_var3);
1509 void doGetUsedFuncs (FuncSet& dst) const
1512 if (dst.insert(this).second)
1514 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1515 m_body[ndx]->getUsedFuncs(dst);
1516 m_ret->getUsedFuncs(dst);
1520 virtual ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args_) const = 0;
1522 // These are transparently initialized when first needed. They cannot be
1523 // initialized in the constructor because they depend on the doExpand
1524 // method of the subclass.
1526 mutable VariableP<Arg0> m_var0;
1527 mutable VariableP<Arg1> m_var1;
1528 mutable VariableP<Arg2> m_var2;
1529 mutable VariableP<Arg3> m_var3;
1530 mutable vector<StatementP> m_body;
1531 mutable ExprP<Ret> m_ret;
1535 void initialize (void) const
1539 const ParamNames& paramNames = this->getParamNames();
1541 ExpandContext ctx (symCounter);
1544 args.a = m_var0 = variable<Arg0>(paramNames.a);
1545 args.b = m_var1 = variable<Arg1>(paramNames.b);
1546 args.c = m_var2 = variable<Arg2>(paramNames.c);
1547 args.d = m_var3 = variable<Arg3>(paramNames.d);
1549 m_ret = this->doExpand(ctx, args);
1550 m_body = ctx.getStatements();
1555 template <typename Sig>
1556 class PrimitiveFunc : public Func<Sig>
1559 typedef typename PrimitiveFunc::Ret Ret;
1560 typedef typename PrimitiveFunc::ArgExprs ArgExprs;
1563 void doPrintDefinition (ostream&) const {}
1564 void doGetUsedFuncs (FuncSet&) const {}
1567 template <typename T>
1568 class Cond : public PrimitiveFunc<Signature<T, bool, T, T> >
1571 typedef typename Cond::IArgs IArgs;
1572 typedef typename Cond::IRet IRet;
1574 string getName (void) const
1581 void doPrint (ostream& os, const BaseArgExprs& args) const
1583 os << "(" << *args[0] << " ? " << *args[1] << " : " << *args[2] << ")";
1586 IRet doApply (const EvalContext&, const IArgs& iargs)const
1590 if (iargs.a.contains(true))
1591 ret = unionIVal<T>(ret, iargs.b);
1593 if (iargs.a.contains(false))
1594 ret = unionIVal<T>(ret, iargs.c);
1600 template <typename T>
1601 class CompareOperator : public PrimitiveFunc<Signature<bool, T, T> >
1604 typedef typename CompareOperator::IArgs IArgs;
1605 typedef typename CompareOperator::IArg0 IArg0;
1606 typedef typename CompareOperator::IArg1 IArg1;
1607 typedef typename CompareOperator::IRet IRet;
1610 void doPrint (ostream& os, const BaseArgExprs& args) const
1612 os << "(" << *args[0] << getSymbol() << *args[1] << ")";
1615 Interval doApply (const EvalContext&, const IArgs& iargs) const
1617 const IArg0& arg0 = iargs.a;
1618 const IArg1& arg1 = iargs.b;
1621 if (canSucceed(arg0, arg1))
1623 if (canFail(arg0, arg1))
1629 virtual string getSymbol (void) const = 0;
1630 virtual bool canSucceed (const IArg0&, const IArg1&) const = 0;
1631 virtual bool canFail (const IArg0&, const IArg1&) const = 0;
1634 template <typename T>
1635 class LessThan : public CompareOperator<T>
1638 string getName (void) const { return "lessThan"; }
1641 string getSymbol (void) const { return "<"; }
1643 bool canSucceed (const Interval& a, const Interval& b) const
1645 return (a.lo() < b.hi());
1648 bool canFail (const Interval& a, const Interval& b) const
1650 return !(a.hi() < b.lo());
1654 template <typename T>
1655 ExprP<bool> operator< (const ExprP<T>& a, const ExprP<T>& b)
1657 return app<LessThan<T> >(a, b);
1660 template <typename T>
1661 ExprP<T> cond (const ExprP<bool>& test,
1662 const ExprP<T>& consequent,
1663 const ExprP<T>& alternative)
1665 return app<Cond<T> >(test, consequent, alternative);
1668 /*--------------------------------------------------------------------*//*!
1672 *//*--------------------------------------------------------------------*/
1674 class FloatFunc1 : public PrimitiveFunc<Signature<float, float> >
1677 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1679 return this->applyMonotone(ctx, iargs.a);
1682 Interval applyMonotone (const EvalContext& ctx, const Interval& iarg0) const
1686 TCU_INTERVAL_APPLY_MONOTONE1(ret, arg0, iarg0, val,
1687 TCU_SET_INTERVAL(val, point,
1688 point = this->applyPoint(ctx, arg0)));
1690 ret |= innerExtrema(ctx, iarg0);
1691 ret &= (this->getCodomain() | TCU_NAN);
1693 return ctx.format.convert(ret);
1696 virtual Interval innerExtrema (const EvalContext&, const Interval&) const
1698 return Interval(); // empty interval, i.e. no extrema
1701 virtual Interval applyPoint (const EvalContext& ctx, double arg0) const
1703 const double exact = this->applyExact(arg0);
1704 const double prec = this->precision(ctx, exact, arg0);
1706 return exact + Interval(-prec, prec);
1709 virtual double applyExact (double) const
1711 TCU_THROW(InternalError, "Cannot apply");
1714 virtual Interval getCodomain (void) const
1716 return Interval::unbounded(true);
1719 virtual double precision (const EvalContext& ctx, double, double) const = 0;
1722 class CFloatFunc1 : public FloatFunc1
1725 CFloatFunc1 (const string& name, DoubleFunc1& func)
1726 : m_name(name), m_func(func) {}
1728 string getName (void) const { return m_name; }
1731 double applyExact (double x) const { return m_func(x); }
1733 const string m_name;
1734 DoubleFunc1& m_func;
1737 class FloatFunc2 : public PrimitiveFunc<Signature<float, float, float> >
1740 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1742 return this->applyMonotone(ctx, iargs.a, iargs.b);
1745 Interval applyMonotone (const EvalContext& ctx,
1747 const Interval& yi) const
1751 TCU_INTERVAL_APPLY_MONOTONE2(reti, x, xi, y, yi, ret,
1752 TCU_SET_INTERVAL(ret, point,
1753 point = this->applyPoint(ctx, x, y)));
1754 reti |= innerExtrema(ctx, xi, yi);
1755 reti &= (this->getCodomain() | TCU_NAN);
1757 return ctx.format.convert(reti);
1760 virtual Interval innerExtrema (const EvalContext&,
1762 const Interval&) const
1764 return Interval(); // empty interval, i.e. no extrema
1767 virtual Interval applyPoint (const EvalContext& ctx,
1771 const double exact = this->applyExact(x, y);
1772 const double prec = this->precision(ctx, exact, x, y);
1774 return exact + Interval(-prec, prec);
1777 virtual double applyExact (double, double) const
1779 TCU_THROW(InternalError, "Cannot apply");
1782 virtual Interval getCodomain (void) const
1784 return Interval::unbounded(true);
1787 virtual double precision (const EvalContext& ctx,
1790 double y) const = 0;
1793 class CFloatFunc2 : public FloatFunc2
1796 CFloatFunc2 (const string& name,
1803 string getName (void) const { return m_name; }
1806 double applyExact (double x, double y) const { return m_func(x, y); }
1808 const string m_name;
1809 DoubleFunc2& m_func;
1812 class InfixOperator : public FloatFunc2
1815 virtual string getSymbol (void) const = 0;
1817 void doPrint (ostream& os, const BaseArgExprs& args) const
1819 os << "(" << *args[0] << " " << getSymbol() << " " << *args[1] << ")";
1822 Interval applyPoint (const EvalContext& ctx,
1826 const double exact = this->applyExact(x, y);
1828 // Allow either representable number on both sides of the exact value,
1829 // but require exactly representable values to be preserved.
1830 return ctx.format.roundOut(exact, !deIsInf(x) && !deIsInf(y));
1833 double precision (const EvalContext&, double, double, double) const
1839 class FloatFunc3 : public PrimitiveFunc<Signature<float, float, float, float> >
1842 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1844 return this->applyMonotone(ctx, iargs.a, iargs.b, iargs.c);
1847 Interval applyMonotone (const EvalContext& ctx,
1850 const Interval& zi) const
1853 TCU_INTERVAL_APPLY_MONOTONE3(reti, x, xi, y, yi, z, zi, ret,
1854 TCU_SET_INTERVAL(ret, point,
1855 point = this->applyPoint(ctx, x, y, z)));
1856 return ctx.format.convert(reti);
1859 virtual Interval applyPoint (const EvalContext& ctx,
1864 const double exact = this->applyExact(x, y, z);
1865 const double prec = this->precision(ctx, exact, x, y, z);
1866 return exact + Interval(-prec, prec);
1869 virtual double applyExact (double, double, double) const
1871 TCU_THROW(InternalError, "Cannot apply");
1874 virtual double precision (const EvalContext& ctx,
1878 double z) const = 0;
1881 // We define syntactic sugar functions for expression constructors. Since
1882 // these have the same names as ordinary mathematical operations (sin, log
1883 // etc.), it's better to give them a dedicated namespace.
1887 using namespace tcu;
1889 class Add : public InfixOperator
1892 string getName (void) const { return "add"; }
1893 string getSymbol (void) const { return "+"; }
1895 Interval doApply (const EvalContext& ctx,
1896 const IArgs& iargs) const
1898 // Fast-path for common case
1899 if (iargs.a.isOrdinary() && iargs.b.isOrdinary())
1902 TCU_SET_INTERVAL_BOUNDS(ret, sum,
1903 sum = iargs.a.lo() + iargs.b.lo(),
1904 sum = iargs.a.hi() + iargs.b.hi());
1905 return ctx.format.convert(ctx.format.roundOut(ret, true));
1907 return this->applyMonotone(ctx, iargs.a, iargs.b);
1911 double applyExact (double x, double y) const { return x + y; }
1914 class Mul : public InfixOperator
1917 string getName (void) const { return "mul"; }
1918 string getSymbol (void) const { return "*"; }
1920 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1922 Interval a = iargs.a;
1923 Interval b = iargs.b;
1925 // Fast-path for common case
1926 if (a.isOrdinary() && b.isOrdinary())
1934 if (a.lo() >= 0 && b.lo() >= 0)
1936 TCU_SET_INTERVAL_BOUNDS(ret, prod,
1937 prod = iargs.a.lo() * iargs.b.lo(),
1938 prod = iargs.a.hi() * iargs.b.hi());
1939 return ctx.format.convert(ctx.format.roundOut(ret, true));
1941 if (a.lo() >= 0 && b.hi() <= 0)
1943 TCU_SET_INTERVAL_BOUNDS(ret, prod,
1944 prod = iargs.a.hi() * iargs.b.lo(),
1945 prod = iargs.a.lo() * iargs.b.hi());
1946 return ctx.format.convert(ctx.format.roundOut(ret, true));
1949 return this->applyMonotone(ctx, iargs.a, iargs.b);
1953 double applyExact (double x, double y) const { return x * y; }
1955 Interval innerExtrema(const EvalContext&, const Interval& xi, const Interval& yi) const
1957 if (((xi.contains(-TCU_INFINITY) || xi.contains(TCU_INFINITY)) && yi.contains(0.0)) ||
1958 ((yi.contains(-TCU_INFINITY) || yi.contains(TCU_INFINITY)) && xi.contains(0.0)))
1959 return Interval(TCU_NAN);
1965 class Sub : public InfixOperator
1968 string getName (void) const { return "sub"; }
1969 string getSymbol (void) const { return "-"; }
1971 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1973 // Fast-path for common case
1974 if (iargs.a.isOrdinary() && iargs.b.isOrdinary())
1978 TCU_SET_INTERVAL_BOUNDS(ret, diff,
1979 diff = iargs.a.lo() - iargs.b.hi(),
1980 diff = iargs.a.hi() - iargs.b.lo());
1981 return ctx.format.convert(ctx.format.roundOut(ret, true));
1986 return this->applyMonotone(ctx, iargs.a, iargs.b);
1991 double applyExact (double x, double y) const { return x - y; }
1994 class Negate : public FloatFunc1
1997 string getName (void) const { return "_negate"; }
1998 void doPrint (ostream& os, const BaseArgExprs& args) const { os << "-" << *args[0]; }
2001 double precision (const EvalContext&, double, double) const { return 0.0; }
2002 double applyExact (double x) const { return -x; }
2005 class Div : public InfixOperator
2008 string getName (void) const { return "div"; }
2011 string getSymbol (void) const { return "/"; }
2013 Interval innerExtrema (const EvalContext&,
2014 const Interval& nom,
2015 const Interval& den) const
2019 if (den.contains(0.0))
2021 if (nom.contains(0.0))
2024 if (nom.lo() < 0.0 || nom.hi() > 0.0)
2025 ret |= Interval::unbounded();
2031 double applyExact (double x, double y) const { return x / y; }
2033 Interval applyPoint (const EvalContext& ctx, double x, double y) const
2035 Interval ret = FloatFunc2::applyPoint(ctx, x, y);
2037 if (!deIsInf(x) && !deIsInf(y) && y != 0.0)
2039 const Interval dst = ctx.format.convert(ret);
2040 if (dst.contains(-TCU_INFINITY)) ret |= -ctx.format.getMaxValue();
2041 if (dst.contains(+TCU_INFINITY)) ret |= +ctx.format.getMaxValue();
2047 double precision (const EvalContext& ctx, double ret, double, double den) const
2049 const FloatFormat& fmt = ctx.format;
2051 // \todo [2014-03-05 lauri] Check that the limits in GLSL 3.10 are actually correct.
2052 // For now, we assume that division's precision is 2.5 ULP when the value is within
2053 // [2^MINEXP, 2^MAXEXP-1]
2056 return 0.0; // Result must be exactly inf
2057 else if (de::inBounds(deAbs(den),
2058 deLdExp(1.0, fmt.getMinExp()),
2059 deLdExp(1.0, fmt.getMaxExp() - 1)))
2060 return fmt.ulp(ret, 2.5);
2062 return TCU_INFINITY; // Can be any number, but must be a number.
2066 class InverseSqrt : public FloatFunc1
2069 string getName (void) const { return "inversesqrt"; }
2072 double applyExact (double x) const { return 1.0 / deSqrt(x); }
2074 double precision (const EvalContext& ctx, double ret, double x) const
2076 return x <= 0 ? TCU_NAN : ctx.format.ulp(ret, 2.0);
2079 Interval getCodomain (void) const
2081 return Interval(0.0, TCU_INFINITY);
2085 class ExpFunc : public CFloatFunc1
2088 ExpFunc (const string& name, DoubleFunc1& func)
2089 : CFloatFunc1(name, func) {}
2091 double precision (const EvalContext& ctx, double ret, double x) const
2093 switch (ctx.floatPrecision)
2095 case glu::PRECISION_HIGHP:
2096 return ctx.format.ulp(ret, 3.0 + 2.0 * deAbs(x));
2097 case glu::PRECISION_MEDIUMP:
2098 return ctx.format.ulp(ret, 2.0 + 2.0 * deAbs(x));
2099 case glu::PRECISION_LOWP:
2100 return ctx.format.ulp(ret, 2.0);
2102 DE_FATAL("Impossible");
2107 Interval getCodomain (void) const
2109 return Interval(0.0, TCU_INFINITY);
2113 class Exp2 : public ExpFunc { public: Exp2 (void) : ExpFunc("exp2", deExp2) {} };
2114 class Exp : public ExpFunc { public: Exp (void) : ExpFunc("exp", deExp) {} };
2116 ExprP<float> exp2 (const ExprP<float>& x) { return app<Exp2>(x); }
2117 ExprP<float> exp (const ExprP<float>& x) { return app<Exp>(x); }
2119 class LogFunc : public CFloatFunc1
2122 LogFunc (const string& name, DoubleFunc1& func)
2123 : CFloatFunc1(name, func) {}
2126 double precision (const EvalContext& ctx, double ret, double x) const
2131 switch (ctx.floatPrecision)
2133 case glu::PRECISION_HIGHP:
2134 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -21) : ctx.format.ulp(ret, 3.0);
2135 case glu::PRECISION_MEDIUMP:
2136 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -7) : ctx.format.ulp(ret, 2.0);
2137 case glu::PRECISION_LOWP:
2138 return ctx.format.ulp(ret, 2.0);
2140 DE_FATAL("Impossible");
2147 class Log2 : public LogFunc { public: Log2 (void) : LogFunc("log2", deLog2) {} };
2148 class Log : public LogFunc { public: Log (void) : LogFunc("log", deLog) {} };
2150 ExprP<float> log2 (const ExprP<float>& x) { return app<Log2>(x); }
2151 ExprP<float> log (const ExprP<float>& x) { return app<Log>(x); }
2153 #define DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0) \
2154 ExprP<TRET> NAME (const ExprP<T0>& arg0) { return app<CLASS>(arg0); }
2156 #define DEFINE_DERIVED1(CLASS, TRET, NAME, T0, ARG0, EXPANSION) \
2157 class CLASS : public DerivedFunc<Signature<TRET, T0> > /* NOLINT(CLASS) */ \
2160 string getName (void) const { return #NAME; } \
2163 ExprP<TRET> doExpand (ExpandContext&, \
2164 const CLASS::ArgExprs& args_) const \
2166 const ExprP<float>& (ARG0) = args_.a; \
2170 DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0)
2172 #define DEFINE_DERIVED_FLOAT1(CLASS, NAME, ARG0, EXPANSION) \
2173 DEFINE_DERIVED1(CLASS, float, NAME, float, ARG0, EXPANSION)
2175 #define DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1) \
2176 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1) \
2178 return app<CLASS>(arg0, arg1); \
2181 #define DEFINE_DERIVED2(CLASS, TRET, NAME, T0, Arg0, T1, Arg1, EXPANSION) \
2182 class CLASS : public DerivedFunc<Signature<TRET, T0, T1> > /* NOLINT(CLASS) */ \
2185 string getName (void) const { return #NAME; } \
2188 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2190 const ExprP<T0>& (Arg0) = args_.a; \
2191 const ExprP<T1>& (Arg1) = args_.b; \
2195 DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1)
2197 #define DEFINE_DERIVED_FLOAT2(CLASS, NAME, Arg0, Arg1, EXPANSION) \
2198 DEFINE_DERIVED2(CLASS, float, NAME, float, Arg0, float, Arg1, EXPANSION)
2200 #define DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2) \
2201 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, const ExprP<T2>& arg2) \
2203 return app<CLASS>(arg0, arg1, arg2); \
2206 #define DEFINE_DERIVED3(CLASS, TRET, NAME, T0, ARG0, T1, ARG1, T2, ARG2, EXPANSION) \
2207 class CLASS : public DerivedFunc<Signature<TRET, T0, T1, T2> > /* NOLINT(CLASS) */ \
2210 string getName (void) const { return #NAME; } \
2213 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2215 const ExprP<T0>& (ARG0) = args_.a; \
2216 const ExprP<T1>& (ARG1) = args_.b; \
2217 const ExprP<T2>& (ARG2) = args_.c; \
2221 DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2)
2223 #define DEFINE_DERIVED_FLOAT3(CLASS, NAME, ARG0, ARG1, ARG2, EXPANSION) \
2224 DEFINE_DERIVED3(CLASS, float, NAME, float, ARG0, float, ARG1, float, ARG2, EXPANSION)
2226 #define DEFINE_CONSTRUCTOR4(CLASS, TRET, NAME, T0, T1, T2, T3) \
2227 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, \
2228 const ExprP<T2>& arg2, const ExprP<T3>& arg3) \
2230 return app<CLASS>(arg0, arg1, arg2, arg3); \
2233 DEFINE_DERIVED_FLOAT1(Sqrt, sqrt, x, constant(1.0f) / app<InverseSqrt>(x));
2234 DEFINE_DERIVED_FLOAT2(Pow, pow, x, y, exp2(y * log2(x)));
2235 DEFINE_DERIVED_FLOAT1(Radians, radians, d, (constant(DE_PI) / constant(180.0f)) * d);
2236 DEFINE_DERIVED_FLOAT1(Degrees, degrees, r, (constant(180.0f) / constant(DE_PI)) * r);
2238 class TrigFunc : public CFloatFunc1
2241 TrigFunc (const string& name,
2243 const Interval& loEx,
2244 const Interval& hiEx)
2245 : CFloatFunc1 (name, func)
2246 , m_loExtremum (loEx)
2247 , m_hiExtremum (hiEx) {}
2250 Interval innerExtrema (const EvalContext&, const Interval& angle) const
2252 const double lo = angle.lo();
2253 const double hi = angle.hi();
2254 const int loSlope = doGetSlope(lo);
2255 const int hiSlope = doGetSlope(hi);
2257 // Detect the high and low values the function can take between the
2258 // interval endpoints.
2259 if (angle.length() >= 2.0 * DE_PI_DOUBLE)
2261 // The interval is longer than a full cycle, so it must get all possible values.
2262 return m_hiExtremum | m_loExtremum;
2264 else if (loSlope == 1 && hiSlope == -1)
2266 // The slope can change from positive to negative only at the maximum value.
2267 return m_hiExtremum;
2269 else if (loSlope == -1 && hiSlope == 1)
2271 // The slope can change from negative to positive only at the maximum value.
2272 return m_loExtremum;
2274 else if (loSlope == hiSlope &&
2275 deIntSign(applyExact(hi) - applyExact(lo)) * loSlope == -1)
2277 // The slope has changed twice between the endpoints, so both extrema are included.
2278 return m_hiExtremum | m_loExtremum;
2284 Interval getCodomain (void) const
2286 // Ensure that result is always within [-1, 1], or NaN (for +-inf)
2287 return Interval(-1.0, 1.0) | TCU_NAN;
2290 double precision (const EvalContext& ctx, double ret, double arg) const
2292 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2294 // Use precision from OpenCL fast relaxed math
2295 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2297 return deLdExp(1.0, -11);
2301 // "larger otherwise", let's pick |x| * 2^-12 , which is slightly over
2302 // 2^-11 at x == pi.
2303 return deLdExp(deAbs(arg), -12);
2306 else if (ctx.floatPrecision == glu::PRECISION_MEDIUMP)
2308 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2310 // from OpenCL half-float extension specification
2311 return ctx.format.ulp(ret, 2.0);
2315 // |x| * 2^-10, slightly larger than 2 ULP at x == pi
2316 return deLdExp(deAbs(arg), -10);
2321 DE_ASSERT(ctx.floatPrecision == glu::PRECISION_LOWP);
2323 // from OpenCL half-float extension specification
2324 return ctx.format.ulp(ret, 2.0);
2328 virtual int doGetSlope (double angle) const = 0;
2330 Interval m_loExtremum;
2331 Interval m_hiExtremum;
2334 class Sin : public TrigFunc
2337 Sin (void) : TrigFunc("sin", deSin, -1.0, 1.0) {}
2340 int doGetSlope (double angle) const { return deIntSign(deCos(angle)); }
2343 ExprP<float> sin (const ExprP<float>& x) { return app<Sin>(x); }
2345 class Cos : public TrigFunc
2348 Cos (void) : TrigFunc("cos", deCos, -1.0, 1.0) {}
2351 int doGetSlope (double angle) const { return -deIntSign(deSin(angle)); }
2354 ExprP<float> cos (const ExprP<float>& x) { return app<Cos>(x); }
2356 DEFINE_DERIVED_FLOAT1(Tan, tan, x, sin(x) * (constant(1.0f) / cos(x)));
2358 class ASin : public CFloatFunc1
2361 ASin (void) : CFloatFunc1("asin", deAsin) {}
2364 double precision (const EvalContext& ctx, double, double x) const
2366 if (!de::inBounds(x, -1.0, 1.0))
2369 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2371 // Absolute error of 2^-11
2372 return deLdExp(1.0, -11);
2376 // Absolute error of 2^-8
2377 return deLdExp(1.0, -8);
2383 class ArcTrigFunc : public CFloatFunc1
2386 ArcTrigFunc (const string& name,
2388 double precisionULPs,
2389 const Interval& domain,
2390 const Interval& codomain)
2391 : CFloatFunc1 (name, func)
2392 , m_precision (precisionULPs)
2394 , m_codomain (codomain) {}
2397 double precision (const EvalContext& ctx, double ret, double x) const
2399 if (!m_domain.contains(x))
2402 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2404 // Use OpenCL's fast relaxed math precision
2405 return ctx.format.ulp(ret, m_precision);
2409 // Use OpenCL half-float spec
2410 return ctx.format.ulp(ret, 2.0);
2414 // We could implement getCodomain with m_codomain, but choose not to,
2415 // because it seems too strict with trascendental constants like pi.
2417 const double m_precision;
2418 const Interval m_domain;
2419 const Interval m_codomain;
2422 class ACos : public ArcTrigFunc
2425 ACos (void) : ArcTrigFunc("acos", deAcos, 4096.0,
2426 Interval(-1.0, 1.0),
2427 Interval(0.0, DE_PI_DOUBLE)) {}
2430 class ATan : public ArcTrigFunc
2433 ATan (void) : ArcTrigFunc("atan", deAtanOver, 4096.0,
2434 Interval::unbounded(),
2435 Interval(-DE_PI_DOUBLE * 0.5, DE_PI_DOUBLE * 0.5)) {}
2438 class ATan2 : public CFloatFunc2
2441 ATan2 (void) : CFloatFunc2 ("atan", deAtan2) {}
2444 Interval innerExtrema (const EvalContext& ctx,
2446 const Interval& xi) const
2450 if (yi.contains(0.0))
2452 if (xi.contains(0.0))
2454 if (xi.intersects(Interval(-TCU_INFINITY, 0.0)))
2455 ret |= Interval(-DE_PI_DOUBLE, DE_PI_DOUBLE);
2458 if (ctx.format.hasInf() != YES && (!yi.isFinite() || !xi.isFinite()))
2460 // Infinities may not be supported, allow anything, including NaN
2467 double precision (const EvalContext& ctx, double ret, double, double) const
2469 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2470 return ctx.format.ulp(ret, 4096.0);
2472 return ctx.format.ulp(ret, 2.0);
2475 // Codomain could be [-pi, pi], but that would probably be too strict.
2478 DEFINE_DERIVED_FLOAT1(Sinh, sinh, x, (exp(x) - exp(-x)) / constant(2.0f));
2479 DEFINE_DERIVED_FLOAT1(Cosh, cosh, x, (exp(x) + exp(-x)) / constant(2.0f));
2480 DEFINE_DERIVED_FLOAT1(Tanh, tanh, x, sinh(x) / cosh(x));
2482 // These are not defined as derived forms in the GLSL ES spec, but
2483 // that gives us a reasonable precision.
2484 DEFINE_DERIVED_FLOAT1(ASinh, asinh, x, log(x + sqrt(x * x + constant(1.0f))));
2485 DEFINE_DERIVED_FLOAT1(ACosh, acosh, x, log(x + sqrt(alternatives((x + constant(1.0f)) * (x - constant(1.0f)),
2486 (x*x - constant(1.0f))))));
2487 DEFINE_DERIVED_FLOAT1(ATanh, atanh, x, constant(0.5f) * log((constant(1.0f) + x) /
2488 (constant(1.0f) - x)));
2490 template <typename T>
2491 class GetComponent : public PrimitiveFunc<Signature<typename T::Element, T, int> >
2494 typedef typename GetComponent::IRet IRet;
2496 string getName (void) const { return "_getComponent"; }
2498 void print (ostream& os,
2499 const BaseArgExprs& args) const
2501 os << *args[0] << "[" << *args[1] << "]";
2505 IRet doApply (const EvalContext&,
2506 const typename GetComponent::IArgs& iargs) const
2510 for (int compNdx = 0; compNdx < T::SIZE; ++compNdx)
2512 if (iargs.b.contains(compNdx))
2513 ret = unionIVal<typename T::Element>(ret, iargs.a[compNdx]);
2521 template <typename T>
2522 ExprP<typename T::Element> getComponent (const ExprP<T>& container, int ndx)
2524 DE_ASSERT(0 <= ndx && ndx < T::SIZE);
2525 return app<GetComponent<T> >(container, constant(ndx));
2528 template <typename T> string vecNamePrefix (void);
2529 template <> string vecNamePrefix<float> (void) { return ""; }
2530 template <> string vecNamePrefix<int> (void) { return "i"; }
2531 template <> string vecNamePrefix<bool> (void) { return "b"; }
2533 template <typename T, int Size>
2534 string vecName (void) { return vecNamePrefix<T>() + "vec" + de::toString(Size); }
2536 template <typename T, int Size> class GenVec;
2538 template <typename T>
2539 class GenVec<T, 1> : public DerivedFunc<Signature<T, T> >
2542 typedef typename GenVec<T, 1>::ArgExprs ArgExprs;
2544 string getName (void) const
2546 return "_" + vecName<T, 1>();
2551 ExprP<T> doExpand (ExpandContext&, const ArgExprs& args) const { return args.a; }
2554 template <typename T>
2555 class GenVec<T, 2> : public PrimitiveFunc<Signature<Vector<T, 2>, T, T> >
2558 typedef typename GenVec::IRet IRet;
2559 typedef typename GenVec::IArgs IArgs;
2561 string getName (void) const
2563 return vecName<T, 2>();
2567 IRet doApply (const EvalContext&, const IArgs& iargs) const
2569 return IRet(iargs.a, iargs.b);
2573 template <typename T>
2574 class GenVec<T, 3> : public PrimitiveFunc<Signature<Vector<T, 3>, T, T, T> >
2577 typedef typename GenVec::IRet IRet;
2578 typedef typename GenVec::IArgs IArgs;
2580 string getName (void) const
2582 return vecName<T, 3>();
2586 IRet doApply (const EvalContext&, const IArgs& iargs) const
2588 return IRet(iargs.a, iargs.b, iargs.c);
2592 template <typename T>
2593 class GenVec<T, 4> : public PrimitiveFunc<Signature<Vector<T, 4>, T, T, T, T> >
2596 typedef typename GenVec::IRet IRet;
2597 typedef typename GenVec::IArgs IArgs;
2599 string getName (void) const { return vecName<T, 4>(); }
2602 IRet doApply (const EvalContext&, const IArgs& iargs) const
2604 return IRet(iargs.a, iargs.b, iargs.c, iargs.d);
2610 template <typename T, int Rows, int Columns>
2613 template <typename T, int Rows>
2614 class GenMat<T, Rows, 2> : public PrimitiveFunc<
2615 Signature<Matrix<T, Rows, 2>, Vector<T, Rows>, Vector<T, Rows> > >
2618 typedef typename GenMat::Ret Ret;
2619 typedef typename GenMat::IRet IRet;
2620 typedef typename GenMat::IArgs IArgs;
2622 string getName (void) const
2624 return dataTypeNameOf<Ret>();
2629 IRet doApply (const EvalContext&, const IArgs& iargs) const
2638 template <typename T, int Rows>
2639 class GenMat<T, Rows, 3> : public PrimitiveFunc<
2640 Signature<Matrix<T, Rows, 3>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
2643 typedef typename GenMat::Ret Ret;
2644 typedef typename GenMat::IRet IRet;
2645 typedef typename GenMat::IArgs IArgs;
2647 string getName (void) const
2649 return dataTypeNameOf<Ret>();
2654 IRet doApply (const EvalContext&, const IArgs& iargs) const
2664 template <typename T, int Rows>
2665 class GenMat<T, Rows, 4> : public PrimitiveFunc<
2666 Signature<Matrix<T, Rows, 4>,
2667 Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
2670 typedef typename GenMat::Ret Ret;
2671 typedef typename GenMat::IRet IRet;
2672 typedef typename GenMat::IArgs IArgs;
2674 string getName (void) const
2676 return dataTypeNameOf<Ret>();
2680 IRet doApply (const EvalContext&, const IArgs& iargs) const
2691 template <typename T, int Rows>
2692 ExprP<Matrix<T, Rows, 2> > mat2 (const ExprP<Vector<T, Rows> >& arg0,
2693 const ExprP<Vector<T, Rows> >& arg1)
2695 return app<GenMat<T, Rows, 2> >(arg0, arg1);
2698 template <typename T, int Rows>
2699 ExprP<Matrix<T, Rows, 3> > mat3 (const ExprP<Vector<T, Rows> >& arg0,
2700 const ExprP<Vector<T, Rows> >& arg1,
2701 const ExprP<Vector<T, Rows> >& arg2)
2703 return app<GenMat<T, Rows, 3> >(arg0, arg1, arg2);
2706 template <typename T, int Rows>
2707 ExprP<Matrix<T, Rows, 4> > mat4 (const ExprP<Vector<T, Rows> >& arg0,
2708 const ExprP<Vector<T, Rows> >& arg1,
2709 const ExprP<Vector<T, Rows> >& arg2,
2710 const ExprP<Vector<T, Rows> >& arg3)
2712 return app<GenMat<T, Rows, 4> >(arg0, arg1, arg2, arg3);
2716 template <int Rows, int Cols>
2717 class MatNeg : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
2718 Matrix<float, Rows, Cols> > >
2721 typedef typename MatNeg::IRet IRet;
2722 typedef typename MatNeg::IArgs IArgs;
2724 string getName (void) const
2730 void doPrint (ostream& os, const BaseArgExprs& args) const
2732 os << "-(" << *args[0] << ")";
2735 IRet doApply (const EvalContext&, const IArgs& iargs) const
2739 for (int col = 0; col < Cols; ++col)
2741 for (int row = 0; row < Rows; ++row)
2742 ret[col][row] = -iargs.a[col][row];
2749 template <typename T, typename Sig>
2750 class CompWiseFunc : public PrimitiveFunc<Sig>
2753 typedef Func<Signature<T, T, T> > ScalarFunc;
2755 string getName (void) const
2757 return doGetScalarFunc().getName();
2760 void doPrint (ostream& os,
2761 const BaseArgExprs& args) const
2763 doGetScalarFunc().print(os, args);
2767 const ScalarFunc& doGetScalarFunc (void) const = 0;
2770 template <int Rows, int Cols>
2771 class CompMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
2772 Matrix<float, Rows, Cols>,
2773 Matrix<float, Rows, Cols> > >
2776 typedef typename CompMatFuncBase::IRet IRet;
2777 typedef typename CompMatFuncBase::IArgs IArgs;
2781 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
2785 for (int col = 0; col < Cols; ++col)
2787 for (int row = 0; row < Rows; ++row)
2788 ret[col][row] = this->doGetScalarFunc().apply(ctx,
2797 template <typename F, int Rows, int Cols>
2798 class CompMatFunc : public CompMatFuncBase<Rows, Cols>
2801 const typename CompMatFunc::ScalarFunc& doGetScalarFunc (void) const
2803 return instance<F>();
2807 class ScalarMatrixCompMult : public Mul
2810 string getName (void) const
2812 return "matrixCompMult";
2815 void doPrint (ostream& os, const BaseArgExprs& args) const
2817 Func<Sig>::doPrint(os, args);
2821 template <int Rows, int Cols>
2822 class MatrixCompMult : public CompMatFunc<ScalarMatrixCompMult, Rows, Cols>
2826 template <int Rows, int Cols>
2827 class ScalarMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
2828 Matrix<float, Rows, Cols>,
2832 typedef typename ScalarMatFuncBase::IRet IRet;
2833 typedef typename ScalarMatFuncBase::IArgs IArgs;
2837 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
2841 for (int col = 0; col < Cols; ++col)
2843 for (int row = 0; row < Rows; ++row)
2844 ret[col][row] = this->doGetScalarFunc().apply(ctx, iargs.a[col][row], iargs.b);
2851 template <typename F, int Rows, int Cols>
2852 class ScalarMatFunc : public ScalarMatFuncBase<Rows, Cols>
2855 const typename ScalarMatFunc::ScalarFunc& doGetScalarFunc (void) const
2857 return instance<F>();
2861 template<typename T, int Size> struct GenXType;
2863 template<typename T>
2864 struct GenXType<T, 1>
2866 static ExprP<T> genXType (const ExprP<T>& x) { return x; }
2869 template<typename T>
2870 struct GenXType<T, 2>
2872 static ExprP<Vector<T, 2> > genXType (const ExprP<T>& x)
2874 return app<GenVec<T, 2> >(x, x);
2878 template<typename T>
2879 struct GenXType<T, 3>
2881 static ExprP<Vector<T, 3> > genXType (const ExprP<T>& x)
2883 return app<GenVec<T, 3> >(x, x, x);
2887 template<typename T>
2888 struct GenXType<T, 4>
2890 static ExprP<Vector<T, 4> > genXType (const ExprP<T>& x)
2892 return app<GenVec<T, 4> >(x, x, x, x);
2896 //! Returns an expression of vector of size `Size` (or scalar if Size == 1),
2897 //! with each element initialized with the expression `x`.
2898 template<typename T, int Size>
2899 ExprP<typename ContainerOf<T, Size>::Container> genXType (const ExprP<T>& x)
2901 return GenXType<T, Size>::genXType(x);
2904 typedef GenVec<float, 2> FloatVec2;
2905 DEFINE_CONSTRUCTOR2(FloatVec2, Vec2, vec2, float, float)
2907 typedef GenVec<float, 3> FloatVec3;
2908 DEFINE_CONSTRUCTOR3(FloatVec3, Vec3, vec3, float, float, float)
2910 typedef GenVec<float, 4> FloatVec4;
2911 DEFINE_CONSTRUCTOR4(FloatVec4, Vec4, vec4, float, float, float, float)
2914 class Dot : public DerivedFunc<Signature<float, Vector<float, Size>, Vector<float, Size> > >
2917 typedef typename Dot::ArgExprs ArgExprs;
2919 string getName (void) const
2925 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2927 ExprP<float> op[Size];
2928 // Precompute all products.
2929 for (int ndx = 0; ndx < Size; ++ndx)
2930 op[ndx] = args.a[ndx] * args.b[ndx];
2933 //Prepare an array of indices.
2934 for (int ndx = 0; ndx < Size; ++ndx)
2937 ExprP<float> res = op[0];
2938 // Compute the first dot alternative: SUM(a[i]*b[i]), i = 0 .. Size-1
2939 for (int ndx = 1; ndx < Size; ++ndx)
2940 res = res + op[ndx];
2942 // Generate all permutations of indices and
2943 // using a permutation compute a dot alternative.
2944 // Generates all possible variants fo summation of products in the dot product expansion expression.
2946 ExprP<float> alt = constant(0.0f);
2947 for (int ndx = 0; ndx < Size; ++ndx)
2948 alt = alt + op[idx[ndx]];
2949 res = alternatives(res, alt);
2950 } while (std::next_permutation(idx, idx + Size));
2957 class Dot<1> : public DerivedFunc<Signature<float, float, float> >
2960 string getName (void) const
2965 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2967 return args.a * args.b;
2972 ExprP<float> dot (const ExprP<Vector<float, Size> >& x, const ExprP<Vector<float, Size> >& y)
2974 return app<Dot<Size> >(x, y);
2977 ExprP<float> dot (const ExprP<float>& x, const ExprP<float>& y)
2979 return app<Dot<1> >(x, y);
2983 class Length : public DerivedFunc<
2984 Signature<float, typename ContainerOf<float, Size>::Container> >
2987 typedef typename Length::ArgExprs ArgExprs;
2989 string getName (void) const
2995 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2997 return sqrt(dot(args.a, args.a));
3002 ExprP<float> length (const ExprP<typename ContainerOf<float, Size>::Container>& x)
3004 return app<Length<Size> >(x);
3008 class Distance : public DerivedFunc<
3010 typename ContainerOf<float, Size>::Container,
3011 typename ContainerOf<float, Size>::Container> >
3014 typedef typename Distance::Ret Ret;
3015 typedef typename Distance::ArgExprs ArgExprs;
3017 string getName (void) const
3023 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3025 return length<Size>(args.a - args.b);
3031 class Cross : public DerivedFunc<Signature<Vec3, Vec3, Vec3> >
3034 string getName (void) const
3040 ExprP<Vec3> doExpand (ExpandContext&, const ArgExprs& x) const
3042 return vec3(x.a[1] * x.b[2] - x.b[1] * x.a[2],
3043 x.a[2] * x.b[0] - x.b[2] * x.a[0],
3044 x.a[0] * x.b[1] - x.b[0] * x.a[1]);
3048 DEFINE_CONSTRUCTOR2(Cross, Vec3, cross, Vec3, Vec3)
3051 class Normalize : public DerivedFunc<
3052 Signature<typename ContainerOf<float, Size>::Container,
3053 typename ContainerOf<float, Size>::Container> >
3056 typedef typename Normalize::Ret Ret;
3057 typedef typename Normalize::ArgExprs ArgExprs;
3059 string getName (void) const
3065 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3067 return args.a / length<Size>(args.a);
3072 class FaceForward : public DerivedFunc<
3073 Signature<typename ContainerOf<float, Size>::Container,
3074 typename ContainerOf<float, Size>::Container,
3075 typename ContainerOf<float, Size>::Container,
3076 typename ContainerOf<float, Size>::Container> >
3079 typedef typename FaceForward::Ret Ret;
3080 typedef typename FaceForward::ArgExprs ArgExprs;
3082 string getName (void) const
3084 return "faceforward";
3090 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3092 return cond(dot(args.c, args.b) < constant(0.0f), args.a, -args.a);
3096 template<int Size, typename Ret, typename Arg0, typename Arg1>
3099 static ExprP<Ret> apply (ExpandContext& ctx,
3100 const ExprP<Arg0>& i,
3101 const ExprP<Arg1>& n)
3103 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3105 return i - alternatives((n * dotNI) * constant(2.0f),
3106 n * (dotNI * constant(2.0f)));
3110 template<typename Ret, typename Arg0, typename Arg1>
3111 struct ApplyReflect<1, Ret, Arg0, Arg1>
3113 static ExprP<Ret> apply (ExpandContext&,
3114 const ExprP<Arg0>& i,
3115 const ExprP<Arg1>& n)
3117 return i - alternatives(alternatives((n * (n*i)) * constant(2.0f),
3118 n * ((n*i) * constant(2.0f))),
3119 (n * n) * (i * constant(2.0f)));
3124 class Reflect : public DerivedFunc<
3125 Signature<typename ContainerOf<float, Size>::Container,
3126 typename ContainerOf<float, Size>::Container,
3127 typename ContainerOf<float, Size>::Container> >
3130 typedef typename Reflect::Ret Ret;
3131 typedef typename Reflect::Arg0 Arg0;
3132 typedef typename Reflect::Arg1 Arg1;
3133 typedef typename Reflect::ArgExprs ArgExprs;
3135 string getName (void) const
3141 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3143 const ExprP<Arg0>& i = args.a;
3144 const ExprP<Arg1>& n = args.b;
3146 return ApplyReflect<Size, Ret, Arg0, Arg1>::apply(ctx, i, n);
3151 class Refract : public DerivedFunc<
3152 Signature<typename ContainerOf<float, Size>::Container,
3153 typename ContainerOf<float, Size>::Container,
3154 typename ContainerOf<float, Size>::Container,
3158 typedef typename Refract::Ret Ret;
3159 typedef typename Refract::Arg0 Arg0;
3160 typedef typename Refract::Arg1 Arg1;
3161 typedef typename Refract::ArgExprs ArgExprs;
3163 string getName (void) const
3169 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3171 const ExprP<Arg0>& i = args.a;
3172 const ExprP<Arg1>& n = args.b;
3173 const ExprP<float>& eta = args.c;
3174 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3175 const ExprP<float> k1 = bindExpression("k1", ctx, constant(1.0f) - eta * eta *
3176 (constant(1.0f) - dotNI * dotNI));
3178 const ExprP<float> k2 = bindExpression("k2", ctx,
3179 (((dotNI * (-dotNI)) + constant(1.0f)) * eta)
3180 * (-eta) + constant(1.0f));
3181 const ExprP<float> k = bindExpression("k", ctx, alternatives(k1, k2));
3183 return cond(k < constant(0.0f),
3184 genXType<float, Size>(constant(0.0f)),
3185 i * eta - n * (eta * dotNI + sqrt(k)));
3189 class PreciseFunc1 : public CFloatFunc1
3192 PreciseFunc1 (const string& name, DoubleFunc1& func) : CFloatFunc1(name, func) {}
3194 double precision (const EvalContext&, double, double) const { return 0.0; }
3197 class Abs : public PreciseFunc1
3200 Abs (void) : PreciseFunc1("abs", deAbs) {}
3203 class Sign : public PreciseFunc1
3206 Sign (void) : PreciseFunc1("sign", deSign) {}
3209 class Floor : public PreciseFunc1
3212 Floor (void) : PreciseFunc1("floor", deFloor) {}
3215 class Trunc : public PreciseFunc1
3218 Trunc (void) : PreciseFunc1("trunc", deTrunc) {}
3221 class Round : public FloatFunc1
3224 string getName (void) const { return "round"; }
3227 Interval applyPoint (const EvalContext&, double x) const
3229 double truncated = 0.0;
3230 const double fract = deModf(x, &truncated);
3233 if (fabs(fract) <= 0.5)
3235 if (fabs(fract) >= 0.5)
3236 ret |= truncated + deSign(fract);
3241 double precision (const EvalContext&, double, double) const { return 0.0; }
3244 class RoundEven : public PreciseFunc1
3247 RoundEven (void) : PreciseFunc1("roundEven", deRoundEven) {}
3250 class Ceil : public PreciseFunc1
3253 Ceil (void) : PreciseFunc1("ceil", deCeil) {}
3256 DEFINE_DERIVED_FLOAT1(Fract, fract, x, x - app<Floor>(x));
3258 class PreciseFunc2 : public CFloatFunc2
3261 PreciseFunc2 (const string& name, DoubleFunc2& func) : CFloatFunc2(name, func) {}
3263 double precision (const EvalContext&, double, double, double) const { return 0.0; }
3266 DEFINE_DERIVED_FLOAT2(Mod, mod, x, y, x - y * app<Floor>(x / y));
3268 class Modf : public PrimitiveFunc<Signature<float, float, float> >
3271 string getName (void) const
3277 IRet doApply (const EvalContext&, const IArgs& iargs) const
3280 Interval& wholeIV = const_cast<Interval&>(iargs.b);
3283 TCU_INTERVAL_APPLY_MONOTONE1(fracIV, x, iargs.a, frac, frac = deModf(x, &intPart));
3284 TCU_INTERVAL_APPLY_MONOTONE1(wholeIV, x, iargs.a, whole,
3285 deModf(x, &intPart); whole = intPart);
3287 if (!iargs.a.isFinite())
3289 // Behavior on modf(Inf) not well-defined, allow anything as a fractional part
3290 // See Khronos bug 13907
3297 int getOutParamIndex (void) const
3303 int compare(const EvalContext& ctx, double x, double y)
3305 if (ctx.format.hasSubnormal() != tcu::YES)
3307 const int minExp = ctx.format.getMinExp();
3308 const int fractionBits = ctx.format.getFractionBits();
3309 const double minQuantum = deLdExp(1.0f, minExp - fractionBits);
3310 const double minNormalized = deLdExp(1.0f, minExp);
3311 const double maxSubnormal = minNormalized - minQuantum;
3312 const double minSubnormal = -maxSubnormal;
3314 if (minSubnormal <= x && x <= maxSubnormal &&
3315 minSubnormal <= y && y <= maxSubnormal)
3326 class MinMaxFunc : public FloatFunc2
3329 MinMaxFunc (const string& name,
3336 string getName (void) const { return m_name; }
3339 Interval applyPoint(const EvalContext& ctx, double x, double y) const
3341 const int cmp = compare(ctx, x, y) * m_sign;
3348 // An implementation without subnormals may not be able to distinguish
3349 // between x and y even when they're not equal in host arithmetic.
3350 return Interval(x, y);
3353 double precision (const EvalContext&, double, double, double) const
3358 const string m_name;
3362 class Min : public MinMaxFunc { public: Min (void) : MinMaxFunc("min", -1) {} };
3363 class Max : public MinMaxFunc { public: Max (void) : MinMaxFunc("max", 1) {} };
3365 class Clamp : public FloatFunc3
3368 string getName (void) const { return "clamp"; }
3371 Interval applyPoint(const EvalContext& ctx, double x, double minVal, double maxVal) const
3373 if (minVal > maxVal)
3376 const int cmpMin = compare(ctx, x, minVal);
3377 const int cmpMax = compare(ctx, x, maxVal);
3378 const int cmpMinMax = compare(ctx, minVal, maxVal);
3384 return Interval(minVal, maxVal);
3390 return Interval(minVal, maxVal);
3393 Interval result = x;
3401 double precision (const EvalContext&, double, double, double minVal, double maxVal) const
3403 return minVal > maxVal ? TCU_NAN : 0.0;
3407 ExprP<float> clamp(const ExprP<float>& x, const ExprP<float>& minVal, const ExprP<float>& maxVal)
3409 return app<Clamp>(x, minVal, maxVal);
3412 DEFINE_DERIVED_FLOAT3(Mix, mix, x, y, a, alternatives((x * (constant(1.0f) - a)) + y * a,
3415 static double step (double edge, double x)
3417 return x < edge ? 0.0 : 1.0;
3420 class Step : public PreciseFunc2 { public: Step (void) : PreciseFunc2("step", step) {} };
3422 class SmoothStep : public DerivedFunc<Signature<float, float, float, float> >
3425 string getName (void) const
3427 return "smoothstep";
3432 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3434 const ExprP<float>& edge0 = args.a;
3435 const ExprP<float>& edge1 = args.b;
3436 const ExprP<float>& x = args.c;
3437 const ExprP<float> tExpr = clamp((x - edge0) / (edge1 - edge0),
3438 constant(0.0f), constant(1.0f));
3439 const ExprP<float> t = bindExpression("t", ctx, tExpr);
3441 return (t * t * (constant(3.0f) - constant(2.0f) * t));
3445 class FrExp : public PrimitiveFunc<Signature<float, float, int> >
3448 string getName (void) const
3454 IRet doApply (const EvalContext&, const IArgs& iargs) const
3457 const IArg0& x = iargs.a;
3458 IArg1& exponent = const_cast<IArg1&>(iargs.b);
3460 if (x.hasNaN() || x.contains(TCU_INFINITY) || x.contains(-TCU_INFINITY))
3462 // GLSL (in contrast to IEEE) says that result of applying frexp
3463 // to infinity is undefined
3464 ret = Interval::unbounded() | TCU_NAN;
3465 exponent = Interval(-deLdExp(1.0, 31), deLdExp(1.0, 31)-1);
3467 else if (!x.empty())
3470 const double loFrac = deFrExp(x.lo(), &loExp);
3472 const double hiFrac = deFrExp(x.hi(), &hiExp);
3474 if (deSign(loFrac) != deSign(hiFrac))
3476 exponent = Interval(-TCU_INFINITY, de::max(loExp, hiExp));
3478 if (deSign(loFrac) < 0)
3479 ret |= Interval(-1.0 + DBL_EPSILON*0.5, 0.0);
3480 if (deSign(hiFrac) > 0)
3481 ret |= Interval(0.0, 1.0 - DBL_EPSILON*0.5);
3485 exponent = Interval(loExp, hiExp);
3487 ret = Interval(loFrac, hiFrac);
3489 ret = deSign(loFrac) * Interval(0.5, 1.0 - DBL_EPSILON*0.5);
3496 int getOutParamIndex (void) const
3502 class LdExp : public PrimitiveFunc<Signature<float, float, int> >
3505 string getName (void) const
3511 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
3513 Interval ret = call<Exp2>(ctx, iargs.b);
3514 // Khronos bug 11180 consensus: if exp2(exponent) cannot be represented,
3515 // the result is undefined.
3517 if (ret.contains(TCU_INFINITY) | ret.contains(-TCU_INFINITY))
3520 return call<Mul>(ctx, iargs.a, ret);
3524 template<int Rows, int Columns>
3525 class Transpose : public PrimitiveFunc<Signature<Matrix<float, Rows, Columns>,
3526 Matrix<float, Columns, Rows> > >
3529 typedef typename Transpose::IRet IRet;
3530 typedef typename Transpose::IArgs IArgs;
3532 string getName (void) const
3538 IRet doApply (const EvalContext&, const IArgs& iargs) const
3542 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
3544 for (int colNdx = 0; colNdx < Columns; ++colNdx)
3545 ret(rowNdx, colNdx) = iargs.a(colNdx, rowNdx);
3552 template<typename Ret, typename Arg0, typename Arg1>
3553 class MulFunc : public PrimitiveFunc<Signature<Ret, Arg0, Arg1> >
3556 string getName (void) const { return "mul"; }
3559 void doPrint (ostream& os, const BaseArgExprs& args) const
3561 os << "(" << *args[0] << " * " << *args[1] << ")";
3565 template<int LeftRows, int Middle, int RightCols>
3566 class MatMul : public MulFunc<Matrix<float, LeftRows, RightCols>,
3567 Matrix<float, LeftRows, Middle>,
3568 Matrix<float, Middle, RightCols> >
3571 typedef typename MatMul::IRet IRet;
3572 typedef typename MatMul::IArgs IArgs;
3573 typedef typename MatMul::IArg0 IArg0;
3574 typedef typename MatMul::IArg1 IArg1;
3576 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3578 const IArg0& left = iargs.a;
3579 const IArg1& right = iargs.b;
3582 for (int row = 0; row < LeftRows; ++row)
3584 for (int col = 0; col < RightCols; ++col)
3586 Interval element (0.0);
3588 for (int ndx = 0; ndx < Middle; ++ndx)
3589 element = call<Add>(ctx, element,
3590 call<Mul>(ctx, left[ndx][row], right[col][ndx]));
3592 ret[col][row] = element;
3600 template<int Rows, int Cols>
3601 class VecMatMul : public MulFunc<Vector<float, Cols>,
3602 Vector<float, Rows>,
3603 Matrix<float, Rows, Cols> >
3606 typedef typename VecMatMul::IRet IRet;
3607 typedef typename VecMatMul::IArgs IArgs;
3608 typedef typename VecMatMul::IArg0 IArg0;
3609 typedef typename VecMatMul::IArg1 IArg1;
3612 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3614 const IArg0& left = iargs.a;
3615 const IArg1& right = iargs.b;
3618 for (int col = 0; col < Cols; ++col)
3620 Interval element (0.0);
3622 for (int row = 0; row < Rows; ++row)
3623 element = call<Add>(ctx, element, call<Mul>(ctx, left[row], right[col][row]));
3632 template<int Rows, int Cols>
3633 class MatVecMul : public MulFunc<Vector<float, Rows>,
3634 Matrix<float, Rows, Cols>,
3635 Vector<float, Cols> >
3638 typedef typename MatVecMul::IRet IRet;
3639 typedef typename MatVecMul::IArgs IArgs;
3640 typedef typename MatVecMul::IArg0 IArg0;
3641 typedef typename MatVecMul::IArg1 IArg1;
3644 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3646 const IArg0& left = iargs.a;
3647 const IArg1& right = iargs.b;
3649 return call<VecMatMul<Cols, Rows> >(ctx, right,
3650 call<Transpose<Rows, Cols> >(ctx, left));
3654 template<int Rows, int Cols>
3655 class OuterProduct : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
3656 Vector<float, Rows>,
3657 Vector<float, Cols> > >
3660 typedef typename OuterProduct::IRet IRet;
3661 typedef typename OuterProduct::IArgs IArgs;
3663 string getName (void) const
3665 return "outerProduct";
3669 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3673 for (int row = 0; row < Rows; ++row)
3675 for (int col = 0; col < Cols; ++col)
3676 ret[col][row] = call<Mul>(ctx, iargs.a[row], iargs.b[col]);
3683 template<int Rows, int Cols>
3684 ExprP<Matrix<float, Rows, Cols> > outerProduct (const ExprP<Vector<float, Rows> >& left,
3685 const ExprP<Vector<float, Cols> >& right)
3687 return app<OuterProduct<Rows, Cols> >(left, right);
3691 class DeterminantBase : public DerivedFunc<Signature<float, Matrix<float, Size, Size> > >
3694 string getName (void) const { return "determinant"; }
3701 ExprP<float> determinant (ExprP<Matrix<float, Size, Size> > mat)
3703 return app<Determinant<Size> >(mat);
3707 class Determinant<2> : public DeterminantBase<2>
3710 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3712 ExprP<Mat2> mat = args.a;
3714 return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
3719 class Determinant<3> : public DeterminantBase<3>
3722 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3724 ExprP<Mat3> mat = args.a;
3726 return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) +
3727 mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) +
3728 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
3733 class Determinant<4> : public DeterminantBase<4>
3736 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3738 ExprP<Mat4> mat = args.a;
3739 ExprP<Mat3> minors[4];
3741 for (int ndx = 0; ndx < 4; ++ndx)
3743 ExprP<Vec4> minorColumns[3];
3744 ExprP<Vec3> columns[3];
3746 for (int col = 0; col < 3; ++col)
3747 minorColumns[col] = mat[col < ndx ? col : col + 1];
3749 for (int col = 0; col < 3; ++col)
3750 columns[col] = vec3(minorColumns[0][col+1],
3751 minorColumns[1][col+1],
3752 minorColumns[2][col+1]);
3754 minors[ndx] = bindExpression("minor", ctx,
3755 mat3(columns[0], columns[1], columns[2]));
3758 return (mat[0][0] * determinant(minors[0]) -
3759 mat[1][0] * determinant(minors[1]) +
3760 mat[2][0] * determinant(minors[2]) -
3761 mat[3][0] * determinant(minors[3]));
3765 template<int Size> class Inverse;
3768 ExprP<Matrix<float, Size, Size> > inverse (ExprP<Matrix<float, Size, Size> > mat)
3770 return app<Inverse<Size> >(mat);
3774 class Inverse<2> : public DerivedFunc<Signature<Mat2, Mat2> >
3777 string getName (void) const
3783 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3785 ExprP<Mat2> mat = args.a;
3786 ExprP<float> det = bindExpression("det", ctx, determinant(mat));
3788 return mat2(vec2(mat[1][1] / det, -mat[0][1] / det),
3789 vec2(-mat[1][0] / det, mat[0][0] / det));
3794 class Inverse<3> : public DerivedFunc<Signature<Mat3, Mat3> >
3797 string getName (void) const
3803 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3805 ExprP<Mat3> mat = args.a;
3806 ExprP<Mat2> invA = bindExpression("invA", ctx,
3807 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3808 vec2(mat[1][0], mat[1][1]))));
3810 ExprP<Vec2> matB = bindExpression("matB", ctx, vec2(mat[2][0], mat[2][1]));
3811 ExprP<Vec2> matC = bindExpression("matC", ctx, vec2(mat[0][2], mat[1][2]));
3812 ExprP<float> matD = bindExpression("matD", ctx, mat[2][2]);
3814 ExprP<float> schur = bindExpression("schur", ctx,
3816 (matD - dot(matC * invA, matB)));
3818 ExprP<Vec2> t1 = invA * matB;
3819 ExprP<Vec2> t2 = t1 * schur;
3820 ExprP<Mat2> t3 = outerProduct(t2, matC);
3821 ExprP<Mat2> t4 = t3 * invA;
3822 ExprP<Mat2> t5 = invA + t4;
3823 ExprP<Mat2> blockA = bindExpression("blockA", ctx, t5);
3824 ExprP<Vec2> blockB = bindExpression("blockB", ctx,
3825 (invA * matB) * -schur);
3826 ExprP<Vec2> blockC = bindExpression("blockC", ctx,
3827 (matC * invA) * -schur);
3829 return mat3(vec3(blockA[0][0], blockA[0][1], blockC[0]),
3830 vec3(blockA[1][0], blockA[1][1], blockC[1]),
3831 vec3(blockB[0], blockB[1], schur));
3836 class Inverse<4> : public DerivedFunc<Signature<Mat4, Mat4> >
3839 string getName (void) const { return "inverse"; }
3842 ExprP<Ret> doExpand (ExpandContext& ctx,
3843 const ArgExprs& args) const
3845 ExprP<Mat4> mat = args.a;
3846 ExprP<Mat2> invA = bindExpression("invA", ctx,
3847 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3848 vec2(mat[1][0], mat[1][1]))));
3849 ExprP<Mat2> matB = bindExpression("matB", ctx,
3850 mat2(vec2(mat[2][0], mat[2][1]),
3851 vec2(mat[3][0], mat[3][1])));
3852 ExprP<Mat2> matC = bindExpression("matC", ctx,
3853 mat2(vec2(mat[0][2], mat[0][3]),
3854 vec2(mat[1][2], mat[1][3])));
3855 ExprP<Mat2> matD = bindExpression("matD", ctx,
3856 mat2(vec2(mat[2][2], mat[2][3]),
3857 vec2(mat[3][2], mat[3][3])));
3858 ExprP<Mat2> schur = bindExpression("schur", ctx,
3859 inverse(matD + -(matC * invA * matB)));
3860 ExprP<Mat2> blockA = bindExpression("blockA", ctx,
3861 invA + (invA * matB * schur * matC * invA));
3862 ExprP<Mat2> blockB = bindExpression("blockB", ctx,
3863 (-invA) * matB * schur);
3864 ExprP<Mat2> blockC = bindExpression("blockC", ctx,
3865 (-schur) * matC * invA);
3867 return mat4(vec4(blockA[0][0], blockA[0][1], blockC[0][0], blockC[0][1]),
3868 vec4(blockA[1][0], blockA[1][1], blockC[1][0], blockC[1][1]),
3869 vec4(blockB[0][0], blockB[0][1], schur[0][0], schur[0][1]),
3870 vec4(blockB[1][0], blockB[1][1], schur[1][0], schur[1][1]));
3874 class Fma : public DerivedFunc<Signature<float, float, float, float> >
3877 string getName (void) const
3882 string getRequiredExtension (void) const
3884 return "GL_EXT_gpu_shader5";
3888 ExprP<float> doExpand (ExpandContext&, const ArgExprs& x) const
3890 return x.a * x.b + x.c;
3896 using namespace Functions;
3898 template <typename T>
3899 ExprP<typename T::Element> ContainerExprPBase<T>::operator[] (int i) const
3901 return Functions::getComponent(exprP<T>(*this), i);
3904 ExprP<float> operator+ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3906 return app<Add>(arg0, arg1);
3909 ExprP<float> operator- (const ExprP<float>& arg0, const ExprP<float>& arg1)
3911 return app<Sub>(arg0, arg1);
3914 ExprP<float> operator- (const ExprP<float>& arg0)
3916 return app<Negate>(arg0);
3919 ExprP<float> operator* (const ExprP<float>& arg0, const ExprP<float>& arg1)
3921 return app<Mul>(arg0, arg1);
3924 ExprP<float> operator/ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3926 return app<Div>(arg0, arg1);
3929 template <typename Sig_, int Size>
3930 class GenFunc : public PrimitiveFunc<Signature<
3931 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3932 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3933 typename ContainerOf<typename Sig_::Arg1, Size>::Container,
3934 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
3935 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
3938 typedef typename GenFunc::IArgs IArgs;
3939 typedef typename GenFunc::IRet IRet;
3941 GenFunc (const Func<Sig_>& scalarFunc) : m_func (scalarFunc) {}
3943 string getName (void) const
3945 return m_func.getName();
3948 int getOutParamIndex (void) const
3950 return m_func.getOutParamIndex();
3953 string getRequiredExtension (void) const
3955 return m_func.getRequiredExtension();
3959 void doPrint (ostream& os, const BaseArgExprs& args) const
3961 m_func.print(os, args);
3964 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3968 for (int ndx = 0; ndx < Size; ++ndx)
3971 m_func.apply(ctx, iargs.a[ndx], iargs.b[ndx], iargs.c[ndx], iargs.d[ndx]);
3977 void doGetUsedFuncs (FuncSet& dst) const
3979 m_func.getUsedFuncs(dst);
3982 const Func<Sig_>& m_func;
3985 template <typename F, int Size>
3986 class VectorizedFunc : public GenFunc<typename F::Sig, Size>
3989 VectorizedFunc (void) : GenFunc<typename F::Sig, Size>(instance<F>()) {}
3994 template <typename Sig_, int Size>
3995 class FixedGenFunc : public PrimitiveFunc <Signature<
3996 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3997 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3998 typename Sig_::Arg1,
3999 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
4000 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
4003 typedef typename FixedGenFunc::IArgs IArgs;
4004 typedef typename FixedGenFunc::IRet IRet;
4006 string getName (void) const
4008 return this->doGetScalarFunc().getName();
4012 void doPrint (ostream& os, const BaseArgExprs& args) const
4014 this->doGetScalarFunc().print(os, args);
4017 IRet doApply (const EvalContext& ctx,
4018 const IArgs& iargs) const
4021 const Func<Sig_>& func = this->doGetScalarFunc();
4023 for (int ndx = 0; ndx < Size; ++ndx)
4024 ret[ndx] = func.apply(ctx, iargs.a[ndx], iargs.b, iargs.c[ndx], iargs.d[ndx]);
4029 virtual const Func<Sig_>& doGetScalarFunc (void) const = 0;
4032 template <typename F, int Size>
4033 class FixedVecFunc : public FixedGenFunc<typename F::Sig, Size>
4036 const Func<typename F::Sig>& doGetScalarFunc (void) const { return instance<F>(); }
4039 template<typename Sig>
4042 GenFuncs (const Func<Sig>& func_,
4043 const GenFunc<Sig, 2>& func2_,
4044 const GenFunc<Sig, 3>& func3_,
4045 const GenFunc<Sig, 4>& func4_)
4052 const Func<Sig>& func;
4053 const GenFunc<Sig, 2>& func2;
4054 const GenFunc<Sig, 3>& func3;
4055 const GenFunc<Sig, 4>& func4;
4058 template<typename F>
4059 GenFuncs<typename F::Sig> makeVectorizedFuncs (void)
4061 return GenFuncs<typename F::Sig>(instance<F>(),
4062 instance<VectorizedFunc<F, 2> >(),
4063 instance<VectorizedFunc<F, 3> >(),
4064 instance<VectorizedFunc<F, 4> >());
4068 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
4069 const ExprP<Vector<float, Size> >& arg1)
4071 return app<VectorizedFunc<Mul, Size> >(arg0, arg1);
4075 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
4076 const ExprP<float>& arg1)
4078 return app<FixedVecFunc<Mul, Size> >(arg0, arg1);
4082 ExprP<Vector<float, Size> > operator/(const ExprP<Vector<float, Size> >& arg0,
4083 const ExprP<float>& arg1)
4085 return app<FixedVecFunc<Div, Size> >(arg0, arg1);
4089 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0)
4091 return app<VectorizedFunc<Negate, Size> >(arg0);
4095 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
4096 const ExprP<Vector<float, Size> >& arg1)
4098 return app<VectorizedFunc<Sub, Size> >(arg0, arg1);
4101 template<int LeftRows, int Middle, int RightCols>
4102 ExprP<Matrix<float, LeftRows, RightCols> >
4103 operator* (const ExprP<Matrix<float, LeftRows, Middle> >& left,
4104 const ExprP<Matrix<float, Middle, RightCols> >& right)
4106 return app<MatMul<LeftRows, Middle, RightCols> >(left, right);
4109 template<int Rows, int Cols>
4110 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
4111 const ExprP<Matrix<float, Rows, Cols> >& right)
4113 return app<VecMatMul<Rows, Cols> >(left, right);
4116 template<int Rows, int Cols>
4117 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
4118 const ExprP<Vector<float, Rows> >& right)
4120 return app<MatVecMul<Rows, Cols> >(left, right);
4123 template<int Rows, int Cols>
4124 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
4125 const ExprP<float>& right)
4127 return app<ScalarMatFunc<Mul, Rows, Cols> >(left, right);
4130 template<int Rows, int Cols>
4131 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
4132 const ExprP<Matrix<float, Rows, Cols> >& right)
4134 return app<CompMatFunc<Add, Rows, Cols> >(left, right);
4137 template<int Rows, int Cols>
4138 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat)
4140 return app<MatNeg<Rows, Cols> >(mat);
4143 template <typename T>
4147 virtual void genFixeds (const FloatFormat&, vector<T>&) const {}
4148 virtual T genRandom (const FloatFormat&, Precision, Random&) const { return T(); }
4149 virtual double getWeight (void) const { return 0.0; }
4153 class DefaultSampling<Void> : public Sampling<Void>
4156 void genFixeds (const FloatFormat&, vector<Void>& dst) const { dst.push_back(Void()); }
4160 class DefaultSampling<bool> : public Sampling<bool>
4163 void genFixeds (const FloatFormat&, vector<bool>& dst) const
4165 dst.push_back(true);
4166 dst.push_back(false);
4171 class DefaultSampling<int> : public Sampling<int>
4174 int genRandom (const FloatFormat&, Precision prec, Random& rnd) const
4176 const int exp = rnd.getInt(0, getNumBits(prec)-2);
4177 const int sign = rnd.getBool() ? -1 : 1;
4179 return sign * rnd.getInt(0, (deInt32)1 << exp);
4182 void genFixeds (const FloatFormat&, vector<int>& dst) const
4188 double getWeight (void) const { return 1.0; }
4191 static inline int getNumBits (Precision prec)
4195 case glu::PRECISION_LOWP: return 8;
4196 case glu::PRECISION_MEDIUMP: return 16;
4197 case glu::PRECISION_HIGHP: return 32;
4206 class DefaultSampling<float> : public Sampling<float>
4209 float genRandom (const FloatFormat& format, Precision prec, Random& rnd) const;
4210 void genFixeds (const FloatFormat& format, vector<float>& dst) const;
4211 double getWeight (void) const { return 1.0; }
4214 //! Generate a random float from a reasonable general-purpose distribution.
4215 float DefaultSampling<float>::genRandom (const FloatFormat& format,
4219 const int minExp = format.getMinExp();
4220 const int maxExp = format.getMaxExp();
4221 const bool haveSubnormal = format.hasSubnormal() != tcu::NO;
4223 // Choose exponent so that the cumulative distribution is cubic.
4224 // This makes the probability distribution quadratic, with the peak centered on zero.
4225 const double minRoot = deCbrt(minExp - 0.5 - (haveSubnormal ? 1.0 : 0.0));
4226 const double maxRoot = deCbrt(maxExp + 0.5);
4227 const int fractionBits = format.getFractionBits();
4228 const int exp = int(deRoundEven(dePow(rnd.getDouble(minRoot, maxRoot),
4230 float base = 0.0f; // integral power of two
4231 float quantum = 0.0f; // smallest representable difference in the binade
4232 float significand = 0.0f; // Significand.
4234 DE_ASSERT(fractionBits < std::numeric_limits<float>::digits);
4236 // Generate some occasional special numbers
4237 switch (rnd.getInt(0, 64))
4240 case 1: return TCU_INFINITY;
4241 case 2: return -TCU_INFINITY;
4242 case 3: return TCU_NAN;
4249 base = deFloatLdExp(1.0f, exp);
4250 quantum = deFloatLdExp(1.0f, exp - fractionBits);
4256 quantum = deFloatLdExp(1.0f, minExp - fractionBits);
4259 switch (rnd.getInt(0, 16))
4261 case 0: // The highest number in this binade, significand is all bits one.
4262 significand = base - quantum;
4264 case 1: // Significand is one.
4265 significand = quantum;
4267 case 2: // Significand is zero.
4270 default: // Random (evenly distributed) significand.
4272 deUint64 intFraction = rnd.getUint64() & ((1 << fractionBits) - 1);
4273 significand = float(intFraction) * quantum;
4277 // Produce positive numbers more often than negative.
4278 return (rnd.getInt(0,3) == 0 ? -1.0f : 1.0f) * (base + significand);
4281 //! Generate a standard set of floats that should always be tested.
4282 void DefaultSampling<float>::genFixeds (const FloatFormat& format, vector<float>& dst) const
4284 const int minExp = format.getMinExp();
4285 const int maxExp = format.getMaxExp();
4286 const int fractionBits = format.getFractionBits();
4287 const float minQuantum = deFloatLdExp(1.0f, minExp - fractionBits);
4288 const float minNormalized = deFloatLdExp(1.0f, minExp);
4289 const float maxQuantum = deFloatLdExp(1.0f, maxExp - fractionBits);
4292 dst.push_back(TCU_NAN);
4294 dst.push_back(0.0f);
4296 for (int sign = -1; sign <= 1; sign += 2)
4298 // Smallest subnormal
4299 dst.push_back((float)sign * minQuantum);
4301 // Largest subnormal
4302 dst.push_back((float)sign * (minNormalized - minQuantum));
4304 // Smallest normalized
4305 dst.push_back((float)sign * minNormalized);
4307 // Next smallest normalized
4308 dst.push_back((float)sign * (minNormalized + minQuantum));
4310 dst.push_back((float)sign * 0.5f);
4311 dst.push_back((float)sign * 1.0f);
4312 dst.push_back((float)sign * 2.0f);
4315 dst.push_back((float)sign * (deFloatLdExp(1.0f, maxExp) +
4316 (deFloatLdExp(1.0f, maxExp) - maxQuantum)));
4318 dst.push_back((float)sign * TCU_INFINITY);
4322 template <typename T, int Size>
4323 class DefaultSampling<Vector<T, Size> > : public Sampling<Vector<T, Size> >
4326 typedef Vector<T, Size> Value;
4328 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4332 for (int ndx = 0; ndx < Size; ++ndx)
4333 ret[ndx] = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4338 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4342 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4344 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4345 dst.push_back(Value(scalars[scalarNdx]));
4348 double getWeight (void) const
4350 return dePow(instance<DefaultSampling<T> >().getWeight(), Size);
4354 template <typename T, int Rows, int Columns>
4355 class DefaultSampling<Matrix<T, Rows, Columns> > : public Sampling<Matrix<T, Rows, Columns> >
4358 typedef Matrix<T, Rows, Columns> Value;
4360 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4364 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
4365 for (int colNdx = 0; colNdx < Columns; ++colNdx)
4366 ret(rowNdx, colNdx) = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4371 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4375 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4377 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4378 dst.push_back(Value(scalars[scalarNdx]));
4380 if (Columns == Rows)
4385 for (int ndx = 0; ndx < Columns; ++ndx)
4387 mat[Columns-1-ndx][ndx] = x;
4394 double getWeight (void) const
4396 return dePow(instance<DefaultSampling<T> >().getWeight(), Rows * Columns);
4402 Context (const string& name_,
4403 TestContext& testContext_,
4404 RenderContext& renderContext_,
4405 const FloatFormat& floatFormat_,
4406 const FloatFormat& highpFormat_,
4407 Precision precision_,
4408 ShaderType shaderType_,
4411 , testContext (testContext_)
4412 , renderContext (renderContext_)
4413 , floatFormat (floatFormat_)
4414 , highpFormat (highpFormat_)
4415 , precision (precision_)
4416 , shaderType (shaderType_)
4417 , numRandoms (numRandoms_) {}
4420 TestContext& testContext;
4421 RenderContext& renderContext;
4422 FloatFormat floatFormat;
4423 FloatFormat highpFormat;
4424 Precision precision;
4425 ShaderType shaderType;
4429 template<typename In0_ = Void, typename In1_ = Void, typename In2_ = Void, typename In3_ = Void>
4438 template <typename In>
4439 int numInputs (void)
4441 return (!isTypeValid<typename In::In0>() ? 0 :
4442 !isTypeValid<typename In::In1>() ? 1 :
4443 !isTypeValid<typename In::In2>() ? 2 :
4444 !isTypeValid<typename In::In3>() ? 3 :
4448 template<typename Out0_, typename Out1_ = Void>
4455 template <typename Out>
4456 int numOutputs (void)
4458 return (!isTypeValid<typename Out::Out0>() ? 0 :
4459 !isTypeValid<typename Out::Out1>() ? 1 :
4463 template<typename In>
4466 vector<typename In::In0> in0;
4467 vector<typename In::In1> in1;
4468 vector<typename In::In2> in2;
4469 vector<typename In::In3> in3;
4472 template<typename Out>
4475 Outputs (size_t size) : out0(size), out1(size) {}
4477 vector<typename Out::Out0> out0;
4478 vector<typename Out::Out1> out1;
4481 template<typename In, typename Out>
4484 VariableP<typename In::In0> in0;
4485 VariableP<typename In::In1> in1;
4486 VariableP<typename In::In2> in2;
4487 VariableP<typename In::In3> in3;
4488 VariableP<typename Out::Out0> out0;
4489 VariableP<typename Out::Out1> out1;
4492 template<typename In>
4495 Samplings (const Sampling<typename In::In0>& in0_,
4496 const Sampling<typename In::In1>& in1_,
4497 const Sampling<typename In::In2>& in2_,
4498 const Sampling<typename In::In3>& in3_)
4499 : in0 (in0_), in1 (in1_), in2 (in2_), in3 (in3_) {}
4501 const Sampling<typename In::In0>& in0;
4502 const Sampling<typename In::In1>& in1;
4503 const Sampling<typename In::In2>& in2;
4504 const Sampling<typename In::In3>& in3;
4507 template<typename In>
4508 struct DefaultSamplings : Samplings<In>
4510 DefaultSamplings (void)
4511 : Samplings<In>(instance<DefaultSampling<typename In::In0> >(),
4512 instance<DefaultSampling<typename In::In1> >(),
4513 instance<DefaultSampling<typename In::In2> >(),
4514 instance<DefaultSampling<typename In::In3> >()) {}
4517 class PrecisionCase : public TestCase
4520 IterateResult iterate (void);
4523 PrecisionCase (const Context& context,
4525 const string& extension = "")
4526 : TestCase (context.testContext,
4531 , m_rnd (0xdeadbeefu +
4532 context.testContext.getCommandLine().getBaseSeed())
4533 , m_extension (extension)
4537 RenderContext& getRenderContext(void) const { return m_ctx.renderContext; }
4539 const FloatFormat& getFormat (void) const { return m_ctx.floatFormat; }
4541 TestLog& log (void) const { return m_testCtx.getLog(); }
4543 virtual void runTest (void) = 0;
4545 template <typename In, typename Out>
4546 void testStatement (const Variables<In, Out>& variables,
4547 const Inputs<In>& inputs,
4548 const Statement& stmt);
4550 template<typename T>
4551 Symbol makeSymbol (const Variable<T>& variable)
4553 return Symbol(variable.getName(), getVarTypeOf<T>(m_ctx.precision));
4557 ResultCollector m_status;
4559 const string m_extension;
4562 IterateResult PrecisionCase::iterate (void)
4565 m_status.setTestContextResult(m_testCtx);
4569 template <typename In, typename Out>
4570 void PrecisionCase::testStatement (const Variables<In, Out>& variables,
4571 const Inputs<In>& inputs,
4572 const Statement& stmt)
4574 using namespace ShaderExecUtil;
4576 typedef typename In::In0 In0;
4577 typedef typename In::In1 In1;
4578 typedef typename In::In2 In2;
4579 typedef typename In::In3 In3;
4580 typedef typename Out::Out0 Out0;
4581 typedef typename Out::Out1 Out1;
4583 const FloatFormat& fmt = getFormat();
4584 const int inCount = numInputs<In>();
4585 const int outCount = numOutputs<Out>();
4586 const size_t numValues = (inCount > 0) ? inputs.in0.size() : 1;
4587 Outputs<Out> outputs (numValues);
4589 const FloatFormat highpFmt = m_ctx.highpFormat;
4590 const int maxMsgs = 100;
4592 Environment env; // Hoisted out of the inner loop for optimization.
4596 case 4: DE_ASSERT(inputs.in3.size() == numValues);
4597 case 3: DE_ASSERT(inputs.in2.size() == numValues);
4598 case 2: DE_ASSERT(inputs.in1.size() == numValues);
4599 case 1: DE_ASSERT(inputs.in0.size() == numValues);
4603 // Print out the statement and its definitions
4604 log() << TestLog::Message << "Statement: " << stmt << TestLog::EndMessage;
4609 stmt.getUsedFuncs(funcs);
4610 for (FuncSet::const_iterator it = funcs.begin(); it != funcs.end(); ++it)
4612 (*it)->printDefinition(oss);
4615 log() << TestLog::Message << "Reference definitions:\n" << oss.str()
4616 << TestLog::EndMessage;
4619 // Initialize ShaderSpec from precision, variables and statement.
4622 os << "precision " << glu::getPrecisionName(m_ctx.precision) << " float;\n";
4623 spec.globalDeclarations = os.str();
4626 spec.version = getContextTypeGLSLVersion(getRenderContext().getType());
4628 if (!m_extension.empty())
4629 spec.globalDeclarations = "#extension " + m_extension + " : require\n";
4631 spec.inputs.resize(inCount);
4635 case 4: spec.inputs[3] = makeSymbol(*variables.in3);
4636 case 3: spec.inputs[2] = makeSymbol(*variables.in2);
4637 case 2: spec.inputs[1] = makeSymbol(*variables.in1);
4638 case 1: spec.inputs[0] = makeSymbol(*variables.in0);
4642 spec.outputs.resize(outCount);
4646 case 2: spec.outputs[1] = makeSymbol(*variables.out1);
4647 case 1: spec.outputs[0] = makeSymbol(*variables.out0);
4651 spec.source = de::toString(stmt);
4653 // Run the shader with inputs.
4655 UniquePtr<ShaderExecutor> executor (createExecutor(getRenderContext(),
4658 const void* inputArr[] =
4660 &inputs.in0.front(), &inputs.in1.front(), &inputs.in2.front(), &inputs.in3.front(),
4664 &outputs.out0.front(), &outputs.out1.front(),
4667 executor->log(log());
4668 if (!executor->isOk())
4669 TCU_FAIL("Shader compilation failed");
4671 executor->useProgram();
4672 executor->execute(int(numValues), inputArr, outputArr);
4675 // Initialize environment with dummy values so we don't need to bind in inner loop.
4677 const typename Traits<In0>::IVal in0;
4678 const typename Traits<In1>::IVal in1;
4679 const typename Traits<In2>::IVal in2;
4680 const typename Traits<In3>::IVal in3;
4681 const typename Traits<Out0>::IVal reference0;
4682 const typename Traits<Out1>::IVal reference1;
4684 env.bind(*variables.in0, in0);
4685 env.bind(*variables.in1, in1);
4686 env.bind(*variables.in2, in2);
4687 env.bind(*variables.in3, in3);
4688 env.bind(*variables.out0, reference0);
4689 env.bind(*variables.out1, reference1);
4692 // For each input tuple, compute output reference interval and compare
4693 // shader output to the reference.
4694 for (size_t valueNdx = 0; valueNdx < numValues; valueNdx++)
4697 typename Traits<Out0>::IVal reference0;
4698 typename Traits<Out1>::IVal reference1;
4700 if (valueNdx % (size_t)TOUCH_WATCHDOG_VALUE_FREQUENCY == 0)
4701 m_testCtx.touchWatchdog();
4703 env.lookup(*variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx]));
4704 env.lookup(*variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx]));
4705 env.lookup(*variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx]));
4706 env.lookup(*variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx]));
4709 EvalContext ctx (fmt, m_ctx.precision, env);
4716 reference1 = convert<Out1>(highpFmt, env.lookup(*variables.out1));
4717 if (!m_status.check(contains(reference1, outputs.out1[valueNdx]),
4718 "Shader output 1 is outside acceptable range"))
4721 reference0 = convert<Out0>(highpFmt, env.lookup(*variables.out0));
4722 if (!m_status.check(contains(reference0, outputs.out0[valueNdx]),
4723 "Shader output 0 is outside acceptable range"))
4731 if ((!result && numErrors <= maxMsgs) || GLS_LOG_ALL_RESULTS)
4733 MessageBuilder builder = log().message();
4735 builder << (result ? "Passed" : "Failed") << " sample:\n";
4739 builder << "\t" << variables.in0->getName() << " = "
4740 << valueToString(highpFmt, inputs.in0[valueNdx]) << "\n";
4745 builder << "\t" << variables.in1->getName() << " = "
4746 << valueToString(highpFmt, inputs.in1[valueNdx]) << "\n";
4751 builder << "\t" << variables.in2->getName() << " = "
4752 << valueToString(highpFmt, inputs.in2[valueNdx]) << "\n";
4757 builder << "\t" << variables.in3->getName() << " = "
4758 << valueToString(highpFmt, inputs.in3[valueNdx]) << "\n";
4763 builder << "\t" << variables.out0->getName() << " = "
4764 << valueToString(highpFmt, outputs.out0[valueNdx]) << "\n"
4765 << "\tExpected range: "
4766 << intervalToString<typename Out::Out0>(highpFmt, reference0) << "\n";
4771 builder << "\t" << variables.out1->getName() << " = "
4772 << valueToString(highpFmt, outputs.out1[valueNdx]) << "\n"
4773 << "\tExpected range: "
4774 << intervalToString<typename Out::Out1>(highpFmt, reference1) << "\n";
4777 builder << TestLog::EndMessage;
4781 if (numErrors > maxMsgs)
4783 log() << TestLog::Message << "(Skipped " << (numErrors - maxMsgs) << " messages.)"
4784 << TestLog::EndMessage;
4789 log() << TestLog::Message << "All " << numValues << " inputs passed."
4790 << TestLog::EndMessage;
4794 log() << TestLog::Message << numErrors << "/" << numValues << " inputs failed."
4795 << TestLog::EndMessage;
4801 template <typename T>
4804 bool operator() (const T& val1, const T& val2) const
4810 template <typename T>
4811 bool inputLess (const T& val1, const T& val2)
4813 return InputLess<T>()(val1, val2);
4817 struct InputLess<float>
4819 bool operator() (const float& val1, const float& val2) const
4829 template <typename T, int Size>
4830 struct InputLess<Vector<T, Size> >
4832 bool operator() (const Vector<T, Size>& vec1, const Vector<T, Size>& vec2) const
4834 for (int ndx = 0; ndx < Size; ++ndx)
4836 if (inputLess(vec1[ndx], vec2[ndx]))
4838 if (inputLess(vec2[ndx], vec1[ndx]))
4846 template <typename T, int Rows, int Cols>
4847 struct InputLess<Matrix<T, Rows, Cols> >
4849 bool operator() (const Matrix<T, Rows, Cols>& mat1,
4850 const Matrix<T, Rows, Cols>& mat2) const
4852 for (int col = 0; col < Cols; ++col)
4854 if (inputLess(mat1[col], mat2[col]))
4856 if (inputLess(mat2[col], mat1[col]))
4864 template <typename In>
4866 public Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4868 InTuple (const typename In::In0& in0,
4869 const typename In::In1& in1,
4870 const typename In::In2& in2,
4871 const typename In::In3& in3)
4872 : Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4873 (in0, in1, in2, in3) {}
4876 template <typename In>
4877 struct InputLess<InTuple<In> >
4879 bool operator() (const InTuple<In>& in1, const InTuple<In>& in2) const
4881 if (inputLess(in1.a, in2.a))
4883 if (inputLess(in2.a, in1.a))
4885 if (inputLess(in1.b, in2.b))
4887 if (inputLess(in2.b, in1.b))
4889 if (inputLess(in1.c, in2.c))
4891 if (inputLess(in2.c, in1.c))
4893 if (inputLess(in1.d, in2.d))
4899 template<typename In>
4900 Inputs<In> generateInputs (const Samplings<In>& samplings,
4901 const FloatFormat& floatFormat,
4902 Precision intPrecision,
4907 Inputs<In> fixedInputs;
4908 set<InTuple<In>, InputLess<InTuple<In> > > seenInputs;
4910 samplings.in0.genFixeds(floatFormat, fixedInputs.in0);
4911 samplings.in1.genFixeds(floatFormat, fixedInputs.in1);
4912 samplings.in2.genFixeds(floatFormat, fixedInputs.in2);
4913 samplings.in3.genFixeds(floatFormat, fixedInputs.in3);
4915 for (size_t ndx0 = 0; ndx0 < fixedInputs.in0.size(); ++ndx0)
4917 for (size_t ndx1 = 0; ndx1 < fixedInputs.in1.size(); ++ndx1)
4919 for (size_t ndx2 = 0; ndx2 < fixedInputs.in2.size(); ++ndx2)
4921 for (size_t ndx3 = 0; ndx3 < fixedInputs.in3.size(); ++ndx3)
4923 const InTuple<In> tuple (fixedInputs.in0[ndx0],
4924 fixedInputs.in1[ndx1],
4925 fixedInputs.in2[ndx2],
4926 fixedInputs.in3[ndx3]);
4928 seenInputs.insert(tuple);
4929 ret.in0.push_back(tuple.a);
4930 ret.in1.push_back(tuple.b);
4931 ret.in2.push_back(tuple.c);
4932 ret.in3.push_back(tuple.d);
4938 for (size_t ndx = 0; ndx < numSamples; ++ndx)
4940 const typename In::In0 in0 = samplings.in0.genRandom(floatFormat, intPrecision, rnd);
4941 const typename In::In1 in1 = samplings.in1.genRandom(floatFormat, intPrecision, rnd);
4942 const typename In::In2 in2 = samplings.in2.genRandom(floatFormat, intPrecision, rnd);
4943 const typename In::In3 in3 = samplings.in3.genRandom(floatFormat, intPrecision, rnd);
4944 const InTuple<In> tuple (in0, in1, in2, in3);
4946 if (de::contains(seenInputs, tuple))
4949 seenInputs.insert(tuple);
4950 ret.in0.push_back(in0);
4951 ret.in1.push_back(in1);
4952 ret.in2.push_back(in2);
4953 ret.in3.push_back(in3);
4959 class FuncCaseBase : public PrecisionCase
4962 IterateResult iterate (void);
4965 FuncCaseBase (const Context& context,
4967 const FuncBase& func)
4968 : PrecisionCase (context, name, func.getRequiredExtension()) {}
4971 IterateResult FuncCaseBase::iterate (void)
4973 MovePtr<ContextInfo> info (ContextInfo::create(getRenderContext()));
4975 if (!m_extension.empty() && !info->isExtensionSupported(m_extension.c_str()))
4976 throw NotSupportedError("Unsupported extension: " + m_extension);
4980 m_status.setTestContextResult(m_testCtx);
4984 template <typename Sig>
4985 class FuncCase : public FuncCaseBase
4988 typedef Func<Sig> CaseFunc;
4989 typedef typename Sig::Ret Ret;
4990 typedef typename Sig::Arg0 Arg0;
4991 typedef typename Sig::Arg1 Arg1;
4992 typedef typename Sig::Arg2 Arg2;
4993 typedef typename Sig::Arg3 Arg3;
4994 typedef InTypes<Arg0, Arg1, Arg2, Arg3> In;
4995 typedef OutTypes<Ret> Out;
4997 FuncCase (const Context& context,
4999 const CaseFunc& func)
5000 : FuncCaseBase (context, name, func)
5004 void runTest (void);
5006 virtual const Samplings<In>& getSamplings (void)
5008 return instance<DefaultSamplings<In> >();
5012 const CaseFunc& m_func;
5015 template <typename Sig>
5016 void FuncCase<Sig>::runTest (void)
5018 const Inputs<In> inputs (generateInputs(getSamplings(),
5023 Variables<In, Out> variables;
5025 variables.out0 = variable<Ret>("out0");
5026 variables.out1 = variable<Void>("out1");
5027 variables.in0 = variable<Arg0>("in0");
5028 variables.in1 = variable<Arg1>("in1");
5029 variables.in2 = variable<Arg2>("in2");
5030 variables.in3 = variable<Arg3>("in3");
5033 ExprP<Ret> expr = applyVar(m_func,
5034 variables.in0, variables.in1,
5035 variables.in2, variables.in3);
5036 StatementP stmt = variableAssignment(variables.out0, expr);
5038 this->testStatement(variables, inputs, *stmt);
5042 template <typename Sig>
5043 class InOutFuncCase : public FuncCaseBase
5046 typedef Func<Sig> CaseFunc;
5047 typedef typename Sig::Ret Ret;
5048 typedef typename Sig::Arg0 Arg0;
5049 typedef typename Sig::Arg1 Arg1;
5050 typedef typename Sig::Arg2 Arg2;
5051 typedef typename Sig::Arg3 Arg3;
5052 typedef InTypes<Arg0, Arg2, Arg3> In;
5053 typedef OutTypes<Ret, Arg1> Out;
5055 InOutFuncCase (const Context& context,
5057 const CaseFunc& func)
5058 : FuncCaseBase (context, name, func)
5062 void runTest (void);
5064 virtual const Samplings<In>& getSamplings (void)
5066 return instance<DefaultSamplings<In> >();
5070 const CaseFunc& m_func;
5073 template <typename Sig>
5074 void InOutFuncCase<Sig>::runTest (void)
5076 const Inputs<In> inputs (generateInputs(getSamplings(),
5081 Variables<In, Out> variables;
5083 variables.out0 = variable<Ret>("out0");
5084 variables.out1 = variable<Arg1>("out1");
5085 variables.in0 = variable<Arg0>("in0");
5086 variables.in1 = variable<Arg2>("in1");
5087 variables.in2 = variable<Arg3>("in2");
5088 variables.in3 = variable<Void>("in3");
5091 ExprP<Ret> expr = applyVar(m_func,
5092 variables.in0, variables.out1,
5093 variables.in1, variables.in2);
5094 StatementP stmt = variableAssignment(variables.out0, expr);
5096 this->testStatement(variables, inputs, *stmt);
5100 template <typename Sig>
5101 PrecisionCase* createFuncCase (const Context& context,
5103 const Func<Sig>& func)
5105 switch (func.getOutParamIndex())
5108 return new FuncCase<Sig>(context, name, func);
5110 return new InOutFuncCase<Sig>(context, name, func);
5112 DE_FATAL("Impossible");
5120 virtual ~CaseFactory (void) {}
5121 virtual MovePtr<TestNode> createCase (const Context& ctx) const = 0;
5122 virtual string getName (void) const = 0;
5123 virtual string getDesc (void) const = 0;
5126 class FuncCaseFactory : public CaseFactory
5129 virtual const FuncBase& getFunc (void) const = 0;
5131 string getName (void) const
5133 return de::toLower(getFunc().getName());
5136 string getDesc (void) const
5138 return "Function '" + getFunc().getName() + "'";
5142 template <typename Sig>
5143 class GenFuncCaseFactory : public CaseFactory
5147 GenFuncCaseFactory (const GenFuncs<Sig>& funcs,
5150 , m_name (de::toLower(name)) {}
5152 MovePtr<TestNode> createCase (const Context& ctx) const
5154 TestCaseGroup* group = new TestCaseGroup(ctx.testContext,
5155 ctx.name.c_str(), ctx.name.c_str());
5157 group->addChild(createFuncCase(ctx, "scalar", m_funcs.func));
5158 group->addChild(createFuncCase(ctx, "vec2", m_funcs.func2));
5159 group->addChild(createFuncCase(ctx, "vec3", m_funcs.func3));
5160 group->addChild(createFuncCase(ctx, "vec4", m_funcs.func4));
5162 return MovePtr<TestNode>(group);
5165 string getName (void) const
5170 string getDesc (void) const
5172 return "Function '" + m_funcs.func.getName() + "'";
5176 const GenFuncs<Sig> m_funcs;
5180 template <template <int> class GenF>
5181 class TemplateFuncCaseFactory : public FuncCaseFactory
5184 MovePtr<TestNode> createCase (const Context& ctx) const
5186 TestCaseGroup* group = new TestCaseGroup(ctx.testContext,
5187 ctx.name.c_str(), ctx.name.c_str());
5188 group->addChild(createFuncCase(ctx, "scalar", instance<GenF<1> >()));
5189 group->addChild(createFuncCase(ctx, "vec2", instance<GenF<2> >()));
5190 group->addChild(createFuncCase(ctx, "vec3", instance<GenF<3> >()));
5191 group->addChild(createFuncCase(ctx, "vec4", instance<GenF<4> >()));
5193 return MovePtr<TestNode>(group);
5196 const FuncBase& getFunc (void) const { return instance<GenF<1> >(); }
5199 template <template <int> class GenF>
5200 class SquareMatrixFuncCaseFactory : public FuncCaseFactory
5203 MovePtr<TestNode> createCase (const Context& ctx) const
5205 TestCaseGroup* group = new TestCaseGroup(ctx.testContext,
5206 ctx.name.c_str(), ctx.name.c_str());
5207 group->addChild(createFuncCase(ctx, "mat2", instance<GenF<2> >()));
5209 // disabled until we get reasonable results
5210 group->addChild(createFuncCase(ctx, "mat3", instance<GenF<3> >()));
5211 group->addChild(createFuncCase(ctx, "mat4", instance<GenF<4> >()));
5214 return MovePtr<TestNode>(group);
5217 const FuncBase& getFunc (void) const { return instance<GenF<2> >(); }
5220 template <template <int, int> class GenF>
5221 class MatrixFuncCaseFactory : public FuncCaseFactory
5224 MovePtr<TestNode> createCase (const Context& ctx) const
5226 TestCaseGroup* const group = new TestCaseGroup(ctx.testContext,
5227 ctx.name.c_str(), ctx.name.c_str());
5229 this->addCase<2, 2>(ctx, group);
5230 this->addCase<3, 2>(ctx, group);
5231 this->addCase<4, 2>(ctx, group);
5232 this->addCase<2, 3>(ctx, group);
5233 this->addCase<3, 3>(ctx, group);
5234 this->addCase<4, 3>(ctx, group);
5235 this->addCase<2, 4>(ctx, group);
5236 this->addCase<3, 4>(ctx, group);
5237 this->addCase<4, 4>(ctx, group);
5239 return MovePtr<TestNode>(group);
5242 const FuncBase& getFunc (void) const { return instance<GenF<2,2> >(); }
5245 template <int Rows, int Cols>
5246 void addCase (const Context& ctx, TestCaseGroup* group) const
5248 const char* const name = dataTypeNameOf<Matrix<float, Rows, Cols> >();
5250 group->addChild(createFuncCase(ctx, name, instance<GenF<Rows, Cols> >()));
5254 template <typename Sig>
5255 class SimpleFuncCaseFactory : public CaseFactory
5258 SimpleFuncCaseFactory (const Func<Sig>& func) : m_func(func) {}
5260 MovePtr<TestNode> createCase (const Context& ctx) const
5262 return MovePtr<TestNode>(createFuncCase(ctx, ctx.name.c_str(), m_func));
5265 string getName (void) const
5267 return de::toLower(m_func.getName());
5270 string getDesc (void) const
5272 return "Function '" + getName() + "'";
5276 const Func<Sig>& m_func;
5279 template <typename F>
5280 SharedPtr<SimpleFuncCaseFactory<typename F::Sig> > createSimpleFuncCaseFactory (void)
5282 return SharedPtr<SimpleFuncCaseFactory<typename F::Sig> >(
5283 new SimpleFuncCaseFactory<typename F::Sig>(instance<F>()));
5286 class BuiltinFuncs : public CaseFactories
5289 const vector<const CaseFactory*> getFactories (void) const
5291 vector<const CaseFactory*> ret;
5293 for (size_t ndx = 0; ndx < m_factories.size(); ++ndx)
5294 ret.push_back(m_factories[ndx].get());
5299 void addFactory (SharedPtr<const CaseFactory> fact)
5301 m_factories.push_back(fact);
5305 vector<SharedPtr<const CaseFactory> > m_factories;
5308 template <typename F>
5309 void addScalarFactory(BuiltinFuncs& funcs, string name = "")
5312 name = instance<F>().getName();
5314 funcs.addFactory(SharedPtr<const CaseFactory>(new GenFuncCaseFactory<typename F::Sig>(
5315 makeVectorizedFuncs<F>(), name)));
5318 MovePtr<const CaseFactories> createES3BuiltinCases (void)
5320 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5322 addScalarFactory<Add>(*funcs);
5323 addScalarFactory<Sub>(*funcs);
5324 addScalarFactory<Mul>(*funcs);
5325 addScalarFactory<Div>(*funcs);
5327 addScalarFactory<Radians>(*funcs);
5328 addScalarFactory<Degrees>(*funcs);
5329 addScalarFactory<Sin>(*funcs);
5330 addScalarFactory<Cos>(*funcs);
5331 addScalarFactory<Tan>(*funcs);
5332 addScalarFactory<ASin>(*funcs);
5333 addScalarFactory<ACos>(*funcs);
5334 addScalarFactory<ATan2>(*funcs, "atan2");
5335 addScalarFactory<ATan>(*funcs);
5336 addScalarFactory<Sinh>(*funcs);
5337 addScalarFactory<Cosh>(*funcs);
5338 addScalarFactory<Tanh>(*funcs);
5339 addScalarFactory<ASinh>(*funcs);
5340 addScalarFactory<ACosh>(*funcs);
5341 addScalarFactory<ATanh>(*funcs);
5343 addScalarFactory<Pow>(*funcs);
5344 addScalarFactory<Exp>(*funcs);
5345 addScalarFactory<Log>(*funcs);
5346 addScalarFactory<Exp2>(*funcs);
5347 addScalarFactory<Log2>(*funcs);
5348 addScalarFactory<Sqrt>(*funcs);
5349 addScalarFactory<InverseSqrt>(*funcs);
5351 addScalarFactory<Abs>(*funcs);
5352 addScalarFactory<Sign>(*funcs);
5353 addScalarFactory<Floor>(*funcs);
5354 addScalarFactory<Trunc>(*funcs);
5355 addScalarFactory<Round>(*funcs);
5356 addScalarFactory<RoundEven>(*funcs);
5357 addScalarFactory<Ceil>(*funcs);
5358 addScalarFactory<Fract>(*funcs);
5359 addScalarFactory<Mod>(*funcs);
5360 funcs->addFactory(createSimpleFuncCaseFactory<Modf>());
5361 addScalarFactory<Min>(*funcs);
5362 addScalarFactory<Max>(*funcs);
5363 addScalarFactory<Clamp>(*funcs);
5364 addScalarFactory<Mix>(*funcs);
5365 addScalarFactory<Step>(*funcs);
5366 addScalarFactory<SmoothStep>(*funcs);
5368 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length>()));
5369 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance>()));
5370 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot>()));
5371 funcs->addFactory(createSimpleFuncCaseFactory<Cross>());
5372 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize>()));
5373 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward>()));
5374 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect>()));
5375 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract>()));
5378 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<MatrixCompMult>()));
5379 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct>()));
5380 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose>()));
5381 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant>()));
5382 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse>()));
5384 return MovePtr<const CaseFactories>(funcs.release());
5387 MovePtr<const CaseFactories> createES31BuiltinCases (void)
5389 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5391 addScalarFactory<FrExp>(*funcs);
5392 addScalarFactory<LdExp>(*funcs);
5393 addScalarFactory<Fma>(*funcs);
5395 return MovePtr<const CaseFactories>(funcs.release());
5398 struct PrecisionTestContext
5400 PrecisionTestContext (TestContext& testCtx_,
5401 RenderContext& renderCtx_,
5402 const FloatFormat& highp_,
5403 const FloatFormat& mediump_,
5404 const FloatFormat& lowp_,
5405 const vector<ShaderType>& shaderTypes_,
5407 : testCtx (testCtx_)
5408 , renderCtx (renderCtx_)
5409 , shaderTypes (shaderTypes_)
5410 , numRandoms (numRandoms_)
5412 formats[glu::PRECISION_HIGHP] = &highp_;
5413 formats[glu::PRECISION_MEDIUMP] = &mediump_;
5414 formats[glu::PRECISION_LOWP] = &lowp_;
5417 TestContext& testCtx;
5418 RenderContext& renderCtx;
5419 const FloatFormat* formats[glu::PRECISION_LAST];
5420 vector<ShaderType> shaderTypes;
5424 TestCaseGroup* createFuncGroup (const PrecisionTestContext& ctx,
5425 const CaseFactory& factory)
5427 TestCaseGroup* const group = new TestCaseGroup(ctx.testCtx,
5428 factory.getName().c_str(),
5429 factory.getDesc().c_str());
5431 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; ++precNdx)
5433 const Precision precision = Precision(precNdx);
5434 const string precName (glu::getPrecisionName(precision));
5435 const FloatFormat& fmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats, precNdx);
5436 const FloatFormat& highpFmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats,
5437 glu::PRECISION_HIGHP);
5439 for (size_t shaderNdx = 0; shaderNdx < ctx.shaderTypes.size(); ++shaderNdx)
5441 const ShaderType shaderType = ctx.shaderTypes[shaderNdx];
5442 const string shaderName (glu::getShaderTypeName(shaderType));
5443 const string name = precName + "_" + shaderName;
5444 const Context caseCtx (name, ctx.testCtx, ctx.renderCtx, fmt, highpFmt,
5445 precision, shaderType, ctx.numRandoms);
5447 group->addChild(factory.createCase(caseCtx).release());
5454 void addBuiltinPrecisionTests (TestContext& testCtx,
5455 RenderContext& renderCtx,
5456 const CaseFactories& cases,
5457 const vector<ShaderType>& shaderTypes,
5458 TestCaseGroup& dstGroup)
5460 const int userRandoms = testCtx.getCommandLine().getTestIterationCount();
5461 const int defRandoms = 16384;
5462 const int numRandoms = userRandoms > 0 ? userRandoms : defRandoms;
5463 const FloatFormat highp (-126, 127, 23, true,
5464 tcu::MAYBE, // subnormals
5465 tcu::YES, // infinities
5467 // \todo [2014-04-01 lauri] Check these once Khronos bug 11840 is resolved.
5468 const FloatFormat mediump (-13, 13, 9, false);
5469 // A fixed-point format is just a floating point format with a fixed
5470 // exponent and support for subnormals.
5471 const FloatFormat lowp (0, 0, 7, false, tcu::YES);
5472 const PrecisionTestContext ctx (testCtx, renderCtx, highp, mediump, lowp,
5473 shaderTypes, numRandoms);
5475 for (size_t ndx = 0; ndx < cases.getFactories().size(); ++ndx)
5476 dstGroup.addChild(createFuncGroup(ctx, *cases.getFactories()[ndx]));
5479 } // BuiltinPrecisionTests