1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and/or associated documentation files (the
10 * "Materials"), to deal in the Materials without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Materials, and to
13 * permit persons to whom the Materials are furnished to do so, subject to
14 * the following conditions:
16 * The above copyright notice(s) and this permission notice shall be included
17 * in all copies or substantial portions of the Materials.
19 * The Materials are Confidential Information as defined by the
20 * Khronos Membership Agreement until designated non-confidential by Khronos,
21 * at which point this condition clause shall be removed.
23 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
26 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
27 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
28 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
33 * \brief Precision and range tests for builtins and types.
35 *//*--------------------------------------------------------------------*/
37 #include "vktShaderBuiltinPrecisionTests.hpp"
38 #include "vktShaderExecutor.hpp"
43 #include "deRandom.hpp"
44 #include "deSTLUtil.hpp"
45 #include "deStringUtil.hpp"
46 #include "deUniquePtr.hpp"
47 #include "deSharedPtr.hpp"
48 #include "deArrayUtil.hpp"
50 #include "tcuCommandLine.hpp"
51 #include "tcuFloatFormat.hpp"
52 #include "tcuInterval.hpp"
53 #include "tcuTestLog.hpp"
54 #include "tcuVector.hpp"
55 #include "tcuMatrix.hpp"
56 #include "tcuResultCollector.hpp"
58 #include "gluContextInfo.hpp"
59 #include "gluVarType.hpp"
60 #include "gluRenderContext.hpp"
61 #include "glwDefs.hpp"
70 // Uncomment this to get evaluation trace dumps to std::cerr
71 // #define GLS_ENABLE_TRACE
73 // set this to true to dump even passing results
74 #define GLS_LOG_ALL_RESULTS false
78 namespace shaderexecutor
84 using std::ostringstream;
94 using tcu::FloatFormat;
95 using tcu::MessageBuilder;
102 using glu::ShaderType;
104 /*--------------------------------------------------------------------*//*!
105 * \brief Generic singleton creator.
107 * instance<T>() returns a reference to a unique default-constructed instance
108 * of T. This is mainly used for our GLSL function implementations: each
109 * function is implemented by an object, and each of the objects has a
110 * distinct class. It would be extremely toilsome to maintain a separate
111 * context object that contained individual instances of the function classes,
112 * so we have to resort to global singleton instances.
114 *//*--------------------------------------------------------------------*/
115 template <typename T>
116 const T& instance (void)
118 static const T s_instance = T();
122 /*--------------------------------------------------------------------*//*!
123 * \brief Dummy placeholder type for unused template parameters.
125 * In the precision tests we are dealing with functions of different arities.
126 * To minimize code duplication, we only define templates with the maximum
127 * number of arguments, currently four. If a function's arity is less than the
128 * maximum, Void us used as the type for unused arguments.
130 * Although Voids are not used at run-time, they still must be compilable, so
131 * they must support all operations that other types do.
133 *//*--------------------------------------------------------------------*/
136 typedef Void Element;
142 template <typename T>
143 explicit Void (const T&) {}
145 operator double (void) const { return TCU_NAN; }
147 // These are used to make Voids usable as containers in container-generic code.
148 Void& operator[] (int) { return *this; }
149 const Void& operator[] (int) const { return *this; }
152 ostream& operator<< (ostream& os, Void) { return os << "()"; }
154 //! Returns true for all other types except Void
155 template <typename T> bool isTypeValid (void) { return true; }
156 template <> bool isTypeValid<Void> (void) { return false; }
158 //! Utility function for getting the name of a data type.
159 //! This is used in vector and matrix constructors.
160 template <typename T>
161 const char* dataTypeNameOf (void)
163 return glu::getDataTypeName(glu::dataTypeOf<T>());
167 const char* dataTypeNameOf<Void> (void)
169 DE_FATAL("Impossible");
173 //! A hack to get Void support for VarType.
174 template <typename T>
175 VarType getVarTypeOf (Precision prec = glu::PRECISION_LAST)
177 return glu::varTypeOf<T>(prec);
181 VarType getVarTypeOf<Void> (Precision)
183 DE_FATAL("Impossible");
187 /*--------------------------------------------------------------------*//*!
188 * \brief Type traits for generalized interval types.
190 * We are trying to compute sets of acceptable values not only for
191 * float-valued expressions but also for compound values: vectors and
192 * matrices. We approximate a set of vectors as a vector of intervals and
193 * likewise for matrices.
195 * We now need generalized operations for each type and its interval
196 * approximation. These are given in the type Traits<T>.
198 * The type Traits<T>::IVal is the approximation of T: it is `Interval` for
199 * scalar types, and a vector or matrix of intervals for container types.
201 * To allow template inference to take place, there are function wrappers for
202 * the actual operations in Traits<T>. Hence we can just use:
204 * makeIVal(someFloat)
208 * Traits<float>::doMakeIVal(value)
210 *//*--------------------------------------------------------------------*/
212 template <typename T> struct Traits;
214 //! Create container from elementwise singleton values.
215 template <typename T>
216 typename Traits<T>::IVal makeIVal (const T& value)
218 return Traits<T>::doMakeIVal(value);
221 //! Elementwise union of intervals.
222 template <typename T>
223 typename Traits<T>::IVal unionIVal (const typename Traits<T>::IVal& a,
224 const typename Traits<T>::IVal& b)
226 return Traits<T>::doUnion(a, b);
229 //! Returns true iff every element of `ival` contains the corresponding element of `value`.
230 template <typename T>
231 bool contains (const typename Traits<T>::IVal& ival, const T& value)
233 return Traits<T>::doContains(ival, value);
236 //! Print out an interval with the precision of `fmt`.
237 template <typename T>
238 void printIVal (const FloatFormat& fmt, const typename Traits<T>::IVal& ival, ostream& os)
240 Traits<T>::doPrintIVal(fmt, ival, os);
243 template <typename T>
244 string intervalToString (const FloatFormat& fmt, const typename Traits<T>::IVal& ival)
247 printIVal<T>(fmt, ival, oss);
251 //! Print out a value with the precision of `fmt`.
252 template <typename T>
253 void printValue (const FloatFormat& fmt, const T& value, ostream& os)
255 Traits<T>::doPrintValue(fmt, value, os);
258 template <typename T>
259 string valueToString (const FloatFormat& fmt, const T& val)
262 printValue(fmt, val, oss);
266 //! Approximate `value` elementwise to the float precision defined in `fmt`.
267 //! The resulting interval might not be a singleton if rounding in both
268 //! directions is allowed.
269 template <typename T>
270 typename Traits<T>::IVal round (const FloatFormat& fmt, const T& value)
272 return Traits<T>::doRound(fmt, value);
275 template <typename T>
276 typename Traits<T>::IVal convert (const FloatFormat& fmt,
277 const typename Traits<T>::IVal& value)
279 return Traits<T>::doConvert(fmt, value);
282 //! Common traits for scalar types.
283 template <typename T>
286 typedef Interval IVal;
288 static Interval doMakeIVal (const T& value)
290 // Thankfully all scalar types have a well-defined conversion to `double`,
291 // hence Interval can represent their ranges without problems.
292 return Interval(double(value));
295 static Interval doUnion (const Interval& a, const Interval& b)
300 static bool doContains (const Interval& a, T value)
302 return a.contains(double(value));
305 static Interval doConvert (const FloatFormat& fmt, const IVal& ival)
307 return fmt.convert(ival);
310 static Interval doRound (const FloatFormat& fmt, T value)
312 return fmt.roundOut(double(value), false);
317 struct Traits<float> : ScalarTraits<float>
319 static void doPrintIVal (const FloatFormat& fmt,
320 const Interval& ival,
323 os << fmt.intervalToHex(ival);
326 static void doPrintValue (const FloatFormat& fmt,
330 os << fmt.floatToHex(value);
335 struct Traits<bool> : ScalarTraits<bool>
337 static void doPrintValue (const FloatFormat&,
341 os << (value != 0.0f ? "true" : "false");
344 static void doPrintIVal (const FloatFormat&,
345 const Interval& ival,
349 if (ival.contains(false))
351 if (ival.contains(false) && ival.contains(true))
353 if (ival.contains(true))
360 struct Traits<int> : ScalarTraits<int>
362 static void doPrintValue (const FloatFormat&,
369 static void doPrintIVal (const FloatFormat&,
370 const Interval& ival,
373 os << "[" << int(ival.lo()) << ", " << int(ival.hi()) << "]";
377 //! Common traits for containers, i.e. vectors and matrices.
378 //! T is the container type itself, I is the same type with interval elements.
379 template <typename T, typename I>
380 struct ContainerTraits
382 typedef typename T::Element Element;
385 static IVal doMakeIVal (const T& value)
389 for (int ndx = 0; ndx < T::SIZE; ++ndx)
390 ret[ndx] = makeIVal(value[ndx]);
395 static IVal doUnion (const IVal& a, const IVal& b)
399 for (int ndx = 0; ndx < T::SIZE; ++ndx)
400 ret[ndx] = unionIVal<Element>(a[ndx], b[ndx]);
405 static bool doContains (const IVal& ival, const T& value)
407 for (int ndx = 0; ndx < T::SIZE; ++ndx)
408 if (!contains(ival[ndx], value[ndx]))
414 static void doPrintIVal (const FloatFormat& fmt, const IVal ival, ostream& os)
418 for (int ndx = 0; ndx < T::SIZE; ++ndx)
423 printIVal<Element>(fmt, ival[ndx], os);
429 static void doPrintValue (const FloatFormat& fmt, const T& value, ostream& os)
431 os << dataTypeNameOf<T>() << "(";
433 for (int ndx = 0; ndx < T::SIZE; ++ndx)
438 printValue<Element>(fmt, value[ndx], os);
444 static IVal doConvert (const FloatFormat& fmt, const IVal& value)
448 for (int ndx = 0; ndx < T::SIZE; ++ndx)
449 ret[ndx] = convert<Element>(fmt, value[ndx]);
454 static IVal doRound (const FloatFormat& fmt, T value)
458 for (int ndx = 0; ndx < T::SIZE; ++ndx)
459 ret[ndx] = round(fmt, value[ndx]);
465 template <typename T, int Size>
466 struct Traits<Vector<T, Size> > :
467 ContainerTraits<Vector<T, Size>, Vector<typename Traits<T>::IVal, Size> >
471 template <typename T, int Rows, int Cols>
472 struct Traits<Matrix<T, Rows, Cols> > :
473 ContainerTraits<Matrix<T, Rows, Cols>, Matrix<typename Traits<T>::IVal, Rows, Cols> >
477 //! Void traits. These are just dummies, but technically valid: a Void is a
478 //! unit type with a single possible value.
484 static Void doMakeIVal (const Void& value) { return value; }
485 static Void doUnion (const Void&, const Void&) { return Void(); }
486 static bool doContains (const Void&, Void) { return true; }
487 static Void doRound (const FloatFormat&, const Void& value) { return value; }
488 static Void doConvert (const FloatFormat&, const Void& value) { return value; }
490 static void doPrintValue (const FloatFormat&, const Void&, ostream& os)
495 static void doPrintIVal (const FloatFormat&, const Void&, ostream& os)
501 //! This is needed for container-generic operations.
502 //! We want a scalar type T to be its own "one-element vector".
503 template <typename T, int Size> struct ContainerOf { typedef Vector<T, Size> Container; };
505 template <typename T> struct ContainerOf<T, 1> { typedef T Container; };
506 template <int Size> struct ContainerOf<Void, Size> { typedef Void Container; };
508 // This is a kludge that is only needed to get the ExprP::operator[] syntactic sugar to work.
509 template <typename T> struct ElementOf { typedef typename T::Element Element; };
510 template <> struct ElementOf<float> { typedef void Element; };
511 template <> struct ElementOf<bool> { typedef void Element; };
512 template <> struct ElementOf<int> { typedef void Element; };
514 /*--------------------------------------------------------------------*//*!
516 * \name Abstract syntax for expressions and statements.
518 * We represent GLSL programs as syntax objects: an Expr<T> represents an
519 * expression whose GLSL type corresponds to the C++ type T, and a Statement
520 * represents a statement.
522 * To ease memory management, we use shared pointers to refer to expressions
523 * and statements. ExprP<T> is a shared pointer to an Expr<T>, and StatementP
524 * is a shared pointer to a Statement.
528 *//*--------------------------------------------------------------------*/
535 template <typename T> class ExprP;
536 template <typename T> class Variable;
537 template <typename T> class VariableP;
538 template <typename T> class DefaultSampling;
540 typedef set<const FuncBase*> FuncSet;
542 template <typename T>
543 VariableP<T> variable (const string& name);
544 StatementP compoundStatement (const vector<StatementP>& statements);
546 /*--------------------------------------------------------------------*//*!
547 * \brief A variable environment.
549 * An Environment object maintains the mapping between variables of the
550 * abstract syntax tree and their values.
552 * \todo [2014-03-28 lauri] At least run-time type safety.
554 *//*--------------------------------------------------------------------*/
559 void bind (const Variable<T>& variable,
560 const typename Traits<T>::IVal& value)
562 deUint8* const data = new deUint8[sizeof(value)];
564 deMemcpy(data, &value, sizeof(value));
565 de::insert(m_map, variable.getName(), SharedPtr<deUint8>(data, de::ArrayDeleter<deUint8>()));
569 typename Traits<T>::IVal& lookup (const Variable<T>& variable) const
571 deUint8* const data = de::lookup(m_map, variable.getName()).get();
573 return *reinterpret_cast<typename Traits<T>::IVal*>(data);
577 map<string, SharedPtr<deUint8> > m_map;
580 /*--------------------------------------------------------------------*//*!
581 * \brief Evaluation context.
583 * The evaluation context contains everything that separates one execution of
584 * an expression from the next. Currently this means the desired floating
585 * point precision and the current variable environment.
587 *//*--------------------------------------------------------------------*/
590 EvalContext (const FloatFormat& format_,
591 Precision floatPrecision_,
595 , floatPrecision (floatPrecision_)
597 , callDepth (callDepth_) {}
600 Precision floatPrecision;
605 /*--------------------------------------------------------------------*//*!
606 * \brief Simple incremental counter.
608 * This is used to make sure that different ExpandContexts will not produce
609 * overlapping temporary names.
611 *//*--------------------------------------------------------------------*/
615 Counter (int count = 0) : m_count(count) {}
616 int operator() (void) { return m_count++; }
625 ExpandContext (Counter& symCounter) : m_symCounter(symCounter) {}
626 ExpandContext (const ExpandContext& parent)
627 : m_symCounter(parent.m_symCounter) {}
630 VariableP<T> genSym (const string& baseName)
632 return variable<T>(baseName + de::toString(m_symCounter()));
635 void addStatement (const StatementP& stmt)
637 m_statements.push_back(stmt);
640 vector<StatementP> getStatements (void) const
645 Counter& m_symCounter;
646 vector<StatementP> m_statements;
649 /*--------------------------------------------------------------------*//*!
650 * \brief A statement or declaration.
652 * Statements have no values. Instead, they are executed for their side
653 * effects only: the execute() method should modify at least one variable in
656 * As a bit of a kludge, a Statement object can also represent a declaration:
657 * when it is evaluated, it can add a variable binding to the environment
658 * instead of modifying a current one.
660 *//*--------------------------------------------------------------------*/
664 virtual ~Statement (void) { }
665 //! Execute the statement, modifying the environment of `ctx`
666 void execute (EvalContext& ctx) const { this->doExecute(ctx); }
667 void print (ostream& os) const { this->doPrint(os); }
668 //! Add the functions used in this statement to `dst`.
669 void getUsedFuncs (FuncSet& dst) const { this->doGetUsedFuncs(dst); }
672 virtual void doPrint (ostream& os) const = 0;
673 virtual void doExecute (EvalContext& ctx) const = 0;
674 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
677 ostream& operator<<(ostream& os, const Statement& stmt)
683 /*--------------------------------------------------------------------*//*!
684 * \brief Smart pointer for statements (and declarations)
686 *//*--------------------------------------------------------------------*/
687 class StatementP : public SharedPtr<const Statement>
690 typedef SharedPtr<const Statement> Super;
693 explicit StatementP (const Statement* ptr) : Super(ptr) {}
694 StatementP (const Super& ptr) : Super(ptr) {}
697 /*--------------------------------------------------------------------*//*!
700 * A statement that modifies a variable or a declaration that binds a variable.
702 *//*--------------------------------------------------------------------*/
703 template <typename T>
704 class VariableStatement : public Statement
707 VariableStatement (const VariableP<T>& variable, const ExprP<T>& value,
709 : m_variable (variable)
711 , m_isDeclaration (isDeclaration) {}
714 void doPrint (ostream& os) const
717 os << glu::declare(getVarTypeOf<T>(), m_variable->getName());
719 os << m_variable->getName();
721 os << " = " << *m_value << ";\n";
724 void doExecute (EvalContext& ctx) const
727 ctx.env.bind(*m_variable, m_value->evaluate(ctx));
729 ctx.env.lookup(*m_variable) = m_value->evaluate(ctx);
732 void doGetUsedFuncs (FuncSet& dst) const
734 m_value->getUsedFuncs(dst);
737 VariableP<T> m_variable;
739 bool m_isDeclaration;
742 template <typename T>
743 StatementP variableStatement (const VariableP<T>& variable,
744 const ExprP<T>& value,
747 return StatementP(new VariableStatement<T>(variable, value, isDeclaration));
750 template <typename T>
751 StatementP variableDeclaration (const VariableP<T>& variable, const ExprP<T>& definiens)
753 return variableStatement(variable, definiens, true);
756 template <typename T>
757 StatementP variableAssignment (const VariableP<T>& variable, const ExprP<T>& value)
759 return variableStatement(variable, value, false);
762 /*--------------------------------------------------------------------*//*!
763 * \brief A compound statement, i.e. a block.
765 * A compound statement is executed by executing its constituent statements in
768 *//*--------------------------------------------------------------------*/
769 class CompoundStatement : public Statement
772 CompoundStatement (const vector<StatementP>& statements)
773 : m_statements (statements) {}
776 void doPrint (ostream& os) const
780 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
781 os << *m_statements[ndx];
786 void doExecute (EvalContext& ctx) const
788 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
789 m_statements[ndx]->execute(ctx);
792 void doGetUsedFuncs (FuncSet& dst) const
794 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
795 m_statements[ndx]->getUsedFuncs(dst);
798 vector<StatementP> m_statements;
801 StatementP compoundStatement(const vector<StatementP>& statements)
803 return StatementP(new CompoundStatement(statements));
806 //! Common base class for all expressions regardless of their type.
810 virtual ~ExprBase (void) {}
811 void printExpr (ostream& os) const { this->doPrintExpr(os); }
813 //! Output the functions that this expression refers to
814 void getUsedFuncs (FuncSet& dst) const
816 this->doGetUsedFuncs(dst);
820 virtual void doPrintExpr (ostream&) const {}
821 virtual void doGetUsedFuncs (FuncSet&) const {}
824 //! Type-specific operations for an expression representing type T.
825 template <typename T>
826 class Expr : public ExprBase
830 typedef typename Traits<T>::IVal IVal;
832 IVal evaluate (const EvalContext& ctx) const;
835 virtual IVal doEvaluate (const EvalContext& ctx) const = 0;
838 //! Evaluate an expression with the given context, optionally tracing the calls to stderr.
839 template <typename T>
840 typename Traits<T>::IVal Expr<T>::evaluate (const EvalContext& ctx) const
842 #ifdef GLS_ENABLE_TRACE
843 static const FloatFormat highpFmt (-126, 127, 23, true,
847 EvalContext newCtx (ctx.format, ctx.floatPrecision,
848 ctx.env, ctx.callDepth + 1);
849 const IVal ret = this->doEvaluate(newCtx);
851 if (isTypeValid<T>())
853 std::cerr << string(ctx.callDepth, ' ');
854 this->printExpr(std::cerr);
855 std::cerr << " -> " << intervalToString<T>(highpFmt, ret) << std::endl;
859 return this->doEvaluate(ctx);
863 template <typename T>
864 class ExprPBase : public SharedPtr<const Expr<T> >
869 ostream& operator<< (ostream& os, const ExprBase& expr)
875 /*--------------------------------------------------------------------*//*!
876 * \brief Shared pointer to an expression of a container type.
878 * Container types (i.e. vectors and matrices) support the subscription
879 * operator. This class provides a bit of syntactic sugar to allow us to use
880 * the C++ subscription operator to create a subscription expression.
881 *//*--------------------------------------------------------------------*/
882 template <typename T>
883 class ContainerExprPBase : public ExprPBase<T>
886 ExprP<typename T::Element> operator[] (int i) const;
889 template <typename T>
890 class ExprP : public ExprPBase<T> {};
892 // We treat Voids as containers since the dummy parameters in generalized
893 // vector functions are represented as Voids.
895 class ExprP<Void> : public ContainerExprPBase<Void> {};
897 template <typename T, int Size>
898 class ExprP<Vector<T, Size> > : public ContainerExprPBase<Vector<T, Size> > {};
900 template <typename T, int Rows, int Cols>
901 class ExprP<Matrix<T, Rows, Cols> > : public ContainerExprPBase<Matrix<T, Rows, Cols> > {};
903 template <typename T> ExprP<T> exprP (void)
908 template <typename T>
909 ExprP<T> exprP (const SharedPtr<const Expr<T> >& ptr)
912 static_cast<SharedPtr<const Expr<T> >&>(ret) = ptr;
916 template <typename T>
917 ExprP<T> exprP (const Expr<T>* ptr)
919 return exprP(SharedPtr<const Expr<T> >(ptr));
922 /*--------------------------------------------------------------------*//*!
923 * \brief A shared pointer to a variable expression.
925 * This is just a narrowing of ExprP for the operations that require a variable
926 * instead of an arbitrary expression.
928 *//*--------------------------------------------------------------------*/
929 template <typename T>
930 class VariableP : public SharedPtr<const Variable<T> >
933 typedef SharedPtr<const Variable<T> > Super;
934 explicit VariableP (const Variable<T>* ptr) : Super(ptr) {}
936 VariableP (const Super& ptr) : Super(ptr) {}
938 operator ExprP<T> (void) const { return exprP(SharedPtr<const Expr<T> >(*this)); }
941 /*--------------------------------------------------------------------*//*!
942 * \name Syntactic sugar operators for expressions.
946 * These operators allow the use of C++ syntax to construct GLSL expressions
947 * containing operators: e.g. "a+b" creates an addition expression with
948 * operands a and b, and so on.
950 *//*--------------------------------------------------------------------*/
951 ExprP<float> operator-(const ExprP<float>& arg0);
952 ExprP<float> operator+(const ExprP<float>& arg0,
953 const ExprP<float>& arg1);
954 ExprP<float> operator-(const ExprP<float>& arg0,
955 const ExprP<float>& arg1);
956 ExprP<float> operator*(const ExprP<float>& arg0,
957 const ExprP<float>& arg1);
958 ExprP<float> operator/(const ExprP<float>& arg0,
959 const ExprP<float>& arg1);
961 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0);
963 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
964 const ExprP<float>& arg1);
966 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
967 const ExprP<Vector<float, Size> >& arg1);
969 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
970 const ExprP<Vector<float, Size> >& arg1);
971 template<int Left, int Mid, int Right>
972 ExprP<Matrix<float, Left, Right> > operator* (const ExprP<Matrix<float, Left, Mid> >& left,
973 const ExprP<Matrix<float, Mid, Right> >& right);
974 template<int Rows, int Cols>
975 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
976 const ExprP<Matrix<float, Rows, Cols> >& right);
977 template<int Rows, int Cols>
978 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
979 const ExprP<Vector<float, Rows> >& right);
980 template<int Rows, int Cols>
981 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
982 const ExprP<float>& right);
983 template<int Rows, int Cols>
984 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
985 const ExprP<Matrix<float, Rows, Cols> >& right);
986 template<int Rows, int Cols>
987 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat);
991 /*--------------------------------------------------------------------*//*!
992 * \brief Variable expression.
994 * A variable is evaluated by looking up its range of possible values from an
996 *//*--------------------------------------------------------------------*/
997 template <typename T>
998 class Variable : public Expr<T>
1001 typedef typename Expr<T>::IVal IVal;
1003 Variable (const string& name) : m_name (name) {}
1004 string getName (void) const { return m_name; }
1007 void doPrintExpr (ostream& os) const { os << m_name; }
1008 IVal doEvaluate (const EvalContext& ctx) const
1010 return ctx.env.lookup<T>(*this);
1017 template <typename T>
1018 VariableP<T> variable (const string& name)
1020 return VariableP<T>(new Variable<T>(name));
1023 template <typename T>
1024 VariableP<T> bindExpression (const string& name, ExpandContext& ctx, const ExprP<T>& expr)
1026 VariableP<T> var = ctx.genSym<T>(name);
1027 ctx.addStatement(variableDeclaration(var, expr));
1031 /*--------------------------------------------------------------------*//*!
1032 * \brief Constant expression.
1034 * A constant is evaluated by rounding it to a set of possible values allowed
1035 * by the current floating point precision.
1036 *//*--------------------------------------------------------------------*/
1037 template <typename T>
1038 class Constant : public Expr<T>
1041 typedef typename Expr<T>::IVal IVal;
1043 Constant (const T& value) : m_value(value) {}
1046 void doPrintExpr (ostream& os) const { os << m_value; }
1047 IVal doEvaluate (const EvalContext&) const { return makeIVal(m_value); }
1053 template <typename T>
1054 ExprP<T> constant (const T& value)
1056 return exprP(new Constant<T>(value));
1059 //! Return a reference to a singleton void constant.
1060 const ExprP<Void>& voidP (void)
1062 static const ExprP<Void> singleton = constant(Void());
1067 /*--------------------------------------------------------------------*//*!
1068 * \brief Four-element tuple.
1070 * This is used for various things where we need one thing for each possible
1071 * function parameter. Currently the maximum supported number of parameters is
1073 *//*--------------------------------------------------------------------*/
1074 template <typename T0 = Void, typename T1 = Void, typename T2 = Void, typename T3 = Void>
1077 explicit Tuple4 (const T0& e0 = T0(),
1078 const T1& e1 = T1(),
1079 const T2& e2 = T2(),
1080 const T3& e3 = T3())
1094 /*--------------------------------------------------------------------*//*!
1095 * \brief Function signature.
1097 * This is a purely compile-time structure used to bundle all types in a
1098 * function signature together. This makes passing the signature around in
1099 * templates easier, since we only need to take and pass a single Sig instead
1100 * of a bunch of parameter types and a return type.
1102 *//*--------------------------------------------------------------------*/
1103 template <typename R,
1104 typename P0 = Void, typename P1 = Void,
1105 typename P2 = Void, typename P3 = Void>
1113 typedef typename Traits<Ret>::IVal IRet;
1114 typedef typename Traits<Arg0>::IVal IArg0;
1115 typedef typename Traits<Arg1>::IVal IArg1;
1116 typedef typename Traits<Arg2>::IVal IArg2;
1117 typedef typename Traits<Arg3>::IVal IArg3;
1119 typedef Tuple4< const Arg0&, const Arg1&, const Arg2&, const Arg3&> Args;
1120 typedef Tuple4< const IArg0&, const IArg1&, const IArg2&, const IArg3&> IArgs;
1121 typedef Tuple4< ExprP<Arg0>, ExprP<Arg1>, ExprP<Arg2>, ExprP<Arg3> > ArgExprs;
1124 typedef vector<const ExprBase*> BaseArgExprs;
1126 /*--------------------------------------------------------------------*//*!
1127 * \brief Type-independent operations for function objects.
1129 *//*--------------------------------------------------------------------*/
1133 virtual ~FuncBase (void) {}
1134 virtual string getName (void) const = 0;
1135 //! Name of extension that this function requires, or empty.
1136 virtual string getRequiredExtension (void) const { return ""; }
1137 virtual void print (ostream&,
1138 const BaseArgExprs&) const = 0;
1139 //! Index of output parameter, or -1 if none of the parameters is output.
1140 virtual int getOutParamIndex (void) const { return -1; }
1142 void printDefinition (ostream& os) const
1144 doPrintDefinition(os);
1147 void getUsedFuncs (FuncSet& dst) const
1149 this->doGetUsedFuncs(dst);
1153 virtual void doPrintDefinition (ostream& os) const = 0;
1154 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
1157 typedef Tuple4<string, string, string, string> ParamNames;
1159 /*--------------------------------------------------------------------*//*!
1160 * \brief Function objects.
1162 * Each Func object represents a GLSL function. It can be applied to interval
1163 * arguments, and it returns the an interval that is a conservative
1164 * approximation of the image of the GLSL function over the argument
1165 * intervals. That is, it is given a set of possible arguments and it returns
1166 * the set of possible values.
1168 *//*--------------------------------------------------------------------*/
1169 template <typename Sig_>
1170 class Func : public FuncBase
1174 typedef typename Sig::Ret Ret;
1175 typedef typename Sig::Arg0 Arg0;
1176 typedef typename Sig::Arg1 Arg1;
1177 typedef typename Sig::Arg2 Arg2;
1178 typedef typename Sig::Arg3 Arg3;
1179 typedef typename Sig::IRet IRet;
1180 typedef typename Sig::IArg0 IArg0;
1181 typedef typename Sig::IArg1 IArg1;
1182 typedef typename Sig::IArg2 IArg2;
1183 typedef typename Sig::IArg3 IArg3;
1184 typedef typename Sig::Args Args;
1185 typedef typename Sig::IArgs IArgs;
1186 typedef typename Sig::ArgExprs ArgExprs;
1188 void print (ostream& os,
1189 const BaseArgExprs& args) const
1191 this->doPrint(os, args);
1194 IRet apply (const EvalContext& ctx,
1195 const IArg0& arg0 = IArg0(),
1196 const IArg1& arg1 = IArg1(),
1197 const IArg2& arg2 = IArg2(),
1198 const IArg3& arg3 = IArg3()) const
1200 return this->applyArgs(ctx, IArgs(arg0, arg1, arg2, arg3));
1202 IRet applyArgs (const EvalContext& ctx,
1203 const IArgs& args) const
1205 return this->doApply(ctx, args);
1207 ExprP<Ret> operator() (const ExprP<Arg0>& arg0 = voidP(),
1208 const ExprP<Arg1>& arg1 = voidP(),
1209 const ExprP<Arg2>& arg2 = voidP(),
1210 const ExprP<Arg3>& arg3 = voidP()) const;
1212 const ParamNames& getParamNames (void) const
1214 return this->doGetParamNames();
1218 virtual IRet doApply (const EvalContext&,
1219 const IArgs&) const = 0;
1220 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1222 os << getName() << "(";
1224 if (isTypeValid<Arg0>())
1227 if (isTypeValid<Arg1>())
1228 os << ", " << *args[1];
1230 if (isTypeValid<Arg2>())
1231 os << ", " << *args[2];
1233 if (isTypeValid<Arg3>())
1234 os << ", " << *args[3];
1239 virtual const ParamNames& doGetParamNames (void) const
1241 static ParamNames names ("a", "b", "c", "d");
1246 template <typename Sig>
1247 class Apply : public Expr<typename Sig::Ret>
1250 typedef typename Sig::Ret Ret;
1251 typedef typename Sig::Arg0 Arg0;
1252 typedef typename Sig::Arg1 Arg1;
1253 typedef typename Sig::Arg2 Arg2;
1254 typedef typename Sig::Arg3 Arg3;
1255 typedef typename Expr<Ret>::Val Val;
1256 typedef typename Expr<Ret>::IVal IVal;
1257 typedef Func<Sig> ApplyFunc;
1258 typedef typename ApplyFunc::ArgExprs ArgExprs;
1260 Apply (const ApplyFunc& func,
1261 const ExprP<Arg0>& arg0 = voidP(),
1262 const ExprP<Arg1>& arg1 = voidP(),
1263 const ExprP<Arg2>& arg2 = voidP(),
1264 const ExprP<Arg3>& arg3 = voidP())
1266 m_args (arg0, arg1, arg2, arg3) {}
1268 Apply (const ApplyFunc& func,
1269 const ArgExprs& args)
1273 void doPrintExpr (ostream& os) const
1276 args.push_back(m_args.a.get());
1277 args.push_back(m_args.b.get());
1278 args.push_back(m_args.c.get());
1279 args.push_back(m_args.d.get());
1280 m_func.print(os, args);
1283 IVal doEvaluate (const EvalContext& ctx) const
1285 return m_func.apply(ctx,
1286 m_args.a->evaluate(ctx), m_args.b->evaluate(ctx),
1287 m_args.c->evaluate(ctx), m_args.d->evaluate(ctx));
1290 void doGetUsedFuncs (FuncSet& dst) const
1292 m_func.getUsedFuncs(dst);
1293 m_args.a->getUsedFuncs(dst);
1294 m_args.b->getUsedFuncs(dst);
1295 m_args.c->getUsedFuncs(dst);
1296 m_args.d->getUsedFuncs(dst);
1299 const ApplyFunc& m_func;
1303 template<typename T>
1304 class Alternatives : public Func<Signature<T, T, T> >
1307 typedef typename Alternatives::Sig Sig;
1310 typedef typename Alternatives::IRet IRet;
1311 typedef typename Alternatives::IArgs IArgs;
1313 virtual string getName (void) const { return "alternatives"; }
1314 virtual void doPrintDefinition (std::ostream&) const {}
1315 void doGetUsedFuncs (FuncSet&) const {}
1317 virtual IRet doApply (const EvalContext&, const IArgs& args) const
1319 return unionIVal<T>(args.a, args.b);
1322 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1324 os << "{" << *args[0] << " | " << *args[1] << "}";
1328 template <typename Sig>
1329 ExprP<typename Sig::Ret> createApply (const Func<Sig>& func,
1330 const typename Func<Sig>::ArgExprs& args)
1332 return exprP(new Apply<Sig>(func, args));
1335 template <typename Sig>
1336 ExprP<typename Sig::Ret> createApply (
1337 const Func<Sig>& func,
1338 const ExprP<typename Sig::Arg0>& arg0 = voidP(),
1339 const ExprP<typename Sig::Arg1>& arg1 = voidP(),
1340 const ExprP<typename Sig::Arg2>& arg2 = voidP(),
1341 const ExprP<typename Sig::Arg3>& arg3 = voidP())
1343 return exprP(new Apply<Sig>(func, arg0, arg1, arg2, arg3));
1346 template <typename Sig>
1347 ExprP<typename Sig::Ret> Func<Sig>::operator() (const ExprP<typename Sig::Arg0>& arg0,
1348 const ExprP<typename Sig::Arg1>& arg1,
1349 const ExprP<typename Sig::Arg2>& arg2,
1350 const ExprP<typename Sig::Arg3>& arg3) const
1352 return createApply(*this, arg0, arg1, arg2, arg3);
1355 template <typename F>
1356 ExprP<typename F::Ret> app (const ExprP<typename F::Arg0>& arg0 = voidP(),
1357 const ExprP<typename F::Arg1>& arg1 = voidP(),
1358 const ExprP<typename F::Arg2>& arg2 = voidP(),
1359 const ExprP<typename F::Arg3>& arg3 = voidP())
1361 return createApply(instance<F>(), arg0, arg1, arg2, arg3);
1364 template <typename F>
1365 typename F::IRet call (const EvalContext& ctx,
1366 const typename F::IArg0& arg0 = Void(),
1367 const typename F::IArg1& arg1 = Void(),
1368 const typename F::IArg2& arg2 = Void(),
1369 const typename F::IArg3& arg3 = Void())
1371 return instance<F>().apply(ctx, arg0, arg1, arg2, arg3);
1374 template <typename T>
1375 ExprP<T> alternatives (const ExprP<T>& arg0,
1376 const ExprP<T>& arg1)
1378 return createApply<typename Alternatives<T>::Sig>(instance<Alternatives<T> >(), arg0, arg1);
1381 template <typename Sig>
1382 class ApplyVar : public Apply<Sig>
1385 typedef typename Sig::Ret Ret;
1386 typedef typename Sig::Arg0 Arg0;
1387 typedef typename Sig::Arg1 Arg1;
1388 typedef typename Sig::Arg2 Arg2;
1389 typedef typename Sig::Arg3 Arg3;
1390 typedef typename Expr<Ret>::Val Val;
1391 typedef typename Expr<Ret>::IVal IVal;
1392 typedef Func<Sig> ApplyFunc;
1393 typedef typename ApplyFunc::ArgExprs ArgExprs;
1395 ApplyVar (const ApplyFunc& func,
1396 const VariableP<Arg0>& arg0,
1397 const VariableP<Arg1>& arg1,
1398 const VariableP<Arg2>& arg2,
1399 const VariableP<Arg3>& arg3)
1400 : Apply<Sig> (func, arg0, arg1, arg2, arg3) {}
1402 IVal doEvaluate (const EvalContext& ctx) const
1404 const Variable<Arg0>& var0 = static_cast<const Variable<Arg0>&>(*this->m_args.a);
1405 const Variable<Arg1>& var1 = static_cast<const Variable<Arg1>&>(*this->m_args.b);
1406 const Variable<Arg2>& var2 = static_cast<const Variable<Arg2>&>(*this->m_args.c);
1407 const Variable<Arg3>& var3 = static_cast<const Variable<Arg3>&>(*this->m_args.d);
1408 return this->m_func.apply(ctx,
1409 ctx.env.lookup(var0), ctx.env.lookup(var1),
1410 ctx.env.lookup(var2), ctx.env.lookup(var3));
1414 template <typename Sig>
1415 ExprP<typename Sig::Ret> applyVar (const Func<Sig>& func,
1416 const VariableP<typename Sig::Arg0>& arg0,
1417 const VariableP<typename Sig::Arg1>& arg1,
1418 const VariableP<typename Sig::Arg2>& arg2,
1419 const VariableP<typename Sig::Arg3>& arg3)
1421 return exprP(new ApplyVar<Sig>(func, arg0, arg1, arg2, arg3));
1424 template <typename Sig_>
1425 class DerivedFunc : public Func<Sig_>
1428 typedef typename DerivedFunc::ArgExprs ArgExprs;
1429 typedef typename DerivedFunc::IRet IRet;
1430 typedef typename DerivedFunc::IArgs IArgs;
1431 typedef typename DerivedFunc::Ret Ret;
1432 typedef typename DerivedFunc::Arg0 Arg0;
1433 typedef typename DerivedFunc::Arg1 Arg1;
1434 typedef typename DerivedFunc::Arg2 Arg2;
1435 typedef typename DerivedFunc::Arg3 Arg3;
1436 typedef typename DerivedFunc::IArg0 IArg0;
1437 typedef typename DerivedFunc::IArg1 IArg1;
1438 typedef typename DerivedFunc::IArg2 IArg2;
1439 typedef typename DerivedFunc::IArg3 IArg3;
1442 void doPrintDefinition (ostream& os) const
1444 const ParamNames& paramNames = this->getParamNames();
1448 os << dataTypeNameOf<Ret>() << " " << this->getName()
1450 if (isTypeValid<Arg0>())
1451 os << dataTypeNameOf<Arg0>() << " " << paramNames.a;
1452 if (isTypeValid<Arg1>())
1453 os << ", " << dataTypeNameOf<Arg1>() << " " << paramNames.b;
1454 if (isTypeValid<Arg2>())
1455 os << ", " << dataTypeNameOf<Arg2>() << " " << paramNames.c;
1456 if (isTypeValid<Arg3>())
1457 os << ", " << dataTypeNameOf<Arg3>() << " " << paramNames.d;
1460 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1462 os << "return " << *m_ret << ";\n";
1466 IRet doApply (const EvalContext& ctx,
1467 const IArgs& args) const
1470 IArgs& mutArgs = const_cast<IArgs&>(args);
1475 funEnv.bind(*m_var0, args.a);
1476 funEnv.bind(*m_var1, args.b);
1477 funEnv.bind(*m_var2, args.c);
1478 funEnv.bind(*m_var3, args.d);
1481 EvalContext funCtx(ctx.format, ctx.floatPrecision, funEnv, ctx.callDepth);
1483 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1484 m_body[ndx]->execute(funCtx);
1486 ret = m_ret->evaluate(funCtx);
1489 // \todo [lauri] Store references instead of values in environment
1490 const_cast<IArg0&>(mutArgs.a) = funEnv.lookup(*m_var0);
1491 const_cast<IArg1&>(mutArgs.b) = funEnv.lookup(*m_var1);
1492 const_cast<IArg2&>(mutArgs.c) = funEnv.lookup(*m_var2);
1493 const_cast<IArg3&>(mutArgs.d) = funEnv.lookup(*m_var3);
1498 void doGetUsedFuncs (FuncSet& dst) const
1501 if (dst.insert(this).second)
1503 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1504 m_body[ndx]->getUsedFuncs(dst);
1505 m_ret->getUsedFuncs(dst);
1509 virtual ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args_) const = 0;
1511 // These are transparently initialized when first needed. They cannot be
1512 // initialized in the constructor because they depend on the doExpand
1513 // method of the subclass.
1515 mutable VariableP<Arg0> m_var0;
1516 mutable VariableP<Arg1> m_var1;
1517 mutable VariableP<Arg2> m_var2;
1518 mutable VariableP<Arg3> m_var3;
1519 mutable vector<StatementP> m_body;
1520 mutable ExprP<Ret> m_ret;
1524 void initialize (void) const
1528 const ParamNames& paramNames = this->getParamNames();
1530 ExpandContext ctx (symCounter);
1533 args.a = m_var0 = variable<Arg0>(paramNames.a);
1534 args.b = m_var1 = variable<Arg1>(paramNames.b);
1535 args.c = m_var2 = variable<Arg2>(paramNames.c);
1536 args.d = m_var3 = variable<Arg3>(paramNames.d);
1538 m_ret = this->doExpand(ctx, args);
1539 m_body = ctx.getStatements();
1544 template <typename Sig>
1545 class PrimitiveFunc : public Func<Sig>
1548 typedef typename PrimitiveFunc::Ret Ret;
1549 typedef typename PrimitiveFunc::ArgExprs ArgExprs;
1552 void doPrintDefinition (ostream&) const {}
1553 void doGetUsedFuncs (FuncSet&) const {}
1556 template <typename T>
1557 class Cond : public PrimitiveFunc<Signature<T, bool, T, T> >
1560 typedef typename Cond::IArgs IArgs;
1561 typedef typename Cond::IRet IRet;
1563 string getName (void) const
1570 void doPrint (ostream& os, const BaseArgExprs& args) const
1572 os << "(" << *args[0] << " ? " << *args[1] << " : " << *args[2] << ")";
1575 IRet doApply (const EvalContext&, const IArgs& iargs)const
1579 if (iargs.a.contains(true))
1580 ret = unionIVal<T>(ret, iargs.b);
1582 if (iargs.a.contains(false))
1583 ret = unionIVal<T>(ret, iargs.c);
1589 template <typename T>
1590 class CompareOperator : public PrimitiveFunc<Signature<bool, T, T> >
1593 typedef typename CompareOperator::IArgs IArgs;
1594 typedef typename CompareOperator::IArg0 IArg0;
1595 typedef typename CompareOperator::IArg1 IArg1;
1596 typedef typename CompareOperator::IRet IRet;
1599 void doPrint (ostream& os, const BaseArgExprs& args) const
1601 os << "(" << *args[0] << getSymbol() << *args[1] << ")";
1604 Interval doApply (const EvalContext&, const IArgs& iargs) const
1606 const IArg0& arg0 = iargs.a;
1607 const IArg1& arg1 = iargs.b;
1610 if (canSucceed(arg0, arg1))
1612 if (canFail(arg0, arg1))
1618 virtual string getSymbol (void) const = 0;
1619 virtual bool canSucceed (const IArg0&, const IArg1&) const = 0;
1620 virtual bool canFail (const IArg0&, const IArg1&) const = 0;
1623 template <typename T>
1624 class LessThan : public CompareOperator<T>
1627 string getName (void) const { return "lessThan"; }
1630 string getSymbol (void) const { return "<"; }
1632 bool canSucceed (const Interval& a, const Interval& b) const
1634 return (a.lo() < b.hi());
1637 bool canFail (const Interval& a, const Interval& b) const
1639 return !(a.hi() < b.lo());
1643 template <typename T>
1644 ExprP<bool> operator< (const ExprP<T>& a, const ExprP<T>& b)
1646 return app<LessThan<T> >(a, b);
1649 template <typename T>
1650 ExprP<T> cond (const ExprP<bool>& test,
1651 const ExprP<T>& consequent,
1652 const ExprP<T>& alternative)
1654 return app<Cond<T> >(test, consequent, alternative);
1657 /*--------------------------------------------------------------------*//*!
1661 *//*--------------------------------------------------------------------*/
1663 class FloatFunc1 : public PrimitiveFunc<Signature<float, float> >
1666 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1668 return this->applyMonotone(ctx, iargs.a);
1671 Interval applyMonotone (const EvalContext& ctx, const Interval& iarg0) const
1675 TCU_INTERVAL_APPLY_MONOTONE1(ret, arg0, iarg0, val,
1676 TCU_SET_INTERVAL(val, point,
1677 point = this->applyPoint(ctx, arg0)));
1679 ret |= innerExtrema(ctx, iarg0);
1680 ret &= (this->getCodomain() | TCU_NAN);
1682 return ctx.format.convert(ret);
1685 virtual Interval innerExtrema (const EvalContext&, const Interval&) const
1687 return Interval(); // empty interval, i.e. no extrema
1690 virtual Interval applyPoint (const EvalContext& ctx, double arg0) const
1692 const double exact = this->applyExact(arg0);
1693 const double prec = this->precision(ctx, exact, arg0);
1695 return exact + Interval(-prec, prec);
1698 virtual double applyExact (double) const
1700 TCU_THROW(InternalError, "Cannot apply");
1703 virtual Interval getCodomain (void) const
1705 return Interval::unbounded(true);
1708 virtual double precision (const EvalContext& ctx, double, double) const = 0;
1711 class CFloatFunc1 : public FloatFunc1
1714 CFloatFunc1 (const string& name, tcu::DoubleFunc1& func)
1715 : m_name(name), m_func(func) {}
1717 string getName (void) const { return m_name; }
1720 double applyExact (double x) const { return m_func(x); }
1722 const string m_name;
1723 tcu::DoubleFunc1& m_func;
1726 class FloatFunc2 : public PrimitiveFunc<Signature<float, float, float> >
1729 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1731 return this->applyMonotone(ctx, iargs.a, iargs.b);
1734 Interval applyMonotone (const EvalContext& ctx,
1736 const Interval& yi) const
1740 TCU_INTERVAL_APPLY_MONOTONE2(reti, x, xi, y, yi, ret,
1741 TCU_SET_INTERVAL(ret, point,
1742 point = this->applyPoint(ctx, x, y)));
1743 reti |= innerExtrema(ctx, xi, yi);
1744 reti &= (this->getCodomain() | TCU_NAN);
1746 return ctx.format.convert(reti);
1749 virtual Interval innerExtrema (const EvalContext&,
1751 const Interval&) const
1753 return Interval(); // empty interval, i.e. no extrema
1756 virtual Interval applyPoint (const EvalContext& ctx,
1760 const double exact = this->applyExact(x, y);
1761 const double prec = this->precision(ctx, exact, x, y);
1763 return exact + Interval(-prec, prec);
1766 virtual double applyExact (double, double) const
1768 TCU_THROW(InternalError, "Cannot apply");
1771 virtual Interval getCodomain (void) const
1773 return Interval::unbounded(true);
1776 virtual double precision (const EvalContext& ctx,
1779 double y) const = 0;
1782 class CFloatFunc2 : public FloatFunc2
1785 CFloatFunc2 (const string& name,
1786 tcu::DoubleFunc2& func)
1792 string getName (void) const { return m_name; }
1795 double applyExact (double x, double y) const { return m_func(x, y); }
1797 const string m_name;
1798 tcu::DoubleFunc2& m_func;
1801 class InfixOperator : public FloatFunc2
1804 virtual string getSymbol (void) const = 0;
1806 void doPrint (ostream& os, const BaseArgExprs& args) const
1808 os << "(" << *args[0] << " " << getSymbol() << " " << *args[1] << ")";
1811 Interval applyPoint (const EvalContext& ctx,
1815 const double exact = this->applyExact(x, y);
1817 // Allow either representable number on both sides of the exact value,
1818 // but require exactly representable values to be preserved.
1819 return ctx.format.roundOut(exact, !deIsInf(x) && !deIsInf(y));
1822 double precision (const EvalContext&, double, double, double) const
1828 class FloatFunc3 : public PrimitiveFunc<Signature<float, float, float, float> >
1831 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1833 return this->applyMonotone(ctx, iargs.a, iargs.b, iargs.c);
1836 Interval applyMonotone (const EvalContext& ctx,
1839 const Interval& zi) const
1842 TCU_INTERVAL_APPLY_MONOTONE3(reti, x, xi, y, yi, z, zi, ret,
1843 TCU_SET_INTERVAL(ret, point,
1844 point = this->applyPoint(ctx, x, y, z)));
1845 return ctx.format.convert(reti);
1848 virtual Interval applyPoint (const EvalContext& ctx,
1853 const double exact = this->applyExact(x, y, z);
1854 const double prec = this->precision(ctx, exact, x, y, z);
1855 return exact + Interval(-prec, prec);
1858 virtual double applyExact (double, double, double) const
1860 TCU_THROW(InternalError, "Cannot apply");
1863 virtual double precision (const EvalContext& ctx,
1867 double z) const = 0;
1870 // We define syntactic sugar functions for expression constructors. Since
1871 // these have the same names as ordinary mathematical operations (sin, log
1872 // etc.), it's better to give them a dedicated namespace.
1876 using namespace tcu;
1878 class Add : public InfixOperator
1881 string getName (void) const { return "add"; }
1882 string getSymbol (void) const { return "+"; }
1884 Interval doApply (const EvalContext& ctx,
1885 const IArgs& iargs) const
1887 // Fast-path for common case
1888 if (iargs.a.isOrdinary() && iargs.b.isOrdinary())
1891 TCU_SET_INTERVAL_BOUNDS(ret, sum,
1892 sum = iargs.a.lo() + iargs.b.lo(),
1893 sum = iargs.a.hi() + iargs.b.hi());
1894 return ctx.format.convert(ctx.format.roundOut(ret, true));
1896 return this->applyMonotone(ctx, iargs.a, iargs.b);
1900 double applyExact (double x, double y) const { return x + y; }
1903 class Mul : public InfixOperator
1906 string getName (void) const { return "mul"; }
1907 string getSymbol (void) const { return "*"; }
1909 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1911 Interval a = iargs.a;
1912 Interval b = iargs.b;
1914 // Fast-path for common case
1915 if (a.isOrdinary() && b.isOrdinary())
1923 if (a.lo() >= 0 && b.lo() >= 0)
1925 TCU_SET_INTERVAL_BOUNDS(ret, prod,
1926 prod = iargs.a.lo() * iargs.b.lo(),
1927 prod = iargs.a.hi() * iargs.b.hi());
1928 return ctx.format.convert(ctx.format.roundOut(ret, true));
1930 if (a.lo() >= 0 && b.hi() <= 0)
1932 TCU_SET_INTERVAL_BOUNDS(ret, prod,
1933 prod = iargs.a.hi() * iargs.b.lo(),
1934 prod = iargs.a.lo() * iargs.b.hi());
1935 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; }
1944 Interval innerExtrema(const EvalContext&, const Interval& xi, const Interval& yi) const
1946 if (((xi.contains(-TCU_INFINITY) || xi.contains(TCU_INFINITY)) && yi.contains(0.0)) ||
1947 ((yi.contains(-TCU_INFINITY) || yi.contains(TCU_INFINITY)) && xi.contains(0.0)))
1948 return Interval(TCU_NAN);
1954 class Sub : public InfixOperator
1957 string getName (void) const { return "sub"; }
1958 string getSymbol (void) const { return "-"; }
1960 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1962 // Fast-path for common case
1963 if (iargs.a.isOrdinary() && iargs.b.isOrdinary())
1967 TCU_SET_INTERVAL_BOUNDS(ret, diff,
1968 diff = iargs.a.lo() - iargs.b.hi(),
1969 diff = iargs.a.hi() - iargs.b.lo());
1970 return ctx.format.convert(ctx.format.roundOut(ret, true));
1975 return this->applyMonotone(ctx, iargs.a, iargs.b);
1980 double applyExact (double x, double y) const { return x - y; }
1983 class Negate : public FloatFunc1
1986 string getName (void) const { return "_negate"; }
1987 void doPrint (ostream& os, const BaseArgExprs& args) const { os << "-" << *args[0]; }
1990 double precision (const EvalContext&, double, double) const { return 0.0; }
1991 double applyExact (double x) const { return -x; }
1994 class Div : public InfixOperator
1997 string getName (void) const { return "div"; }
2000 string getSymbol (void) const { return "/"; }
2002 Interval innerExtrema (const EvalContext&,
2003 const Interval& nom,
2004 const Interval& den) const
2008 if (den.contains(0.0))
2010 if (nom.contains(0.0))
2013 if (nom.lo() < 0.0 || nom.hi() > 0.0)
2014 ret |= Interval::unbounded();
2020 double applyExact (double x, double y) const { return x / y; }
2022 Interval applyPoint (const EvalContext& ctx, double x, double y) const
2024 Interval ret = FloatFunc2::applyPoint(ctx, x, y);
2026 if (!deIsInf(x) && !deIsInf(y) && y != 0.0)
2028 const Interval dst = ctx.format.convert(ret);
2029 if (dst.contains(-TCU_INFINITY)) ret |= -ctx.format.getMaxValue();
2030 if (dst.contains(+TCU_INFINITY)) ret |= +ctx.format.getMaxValue();
2036 double precision (const EvalContext& ctx, double ret, double, double den) const
2038 const FloatFormat& fmt = ctx.format;
2040 // \todo [2014-03-05 lauri] Check that the limits in GLSL 3.10 are actually correct.
2041 // For now, we assume that division's precision is 2.5 ULP when the value is within
2042 // [2^MINEXP, 2^MAXEXP-1]
2045 return 0.0; // Result must be exactly inf
2046 else if (de::inBounds(deAbs(den),
2047 deLdExp(1.0, fmt.getMinExp()),
2048 deLdExp(1.0, fmt.getMaxExp() - 1)))
2049 return fmt.ulp(ret, 2.5);
2051 return TCU_INFINITY; // Can be any number, but must be a number.
2055 class InverseSqrt : public FloatFunc1
2058 string getName (void) const { return "inversesqrt"; }
2061 double applyExact (double x) const { return 1.0 / deSqrt(x); }
2063 double precision (const EvalContext& ctx, double ret, double x) const
2065 return x <= 0 ? TCU_NAN : ctx.format.ulp(ret, 2.0);
2068 Interval getCodomain (void) const
2070 return Interval(0.0, TCU_INFINITY);
2074 class ExpFunc : public CFloatFunc1
2077 ExpFunc (const string& name, DoubleFunc1& func)
2078 : CFloatFunc1(name, func) {}
2080 double precision (const EvalContext& ctx, double ret, double x) const
2082 switch (ctx.floatPrecision)
2084 case glu::PRECISION_HIGHP:
2085 return ctx.format.ulp(ret, 3.0 + 2.0 * deAbs(x));
2086 case glu::PRECISION_MEDIUMP:
2087 return ctx.format.ulp(ret, 2.0 + 2.0 * deAbs(x));
2088 case glu::PRECISION_LOWP:
2089 return ctx.format.ulp(ret, 2.0);
2091 DE_FATAL("Impossible");
2096 Interval getCodomain (void) const
2098 return Interval(0.0, TCU_INFINITY);
2102 class Exp2 : public ExpFunc { public: Exp2 (void) : ExpFunc("exp2", deExp2) {} };
2103 class Exp : public ExpFunc { public: Exp (void) : ExpFunc("exp", deExp) {} };
2105 ExprP<float> exp2 (const ExprP<float>& x) { return app<Exp2>(x); }
2106 ExprP<float> exp (const ExprP<float>& x) { return app<Exp>(x); }
2108 class LogFunc : public CFloatFunc1
2111 LogFunc (const string& name, DoubleFunc1& func)
2112 : CFloatFunc1(name, func) {}
2115 double precision (const EvalContext& ctx, double ret, double x) const
2120 switch (ctx.floatPrecision)
2122 case glu::PRECISION_HIGHP:
2123 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -21) : ctx.format.ulp(ret, 3.0);
2124 case glu::PRECISION_MEDIUMP:
2125 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -7) : ctx.format.ulp(ret, 2.0);
2126 case glu::PRECISION_LOWP:
2127 return ctx.format.ulp(ret, 2.0);
2129 DE_FATAL("Impossible");
2136 class Log2 : public LogFunc { public: Log2 (void) : LogFunc("log2", deLog2) {} };
2137 class Log : public LogFunc { public: Log (void) : LogFunc("log", deLog) {} };
2139 ExprP<float> log2 (const ExprP<float>& x) { return app<Log2>(x); }
2140 ExprP<float> log (const ExprP<float>& x) { return app<Log>(x); }
2142 #define DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0) \
2143 ExprP<TRET> NAME (const ExprP<T0>& arg0) { return app<CLASS>(arg0); }
2145 #define DEFINE_DERIVED1(CLASS, TRET, NAME, T0, ARG0, EXPANSION) \
2146 class CLASS : public DerivedFunc<Signature<TRET, T0> > \
2149 string getName (void) const { return #NAME; } \
2152 ExprP<TRET> doExpand (ExpandContext&, \
2153 const CLASS::ArgExprs& args_) const \
2155 const ExprP<float>& ARG0 = args_.a; \
2159 DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0)
2161 #define DEFINE_DERIVED_FLOAT1(CLASS, NAME, ARG0, EXPANSION) \
2162 DEFINE_DERIVED1(CLASS, float, NAME, float, ARG0, EXPANSION)
2164 #define DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1) \
2165 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1) \
2167 return app<CLASS>(arg0, arg1); \
2170 #define DEFINE_DERIVED2(CLASS, TRET, NAME, T0, Arg0, T1, Arg1, EXPANSION) \
2171 class CLASS : public DerivedFunc<Signature<TRET, T0, T1> > \
2174 string getName (void) const { return #NAME; } \
2177 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2179 const ExprP<T0>& Arg0 = args_.a; \
2180 const ExprP<T1>& Arg1 = args_.b; \
2184 DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1)
2186 #define DEFINE_DERIVED_FLOAT2(CLASS, NAME, Arg0, Arg1, EXPANSION) \
2187 DEFINE_DERIVED2(CLASS, float, NAME, float, Arg0, float, Arg1, EXPANSION)
2189 #define DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2) \
2190 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, const ExprP<T2>& arg2) \
2192 return app<CLASS>(arg0, arg1, arg2); \
2195 #define DEFINE_DERIVED3(CLASS, TRET, NAME, T0, ARG0, T1, ARG1, T2, ARG2, EXPANSION) \
2196 class CLASS : public DerivedFunc<Signature<TRET, T0, T1, T2> > \
2199 string getName (void) const { return #NAME; } \
2202 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2204 const ExprP<T0>& ARG0 = args_.a; \
2205 const ExprP<T1>& ARG1 = args_.b; \
2206 const ExprP<T2>& ARG2 = args_.c; \
2210 DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2)
2212 #define DEFINE_DERIVED_FLOAT3(CLASS, NAME, ARG0, ARG1, ARG2, EXPANSION) \
2213 DEFINE_DERIVED3(CLASS, float, NAME, float, ARG0, float, ARG1, float, ARG2, EXPANSION)
2215 #define DEFINE_CONSTRUCTOR4(CLASS, TRET, NAME, T0, T1, T2, T3) \
2216 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, \
2217 const ExprP<T2>& arg2, const ExprP<T3>& arg3) \
2219 return app<CLASS>(arg0, arg1, arg2, arg3); \
2222 DEFINE_DERIVED_FLOAT1(Sqrt, sqrt, x, constant(1.0f) / app<InverseSqrt>(x));
2223 DEFINE_DERIVED_FLOAT2(Pow, pow, x, y, exp2(y * log2(x)));
2224 DEFINE_DERIVED_FLOAT1(Radians, radians, d, (constant(DE_PI) / constant(180.0f)) * d);
2225 DEFINE_DERIVED_FLOAT1(Degrees, degrees, r, (constant(180.0f) / constant(DE_PI)) * r);
2227 class TrigFunc : public CFloatFunc1
2230 TrigFunc (const string& name,
2232 const Interval& loEx,
2233 const Interval& hiEx)
2234 : CFloatFunc1 (name, func)
2235 , m_loExtremum (loEx)
2236 , m_hiExtremum (hiEx) {}
2239 Interval innerExtrema (const EvalContext&, const Interval& angle) const
2241 const double lo = angle.lo();
2242 const double hi = angle.hi();
2243 const int loSlope = doGetSlope(lo);
2244 const int hiSlope = doGetSlope(hi);
2246 // Detect the high and low values the function can take between the
2247 // interval endpoints.
2248 if (angle.length() >= 2.0 * DE_PI_DOUBLE)
2250 // The interval is longer than a full cycle, so it must get all possible values.
2251 return m_hiExtremum | m_loExtremum;
2253 else if (loSlope == 1 && hiSlope == -1)
2255 // The slope can change from positive to negative only at the maximum value.
2256 return m_hiExtremum;
2258 else if (loSlope == -1 && hiSlope == 1)
2260 // The slope can change from negative to positive only at the maximum value.
2261 return m_loExtremum;
2263 else if (loSlope == hiSlope &&
2264 deIntSign(applyExact(hi) - applyExact(lo)) * loSlope == -1)
2266 // The slope has changed twice between the endpoints, so both extrema are included.
2267 return m_hiExtremum | m_loExtremum;
2273 Interval getCodomain (void) const
2275 // Ensure that result is always within [-1, 1], or NaN (for +-inf)
2276 return Interval(-1.0, 1.0) | TCU_NAN;
2279 double precision (const EvalContext& ctx, double ret, double arg) const
2281 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2283 // Use precision from OpenCL fast relaxed math
2284 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2286 return deLdExp(1.0, -11);
2290 // "larger otherwise", let's pick |x| * 2^-12 , which is slightly over
2291 // 2^-11 at x == pi.
2292 return deLdExp(deAbs(arg), -12);
2295 else if (ctx.floatPrecision == glu::PRECISION_MEDIUMP)
2297 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2299 // from OpenCL half-float extension specification
2300 return ctx.format.ulp(ret, 2.0);
2304 // |x| * 2^-10, slightly larger than 2 ULP at x == pi
2305 return deLdExp(deAbs(arg), -10);
2310 DE_ASSERT(ctx.floatPrecision == glu::PRECISION_LOWP);
2312 // from OpenCL half-float extension specification
2313 return ctx.format.ulp(ret, 2.0);
2317 virtual int doGetSlope (double angle) const = 0;
2319 Interval m_loExtremum;
2320 Interval m_hiExtremum;
2323 class Sin : public TrigFunc
2326 Sin (void) : TrigFunc("sin", deSin, -1.0, 1.0) {}
2329 int doGetSlope (double angle) const { return deIntSign(deCos(angle)); }
2332 ExprP<float> sin (const ExprP<float>& x) { return app<Sin>(x); }
2334 class Cos : public TrigFunc
2337 Cos (void) : TrigFunc("cos", deCos, -1.0, 1.0) {}
2340 int doGetSlope (double angle) const { return -deIntSign(deSin(angle)); }
2343 ExprP<float> cos (const ExprP<float>& x) { return app<Cos>(x); }
2345 DEFINE_DERIVED_FLOAT1(Tan, tan, x, sin(x) * (constant(1.0f) / cos(x)));
2347 class ASin : public CFloatFunc1
2350 ASin (void) : CFloatFunc1("asin", deAsin) {}
2353 double precision (const EvalContext& ctx, double, double x) const
2355 if (!de::inBounds(x, -1.0, 1.0))
2358 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2360 // Absolute error of 2^-11
2361 return deLdExp(1.0, -11);
2365 // Absolute error of 2^-8
2366 return deLdExp(1.0, -8);
2372 class ArcTrigFunc : public CFloatFunc1
2375 ArcTrigFunc (const string& name,
2377 double precisionULPs,
2378 const Interval& domain,
2379 const Interval& codomain)
2380 : CFloatFunc1 (name, func)
2381 , m_precision (precisionULPs)
2383 , m_codomain (codomain) {}
2386 double precision (const EvalContext& ctx, double ret, double x) const
2388 if (!m_domain.contains(x))
2391 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2393 // Use OpenCL's fast relaxed math precision
2394 return ctx.format.ulp(ret, m_precision);
2398 // Use OpenCL half-float spec
2399 return ctx.format.ulp(ret, 2.0);
2403 // We could implement getCodomain with m_codomain, but choose not to,
2404 // because it seems too strict with trascendental constants like pi.
2406 const double m_precision;
2407 const Interval m_domain;
2408 const Interval m_codomain;
2411 class ACos : public ArcTrigFunc
2414 ACos (void) : ArcTrigFunc("acos", deAcos, 4096.0,
2415 Interval(-1.0, 1.0),
2416 Interval(0.0, DE_PI_DOUBLE)) {}
2419 class ATan : public ArcTrigFunc
2422 ATan (void) : ArcTrigFunc("atan", deAtanOver, 4096.0,
2423 Interval::unbounded(),
2424 Interval(-DE_PI_DOUBLE * 0.5, DE_PI_DOUBLE * 0.5)) {}
2427 class ATan2 : public CFloatFunc2
2430 ATan2 (void) : CFloatFunc2 ("atan", deAtan2) {}
2433 Interval innerExtrema (const EvalContext& ctx,
2435 const Interval& xi) const
2439 if (yi.contains(0.0))
2441 if (xi.contains(0.0))
2443 if (xi.intersects(Interval(-TCU_INFINITY, 0.0)))
2444 ret |= Interval(-DE_PI_DOUBLE, DE_PI_DOUBLE);
2447 if (ctx.format.hasInf() != YES && (!yi.isFinite() || !xi.isFinite()))
2449 // Infinities may not be supported, allow anything, including NaN
2456 double precision (const EvalContext& ctx, double ret, double, double) const
2458 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2459 return ctx.format.ulp(ret, 4096.0);
2461 return ctx.format.ulp(ret, 2.0);
2464 // Codomain could be [-pi, pi], but that would probably be too strict.
2467 DEFINE_DERIVED_FLOAT1(Sinh, sinh, x, (exp(x) - exp(-x)) / constant(2.0f));
2468 DEFINE_DERIVED_FLOAT1(Cosh, cosh, x, (exp(x) + exp(-x)) / constant(2.0f));
2469 DEFINE_DERIVED_FLOAT1(Tanh, tanh, x, sinh(x) / cosh(x));
2471 // These are not defined as derived forms in the GLSL ES spec, but
2472 // that gives us a reasonable precision.
2473 DEFINE_DERIVED_FLOAT1(ASinh, asinh, x, log(x + sqrt(x * x + constant(1.0f))));
2474 DEFINE_DERIVED_FLOAT1(ACosh, acosh, x, log(x + sqrt(alternatives((x + constant(1.0f)) * (x - constant(1.0f)),
2475 (x*x - constant(1.0f))))));
2476 DEFINE_DERIVED_FLOAT1(ATanh, atanh, x, constant(0.5f) * log((constant(1.0f) + x) /
2477 (constant(1.0f) - x)));
2479 template <typename T>
2480 class GetComponent : public PrimitiveFunc<Signature<typename T::Element, T, int> >
2483 typedef typename GetComponent::IRet IRet;
2485 string getName (void) const { return "_getComponent"; }
2487 void print (ostream& os,
2488 const BaseArgExprs& args) const
2490 os << *args[0] << "[" << *args[1] << "]";
2494 IRet doApply (const EvalContext&,
2495 const typename GetComponent::IArgs& iargs) const
2499 for (int compNdx = 0; compNdx < T::SIZE; ++compNdx)
2501 if (iargs.b.contains(compNdx))
2502 ret = unionIVal<typename T::Element>(ret, iargs.a[compNdx]);
2510 template <typename T>
2511 ExprP<typename T::Element> getComponent (const ExprP<T>& container, int ndx)
2513 DE_ASSERT(0 <= ndx && ndx < T::SIZE);
2514 return app<GetComponent<T> >(container, constant(ndx));
2517 template <typename T> string vecNamePrefix (void);
2518 template <> string vecNamePrefix<float> (void) { return ""; }
2519 template <> string vecNamePrefix<int> (void) { return "i"; }
2520 template <> string vecNamePrefix<bool> (void) { return "b"; }
2522 template <typename T, int Size>
2523 string vecName (void) { return vecNamePrefix<T>() + "vec" + de::toString(Size); }
2525 template <typename T, int Size> class GenVec;
2527 template <typename T>
2528 class GenVec<T, 1> : public DerivedFunc<Signature<T, T> >
2531 typedef typename GenVec<T, 1>::ArgExprs ArgExprs;
2533 string getName (void) const
2535 return "_" + vecName<T, 1>();
2540 ExprP<T> doExpand (ExpandContext&, const ArgExprs& args) const { return args.a; }
2543 template <typename T>
2544 class GenVec<T, 2> : public PrimitiveFunc<Signature<Vector<T, 2>, T, T> >
2547 typedef typename GenVec::IRet IRet;
2548 typedef typename GenVec::IArgs IArgs;
2550 string getName (void) const
2552 return vecName<T, 2>();
2556 IRet doApply (const EvalContext&, const IArgs& iargs) const
2558 return IRet(iargs.a, iargs.b);
2562 template <typename T>
2563 class GenVec<T, 3> : public PrimitiveFunc<Signature<Vector<T, 3>, T, T, T> >
2566 typedef typename GenVec::IRet IRet;
2567 typedef typename GenVec::IArgs IArgs;
2569 string getName (void) const
2571 return vecName<T, 3>();
2575 IRet doApply (const EvalContext&, const IArgs& iargs) const
2577 return IRet(iargs.a, iargs.b, iargs.c);
2581 template <typename T>
2582 class GenVec<T, 4> : public PrimitiveFunc<Signature<Vector<T, 4>, T, T, T, T> >
2585 typedef typename GenVec::IRet IRet;
2586 typedef typename GenVec::IArgs IArgs;
2588 string getName (void) const { return vecName<T, 4>(); }
2591 IRet doApply (const EvalContext&, const IArgs& iargs) const
2593 return IRet(iargs.a, iargs.b, iargs.c, iargs.d);
2599 template <typename T, int Rows, int Columns>
2602 template <typename T, int Rows>
2603 class GenMat<T, Rows, 2> : public PrimitiveFunc<
2604 Signature<Matrix<T, Rows, 2>, Vector<T, Rows>, Vector<T, Rows> > >
2607 typedef typename GenMat::Ret Ret;
2608 typedef typename GenMat::IRet IRet;
2609 typedef typename GenMat::IArgs IArgs;
2611 string getName (void) const
2613 return dataTypeNameOf<Ret>();
2618 IRet doApply (const EvalContext&, const IArgs& iargs) const
2627 template <typename T, int Rows>
2628 class GenMat<T, Rows, 3> : public PrimitiveFunc<
2629 Signature<Matrix<T, Rows, 3>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
2632 typedef typename GenMat::Ret Ret;
2633 typedef typename GenMat::IRet IRet;
2634 typedef typename GenMat::IArgs IArgs;
2636 string getName (void) const
2638 return dataTypeNameOf<Ret>();
2643 IRet doApply (const EvalContext&, const IArgs& iargs) const
2653 template <typename T, int Rows>
2654 class GenMat<T, Rows, 4> : public PrimitiveFunc<
2655 Signature<Matrix<T, Rows, 4>,
2656 Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
2659 typedef typename GenMat::Ret Ret;
2660 typedef typename GenMat::IRet IRet;
2661 typedef typename GenMat::IArgs IArgs;
2663 string getName (void) const
2665 return dataTypeNameOf<Ret>();
2669 IRet doApply (const EvalContext&, const IArgs& iargs) const
2680 template <typename T, int Rows>
2681 ExprP<Matrix<T, Rows, 2> > mat2 (const ExprP<Vector<T, Rows> >& arg0,
2682 const ExprP<Vector<T, Rows> >& arg1)
2684 return app<GenMat<T, Rows, 2> >(arg0, arg1);
2687 template <typename T, int Rows>
2688 ExprP<Matrix<T, Rows, 3> > mat3 (const ExprP<Vector<T, Rows> >& arg0,
2689 const ExprP<Vector<T, Rows> >& arg1,
2690 const ExprP<Vector<T, Rows> >& arg2)
2692 return app<GenMat<T, Rows, 3> >(arg0, arg1, arg2);
2695 template <typename T, int Rows>
2696 ExprP<Matrix<T, Rows, 4> > mat4 (const ExprP<Vector<T, Rows> >& arg0,
2697 const ExprP<Vector<T, Rows> >& arg1,
2698 const ExprP<Vector<T, Rows> >& arg2,
2699 const ExprP<Vector<T, Rows> >& arg3)
2701 return app<GenMat<T, Rows, 4> >(arg0, arg1, arg2, arg3);
2705 template <int Rows, int Cols>
2706 class MatNeg : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
2707 Matrix<float, Rows, Cols> > >
2710 typedef typename MatNeg::IRet IRet;
2711 typedef typename MatNeg::IArgs IArgs;
2713 string getName (void) const
2719 void doPrint (ostream& os, const BaseArgExprs& args) const
2721 os << "-(" << *args[0] << ")";
2724 IRet doApply (const EvalContext&, const IArgs& iargs) const
2728 for (int col = 0; col < Cols; ++col)
2730 for (int row = 0; row < Rows; ++row)
2731 ret[col][row] = -iargs.a[col][row];
2738 template <typename T, typename Sig>
2739 class CompWiseFunc : public PrimitiveFunc<Sig>
2742 typedef Func<Signature<T, T, T> > ScalarFunc;
2744 string getName (void) const
2746 return doGetScalarFunc().getName();
2749 void doPrint (ostream& os,
2750 const BaseArgExprs& args) const
2752 doGetScalarFunc().print(os, args);
2756 const ScalarFunc& doGetScalarFunc (void) const = 0;
2759 template <int Rows, int Cols>
2760 class CompMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
2761 Matrix<float, Rows, Cols>,
2762 Matrix<float, Rows, Cols> > >
2765 typedef typename CompMatFuncBase::IRet IRet;
2766 typedef typename CompMatFuncBase::IArgs IArgs;
2770 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
2774 for (int col = 0; col < Cols; ++col)
2776 for (int row = 0; row < Rows; ++row)
2777 ret[col][row] = this->doGetScalarFunc().apply(ctx,
2786 template <typename F, int Rows, int Cols>
2787 class CompMatFunc : public CompMatFuncBase<Rows, Cols>
2790 const typename CompMatFunc::ScalarFunc& doGetScalarFunc (void) const
2792 return instance<F>();
2796 class ScalarMatrixCompMult : public Mul
2799 string getName (void) const
2801 return "matrixCompMult";
2804 void doPrint (ostream& os, const BaseArgExprs& args) const
2806 Func<Sig>::doPrint(os, args);
2810 template <int Rows, int Cols>
2811 class MatrixCompMult : public CompMatFunc<ScalarMatrixCompMult, Rows, Cols>
2815 template <int Rows, int Cols>
2816 class ScalarMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
2817 Matrix<float, Rows, Cols>,
2821 typedef typename ScalarMatFuncBase::IRet IRet;
2822 typedef typename ScalarMatFuncBase::IArgs IArgs;
2826 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
2830 for (int col = 0; col < Cols; ++col)
2832 for (int row = 0; row < Rows; ++row)
2833 ret[col][row] = this->doGetScalarFunc().apply(ctx, iargs.a[col][row], iargs.b);
2840 template <typename F, int Rows, int Cols>
2841 class ScalarMatFunc : public ScalarMatFuncBase<Rows, Cols>
2844 const typename ScalarMatFunc::ScalarFunc& doGetScalarFunc (void) const
2846 return instance<F>();
2850 template<typename T, int Size> struct GenXType;
2852 template<typename T>
2853 struct GenXType<T, 1>
2855 static ExprP<T> genXType (const ExprP<T>& x) { return x; }
2858 template<typename T>
2859 struct GenXType<T, 2>
2861 static ExprP<Vector<T, 2> > genXType (const ExprP<T>& x)
2863 return app<GenVec<T, 2> >(x, x);
2867 template<typename T>
2868 struct GenXType<T, 3>
2870 static ExprP<Vector<T, 3> > genXType (const ExprP<T>& x)
2872 return app<GenVec<T, 3> >(x, x, x);
2876 template<typename T>
2877 struct GenXType<T, 4>
2879 static ExprP<Vector<T, 4> > genXType (const ExprP<T>& x)
2881 return app<GenVec<T, 4> >(x, x, x, x);
2885 //! Returns an expression of vector of size `Size` (or scalar if Size == 1),
2886 //! with each element initialized with the expression `x`.
2887 template<typename T, int Size>
2888 ExprP<typename ContainerOf<T, Size>::Container> genXType (const ExprP<T>& x)
2890 return GenXType<T, Size>::genXType(x);
2893 typedef GenVec<float, 2> FloatVec2;
2894 DEFINE_CONSTRUCTOR2(FloatVec2, Vec2, vec2, float, float)
2896 typedef GenVec<float, 3> FloatVec3;
2897 DEFINE_CONSTRUCTOR3(FloatVec3, Vec3, vec3, float, float, float)
2899 typedef GenVec<float, 4> FloatVec4;
2900 DEFINE_CONSTRUCTOR4(FloatVec4, Vec4, vec4, float, float, float, float)
2903 class Dot : public DerivedFunc<Signature<float, Vector<float, Size>, Vector<float, Size> > >
2906 typedef typename Dot::ArgExprs ArgExprs;
2908 string getName (void) const
2914 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2916 ExprP<float> val = args.a[0] * args.b[0];
2918 for (int ndx = 1; ndx < Size; ++ndx)
2919 val = val + args.a[ndx] * args.b[ndx];
2926 class Dot<1> : public DerivedFunc<Signature<float, float, float> >
2929 string getName (void) const
2934 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2936 return args.a * args.b;
2941 ExprP<float> dot (const ExprP<Vector<float, Size> >& x, const ExprP<Vector<float, Size> >& y)
2943 return app<Dot<Size> >(x, y);
2946 ExprP<float> dot (const ExprP<float>& x, const ExprP<float>& y)
2948 return app<Dot<1> >(x, y);
2952 class Length : public DerivedFunc<
2953 Signature<float, typename ContainerOf<float, Size>::Container> >
2956 typedef typename Length::ArgExprs ArgExprs;
2958 string getName (void) const
2964 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2966 return sqrt(dot(args.a, args.a));
2971 ExprP<float> length (const ExprP<typename ContainerOf<float, Size>::Container>& x)
2973 return app<Length<Size> >(x);
2977 class Distance : public DerivedFunc<
2979 typename ContainerOf<float, Size>::Container,
2980 typename ContainerOf<float, Size>::Container> >
2983 typedef typename Distance::Ret Ret;
2984 typedef typename Distance::ArgExprs ArgExprs;
2986 string getName (void) const
2992 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
2994 return length<Size>(args.a - args.b);
3000 class Cross : public DerivedFunc<Signature<Vec3, Vec3, Vec3> >
3003 string getName (void) const
3009 ExprP<Vec3> doExpand (ExpandContext&, const ArgExprs& x) const
3011 return vec3(x.a[1] * x.b[2] - x.b[1] * x.a[2],
3012 x.a[2] * x.b[0] - x.b[2] * x.a[0],
3013 x.a[0] * x.b[1] - x.b[0] * x.a[1]);
3017 DEFINE_CONSTRUCTOR2(Cross, Vec3, cross, Vec3, Vec3)
3020 class Normalize : public DerivedFunc<
3021 Signature<typename ContainerOf<float, Size>::Container,
3022 typename ContainerOf<float, Size>::Container> >
3025 typedef typename Normalize::Ret Ret;
3026 typedef typename Normalize::ArgExprs ArgExprs;
3028 string getName (void) const
3034 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3036 return args.a / length<Size>(args.a);
3041 class FaceForward : public DerivedFunc<
3042 Signature<typename ContainerOf<float, Size>::Container,
3043 typename ContainerOf<float, Size>::Container,
3044 typename ContainerOf<float, Size>::Container,
3045 typename ContainerOf<float, Size>::Container> >
3048 typedef typename FaceForward::Ret Ret;
3049 typedef typename FaceForward::ArgExprs ArgExprs;
3051 string getName (void) const
3053 return "faceforward";
3059 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3061 return cond(dot(args.c, args.b) < constant(0.0f), args.a, -args.a);
3066 class Reflect : public DerivedFunc<
3067 Signature<typename ContainerOf<float, Size>::Container,
3068 typename ContainerOf<float, Size>::Container,
3069 typename ContainerOf<float, Size>::Container> >
3072 typedef typename Reflect::Ret Ret;
3073 typedef typename Reflect::Arg0 Arg0;
3074 typedef typename Reflect::Arg1 Arg1;
3075 typedef typename Reflect::ArgExprs ArgExprs;
3077 string getName (void) const
3083 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3085 const ExprP<Arg0>& i = args.a;
3086 const ExprP<Arg1>& n = args.b;
3087 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3089 return i - alternatives((n * dotNI) * constant(2.0f),
3090 n * (dotNI * constant(2.0f)));
3095 class Refract : public DerivedFunc<
3096 Signature<typename ContainerOf<float, Size>::Container,
3097 typename ContainerOf<float, Size>::Container,
3098 typename ContainerOf<float, Size>::Container,
3102 typedef typename Refract::Ret Ret;
3103 typedef typename Refract::Arg0 Arg0;
3104 typedef typename Refract::Arg1 Arg1;
3105 typedef typename Refract::ArgExprs ArgExprs;
3107 string getName (void) const
3113 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3115 const ExprP<Arg0>& i = args.a;
3116 const ExprP<Arg1>& n = args.b;
3117 const ExprP<float>& eta = args.c;
3118 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3119 const ExprP<float> k = bindExpression("k", ctx, constant(1.0f) - eta * eta *
3120 (constant(1.0f) - dotNI * dotNI));
3122 return cond(k < constant(0.0f),
3123 genXType<float, Size>(constant(0.0f)),
3124 i * eta - n * (eta * dotNI + sqrt(k)));
3128 class PreciseFunc1 : public CFloatFunc1
3131 PreciseFunc1 (const string& name, DoubleFunc1& func) : CFloatFunc1(name, func) {}
3133 double precision (const EvalContext&, double, double) const { return 0.0; }
3136 class Abs : public PreciseFunc1
3139 Abs (void) : PreciseFunc1("abs", deAbs) {}
3142 class Sign : public PreciseFunc1
3145 Sign (void) : PreciseFunc1("sign", deSign) {}
3148 class Floor : public PreciseFunc1
3151 Floor (void) : PreciseFunc1("floor", deFloor) {}
3154 class Trunc : public PreciseFunc1
3157 Trunc (void) : PreciseFunc1("trunc", deTrunc) {}
3160 class Round : public FloatFunc1
3163 string getName (void) const { return "round"; }
3166 Interval applyPoint (const EvalContext&, double x) const
3168 double truncated = 0.0;
3169 const double fract = deModf(x, &truncated);
3172 if (fabs(fract) <= 0.5)
3174 if (fabs(fract) >= 0.5)
3175 ret |= truncated + deSign(fract);
3180 double precision (const EvalContext&, double, double) const { return 0.0; }
3183 class RoundEven : public PreciseFunc1
3186 RoundEven (void) : PreciseFunc1("roundEven", deRoundEven) {}
3189 class Ceil : public PreciseFunc1
3192 Ceil (void) : PreciseFunc1("ceil", deCeil) {}
3195 DEFINE_DERIVED_FLOAT1(Fract, fract, x, x - app<Floor>(x));
3197 class PreciseFunc2 : public CFloatFunc2
3200 PreciseFunc2 (const string& name, DoubleFunc2& func) : CFloatFunc2(name, func) {}
3202 double precision (const EvalContext&, double, double, double) const { return 0.0; }
3205 DEFINE_DERIVED_FLOAT2(Mod, mod, x, y, x - y * app<Floor>(x / y));
3207 class Modf : public PrimitiveFunc<Signature<float, float, float> >
3210 string getName (void) const
3216 IRet doApply (const EvalContext&, const IArgs& iargs) const
3219 Interval& wholeIV = const_cast<Interval&>(iargs.b);
3222 TCU_INTERVAL_APPLY_MONOTONE1(fracIV, x, iargs.a, frac, frac = deModf(x, &intPart));
3223 TCU_INTERVAL_APPLY_MONOTONE1(wholeIV, x, iargs.a, whole,
3224 deModf(x, &intPart); whole = intPart);
3226 if (!iargs.a.isFinite())
3228 // Behavior on modf(Inf) not well-defined, allow anything as a fractional part
3229 // See Khronos bug 13907
3236 int getOutParamIndex (void) const
3242 class Min : public PreciseFunc2 { public: Min (void) : PreciseFunc2("min", deMin) {} };
3243 class Max : public PreciseFunc2 { public: Max (void) : PreciseFunc2("max", deMax) {} };
3245 class Clamp : public FloatFunc3
3248 string getName (void) const { return "clamp"; }
3250 double applyExact (double x, double minVal, double maxVal) const
3252 return de::min(de::max(x, minVal), maxVal);
3255 double precision (const EvalContext&, double, double, double minVal, double maxVal) const
3257 return minVal > maxVal ? TCU_NAN : 0.0;
3261 ExprP<float> clamp(const ExprP<float>& x, const ExprP<float>& minVal, const ExprP<float>& maxVal)
3263 return app<Clamp>(x, minVal, maxVal);
3266 DEFINE_DERIVED_FLOAT3(Mix, mix, x, y, a, alternatives((x * (constant(1.0f) - a)) + y * a,
3269 static double step (double edge, double x)
3271 return x < edge ? 0.0 : 1.0;
3274 class Step : public PreciseFunc2 { public: Step (void) : PreciseFunc2("step", step) {} };
3276 class SmoothStep : public DerivedFunc<Signature<float, float, float, float> >
3279 string getName (void) const
3281 return "smoothstep";
3286 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3288 const ExprP<float>& edge0 = args.a;
3289 const ExprP<float>& edge1 = args.b;
3290 const ExprP<float>& x = args.c;
3291 const ExprP<float> tExpr = clamp((x - edge0) / (edge1 - edge0),
3292 constant(0.0f), constant(1.0f));
3293 const ExprP<float> t = bindExpression("t", ctx, tExpr);
3295 return (t * t * (constant(3.0f) - constant(2.0f) * t));
3299 class FrExp : public PrimitiveFunc<Signature<float, float, int> >
3302 string getName (void) const
3308 IRet doApply (const EvalContext&, const IArgs& iargs) const
3311 const IArg0& x = iargs.a;
3312 IArg1& exponent = const_cast<IArg1&>(iargs.b);
3314 if (x.hasNaN() || x.contains(TCU_INFINITY) || x.contains(-TCU_INFINITY))
3316 // GLSL (in contrast to IEEE) says that result of applying frexp
3317 // to infinity is undefined
3318 ret = Interval::unbounded() | TCU_NAN;
3319 exponent = Interval(-deLdExp(1.0, 31), deLdExp(1.0, 31)-1);
3321 else if (!x.empty())
3324 const double loFrac = deFrExp(x.lo(), &loExp);
3326 const double hiFrac = deFrExp(x.hi(), &hiExp);
3328 if (deSign(loFrac) != deSign(hiFrac))
3330 exponent = Interval(-TCU_INFINITY, de::max(loExp, hiExp));
3332 if (deSign(loFrac) < 0)
3333 ret |= Interval(-1.0 + DBL_EPSILON*0.5, 0.0);
3334 if (deSign(hiFrac) > 0)
3335 ret |= Interval(0.0, 1.0 - DBL_EPSILON*0.5);
3339 exponent = Interval(loExp, hiExp);
3341 ret = Interval(loFrac, hiFrac);
3343 ret = deSign(loFrac) * Interval(0.5, 1.0 - DBL_EPSILON*0.5);
3350 int getOutParamIndex (void) const
3356 class LdExp : public PrimitiveFunc<Signature<float, float, int> >
3359 string getName (void) const
3365 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
3367 Interval ret = call<Exp2>(ctx, iargs.b);
3368 // Khronos bug 11180 consensus: if exp2(exponent) cannot be represented,
3369 // the result is undefined.
3371 if (ret.contains(TCU_INFINITY) | ret.contains(-TCU_INFINITY))
3374 return call<Mul>(ctx, iargs.a, ret);
3378 template<int Rows, int Columns>
3379 class Transpose : public PrimitiveFunc<Signature<Matrix<float, Rows, Columns>,
3380 Matrix<float, Columns, Rows> > >
3383 typedef typename Transpose::IRet IRet;
3384 typedef typename Transpose::IArgs IArgs;
3386 string getName (void) const
3392 IRet doApply (const EvalContext&, const IArgs& iargs) const
3396 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
3398 for (int colNdx = 0; colNdx < Columns; ++colNdx)
3399 ret(rowNdx, colNdx) = iargs.a(colNdx, rowNdx);
3406 template<typename Ret, typename Arg0, typename Arg1>
3407 class MulFunc : public PrimitiveFunc<Signature<Ret, Arg0, Arg1> >
3410 string getName (void) const { return "mul"; }
3413 void doPrint (ostream& os, const BaseArgExprs& args) const
3415 os << "(" << *args[0] << " * " << *args[1] << ")";
3419 template<int LeftRows, int Middle, int RightCols>
3420 class MatMul : public MulFunc<Matrix<float, LeftRows, RightCols>,
3421 Matrix<float, LeftRows, Middle>,
3422 Matrix<float, Middle, RightCols> >
3425 typedef typename MatMul::IRet IRet;
3426 typedef typename MatMul::IArgs IArgs;
3427 typedef typename MatMul::IArg0 IArg0;
3428 typedef typename MatMul::IArg1 IArg1;
3430 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3432 const IArg0& left = iargs.a;
3433 const IArg1& right = iargs.b;
3436 for (int row = 0; row < LeftRows; ++row)
3438 for (int col = 0; col < RightCols; ++col)
3440 Interval element (0.0);
3442 for (int ndx = 0; ndx < Middle; ++ndx)
3443 element = call<Add>(ctx, element,
3444 call<Mul>(ctx, left[ndx][row], right[col][ndx]));
3446 ret[col][row] = element;
3454 template<int Rows, int Cols>
3455 class VecMatMul : public MulFunc<Vector<float, Cols>,
3456 Vector<float, Rows>,
3457 Matrix<float, Rows, Cols> >
3460 typedef typename VecMatMul::IRet IRet;
3461 typedef typename VecMatMul::IArgs IArgs;
3462 typedef typename VecMatMul::IArg0 IArg0;
3463 typedef typename VecMatMul::IArg1 IArg1;
3466 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3468 const IArg0& left = iargs.a;
3469 const IArg1& right = iargs.b;
3472 for (int col = 0; col < Cols; ++col)
3474 Interval element (0.0);
3476 for (int row = 0; row < Rows; ++row)
3477 element = call<Add>(ctx, element, call<Mul>(ctx, left[row], right[col][row]));
3486 template<int Rows, int Cols>
3487 class MatVecMul : public MulFunc<Vector<float, Rows>,
3488 Matrix<float, Rows, Cols>,
3489 Vector<float, Cols> >
3492 typedef typename MatVecMul::IRet IRet;
3493 typedef typename MatVecMul::IArgs IArgs;
3494 typedef typename MatVecMul::IArg0 IArg0;
3495 typedef typename MatVecMul::IArg1 IArg1;
3498 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3500 const IArg0& left = iargs.a;
3501 const IArg1& right = iargs.b;
3503 return call<VecMatMul<Cols, Rows> >(ctx, right,
3504 call<Transpose<Rows, Cols> >(ctx, left));
3508 template<int Rows, int Cols>
3509 class OuterProduct : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
3510 Vector<float, Rows>,
3511 Vector<float, Cols> > >
3514 typedef typename OuterProduct::IRet IRet;
3515 typedef typename OuterProduct::IArgs IArgs;
3517 string getName (void) const
3519 return "outerProduct";
3523 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3527 for (int row = 0; row < Rows; ++row)
3529 for (int col = 0; col < Cols; ++col)
3530 ret[col][row] = call<Mul>(ctx, iargs.a[row], iargs.b[col]);
3537 template<int Rows, int Cols>
3538 ExprP<Matrix<float, Rows, Cols> > outerProduct (const ExprP<Vector<float, Rows> >& left,
3539 const ExprP<Vector<float, Cols> >& right)
3541 return app<OuterProduct<Rows, Cols> >(left, right);
3545 class DeterminantBase : public DerivedFunc<Signature<float, Matrix<float, Size, Size> > >
3548 string getName (void) const { return "determinant"; }
3555 ExprP<float> determinant (ExprP<Matrix<float, Size, Size> > mat)
3557 return app<Determinant<Size> >(mat);
3561 class Determinant<2> : public DeterminantBase<2>
3564 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3566 ExprP<Mat2> mat = args.a;
3568 return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
3573 class Determinant<3> : public DeterminantBase<3>
3576 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3578 ExprP<Mat3> mat = args.a;
3580 return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) +
3581 mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) +
3582 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
3587 class Determinant<4> : public DeterminantBase<4>
3590 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3592 ExprP<Mat4> mat = args.a;
3593 ExprP<Mat3> minors[4];
3595 for (int ndx = 0; ndx < 4; ++ndx)
3597 ExprP<Vec4> minorColumns[3];
3598 ExprP<Vec3> columns[3];
3600 for (int col = 0; col < 3; ++col)
3601 minorColumns[col] = mat[col < ndx ? col : col + 1];
3603 for (int col = 0; col < 3; ++col)
3604 columns[col] = vec3(minorColumns[0][col+1],
3605 minorColumns[1][col+1],
3606 minorColumns[2][col+1]);
3608 minors[ndx] = bindExpression("minor", ctx,
3609 mat3(columns[0], columns[1], columns[2]));
3612 return (mat[0][0] * determinant(minors[0]) -
3613 mat[1][0] * determinant(minors[1]) +
3614 mat[2][0] * determinant(minors[2]) -
3615 mat[3][0] * determinant(minors[3]));
3619 template<int Size> class Inverse;
3622 ExprP<Matrix<float, Size, Size> > inverse (ExprP<Matrix<float, Size, Size> > mat)
3624 return app<Inverse<Size> >(mat);
3628 class Inverse<2> : public DerivedFunc<Signature<Mat2, Mat2> >
3631 string getName (void) const
3637 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3639 ExprP<Mat2> mat = args.a;
3640 ExprP<float> det = bindExpression("det", ctx, determinant(mat));
3642 return mat2(vec2(mat[1][1] / det, -mat[0][1] / det),
3643 vec2(-mat[1][0] / det, mat[0][0] / det));
3648 class Inverse<3> : public DerivedFunc<Signature<Mat3, Mat3> >
3651 string getName (void) const
3657 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3659 ExprP<Mat3> mat = args.a;
3660 ExprP<Mat2> invA = bindExpression("invA", ctx,
3661 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3662 vec2(mat[1][0], mat[1][1]))));
3664 ExprP<Vec2> matB = bindExpression("matB", ctx, vec2(mat[2][0], mat[2][1]));
3665 ExprP<Vec2> matC = bindExpression("matC", ctx, vec2(mat[0][2], mat[1][2]));
3666 ExprP<float> matD = bindExpression("matD", ctx, mat[2][2]);
3668 ExprP<float> schur = bindExpression("schur", ctx,
3670 (matD - dot(matC * invA, matB)));
3672 ExprP<Vec2> t1 = invA * matB;
3673 ExprP<Vec2> t2 = t1 * schur;
3674 ExprP<Mat2> t3 = outerProduct(t2, matC);
3675 ExprP<Mat2> t4 = t3 * invA;
3676 ExprP<Mat2> t5 = invA + t4;
3677 ExprP<Mat2> blockA = bindExpression("blockA", ctx, t5);
3678 ExprP<Vec2> blockB = bindExpression("blockB", ctx,
3679 (invA * matB) * -schur);
3680 ExprP<Vec2> blockC = bindExpression("blockC", ctx,
3681 (matC * invA) * -schur);
3683 return mat3(vec3(blockA[0][0], blockA[0][1], blockC[0]),
3684 vec3(blockA[1][0], blockA[1][1], blockC[1]),
3685 vec3(blockB[0], blockB[1], schur));
3690 class Inverse<4> : public DerivedFunc<Signature<Mat4, Mat4> >
3693 string getName (void) const { return "inverse"; }
3696 ExprP<Ret> doExpand (ExpandContext& ctx,
3697 const ArgExprs& args) const
3699 ExprP<Mat4> mat = args.a;
3700 ExprP<Mat2> invA = bindExpression("invA", ctx,
3701 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3702 vec2(mat[1][0], mat[1][1]))));
3703 ExprP<Mat2> matB = bindExpression("matB", ctx,
3704 mat2(vec2(mat[2][0], mat[2][1]),
3705 vec2(mat[3][0], mat[3][1])));
3706 ExprP<Mat2> matC = bindExpression("matC", ctx,
3707 mat2(vec2(mat[0][2], mat[0][3]),
3708 vec2(mat[1][2], mat[1][3])));
3709 ExprP<Mat2> matD = bindExpression("matD", ctx,
3710 mat2(vec2(mat[2][2], mat[2][3]),
3711 vec2(mat[3][2], mat[3][3])));
3712 ExprP<Mat2> schur = bindExpression("schur", ctx,
3713 inverse(matD + -(matC * invA * matB)));
3714 ExprP<Mat2> blockA = bindExpression("blockA", ctx,
3715 invA + (invA * matB * schur * matC * invA));
3716 ExprP<Mat2> blockB = bindExpression("blockB", ctx,
3717 (-invA) * matB * schur);
3718 ExprP<Mat2> blockC = bindExpression("blockC", ctx,
3719 (-schur) * matC * invA);
3721 return mat4(vec4(blockA[0][0], blockA[0][1], blockC[0][0], blockC[0][1]),
3722 vec4(blockA[1][0], blockA[1][1], blockC[1][0], blockC[1][1]),
3723 vec4(blockB[0][0], blockB[0][1], schur[0][0], schur[0][1]),
3724 vec4(blockB[1][0], blockB[1][1], schur[1][0], schur[1][1]));
3728 class Fma : public DerivedFunc<Signature<float, float, float, float> >
3731 string getName (void) const
3736 string getRequiredExtension (void) const
3738 return "GL_EXT_gpu_shader5";
3742 ExprP<float> doExpand (ExpandContext&, const ArgExprs& x) const
3744 return x.a * x.b + x.c;
3750 using namespace Functions;
3752 template <typename T>
3753 ExprP<typename T::Element> ContainerExprPBase<T>::operator[] (int i) const
3755 return Functions::getComponent(exprP<T>(*this), i);
3758 ExprP<float> operator+ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3760 return app<Add>(arg0, arg1);
3763 ExprP<float> operator- (const ExprP<float>& arg0, const ExprP<float>& arg1)
3765 return app<Sub>(arg0, arg1);
3768 ExprP<float> operator- (const ExprP<float>& arg0)
3770 return app<Negate>(arg0);
3773 ExprP<float> operator* (const ExprP<float>& arg0, const ExprP<float>& arg1)
3775 return app<Mul>(arg0, arg1);
3778 ExprP<float> operator/ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3780 return app<Div>(arg0, arg1);
3783 template <typename Sig_, int Size>
3784 class GenFunc : public PrimitiveFunc<Signature<
3785 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3786 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3787 typename ContainerOf<typename Sig_::Arg1, Size>::Container,
3788 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
3789 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
3792 typedef typename GenFunc::IArgs IArgs;
3793 typedef typename GenFunc::IRet IRet;
3795 GenFunc (const Func<Sig_>& scalarFunc) : m_func (scalarFunc) {}
3797 string getName (void) const
3799 return m_func.getName();
3802 int getOutParamIndex (void) const
3804 return m_func.getOutParamIndex();
3807 string getRequiredExtension (void) const
3809 return m_func.getRequiredExtension();
3813 void doPrint (ostream& os, const BaseArgExprs& args) const
3815 m_func.print(os, args);
3818 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3822 for (int ndx = 0; ndx < Size; ++ndx)
3825 m_func.apply(ctx, iargs.a[ndx], iargs.b[ndx], iargs.c[ndx], iargs.d[ndx]);
3831 void doGetUsedFuncs (FuncSet& dst) const
3833 m_func.getUsedFuncs(dst);
3836 const Func<Sig_>& m_func;
3839 template <typename F, int Size>
3840 class VectorizedFunc : public GenFunc<typename F::Sig, Size>
3843 VectorizedFunc (void) : GenFunc<typename F::Sig, Size>(instance<F>()) {}
3848 template <typename Sig_, int Size>
3849 class FixedGenFunc : public PrimitiveFunc <Signature<
3850 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3851 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3852 typename Sig_::Arg1,
3853 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
3854 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
3857 typedef typename FixedGenFunc::IArgs IArgs;
3858 typedef typename FixedGenFunc::IRet IRet;
3860 string getName (void) const
3862 return this->doGetScalarFunc().getName();
3866 void doPrint (ostream& os, const BaseArgExprs& args) const
3868 this->doGetScalarFunc().print(os, args);
3871 IRet doApply (const EvalContext& ctx,
3872 const IArgs& iargs) const
3875 const Func<Sig_>& func = this->doGetScalarFunc();
3877 for (int ndx = 0; ndx < Size; ++ndx)
3878 ret[ndx] = func.apply(ctx, iargs.a[ndx], iargs.b, iargs.c[ndx], iargs.d[ndx]);
3883 virtual const Func<Sig_>& doGetScalarFunc (void) const = 0;
3886 template <typename F, int Size>
3887 class FixedVecFunc : public FixedGenFunc<typename F::Sig, Size>
3890 const Func<typename F::Sig>& doGetScalarFunc (void) const { return instance<F>(); }
3893 template<typename Sig>
3896 GenFuncs (const Func<Sig>& func_,
3897 const GenFunc<Sig, 2>& func2_,
3898 const GenFunc<Sig, 3>& func3_,
3899 const GenFunc<Sig, 4>& func4_)
3906 const Func<Sig>& func;
3907 const GenFunc<Sig, 2>& func2;
3908 const GenFunc<Sig, 3>& func3;
3909 const GenFunc<Sig, 4>& func4;
3912 template<typename F>
3913 GenFuncs<typename F::Sig> makeVectorizedFuncs (void)
3915 return GenFuncs<typename F::Sig>(instance<F>(),
3916 instance<VectorizedFunc<F, 2> >(),
3917 instance<VectorizedFunc<F, 3> >(),
3918 instance<VectorizedFunc<F, 4> >());
3922 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
3923 const ExprP<Vector<float, Size> >& arg1)
3925 return app<VectorizedFunc<Mul, Size> >(arg0, arg1);
3929 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
3930 const ExprP<float>& arg1)
3932 return app<FixedVecFunc<Mul, Size> >(arg0, arg1);
3936 ExprP<Vector<float, Size> > operator/(const ExprP<Vector<float, Size> >& arg0,
3937 const ExprP<float>& arg1)
3939 return app<FixedVecFunc<Div, Size> >(arg0, arg1);
3943 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0)
3945 return app<VectorizedFunc<Negate, Size> >(arg0);
3949 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
3950 const ExprP<Vector<float, Size> >& arg1)
3952 return app<VectorizedFunc<Sub, Size> >(arg0, arg1);
3955 template<int LeftRows, int Middle, int RightCols>
3956 ExprP<Matrix<float, LeftRows, RightCols> >
3957 operator* (const ExprP<Matrix<float, LeftRows, Middle> >& left,
3958 const ExprP<Matrix<float, Middle, RightCols> >& right)
3960 return app<MatMul<LeftRows, Middle, RightCols> >(left, right);
3963 template<int Rows, int Cols>
3964 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
3965 const ExprP<Matrix<float, Rows, Cols> >& right)
3967 return app<VecMatMul<Rows, Cols> >(left, right);
3970 template<int Rows, int Cols>
3971 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
3972 const ExprP<Vector<float, Rows> >& right)
3974 return app<MatVecMul<Rows, Cols> >(left, right);
3977 template<int Rows, int Cols>
3978 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
3979 const ExprP<float>& right)
3981 return app<ScalarMatFunc<Mul, Rows, Cols> >(left, right);
3984 template<int Rows, int Cols>
3985 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
3986 const ExprP<Matrix<float, Rows, Cols> >& right)
3988 return app<CompMatFunc<Add, Rows, Cols> >(left, right);
3991 template<int Rows, int Cols>
3992 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat)
3994 return app<MatNeg<Rows, Cols> >(mat);
3997 template <typename T>
4001 virtual void genFixeds (const FloatFormat&, vector<T>&) const {}
4002 virtual T genRandom (const FloatFormat&, Precision, Random&) const { return T(); }
4003 virtual double getWeight (void) const { return 0.0; }
4007 class DefaultSampling<Void> : public Sampling<Void>
4010 void genFixeds (const FloatFormat&, vector<Void>& dst) const { dst.push_back(Void()); }
4014 class DefaultSampling<bool> : public Sampling<bool>
4017 void genFixeds (const FloatFormat&, vector<bool>& dst) const
4019 dst.push_back(true);
4020 dst.push_back(false);
4025 class DefaultSampling<int> : public Sampling<int>
4028 int genRandom (const FloatFormat&, Precision prec, Random& rnd) const
4030 const int exp = rnd.getInt(0, getNumBits(prec)-2);
4031 const int sign = rnd.getBool() ? -1 : 1;
4033 return sign * rnd.getInt(0, (deInt32)1 << exp);
4036 void genFixeds (const FloatFormat&, vector<int>& dst) const
4042 double getWeight (void) const { return 1.0; }
4045 static inline int getNumBits (Precision prec)
4049 case glu::PRECISION_LOWP: return 8;
4050 case glu::PRECISION_MEDIUMP: return 16;
4051 case glu::PRECISION_HIGHP: return 32;
4060 class DefaultSampling<float> : public Sampling<float>
4063 float genRandom (const FloatFormat& format, Precision prec, Random& rnd) const;
4064 void genFixeds (const FloatFormat& format, vector<float>& dst) const;
4065 double getWeight (void) const { return 1.0; }
4068 //! Generate a random float from a reasonable general-purpose distribution.
4069 float DefaultSampling<float>::genRandom (const FloatFormat& format,
4073 const int minExp = format.getMinExp();
4074 const int maxExp = format.getMaxExp();
4075 const bool haveSubnormal = format.hasSubnormal() != tcu::NO;
4077 // Choose exponent so that the cumulative distribution is cubic.
4078 // This makes the probability distribution quadratic, with the peak centered on zero.
4079 const double minRoot = deCbrt(minExp - 0.5 - (haveSubnormal ? 1.0 : 0.0));
4080 const double maxRoot = deCbrt(maxExp + 0.5);
4081 const int fractionBits = format.getFractionBits();
4082 const int exp = int(deRoundEven(dePow(rnd.getDouble(minRoot, maxRoot),
4084 float base = 0.0f; // integral power of two
4085 float quantum = 0.0f; // smallest representable difference in the binade
4086 float significand = 0.0f; // Significand.
4088 DE_ASSERT(fractionBits < std::numeric_limits<float>::digits);
4090 // Generate some occasional special numbers
4091 switch (rnd.getInt(0, 64))
4094 case 1: return TCU_INFINITY;
4095 case 2: return -TCU_INFINITY;
4096 case 3: return TCU_NAN;
4103 base = deFloatLdExp(1.0f, exp);
4104 quantum = deFloatLdExp(1.0f, exp - fractionBits);
4110 quantum = deFloatLdExp(1.0f, minExp - fractionBits);
4113 switch (rnd.getInt(0, 16))
4115 case 0: // The highest number in this binade, significand is all bits one.
4116 significand = base - quantum;
4118 case 1: // Significand is one.
4119 significand = quantum;
4121 case 2: // Significand is zero.
4124 default: // Random (evenly distributed) significand.
4126 deUint64 intFraction = rnd.getUint64() & ((1 << fractionBits) - 1);
4127 significand = float(intFraction) * quantum;
4131 // Produce positive numbers more often than negative.
4132 return (rnd.getInt(0,3) == 0 ? -1.0f : 1.0f) * (base + significand);
4135 //! Generate a standard set of floats that should always be tested.
4136 void DefaultSampling<float>::genFixeds (const FloatFormat& format, vector<float>& dst) const
4138 const int minExp = format.getMinExp();
4139 const int maxExp = format.getMaxExp();
4140 const int fractionBits = format.getFractionBits();
4141 const float minQuantum = deFloatLdExp(1.0f, minExp - fractionBits);
4142 const float minNormalized = deFloatLdExp(1.0f, minExp);
4143 const float maxQuantum = deFloatLdExp(1.0f, maxExp - fractionBits);
4146 dst.push_back(TCU_NAN);
4148 dst.push_back(0.0f);
4150 for (int sign = -1; sign <= 1; sign += 2)
4152 // Smallest subnormal
4153 dst.push_back((float)sign * minQuantum);
4155 // Largest subnormal
4156 dst.push_back((float)sign * (minNormalized - minQuantum));
4158 // Smallest normalized
4159 dst.push_back((float)sign * minNormalized);
4161 // Next smallest normalized
4162 dst.push_back((float)sign * (minNormalized + minQuantum));
4164 dst.push_back((float)sign * 0.5f);
4165 dst.push_back((float)sign * 1.0f);
4166 dst.push_back((float)sign * 2.0f);
4169 dst.push_back((float)sign * (deFloatLdExp(1.0f, maxExp) +
4170 (deFloatLdExp(1.0f, maxExp) - maxQuantum)));
4172 dst.push_back((float)sign * TCU_INFINITY);
4176 template <typename T, int Size>
4177 class DefaultSampling<Vector<T, Size> > : public Sampling<Vector<T, Size> >
4180 typedef Vector<T, Size> Value;
4182 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4186 for (int ndx = 0; ndx < Size; ++ndx)
4187 ret[ndx] = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4192 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4196 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4198 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4199 dst.push_back(Value(scalars[scalarNdx]));
4202 double getWeight (void) const
4204 return dePow(instance<DefaultSampling<T> >().getWeight(), Size);
4208 template <typename T, int Rows, int Columns>
4209 class DefaultSampling<Matrix<T, Rows, Columns> > : public Sampling<Matrix<T, Rows, Columns> >
4212 typedef Matrix<T, Rows, Columns> Value;
4214 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4218 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
4219 for (int colNdx = 0; colNdx < Columns; ++colNdx)
4220 ret(rowNdx, colNdx) = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4225 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4229 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4231 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4232 dst.push_back(Value(scalars[scalarNdx]));
4234 if (Columns == Rows)
4239 for (int ndx = 0; ndx < Columns; ++ndx)
4241 mat[Columns-1-ndx][ndx] = x;
4248 double getWeight (void) const
4250 return dePow(instance<DefaultSampling<T> >().getWeight(), Rows * Columns);
4256 CaseContext (const string& name_,
4257 TestContext& testContext_,
4258 const FloatFormat& floatFormat_,
4259 const FloatFormat& highpFormat_,
4260 Precision precision_,
4261 ShaderType shaderType_,
4264 , testContext (testContext_)
4265 , floatFormat (floatFormat_)
4266 , highpFormat (highpFormat_)
4267 , precision (precision_)
4268 , shaderType (shaderType_)
4269 , numRandoms (numRandoms_) {}
4272 TestContext& testContext;
4273 FloatFormat floatFormat;
4274 FloatFormat highpFormat;
4275 Precision precision;
4276 ShaderType shaderType;
4280 template<typename In0_ = Void, typename In1_ = Void, typename In2_ = Void, typename In3_ = Void>
4289 template <typename In>
4290 int numInputs (void)
4292 return (!isTypeValid<typename In::In0>() ? 0 :
4293 !isTypeValid<typename In::In1>() ? 1 :
4294 !isTypeValid<typename In::In2>() ? 2 :
4295 !isTypeValid<typename In::In3>() ? 3 :
4299 template<typename Out0_, typename Out1_ = Void>
4306 template <typename Out>
4307 int numOutputs (void)
4309 return (!isTypeValid<typename Out::Out0>() ? 0 :
4310 !isTypeValid<typename Out::Out1>() ? 1 :
4314 template<typename In>
4317 vector<typename In::In0> in0;
4318 vector<typename In::In1> in1;
4319 vector<typename In::In2> in2;
4320 vector<typename In::In3> in3;
4323 template<typename Out>
4326 Outputs (size_t size) : out0(size), out1(size) {}
4328 vector<typename Out::Out0> out0;
4329 vector<typename Out::Out1> out1;
4332 template<typename In, typename Out>
4335 VariableP<typename In::In0> in0;
4336 VariableP<typename In::In1> in1;
4337 VariableP<typename In::In2> in2;
4338 VariableP<typename In::In3> in3;
4339 VariableP<typename Out::Out0> out0;
4340 VariableP<typename Out::Out1> out1;
4343 template<typename In>
4346 Samplings (const Sampling<typename In::In0>& in0_,
4347 const Sampling<typename In::In1>& in1_,
4348 const Sampling<typename In::In2>& in2_,
4349 const Sampling<typename In::In3>& in3_)
4350 : in0 (in0_), in1 (in1_), in2 (in2_), in3 (in3_) {}
4352 const Sampling<typename In::In0>& in0;
4353 const Sampling<typename In::In1>& in1;
4354 const Sampling<typename In::In2>& in2;
4355 const Sampling<typename In::In3>& in3;
4358 template<typename In>
4359 struct DefaultSamplings : Samplings<In>
4361 DefaultSamplings (void)
4362 : Samplings<In>(instance<DefaultSampling<typename In::In0> >(),
4363 instance<DefaultSampling<typename In::In1> >(),
4364 instance<DefaultSampling<typename In::In2> >(),
4365 instance<DefaultSampling<typename In::In3> >()) {}
4368 template <typename In, typename Out>
4369 class BuiltinPrecisionCaseTestInstance : public TestInstance
4372 BuiltinPrecisionCaseTestInstance (Context& context,
4373 const CaseContext caseCtx,
4374 ShaderExecutor& executor,
4375 const Variables<In, Out> variables,
4376 const Samplings<In>& samplings,
4377 const StatementP stmt)
4378 : TestInstance (context)
4379 , m_caseCtx (caseCtx)
4380 , m_executor (executor)
4381 , m_variables (variables)
4382 , m_samplings (samplings)
4386 virtual tcu::TestStatus iterate (void);
4389 CaseContext m_caseCtx;
4390 ShaderExecutor& m_executor;
4391 Variables<In, Out> m_variables;
4392 const Samplings<In>& m_samplings;
4396 template<class In, class Out>
4397 tcu::TestStatus BuiltinPrecisionCaseTestInstance<In, Out>::iterate (void)
4399 typedef typename In::In0 In0;
4400 typedef typename In::In1 In1;
4401 typedef typename In::In2 In2;
4402 typedef typename In::In3 In3;
4403 typedef typename Out::Out0 Out0;
4404 typedef typename Out::Out1 Out1;
4406 Inputs<In> inputs = generateInputs(m_samplings, m_caseCtx.floatFormat, m_caseCtx.precision, m_caseCtx.numRandoms, 0xdeadbeefu + m_caseCtx.testContext.getCommandLine().getBaseSeed());
4407 const FloatFormat& fmt = m_caseCtx.floatFormat;
4408 const int inCount = numInputs<In>();
4409 const int outCount = numOutputs<Out>();
4410 const size_t numValues = (inCount > 0) ? inputs.in0.size() : 1;
4411 Outputs<Out> outputs (numValues);
4412 const FloatFormat highpFmt = m_caseCtx.highpFormat;
4413 const int maxMsgs = 100;
4415 Environment env; // Hoisted out of the inner loop for optimization.
4416 ResultCollector status;
4417 TestLog& testLog = m_context.getTestContext().getLog();
4419 const void* inputArr[] =
4421 &inputs.in0.front(), &inputs.in1.front(), &inputs.in2.front(), &inputs.in3.front(),
4425 &outputs.out0.front(), &outputs.out1.front(),
4428 // Print out the statement and its definitions
4429 testLog << TestLog::Message << "Statement: " << m_stmt << TestLog::EndMessage;
4434 m_stmt->getUsedFuncs(funcs);
4435 for (FuncSet::const_iterator it = funcs.begin(); it != funcs.end(); ++it)
4437 (*it)->printDefinition(oss);
4440 testLog << TestLog::Message << "Reference definitions:\n" << oss.str()
4441 << TestLog::EndMessage;
4446 case 4: DE_ASSERT(inputs.in3.size() == numValues);
4447 case 3: DE_ASSERT(inputs.in2.size() == numValues);
4448 case 2: DE_ASSERT(inputs.in1.size() == numValues);
4449 case 1: DE_ASSERT(inputs.in0.size() == numValues);
4453 m_executor.execute(m_context, int(numValues), inputArr, outputArr);
4455 // Initialize environment with dummy values so we don't need to bind in inner loop.
4457 const typename Traits<In0>::IVal in0;
4458 const typename Traits<In1>::IVal in1;
4459 const typename Traits<In2>::IVal in2;
4460 const typename Traits<In3>::IVal in3;
4461 const typename Traits<Out0>::IVal reference0;
4462 const typename Traits<Out1>::IVal reference1;
4464 env.bind(*m_variables.in0, in0);
4465 env.bind(*m_variables.in1, in1);
4466 env.bind(*m_variables.in2, in2);
4467 env.bind(*m_variables.in3, in3);
4468 env.bind(*m_variables.out0, reference0);
4469 env.bind(*m_variables.out1, reference1);
4472 // For each input tuple, compute output reference interval and compare
4473 // shader output to the reference.
4474 for (size_t valueNdx = 0; valueNdx < numValues; valueNdx++)
4477 typename Traits<Out0>::IVal reference0;
4478 typename Traits<Out1>::IVal reference1;
4480 env.lookup(*m_variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx]));
4481 env.lookup(*m_variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx]));
4482 env.lookup(*m_variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx]));
4483 env.lookup(*m_variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx]));
4486 EvalContext ctx (fmt, m_caseCtx.precision, env);
4487 m_stmt->execute(ctx);
4493 reference1 = convert<Out1>(highpFmt, env.lookup(*m_variables.out1));
4494 if (!status.check(contains(reference1, outputs.out1[valueNdx]),
4495 "Shader output 1 is outside acceptable range"))
4498 reference0 = convert<Out0>(highpFmt, env.lookup(*m_variables.out0));
4499 if (!status.check(contains(reference0, outputs.out0[valueNdx]),
4500 "Shader output 0 is outside acceptable range"))
4508 if ((!result && numErrors <= maxMsgs) || GLS_LOG_ALL_RESULTS)
4510 MessageBuilder builder = testLog.message();
4512 builder << (result ? "Passed" : "Failed") << " sample:\n";
4516 builder << "\t" << m_variables.in0->getName() << " = "
4517 << valueToString(highpFmt, inputs.in0[valueNdx]) << "\n";
4522 builder << "\t" << m_variables.in1->getName() << " = "
4523 << valueToString(highpFmt, inputs.in1[valueNdx]) << "\n";
4528 builder << "\t" << m_variables.in2->getName() << " = "
4529 << valueToString(highpFmt, inputs.in2[valueNdx]) << "\n";
4534 builder << "\t" << m_variables.in3->getName() << " = "
4535 << valueToString(highpFmt, inputs.in3[valueNdx]) << "\n";
4540 builder << "\t" << m_variables.out0->getName() << " = "
4541 << valueToString(highpFmt, outputs.out0[valueNdx]) << "\n"
4542 << "\tExpected range: "
4543 << intervalToString<typename Out::Out0>(highpFmt, reference0) << "\n";
4548 builder << "\t" << m_variables.out1->getName() << " = "
4549 << valueToString(highpFmt, outputs.out1[valueNdx]) << "\n"
4550 << "\tExpected range: "
4551 << intervalToString<typename Out::Out1>(highpFmt, reference1) << "\n";
4554 builder << TestLog::EndMessage;
4558 if (numErrors > maxMsgs)
4560 testLog << TestLog::Message << "(Skipped " << (numErrors - maxMsgs) << " messages.)"
4561 << TestLog::EndMessage;
4566 testLog << TestLog::Message << "All " << numValues << " inputs passed."
4567 << TestLog::EndMessage;
4571 testLog << TestLog::Message << numErrors << "/" << numValues << " inputs failed."
4572 << TestLog::EndMessage;
4576 return tcu::TestStatus::fail(de::toString(numErrors) + string(" test failed. Check log for the details"));
4578 return tcu::TestStatus::pass("Pass");
4582 class PrecisionCase : public TestCase
4585 PrecisionCase (const CaseContext& context, const string& name, const string& extension = "")
4586 : TestCase (context.testContext, name.c_str(), name.c_str())
4588 , m_extension (extension)
4589 , m_executor (DE_NULL)
4593 virtual void initPrograms (vk::SourceCollections& programCollection) const
4595 m_executor->setShaderSources(programCollection);
4598 const FloatFormat& getFormat (void) const { return m_ctx.floatFormat; }
4600 template <typename In, typename Out>
4601 void testStatement (const Variables<In, Out>& variables, const Statement& stmt);
4603 template<typename T>
4604 Symbol makeSymbol (const Variable<T>& variable)
4606 return Symbol(variable.getName(), getVarTypeOf<T>(m_ctx.precision));
4610 const string m_extension;
4612 de::MovePtr<ShaderExecutor> m_executor;
4615 template <typename In, typename Out>
4616 void PrecisionCase::testStatement (const Variables<In, Out>& variables, const Statement& stmt)
4618 const int inCount = numInputs<In>();
4619 const int outCount = numOutputs<Out>();
4620 Environment env; // Hoisted out of the inner loop for optimization.
4622 // Initialize ShaderSpec from precision, variables and statement.
4625 os << "precision " << glu::getPrecisionName(m_ctx.precision) << " float;\n";
4626 m_spec.globalDeclarations = os.str();
4629 if (!m_extension.empty())
4630 m_spec.globalDeclarations = "#extension " + m_extension + " : require\n";
4632 m_spec.inputs.resize(inCount);
4636 case 4: m_spec.inputs[3] = makeSymbol(*variables.in3);
4637 case 3: m_spec.inputs[2] = makeSymbol(*variables.in2);
4638 case 2: m_spec.inputs[1] = makeSymbol(*variables.in1);
4639 case 1: m_spec.inputs[0] = makeSymbol(*variables.in0);
4643 m_spec.outputs.resize(outCount);
4647 case 2: m_spec.outputs[1] = makeSymbol(*variables.out1);
4648 case 1: m_spec.outputs[0] = makeSymbol(*variables.out0);
4652 m_spec.source = de::toString(stmt);
4654 m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_ctx.shaderType, m_spec));
4657 template <typename T>
4660 bool operator() (const T& val1, const T& val2) const
4666 template <typename T>
4667 bool inputLess (const T& val1, const T& val2)
4669 return InputLess<T>()(val1, val2);
4673 struct InputLess<float>
4675 bool operator() (const float& val1, const float& val2) const
4685 template <typename T, int Size>
4686 struct InputLess<Vector<T, Size> >
4688 bool operator() (const Vector<T, Size>& vec1, const Vector<T, Size>& vec2) const
4690 for (int ndx = 0; ndx < Size; ++ndx)
4692 if (inputLess(vec1[ndx], vec2[ndx]))
4694 if (inputLess(vec2[ndx], vec1[ndx]))
4702 template <typename T, int Rows, int Cols>
4703 struct InputLess<Matrix<T, Rows, Cols> >
4705 bool operator() (const Matrix<T, Rows, Cols>& mat1,
4706 const Matrix<T, Rows, Cols>& mat2) const
4708 for (int col = 0; col < Cols; ++col)
4710 if (inputLess(mat1[col], mat2[col]))
4712 if (inputLess(mat2[col], mat1[col]))
4720 template <typename In>
4722 public Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4724 InTuple (const typename In::In0& in0,
4725 const typename In::In1& in1,
4726 const typename In::In2& in2,
4727 const typename In::In3& in3)
4728 : Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4729 (in0, in1, in2, in3) {}
4732 template <typename In>
4733 struct InputLess<InTuple<In> >
4735 bool operator() (const InTuple<In>& in1, const InTuple<In>& in2) const
4737 if (inputLess(in1.a, in2.a))
4739 if (inputLess(in2.a, in1.a))
4741 if (inputLess(in1.b, in2.b))
4743 if (inputLess(in2.b, in1.b))
4745 if (inputLess(in1.c, in2.c))
4747 if (inputLess(in2.c, in1.c))
4749 if (inputLess(in1.d, in2.d))
4755 template<typename In>
4756 Inputs<In> generateInputs (const Samplings<In>& samplings,
4757 const FloatFormat& floatFormat,
4758 Precision intPrecision,
4764 Inputs<In> fixedInputs;
4765 set<InTuple<In>, InputLess<InTuple<In> > > seenInputs;
4767 samplings.in0.genFixeds(floatFormat, fixedInputs.in0);
4768 samplings.in1.genFixeds(floatFormat, fixedInputs.in1);
4769 samplings.in2.genFixeds(floatFormat, fixedInputs.in2);
4770 samplings.in3.genFixeds(floatFormat, fixedInputs.in3);
4772 for (size_t ndx0 = 0; ndx0 < fixedInputs.in0.size(); ++ndx0)
4774 for (size_t ndx1 = 0; ndx1 < fixedInputs.in1.size(); ++ndx1)
4776 for (size_t ndx2 = 0; ndx2 < fixedInputs.in2.size(); ++ndx2)
4778 for (size_t ndx3 = 0; ndx3 < fixedInputs.in3.size(); ++ndx3)
4780 const InTuple<In> tuple (fixedInputs.in0[ndx0],
4781 fixedInputs.in1[ndx1],
4782 fixedInputs.in2[ndx2],
4783 fixedInputs.in3[ndx3]);
4785 seenInputs.insert(tuple);
4786 ret.in0.push_back(tuple.a);
4787 ret.in1.push_back(tuple.b);
4788 ret.in2.push_back(tuple.c);
4789 ret.in3.push_back(tuple.d);
4795 for (size_t ndx = 0; ndx < numSamples; ++ndx)
4797 const typename In::In0 in0 = samplings.in0.genRandom(floatFormat, intPrecision, rnd);
4798 const typename In::In1 in1 = samplings.in1.genRandom(floatFormat, intPrecision, rnd);
4799 const typename In::In2 in2 = samplings.in2.genRandom(floatFormat, intPrecision, rnd);
4800 const typename In::In3 in3 = samplings.in3.genRandom(floatFormat, intPrecision, rnd);
4801 const InTuple<In> tuple (in0, in1, in2, in3);
4803 if (de::contains(seenInputs, tuple))
4806 seenInputs.insert(tuple);
4807 ret.in0.push_back(in0);
4808 ret.in1.push_back(in1);
4809 ret.in2.push_back(in2);
4810 ret.in3.push_back(in3);
4816 class FuncCaseBase : public PrecisionCase
4819 FuncCaseBase (const CaseContext& context, const string& name, const FuncBase& func)
4820 : PrecisionCase (context, name, func.getRequiredExtension())
4827 template <typename Sig>
4828 class FuncCase : public FuncCaseBase
4831 typedef Func<Sig> CaseFunc;
4832 typedef typename Sig::Ret Ret;
4833 typedef typename Sig::Arg0 Arg0;
4834 typedef typename Sig::Arg1 Arg1;
4835 typedef typename Sig::Arg2 Arg2;
4836 typedef typename Sig::Arg3 Arg3;
4837 typedef InTypes<Arg0, Arg1, Arg2, Arg3> In;
4838 typedef OutTypes<Ret> Out;
4840 FuncCase (const CaseContext& context, const string& name, const CaseFunc& func)
4841 : FuncCaseBase (context, name, func)
4847 virtual TestInstance* createInstance (Context& context) const
4849 return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, getSamplings(), m_stmt);
4853 void buildTest (void);
4854 virtual const Samplings<In>& getSamplings (void) const
4856 return instance<DefaultSamplings<In> >();
4860 const CaseFunc& m_func;
4861 Variables<In, Out> m_variables;
4864 template <typename Sig>
4865 void FuncCase<Sig>::buildTest (void)
4867 m_variables.out0 = variable<Ret>("out0");
4868 m_variables.out1 = variable<Void>("out1");
4869 m_variables.in0 = variable<Arg0>("in0");
4870 m_variables.in1 = variable<Arg1>("in1");
4871 m_variables.in2 = variable<Arg2>("in2");
4872 m_variables.in3 = variable<Arg3>("in3");
4875 ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.in1, m_variables.in2, m_variables.in3);
4876 m_stmt = variableAssignment(m_variables.out0, expr);
4878 this->testStatement(m_variables, *m_stmt);
4882 template <typename Sig>
4883 class InOutFuncCase : public FuncCaseBase
4886 typedef Func<Sig> CaseFunc;
4887 typedef typename Sig::Ret Ret;
4888 typedef typename Sig::Arg0 Arg0;
4889 typedef typename Sig::Arg1 Arg1;
4890 typedef typename Sig::Arg2 Arg2;
4891 typedef typename Sig::Arg3 Arg3;
4892 typedef InTypes<Arg0, Arg2, Arg3> In;
4893 typedef OutTypes<Ret, Arg1> Out;
4895 InOutFuncCase (const CaseContext& context, const string& name, const CaseFunc& func)
4896 : FuncCaseBase (context, name, func)
4901 virtual TestInstance* createInstance (Context& context) const
4903 return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, getSamplings(), m_stmt);
4907 void buildTest (void);
4908 virtual const Samplings<In>& getSamplings (void) const
4910 return instance<DefaultSamplings<In> >();
4914 const CaseFunc& m_func;
4915 Variables<In, Out> m_variables;
4918 template <typename Sig>
4919 void InOutFuncCase<Sig>::buildTest (void)
4922 m_variables.out0 = variable<Ret>("out0");
4923 m_variables.out1 = variable<Arg1>("out1");
4924 m_variables.in0 = variable<Arg0>("in0");
4925 m_variables.in1 = variable<Arg2>("in1");
4926 m_variables.in2 = variable<Arg3>("in2");
4927 m_variables.in3 = variable<Void>("in3");
4930 ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.out1, m_variables.in1, m_variables.in2);
4931 m_stmt = variableAssignment(m_variables.out0, expr);
4933 this->testStatement(m_variables, *m_stmt);
4937 template <typename Sig>
4938 PrecisionCase* createFuncCase (const CaseContext& context, const string& name, const Func<Sig>& func)
4940 switch (func.getOutParamIndex())
4943 return new FuncCase<Sig>(context, name, func);
4945 return new InOutFuncCase<Sig>(context, name, func);
4947 DE_FATAL("Impossible");
4955 virtual ~CaseFactory (void) {}
4956 virtual MovePtr<TestNode> createCase (const CaseContext& ctx) const = 0;
4957 virtual string getName (void) const = 0;
4958 virtual string getDesc (void) const = 0;
4961 class FuncCaseFactory : public CaseFactory
4964 virtual const FuncBase& getFunc (void) const = 0;
4965 string getName (void) const { return de::toLower(getFunc().getName()); }
4966 string getDesc (void) const { return "Function '" + getFunc().getName() + "'"; }
4969 template <typename Sig>
4970 class GenFuncCaseFactory : public CaseFactory
4973 GenFuncCaseFactory (const GenFuncs<Sig>& funcs, const string& name)
4975 , m_name (de::toLower(name))
4979 MovePtr<TestNode> createCase (const CaseContext& ctx) const
4981 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
4983 group->addChild(createFuncCase(ctx, "scalar", m_funcs.func));
4984 group->addChild(createFuncCase(ctx, "vec2", m_funcs.func2));
4985 group->addChild(createFuncCase(ctx, "vec3", m_funcs.func3));
4986 group->addChild(createFuncCase(ctx, "vec4", m_funcs.func4));
4987 return MovePtr<TestNode>(group);
4990 string getName (void) const { return m_name; }
4991 string getDesc (void) const { return "Function '" + m_funcs.func.getName() + "'"; }
4994 const GenFuncs<Sig> m_funcs;
4998 template <template <int> class GenF>
4999 class TemplateFuncCaseFactory : public FuncCaseFactory
5002 MovePtr<TestNode> createCase (const CaseContext& ctx) const
5004 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5006 group->addChild(createFuncCase(ctx, "scalar", instance<GenF<1> >()));
5007 group->addChild(createFuncCase(ctx, "vec2", instance<GenF<2> >()));
5008 group->addChild(createFuncCase(ctx, "vec3", instance<GenF<3> >()));
5009 group->addChild(createFuncCase(ctx, "vec4", instance<GenF<4> >()));
5011 return MovePtr<TestNode>(group);
5014 const FuncBase& getFunc (void) const { return instance<GenF<1> >(); }
5017 template <template <int> class GenF>
5018 class SquareMatrixFuncCaseFactory : public FuncCaseFactory
5021 MovePtr<TestNode> createCase (const CaseContext& ctx) const
5023 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5025 group->addChild(createFuncCase(ctx, "mat2", instance<GenF<2> >()));
5027 // disabled until we get reasonable results
5028 group->addChild(createFuncCase(ctx, "mat3", instance<GenF<3> >()));
5029 group->addChild(createFuncCase(ctx, "mat4", instance<GenF<4> >()));
5032 return MovePtr<TestNode>(group);
5035 const FuncBase& getFunc (void) const { return instance<GenF<2> >(); }
5038 template <template <int, int> class GenF>
5039 class MatrixFuncCaseFactory : public FuncCaseFactory
5042 MovePtr<TestNode> createCase (const CaseContext& ctx) const
5044 TestCaseGroup* const group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5046 this->addCase<2, 2>(ctx, group);
5047 this->addCase<3, 2>(ctx, group);
5048 this->addCase<4, 2>(ctx, group);
5049 this->addCase<2, 3>(ctx, group);
5050 this->addCase<3, 3>(ctx, group);
5051 this->addCase<4, 3>(ctx, group);
5052 this->addCase<2, 4>(ctx, group);
5053 this->addCase<3, 4>(ctx, group);
5054 this->addCase<4, 4>(ctx, group);
5056 return MovePtr<TestNode>(group);
5059 const FuncBase& getFunc (void) const { return instance<GenF<2,2> >(); }
5062 template <int Rows, int Cols>
5063 void addCase (const CaseContext& ctx, TestCaseGroup* group) const
5065 const char* const name = dataTypeNameOf<Matrix<float, Rows, Cols> >();
5066 group->addChild(createFuncCase(ctx, name, instance<GenF<Rows, Cols> >()));
5070 template <typename Sig>
5071 class SimpleFuncCaseFactory : public CaseFactory
5074 SimpleFuncCaseFactory (const Func<Sig>& func) : m_func(func) {}
5076 MovePtr<TestNode> createCase (const CaseContext& ctx) const { return MovePtr<TestNode>(createFuncCase(ctx, ctx.name.c_str(), m_func)); }
5077 string getName (void) const { return de::toLower(m_func.getName()); }
5078 string getDesc (void) const { return "Function '" + getName() + "'"; }
5081 const Func<Sig>& m_func;
5084 template <typename F>
5085 SharedPtr<SimpleFuncCaseFactory<typename F::Sig> > createSimpleFuncCaseFactory (void)
5087 return SharedPtr<SimpleFuncCaseFactory<typename F::Sig> >(new SimpleFuncCaseFactory<typename F::Sig>(instance<F>()));
5093 virtual ~CaseFactories (void) {}
5094 virtual const std::vector<const CaseFactory*> getFactories (void) const = 0;
5097 class BuiltinFuncs : public CaseFactories
5100 const vector<const CaseFactory*> getFactories (void) const
5102 vector<const CaseFactory*> ret;
5104 for (size_t ndx = 0; ndx < m_factories.size(); ++ndx)
5105 ret.push_back(m_factories[ndx].get());
5110 void addFactory (SharedPtr<const CaseFactory> fact) { m_factories.push_back(fact); }
5113 vector<SharedPtr<const CaseFactory> > m_factories;
5116 template <typename F>
5117 void addScalarFactory(BuiltinFuncs& funcs, string name = "")
5120 name = instance<F>().getName();
5122 funcs.addFactory(SharedPtr<const CaseFactory>(new GenFuncCaseFactory<typename F::Sig>(makeVectorizedFuncs<F>(), name)));
5125 MovePtr<const CaseFactories> createComputeOnlyBuiltinCases (void)
5127 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5129 // Tests for ES3 builtins
5131 addScalarFactory<Add>(*funcs);
5132 addScalarFactory<Sub>(*funcs);
5133 addScalarFactory<Mul>(*funcs);
5134 addScalarFactory<Div>(*funcs);
5136 addScalarFactory<Radians>(*funcs);
5137 addScalarFactory<Degrees>(*funcs);
5138 addScalarFactory<Sin>(*funcs);
5139 addScalarFactory<Cos>(*funcs);
5140 addScalarFactory<Tan>(*funcs);
5141 addScalarFactory<ASin>(*funcs);
5142 addScalarFactory<ACos>(*funcs);
5143 addScalarFactory<ATan2>(*funcs, "atan2");
5144 addScalarFactory<ATan>(*funcs);
5145 addScalarFactory<Sinh>(*funcs);
5146 addScalarFactory<Cosh>(*funcs);
5147 addScalarFactory<Tanh>(*funcs);
5148 addScalarFactory<ASinh>(*funcs);
5149 addScalarFactory<ACosh>(*funcs);
5150 addScalarFactory<ATanh>(*funcs);
5152 addScalarFactory<Pow>(*funcs);
5153 addScalarFactory<Exp>(*funcs);
5154 addScalarFactory<Log>(*funcs);
5155 addScalarFactory<Exp2>(*funcs);
5156 addScalarFactory<Log2>(*funcs);
5157 addScalarFactory<Sqrt>(*funcs);
5158 addScalarFactory<InverseSqrt>(*funcs);
5160 addScalarFactory<Abs>(*funcs);
5161 addScalarFactory<Sign>(*funcs);
5162 addScalarFactory<Floor>(*funcs);
5163 addScalarFactory<Trunc>(*funcs);
5164 addScalarFactory<Round>(*funcs);
5165 addScalarFactory<RoundEven>(*funcs);
5166 addScalarFactory<Ceil>(*funcs);
5167 addScalarFactory<Fract>(*funcs);
5168 addScalarFactory<Mod>(*funcs);
5169 funcs->addFactory(createSimpleFuncCaseFactory<Modf>());
5170 addScalarFactory<Min>(*funcs);
5171 addScalarFactory<Max>(*funcs);
5172 addScalarFactory<Clamp>(*funcs);
5173 addScalarFactory<Mix>(*funcs);
5174 addScalarFactory<Step>(*funcs);
5175 addScalarFactory<SmoothStep>(*funcs);
5177 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length>()));
5178 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance>()));
5179 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot>()));
5180 funcs->addFactory(createSimpleFuncCaseFactory<Cross>());
5181 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize>()));
5182 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward>()));
5183 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect>()));
5184 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract>()));
5187 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<MatrixCompMult>()));
5188 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct>()));
5189 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose>()));
5190 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant>()));
5191 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse>()));
5193 return MovePtr<const CaseFactories>(funcs.release());
5196 MovePtr<const CaseFactories> createCompleteBuiltinCases (void)
5198 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5200 // Tests for ES31 builtins
5201 addScalarFactory<FrExp>(*funcs);
5202 addScalarFactory<LdExp>(*funcs);
5203 addScalarFactory<Fma>(*funcs);
5205 return MovePtr<const CaseFactories>(funcs.release());
5208 struct PrecisionTestContext
5210 PrecisionTestContext (TestContext& testCtx_,
5211 const FloatFormat& highp_,
5212 const FloatFormat& mediump_,
5213 const FloatFormat& lowp_,
5214 const vector<ShaderType>& shaderTypes_,
5216 : testCtx (testCtx_)
5217 , shaderTypes (shaderTypes_)
5218 , numRandoms (numRandoms_)
5220 formats[glu::PRECISION_HIGHP] = &highp_;
5221 formats[glu::PRECISION_MEDIUMP] = &mediump_;
5222 formats[glu::PRECISION_LOWP] = &lowp_;
5225 TestContext& testCtx;
5226 const FloatFormat* formats[glu::PRECISION_LAST];
5227 vector<ShaderType> shaderTypes;
5231 TestCaseGroup* createFuncGroup (const PrecisionTestContext& ctx, const CaseFactory& factory)
5233 TestCaseGroup* const group = new TestCaseGroup(ctx.testCtx, factory.getName().c_str(), factory.getDesc().c_str());
5235 for (int precNdx = glu::PRECISION_MEDIUMP; precNdx < glu::PRECISION_LAST; ++precNdx)
5237 const Precision precision = Precision(precNdx);
5238 const string precName (glu::getPrecisionName(precision));
5239 const FloatFormat& fmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats, precNdx);
5240 const FloatFormat& highpFmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats,
5241 glu::PRECISION_HIGHP);
5243 for (size_t shaderNdx = 0; shaderNdx < ctx.shaderTypes.size(); ++shaderNdx)
5245 const ShaderType shaderType = ctx.shaderTypes[shaderNdx];
5246 const string shaderName (glu::getShaderTypeName(shaderType));
5247 const string name = precName + "_" + shaderName;
5248 const CaseContext caseCtx (name, ctx.testCtx, fmt, highpFmt,
5249 precision, shaderType, ctx.numRandoms);
5251 group->addChild(factory.createCase(caseCtx).release());
5258 void addBuiltinPrecisionTests (TestContext& testCtx,
5259 const CaseFactories& cases,
5260 const vector<ShaderType>& shaderTypes,
5261 TestCaseGroup& dstGroup)
5263 const int userRandoms = testCtx.getCommandLine().getTestIterationCount();
5264 const int defRandoms = 16384;
5265 const int numRandoms = userRandoms > 0 ? userRandoms : defRandoms;
5266 const FloatFormat highp (-126, 127, 23, true,
5267 tcu::MAYBE, // subnormals
5268 tcu::YES, // infinities
5270 // \todo [2014-04-01 lauri] Check these once Khronos bug 11840 is resolved.
5271 const FloatFormat mediump (-13, 13, 9, false);
5272 // A fixed-point format is just a floating point format with a fixed
5273 // exponent and support for subnormals.
5274 const FloatFormat lowp (0, 0, 7, false, tcu::YES);
5275 const PrecisionTestContext ctx (testCtx, highp, mediump, lowp,
5276 shaderTypes, numRandoms);
5278 for (size_t ndx = 0; ndx < cases.getFactories().size(); ++ndx)
5279 dstGroup.addChild(createFuncGroup(ctx, *cases.getFactories()[ndx]));
5282 BuiltinPrecisionTests::BuiltinPrecisionTests (tcu::TestContext& testCtx)
5283 : tcu::TestCaseGroup(testCtx, "precision", "Builtin precision tests")
5287 BuiltinPrecisionTests::~BuiltinPrecisionTests (void)
5291 void BuiltinPrecisionTests::init (void)
5293 std::vector<glu::ShaderType> shaderTypes;
5294 de::MovePtr<const CaseFactories> computeOnlyCases = createComputeOnlyBuiltinCases();
5295 de::MovePtr<const CaseFactories> completeCases = createCompleteBuiltinCases();
5297 shaderTypes.push_back(glu::SHADERTYPE_COMPUTE);
5299 addBuiltinPrecisionTests(m_testCtx,
5304 shaderTypes.clear();
5305 shaderTypes.push_back(glu::SHADERTYPE_VERTEX);
5306 shaderTypes.push_back(glu::SHADERTYPE_FRAGMENT);
5307 shaderTypes.push_back(glu::SHADERTYPE_COMPUTE);
5309 addBuiltinPrecisionTests(m_testCtx,