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(),
4430 case 4: DE_ASSERT(inputs.in3.size() == numValues);
4431 case 3: DE_ASSERT(inputs.in2.size() == numValues);
4432 case 2: DE_ASSERT(inputs.in1.size() == numValues);
4433 case 1: DE_ASSERT(inputs.in0.size() == numValues);
4437 m_executor.execute(m_context, int(numValues), inputArr, outputArr);
4439 // Initialize environment with dummy values so we don't need to bind in inner loop.
4441 const typename Traits<In0>::IVal in0;
4442 const typename Traits<In1>::IVal in1;
4443 const typename Traits<In2>::IVal in2;
4444 const typename Traits<In3>::IVal in3;
4445 const typename Traits<Out0>::IVal reference0;
4446 const typename Traits<Out1>::IVal reference1;
4448 env.bind(*m_variables.in0, in0);
4449 env.bind(*m_variables.in1, in1);
4450 env.bind(*m_variables.in2, in2);
4451 env.bind(*m_variables.in3, in3);
4452 env.bind(*m_variables.out0, reference0);
4453 env.bind(*m_variables.out1, reference1);
4456 // For each input tuple, compute output reference interval and compare
4457 // shader output to the reference.
4458 for (size_t valueNdx = 0; valueNdx < numValues; valueNdx++)
4461 typename Traits<Out0>::IVal reference0;
4462 typename Traits<Out1>::IVal reference1;
4464 env.lookup(*m_variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx]));
4465 env.lookup(*m_variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx]));
4466 env.lookup(*m_variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx]));
4467 env.lookup(*m_variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx]));
4470 EvalContext ctx (fmt, m_caseCtx.precision, env);
4471 m_stmt->execute(ctx);
4477 reference1 = convert<Out1>(highpFmt, env.lookup(*m_variables.out1));
4478 if (!status.check(contains(reference1, outputs.out1[valueNdx]),
4479 "Shader output 1 is outside acceptable range"))
4482 reference0 = convert<Out0>(highpFmt, env.lookup(*m_variables.out0));
4483 if (!status.check(contains(reference0, outputs.out0[valueNdx]),
4484 "Shader output 0 is outside acceptable range"))
4492 if ((!result && numErrors <= maxMsgs) || GLS_LOG_ALL_RESULTS)
4494 MessageBuilder builder = testLog.message();
4496 builder << (result ? "Passed" : "Failed") << " sample:\n";
4500 builder << "\t" << m_variables.in0->getName() << " = "
4501 << valueToString(highpFmt, inputs.in0[valueNdx]) << "\n";
4506 builder << "\t" << m_variables.in1->getName() << " = "
4507 << valueToString(highpFmt, inputs.in1[valueNdx]) << "\n";
4512 builder << "\t" << m_variables.in2->getName() << " = "
4513 << valueToString(highpFmt, inputs.in2[valueNdx]) << "\n";
4518 builder << "\t" << m_variables.in3->getName() << " = "
4519 << valueToString(highpFmt, inputs.in3[valueNdx]) << "\n";
4524 builder << "\t" << m_variables.out0->getName() << " = "
4525 << valueToString(highpFmt, outputs.out0[valueNdx]) << "\n"
4526 << "\tExpected range: "
4527 << intervalToString<typename Out::Out0>(highpFmt, reference0) << "\n";
4532 builder << "\t" << m_variables.out1->getName() << " = "
4533 << valueToString(highpFmt, outputs.out1[valueNdx]) << "\n"
4534 << "\tExpected range: "
4535 << intervalToString<typename Out::Out1>(highpFmt, reference1) << "\n";
4538 builder << TestLog::EndMessage;
4542 if (numErrors > maxMsgs)
4544 testLog << TestLog::Message << "(Skipped " << (numErrors - maxMsgs) << " messages.)"
4545 << TestLog::EndMessage;
4550 testLog << TestLog::Message << "All " << numValues << " inputs passed."
4551 << TestLog::EndMessage;
4555 testLog << TestLog::Message << numErrors << "/" << numValues << " inputs failed."
4556 << TestLog::EndMessage;
4560 return tcu::TestStatus::fail(de::toString(numErrors) + string(" test failed. Check log for the details"));
4562 return tcu::TestStatus::pass("Pass");
4566 class PrecisionCase : public TestCase
4569 PrecisionCase (const CaseContext& context, const string& name, const string& extension = "")
4570 : TestCase (context.testContext, name.c_str(), name.c_str())
4572 , m_extension (extension)
4573 , m_executor (DE_NULL)
4577 virtual void initPrograms (vk::SourceCollections& programCollection) const
4579 m_executor->setShaderSources(programCollection);
4582 const FloatFormat& getFormat (void) const { return m_ctx.floatFormat; }
4583 TestLog& log (void) const { return m_testCtx.getLog(); }
4585 template <typename In, typename Out>
4586 void testStatement (const Variables<In, Out>& variables, const Statement& stmt);
4588 template<typename T>
4589 Symbol makeSymbol (const Variable<T>& variable)
4591 return Symbol(variable.getName(), getVarTypeOf<T>(m_ctx.precision));
4595 const string m_extension;
4597 de::MovePtr<ShaderExecutor> m_executor;
4600 template <typename In, typename Out>
4601 void PrecisionCase::testStatement (const Variables<In, Out>& variables, const Statement& stmt)
4603 const int inCount = numInputs<In>();
4604 const int outCount = numOutputs<Out>();
4605 Environment env; // Hoisted out of the inner loop for optimization.
4607 // Print out the statement and its definitions
4608 log() << TestLog::Message << "Statement: " << stmt << TestLog::EndMessage;
4613 stmt.getUsedFuncs(funcs);
4614 for (FuncSet::const_iterator it = funcs.begin(); it != funcs.end(); ++it)
4616 (*it)->printDefinition(oss);
4619 log() << TestLog::Message << "Reference definitions:\n" << oss.str()
4620 << TestLog::EndMessage;
4623 // Initialize ShaderSpec from precision, variables and statement.
4626 os << "precision " << glu::getPrecisionName(m_ctx.precision) << " float;\n";
4627 m_spec.globalDeclarations = os.str();
4630 if (!m_extension.empty())
4631 m_spec.globalDeclarations = "#extension " + m_extension + " : require\n";
4633 m_spec.inputs.resize(inCount);
4637 case 4: m_spec.inputs[3] = makeSymbol(*variables.in3);
4638 case 3: m_spec.inputs[2] = makeSymbol(*variables.in2);
4639 case 2: m_spec.inputs[1] = makeSymbol(*variables.in1);
4640 case 1: m_spec.inputs[0] = makeSymbol(*variables.in0);
4644 m_spec.outputs.resize(outCount);
4648 case 2: m_spec.outputs[1] = makeSymbol(*variables.out1);
4649 case 1: m_spec.outputs[0] = makeSymbol(*variables.out0);
4653 m_spec.source = de::toString(stmt);
4655 m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_ctx.shaderType, m_spec));
4658 template <typename T>
4661 bool operator() (const T& val1, const T& val2) const
4667 template <typename T>
4668 bool inputLess (const T& val1, const T& val2)
4670 return InputLess<T>()(val1, val2);
4674 struct InputLess<float>
4676 bool operator() (const float& val1, const float& val2) const
4686 template <typename T, int Size>
4687 struct InputLess<Vector<T, Size> >
4689 bool operator() (const Vector<T, Size>& vec1, const Vector<T, Size>& vec2) const
4691 for (int ndx = 0; ndx < Size; ++ndx)
4693 if (inputLess(vec1[ndx], vec2[ndx]))
4695 if (inputLess(vec2[ndx], vec1[ndx]))
4703 template <typename T, int Rows, int Cols>
4704 struct InputLess<Matrix<T, Rows, Cols> >
4706 bool operator() (const Matrix<T, Rows, Cols>& mat1,
4707 const Matrix<T, Rows, Cols>& mat2) const
4709 for (int col = 0; col < Cols; ++col)
4711 if (inputLess(mat1[col], mat2[col]))
4713 if (inputLess(mat2[col], mat1[col]))
4721 template <typename In>
4723 public Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4725 InTuple (const typename In::In0& in0,
4726 const typename In::In1& in1,
4727 const typename In::In2& in2,
4728 const typename In::In3& in3)
4729 : Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4730 (in0, in1, in2, in3) {}
4733 template <typename In>
4734 struct InputLess<InTuple<In> >
4736 bool operator() (const InTuple<In>& in1, const InTuple<In>& in2) const
4738 if (inputLess(in1.a, in2.a))
4740 if (inputLess(in2.a, in1.a))
4742 if (inputLess(in1.b, in2.b))
4744 if (inputLess(in2.b, in1.b))
4746 if (inputLess(in1.c, in2.c))
4748 if (inputLess(in2.c, in1.c))
4750 if (inputLess(in1.d, in2.d))
4756 template<typename In>
4757 Inputs<In> generateInputs (const Samplings<In>& samplings,
4758 const FloatFormat& floatFormat,
4759 Precision intPrecision,
4765 Inputs<In> fixedInputs;
4766 set<InTuple<In>, InputLess<InTuple<In> > > seenInputs;
4768 samplings.in0.genFixeds(floatFormat, fixedInputs.in0);
4769 samplings.in1.genFixeds(floatFormat, fixedInputs.in1);
4770 samplings.in2.genFixeds(floatFormat, fixedInputs.in2);
4771 samplings.in3.genFixeds(floatFormat, fixedInputs.in3);
4773 for (size_t ndx0 = 0; ndx0 < fixedInputs.in0.size(); ++ndx0)
4775 for (size_t ndx1 = 0; ndx1 < fixedInputs.in1.size(); ++ndx1)
4777 for (size_t ndx2 = 0; ndx2 < fixedInputs.in2.size(); ++ndx2)
4779 for (size_t ndx3 = 0; ndx3 < fixedInputs.in3.size(); ++ndx3)
4781 const InTuple<In> tuple (fixedInputs.in0[ndx0],
4782 fixedInputs.in1[ndx1],
4783 fixedInputs.in2[ndx2],
4784 fixedInputs.in3[ndx3]);
4786 seenInputs.insert(tuple);
4787 ret.in0.push_back(tuple.a);
4788 ret.in1.push_back(tuple.b);
4789 ret.in2.push_back(tuple.c);
4790 ret.in3.push_back(tuple.d);
4796 for (size_t ndx = 0; ndx < numSamples; ++ndx)
4798 const typename In::In0 in0 = samplings.in0.genRandom(floatFormat, intPrecision, rnd);
4799 const typename In::In1 in1 = samplings.in1.genRandom(floatFormat, intPrecision, rnd);
4800 const typename In::In2 in2 = samplings.in2.genRandom(floatFormat, intPrecision, rnd);
4801 const typename In::In3 in3 = samplings.in3.genRandom(floatFormat, intPrecision, rnd);
4802 const InTuple<In> tuple (in0, in1, in2, in3);
4804 if (de::contains(seenInputs, tuple))
4807 seenInputs.insert(tuple);
4808 ret.in0.push_back(in0);
4809 ret.in1.push_back(in1);
4810 ret.in2.push_back(in2);
4811 ret.in3.push_back(in3);
4817 class FuncCaseBase : public PrecisionCase
4820 FuncCaseBase (const CaseContext& context, const string& name, const FuncBase& func)
4821 : PrecisionCase (context, name, func.getRequiredExtension())
4828 template <typename Sig>
4829 class FuncCase : public FuncCaseBase
4832 typedef Func<Sig> CaseFunc;
4833 typedef typename Sig::Ret Ret;
4834 typedef typename Sig::Arg0 Arg0;
4835 typedef typename Sig::Arg1 Arg1;
4836 typedef typename Sig::Arg2 Arg2;
4837 typedef typename Sig::Arg3 Arg3;
4838 typedef InTypes<Arg0, Arg1, Arg2, Arg3> In;
4839 typedef OutTypes<Ret> Out;
4841 FuncCase (const CaseContext& context, const string& name, const CaseFunc& func)
4842 : FuncCaseBase (context, name, func)
4848 virtual TestInstance* createInstance (Context& context) const
4850 return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, getSamplings(), m_stmt);
4854 void buildTest (void);
4855 virtual const Samplings<In>& getSamplings (void) const
4857 return instance<DefaultSamplings<In> >();
4861 const CaseFunc& m_func;
4862 Variables<In, Out> m_variables;
4865 template <typename Sig>
4866 void FuncCase<Sig>::buildTest (void)
4868 m_variables.out0 = variable<Ret>("out0");
4869 m_variables.out1 = variable<Void>("out1");
4870 m_variables.in0 = variable<Arg0>("in0");
4871 m_variables.in1 = variable<Arg1>("in1");
4872 m_variables.in2 = variable<Arg2>("in2");
4873 m_variables.in3 = variable<Arg3>("in3");
4876 ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.in1, m_variables.in2, m_variables.in3);
4877 m_stmt = variableAssignment(m_variables.out0, expr);
4879 this->testStatement(m_variables, *m_stmt);
4883 template <typename Sig>
4884 class InOutFuncCase : public FuncCaseBase
4887 typedef Func<Sig> CaseFunc;
4888 typedef typename Sig::Ret Ret;
4889 typedef typename Sig::Arg0 Arg0;
4890 typedef typename Sig::Arg1 Arg1;
4891 typedef typename Sig::Arg2 Arg2;
4892 typedef typename Sig::Arg3 Arg3;
4893 typedef InTypes<Arg0, Arg2, Arg3> In;
4894 typedef OutTypes<Ret, Arg1> Out;
4896 InOutFuncCase (const CaseContext& context, const string& name, const CaseFunc& func)
4897 : FuncCaseBase (context, name, func)
4902 virtual TestInstance* createInstance (Context& context) const
4904 return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, getSamplings(), m_stmt);
4908 void buildTest (void);
4909 virtual const Samplings<In>& getSamplings (void) const
4911 return instance<DefaultSamplings<In> >();
4915 const CaseFunc& m_func;
4916 Variables<In, Out> m_variables;
4919 template <typename Sig>
4920 void InOutFuncCase<Sig>::buildTest (void)
4923 m_variables.out0 = variable<Ret>("out0");
4924 m_variables.out1 = variable<Arg1>("out1");
4925 m_variables.in0 = variable<Arg0>("in0");
4926 m_variables.in1 = variable<Arg2>("in1");
4927 m_variables.in2 = variable<Arg3>("in2");
4928 m_variables.in3 = variable<Void>("in3");
4931 ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.out1, m_variables.in1, m_variables.in2);
4932 m_stmt = variableAssignment(m_variables.out0, expr);
4934 this->testStatement(m_variables, *m_stmt);
4938 template <typename Sig>
4939 PrecisionCase* createFuncCase (const CaseContext& context, const string& name, const Func<Sig>& func)
4941 switch (func.getOutParamIndex())
4944 return new FuncCase<Sig>(context, name, func);
4946 return new InOutFuncCase<Sig>(context, name, func);
4948 DE_FATAL("Impossible");
4956 virtual ~CaseFactory (void) {}
4957 virtual MovePtr<TestNode> createCase (const CaseContext& ctx) const = 0;
4958 virtual string getName (void) const = 0;
4959 virtual string getDesc (void) const = 0;
4962 class FuncCaseFactory : public CaseFactory
4965 virtual const FuncBase& getFunc (void) const = 0;
4966 string getName (void) const { return de::toLower(getFunc().getName()); }
4967 string getDesc (void) const { return "Function '" + getFunc().getName() + "'"; }
4970 template <typename Sig>
4971 class GenFuncCaseFactory : public CaseFactory
4974 GenFuncCaseFactory (const GenFuncs<Sig>& funcs, const string& name)
4976 , m_name (de::toLower(name))
4980 MovePtr<TestNode> createCase (const CaseContext& ctx) const
4982 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
4984 group->addChild(createFuncCase(ctx, "scalar", m_funcs.func));
4985 group->addChild(createFuncCase(ctx, "vec2", m_funcs.func2));
4986 group->addChild(createFuncCase(ctx, "vec3", m_funcs.func3));
4987 group->addChild(createFuncCase(ctx, "vec4", m_funcs.func4));
4988 return MovePtr<TestNode>(group);
4991 string getName (void) const { return m_name; }
4992 string getDesc (void) const { return "Function '" + m_funcs.func.getName() + "'"; }
4995 const GenFuncs<Sig> m_funcs;
4999 template <template <int> class GenF>
5000 class TemplateFuncCaseFactory : public FuncCaseFactory
5003 MovePtr<TestNode> createCase (const CaseContext& ctx) const
5005 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5007 group->addChild(createFuncCase(ctx, "scalar", instance<GenF<1> >()));
5008 group->addChild(createFuncCase(ctx, "vec2", instance<GenF<2> >()));
5009 group->addChild(createFuncCase(ctx, "vec3", instance<GenF<3> >()));
5010 group->addChild(createFuncCase(ctx, "vec4", instance<GenF<4> >()));
5012 return MovePtr<TestNode>(group);
5015 const FuncBase& getFunc (void) const { return instance<GenF<1> >(); }
5018 template <template <int> class GenF>
5019 class SquareMatrixFuncCaseFactory : public FuncCaseFactory
5022 MovePtr<TestNode> createCase (const CaseContext& ctx) const
5024 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5026 group->addChild(createFuncCase(ctx, "mat2", instance<GenF<2> >()));
5028 // disabled until we get reasonable results
5029 group->addChild(createFuncCase(ctx, "mat3", instance<GenF<3> >()));
5030 group->addChild(createFuncCase(ctx, "mat4", instance<GenF<4> >()));
5033 return MovePtr<TestNode>(group);
5036 const FuncBase& getFunc (void) const { return instance<GenF<2> >(); }
5039 template <template <int, int> class GenF>
5040 class MatrixFuncCaseFactory : public FuncCaseFactory
5043 MovePtr<TestNode> createCase (const CaseContext& ctx) const
5045 TestCaseGroup* const group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5047 this->addCase<2, 2>(ctx, group);
5048 this->addCase<3, 2>(ctx, group);
5049 this->addCase<4, 2>(ctx, group);
5050 this->addCase<2, 3>(ctx, group);
5051 this->addCase<3, 3>(ctx, group);
5052 this->addCase<4, 3>(ctx, group);
5053 this->addCase<2, 4>(ctx, group);
5054 this->addCase<3, 4>(ctx, group);
5055 this->addCase<4, 4>(ctx, group);
5057 return MovePtr<TestNode>(group);
5060 const FuncBase& getFunc (void) const { return instance<GenF<2,2> >(); }
5063 template <int Rows, int Cols>
5064 void addCase (const CaseContext& ctx, TestCaseGroup* group) const
5066 const char* const name = dataTypeNameOf<Matrix<float, Rows, Cols> >();
5067 group->addChild(createFuncCase(ctx, name, instance<GenF<Rows, Cols> >()));
5071 template <typename Sig>
5072 class SimpleFuncCaseFactory : public CaseFactory
5075 SimpleFuncCaseFactory (const Func<Sig>& func) : m_func(func) {}
5077 MovePtr<TestNode> createCase (const CaseContext& ctx) const { return MovePtr<TestNode>(createFuncCase(ctx, ctx.name.c_str(), m_func)); }
5078 string getName (void) const { return de::toLower(m_func.getName()); }
5079 string getDesc (void) const { return "Function '" + getName() + "'"; }
5082 const Func<Sig>& m_func;
5085 template <typename F>
5086 SharedPtr<SimpleFuncCaseFactory<typename F::Sig> > createSimpleFuncCaseFactory (void)
5088 return SharedPtr<SimpleFuncCaseFactory<typename F::Sig> >(new SimpleFuncCaseFactory<typename F::Sig>(instance<F>()));
5094 virtual ~CaseFactories (void) {}
5095 virtual const std::vector<const CaseFactory*> getFactories (void) const = 0;
5098 class BuiltinFuncs : public CaseFactories
5101 const vector<const CaseFactory*> getFactories (void) const
5103 vector<const CaseFactory*> ret;
5105 for (size_t ndx = 0; ndx < m_factories.size(); ++ndx)
5106 ret.push_back(m_factories[ndx].get());
5111 void addFactory (SharedPtr<const CaseFactory> fact) { m_factories.push_back(fact); }
5114 vector<SharedPtr<const CaseFactory> > m_factories;
5117 template <typename F>
5118 void addScalarFactory(BuiltinFuncs& funcs, string name = "")
5121 name = instance<F>().getName();
5123 funcs.addFactory(SharedPtr<const CaseFactory>(new GenFuncCaseFactory<typename F::Sig>(makeVectorizedFuncs<F>(), name)));
5126 MovePtr<const CaseFactories> createComputeOnlyBuiltinCases (void)
5128 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5130 // Tests for ES3 builtins
5132 addScalarFactory<Add>(*funcs);
5133 addScalarFactory<Sub>(*funcs);
5134 addScalarFactory<Mul>(*funcs);
5135 addScalarFactory<Div>(*funcs);
5137 addScalarFactory<Radians>(*funcs);
5138 addScalarFactory<Degrees>(*funcs);
5139 addScalarFactory<Sin>(*funcs);
5140 addScalarFactory<Cos>(*funcs);
5141 addScalarFactory<Tan>(*funcs);
5142 addScalarFactory<ASin>(*funcs);
5143 addScalarFactory<ACos>(*funcs);
5144 addScalarFactory<ATan2>(*funcs, "atan2");
5145 addScalarFactory<ATan>(*funcs);
5146 addScalarFactory<Sinh>(*funcs);
5147 addScalarFactory<Cosh>(*funcs);
5148 addScalarFactory<Tanh>(*funcs);
5149 addScalarFactory<ASinh>(*funcs);
5150 addScalarFactory<ACosh>(*funcs);
5151 addScalarFactory<ATanh>(*funcs);
5153 addScalarFactory<Pow>(*funcs);
5154 addScalarFactory<Exp>(*funcs);
5155 addScalarFactory<Log>(*funcs);
5156 addScalarFactory<Exp2>(*funcs);
5157 addScalarFactory<Log2>(*funcs);
5158 addScalarFactory<Sqrt>(*funcs);
5159 addScalarFactory<InverseSqrt>(*funcs);
5161 addScalarFactory<Abs>(*funcs);
5162 addScalarFactory<Sign>(*funcs);
5163 addScalarFactory<Floor>(*funcs);
5164 addScalarFactory<Trunc>(*funcs);
5165 addScalarFactory<Round>(*funcs);
5166 addScalarFactory<RoundEven>(*funcs);
5167 addScalarFactory<Ceil>(*funcs);
5168 addScalarFactory<Fract>(*funcs);
5169 addScalarFactory<Mod>(*funcs);
5170 funcs->addFactory(createSimpleFuncCaseFactory<Modf>());
5171 addScalarFactory<Min>(*funcs);
5172 addScalarFactory<Max>(*funcs);
5173 addScalarFactory<Clamp>(*funcs);
5174 addScalarFactory<Mix>(*funcs);
5175 addScalarFactory<Step>(*funcs);
5176 addScalarFactory<SmoothStep>(*funcs);
5178 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length>()));
5179 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance>()));
5180 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot>()));
5181 funcs->addFactory(createSimpleFuncCaseFactory<Cross>());
5182 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize>()));
5183 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward>()));
5184 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect>()));
5185 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract>()));
5188 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<MatrixCompMult>()));
5189 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct>()));
5190 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose>()));
5191 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant>()));
5192 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse>()));
5194 return MovePtr<const CaseFactories>(funcs.release());
5197 MovePtr<const CaseFactories> createCompleteBuiltinCases (void)
5199 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5201 // Tests for ES31 builtins
5202 addScalarFactory<FrExp>(*funcs);
5203 addScalarFactory<LdExp>(*funcs);
5204 addScalarFactory<Fma>(*funcs);
5206 return MovePtr<const CaseFactories>(funcs.release());
5209 struct PrecisionTestContext
5211 PrecisionTestContext (TestContext& testCtx_,
5212 const FloatFormat& highp_,
5213 const FloatFormat& mediump_,
5214 const FloatFormat& lowp_,
5215 const vector<ShaderType>& shaderTypes_,
5217 : testCtx (testCtx_)
5218 , shaderTypes (shaderTypes_)
5219 , numRandoms (numRandoms_)
5221 formats[glu::PRECISION_HIGHP] = &highp_;
5222 formats[glu::PRECISION_MEDIUMP] = &mediump_;
5223 formats[glu::PRECISION_LOWP] = &lowp_;
5226 TestContext& testCtx;
5227 const FloatFormat* formats[glu::PRECISION_LAST];
5228 vector<ShaderType> shaderTypes;
5232 TestCaseGroup* createFuncGroup (const PrecisionTestContext& ctx, const CaseFactory& factory)
5234 TestCaseGroup* const group = new TestCaseGroup(ctx.testCtx, factory.getName().c_str(), factory.getDesc().c_str());
5236 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; ++precNdx)
5238 const Precision precision = Precision(precNdx);
5239 const string precName (glu::getPrecisionName(precision));
5240 const FloatFormat& fmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats, precNdx);
5241 const FloatFormat& highpFmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats,
5242 glu::PRECISION_HIGHP);
5244 for (size_t shaderNdx = 0; shaderNdx < ctx.shaderTypes.size(); ++shaderNdx)
5246 const ShaderType shaderType = ctx.shaderTypes[shaderNdx];
5247 const string shaderName (glu::getShaderTypeName(shaderType));
5248 const string name = precName + "_" + shaderName;
5249 const CaseContext caseCtx (name, ctx.testCtx, fmt, highpFmt,
5250 precision, shaderType, ctx.numRandoms);
5252 group->addChild(factory.createCase(caseCtx).release());
5259 void addBuiltinPrecisionTests (TestContext& testCtx,
5260 const CaseFactories& cases,
5261 const vector<ShaderType>& shaderTypes,
5262 TestCaseGroup& dstGroup)
5264 const int userRandoms = testCtx.getCommandLine().getTestIterationCount();
5265 const int defRandoms = 16384;
5266 const int numRandoms = userRandoms > 0 ? userRandoms : defRandoms;
5267 const FloatFormat highp (-126, 127, 23, true,
5268 tcu::MAYBE, // subnormals
5269 tcu::YES, // infinities
5271 // \todo [2014-04-01 lauri] Check these once Khronos bug 11840 is resolved.
5272 const FloatFormat mediump (-13, 13, 9, false);
5273 // A fixed-point format is just a floating point format with a fixed
5274 // exponent and support for subnormals.
5275 const FloatFormat lowp (0, 0, 7, false, tcu::YES);
5276 const PrecisionTestContext ctx (testCtx, highp, mediump, lowp,
5277 shaderTypes, numRandoms);
5279 for (size_t ndx = 0; ndx < cases.getFactories().size(); ++ndx)
5280 dstGroup.addChild(createFuncGroup(ctx, *cases.getFactories()[ndx]));
5283 BuiltinPrecisionTests::BuiltinPrecisionTests (tcu::TestContext& testCtx)
5284 : tcu::TestCaseGroup(testCtx, "precision", "Builtin precision tests")
5288 BuiltinPrecisionTests::~BuiltinPrecisionTests (void)
5292 void BuiltinPrecisionTests::init (void)
5294 std::vector<glu::ShaderType> shaderTypes;
5295 de::MovePtr<const CaseFactories> computeOnlyCases = createComputeOnlyBuiltinCases();
5296 de::MovePtr<const CaseFactories> completeCases = createCompleteBuiltinCases();
5298 shaderTypes.push_back(glu::SHADERTYPE_COMPUTE);
5300 addBuiltinPrecisionTests(m_testCtx,
5305 shaderTypes.clear();
5306 shaderTypes.push_back(glu::SHADERTYPE_VERTEX);
5307 shaderTypes.push_back(glu::SHADERTYPE_FRAGMENT);
5308 shaderTypes.push_back(glu::SHADERTYPE_COMPUTE);
5310 addBuiltinPrecisionTests(m_testCtx,