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"
61 // Uncomment this to get evaluation trace dumps to std::cerr
62 // #define GLS_ENABLE_TRACE
64 // set this to true to dump even passing results
65 #define GLS_LOG_ALL_RESULTS false
69 // Computing reference intervals can take a non-trivial amount of time, especially on
70 // platforms where toggling floating-point rounding mode is slow (emulated arm on x86).
71 // As a workaround watchdog is kept happy by touching it periodically during reference
72 // interval computation.
73 TOUCH_WATCHDOG_VALUE_FREQUENCY = 4096
80 namespace BuiltinPrecisionTests
86 using std::ostringstream;
96 using tcu::FloatFormat;
97 using tcu::MessageBuilder;
102 namespace matrix = tcu::matrix;
103 using glu::Precision;
104 using glu::RenderContext;
107 using glu::ShaderType;
108 using glu::ContextInfo;
109 using gls::ShaderExecUtil::Symbol;
111 typedef TestCase::IterateResult IterateResult;
116 /*--------------------------------------------------------------------*//*!
117 * \brief Generic singleton creator.
119 * instance<T>() returns a reference to a unique default-constructed instance
120 * of T. This is mainly used for our GLSL function implementations: each
121 * function is implemented by an object, and each of the objects has a
122 * distinct class. It would be extremely toilsome to maintain a separate
123 * context object that contained individual instances of the function classes,
124 * so we have to resort to global singleton instances.
126 *//*--------------------------------------------------------------------*/
127 template <typename T>
128 const T& instance (void)
130 static const T s_instance = T();
134 /*--------------------------------------------------------------------*//*!
135 * \brief A placeholder type for unused template parameters.
137 * In the precision tests we are dealing with functions of different arities.
138 * To minimize code duplication, we only define templates with the maximum
139 * number of arguments, currently four. If a function's arity is less than the
140 * maximum, Void us used as the type for unused arguments.
142 * Although Voids are not used at run-time, they still must be compilable, so
143 * they must support all operations that other types do.
145 *//*--------------------------------------------------------------------*/
148 typedef Void Element;
154 template <typename T>
155 explicit Void (const T&) {}
157 operator double (void) const { return TCU_NAN; }
159 // These are used to make Voids usable as containers in container-generic code.
160 Void& operator[] (int) { return *this; }
161 const Void& operator[] (int) const { return *this; }
164 ostream& operator<< (ostream& os, Void) { return os << "()"; }
166 //! Returns true for all other types except Void
167 template <typename T> bool isTypeValid (void) { return true; }
168 template <> bool isTypeValid<Void> (void) { return false; }
170 //! Utility function for getting the name of a data type.
171 //! This is used in vector and matrix constructors.
172 template <typename T>
173 const char* dataTypeNameOf (void)
175 return glu::getDataTypeName(glu::dataTypeOf<T>());
179 const char* dataTypeNameOf<Void> (void)
181 DE_FATAL("Impossible");
185 //! A hack to get Void support for VarType.
186 template <typename T>
187 VarType getVarTypeOf (Precision prec = glu::PRECISION_LAST)
189 return glu::varTypeOf<T>(prec);
193 VarType getVarTypeOf<Void> (Precision)
195 DE_FATAL("Impossible");
199 /*--------------------------------------------------------------------*//*!
200 * \brief Type traits for generalized interval types.
202 * We are trying to compute sets of acceptable values not only for
203 * float-valued expressions but also for compound values: vectors and
204 * matrices. We approximate a set of vectors as a vector of intervals and
205 * likewise for matrices.
207 * We now need generalized operations for each type and its interval
208 * approximation. These are given in the type Traits<T>.
210 * The type Traits<T>::IVal is the approximation of T: it is `Interval` for
211 * scalar types, and a vector or matrix of intervals for container types.
213 * To allow template inference to take place, there are function wrappers for
214 * the actual operations in Traits<T>. Hence we can just use:
216 * makeIVal(someFloat)
220 * Traits<float>::doMakeIVal(value)
222 *//*--------------------------------------------------------------------*/
224 template <typename T> struct Traits;
226 //! Create container from elementwise singleton values.
227 template <typename T>
228 typename Traits<T>::IVal makeIVal (const T& value)
230 return Traits<T>::doMakeIVal(value);
233 //! Elementwise union of intervals.
234 template <typename T>
235 typename Traits<T>::IVal unionIVal (const typename Traits<T>::IVal& a,
236 const typename Traits<T>::IVal& b)
238 return Traits<T>::doUnion(a, b);
241 //! Returns true iff every element of `ival` contains the corresponding element of `value`.
242 template <typename T>
243 bool contains (const typename Traits<T>::IVal& ival, const T& value)
245 return Traits<T>::doContains(ival, value);
248 //! Returns true iff every element of `ival` contains corresponding element of `value` within the warning interval
249 template <typename T>
250 bool containsWarning(const typename Traits<T>::IVal& ival, const T& value)
252 return Traits<T>::doContainsWarning(ival, value);
255 //! Print out an interval with the precision of `fmt`.
256 template <typename T>
257 void printIVal (const FloatFormat& fmt, const typename Traits<T>::IVal& ival, ostream& os)
259 Traits<T>::doPrintIVal(fmt, ival, os);
262 template <typename T>
263 string intervalToString (const FloatFormat& fmt, const typename Traits<T>::IVal& ival)
266 printIVal<T>(fmt, ival, oss);
270 //! Print out a value with the precision of `fmt`.
271 template <typename T>
272 void printValue (const FloatFormat& fmt, const T& value, ostream& os)
274 Traits<T>::doPrintValue(fmt, value, os);
277 template <typename T>
278 string valueToString (const FloatFormat& fmt, const T& val)
281 printValue(fmt, val, oss);
285 //! Approximate `value` elementwise to the float precision defined in `fmt`.
286 //! The resulting interval might not be a singleton if rounding in both
287 //! directions is allowed.
288 template <typename T>
289 typename Traits<T>::IVal round (const FloatFormat& fmt, const T& value)
291 return Traits<T>::doRound(fmt, value);
294 template <typename T>
295 typename Traits<T>::IVal convert (const FloatFormat& fmt,
296 const typename Traits<T>::IVal& value)
298 return Traits<T>::doConvert(fmt, value);
301 //! Common traits for scalar types.
302 template <typename T>
305 typedef Interval IVal;
307 static Interval doMakeIVal (const T& value)
309 // Thankfully all scalar types have a well-defined conversion to `double`,
310 // hence Interval can represent their ranges without problems.
311 return Interval(double(value));
314 static Interval doUnion (const Interval& a, const Interval& b)
319 static bool doContains (const Interval& a, T value)
321 return a.contains(double(value));
324 static bool doContainsWarning(const Interval& a, T value)
326 return a.containsWarning(double(value));
329 static Interval doConvert (const FloatFormat& fmt, const IVal& ival)
331 return fmt.convert(ival);
334 static Interval doRound (const FloatFormat& fmt, T value)
336 return fmt.roundOut(double(value), false);
341 struct Traits<float> : ScalarTraits<float>
343 static void doPrintIVal (const FloatFormat& fmt,
344 const Interval& ival,
347 os << fmt.intervalToHex(ival);
350 static void doPrintValue (const FloatFormat& fmt,
354 os << fmt.floatToHex(value);
359 struct Traits<bool> : ScalarTraits<bool>
361 static void doPrintValue (const FloatFormat&,
365 os << (value != 0.0f ? "true" : "false");
368 static void doPrintIVal (const FloatFormat&,
369 const Interval& ival,
373 if (ival.contains(false))
375 if (ival.contains(false) && ival.contains(true))
377 if (ival.contains(true))
384 struct Traits<int> : ScalarTraits<int>
386 static void doPrintValue (const FloatFormat&,
393 static void doPrintIVal (const FloatFormat&,
394 const Interval& ival,
397 os << "[" << int(ival.lo()) << ", " << int(ival.hi()) << "]";
401 //! Common traits for containers, i.e. vectors and matrices.
402 //! T is the container type itself, I is the same type with interval elements.
403 template <typename T, typename I>
404 struct ContainerTraits
406 typedef typename T::Element Element;
409 static IVal doMakeIVal (const T& value)
413 for (int ndx = 0; ndx < T::SIZE; ++ndx)
414 ret[ndx] = makeIVal(value[ndx]);
419 static IVal doUnion (const IVal& a, const IVal& b)
423 for (int ndx = 0; ndx < T::SIZE; ++ndx)
424 ret[ndx] = unionIVal<Element>(a[ndx], b[ndx]);
429 static bool doContains (const IVal& ival, const T& value)
431 for (int ndx = 0; ndx < T::SIZE; ++ndx)
432 if (!contains(ival[ndx], value[ndx]))
438 static bool doContainsWarning(const IVal& ival, const T& value)
440 for (int ndx = 0; ndx < T::SIZE; ++ndx)
441 if (!containsWarning(ival[ndx], value[ndx]))
447 static void doPrintIVal (const FloatFormat& fmt, const IVal ival, ostream& os)
451 for (int ndx = 0; ndx < T::SIZE; ++ndx)
456 printIVal<Element>(fmt, ival[ndx], os);
462 static void doPrintValue (const FloatFormat& fmt, const T& value, ostream& os)
464 os << dataTypeNameOf<T>() << "(";
466 for (int ndx = 0; ndx < T::SIZE; ++ndx)
471 printValue<Element>(fmt, value[ndx], os);
477 static IVal doConvert (const FloatFormat& fmt, const IVal& value)
481 for (int ndx = 0; ndx < T::SIZE; ++ndx)
482 ret[ndx] = convert<Element>(fmt, value[ndx]);
487 static IVal doRound (const FloatFormat& fmt, T value)
491 for (int ndx = 0; ndx < T::SIZE; ++ndx)
492 ret[ndx] = round(fmt, value[ndx]);
498 template <typename T, int Size>
499 struct Traits<Vector<T, Size> > :
500 ContainerTraits<Vector<T, Size>, Vector<typename Traits<T>::IVal, Size> >
504 template <typename T, int Rows, int Cols>
505 struct Traits<Matrix<T, Rows, Cols> > :
506 ContainerTraits<Matrix<T, Rows, Cols>, Matrix<typename Traits<T>::IVal, Rows, Cols> >
510 //! Void traits. These are just dummies, but technically valid: a Void is a
511 //! unit type with a single possible value.
517 static Void doMakeIVal (const Void& value) { return value; }
518 static Void doUnion (const Void&, const Void&) { return Void(); }
519 static bool doContains (const Void&, Void) { return true; }
520 static bool doContainsWarning (const Void&, Void) { return true; }
521 static Void doRound (const FloatFormat&, const Void& value) { return value; }
522 static Void doConvert (const FloatFormat&, const Void& value) { return value; }
524 static void doPrintValue (const FloatFormat&, const Void&, ostream& os)
529 static void doPrintIVal (const FloatFormat&, const Void&, ostream& os)
535 //! This is needed for container-generic operations.
536 //! We want a scalar type T to be its own "one-element vector".
537 template <typename T, int Size> struct ContainerOf { typedef Vector<T, Size> Container; };
539 template <typename T> struct ContainerOf<T, 1> { typedef T Container; };
540 template <int Size> struct ContainerOf<Void, Size> { typedef Void Container; };
542 // This is a kludge that is only needed to get the ExprP::operator[] syntactic sugar to work.
543 template <typename T> struct ElementOf { typedef typename T::Element Element; };
544 template <> struct ElementOf<float> { typedef void Element; };
545 template <> struct ElementOf<bool> { typedef void Element; };
546 template <> struct ElementOf<int> { typedef void Element; };
548 /*--------------------------------------------------------------------*//*!
550 * \name Abstract syntax for expressions and statements.
552 * We represent GLSL programs as syntax objects: an Expr<T> represents an
553 * expression whose GLSL type corresponds to the C++ type T, and a Statement
554 * represents a statement.
556 * To ease memory management, we use shared pointers to refer to expressions
557 * and statements. ExprP<T> is a shared pointer to an Expr<T>, and StatementP
558 * is a shared pointer to a Statement.
562 *//*--------------------------------------------------------------------*/
569 template <typename T> class ExprP;
570 template <typename T> class Variable;
571 template <typename T> class VariableP;
572 template <typename T> class DefaultSampling;
574 typedef set<const FuncBase*> FuncSet;
576 template <typename T>
577 VariableP<T> variable (const string& name);
578 StatementP compoundStatement (const vector<StatementP>& statements);
580 /*--------------------------------------------------------------------*//*!
581 * \brief A variable environment.
583 * An Environment object maintains the mapping between variables of the
584 * abstract syntax tree and their values.
586 * \todo [2014-03-28 lauri] At least run-time type safety.
588 *//*--------------------------------------------------------------------*/
593 void bind (const Variable<T>& variable,
594 const typename Traits<T>::IVal& value)
596 deUint8* const data = new deUint8[sizeof(value)];
598 deMemcpy(data, &value, sizeof(value));
599 de::insert(m_map, variable.getName(), SharedPtr<deUint8>(data, de::ArrayDeleter<deUint8>()));
603 typename Traits<T>::IVal& lookup (const Variable<T>& variable) const
605 deUint8* const data = de::lookup(m_map, variable.getName()).get();
607 return *reinterpret_cast<typename Traits<T>::IVal*>(data);
611 map<string, SharedPtr<deUint8> > m_map;
614 /*--------------------------------------------------------------------*//*!
615 * \brief Evaluation context.
617 * The evaluation context contains everything that separates one execution of
618 * an expression from the next. Currently this means the desired floating
619 * point precision and the current variable environment.
621 *//*--------------------------------------------------------------------*/
624 EvalContext (const FloatFormat& format_,
625 Precision floatPrecision_,
629 , floatPrecision (floatPrecision_)
631 , callDepth (callDepth_) {}
634 Precision floatPrecision;
639 /*--------------------------------------------------------------------*//*!
640 * \brief Simple incremental counter.
642 * This is used to make sure that different ExpandContexts will not produce
643 * overlapping temporary names.
645 *//*--------------------------------------------------------------------*/
649 Counter (int count = 0) : m_count(count) {}
650 int operator() (void) { return m_count++; }
656 /*--------------------------------------------------------------------*//*!
657 * \brief A statement or declaration.
659 * Statements have no values. Instead, they are executed for their side
660 * effects only: the execute() method should modify at least one variable in
663 * As a bit of a kludge, a Statement object can also represent a declaration:
664 * when it is evaluated, it can add a variable binding to the environment
665 * instead of modifying a current one.
667 *//*--------------------------------------------------------------------*/
671 virtual ~Statement (void) { }
672 //! Execute the statement, modifying the environment of `ctx`
673 void execute (EvalContext& ctx) const { this->doExecute(ctx); }
674 void print (ostream& os) const { this->doPrint(os); }
675 //! Add the functions used in this statement to `dst`.
676 void getUsedFuncs (FuncSet& dst) const { this->doGetUsedFuncs(dst); }
679 virtual void doPrint (ostream& os) const = 0;
680 virtual void doExecute (EvalContext& ctx) const = 0;
681 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
684 ostream& operator<<(ostream& os, const Statement& stmt)
690 /*--------------------------------------------------------------------*//*!
691 * \brief Smart pointer for statements (and declarations)
693 *//*--------------------------------------------------------------------*/
694 class StatementP : public SharedPtr<const Statement>
697 typedef SharedPtr<const Statement> Super;
700 explicit StatementP (const Statement* ptr) : Super(ptr) {}
701 StatementP (const Super& ptr) : Super(ptr) {}
707 ExpandContext (Counter& symCounter) : m_symCounter(symCounter) {}
708 ExpandContext (const ExpandContext& parent)
709 : m_symCounter(parent.m_symCounter) {}
712 VariableP<T> genSym (const string& baseName)
714 return variable<T>(baseName + de::toString(m_symCounter()));
717 void addStatement (const StatementP& stmt)
719 m_statements.push_back(stmt);
722 vector<StatementP> getStatements (void) const
727 Counter& m_symCounter;
728 vector<StatementP> m_statements;
731 /*--------------------------------------------------------------------*//*!
734 * A statement that modifies a variable or a declaration that binds a variable.
736 *//*--------------------------------------------------------------------*/
737 template <typename T>
738 class VariableStatement : public Statement
741 VariableStatement (const VariableP<T>& variable, const ExprP<T>& value,
743 : m_variable (variable)
745 , m_isDeclaration (isDeclaration) {}
748 void doPrint (ostream& os) const
751 os << glu::declare(getVarTypeOf<T>(), m_variable->getName());
753 os << m_variable->getName();
755 os << " = " << *m_value << ";\n";
758 void doExecute (EvalContext& ctx) const
761 ctx.env.bind(*m_variable, m_value->evaluate(ctx));
763 ctx.env.lookup(*m_variable) = m_value->evaluate(ctx);
766 void doGetUsedFuncs (FuncSet& dst) const
768 m_value->getUsedFuncs(dst);
771 VariableP<T> m_variable;
773 bool m_isDeclaration;
776 template <typename T>
777 StatementP variableStatement (const VariableP<T>& variable,
778 const ExprP<T>& value,
781 return StatementP(new VariableStatement<T>(variable, value, isDeclaration));
784 template <typename T>
785 StatementP variableDeclaration (const VariableP<T>& variable, const ExprP<T>& definiens)
787 return variableStatement(variable, definiens, true);
790 template <typename T>
791 StatementP variableAssignment (const VariableP<T>& variable, const ExprP<T>& value)
793 return variableStatement(variable, value, false);
796 /*--------------------------------------------------------------------*//*!
797 * \brief A compound statement, i.e. a block.
799 * A compound statement is executed by executing its constituent statements in
802 *//*--------------------------------------------------------------------*/
803 class CompoundStatement : public Statement
806 CompoundStatement (const vector<StatementP>& statements)
807 : m_statements (statements) {}
810 void doPrint (ostream& os) const
814 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
815 os << *m_statements[ndx];
820 void doExecute (EvalContext& ctx) const
822 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
823 m_statements[ndx]->execute(ctx);
826 void doGetUsedFuncs (FuncSet& dst) const
828 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
829 m_statements[ndx]->getUsedFuncs(dst);
832 vector<StatementP> m_statements;
835 StatementP compoundStatement(const vector<StatementP>& statements)
837 return StatementP(new CompoundStatement(statements));
840 //! Common base class for all expressions regardless of their type.
844 virtual ~ExprBase (void) {}
845 void printExpr (ostream& os) const { this->doPrintExpr(os); }
847 //! Output the functions that this expression refers to
848 void getUsedFuncs (FuncSet& dst) const
850 this->doGetUsedFuncs(dst);
854 virtual void doPrintExpr (ostream&) const {}
855 virtual void doGetUsedFuncs (FuncSet&) const {}
858 //! Type-specific operations for an expression representing type T.
859 template <typename T>
860 class Expr : public ExprBase
864 typedef typename Traits<T>::IVal IVal;
866 IVal evaluate (const EvalContext& ctx) const;
869 virtual IVal doEvaluate (const EvalContext& ctx) const = 0;
872 //! Evaluate an expression with the given context, optionally tracing the calls to stderr.
873 template <typename T>
874 typename Traits<T>::IVal Expr<T>::evaluate (const EvalContext& ctx) const
876 #ifdef GLS_ENABLE_TRACE
877 static const FloatFormat highpFmt (-126, 127, 23, true,
881 EvalContext newCtx (ctx.format, ctx.floatPrecision,
882 ctx.env, ctx.callDepth + 1);
883 const IVal ret = this->doEvaluate(newCtx);
885 if (isTypeValid<T>())
887 std::cerr << string(ctx.callDepth, ' ');
888 this->printExpr(std::cerr);
889 std::cerr << " -> " << intervalToString<T>(highpFmt, ret) << std::endl;
893 return this->doEvaluate(ctx);
897 template <typename T>
898 class ExprPBase : public SharedPtr<const Expr<T> >
903 ostream& operator<< (ostream& os, const ExprBase& expr)
909 /*--------------------------------------------------------------------*//*!
910 * \brief Shared pointer to an expression of a container type.
912 * Container types (i.e. vectors and matrices) support the subscription
913 * operator. This class provides a bit of syntactic sugar to allow us to use
914 * the C++ subscription operator to create a subscription expression.
915 *//*--------------------------------------------------------------------*/
916 template <typename T>
917 class ContainerExprPBase : public ExprPBase<T>
920 ExprP<typename T::Element> operator[] (int i) const;
923 template <typename T>
924 class ExprP : public ExprPBase<T> {};
926 // We treat Voids as containers since the unused parameters in generalized
927 // vector functions are represented as Voids.
929 class ExprP<Void> : public ContainerExprPBase<Void> {};
931 template <typename T, int Size>
932 class ExprP<Vector<T, Size> > : public ContainerExprPBase<Vector<T, Size> > {};
934 template <typename T, int Rows, int Cols>
935 class ExprP<Matrix<T, Rows, Cols> > : public ContainerExprPBase<Matrix<T, Rows, Cols> > {};
937 template <typename T> ExprP<T> exprP (void)
942 template <typename T>
943 ExprP<T> exprP (const SharedPtr<const Expr<T> >& ptr)
946 static_cast<SharedPtr<const Expr<T> >&>(ret) = ptr;
950 template <typename T>
951 ExprP<T> exprP (const Expr<T>* ptr)
953 return exprP(SharedPtr<const Expr<T> >(ptr));
956 /*--------------------------------------------------------------------*//*!
957 * \brief A shared pointer to a variable expression.
959 * This is just a narrowing of ExprP for the operations that require a variable
960 * instead of an arbitrary expression.
962 *//*--------------------------------------------------------------------*/
963 template <typename T>
964 class VariableP : public SharedPtr<const Variable<T> >
967 typedef SharedPtr<const Variable<T> > Super;
968 explicit VariableP (const Variable<T>* ptr) : Super(ptr) {}
970 VariableP (const Super& ptr) : Super(ptr) {}
972 operator ExprP<T> (void) const { return exprP(SharedPtr<const Expr<T> >(*this)); }
975 /*--------------------------------------------------------------------*//*!
976 * \name Syntactic sugar operators for expressions.
980 * These operators allow the use of C++ syntax to construct GLSL expressions
981 * containing operators: e.g. "a+b" creates an addition expression with
982 * operands a and b, and so on.
984 *//*--------------------------------------------------------------------*/
985 ExprP<float> operator-(const ExprP<float>& arg0);
986 ExprP<float> operator+(const ExprP<float>& arg0,
987 const ExprP<float>& arg1);
988 ExprP<float> operator-(const ExprP<float>& arg0,
989 const ExprP<float>& arg1);
990 ExprP<float> operator*(const ExprP<float>& arg0,
991 const ExprP<float>& arg1);
992 ExprP<float> operator/(const ExprP<float>& arg0,
993 const ExprP<float>& arg1);
995 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0);
997 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
998 const ExprP<float>& arg1);
1000 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
1001 const ExprP<Vector<float, Size> >& arg1);
1003 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
1004 const ExprP<Vector<float, Size> >& arg1);
1005 template<int Left, int Mid, int Right>
1006 ExprP<Matrix<float, Left, Right> > operator* (const ExprP<Matrix<float, Left, Mid> >& left,
1007 const ExprP<Matrix<float, Mid, Right> >& right);
1008 template<int Rows, int Cols>
1009 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
1010 const ExprP<Matrix<float, Rows, Cols> >& right);
1011 template<int Rows, int Cols>
1012 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
1013 const ExprP<Vector<float, Rows> >& right);
1014 template<int Rows, int Cols>
1015 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
1016 const ExprP<float>& right);
1017 template<int Rows, int Cols>
1018 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
1019 const ExprP<Matrix<float, Rows, Cols> >& right);
1020 template<int Rows, int Cols>
1021 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat);
1025 /*--------------------------------------------------------------------*//*!
1026 * \brief Variable expression.
1028 * A variable is evaluated by looking up its range of possible values from an
1030 *//*--------------------------------------------------------------------*/
1031 template <typename T>
1032 class Variable : public Expr<T>
1035 typedef typename Expr<T>::IVal IVal;
1037 Variable (const string& name) : m_name (name) {}
1038 string getName (void) const { return m_name; }
1041 void doPrintExpr (ostream& os) const { os << m_name; }
1042 IVal doEvaluate (const EvalContext& ctx) const
1044 return ctx.env.lookup<T>(*this);
1051 template <typename T>
1052 VariableP<T> variable (const string& name)
1054 return VariableP<T>(new Variable<T>(name));
1057 template <typename T>
1058 VariableP<T> bindExpression (const string& name, ExpandContext& ctx, const ExprP<T>& expr)
1060 VariableP<T> var = ctx.genSym<T>(name);
1061 ctx.addStatement(variableDeclaration(var, expr));
1065 /*--------------------------------------------------------------------*//*!
1066 * \brief Constant expression.
1068 * A constant is evaluated by rounding it to a set of possible values allowed
1069 * by the current floating point precision.
1070 *//*--------------------------------------------------------------------*/
1071 template <typename T>
1072 class Constant : public Expr<T>
1075 typedef typename Expr<T>::IVal IVal;
1077 Constant (const T& value) : m_value(value) {}
1080 void doPrintExpr (ostream& os) const { os << m_value; }
1081 IVal doEvaluate (const EvalContext&) const { return makeIVal(m_value); }
1087 template <typename T>
1088 ExprP<T> constant (const T& value)
1090 return exprP(new Constant<T>(value));
1093 //! Return a reference to a singleton void constant.
1094 const ExprP<Void>& voidP (void)
1096 static const ExprP<Void> singleton = constant(Void());
1101 /*--------------------------------------------------------------------*//*!
1102 * \brief Four-element tuple.
1104 * This is used for various things where we need one thing for each possible
1105 * function parameter. Currently the maximum supported number of parameters is
1107 *//*--------------------------------------------------------------------*/
1108 template <typename T0 = Void, typename T1 = Void, typename T2 = Void, typename T3 = Void>
1111 explicit Tuple4 (const T0 e0 = T0(),
1128 /*--------------------------------------------------------------------*//*!
1129 * \brief Function signature.
1131 * This is a purely compile-time structure used to bundle all types in a
1132 * function signature together. This makes passing the signature around in
1133 * templates easier, since we only need to take and pass a single Sig instead
1134 * of a bunch of parameter types and a return type.
1136 *//*--------------------------------------------------------------------*/
1137 template <typename R,
1138 typename P0 = Void, typename P1 = Void,
1139 typename P2 = Void, typename P3 = Void>
1147 typedef typename Traits<Ret>::IVal IRet;
1148 typedef typename Traits<Arg0>::IVal IArg0;
1149 typedef typename Traits<Arg1>::IVal IArg1;
1150 typedef typename Traits<Arg2>::IVal IArg2;
1151 typedef typename Traits<Arg3>::IVal IArg3;
1153 typedef Tuple4< const Arg0&, const Arg1&, const Arg2&, const Arg3&> Args;
1154 typedef Tuple4< const IArg0&, const IArg1&, const IArg2&, const IArg3&> IArgs;
1155 typedef Tuple4< ExprP<Arg0>, ExprP<Arg1>, ExprP<Arg2>, ExprP<Arg3> > ArgExprs;
1158 typedef vector<const ExprBase*> BaseArgExprs;
1160 /*--------------------------------------------------------------------*//*!
1161 * \brief Type-independent operations for function objects.
1163 *//*--------------------------------------------------------------------*/
1167 virtual ~FuncBase (void) {}
1168 virtual string getName (void) const = 0;
1169 //! Name of extension that this function requires, or empty.
1170 virtual string getRequiredExtension (const RenderContext &) const { return ""; }
1171 virtual void print (ostream&,
1172 const BaseArgExprs&) const = 0;
1173 //! Index of output parameter, or -1 if none of the parameters is output.
1174 virtual int getOutParamIndex (void) const { return -1; }
1176 void printDefinition (ostream& os) const
1178 doPrintDefinition(os);
1181 void getUsedFuncs (FuncSet& dst) const
1183 this->doGetUsedFuncs(dst);
1187 virtual void doPrintDefinition (ostream& os) const = 0;
1188 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
1191 typedef Tuple4<string, string, string, string> ParamNames;
1193 /*--------------------------------------------------------------------*//*!
1194 * \brief Function objects.
1196 * Each Func object represents a GLSL function. It can be applied to interval
1197 * arguments, and it returns the an interval that is a conservative
1198 * approximation of the image of the GLSL function over the argument
1199 * intervals. That is, it is given a set of possible arguments and it returns
1200 * the set of possible values.
1202 *//*--------------------------------------------------------------------*/
1203 template <typename Sig_>
1204 class Func : public FuncBase
1208 typedef typename Sig::Ret Ret;
1209 typedef typename Sig::Arg0 Arg0;
1210 typedef typename Sig::Arg1 Arg1;
1211 typedef typename Sig::Arg2 Arg2;
1212 typedef typename Sig::Arg3 Arg3;
1213 typedef typename Sig::IRet IRet;
1214 typedef typename Sig::IArg0 IArg0;
1215 typedef typename Sig::IArg1 IArg1;
1216 typedef typename Sig::IArg2 IArg2;
1217 typedef typename Sig::IArg3 IArg3;
1218 typedef typename Sig::Args Args;
1219 typedef typename Sig::IArgs IArgs;
1220 typedef typename Sig::ArgExprs ArgExprs;
1222 void print (ostream& os,
1223 const BaseArgExprs& args) const
1225 this->doPrint(os, args);
1228 IRet apply (const EvalContext& ctx,
1229 const IArg0& arg0 = IArg0(),
1230 const IArg1& arg1 = IArg1(),
1231 const IArg2& arg2 = IArg2(),
1232 const IArg3& arg3 = IArg3()) const
1234 return this->applyArgs(ctx, IArgs(arg0, arg1, arg2, arg3));
1236 IRet applyArgs (const EvalContext& ctx,
1237 const IArgs& args) const
1239 return this->doApply(ctx, args);
1241 ExprP<Ret> operator() (const ExprP<Arg0>& arg0 = voidP(),
1242 const ExprP<Arg1>& arg1 = voidP(),
1243 const ExprP<Arg2>& arg2 = voidP(),
1244 const ExprP<Arg3>& arg3 = voidP()) const;
1246 const ParamNames& getParamNames (void) const
1248 return this->doGetParamNames();
1252 virtual IRet doApply (const EvalContext&,
1253 const IArgs&) const = 0;
1254 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1256 os << getName() << "(";
1258 if (isTypeValid<Arg0>())
1261 if (isTypeValid<Arg1>())
1262 os << ", " << *args[1];
1264 if (isTypeValid<Arg2>())
1265 os << ", " << *args[2];
1267 if (isTypeValid<Arg3>())
1268 os << ", " << *args[3];
1273 virtual const ParamNames& doGetParamNames (void) const
1275 static ParamNames names ("a", "b", "c", "d");
1280 template <typename Sig>
1281 class Apply : public Expr<typename Sig::Ret>
1284 typedef typename Sig::Ret Ret;
1285 typedef typename Sig::Arg0 Arg0;
1286 typedef typename Sig::Arg1 Arg1;
1287 typedef typename Sig::Arg2 Arg2;
1288 typedef typename Sig::Arg3 Arg3;
1289 typedef typename Expr<Ret>::Val Val;
1290 typedef typename Expr<Ret>::IVal IVal;
1291 typedef Func<Sig> ApplyFunc;
1292 typedef typename ApplyFunc::ArgExprs ArgExprs;
1294 Apply (const ApplyFunc& func,
1295 const ExprP<Arg0>& arg0 = voidP(),
1296 const ExprP<Arg1>& arg1 = voidP(),
1297 const ExprP<Arg2>& arg2 = voidP(),
1298 const ExprP<Arg3>& arg3 = voidP())
1300 m_args (arg0, arg1, arg2, arg3) {}
1302 Apply (const ApplyFunc& func,
1303 const ArgExprs& args)
1307 void doPrintExpr (ostream& os) const
1310 args.push_back(m_args.a.get());
1311 args.push_back(m_args.b.get());
1312 args.push_back(m_args.c.get());
1313 args.push_back(m_args.d.get());
1314 m_func.print(os, args);
1317 IVal doEvaluate (const EvalContext& ctx) const
1319 return m_func.apply(ctx,
1320 m_args.a->evaluate(ctx), m_args.b->evaluate(ctx),
1321 m_args.c->evaluate(ctx), m_args.d->evaluate(ctx));
1324 void doGetUsedFuncs (FuncSet& dst) const
1326 m_func.getUsedFuncs(dst);
1327 m_args.a->getUsedFuncs(dst);
1328 m_args.b->getUsedFuncs(dst);
1329 m_args.c->getUsedFuncs(dst);
1330 m_args.d->getUsedFuncs(dst);
1333 const ApplyFunc& m_func;
1337 template<typename T>
1338 class Alternatives : public Func<Signature<T, T, T> >
1341 typedef typename Alternatives::Sig Sig;
1344 typedef typename Alternatives::IRet IRet;
1345 typedef typename Alternatives::IArgs IArgs;
1347 virtual string getName (void) const { return "alternatives"; }
1348 virtual void doPrintDefinition (std::ostream&) const {}
1349 void doGetUsedFuncs (FuncSet&) const {}
1351 virtual IRet doApply (const EvalContext&, const IArgs& args) const
1353 return unionIVal<T>(args.a, args.b);
1356 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1358 os << "{" << *args[0] << " | " << *args[1] << "}";
1362 template <typename Sig>
1363 ExprP<typename Sig::Ret> createApply (const Func<Sig>& func,
1364 const typename Func<Sig>::ArgExprs& args)
1366 return exprP(new Apply<Sig>(func, args));
1369 template <typename Sig>
1370 ExprP<typename Sig::Ret> createApply (
1371 const Func<Sig>& func,
1372 const ExprP<typename Sig::Arg0>& arg0 = voidP(),
1373 const ExprP<typename Sig::Arg1>& arg1 = voidP(),
1374 const ExprP<typename Sig::Arg2>& arg2 = voidP(),
1375 const ExprP<typename Sig::Arg3>& arg3 = voidP())
1377 return exprP(new Apply<Sig>(func, arg0, arg1, arg2, arg3));
1380 template <typename Sig>
1381 ExprP<typename Sig::Ret> Func<Sig>::operator() (const ExprP<typename Sig::Arg0>& arg0,
1382 const ExprP<typename Sig::Arg1>& arg1,
1383 const ExprP<typename Sig::Arg2>& arg2,
1384 const ExprP<typename Sig::Arg3>& arg3) const
1386 return createApply(*this, arg0, arg1, arg2, arg3);
1389 template <typename F>
1390 ExprP<typename F::Ret> app (const ExprP<typename F::Arg0>& arg0 = voidP(),
1391 const ExprP<typename F::Arg1>& arg1 = voidP(),
1392 const ExprP<typename F::Arg2>& arg2 = voidP(),
1393 const ExprP<typename F::Arg3>& arg3 = voidP())
1395 return createApply(instance<F>(), arg0, arg1, arg2, arg3);
1398 template <typename F>
1399 typename F::IRet call (const EvalContext& ctx,
1400 const typename F::IArg0& arg0 = Void(),
1401 const typename F::IArg1& arg1 = Void(),
1402 const typename F::IArg2& arg2 = Void(),
1403 const typename F::IArg3& arg3 = Void())
1405 return instance<F>().apply(ctx, arg0, arg1, arg2, arg3);
1408 template <typename T>
1409 ExprP<T> alternatives (const ExprP<T>& arg0,
1410 const ExprP<T>& arg1)
1412 return createApply<typename Alternatives<T>::Sig>(instance<Alternatives<T> >(), arg0, arg1);
1415 template <typename Sig>
1416 class ApplyVar : public Apply<Sig>
1419 typedef typename Sig::Ret Ret;
1420 typedef typename Sig::Arg0 Arg0;
1421 typedef typename Sig::Arg1 Arg1;
1422 typedef typename Sig::Arg2 Arg2;
1423 typedef typename Sig::Arg3 Arg3;
1424 typedef typename Expr<Ret>::Val Val;
1425 typedef typename Expr<Ret>::IVal IVal;
1426 typedef Func<Sig> ApplyFunc;
1427 typedef typename ApplyFunc::ArgExprs ArgExprs;
1429 ApplyVar (const ApplyFunc& func,
1430 const VariableP<Arg0>& arg0,
1431 const VariableP<Arg1>& arg1,
1432 const VariableP<Arg2>& arg2,
1433 const VariableP<Arg3>& arg3)
1434 : Apply<Sig> (func, arg0, arg1, arg2, arg3) {}
1436 IVal doEvaluate (const EvalContext& ctx) const
1438 const Variable<Arg0>& var0 = static_cast<const Variable<Arg0>&>(*this->m_args.a);
1439 const Variable<Arg1>& var1 = static_cast<const Variable<Arg1>&>(*this->m_args.b);
1440 const Variable<Arg2>& var2 = static_cast<const Variable<Arg2>&>(*this->m_args.c);
1441 const Variable<Arg3>& var3 = static_cast<const Variable<Arg3>&>(*this->m_args.d);
1442 return this->m_func.apply(ctx,
1443 ctx.env.lookup(var0), ctx.env.lookup(var1),
1444 ctx.env.lookup(var2), ctx.env.lookup(var3));
1448 template <typename Sig>
1449 ExprP<typename Sig::Ret> applyVar (const Func<Sig>& func,
1450 const VariableP<typename Sig::Arg0>& arg0,
1451 const VariableP<typename Sig::Arg1>& arg1,
1452 const VariableP<typename Sig::Arg2>& arg2,
1453 const VariableP<typename Sig::Arg3>& arg3)
1455 return exprP(new ApplyVar<Sig>(func, arg0, arg1, arg2, arg3));
1458 template <typename Sig_>
1459 class DerivedFunc : public Func<Sig_>
1462 typedef typename DerivedFunc::ArgExprs ArgExprs;
1463 typedef typename DerivedFunc::IRet IRet;
1464 typedef typename DerivedFunc::IArgs IArgs;
1465 typedef typename DerivedFunc::Ret Ret;
1466 typedef typename DerivedFunc::Arg0 Arg0;
1467 typedef typename DerivedFunc::Arg1 Arg1;
1468 typedef typename DerivedFunc::Arg2 Arg2;
1469 typedef typename DerivedFunc::Arg3 Arg3;
1470 typedef typename DerivedFunc::IArg0 IArg0;
1471 typedef typename DerivedFunc::IArg1 IArg1;
1472 typedef typename DerivedFunc::IArg2 IArg2;
1473 typedef typename DerivedFunc::IArg3 IArg3;
1476 void doPrintDefinition (ostream& os) const
1478 const ParamNames& paramNames = this->getParamNames();
1482 os << dataTypeNameOf<Ret>() << " " << this->getName()
1484 if (isTypeValid<Arg0>())
1485 os << dataTypeNameOf<Arg0>() << " " << paramNames.a;
1486 if (isTypeValid<Arg1>())
1487 os << ", " << dataTypeNameOf<Arg1>() << " " << paramNames.b;
1488 if (isTypeValid<Arg2>())
1489 os << ", " << dataTypeNameOf<Arg2>() << " " << paramNames.c;
1490 if (isTypeValid<Arg3>())
1491 os << ", " << dataTypeNameOf<Arg3>() << " " << paramNames.d;
1494 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1496 os << "return " << *m_ret << ";\n";
1500 IRet doApply (const EvalContext& ctx,
1501 const IArgs& args) const
1504 IArgs& mutArgs = const_cast<IArgs&>(args);
1509 funEnv.bind(*m_var0, args.a);
1510 funEnv.bind(*m_var1, args.b);
1511 funEnv.bind(*m_var2, args.c);
1512 funEnv.bind(*m_var3, args.d);
1515 EvalContext funCtx(ctx.format, ctx.floatPrecision, funEnv, ctx.callDepth);
1517 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1518 m_body[ndx]->execute(funCtx);
1520 ret = m_ret->evaluate(funCtx);
1523 // \todo [lauri] Store references instead of values in environment
1524 const_cast<IArg0&>(mutArgs.a) = funEnv.lookup(*m_var0);
1525 const_cast<IArg1&>(mutArgs.b) = funEnv.lookup(*m_var1);
1526 const_cast<IArg2&>(mutArgs.c) = funEnv.lookup(*m_var2);
1527 const_cast<IArg3&>(mutArgs.d) = funEnv.lookup(*m_var3);
1532 void doGetUsedFuncs (FuncSet& dst) const
1535 if (dst.insert(this).second)
1537 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1538 m_body[ndx]->getUsedFuncs(dst);
1539 m_ret->getUsedFuncs(dst);
1543 virtual ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args_) const = 0;
1545 // These are transparently initialized when first needed. They cannot be
1546 // initialized in the constructor because they depend on the doExpand
1547 // method of the subclass.
1549 mutable VariableP<Arg0> m_var0;
1550 mutable VariableP<Arg1> m_var1;
1551 mutable VariableP<Arg2> m_var2;
1552 mutable VariableP<Arg3> m_var3;
1553 mutable vector<StatementP> m_body;
1554 mutable ExprP<Ret> m_ret;
1558 void initialize (void) const
1562 const ParamNames& paramNames = this->getParamNames();
1564 ExpandContext ctx (symCounter);
1567 args.a = m_var0 = variable<Arg0>(paramNames.a);
1568 args.b = m_var1 = variable<Arg1>(paramNames.b);
1569 args.c = m_var2 = variable<Arg2>(paramNames.c);
1570 args.d = m_var3 = variable<Arg3>(paramNames.d);
1572 m_ret = this->doExpand(ctx, args);
1573 m_body = ctx.getStatements();
1578 template <typename Sig>
1579 class PrimitiveFunc : public Func<Sig>
1582 typedef typename PrimitiveFunc::Ret Ret;
1583 typedef typename PrimitiveFunc::ArgExprs ArgExprs;
1586 void doPrintDefinition (ostream&) const {}
1587 void doGetUsedFuncs (FuncSet&) const {}
1590 template <typename T>
1591 class Cond : public PrimitiveFunc<Signature<T, bool, T, T> >
1594 typedef typename Cond::IArgs IArgs;
1595 typedef typename Cond::IRet IRet;
1597 string getName (void) const
1604 void doPrint (ostream& os, const BaseArgExprs& args) const
1606 os << "(" << *args[0] << " ? " << *args[1] << " : " << *args[2] << ")";
1609 IRet doApply (const EvalContext&, const IArgs& iargs)const
1613 if (iargs.a.contains(true))
1614 ret = unionIVal<T>(ret, iargs.b);
1616 if (iargs.a.contains(false))
1617 ret = unionIVal<T>(ret, iargs.c);
1623 template <typename T>
1624 class CompareOperator : public PrimitiveFunc<Signature<bool, T, T> >
1627 typedef typename CompareOperator::IArgs IArgs;
1628 typedef typename CompareOperator::IArg0 IArg0;
1629 typedef typename CompareOperator::IArg1 IArg1;
1630 typedef typename CompareOperator::IRet IRet;
1633 void doPrint (ostream& os, const BaseArgExprs& args) const
1635 os << "(" << *args[0] << getSymbol() << *args[1] << ")";
1638 Interval doApply (const EvalContext&, const IArgs& iargs) const
1640 const IArg0& arg0 = iargs.a;
1641 const IArg1& arg1 = iargs.b;
1644 if (canSucceed(arg0, arg1))
1646 if (canFail(arg0, arg1))
1652 virtual string getSymbol (void) const = 0;
1653 virtual bool canSucceed (const IArg0&, const IArg1&) const = 0;
1654 virtual bool canFail (const IArg0&, const IArg1&) const = 0;
1657 template <typename T>
1658 class LessThan : public CompareOperator<T>
1661 string getName (void) const { return "lessThan"; }
1664 string getSymbol (void) const { return "<"; }
1666 bool canSucceed (const Interval& a, const Interval& b) const
1668 return (a.lo() < b.hi());
1671 bool canFail (const Interval& a, const Interval& b) const
1673 return !(a.hi() < b.lo());
1677 template <typename T>
1678 ExprP<bool> operator< (const ExprP<T>& a, const ExprP<T>& b)
1680 return app<LessThan<T> >(a, b);
1683 template <typename T>
1684 ExprP<T> cond (const ExprP<bool>& test,
1685 const ExprP<T>& consequent,
1686 const ExprP<T>& alternative)
1688 return app<Cond<T> >(test, consequent, alternative);
1691 /*--------------------------------------------------------------------*//*!
1695 *//*--------------------------------------------------------------------*/
1697 class FloatFunc1 : public PrimitiveFunc<Signature<float, float> >
1700 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1702 return this->applyMonotone(ctx, iargs.a);
1705 Interval applyMonotone (const EvalContext& ctx, const Interval& iarg0) const
1709 TCU_INTERVAL_APPLY_MONOTONE1(ret, arg0, iarg0, val,
1710 TCU_SET_INTERVAL(val, point,
1711 point = this->applyPoint(ctx, arg0)));
1713 ret |= innerExtrema(ctx, iarg0);
1714 ret &= (this->getCodomain() | TCU_NAN);
1716 return ctx.format.convert(ret);
1719 virtual Interval innerExtrema (const EvalContext&, const Interval&) const
1721 return Interval(); // empty interval, i.e. no extrema
1724 virtual Interval applyPoint (const EvalContext& ctx, double arg0) const
1726 const double exact = this->applyExact(arg0);
1727 const double prec = this->precision(ctx, exact, arg0);
1728 const double wprec = this->warningPrecision(ctx, exact, arg0);
1729 Interval ioutput = exact + Interval(-prec, prec);
1730 ioutput.warning(exact - wprec, exact + wprec);
1734 virtual double applyExact (double) const
1736 TCU_THROW(InternalError, "Cannot apply");
1739 virtual Interval getCodomain (void) const
1741 return Interval::unbounded(true);
1744 virtual double precision (const EvalContext& ctx, double, double) const = 0;
1746 virtual double warningPrecision (const EvalContext& ctx, double exact, double arg0) const
1748 return precision(ctx, exact, arg0);
1753 class CFloatFunc1 : public FloatFunc1
1756 CFloatFunc1 (const string& name, DoubleFunc1& func)
1757 : m_name(name), m_func(func) {}
1759 string getName (void) const { return m_name; }
1762 double applyExact (double x) const { return m_func(x); }
1764 const string m_name;
1765 DoubleFunc1& m_func;
1768 class FloatFunc2 : public PrimitiveFunc<Signature<float, float, float> >
1771 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1773 return this->applyMonotone(ctx, iargs.a, iargs.b);
1776 Interval applyMonotone (const EvalContext& ctx,
1778 const Interval& yi) const
1782 TCU_INTERVAL_APPLY_MONOTONE2(reti, x, xi, y, yi, ret,
1783 TCU_SET_INTERVAL(ret, point,
1784 point = this->applyPoint(ctx, x, y)));
1785 reti |= innerExtrema(ctx, xi, yi);
1786 reti &= (this->getCodomain() | TCU_NAN);
1788 return ctx.format.convert(reti);
1791 virtual Interval innerExtrema (const EvalContext&,
1793 const Interval&) const
1795 return Interval(); // empty interval, i.e. no extrema
1798 virtual Interval applyPoint (const EvalContext& ctx,
1802 const double exact = this->applyExact(x, y);
1803 const double prec = this->precision(ctx, exact, x, y);
1805 return exact + Interval(-prec, prec);
1808 virtual double applyExact (double, double) const
1810 TCU_THROW(InternalError, "Cannot apply");
1813 virtual Interval getCodomain (void) const
1815 return Interval::unbounded(true);
1818 virtual double precision (const EvalContext& ctx,
1821 double y) const = 0;
1824 class CFloatFunc2 : public FloatFunc2
1827 CFloatFunc2 (const string& name,
1834 string getName (void) const { return m_name; }
1837 double applyExact (double x, double y) const { return m_func(x, y); }
1839 const string m_name;
1840 DoubleFunc2& m_func;
1843 class InfixOperator : public FloatFunc2
1846 virtual string getSymbol (void) const = 0;
1848 void doPrint (ostream& os, const BaseArgExprs& args) const
1850 os << "(" << *args[0] << " " << getSymbol() << " " << *args[1] << ")";
1853 Interval applyPoint (const EvalContext& ctx,
1857 const double exact = this->applyExact(x, y);
1859 // Allow either representable number on both sides of the exact value,
1860 // but require exactly representable values to be preserved.
1861 return ctx.format.roundOut(exact, !deIsInf(x) && !deIsInf(y));
1864 double precision (const EvalContext&, double, double, double) const
1870 class FloatFunc3 : public PrimitiveFunc<Signature<float, float, float, float> >
1873 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1875 return this->applyMonotone(ctx, iargs.a, iargs.b, iargs.c);
1878 Interval applyMonotone (const EvalContext& ctx,
1881 const Interval& zi) const
1884 TCU_INTERVAL_APPLY_MONOTONE3(reti, x, xi, y, yi, z, zi, ret,
1885 TCU_SET_INTERVAL(ret, point,
1886 point = this->applyPoint(ctx, x, y, z)));
1887 return ctx.format.convert(reti);
1890 virtual Interval applyPoint (const EvalContext& ctx,
1895 const double exact = this->applyExact(x, y, z);
1896 const double prec = this->precision(ctx, exact, x, y, z);
1897 return exact + Interval(-prec, prec);
1900 virtual double applyExact (double, double, double) const
1902 TCU_THROW(InternalError, "Cannot apply");
1905 virtual double precision (const EvalContext& ctx,
1909 double z) const = 0;
1912 // We define syntactic sugar functions for expression constructors. Since
1913 // these have the same names as ordinary mathematical operations (sin, log
1914 // etc.), it's better to give them a dedicated namespace.
1918 using namespace tcu;
1920 class Add : public InfixOperator
1923 string getName (void) const { return "add"; }
1924 string getSymbol (void) const { return "+"; }
1926 Interval doApply (const EvalContext& ctx,
1927 const IArgs& iargs) const
1929 // Fast-path for common case
1930 if (iargs.a.isOrdinary(ctx.format.getMaxValue()) && iargs.b.isOrdinary(ctx.format.getMaxValue()))
1933 TCU_SET_INTERVAL_BOUNDS(ret, sum,
1934 sum = iargs.a.lo() + iargs.b.lo(),
1935 sum = iargs.a.hi() + iargs.b.hi());
1936 return ctx.format.convert(ctx.format.roundOut(ret, true));
1938 return this->applyMonotone(ctx, iargs.a, iargs.b);
1942 double applyExact (double x, double y) const { return x + y; }
1945 class Mul : public InfixOperator
1948 string getName (void) const { return "mul"; }
1949 string getSymbol (void) const { return "*"; }
1951 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1953 Interval a = iargs.a;
1954 Interval b = iargs.b;
1956 // Fast-path for common case
1957 if (a.isOrdinary(ctx.format.getMaxValue()) && b.isOrdinary(ctx.format.getMaxValue()))
1965 if (a.lo() >= 0 && b.lo() >= 0)
1967 TCU_SET_INTERVAL_BOUNDS(ret, prod,
1968 prod = iargs.a.lo() * iargs.b.lo(),
1969 prod = iargs.a.hi() * iargs.b.hi());
1970 return ctx.format.convert(ctx.format.roundOut(ret, true));
1972 if (a.lo() >= 0 && b.hi() <= 0)
1974 TCU_SET_INTERVAL_BOUNDS(ret, prod,
1975 prod = iargs.a.hi() * iargs.b.lo(),
1976 prod = iargs.a.lo() * iargs.b.hi());
1977 return ctx.format.convert(ctx.format.roundOut(ret, true));
1980 return this->applyMonotone(ctx, iargs.a, iargs.b);
1984 double applyExact (double x, double y) const { return x * y; }
1986 Interval innerExtrema(const EvalContext&, const Interval& xi, const Interval& yi) const
1988 if (((xi.contains(-TCU_INFINITY) || xi.contains(TCU_INFINITY)) && yi.contains(0.0)) ||
1989 ((yi.contains(-TCU_INFINITY) || yi.contains(TCU_INFINITY)) && xi.contains(0.0)))
1990 return Interval(TCU_NAN);
1996 class Sub : public InfixOperator
1999 string getName (void) const { return "sub"; }
2000 string getSymbol (void) const { return "-"; }
2002 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
2004 // Fast-path for common case
2005 if (iargs.a.isOrdinary(ctx.format.getMaxValue()) && iargs.b.isOrdinary(ctx.format.getMaxValue()))
2009 TCU_SET_INTERVAL_BOUNDS(ret, diff,
2010 diff = iargs.a.lo() - iargs.b.hi(),
2011 diff = iargs.a.hi() - iargs.b.lo());
2012 return ctx.format.convert(ctx.format.roundOut(ret, true));
2017 return this->applyMonotone(ctx, iargs.a, iargs.b);
2022 double applyExact (double x, double y) const { return x - y; }
2025 class Negate : public FloatFunc1
2028 string getName (void) const { return "_negate"; }
2029 void doPrint (ostream& os, const BaseArgExprs& args) const { os << "-" << *args[0]; }
2032 double precision (const EvalContext&, double, double) const { return 0.0; }
2033 double applyExact (double x) const { return -x; }
2036 class Div : public InfixOperator
2039 string getName (void) const { return "div"; }
2042 string getSymbol (void) const { return "/"; }
2044 Interval innerExtrema (const EvalContext&,
2045 const Interval& nom,
2046 const Interval& den) const
2050 if (den.contains(0.0))
2052 if (nom.contains(0.0))
2055 if (nom.lo() < 0.0 || nom.hi() > 0.0)
2056 ret |= Interval::unbounded();
2062 double applyExact (double x, double y) const { return x / y; }
2064 Interval applyPoint (const EvalContext& ctx, double x, double y) const
2066 Interval ret = FloatFunc2::applyPoint(ctx, x, y);
2068 if (!deIsInf(x) && !deIsInf(y) && y != 0.0)
2070 const Interval dst = ctx.format.convert(ret);
2071 if (dst.contains(-TCU_INFINITY)) ret |= -ctx.format.getMaxValue();
2072 if (dst.contains(+TCU_INFINITY)) ret |= +ctx.format.getMaxValue();
2078 double precision (const EvalContext& ctx, double ret, double, double den) const
2080 const FloatFormat& fmt = ctx.format;
2082 // \todo [2014-03-05 lauri] Check that the limits in GLSL 3.10 are actually correct.
2083 // For now, we assume that division's precision is 2.5 ULP when the value is within
2084 // [2^MINEXP, 2^MAXEXP-1]
2087 return 0.0; // Result must be exactly inf
2088 else if (de::inBounds(deAbs(den),
2089 deLdExp(1.0, fmt.getMinExp()),
2090 deLdExp(1.0, fmt.getMaxExp() - 1)))
2091 return fmt.ulp(ret, 2.5);
2093 return TCU_INFINITY; // Can be any number, but must be a number.
2097 class InverseSqrt : public FloatFunc1
2100 string getName (void) const { return "inversesqrt"; }
2103 double applyExact (double x) const { return 1.0 / deSqrt(x); }
2105 double precision (const EvalContext& ctx, double ret, double x) const
2107 return x <= 0 ? TCU_NAN : ctx.format.ulp(ret, 2.0);
2110 Interval getCodomain (void) const
2112 return Interval(0.0, TCU_INFINITY);
2116 class ExpFunc : public CFloatFunc1
2119 ExpFunc (const string& name, DoubleFunc1& func)
2120 : CFloatFunc1(name, func) {}
2122 double precision (const EvalContext& ctx, double ret, double x) const
2124 switch (ctx.floatPrecision)
2126 case glu::PRECISION_HIGHP:
2127 return ctx.format.ulp(ret, 3.0 + 2.0 * deAbs(x));
2128 case glu::PRECISION_MEDIUMP:
2129 return ctx.format.ulp(ret, 2.0 + 2.0 * deAbs(x));
2130 case glu::PRECISION_LOWP:
2131 return ctx.format.ulp(ret, 2.0);
2133 DE_FATAL("Impossible");
2138 Interval getCodomain (void) const
2140 return Interval(0.0, TCU_INFINITY);
2144 class Exp2 : public ExpFunc { public: Exp2 (void) : ExpFunc("exp2", deExp2) {} };
2145 class Exp : public ExpFunc { public: Exp (void) : ExpFunc("exp", deExp) {} };
2147 ExprP<float> exp2 (const ExprP<float>& x) { return app<Exp2>(x); }
2148 ExprP<float> exp (const ExprP<float>& x) { return app<Exp>(x); }
2150 class LogFunc : public CFloatFunc1
2153 LogFunc (const string& name, DoubleFunc1& func)
2154 : CFloatFunc1(name, func) {}
2157 double precision (const EvalContext& ctx, double ret, double x) const
2162 switch (ctx.floatPrecision)
2164 case glu::PRECISION_HIGHP:
2165 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -21) : ctx.format.ulp(ret, 3.0);
2166 case glu::PRECISION_MEDIUMP:
2167 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -7) : ctx.format.ulp(ret, 2.0);
2168 case glu::PRECISION_LOWP:
2169 return ctx.format.ulp(ret, 2.0);
2171 DE_FATAL("Impossible");
2177 // OpenGL API Issue #57 "Clarifying the required ULP precision for GLSL built-in log()". Agreed that
2178 // implementations will be allowed 4 ULPs for HIGHP Log/Log2, but CTS should generate a quality warning.
2179 double warningPrecision(const EvalContext& ctx, double ret, double x) const
2181 if (ctx.floatPrecision == glu::PRECISION_HIGHP && x > 0)
2183 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -21) : ctx.format.ulp(ret, 4.0);
2187 return precision(ctx, ret, x);
2193 class Log2 : public LogFunc { public: Log2 (void) : LogFunc("log2", deLog2) {} };
2194 class Log : public LogFunc { public: Log (void) : LogFunc("log", deLog) {} };
2196 ExprP<float> log2 (const ExprP<float>& x) { return app<Log2>(x); }
2197 ExprP<float> log (const ExprP<float>& x) { return app<Log>(x); }
2199 #define DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0) \
2200 ExprP<TRET> NAME (const ExprP<T0>& arg0) { return app<CLASS>(arg0); }
2202 #define DEFINE_DERIVED1(CLASS, TRET, NAME, T0, ARG0, EXPANSION) \
2203 class CLASS : public DerivedFunc<Signature<TRET, T0> > /* NOLINT(CLASS) */ \
2206 string getName (void) const { return #NAME; } \
2209 ExprP<TRET> doExpand (ExpandContext&, \
2210 const CLASS::ArgExprs& args_) const \
2212 const ExprP<float>& ARG0 = args_.a; \
2216 DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0)
2218 #define DEFINE_DERIVED_FLOAT1(CLASS, NAME, ARG0, EXPANSION) \
2219 DEFINE_DERIVED1(CLASS, float, NAME, float, ARG0, EXPANSION)
2221 #define DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1) \
2222 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1) \
2224 return app<CLASS>(arg0, arg1); \
2227 #define DEFINE_DERIVED2(CLASS, TRET, NAME, T0, Arg0, T1, Arg1, EXPANSION) \
2228 class CLASS : public DerivedFunc<Signature<TRET, T0, T1> > /* NOLINT(CLASS) */ \
2231 string getName (void) const { return #NAME; } \
2234 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2236 const ExprP<T0>& Arg0 = args_.a; \
2237 const ExprP<T1>& Arg1 = args_.b; \
2241 DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1)
2243 #define DEFINE_DERIVED_FLOAT2(CLASS, NAME, Arg0, Arg1, EXPANSION) \
2244 DEFINE_DERIVED2(CLASS, float, NAME, float, Arg0, float, Arg1, EXPANSION)
2246 #define DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2) \
2247 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, const ExprP<T2>& arg2) \
2249 return app<CLASS>(arg0, arg1, arg2); \
2252 #define DEFINE_DERIVED3(CLASS, TRET, NAME, T0, ARG0, T1, ARG1, T2, ARG2, EXPANSION) \
2253 class CLASS : public DerivedFunc<Signature<TRET, T0, T1, T2> > /* NOLINT(CLASS) */ \
2256 string getName (void) const { return #NAME; } \
2259 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2261 const ExprP<T0>& ARG0 = args_.a; \
2262 const ExprP<T1>& ARG1 = args_.b; \
2263 const ExprP<T2>& ARG2 = args_.c; \
2267 DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2)
2269 #define DEFINE_DERIVED_FLOAT3(CLASS, NAME, ARG0, ARG1, ARG2, EXPANSION) \
2270 DEFINE_DERIVED3(CLASS, float, NAME, float, ARG0, float, ARG1, float, ARG2, EXPANSION)
2272 #define DEFINE_CONSTRUCTOR4(CLASS, TRET, NAME, T0, T1, T2, T3) \
2273 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, \
2274 const ExprP<T2>& arg2, const ExprP<T3>& arg3) \
2276 return app<CLASS>(arg0, arg1, arg2, arg3); \
2279 DEFINE_DERIVED_FLOAT1(Sqrt, sqrt, x, (x == 0.0f ? constant(1.0f) : (constant(1.0f) / app<InverseSqrt>(x))))
2280 DEFINE_DERIVED_FLOAT2(Pow, pow, x, y, exp2(y * log2(x)))
2281 DEFINE_DERIVED_FLOAT1(Radians, radians, d, (constant(DE_PI) / constant(180.0f)) * d)
2282 DEFINE_DERIVED_FLOAT1(Degrees, degrees, r, (constant(180.0f) / constant(DE_PI)) * r)
2284 class TrigFunc : public CFloatFunc1
2287 TrigFunc (const string& name,
2289 const Interval& loEx,
2290 const Interval& hiEx)
2291 : CFloatFunc1 (name, func)
2292 , m_loExtremum (loEx)
2293 , m_hiExtremum (hiEx) {}
2296 Interval innerExtrema (const EvalContext&, const Interval& angle) const
2298 const double lo = angle.lo();
2299 const double hi = angle.hi();
2300 const int loSlope = doGetSlope(lo);
2301 const int hiSlope = doGetSlope(hi);
2303 // Detect the high and low values the function can take between the
2304 // interval endpoints.
2305 if (angle.length() >= 2.0 * DE_PI_DOUBLE)
2307 // The interval is longer than a full cycle, so it must get all possible values.
2308 return m_hiExtremum | m_loExtremum;
2310 else if (loSlope == 1 && hiSlope == -1)
2312 // The slope can change from positive to negative only at the maximum value.
2313 return m_hiExtremum;
2315 else if (loSlope == -1 && hiSlope == 1)
2317 // The slope can change from negative to positive only at the maximum value.
2318 return m_loExtremum;
2320 else if (loSlope == hiSlope &&
2321 deIntSign(applyExact(hi) - applyExact(lo)) * loSlope == -1)
2323 // The slope has changed twice between the endpoints, so both extrema are included.
2324 return m_hiExtremum | m_loExtremum;
2330 Interval getCodomain (void) const
2332 // Ensure that result is always within [-1, 1], or NaN (for +-inf)
2333 return Interval(-1.0, 1.0) | TCU_NAN;
2336 double precision (const EvalContext& ctx, double ret, double arg) const
2338 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2340 // Use precision from OpenCL fast relaxed math
2341 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2343 return deLdExp(1.0, -11);
2347 // "larger otherwise", let's pick |x| * 2^-12 , which is slightly over
2348 // 2^-11 at x == pi.
2349 return deLdExp(deAbs(arg), -12);
2352 else if (ctx.floatPrecision == glu::PRECISION_MEDIUMP)
2354 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2356 // from OpenCL half-float extension specification
2357 return ctx.format.ulp(ret, 2.0);
2361 // |x| * 2^-10, slightly larger than 2 ULP at x == pi
2362 return deLdExp(deAbs(arg), -10);
2367 DE_ASSERT(ctx.floatPrecision == glu::PRECISION_LOWP);
2369 // from OpenCL half-float extension specification
2370 return ctx.format.ulp(ret, 2.0);
2374 virtual int doGetSlope (double angle) const = 0;
2376 Interval m_loExtremum;
2377 Interval m_hiExtremum;
2380 class Sin : public TrigFunc
2383 Sin (void) : TrigFunc("sin", deSin, -1.0, 1.0) {}
2386 int doGetSlope (double angle) const { return deIntSign(deCos(angle)); }
2389 ExprP<float> sin (const ExprP<float>& x) { return app<Sin>(x); }
2391 class Cos : public TrigFunc
2394 Cos (void) : TrigFunc("cos", deCos, -1.0, 1.0) {}
2397 int doGetSlope (double angle) const { return -deIntSign(deSin(angle)); }
2400 ExprP<float> cos (const ExprP<float>& x) { return app<Cos>(x); }
2402 DEFINE_DERIVED_FLOAT1(Tan, tan, x, sin(x) * (constant(1.0f) / cos(x)))
2404 class ASin : public CFloatFunc1
2407 ASin (void) : CFloatFunc1("asin", deAsin) {}
2410 double precision (const EvalContext& ctx, double, double x) const
2412 if (!de::inBounds(x, -1.0, 1.0))
2415 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2417 // Absolute error of 2^-11
2418 return deLdExp(1.0, -11);
2422 // Absolute error of 2^-8
2423 return deLdExp(1.0, -8);
2429 class ArcTrigFunc : public CFloatFunc1
2432 ArcTrigFunc (const string& name,
2434 double precisionULPs,
2435 const Interval& domain,
2436 const Interval& codomain)
2437 : CFloatFunc1 (name, func)
2438 , m_precision (precisionULPs)
2440 , m_codomain (codomain) {}
2443 double precision (const EvalContext& ctx, double ret, double x) const
2445 if (!m_domain.contains(x))
2448 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2450 // Use OpenCL's fast relaxed math precision
2451 return ctx.format.ulp(ret, m_precision);
2455 // Use OpenCL half-float spec
2456 return ctx.format.ulp(ret, 2.0);
2460 // We could implement getCodomain with m_codomain, but choose not to,
2461 // because it seems too strict with trascendental constants like pi.
2463 const double m_precision;
2464 const Interval m_domain;
2465 const Interval m_codomain;
2468 class ACos : public ArcTrigFunc
2471 ACos (void) : ArcTrigFunc("acos", deAcos, 4096.0,
2472 Interval(-1.0, 1.0),
2473 Interval(0.0, DE_PI_DOUBLE)) {}
2476 class ATan : public ArcTrigFunc
2479 ATan (void) : ArcTrigFunc("atan", deAtanOver, 4096.0,
2480 Interval::unbounded(),
2481 Interval(-DE_PI_DOUBLE * 0.5, DE_PI_DOUBLE * 0.5)) {}
2484 class ATan2 : public CFloatFunc2
2487 ATan2 (void) : CFloatFunc2 ("atan", deAtan2) {}
2490 Interval innerExtrema (const EvalContext& ctx,
2492 const Interval& xi) const
2496 if (yi.contains(0.0))
2498 if (xi.contains(0.0))
2500 if (xi.intersects(Interval(-TCU_INFINITY, 0.0)))
2501 ret |= Interval(-DE_PI_DOUBLE, DE_PI_DOUBLE);
2504 if (!yi.isFinite(ctx.format.getMaxValue()) || !xi.isFinite(ctx.format.getMaxValue()))
2506 // Infinities may not be supported, allow anything, including NaN
2513 double precision (const EvalContext& ctx, double ret, double, double) const
2515 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2516 return ctx.format.ulp(ret, 4096.0);
2518 return ctx.format.ulp(ret, 2.0);
2521 // Codomain could be [-pi, pi], but that would probably be too strict.
2524 DEFINE_DERIVED_FLOAT1(Sinh, sinh, x, (exp(x) - exp(-x)) / constant(2.0f))
2525 DEFINE_DERIVED_FLOAT1(Cosh, cosh, x, (exp(x) + exp(-x)) / constant(2.0f))
2526 DEFINE_DERIVED_FLOAT1(Tanh, tanh, x, sinh(x) / cosh(x))
2528 // These are not defined as derived forms in the GLSL ES spec, but
2529 // that gives us a reasonable precision.
2530 DEFINE_DERIVED_FLOAT1(ASinh, asinh, x, log(x + sqrt(x * x + constant(1.0f))))
2531 DEFINE_DERIVED_FLOAT1(ACosh, acosh, x, log(x + sqrt(alternatives((x + constant(1.0f)) * (x - constant(1.0f)),
2532 (x*x - constant(1.0f))))))
2533 DEFINE_DERIVED_FLOAT1(ATanh, atanh, x, constant(0.5f) * log((constant(1.0f) + x) /
2534 (constant(1.0f) - x)))
2536 template <typename T>
2537 class GetComponent : public PrimitiveFunc<Signature<typename T::Element, T, int> >
2540 typedef typename GetComponent::IRet IRet;
2542 string getName (void) const { return "_getComponent"; }
2544 void print (ostream& os,
2545 const BaseArgExprs& args) const
2547 os << *args[0] << "[" << *args[1] << "]";
2551 IRet doApply (const EvalContext&,
2552 const typename GetComponent::IArgs& iargs) const
2556 for (int compNdx = 0; compNdx < T::SIZE; ++compNdx)
2558 if (iargs.b.contains(compNdx))
2559 ret = unionIVal<typename T::Element>(ret, iargs.a[compNdx]);
2567 template <typename T>
2568 ExprP<typename T::Element> getComponent (const ExprP<T>& container, int ndx)
2570 DE_ASSERT(0 <= ndx && ndx < T::SIZE);
2571 return app<GetComponent<T> >(container, constant(ndx));
2574 template <typename T> string vecNamePrefix (void);
2575 template <> string vecNamePrefix<float> (void) { return ""; }
2576 template <> string vecNamePrefix<int> (void) { return "i"; }
2577 template <> string vecNamePrefix<bool> (void) { return "b"; }
2579 template <typename T, int Size>
2580 string vecName (void) { return vecNamePrefix<T>() + "vec" + de::toString(Size); }
2582 template <typename T, int Size> class GenVec;
2584 template <typename T>
2585 class GenVec<T, 1> : public DerivedFunc<Signature<T, T> >
2588 typedef typename GenVec<T, 1>::ArgExprs ArgExprs;
2590 string getName (void) const
2592 return "_" + vecName<T, 1>();
2597 ExprP<T> doExpand (ExpandContext&, const ArgExprs& args) const { return args.a; }
2600 template <typename T>
2601 class GenVec<T, 2> : public PrimitiveFunc<Signature<Vector<T, 2>, T, T> >
2604 typedef typename GenVec::IRet IRet;
2605 typedef typename GenVec::IArgs IArgs;
2607 string getName (void) const
2609 return vecName<T, 2>();
2613 IRet doApply (const EvalContext&, const IArgs& iargs) const
2615 return IRet(iargs.a, iargs.b);
2619 template <typename T>
2620 class GenVec<T, 3> : public PrimitiveFunc<Signature<Vector<T, 3>, T, T, T> >
2623 typedef typename GenVec::IRet IRet;
2624 typedef typename GenVec::IArgs IArgs;
2626 string getName (void) const
2628 return vecName<T, 3>();
2632 IRet doApply (const EvalContext&, const IArgs& iargs) const
2634 return IRet(iargs.a, iargs.b, iargs.c);
2638 template <typename T>
2639 class GenVec<T, 4> : public PrimitiveFunc<Signature<Vector<T, 4>, T, T, T, T> >
2642 typedef typename GenVec::IRet IRet;
2643 typedef typename GenVec::IArgs IArgs;
2645 string getName (void) const { return vecName<T, 4>(); }
2648 IRet doApply (const EvalContext&, const IArgs& iargs) const
2650 return IRet(iargs.a, iargs.b, iargs.c, iargs.d);
2656 template <typename T, int Rows, int Columns>
2659 template <typename T, int Rows>
2660 class GenMat<T, Rows, 2> : public PrimitiveFunc<
2661 Signature<Matrix<T, Rows, 2>, Vector<T, Rows>, Vector<T, Rows> > >
2664 typedef typename GenMat::Ret Ret;
2665 typedef typename GenMat::IRet IRet;
2666 typedef typename GenMat::IArgs IArgs;
2668 string getName (void) const
2670 return dataTypeNameOf<Ret>();
2675 IRet doApply (const EvalContext&, const IArgs& iargs) const
2684 template <typename T, int Rows>
2685 class GenMat<T, Rows, 3> : public PrimitiveFunc<
2686 Signature<Matrix<T, Rows, 3>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
2689 typedef typename GenMat::Ret Ret;
2690 typedef typename GenMat::IRet IRet;
2691 typedef typename GenMat::IArgs IArgs;
2693 string getName (void) const
2695 return dataTypeNameOf<Ret>();
2700 IRet doApply (const EvalContext&, const IArgs& iargs) const
2710 template <typename T, int Rows>
2711 class GenMat<T, Rows, 4> : public PrimitiveFunc<
2712 Signature<Matrix<T, Rows, 4>,
2713 Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
2716 typedef typename GenMat::Ret Ret;
2717 typedef typename GenMat::IRet IRet;
2718 typedef typename GenMat::IArgs IArgs;
2720 string getName (void) const
2722 return dataTypeNameOf<Ret>();
2726 IRet doApply (const EvalContext&, const IArgs& iargs) const
2737 template <typename T, int Rows>
2738 ExprP<Matrix<T, Rows, 2> > mat2 (const ExprP<Vector<T, Rows> >& arg0,
2739 const ExprP<Vector<T, Rows> >& arg1)
2741 return app<GenMat<T, Rows, 2> >(arg0, arg1);
2744 template <typename T, int Rows>
2745 ExprP<Matrix<T, Rows, 3> > mat3 (const ExprP<Vector<T, Rows> >& arg0,
2746 const ExprP<Vector<T, Rows> >& arg1,
2747 const ExprP<Vector<T, Rows> >& arg2)
2749 return app<GenMat<T, Rows, 3> >(arg0, arg1, arg2);
2752 template <typename T, int Rows>
2753 ExprP<Matrix<T, Rows, 4> > mat4 (const ExprP<Vector<T, Rows> >& arg0,
2754 const ExprP<Vector<T, Rows> >& arg1,
2755 const ExprP<Vector<T, Rows> >& arg2,
2756 const ExprP<Vector<T, Rows> >& arg3)
2758 return app<GenMat<T, Rows, 4> >(arg0, arg1, arg2, arg3);
2762 template <int Rows, int Cols>
2763 class MatNeg : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
2764 Matrix<float, Rows, Cols> > >
2767 typedef typename MatNeg::IRet IRet;
2768 typedef typename MatNeg::IArgs IArgs;
2770 string getName (void) const
2776 void doPrint (ostream& os, const BaseArgExprs& args) const
2778 os << "-(" << *args[0] << ")";
2781 IRet doApply (const EvalContext&, const IArgs& iargs) const
2785 for (int col = 0; col < Cols; ++col)
2787 for (int row = 0; row < Rows; ++row)
2788 ret[col][row] = -iargs.a[col][row];
2795 template <typename T, typename Sig>
2796 class CompWiseFunc : public PrimitiveFunc<Sig>
2799 typedef Func<Signature<T, T, T> > ScalarFunc;
2801 string getName (void) const
2803 return doGetScalarFunc().getName();
2806 void doPrint (ostream& os,
2807 const BaseArgExprs& args) const
2809 doGetScalarFunc().print(os, args);
2813 const ScalarFunc& doGetScalarFunc (void) const = 0;
2816 template <int Rows, int Cols>
2817 class CompMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
2818 Matrix<float, Rows, Cols>,
2819 Matrix<float, Rows, Cols> > >
2822 typedef typename CompMatFuncBase::IRet IRet;
2823 typedef typename CompMatFuncBase::IArgs IArgs;
2827 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
2831 for (int col = 0; col < Cols; ++col)
2833 for (int row = 0; row < Rows; ++row)
2834 ret[col][row] = this->doGetScalarFunc().apply(ctx,
2843 template <typename F, int Rows, int Cols>
2844 class CompMatFunc : public CompMatFuncBase<Rows, Cols>
2847 const typename CompMatFunc::ScalarFunc& doGetScalarFunc (void) const
2849 return instance<F>();
2853 class ScalarMatrixCompMult : public Mul
2856 string getName (void) const
2858 return "matrixCompMult";
2861 void doPrint (ostream& os, const BaseArgExprs& args) const
2863 Func<Sig>::doPrint(os, args);
2867 template <int Rows, int Cols>
2868 class MatrixCompMult : public CompMatFunc<ScalarMatrixCompMult, Rows, Cols>
2872 template <int Rows, int Cols>
2873 class ScalarMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
2874 Matrix<float, Rows, Cols>,
2878 typedef typename ScalarMatFuncBase::IRet IRet;
2879 typedef typename ScalarMatFuncBase::IArgs IArgs;
2883 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
2887 for (int col = 0; col < Cols; ++col)
2889 for (int row = 0; row < Rows; ++row)
2890 ret[col][row] = this->doGetScalarFunc().apply(ctx, iargs.a[col][row], iargs.b);
2897 template <typename F, int Rows, int Cols>
2898 class ScalarMatFunc : public ScalarMatFuncBase<Rows, Cols>
2901 const typename ScalarMatFunc::ScalarFunc& doGetScalarFunc (void) const
2903 return instance<F>();
2907 template<typename T, int Size> struct GenXType;
2909 template<typename T>
2910 struct GenXType<T, 1>
2912 static ExprP<T> genXType (const ExprP<T>& x) { return x; }
2915 template<typename T>
2916 struct GenXType<T, 2>
2918 static ExprP<Vector<T, 2> > genXType (const ExprP<T>& x)
2920 return app<GenVec<T, 2> >(x, x);
2924 template<typename T>
2925 struct GenXType<T, 3>
2927 static ExprP<Vector<T, 3> > genXType (const ExprP<T>& x)
2929 return app<GenVec<T, 3> >(x, x, x);
2933 template<typename T>
2934 struct GenXType<T, 4>
2936 static ExprP<Vector<T, 4> > genXType (const ExprP<T>& x)
2938 return app<GenVec<T, 4> >(x, x, x, x);
2942 //! Returns an expression of vector of size `Size` (or scalar if Size == 1),
2943 //! with each element initialized with the expression `x`.
2944 template<typename T, int Size>
2945 ExprP<typename ContainerOf<T, Size>::Container> genXType (const ExprP<T>& x)
2947 return GenXType<T, Size>::genXType(x);
2950 typedef GenVec<float, 2> FloatVec2;
2951 DEFINE_CONSTRUCTOR2(FloatVec2, Vec2, vec2, float, float)
2953 typedef GenVec<float, 3> FloatVec3;
2954 DEFINE_CONSTRUCTOR3(FloatVec3, Vec3, vec3, float, float, float)
2956 typedef GenVec<float, 4> FloatVec4;
2957 DEFINE_CONSTRUCTOR4(FloatVec4, Vec4, vec4, float, float, float, float)
2960 class Dot : public DerivedFunc<Signature<float, Vector<float, Size>, Vector<float, Size> > >
2963 typedef typename Dot::ArgExprs ArgExprs;
2965 string getName (void) const
2971 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2973 ExprP<float> op[Size];
2974 // Precompute all products.
2975 for (int ndx = 0; ndx < Size; ++ndx)
2976 op[ndx] = args.a[ndx] * args.b[ndx];
2979 //Prepare an array of indices.
2980 for (int ndx = 0; ndx < Size; ++ndx)
2983 ExprP<float> res = op[0];
2984 // Compute the first dot alternative: SUM(a[i]*b[i]), i = 0 .. Size-1
2985 for (int ndx = 1; ndx < Size; ++ndx)
2986 res = res + op[ndx];
2988 // Generate all permutations of indices and
2989 // using a permutation compute a dot alternative.
2990 // Generates all possible variants fo summation of products in the dot product expansion expression.
2992 ExprP<float> alt = constant(0.0f);
2993 for (int ndx = 0; ndx < Size; ++ndx)
2994 alt = alt + op[idx[ndx]];
2995 res = alternatives(res, alt);
2996 } while (std::next_permutation(idx, idx + Size));
3003 class Dot<1> : public DerivedFunc<Signature<float, float, float> >
3006 string getName (void) const
3011 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
3013 return args.a * args.b;
3018 ExprP<float> dot (const ExprP<Vector<float, Size> >& x, const ExprP<Vector<float, Size> >& y)
3020 return app<Dot<Size> >(x, y);
3023 ExprP<float> dot (const ExprP<float>& x, const ExprP<float>& y)
3025 return app<Dot<1> >(x, y);
3029 class Length : public DerivedFunc<
3030 Signature<float, typename ContainerOf<float, Size>::Container> >
3033 typedef typename Length::ArgExprs ArgExprs;
3035 string getName (void) const
3041 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
3043 return sqrt(dot(args.a, args.a));
3048 ExprP<float> length (const ExprP<typename ContainerOf<float, Size>::Container>& x)
3050 return app<Length<Size> >(x);
3054 class Distance : public DerivedFunc<
3056 typename ContainerOf<float, Size>::Container,
3057 typename ContainerOf<float, Size>::Container> >
3060 typedef typename Distance::Ret Ret;
3061 typedef typename Distance::ArgExprs ArgExprs;
3063 string getName (void) const
3069 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3071 return length<Size>(args.a - args.b);
3077 class Cross : public DerivedFunc<Signature<Vec3, Vec3, Vec3> >
3080 string getName (void) const
3086 ExprP<Vec3> doExpand (ExpandContext&, const ArgExprs& x) const
3088 return vec3(x.a[1] * x.b[2] - x.b[1] * x.a[2],
3089 x.a[2] * x.b[0] - x.b[2] * x.a[0],
3090 x.a[0] * x.b[1] - x.b[0] * x.a[1]);
3094 DEFINE_CONSTRUCTOR2(Cross, Vec3, cross, Vec3, Vec3)
3097 class Normalize : public DerivedFunc<
3098 Signature<typename ContainerOf<float, Size>::Container,
3099 typename ContainerOf<float, Size>::Container> >
3102 typedef typename Normalize::Ret Ret;
3103 typedef typename Normalize::ArgExprs ArgExprs;
3105 string getName (void) const
3111 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3113 return args.a / length<Size>(args.a);
3118 class FaceForward : public DerivedFunc<
3119 Signature<typename ContainerOf<float, Size>::Container,
3120 typename ContainerOf<float, Size>::Container,
3121 typename ContainerOf<float, Size>::Container,
3122 typename ContainerOf<float, Size>::Container> >
3125 typedef typename FaceForward::Ret Ret;
3126 typedef typename FaceForward::ArgExprs ArgExprs;
3128 string getName (void) const
3130 return "faceforward";
3136 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3138 return cond(dot(args.c, args.b) < constant(0.0f), args.a, -args.a);
3142 template<int Size, typename Ret, typename Arg0, typename Arg1>
3145 static ExprP<Ret> apply (ExpandContext& ctx,
3146 const ExprP<Arg0>& i,
3147 const ExprP<Arg1>& n)
3149 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3151 return i - alternatives((n * dotNI) * constant(2.0f),
3152 n * (dotNI * constant(2.0f)));
3156 template<typename Ret, typename Arg0, typename Arg1>
3157 struct ApplyReflect<1, Ret, Arg0, Arg1>
3159 static ExprP<Ret> apply (ExpandContext&,
3160 const ExprP<Arg0>& i,
3161 const ExprP<Arg1>& n)
3163 return i - alternatives(alternatives((n * (n*i)) * constant(2.0f),
3164 n * ((n*i) * constant(2.0f))),
3165 (n * n) * (i * constant(2.0f)));
3170 class Reflect : public DerivedFunc<
3171 Signature<typename ContainerOf<float, Size>::Container,
3172 typename ContainerOf<float, Size>::Container,
3173 typename ContainerOf<float, Size>::Container> >
3176 typedef typename Reflect::Ret Ret;
3177 typedef typename Reflect::Arg0 Arg0;
3178 typedef typename Reflect::Arg1 Arg1;
3179 typedef typename Reflect::ArgExprs ArgExprs;
3181 string getName (void) const
3187 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3189 const ExprP<Arg0>& i = args.a;
3190 const ExprP<Arg1>& n = args.b;
3192 return ApplyReflect<Size, Ret, Arg0, Arg1>::apply(ctx, i, n);
3197 class Refract : public DerivedFunc<
3198 Signature<typename ContainerOf<float, Size>::Container,
3199 typename ContainerOf<float, Size>::Container,
3200 typename ContainerOf<float, Size>::Container,
3204 typedef typename Refract::Ret Ret;
3205 typedef typename Refract::Arg0 Arg0;
3206 typedef typename Refract::Arg1 Arg1;
3207 typedef typename Refract::ArgExprs ArgExprs;
3209 string getName (void) const
3215 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3217 const ExprP<Arg0>& i = args.a;
3218 const ExprP<Arg1>& n = args.b;
3219 const ExprP<float>& eta = args.c;
3220 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3221 const ExprP<float> k1 = bindExpression("k1", ctx, constant(1.0f) - eta * eta *
3222 (constant(1.0f) - dotNI * dotNI));
3224 const ExprP<float> k2 = bindExpression("k2", ctx,
3225 (((dotNI * (-dotNI)) + constant(1.0f)) * eta)
3226 * (-eta) + constant(1.0f));
3227 const ExprP<float> k = bindExpression("k", ctx, alternatives(k1, k2));
3229 return cond(k < constant(0.0f),
3230 genXType<float, Size>(constant(0.0f)),
3231 i * eta - n * (eta * dotNI + sqrt(k)));
3235 class PreciseFunc1 : public CFloatFunc1
3238 PreciseFunc1 (const string& name, DoubleFunc1& func) : CFloatFunc1(name, func) {}
3240 double precision (const EvalContext&, double, double) const { return 0.0; }
3243 class Abs : public PreciseFunc1
3246 Abs (void) : PreciseFunc1("abs", deAbs) {}
3249 class Sign : public PreciseFunc1
3252 Sign (void) : PreciseFunc1("sign", deSign) {}
3255 class Floor : public PreciseFunc1
3258 Floor (void) : PreciseFunc1("floor", deFloor) {}
3261 class Trunc : public PreciseFunc1
3264 Trunc (void) : PreciseFunc1("trunc", deTrunc) {}
3267 class Round : public FloatFunc1
3270 string getName (void) const { return "round"; }
3273 Interval applyPoint (const EvalContext&, double x) const
3275 double truncated = 0.0;
3276 const double fract = deModf(x, &truncated);
3279 if (fabs(fract) <= 0.5)
3281 if (fabs(fract) >= 0.5)
3282 ret |= truncated + deSign(fract);
3287 double precision (const EvalContext&, double, double) const { return 0.0; }
3290 class RoundEven : public PreciseFunc1
3293 RoundEven (void) : PreciseFunc1("roundEven", deRoundEven) {}
3296 class Ceil : public PreciseFunc1
3299 Ceil (void) : PreciseFunc1("ceil", deCeil) {}
3302 DEFINE_DERIVED_FLOAT1(Fract, fract, x, x - app<Floor>(x))
3304 class PreciseFunc2 : public CFloatFunc2
3307 PreciseFunc2 (const string& name, DoubleFunc2& func) : CFloatFunc2(name, func) {}
3309 double precision (const EvalContext&, double, double, double) const { return 0.0; }
3312 DEFINE_DERIVED_FLOAT2(Mod, mod, x, y, x - y * app<Floor>(x / y))
3314 class Modf : public PrimitiveFunc<Signature<float, float, float> >
3317 string getName (void) const
3323 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3326 Interval& wholeIV = const_cast<Interval&>(iargs.b);
3329 TCU_INTERVAL_APPLY_MONOTONE1(fracIV, x, iargs.a, frac, frac = deModf(x, &intPart));
3330 TCU_INTERVAL_APPLY_MONOTONE1(wholeIV, x, iargs.a, whole,
3331 deModf(x, &intPart); whole = intPart);
3333 if (!iargs.a.isFinite(ctx.format.getMaxValue()))
3335 // Behavior on modf(Inf) not well-defined, allow anything as a fractional part
3336 // See Khronos bug 13907
3343 int getOutParamIndex (void) const
3349 int compare(const EvalContext& ctx, double x, double y)
3351 if (ctx.format.hasSubnormal() != tcu::YES)
3353 const int minExp = ctx.format.getMinExp();
3354 const int fractionBits = ctx.format.getFractionBits();
3355 const double minQuantum = deLdExp(1.0f, minExp - fractionBits);
3356 const double minNormalized = deLdExp(1.0f, minExp);
3357 const double maxSubnormal = minNormalized - minQuantum;
3358 const double minSubnormal = -maxSubnormal;
3360 if (minSubnormal <= x && x <= maxSubnormal &&
3361 minSubnormal <= y && y <= maxSubnormal)
3372 class MinMaxFunc : public FloatFunc2
3375 MinMaxFunc (const string& name,
3382 string getName (void) const { return m_name; }
3385 Interval applyPoint(const EvalContext& ctx, double x, double y) const
3387 const int cmp = compare(ctx, x, y) * m_sign;
3394 // An implementation without subnormals may not be able to distinguish
3395 // between x and y even when they're not equal in host arithmetic.
3396 return Interval(x, y);
3399 double precision (const EvalContext&, double, double, double) const
3404 const string m_name;
3408 class Min : public MinMaxFunc { public: Min (void) : MinMaxFunc("min", -1) {} };
3409 class Max : public MinMaxFunc { public: Max (void) : MinMaxFunc("max", 1) {} };
3411 class Clamp : public FloatFunc3
3414 string getName (void) const { return "clamp"; }
3417 Interval applyPoint(const EvalContext& ctx, double x, double minVal, double maxVal) const
3419 if (minVal > maxVal)
3422 const int cmpMin = compare(ctx, x, minVal);
3423 const int cmpMax = compare(ctx, x, maxVal);
3424 const int cmpMinMax = compare(ctx, minVal, maxVal);
3430 return Interval(minVal, maxVal);
3436 return Interval(minVal, maxVal);
3439 Interval result = x;
3447 double precision (const EvalContext&, double, double, double minVal, double maxVal) const
3449 return minVal > maxVal ? TCU_NAN : 0.0;
3453 ExprP<float> clamp(const ExprP<float>& x, const ExprP<float>& minVal, const ExprP<float>& maxVal)
3455 return app<Clamp>(x, minVal, maxVal);
3458 DEFINE_DERIVED_FLOAT3(Mix, mix, x, y, a, alternatives((x * (constant(1.0f) - a)) + y * a,
3461 static double step (double edge, double x)
3463 return x < edge ? 0.0 : 1.0;
3466 class Step : public PreciseFunc2 { public: Step (void) : PreciseFunc2("step", step) {} };
3468 class SmoothStep : public DerivedFunc<Signature<float, float, float, float> >
3471 string getName (void) const
3473 return "smoothstep";
3478 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3480 const ExprP<float>& edge0 = args.a;
3481 const ExprP<float>& edge1 = args.b;
3482 const ExprP<float>& x = args.c;
3483 const ExprP<float> tExpr = clamp((x - edge0) / (edge1 - edge0),
3484 constant(0.0f), constant(1.0f));
3485 const ExprP<float> t = bindExpression("t", ctx, tExpr);
3487 return (t * t * (constant(3.0f) - constant(2.0f) * t));
3491 class FrExp : public PrimitiveFunc<Signature<float, float, int> >
3494 string getName (void) const
3500 IRet doApply (const EvalContext&, const IArgs& iargs) const
3503 const IArg0& x = iargs.a;
3504 IArg1& exponent = const_cast<IArg1&>(iargs.b);
3506 if (x.hasNaN() || x.contains(TCU_INFINITY) || x.contains(-TCU_INFINITY))
3508 // GLSL (in contrast to IEEE) says that result of applying frexp
3509 // to infinity is undefined
3510 ret = Interval::unbounded() | TCU_NAN;
3511 exponent = Interval(-deLdExp(1.0, 31), deLdExp(1.0, 31)-1);
3513 else if (!x.empty())
3516 const double loFrac = deFrExp(x.lo(), &loExp);
3518 const double hiFrac = deFrExp(x.hi(), &hiExp);
3520 if (deSign(loFrac) != deSign(hiFrac))
3522 exponent = Interval(-TCU_INFINITY, de::max(loExp, hiExp));
3524 if (deSign(loFrac) < 0)
3525 ret |= Interval(-1.0 + DBL_EPSILON*0.5, 0.0);
3526 if (deSign(hiFrac) > 0)
3527 ret |= Interval(0.0, 1.0 - DBL_EPSILON*0.5);
3531 exponent = Interval(loExp, hiExp);
3533 ret = Interval(loFrac, hiFrac);
3535 ret = deSign(loFrac) * Interval(0.5, 1.0 - DBL_EPSILON*0.5);
3542 int getOutParamIndex (void) const
3548 class LdExp : public PrimitiveFunc<Signature<float, float, int> >
3551 string getName (void) const
3557 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
3559 Interval ret = call<Exp2>(ctx, iargs.b);
3560 // Khronos bug 11180 consensus: if exp2(exponent) cannot be represented,
3561 // the result is undefined.
3563 if (ret.contains(TCU_INFINITY) || ret.contains(-TCU_INFINITY))
3566 return call<Mul>(ctx, iargs.a, ret);
3570 template<int Rows, int Columns>
3571 class Transpose : public PrimitiveFunc<Signature<Matrix<float, Rows, Columns>,
3572 Matrix<float, Columns, Rows> > >
3575 typedef typename Transpose::IRet IRet;
3576 typedef typename Transpose::IArgs IArgs;
3578 string getName (void) const
3584 IRet doApply (const EvalContext&, const IArgs& iargs) const
3588 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
3590 for (int colNdx = 0; colNdx < Columns; ++colNdx)
3591 ret(rowNdx, colNdx) = iargs.a(colNdx, rowNdx);
3598 template<typename Ret, typename Arg0, typename Arg1>
3599 class MulFunc : public PrimitiveFunc<Signature<Ret, Arg0, Arg1> >
3602 string getName (void) const { return "mul"; }
3605 void doPrint (ostream& os, const BaseArgExprs& args) const
3607 os << "(" << *args[0] << " * " << *args[1] << ")";
3611 template<int LeftRows, int Middle, int RightCols>
3612 class MatMul : public MulFunc<Matrix<float, LeftRows, RightCols>,
3613 Matrix<float, LeftRows, Middle>,
3614 Matrix<float, Middle, RightCols> >
3617 typedef typename MatMul::IRet IRet;
3618 typedef typename MatMul::IArgs IArgs;
3619 typedef typename MatMul::IArg0 IArg0;
3620 typedef typename MatMul::IArg1 IArg1;
3622 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3624 const IArg0& left = iargs.a;
3625 const IArg1& right = iargs.b;
3628 for (int row = 0; row < LeftRows; ++row)
3630 for (int col = 0; col < RightCols; ++col)
3632 Interval element (0.0);
3634 for (int ndx = 0; ndx < Middle; ++ndx)
3635 element = call<Add>(ctx, element,
3636 call<Mul>(ctx, left[ndx][row], right[col][ndx]));
3638 ret[col][row] = element;
3646 template<int Rows, int Cols>
3647 class VecMatMul : public MulFunc<Vector<float, Cols>,
3648 Vector<float, Rows>,
3649 Matrix<float, Rows, Cols> >
3652 typedef typename VecMatMul::IRet IRet;
3653 typedef typename VecMatMul::IArgs IArgs;
3654 typedef typename VecMatMul::IArg0 IArg0;
3655 typedef typename VecMatMul::IArg1 IArg1;
3658 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3660 const IArg0& left = iargs.a;
3661 const IArg1& right = iargs.b;
3664 for (int col = 0; col < Cols; ++col)
3666 Interval element (0.0);
3668 for (int row = 0; row < Rows; ++row)
3669 element = call<Add>(ctx, element, call<Mul>(ctx, left[row], right[col][row]));
3678 template<int Rows, int Cols>
3679 class MatVecMul : public MulFunc<Vector<float, Rows>,
3680 Matrix<float, Rows, Cols>,
3681 Vector<float, Cols> >
3684 typedef typename MatVecMul::IRet IRet;
3685 typedef typename MatVecMul::IArgs IArgs;
3686 typedef typename MatVecMul::IArg0 IArg0;
3687 typedef typename MatVecMul::IArg1 IArg1;
3690 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3692 const IArg0& left = iargs.a;
3693 const IArg1& right = iargs.b;
3695 return call<VecMatMul<Cols, Rows> >(ctx, right,
3696 call<Transpose<Rows, Cols> >(ctx, left));
3700 template<int Rows, int Cols>
3701 class OuterProduct : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
3702 Vector<float, Rows>,
3703 Vector<float, Cols> > >
3706 typedef typename OuterProduct::IRet IRet;
3707 typedef typename OuterProduct::IArgs IArgs;
3709 string getName (void) const
3711 return "outerProduct";
3715 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3719 for (int row = 0; row < Rows; ++row)
3721 for (int col = 0; col < Cols; ++col)
3722 ret[col][row] = call<Mul>(ctx, iargs.a[row], iargs.b[col]);
3729 template<int Rows, int Cols>
3730 ExprP<Matrix<float, Rows, Cols> > outerProduct (const ExprP<Vector<float, Rows> >& left,
3731 const ExprP<Vector<float, Cols> >& right)
3733 return app<OuterProduct<Rows, Cols> >(left, right);
3737 class DeterminantBase : public DerivedFunc<Signature<float, Matrix<float, Size, Size> > >
3740 string getName (void) const { return "determinant"; }
3747 ExprP<float> determinant (ExprP<Matrix<float, Size, Size> > mat)
3749 return app<Determinant<Size> >(mat);
3753 class Determinant<2> : public DeterminantBase<2>
3756 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3758 ExprP<Mat2> mat = args.a;
3760 return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
3765 class Determinant<3> : public DeterminantBase<3>
3768 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3770 ExprP<Mat3> mat = args.a;
3772 return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) +
3773 mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) +
3774 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
3779 class Determinant<4> : public DeterminantBase<4>
3782 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3784 ExprP<Mat4> mat = args.a;
3785 ExprP<Mat3> minors[4];
3787 for (int ndx = 0; ndx < 4; ++ndx)
3789 ExprP<Vec4> minorColumns[3];
3790 ExprP<Vec3> columns[3];
3792 for (int col = 0; col < 3; ++col)
3793 minorColumns[col] = mat[col < ndx ? col : col + 1];
3795 for (int col = 0; col < 3; ++col)
3796 columns[col] = vec3(minorColumns[0][col+1],
3797 minorColumns[1][col+1],
3798 minorColumns[2][col+1]);
3800 minors[ndx] = bindExpression("minor", ctx,
3801 mat3(columns[0], columns[1], columns[2]));
3804 return (mat[0][0] * determinant(minors[0]) -
3805 mat[1][0] * determinant(minors[1]) +
3806 mat[2][0] * determinant(minors[2]) -
3807 mat[3][0] * determinant(minors[3]));
3811 template<int Size> class Inverse;
3814 ExprP<Matrix<float, Size, Size> > inverse (ExprP<Matrix<float, Size, Size> > mat)
3816 return app<Inverse<Size> >(mat);
3820 class Inverse<2> : public DerivedFunc<Signature<Mat2, Mat2> >
3823 string getName (void) const
3829 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3831 ExprP<Mat2> mat = args.a;
3832 ExprP<float> det = bindExpression("det", ctx, determinant(mat));
3834 return mat2(vec2(mat[1][1] / det, -mat[0][1] / det),
3835 vec2(-mat[1][0] / det, mat[0][0] / det));
3840 class Inverse<3> : public DerivedFunc<Signature<Mat3, Mat3> >
3843 string getName (void) const
3849 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3851 ExprP<Mat3> mat = args.a;
3852 ExprP<Mat2> invA = bindExpression("invA", ctx,
3853 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3854 vec2(mat[1][0], mat[1][1]))));
3856 ExprP<Vec2> matB = bindExpression("matB", ctx, vec2(mat[2][0], mat[2][1]));
3857 ExprP<Vec2> matC = bindExpression("matC", ctx, vec2(mat[0][2], mat[1][2]));
3858 ExprP<float> matD = bindExpression("matD", ctx, mat[2][2]);
3860 ExprP<float> schur = bindExpression("schur", ctx,
3862 (matD - dot(matC * invA, matB)));
3864 ExprP<Vec2> t1 = invA * matB;
3865 ExprP<Vec2> t2 = t1 * schur;
3866 ExprP<Mat2> t3 = outerProduct(t2, matC);
3867 ExprP<Mat2> t4 = t3 * invA;
3868 ExprP<Mat2> t5 = invA + t4;
3869 ExprP<Mat2> blockA = bindExpression("blockA", ctx, t5);
3870 ExprP<Vec2> blockB = bindExpression("blockB", ctx,
3871 (invA * matB) * -schur);
3872 ExprP<Vec2> blockC = bindExpression("blockC", ctx,
3873 (matC * invA) * -schur);
3875 return mat3(vec3(blockA[0][0], blockA[0][1], blockC[0]),
3876 vec3(blockA[1][0], blockA[1][1], blockC[1]),
3877 vec3(blockB[0], blockB[1], schur));
3882 class Inverse<4> : public DerivedFunc<Signature<Mat4, Mat4> >
3885 string getName (void) const { return "inverse"; }
3888 ExprP<Ret> doExpand (ExpandContext& ctx,
3889 const ArgExprs& args) const
3891 ExprP<Mat4> mat = args.a;
3892 ExprP<Mat2> invA = bindExpression("invA", ctx,
3893 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3894 vec2(mat[1][0], mat[1][1]))));
3895 ExprP<Mat2> matB = bindExpression("matB", ctx,
3896 mat2(vec2(mat[2][0], mat[2][1]),
3897 vec2(mat[3][0], mat[3][1])));
3898 ExprP<Mat2> matC = bindExpression("matC", ctx,
3899 mat2(vec2(mat[0][2], mat[0][3]),
3900 vec2(mat[1][2], mat[1][3])));
3901 ExprP<Mat2> matD = bindExpression("matD", ctx,
3902 mat2(vec2(mat[2][2], mat[2][3]),
3903 vec2(mat[3][2], mat[3][3])));
3904 ExprP<Mat2> schur = bindExpression("schur", ctx,
3905 inverse(matD + -(matC * invA * matB)));
3906 ExprP<Mat2> blockA = bindExpression("blockA", ctx,
3907 invA + (invA * matB * schur * matC * invA));
3908 ExprP<Mat2> blockB = bindExpression("blockB", ctx,
3909 (-invA) * matB * schur);
3910 ExprP<Mat2> blockC = bindExpression("blockC", ctx,
3911 (-schur) * matC * invA);
3913 return mat4(vec4(blockA[0][0], blockA[0][1], blockC[0][0], blockC[0][1]),
3914 vec4(blockA[1][0], blockA[1][1], blockC[1][0], blockC[1][1]),
3915 vec4(blockB[0][0], blockB[0][1], schur[0][0], schur[0][1]),
3916 vec4(blockB[1][0], blockB[1][1], schur[1][0], schur[1][1]));
3920 class Fma : public DerivedFunc<Signature<float, float, float, float> >
3923 string getName (void) const
3928 string getRequiredExtension (const RenderContext& context) const
3930 return (glu::contextSupports(context.getType(), glu::ApiType::core(4, 5))) ? "" : "GL_EXT_gpu_shader5";
3934 ExprP<float> doExpand (ExpandContext&, const ArgExprs& x) const
3936 return x.a * x.b + x.c;
3942 using namespace Functions;
3944 template <typename T>
3945 ExprP<typename T::Element> ContainerExprPBase<T>::operator[] (int i) const
3947 return Functions::getComponent(exprP<T>(*this), i);
3950 ExprP<float> operator+ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3952 return app<Add>(arg0, arg1);
3955 ExprP<float> operator- (const ExprP<float>& arg0, const ExprP<float>& arg1)
3957 return app<Sub>(arg0, arg1);
3960 ExprP<float> operator- (const ExprP<float>& arg0)
3962 return app<Negate>(arg0);
3965 ExprP<float> operator* (const ExprP<float>& arg0, const ExprP<float>& arg1)
3967 return app<Mul>(arg0, arg1);
3970 ExprP<float> operator/ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3972 return app<Div>(arg0, arg1);
3975 template <typename Sig_, int Size>
3976 class GenFunc : public PrimitiveFunc<Signature<
3977 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3978 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3979 typename ContainerOf<typename Sig_::Arg1, Size>::Container,
3980 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
3981 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
3984 typedef typename GenFunc::IArgs IArgs;
3985 typedef typename GenFunc::IRet IRet;
3987 GenFunc (const Func<Sig_>& scalarFunc) : m_func (scalarFunc) {}
3989 string getName (void) const
3991 return m_func.getName();
3994 int getOutParamIndex (void) const
3996 return m_func.getOutParamIndex();
3999 string getRequiredExtension (const RenderContext &context) const
4001 return m_func.getRequiredExtension(context);
4005 void doPrint (ostream& os, const BaseArgExprs& args) const
4007 m_func.print(os, args);
4010 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
4014 for (int ndx = 0; ndx < Size; ++ndx)
4017 m_func.apply(ctx, iargs.a[ndx], iargs.b[ndx], iargs.c[ndx], iargs.d[ndx]);
4023 void doGetUsedFuncs (FuncSet& dst) const
4025 m_func.getUsedFuncs(dst);
4028 const Func<Sig_>& m_func;
4031 template <typename F, int Size>
4032 class VectorizedFunc : public GenFunc<typename F::Sig, Size>
4035 VectorizedFunc (void) : GenFunc<typename F::Sig, Size>(instance<F>()) {}
4040 template <typename Sig_, int Size>
4041 class FixedGenFunc : public PrimitiveFunc <Signature<
4042 typename ContainerOf<typename Sig_::Ret, Size>::Container,
4043 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
4044 typename Sig_::Arg1,
4045 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
4046 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
4049 typedef typename FixedGenFunc::IArgs IArgs;
4050 typedef typename FixedGenFunc::IRet IRet;
4052 string getName (void) const
4054 return this->doGetScalarFunc().getName();
4058 void doPrint (ostream& os, const BaseArgExprs& args) const
4060 this->doGetScalarFunc().print(os, args);
4063 IRet doApply (const EvalContext& ctx,
4064 const IArgs& iargs) const
4067 const Func<Sig_>& func = this->doGetScalarFunc();
4069 for (int ndx = 0; ndx < Size; ++ndx)
4070 ret[ndx] = func.apply(ctx, iargs.a[ndx], iargs.b, iargs.c[ndx], iargs.d[ndx]);
4075 virtual const Func<Sig_>& doGetScalarFunc (void) const = 0;
4078 template <typename F, int Size>
4079 class FixedVecFunc : public FixedGenFunc<typename F::Sig, Size>
4082 const Func<typename F::Sig>& doGetScalarFunc (void) const { return instance<F>(); }
4085 template<typename Sig>
4088 GenFuncs (const Func<Sig>& func_,
4089 const GenFunc<Sig, 2>& func2_,
4090 const GenFunc<Sig, 3>& func3_,
4091 const GenFunc<Sig, 4>& func4_)
4098 const Func<Sig>& func;
4099 const GenFunc<Sig, 2>& func2;
4100 const GenFunc<Sig, 3>& func3;
4101 const GenFunc<Sig, 4>& func4;
4104 template<typename F>
4105 GenFuncs<typename F::Sig> makeVectorizedFuncs (void)
4107 return GenFuncs<typename F::Sig>(instance<F>(),
4108 instance<VectorizedFunc<F, 2> >(),
4109 instance<VectorizedFunc<F, 3> >(),
4110 instance<VectorizedFunc<F, 4> >());
4114 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
4115 const ExprP<Vector<float, Size> >& arg1)
4117 return app<VectorizedFunc<Mul, Size> >(arg0, arg1);
4121 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
4122 const ExprP<float>& arg1)
4124 return app<FixedVecFunc<Mul, Size> >(arg0, arg1);
4128 ExprP<Vector<float, Size> > operator/(const ExprP<Vector<float, Size> >& arg0,
4129 const ExprP<float>& arg1)
4131 return app<FixedVecFunc<Div, Size> >(arg0, arg1);
4135 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0)
4137 return app<VectorizedFunc<Negate, Size> >(arg0);
4141 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
4142 const ExprP<Vector<float, Size> >& arg1)
4144 return app<VectorizedFunc<Sub, Size> >(arg0, arg1);
4147 template<int LeftRows, int Middle, int RightCols>
4148 ExprP<Matrix<float, LeftRows, RightCols> >
4149 operator* (const ExprP<Matrix<float, LeftRows, Middle> >& left,
4150 const ExprP<Matrix<float, Middle, RightCols> >& right)
4152 return app<MatMul<LeftRows, Middle, RightCols> >(left, right);
4155 template<int Rows, int Cols>
4156 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
4157 const ExprP<Matrix<float, Rows, Cols> >& right)
4159 return app<VecMatMul<Rows, Cols> >(left, right);
4162 template<int Rows, int Cols>
4163 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
4164 const ExprP<Vector<float, Rows> >& right)
4166 return app<MatVecMul<Rows, Cols> >(left, right);
4169 template<int Rows, int Cols>
4170 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
4171 const ExprP<float>& right)
4173 return app<ScalarMatFunc<Mul, Rows, Cols> >(left, right);
4176 template<int Rows, int Cols>
4177 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
4178 const ExprP<Matrix<float, Rows, Cols> >& right)
4180 return app<CompMatFunc<Add, Rows, Cols> >(left, right);
4183 template<int Rows, int Cols>
4184 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat)
4186 return app<MatNeg<Rows, Cols> >(mat);
4189 template <typename T>
4193 virtual void genFixeds (const FloatFormat&, vector<T>&) const {}
4194 virtual T genRandom (const FloatFormat&, Precision, Random&) const { return T(); }
4195 virtual double getWeight (void) const { return 0.0; }
4199 class DefaultSampling<Void> : public Sampling<Void>
4202 void genFixeds (const FloatFormat&, vector<Void>& dst) const { dst.push_back(Void()); }
4206 class DefaultSampling<bool> : public Sampling<bool>
4209 void genFixeds (const FloatFormat&, vector<bool>& dst) const
4211 dst.push_back(true);
4212 dst.push_back(false);
4217 class DefaultSampling<int> : public Sampling<int>
4220 int genRandom (const FloatFormat&, Precision prec, Random& rnd) const
4222 const int exp = rnd.getInt(0, getNumBits(prec)-2);
4223 const int sign = rnd.getBool() ? -1 : 1;
4225 return sign * rnd.getInt(0, (deInt32)1 << exp);
4228 void genFixeds (const FloatFormat&, vector<int>& dst) const
4234 double getWeight (void) const { return 1.0; }
4237 static inline int getNumBits (Precision prec)
4241 case glu::PRECISION_LOWP: return 8;
4242 case glu::PRECISION_MEDIUMP: return 16;
4243 case glu::PRECISION_HIGHP: return 32;
4252 class DefaultSampling<float> : public Sampling<float>
4255 float genRandom (const FloatFormat& format, Precision prec, Random& rnd) const;
4256 void genFixeds (const FloatFormat& format, vector<float>& dst) const;
4257 double getWeight (void) const { return 1.0; }
4260 //! Generate a random float from a reasonable general-purpose distribution.
4261 float DefaultSampling<float>::genRandom (const FloatFormat& format,
4265 const int minExp = format.getMinExp();
4266 const int maxExp = format.getMaxExp();
4267 const bool haveSubnormal = format.hasSubnormal() != tcu::NO;
4269 // Choose exponent so that the cumulative distribution is cubic.
4270 // This makes the probability distribution quadratic, with the peak centered on zero.
4271 const double minRoot = deCbrt(minExp - 0.5 - (haveSubnormal ? 1.0 : 0.0));
4272 const double maxRoot = deCbrt(maxExp + 0.5);
4273 const int fractionBits = format.getFractionBits();
4274 const int exp = int(deRoundEven(dePow(rnd.getDouble(minRoot, maxRoot),
4276 float base = 0.0f; // integral power of two
4277 float quantum = 0.0f; // smallest representable difference in the binade
4278 float significand = 0.0f; // Significand.
4280 DE_ASSERT(fractionBits < std::numeric_limits<float>::digits);
4282 // Generate some occasional special numbers
4283 switch (rnd.getInt(0, 64))
4286 case 1: return TCU_INFINITY;
4287 case 2: return -TCU_INFINITY;
4288 case 3: return TCU_NAN;
4295 base = deFloatLdExp(1.0f, exp);
4296 quantum = deFloatLdExp(1.0f, exp - fractionBits);
4302 quantum = deFloatLdExp(1.0f, minExp - fractionBits);
4305 switch (rnd.getInt(0, 16))
4307 case 0: // The highest number in this binade, significand is all bits one.
4308 significand = base - quantum;
4310 case 1: // Significand is one.
4311 significand = quantum;
4313 case 2: // Significand is zero.
4316 default: // Random (evenly distributed) significand.
4318 deUint64 intFraction = rnd.getUint64() & ((1ull << fractionBits) - 1);
4319 significand = float(intFraction) * quantum;
4323 // Produce positive numbers more often than negative.
4324 return (rnd.getInt(0,3) == 0 ? -1.0f : 1.0f) * (base + significand);
4327 //! Generate a standard set of floats that should always be tested.
4328 void DefaultSampling<float>::genFixeds (const FloatFormat& format, vector<float>& dst) const
4330 const int minExp = format.getMinExp();
4331 const int maxExp = format.getMaxExp();
4332 const int fractionBits = format.getFractionBits();
4333 const float minQuantum = deFloatLdExp(1.0f, minExp - fractionBits);
4334 const float minNormalized = deFloatLdExp(1.0f, minExp);
4335 const float maxQuantum = deFloatLdExp(1.0f, maxExp - fractionBits);
4338 dst.push_back(TCU_NAN);
4340 dst.push_back(0.0f);
4342 for (int sign = -1; sign <= 1; sign += 2)
4344 // Smallest subnormal
4345 dst.push_back((float)sign * minQuantum);
4347 // Largest subnormal
4348 dst.push_back((float)sign * (minNormalized - minQuantum));
4350 // Smallest normalized
4351 dst.push_back((float)sign * minNormalized);
4353 // Next smallest normalized
4354 dst.push_back((float)sign * (minNormalized + minQuantum));
4356 dst.push_back((float)sign * 0.5f);
4357 dst.push_back((float)sign * 1.0f);
4358 dst.push_back((float)sign * 2.0f);
4361 dst.push_back((float)sign * (deFloatLdExp(1.0f, maxExp) +
4362 (deFloatLdExp(1.0f, maxExp) - maxQuantum)));
4364 dst.push_back((float)sign * TCU_INFINITY);
4368 template <typename T, int Size>
4369 class DefaultSampling<Vector<T, Size> > : public Sampling<Vector<T, Size> >
4372 typedef Vector<T, Size> Value;
4374 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4378 for (int ndx = 0; ndx < Size; ++ndx)
4379 ret[ndx] = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4384 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4388 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4390 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4391 dst.push_back(Value(scalars[scalarNdx]));
4394 double getWeight (void) const
4396 return dePow(instance<DefaultSampling<T> >().getWeight(), Size);
4400 template <typename T, int Rows, int Columns>
4401 class DefaultSampling<Matrix<T, Rows, Columns> > : public Sampling<Matrix<T, Rows, Columns> >
4404 typedef Matrix<T, Rows, Columns> Value;
4406 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4410 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
4411 for (int colNdx = 0; colNdx < Columns; ++colNdx)
4412 ret(rowNdx, colNdx) = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4417 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4421 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4423 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4424 dst.push_back(Value(scalars[scalarNdx]));
4426 if (Columns == Rows)
4431 for (int ndx = 0; ndx < Columns; ++ndx)
4433 mat[Columns-1-ndx][ndx] = x;
4440 double getWeight (void) const
4442 return dePow(instance<DefaultSampling<T> >().getWeight(), Rows * Columns);
4448 Context (const string& name_,
4449 TestContext& testContext_,
4450 RenderContext& renderContext_,
4451 const FloatFormat& floatFormat_,
4452 const FloatFormat& highpFormat_,
4453 Precision precision_,
4454 ShaderType shaderType_,
4457 , testContext (testContext_)
4458 , renderContext (renderContext_)
4459 , floatFormat (floatFormat_)
4460 , highpFormat (highpFormat_)
4461 , precision (precision_)
4462 , shaderType (shaderType_)
4463 , numRandoms (numRandoms_) {}
4466 TestContext& testContext;
4467 RenderContext& renderContext;
4468 FloatFormat floatFormat;
4469 FloatFormat highpFormat;
4470 Precision precision;
4471 ShaderType shaderType;
4475 template<typename In0_ = Void, typename In1_ = Void, typename In2_ = Void, typename In3_ = Void>
4484 template <typename In>
4485 int numInputs (void)
4487 return (!isTypeValid<typename In::In0>() ? 0 :
4488 !isTypeValid<typename In::In1>() ? 1 :
4489 !isTypeValid<typename In::In2>() ? 2 :
4490 !isTypeValid<typename In::In3>() ? 3 :
4494 template<typename Out0_, typename Out1_ = Void>
4501 template <typename Out>
4502 int numOutputs (void)
4504 return (!isTypeValid<typename Out::Out0>() ? 0 :
4505 !isTypeValid<typename Out::Out1>() ? 1 :
4509 template<typename In>
4512 vector<typename In::In0> in0;
4513 vector<typename In::In1> in1;
4514 vector<typename In::In2> in2;
4515 vector<typename In::In3> in3;
4518 template<typename Out>
4521 Outputs (size_t size) : out0(size), out1(size) {}
4523 vector<typename Out::Out0> out0;
4524 vector<typename Out::Out1> out1;
4527 template<typename In, typename Out>
4530 VariableP<typename In::In0> in0;
4531 VariableP<typename In::In1> in1;
4532 VariableP<typename In::In2> in2;
4533 VariableP<typename In::In3> in3;
4534 VariableP<typename Out::Out0> out0;
4535 VariableP<typename Out::Out1> out1;
4538 template<typename In>
4541 Samplings (const Sampling<typename In::In0>& in0_,
4542 const Sampling<typename In::In1>& in1_,
4543 const Sampling<typename In::In2>& in2_,
4544 const Sampling<typename In::In3>& in3_)
4545 : in0 (in0_), in1 (in1_), in2 (in2_), in3 (in3_) {}
4547 const Sampling<typename In::In0>& in0;
4548 const Sampling<typename In::In1>& in1;
4549 const Sampling<typename In::In2>& in2;
4550 const Sampling<typename In::In3>& in3;
4553 template<typename In>
4554 struct DefaultSamplings : Samplings<In>
4556 DefaultSamplings (void)
4557 : Samplings<In>(instance<DefaultSampling<typename In::In0> >(),
4558 instance<DefaultSampling<typename In::In1> >(),
4559 instance<DefaultSampling<typename In::In2> >(),
4560 instance<DefaultSampling<typename In::In3> >()) {}
4563 class PrecisionCase : public TestCase
4566 IterateResult iterate (void);
4569 PrecisionCase (const Context& context,
4571 const string& extension = "")
4572 : TestCase (context.testContext,
4577 , m_rnd (0xdeadbeefu +
4578 context.testContext.getCommandLine().getBaseSeed())
4579 , m_extension (extension)
4583 RenderContext& getRenderContext(void) const { return m_ctx.renderContext; }
4585 const FloatFormat& getFormat (void) const { return m_ctx.floatFormat; }
4587 TestLog& log (void) const { return m_testCtx.getLog(); }
4589 virtual void runTest (void) = 0;
4591 template <typename In, typename Out>
4592 void testStatement (const Variables<In, Out>& variables,
4593 const Inputs<In>& inputs,
4594 const Statement& stmt);
4596 template<typename T>
4597 Symbol makeSymbol (const Variable<T>& variable)
4599 return Symbol(variable.getName(), getVarTypeOf<T>(m_ctx.precision));
4603 ResultCollector m_status;
4605 const string m_extension;
4608 IterateResult PrecisionCase::iterate (void)
4611 m_status.setTestContextResult(m_testCtx);
4615 template <typename In, typename Out>
4616 void PrecisionCase::testStatement (const Variables<In, Out>& variables,
4617 const Inputs<In>& inputs,
4618 const Statement& stmt)
4620 using namespace ShaderExecUtil;
4622 typedef typename In::In0 In0;
4623 typedef typename In::In1 In1;
4624 typedef typename In::In2 In2;
4625 typedef typename In::In3 In3;
4626 typedef typename Out::Out0 Out0;
4627 typedef typename Out::Out1 Out1;
4629 const FloatFormat& fmt = getFormat();
4630 const int inCount = numInputs<In>();
4631 const int outCount = numOutputs<Out>();
4632 const size_t numValues = (inCount > 0) ? inputs.in0.size() : 1;
4633 Outputs<Out> outputs (numValues);
4635 const FloatFormat highpFmt = m_ctx.highpFormat;
4636 const int maxMsgs = 100;
4638 Environment env; // Hoisted out of the inner loop for optimization.
4643 DE_ASSERT(inputs.in3.size() == numValues);
4646 DE_ASSERT(inputs.in2.size() == numValues);
4649 DE_ASSERT(inputs.in1.size() == numValues);
4652 DE_ASSERT(inputs.in0.size() == numValues);
4658 // Print out the statement and its definitions
4659 log() << TestLog::Message << "Statement: " << stmt << TestLog::EndMessage;
4664 stmt.getUsedFuncs(funcs);
4665 for (FuncSet::const_iterator it = funcs.begin(); it != funcs.end(); ++it)
4667 (*it)->printDefinition(oss);
4670 log() << TestLog::Message << "Reference definitions:\n" << oss.str()
4671 << TestLog::EndMessage;
4674 // Initialize ShaderSpec from precision, variables and statement.
4677 os << "precision " << glu::getPrecisionName(m_ctx.precision) << " float;\n";
4678 spec.globalDeclarations = os.str();
4681 spec.version = getContextTypeGLSLVersion(getRenderContext().getType());
4683 if (!m_extension.empty())
4684 spec.globalDeclarations = "#extension " + m_extension + " : require\n";
4686 spec.inputs.resize(inCount);
4691 spec.inputs[3] = makeSymbol(*variables.in3);
4694 spec.inputs[2] = makeSymbol(*variables.in2);
4697 spec.inputs[1] = makeSymbol(*variables.in1);
4700 spec.inputs[0] = makeSymbol(*variables.in0);
4706 spec.outputs.resize(outCount);
4710 case 2: spec.outputs[1] = makeSymbol(*variables.out1); // Fallthrough
4711 case 1: spec.outputs[0] = makeSymbol(*variables.out0);
4715 spec.source = de::toString(stmt);
4717 // Run the shader with inputs.
4719 UniquePtr<ShaderExecutor> executor (createExecutor(getRenderContext(),
4722 const void* inputArr[] =
4724 &inputs.in0.front(), &inputs.in1.front(), &inputs.in2.front(), &inputs.in3.front(),
4728 &outputs.out0.front(), &outputs.out1.front(),
4731 executor->log(log());
4732 if (!executor->isOk())
4733 TCU_FAIL("Shader compilation failed");
4735 executor->useProgram();
4736 executor->execute(int(numValues), inputArr, outputArr);
4739 // Initialize environment with unused values so we don't need to bind in inner loop.
4741 const typename Traits<In0>::IVal in0;
4742 const typename Traits<In1>::IVal in1;
4743 const typename Traits<In2>::IVal in2;
4744 const typename Traits<In3>::IVal in3;
4745 const typename Traits<Out0>::IVal reference0;
4746 const typename Traits<Out1>::IVal reference1;
4748 env.bind(*variables.in0, in0);
4749 env.bind(*variables.in1, in1);
4750 env.bind(*variables.in2, in2);
4751 env.bind(*variables.in3, in3);
4752 env.bind(*variables.out0, reference0);
4753 env.bind(*variables.out1, reference1);
4756 // For each input tuple, compute output reference interval and compare
4757 // shader output to the reference.
4758 for (size_t valueNdx = 0; valueNdx < numValues; valueNdx++)
4761 bool inExpectedRange;
4762 bool inWarningRange;
4763 const char* failStr = "Fail";
4764 typename Traits<Out0>::IVal reference0;
4765 typename Traits<Out1>::IVal reference1;
4767 if (valueNdx % (size_t)TOUCH_WATCHDOG_VALUE_FREQUENCY == 0)
4768 m_testCtx.touchWatchdog();
4770 env.lookup(*variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx]));
4771 env.lookup(*variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx]));
4772 env.lookup(*variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx]));
4773 env.lookup(*variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx]));
4776 EvalContext ctx (fmt, m_ctx.precision, env);
4783 reference1 = convert<Out1>(highpFmt, env.lookup(*variables.out1));
4784 inExpectedRange = contains(reference1, outputs.out1[valueNdx]);
4785 inWarningRange = containsWarning(reference1, outputs.out1[valueNdx]);
4786 if (!inExpectedRange && inWarningRange)
4788 m_status.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Shader output 1 has low-quality shader precision");
4789 failStr = "QualityWarning";
4792 else if (!inExpectedRange)
4794 m_status.addResult(QP_TEST_RESULT_FAIL, "Shader output 1 is outside acceptable range");
4801 reference0 = convert<Out0>(highpFmt, env.lookup(*variables.out0));
4802 inExpectedRange = contains(reference0, outputs.out0[valueNdx]);
4803 inWarningRange = containsWarning(reference0, outputs.out0[valueNdx]);
4804 if (!inExpectedRange && inWarningRange)
4806 m_status.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Shader output 0 has low-quality shader precision");
4807 failStr = "QualityWarning";
4810 else if (!inExpectedRange)
4812 m_status.addResult(QP_TEST_RESULT_FAIL, "Shader output 0 is outside acceptable range");
4823 if ((!result && numErrors <= maxMsgs) || GLS_LOG_ALL_RESULTS)
4825 MessageBuilder builder = log().message();
4827 builder << (result ? "Passed" : failStr) << " sample:\n";
4831 builder << "\t" << variables.in0->getName() << " = "
4832 << valueToString(highpFmt, inputs.in0[valueNdx]) << "\n";
4837 builder << "\t" << variables.in1->getName() << " = "
4838 << valueToString(highpFmt, inputs.in1[valueNdx]) << "\n";
4843 builder << "\t" << variables.in2->getName() << " = "
4844 << valueToString(highpFmt, inputs.in2[valueNdx]) << "\n";
4849 builder << "\t" << variables.in3->getName() << " = "
4850 << valueToString(highpFmt, inputs.in3[valueNdx]) << "\n";
4855 builder << "\t" << variables.out0->getName() << " = "
4856 << valueToString(highpFmt, outputs.out0[valueNdx]) << "\n"
4857 << "\tExpected range: "
4858 << intervalToString<typename Out::Out0>(highpFmt, reference0) << "\n";
4863 builder << "\t" << variables.out1->getName() << " = "
4864 << valueToString(highpFmt, outputs.out1[valueNdx]) << "\n"
4865 << "\tExpected range: "
4866 << intervalToString<typename Out::Out1>(highpFmt, reference1) << "\n";
4869 builder << TestLog::EndMessage;
4873 if (numErrors > maxMsgs)
4875 log() << TestLog::Message << "(Skipped " << (numErrors - maxMsgs) << " messages.)"
4876 << TestLog::EndMessage;
4881 log() << TestLog::Message << "All " << numValues << " inputs passed."
4882 << TestLog::EndMessage;
4886 log() << TestLog::Message << numErrors << "/" << numValues << " inputs failed or had quality warnings."
4887 << TestLog::EndMessage;
4893 template <typename T>
4896 bool operator() (const T& val1, const T& val2) const
4902 template <typename T>
4903 bool inputLess (const T& val1, const T& val2)
4905 return InputLess<T>()(val1, val2);
4909 struct InputLess<float>
4911 bool operator() (const float& val1, const float& val2) const
4921 template <typename T, int Size>
4922 struct InputLess<Vector<T, Size> >
4924 bool operator() (const Vector<T, Size>& vec1, const Vector<T, Size>& vec2) const
4926 for (int ndx = 0; ndx < Size; ++ndx)
4928 if (inputLess(vec1[ndx], vec2[ndx]))
4930 if (inputLess(vec2[ndx], vec1[ndx]))
4938 template <typename T, int Rows, int Cols>
4939 struct InputLess<Matrix<T, Rows, Cols> >
4941 bool operator() (const Matrix<T, Rows, Cols>& mat1,
4942 const Matrix<T, Rows, Cols>& mat2) const
4944 for (int col = 0; col < Cols; ++col)
4946 if (inputLess(mat1[col], mat2[col]))
4948 if (inputLess(mat2[col], mat1[col]))
4956 template <typename In>
4958 public Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4960 InTuple (const typename In::In0& in0,
4961 const typename In::In1& in1,
4962 const typename In::In2& in2,
4963 const typename In::In3& in3)
4964 : Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4965 (in0, in1, in2, in3) {}
4968 template <typename In>
4969 struct InputLess<InTuple<In> >
4971 bool operator() (const InTuple<In>& in1, const InTuple<In>& in2) const
4973 if (inputLess(in1.a, in2.a))
4975 if (inputLess(in2.a, in1.a))
4977 if (inputLess(in1.b, in2.b))
4979 if (inputLess(in2.b, in1.b))
4981 if (inputLess(in1.c, in2.c))
4983 if (inputLess(in2.c, in1.c))
4985 if (inputLess(in1.d, in2.d))
4991 template<typename In>
4992 Inputs<In> generateInputs (const Samplings<In>& samplings,
4993 const FloatFormat& floatFormat,
4994 Precision intPrecision,
4999 Inputs<In> fixedInputs;
5000 set<InTuple<In>, InputLess<InTuple<In> > > seenInputs;
5002 samplings.in0.genFixeds(floatFormat, fixedInputs.in0);
5003 samplings.in1.genFixeds(floatFormat, fixedInputs.in1);
5004 samplings.in2.genFixeds(floatFormat, fixedInputs.in2);
5005 samplings.in3.genFixeds(floatFormat, fixedInputs.in3);
5007 for (size_t ndx0 = 0; ndx0 < fixedInputs.in0.size(); ++ndx0)
5009 for (size_t ndx1 = 0; ndx1 < fixedInputs.in1.size(); ++ndx1)
5011 for (size_t ndx2 = 0; ndx2 < fixedInputs.in2.size(); ++ndx2)
5013 for (size_t ndx3 = 0; ndx3 < fixedInputs.in3.size(); ++ndx3)
5015 const InTuple<In> tuple (fixedInputs.in0[ndx0],
5016 fixedInputs.in1[ndx1],
5017 fixedInputs.in2[ndx2],
5018 fixedInputs.in3[ndx3]);
5020 seenInputs.insert(tuple);
5021 ret.in0.push_back(tuple.a);
5022 ret.in1.push_back(tuple.b);
5023 ret.in2.push_back(tuple.c);
5024 ret.in3.push_back(tuple.d);
5030 for (size_t ndx = 0; ndx < numSamples; ++ndx)
5032 const typename In::In0 in0 = samplings.in0.genRandom(floatFormat, intPrecision, rnd);
5033 const typename In::In1 in1 = samplings.in1.genRandom(floatFormat, intPrecision, rnd);
5034 const typename In::In2 in2 = samplings.in2.genRandom(floatFormat, intPrecision, rnd);
5035 const typename In::In3 in3 = samplings.in3.genRandom(floatFormat, intPrecision, rnd);
5036 const InTuple<In> tuple (in0, in1, in2, in3);
5038 if (de::contains(seenInputs, tuple))
5041 seenInputs.insert(tuple);
5042 ret.in0.push_back(in0);
5043 ret.in1.push_back(in1);
5044 ret.in2.push_back(in2);
5045 ret.in3.push_back(in3);
5051 class FuncCaseBase : public PrecisionCase
5054 IterateResult iterate (void);
5057 FuncCaseBase (const Context& context,
5059 const FuncBase& func)
5060 : PrecisionCase (context, name, func.getRequiredExtension(context.renderContext)) {}
5063 IterateResult FuncCaseBase::iterate (void)
5065 MovePtr<ContextInfo> info (ContextInfo::create(getRenderContext()));
5067 if (!m_extension.empty() && !info->isExtensionSupported(m_extension.c_str()) &&
5068 !glu::contextSupports(getRenderContext().getType(), glu::ApiType::core(4, 5)))
5069 throw NotSupportedError("Unsupported extension: " + m_extension);
5073 m_status.setTestContextResult(m_testCtx);
5077 template <typename Sig>
5078 class FuncCase : public FuncCaseBase
5081 typedef Func<Sig> CaseFunc;
5082 typedef typename Sig::Ret Ret;
5083 typedef typename Sig::Arg0 Arg0;
5084 typedef typename Sig::Arg1 Arg1;
5085 typedef typename Sig::Arg2 Arg2;
5086 typedef typename Sig::Arg3 Arg3;
5087 typedef InTypes<Arg0, Arg1, Arg2, Arg3> In;
5088 typedef OutTypes<Ret> Out;
5090 FuncCase (const Context& context,
5092 const CaseFunc& func)
5093 : FuncCaseBase (context, name, func)
5097 void runTest (void);
5099 virtual const Samplings<In>& getSamplings (void)
5101 return instance<DefaultSamplings<In> >();
5105 const CaseFunc& m_func;
5108 template <typename Sig>
5109 void FuncCase<Sig>::runTest (void)
5111 const Inputs<In> inputs (generateInputs(getSamplings(),
5116 Variables<In, Out> variables;
5118 variables.out0 = variable<Ret>("out0");
5119 variables.out1 = variable<Void>("out1");
5120 variables.in0 = variable<Arg0>("in0");
5121 variables.in1 = variable<Arg1>("in1");
5122 variables.in2 = variable<Arg2>("in2");
5123 variables.in3 = variable<Arg3>("in3");
5126 ExprP<Ret> expr = applyVar(m_func,
5127 variables.in0, variables.in1,
5128 variables.in2, variables.in3);
5129 StatementP stmt = variableAssignment(variables.out0, expr);
5131 this->testStatement(variables, inputs, *stmt);
5135 template <typename Sig>
5136 class InOutFuncCase : public FuncCaseBase
5139 typedef Func<Sig> CaseFunc;
5140 typedef typename Sig::Ret Ret;
5141 typedef typename Sig::Arg0 Arg0;
5142 typedef typename Sig::Arg1 Arg1;
5143 typedef typename Sig::Arg2 Arg2;
5144 typedef typename Sig::Arg3 Arg3;
5145 typedef InTypes<Arg0, Arg2, Arg3> In;
5146 typedef OutTypes<Ret, Arg1> Out;
5148 InOutFuncCase (const Context& context,
5150 const CaseFunc& func)
5151 : FuncCaseBase (context, name, func)
5155 void runTest (void);
5157 virtual const Samplings<In>& getSamplings (void)
5159 return instance<DefaultSamplings<In> >();
5163 const CaseFunc& m_func;
5166 template <typename Sig>
5167 void InOutFuncCase<Sig>::runTest (void)
5169 const Inputs<In> inputs (generateInputs(getSamplings(),
5174 Variables<In, Out> variables;
5176 variables.out0 = variable<Ret>("out0");
5177 variables.out1 = variable<Arg1>("out1");
5178 variables.in0 = variable<Arg0>("in0");
5179 variables.in1 = variable<Arg2>("in1");
5180 variables.in2 = variable<Arg3>("in2");
5181 variables.in3 = variable<Void>("in3");
5184 ExprP<Ret> expr = applyVar(m_func,
5185 variables.in0, variables.out1,
5186 variables.in1, variables.in2);
5187 StatementP stmt = variableAssignment(variables.out0, expr);
5189 this->testStatement(variables, inputs, *stmt);
5193 template <typename Sig>
5194 PrecisionCase* createFuncCase (const Context& context,
5196 const Func<Sig>& func)
5198 switch (func.getOutParamIndex())
5201 return new FuncCase<Sig>(context, name, func);
5203 return new InOutFuncCase<Sig>(context, name, func);
5205 DE_FATAL("Impossible");
5213 virtual ~CaseFactory (void) {}
5214 virtual MovePtr<TestNode> createCase (const Context& ctx) const = 0;
5215 virtual string getName (void) const = 0;
5216 virtual string getDesc (void) const = 0;
5219 class FuncCaseFactory : public CaseFactory
5222 virtual const FuncBase& getFunc (void) const = 0;
5224 string getName (void) const
5226 return de::toLower(getFunc().getName());
5229 string getDesc (void) const
5231 return "Function '" + getFunc().getName() + "'";
5235 template <typename Sig>
5236 class GenFuncCaseFactory : public CaseFactory
5240 GenFuncCaseFactory (const GenFuncs<Sig>& funcs,
5243 , m_name (de::toLower(name)) {}
5245 MovePtr<TestNode> createCase (const Context& ctx) const
5247 TestCaseGroup* group = new TestCaseGroup(ctx.testContext,
5248 ctx.name.c_str(), ctx.name.c_str());
5250 group->addChild(createFuncCase(ctx, "scalar", m_funcs.func));
5251 group->addChild(createFuncCase(ctx, "vec2", m_funcs.func2));
5252 group->addChild(createFuncCase(ctx, "vec3", m_funcs.func3));
5253 group->addChild(createFuncCase(ctx, "vec4", m_funcs.func4));
5255 return MovePtr<TestNode>(group);
5258 string getName (void) const
5263 string getDesc (void) const
5265 return "Function '" + m_funcs.func.getName() + "'";
5269 const GenFuncs<Sig> m_funcs;
5273 template <template <int> class GenF>
5274 class TemplateFuncCaseFactory : public FuncCaseFactory
5277 MovePtr<TestNode> createCase (const Context& ctx) const
5279 TestCaseGroup* group = new TestCaseGroup(ctx.testContext,
5280 ctx.name.c_str(), ctx.name.c_str());
5281 group->addChild(createFuncCase(ctx, "scalar", instance<GenF<1> >()));
5282 group->addChild(createFuncCase(ctx, "vec2", instance<GenF<2> >()));
5283 group->addChild(createFuncCase(ctx, "vec3", instance<GenF<3> >()));
5284 group->addChild(createFuncCase(ctx, "vec4", instance<GenF<4> >()));
5286 return MovePtr<TestNode>(group);
5289 const FuncBase& getFunc (void) const { return instance<GenF<1> >(); }
5292 template <template <int> class GenF>
5293 class SquareMatrixFuncCaseFactory : public FuncCaseFactory
5296 MovePtr<TestNode> createCase (const Context& ctx) const
5298 TestCaseGroup* group = new TestCaseGroup(ctx.testContext,
5299 ctx.name.c_str(), ctx.name.c_str());
5300 group->addChild(createFuncCase(ctx, "mat2", instance<GenF<2> >()));
5302 // disabled until we get reasonable results
5303 group->addChild(createFuncCase(ctx, "mat3", instance<GenF<3> >()));
5304 group->addChild(createFuncCase(ctx, "mat4", instance<GenF<4> >()));
5307 return MovePtr<TestNode>(group);
5310 const FuncBase& getFunc (void) const { return instance<GenF<2> >(); }
5313 template <template <int, int> class GenF>
5314 class MatrixFuncCaseFactory : public FuncCaseFactory
5317 MovePtr<TestNode> createCase (const Context& ctx) const
5319 TestCaseGroup* const group = new TestCaseGroup(ctx.testContext,
5320 ctx.name.c_str(), ctx.name.c_str());
5322 this->addCase<2, 2>(ctx, group);
5323 this->addCase<3, 2>(ctx, group);
5324 this->addCase<4, 2>(ctx, group);
5325 this->addCase<2, 3>(ctx, group);
5326 this->addCase<3, 3>(ctx, group);
5327 this->addCase<4, 3>(ctx, group);
5328 this->addCase<2, 4>(ctx, group);
5329 this->addCase<3, 4>(ctx, group);
5330 this->addCase<4, 4>(ctx, group);
5332 return MovePtr<TestNode>(group);
5335 const FuncBase& getFunc (void) const { return instance<GenF<2,2> >(); }
5338 template <int Rows, int Cols>
5339 void addCase (const Context& ctx, TestCaseGroup* group) const
5341 const char* const name = dataTypeNameOf<Matrix<float, Rows, Cols> >();
5343 group->addChild(createFuncCase(ctx, name, instance<GenF<Rows, Cols> >()));
5347 template <typename Sig>
5348 class SimpleFuncCaseFactory : public CaseFactory
5351 SimpleFuncCaseFactory (const Func<Sig>& func) : m_func(func) {}
5353 MovePtr<TestNode> createCase (const Context& ctx) const
5355 return MovePtr<TestNode>(createFuncCase(ctx, ctx.name.c_str(), m_func));
5358 string getName (void) const
5360 return de::toLower(m_func.getName());
5363 string getDesc (void) const
5365 return "Function '" + getName() + "'";
5369 const Func<Sig>& m_func;
5372 template <typename F>
5373 SharedPtr<SimpleFuncCaseFactory<typename F::Sig> > createSimpleFuncCaseFactory (void)
5375 return SharedPtr<SimpleFuncCaseFactory<typename F::Sig> >(
5376 new SimpleFuncCaseFactory<typename F::Sig>(instance<F>()));
5379 class BuiltinFuncs : public CaseFactories
5382 const vector<const CaseFactory*> getFactories (void) const
5384 vector<const CaseFactory*> ret;
5386 for (size_t ndx = 0; ndx < m_factories.size(); ++ndx)
5387 ret.push_back(m_factories[ndx].get());
5392 void addFactory (SharedPtr<const CaseFactory> fact)
5394 m_factories.push_back(fact);
5398 vector<SharedPtr<const CaseFactory> > m_factories;
5401 template <typename F>
5402 void addScalarFactory(BuiltinFuncs& funcs, string name = "")
5405 name = instance<F>().getName();
5407 funcs.addFactory(SharedPtr<const CaseFactory>(new GenFuncCaseFactory<typename F::Sig>(
5408 makeVectorizedFuncs<F>(), name)));
5411 MovePtr<const CaseFactories> createES3BuiltinCases (void)
5413 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5415 addScalarFactory<Add>(*funcs);
5416 addScalarFactory<Sub>(*funcs);
5417 addScalarFactory<Mul>(*funcs);
5418 addScalarFactory<Div>(*funcs);
5420 addScalarFactory<Radians>(*funcs);
5421 addScalarFactory<Degrees>(*funcs);
5422 addScalarFactory<Sin>(*funcs);
5423 addScalarFactory<Cos>(*funcs);
5424 addScalarFactory<Tan>(*funcs);
5425 addScalarFactory<ASin>(*funcs);
5426 addScalarFactory<ACos>(*funcs);
5427 addScalarFactory<ATan2>(*funcs, "atan2");
5428 addScalarFactory<ATan>(*funcs);
5429 addScalarFactory<Sinh>(*funcs);
5430 addScalarFactory<Cosh>(*funcs);
5431 addScalarFactory<Tanh>(*funcs);
5432 addScalarFactory<ASinh>(*funcs);
5433 addScalarFactory<ACosh>(*funcs);
5434 addScalarFactory<ATanh>(*funcs);
5436 addScalarFactory<Pow>(*funcs);
5437 addScalarFactory<Exp>(*funcs);
5438 addScalarFactory<Log>(*funcs);
5439 addScalarFactory<Exp2>(*funcs);
5440 addScalarFactory<Log2>(*funcs);
5441 addScalarFactory<Sqrt>(*funcs);
5442 addScalarFactory<InverseSqrt>(*funcs);
5444 addScalarFactory<Abs>(*funcs);
5445 addScalarFactory<Sign>(*funcs);
5446 addScalarFactory<Floor>(*funcs);
5447 addScalarFactory<Trunc>(*funcs);
5448 addScalarFactory<Round>(*funcs);
5449 addScalarFactory<RoundEven>(*funcs);
5450 addScalarFactory<Ceil>(*funcs);
5451 addScalarFactory<Fract>(*funcs);
5452 addScalarFactory<Mod>(*funcs);
5453 funcs->addFactory(createSimpleFuncCaseFactory<Modf>());
5454 addScalarFactory<Min>(*funcs);
5455 addScalarFactory<Max>(*funcs);
5456 addScalarFactory<Clamp>(*funcs);
5457 addScalarFactory<Mix>(*funcs);
5458 addScalarFactory<Step>(*funcs);
5459 addScalarFactory<SmoothStep>(*funcs);
5461 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length>()));
5462 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance>()));
5463 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot>()));
5464 funcs->addFactory(createSimpleFuncCaseFactory<Cross>());
5465 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize>()));
5466 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward>()));
5467 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect>()));
5468 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract>()));
5471 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<MatrixCompMult>()));
5472 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct>()));
5473 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose>()));
5474 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant>()));
5475 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse>()));
5477 return MovePtr<const CaseFactories>(funcs.release());
5480 MovePtr<const CaseFactories> createES31BuiltinCases (void)
5482 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5484 addScalarFactory<FrExp>(*funcs);
5485 addScalarFactory<LdExp>(*funcs);
5486 addScalarFactory<Fma>(*funcs);
5488 return MovePtr<const CaseFactories>(funcs.release());
5491 struct PrecisionTestContext
5493 PrecisionTestContext (TestContext& testCtx_,
5494 RenderContext& renderCtx_,
5495 const FloatFormat& highp_,
5496 const FloatFormat& mediump_,
5497 const FloatFormat& lowp_,
5498 const vector<ShaderType>& shaderTypes_,
5500 : testCtx (testCtx_)
5501 , renderCtx (renderCtx_)
5502 , shaderTypes (shaderTypes_)
5503 , numRandoms (numRandoms_)
5505 formats[glu::PRECISION_HIGHP] = &highp_;
5506 formats[glu::PRECISION_MEDIUMP] = &mediump_;
5507 formats[glu::PRECISION_LOWP] = &lowp_;
5510 TestContext& testCtx;
5511 RenderContext& renderCtx;
5512 const FloatFormat* formats[glu::PRECISION_LAST];
5513 vector<ShaderType> shaderTypes;
5517 TestCaseGroup* createFuncGroup (const PrecisionTestContext& ctx,
5518 const CaseFactory& factory)
5520 TestCaseGroup* const group = new TestCaseGroup(ctx.testCtx,
5521 factory.getName().c_str(),
5522 factory.getDesc().c_str());
5524 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; ++precNdx)
5526 const Precision precision = Precision(precNdx);
5527 const string precName (glu::getPrecisionName(precision));
5528 const FloatFormat& fmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats, precNdx);
5529 const FloatFormat& highpFmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats,
5530 glu::PRECISION_HIGHP);
5532 for (size_t shaderNdx = 0; shaderNdx < ctx.shaderTypes.size(); ++shaderNdx)
5534 const ShaderType shaderType = ctx.shaderTypes[shaderNdx];
5535 const string shaderName (glu::getShaderTypeName(shaderType));
5536 const string name = precName + "_" + shaderName;
5537 const Context caseCtx (name, ctx.testCtx, ctx.renderCtx, fmt, highpFmt,
5538 precision, shaderType, ctx.numRandoms);
5540 group->addChild(factory.createCase(caseCtx).release());
5547 void addBuiltinPrecisionTests (TestContext& testCtx,
5548 RenderContext& renderCtx,
5549 const CaseFactories& cases,
5550 const vector<ShaderType>& shaderTypes,
5551 TestCaseGroup& dstGroup)
5553 const int userRandoms = testCtx.getCommandLine().getTestIterationCount();
5554 const int defRandoms = 16384;
5555 const int numRandoms = userRandoms > 0 ? userRandoms : defRandoms;
5556 const FloatFormat highp (-126, 127, 23, true,
5557 tcu::MAYBE, // subnormals
5558 tcu::YES, // infinities
5560 // \todo [2014-04-01 lauri] Check these once Khronos bug 11840 is resolved.
5561 const FloatFormat mediump (-13, 13, 9, false);
5562 // A fixed-point format is just a floating point format with a fixed
5563 // exponent and support for subnormals.
5564 const FloatFormat lowp (0, 0, 7, false, tcu::YES);
5565 const PrecisionTestContext ctx (testCtx, renderCtx, highp, mediump, lowp,
5566 shaderTypes, numRandoms);
5568 for (size_t ndx = 0; ndx < cases.getFactories().size(); ++ndx)
5569 dstGroup.addChild(createFuncGroup(ctx, *cases.getFactories()[ndx]));
5572 } // BuiltinPrecisionTests