1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7 * Copyright (c) 2016 The Android Open Source Project
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and/or associated documentation files (the
11 * "Materials"), to deal in the Materials without restriction, including
12 * without limitation the rights to use, copy, modify, merge, publish,
13 * distribute, sublicense, and/or sell copies of the Materials, and to
14 * permit persons to whom the Materials are furnished to do so, subject to
15 * the following conditions:
17 * The above copyright notice(s) and this permission notice shall be included
18 * in all copies or substantial portions of the Materials.
20 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
30 * \brief Precision and range tests for builtins and types.
32 *//*--------------------------------------------------------------------*/
34 #include "vktShaderBuiltinPrecisionTests.hpp"
35 #include "vktShaderExecutor.hpp"
40 #include "deRandom.hpp"
41 #include "deSTLUtil.hpp"
42 #include "deStringUtil.hpp"
43 #include "deUniquePtr.hpp"
44 #include "deSharedPtr.hpp"
45 #include "deArrayUtil.hpp"
47 #include "tcuCommandLine.hpp"
48 #include "tcuFloatFormat.hpp"
49 #include "tcuInterval.hpp"
50 #include "tcuTestLog.hpp"
51 #include "tcuVector.hpp"
52 #include "tcuMatrix.hpp"
53 #include "tcuResultCollector.hpp"
55 #include "gluContextInfo.hpp"
56 #include "gluVarType.hpp"
57 #include "gluRenderContext.hpp"
58 #include "glwDefs.hpp"
67 // Uncomment this to get evaluation trace dumps to std::cerr
68 // #define GLS_ENABLE_TRACE
70 // set this to true to dump even passing results
71 #define GLS_LOG_ALL_RESULTS false
75 namespace shaderexecutor
81 using std::ostringstream;
91 using tcu::FloatFormat;
92 using tcu::MessageBuilder;
99 using glu::ShaderType;
101 /*--------------------------------------------------------------------*//*!
102 * \brief Generic singleton creator.
104 * instance<T>() returns a reference to a unique default-constructed instance
105 * of T. This is mainly used for our GLSL function implementations: each
106 * function is implemented by an object, and each of the objects has a
107 * distinct class. It would be extremely toilsome to maintain a separate
108 * context object that contained individual instances of the function classes,
109 * so we have to resort to global singleton instances.
111 *//*--------------------------------------------------------------------*/
112 template <typename T>
113 const T& instance (void)
115 static const T s_instance = T();
119 /*--------------------------------------------------------------------*//*!
120 * \brief Dummy placeholder type for unused template parameters.
122 * In the precision tests we are dealing with functions of different arities.
123 * To minimize code duplication, we only define templates with the maximum
124 * number of arguments, currently four. If a function's arity is less than the
125 * maximum, Void us used as the type for unused arguments.
127 * Although Voids are not used at run-time, they still must be compilable, so
128 * they must support all operations that other types do.
130 *//*--------------------------------------------------------------------*/
133 typedef Void Element;
139 template <typename T>
140 explicit Void (const T&) {}
142 operator double (void) const { return TCU_NAN; }
144 // These are used to make Voids usable as containers in container-generic code.
145 Void& operator[] (int) { return *this; }
146 const Void& operator[] (int) const { return *this; }
149 ostream& operator<< (ostream& os, Void) { return os << "()"; }
151 //! Returns true for all other types except Void
152 template <typename T> bool isTypeValid (void) { return true; }
153 template <> bool isTypeValid<Void> (void) { return false; }
155 //! Utility function for getting the name of a data type.
156 //! This is used in vector and matrix constructors.
157 template <typename T>
158 const char* dataTypeNameOf (void)
160 return glu::getDataTypeName(glu::dataTypeOf<T>());
164 const char* dataTypeNameOf<Void> (void)
166 DE_FATAL("Impossible");
170 //! A hack to get Void support for VarType.
171 template <typename T>
172 VarType getVarTypeOf (Precision prec = glu::PRECISION_LAST)
174 return glu::varTypeOf<T>(prec);
178 VarType getVarTypeOf<Void> (Precision)
180 DE_FATAL("Impossible");
184 /*--------------------------------------------------------------------*//*!
185 * \brief Type traits for generalized interval types.
187 * We are trying to compute sets of acceptable values not only for
188 * float-valued expressions but also for compound values: vectors and
189 * matrices. We approximate a set of vectors as a vector of intervals and
190 * likewise for matrices.
192 * We now need generalized operations for each type and its interval
193 * approximation. These are given in the type Traits<T>.
195 * The type Traits<T>::IVal is the approximation of T: it is `Interval` for
196 * scalar types, and a vector or matrix of intervals for container types.
198 * To allow template inference to take place, there are function wrappers for
199 * the actual operations in Traits<T>. Hence we can just use:
201 * makeIVal(someFloat)
205 * Traits<float>::doMakeIVal(value)
207 *//*--------------------------------------------------------------------*/
209 template <typename T> struct Traits;
211 //! Create container from elementwise singleton values.
212 template <typename T>
213 typename Traits<T>::IVal makeIVal (const T& value)
215 return Traits<T>::doMakeIVal(value);
218 //! Elementwise union of intervals.
219 template <typename T>
220 typename Traits<T>::IVal unionIVal (const typename Traits<T>::IVal& a,
221 const typename Traits<T>::IVal& b)
223 return Traits<T>::doUnion(a, b);
226 //! Returns true iff every element of `ival` contains the corresponding element of `value`.
227 template <typename T>
228 bool contains (const typename Traits<T>::IVal& ival, const T& value)
230 return Traits<T>::doContains(ival, value);
233 //! Print out an interval with the precision of `fmt`.
234 template <typename T>
235 void printIVal (const FloatFormat& fmt, const typename Traits<T>::IVal& ival, ostream& os)
237 Traits<T>::doPrintIVal(fmt, ival, os);
240 template <typename T>
241 string intervalToString (const FloatFormat& fmt, const typename Traits<T>::IVal& ival)
244 printIVal<T>(fmt, ival, oss);
248 //! Print out a value with the precision of `fmt`.
249 template <typename T>
250 void printValue (const FloatFormat& fmt, const T& value, ostream& os)
252 Traits<T>::doPrintValue(fmt, value, os);
255 template <typename T>
256 string valueToString (const FloatFormat& fmt, const T& val)
259 printValue(fmt, val, oss);
263 //! Approximate `value` elementwise to the float precision defined in `fmt`.
264 //! The resulting interval might not be a singleton if rounding in both
265 //! directions is allowed.
266 template <typename T>
267 typename Traits<T>::IVal round (const FloatFormat& fmt, const T& value)
269 return Traits<T>::doRound(fmt, value);
272 template <typename T>
273 typename Traits<T>::IVal convert (const FloatFormat& fmt,
274 const typename Traits<T>::IVal& value)
276 return Traits<T>::doConvert(fmt, value);
279 //! Common traits for scalar types.
280 template <typename T>
283 typedef Interval IVal;
285 static Interval doMakeIVal (const T& value)
287 // Thankfully all scalar types have a well-defined conversion to `double`,
288 // hence Interval can represent their ranges without problems.
289 return Interval(double(value));
292 static Interval doUnion (const Interval& a, const Interval& b)
297 static bool doContains (const Interval& a, T value)
299 return a.contains(double(value));
302 static Interval doConvert (const FloatFormat& fmt, const IVal& ival)
304 return fmt.convert(ival);
307 static Interval doRound (const FloatFormat& fmt, T value)
309 return fmt.roundOut(double(value), false);
314 struct Traits<float> : ScalarTraits<float>
316 static void doPrintIVal (const FloatFormat& fmt,
317 const Interval& ival,
320 os << fmt.intervalToHex(ival);
323 static void doPrintValue (const FloatFormat& fmt,
327 os << fmt.floatToHex(value);
332 struct Traits<bool> : ScalarTraits<bool>
334 static void doPrintValue (const FloatFormat&,
338 os << (value != 0.0f ? "true" : "false");
341 static void doPrintIVal (const FloatFormat&,
342 const Interval& ival,
346 if (ival.contains(false))
348 if (ival.contains(false) && ival.contains(true))
350 if (ival.contains(true))
357 struct Traits<int> : ScalarTraits<int>
359 static void doPrintValue (const FloatFormat&,
366 static void doPrintIVal (const FloatFormat&,
367 const Interval& ival,
370 os << "[" << int(ival.lo()) << ", " << int(ival.hi()) << "]";
374 //! Common traits for containers, i.e. vectors and matrices.
375 //! T is the container type itself, I is the same type with interval elements.
376 template <typename T, typename I>
377 struct ContainerTraits
379 typedef typename T::Element Element;
382 static IVal doMakeIVal (const T& value)
386 for (int ndx = 0; ndx < T::SIZE; ++ndx)
387 ret[ndx] = makeIVal(value[ndx]);
392 static IVal doUnion (const IVal& a, const IVal& b)
396 for (int ndx = 0; ndx < T::SIZE; ++ndx)
397 ret[ndx] = unionIVal<Element>(a[ndx], b[ndx]);
402 static bool doContains (const IVal& ival, const T& value)
404 for (int ndx = 0; ndx < T::SIZE; ++ndx)
405 if (!contains(ival[ndx], value[ndx]))
411 static void doPrintIVal (const FloatFormat& fmt, const IVal ival, ostream& os)
415 for (int ndx = 0; ndx < T::SIZE; ++ndx)
420 printIVal<Element>(fmt, ival[ndx], os);
426 static void doPrintValue (const FloatFormat& fmt, const T& value, ostream& os)
428 os << dataTypeNameOf<T>() << "(";
430 for (int ndx = 0; ndx < T::SIZE; ++ndx)
435 printValue<Element>(fmt, value[ndx], os);
441 static IVal doConvert (const FloatFormat& fmt, const IVal& value)
445 for (int ndx = 0; ndx < T::SIZE; ++ndx)
446 ret[ndx] = convert<Element>(fmt, value[ndx]);
451 static IVal doRound (const FloatFormat& fmt, T value)
455 for (int ndx = 0; ndx < T::SIZE; ++ndx)
456 ret[ndx] = round(fmt, value[ndx]);
462 template <typename T, int Size>
463 struct Traits<Vector<T, Size> > :
464 ContainerTraits<Vector<T, Size>, Vector<typename Traits<T>::IVal, Size> >
468 template <typename T, int Rows, int Cols>
469 struct Traits<Matrix<T, Rows, Cols> > :
470 ContainerTraits<Matrix<T, Rows, Cols>, Matrix<typename Traits<T>::IVal, Rows, Cols> >
474 //! Void traits. These are just dummies, but technically valid: a Void is a
475 //! unit type with a single possible value.
481 static Void doMakeIVal (const Void& value) { return value; }
482 static Void doUnion (const Void&, const Void&) { return Void(); }
483 static bool doContains (const Void&, Void) { return true; }
484 static Void doRound (const FloatFormat&, const Void& value) { return value; }
485 static Void doConvert (const FloatFormat&, const Void& value) { return value; }
487 static void doPrintValue (const FloatFormat&, const Void&, ostream& os)
492 static void doPrintIVal (const FloatFormat&, const Void&, ostream& os)
498 //! This is needed for container-generic operations.
499 //! We want a scalar type T to be its own "one-element vector".
500 template <typename T, int Size> struct ContainerOf { typedef Vector<T, Size> Container; };
502 template <typename T> struct ContainerOf<T, 1> { typedef T Container; };
503 template <int Size> struct ContainerOf<Void, Size> { typedef Void Container; };
505 // This is a kludge that is only needed to get the ExprP::operator[] syntactic sugar to work.
506 template <typename T> struct ElementOf { typedef typename T::Element Element; };
507 template <> struct ElementOf<float> { typedef void Element; };
508 template <> struct ElementOf<bool> { typedef void Element; };
509 template <> struct ElementOf<int> { typedef void Element; };
511 /*--------------------------------------------------------------------*//*!
513 * \name Abstract syntax for expressions and statements.
515 * We represent GLSL programs as syntax objects: an Expr<T> represents an
516 * expression whose GLSL type corresponds to the C++ type T, and a Statement
517 * represents a statement.
519 * To ease memory management, we use shared pointers to refer to expressions
520 * and statements. ExprP<T> is a shared pointer to an Expr<T>, and StatementP
521 * is a shared pointer to a Statement.
525 *//*--------------------------------------------------------------------*/
532 template <typename T> class ExprP;
533 template <typename T> class Variable;
534 template <typename T> class VariableP;
535 template <typename T> class DefaultSampling;
537 typedef set<const FuncBase*> FuncSet;
539 template <typename T>
540 VariableP<T> variable (const string& name);
541 StatementP compoundStatement (const vector<StatementP>& statements);
543 /*--------------------------------------------------------------------*//*!
544 * \brief A variable environment.
546 * An Environment object maintains the mapping between variables of the
547 * abstract syntax tree and their values.
549 * \todo [2014-03-28 lauri] At least run-time type safety.
551 *//*--------------------------------------------------------------------*/
556 void bind (const Variable<T>& variable,
557 const typename Traits<T>::IVal& value)
559 deUint8* const data = new deUint8[sizeof(value)];
561 deMemcpy(data, &value, sizeof(value));
562 de::insert(m_map, variable.getName(), SharedPtr<deUint8>(data, de::ArrayDeleter<deUint8>()));
566 typename Traits<T>::IVal& lookup (const Variable<T>& variable) const
568 deUint8* const data = de::lookup(m_map, variable.getName()).get();
570 return *reinterpret_cast<typename Traits<T>::IVal*>(data);
574 map<string, SharedPtr<deUint8> > m_map;
577 /*--------------------------------------------------------------------*//*!
578 * \brief Evaluation context.
580 * The evaluation context contains everything that separates one execution of
581 * an expression from the next. Currently this means the desired floating
582 * point precision and the current variable environment.
584 *//*--------------------------------------------------------------------*/
587 EvalContext (const FloatFormat& format_,
588 Precision floatPrecision_,
592 , floatPrecision (floatPrecision_)
594 , callDepth (callDepth_) {}
597 Precision floatPrecision;
602 /*--------------------------------------------------------------------*//*!
603 * \brief Simple incremental counter.
605 * This is used to make sure that different ExpandContexts will not produce
606 * overlapping temporary names.
608 *//*--------------------------------------------------------------------*/
612 Counter (int count = 0) : m_count(count) {}
613 int operator() (void) { return m_count++; }
622 ExpandContext (Counter& symCounter) : m_symCounter(symCounter) {}
623 ExpandContext (const ExpandContext& parent)
624 : m_symCounter(parent.m_symCounter) {}
627 VariableP<T> genSym (const string& baseName)
629 return variable<T>(baseName + de::toString(m_symCounter()));
632 void addStatement (const StatementP& stmt)
634 m_statements.push_back(stmt);
637 vector<StatementP> getStatements (void) const
642 Counter& m_symCounter;
643 vector<StatementP> m_statements;
646 /*--------------------------------------------------------------------*//*!
647 * \brief A statement or declaration.
649 * Statements have no values. Instead, they are executed for their side
650 * effects only: the execute() method should modify at least one variable in
653 * As a bit of a kludge, a Statement object can also represent a declaration:
654 * when it is evaluated, it can add a variable binding to the environment
655 * instead of modifying a current one.
657 *//*--------------------------------------------------------------------*/
661 virtual ~Statement (void) { }
662 //! Execute the statement, modifying the environment of `ctx`
663 void execute (EvalContext& ctx) const { this->doExecute(ctx); }
664 void print (ostream& os) const { this->doPrint(os); }
665 //! Add the functions used in this statement to `dst`.
666 void getUsedFuncs (FuncSet& dst) const { this->doGetUsedFuncs(dst); }
669 virtual void doPrint (ostream& os) const = 0;
670 virtual void doExecute (EvalContext& ctx) const = 0;
671 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
674 ostream& operator<<(ostream& os, const Statement& stmt)
680 /*--------------------------------------------------------------------*//*!
681 * \brief Smart pointer for statements (and declarations)
683 *//*--------------------------------------------------------------------*/
684 class StatementP : public SharedPtr<const Statement>
687 typedef SharedPtr<const Statement> Super;
690 explicit StatementP (const Statement* ptr) : Super(ptr) {}
691 StatementP (const Super& ptr) : Super(ptr) {}
694 /*--------------------------------------------------------------------*//*!
697 * A statement that modifies a variable or a declaration that binds a variable.
699 *//*--------------------------------------------------------------------*/
700 template <typename T>
701 class VariableStatement : public Statement
704 VariableStatement (const VariableP<T>& variable, const ExprP<T>& value,
706 : m_variable (variable)
708 , m_isDeclaration (isDeclaration) {}
711 void doPrint (ostream& os) const
714 os << glu::declare(getVarTypeOf<T>(), m_variable->getName());
716 os << m_variable->getName();
718 os << " = " << *m_value << ";\n";
721 void doExecute (EvalContext& ctx) const
724 ctx.env.bind(*m_variable, m_value->evaluate(ctx));
726 ctx.env.lookup(*m_variable) = m_value->evaluate(ctx);
729 void doGetUsedFuncs (FuncSet& dst) const
731 m_value->getUsedFuncs(dst);
734 VariableP<T> m_variable;
736 bool m_isDeclaration;
739 template <typename T>
740 StatementP variableStatement (const VariableP<T>& variable,
741 const ExprP<T>& value,
744 return StatementP(new VariableStatement<T>(variable, value, isDeclaration));
747 template <typename T>
748 StatementP variableDeclaration (const VariableP<T>& variable, const ExprP<T>& definiens)
750 return variableStatement(variable, definiens, true);
753 template <typename T>
754 StatementP variableAssignment (const VariableP<T>& variable, const ExprP<T>& value)
756 return variableStatement(variable, value, false);
759 /*--------------------------------------------------------------------*//*!
760 * \brief A compound statement, i.e. a block.
762 * A compound statement is executed by executing its constituent statements in
765 *//*--------------------------------------------------------------------*/
766 class CompoundStatement : public Statement
769 CompoundStatement (const vector<StatementP>& statements)
770 : m_statements (statements) {}
773 void doPrint (ostream& os) const
777 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
778 os << *m_statements[ndx];
783 void doExecute (EvalContext& ctx) const
785 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
786 m_statements[ndx]->execute(ctx);
789 void doGetUsedFuncs (FuncSet& dst) const
791 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
792 m_statements[ndx]->getUsedFuncs(dst);
795 vector<StatementP> m_statements;
798 StatementP compoundStatement(const vector<StatementP>& statements)
800 return StatementP(new CompoundStatement(statements));
803 //! Common base class for all expressions regardless of their type.
807 virtual ~ExprBase (void) {}
808 void printExpr (ostream& os) const { this->doPrintExpr(os); }
810 //! Output the functions that this expression refers to
811 void getUsedFuncs (FuncSet& dst) const
813 this->doGetUsedFuncs(dst);
817 virtual void doPrintExpr (ostream&) const {}
818 virtual void doGetUsedFuncs (FuncSet&) const {}
821 //! Type-specific operations for an expression representing type T.
822 template <typename T>
823 class Expr : public ExprBase
827 typedef typename Traits<T>::IVal IVal;
829 IVal evaluate (const EvalContext& ctx) const;
832 virtual IVal doEvaluate (const EvalContext& ctx) const = 0;
835 //! Evaluate an expression with the given context, optionally tracing the calls to stderr.
836 template <typename T>
837 typename Traits<T>::IVal Expr<T>::evaluate (const EvalContext& ctx) const
839 #ifdef GLS_ENABLE_TRACE
840 static const FloatFormat highpFmt (-126, 127, 23, true,
844 EvalContext newCtx (ctx.format, ctx.floatPrecision,
845 ctx.env, ctx.callDepth + 1);
846 const IVal ret = this->doEvaluate(newCtx);
848 if (isTypeValid<T>())
850 std::cerr << string(ctx.callDepth, ' ');
851 this->printExpr(std::cerr);
852 std::cerr << " -> " << intervalToString<T>(highpFmt, ret) << std::endl;
856 return this->doEvaluate(ctx);
860 template <typename T>
861 class ExprPBase : public SharedPtr<const Expr<T> >
866 ostream& operator<< (ostream& os, const ExprBase& expr)
872 /*--------------------------------------------------------------------*//*!
873 * \brief Shared pointer to an expression of a container type.
875 * Container types (i.e. vectors and matrices) support the subscription
876 * operator. This class provides a bit of syntactic sugar to allow us to use
877 * the C++ subscription operator to create a subscription expression.
878 *//*--------------------------------------------------------------------*/
879 template <typename T>
880 class ContainerExprPBase : public ExprPBase<T>
883 ExprP<typename T::Element> operator[] (int i) const;
886 template <typename T>
887 class ExprP : public ExprPBase<T> {};
889 // We treat Voids as containers since the dummy parameters in generalized
890 // vector functions are represented as Voids.
892 class ExprP<Void> : public ContainerExprPBase<Void> {};
894 template <typename T, int Size>
895 class ExprP<Vector<T, Size> > : public ContainerExprPBase<Vector<T, Size> > {};
897 template <typename T, int Rows, int Cols>
898 class ExprP<Matrix<T, Rows, Cols> > : public ContainerExprPBase<Matrix<T, Rows, Cols> > {};
900 template <typename T> ExprP<T> exprP (void)
905 template <typename T>
906 ExprP<T> exprP (const SharedPtr<const Expr<T> >& ptr)
909 static_cast<SharedPtr<const Expr<T> >&>(ret) = ptr;
913 template <typename T>
914 ExprP<T> exprP (const Expr<T>* ptr)
916 return exprP(SharedPtr<const Expr<T> >(ptr));
919 /*--------------------------------------------------------------------*//*!
920 * \brief A shared pointer to a variable expression.
922 * This is just a narrowing of ExprP for the operations that require a variable
923 * instead of an arbitrary expression.
925 *//*--------------------------------------------------------------------*/
926 template <typename T>
927 class VariableP : public SharedPtr<const Variable<T> >
930 typedef SharedPtr<const Variable<T> > Super;
931 explicit VariableP (const Variable<T>* ptr) : Super(ptr) {}
933 VariableP (const Super& ptr) : Super(ptr) {}
935 operator ExprP<T> (void) const { return exprP(SharedPtr<const Expr<T> >(*this)); }
938 /*--------------------------------------------------------------------*//*!
939 * \name Syntactic sugar operators for expressions.
943 * These operators allow the use of C++ syntax to construct GLSL expressions
944 * containing operators: e.g. "a+b" creates an addition expression with
945 * operands a and b, and so on.
947 *//*--------------------------------------------------------------------*/
948 ExprP<float> operator-(const ExprP<float>& arg0);
949 ExprP<float> operator+(const ExprP<float>& arg0,
950 const ExprP<float>& arg1);
951 ExprP<float> operator-(const ExprP<float>& arg0,
952 const ExprP<float>& arg1);
953 ExprP<float> operator*(const ExprP<float>& arg0,
954 const ExprP<float>& arg1);
955 ExprP<float> operator/(const ExprP<float>& arg0,
956 const ExprP<float>& arg1);
958 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0);
960 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
961 const ExprP<float>& arg1);
963 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
964 const ExprP<Vector<float, Size> >& arg1);
966 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
967 const ExprP<Vector<float, Size> >& arg1);
968 template<int Left, int Mid, int Right>
969 ExprP<Matrix<float, Left, Right> > operator* (const ExprP<Matrix<float, Left, Mid> >& left,
970 const ExprP<Matrix<float, Mid, Right> >& right);
971 template<int Rows, int Cols>
972 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
973 const ExprP<Matrix<float, Rows, Cols> >& right);
974 template<int Rows, int Cols>
975 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
976 const ExprP<Vector<float, Rows> >& right);
977 template<int Rows, int Cols>
978 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
979 const ExprP<float>& right);
980 template<int Rows, int Cols>
981 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
982 const ExprP<Matrix<float, Rows, Cols> >& right);
983 template<int Rows, int Cols>
984 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat);
988 /*--------------------------------------------------------------------*//*!
989 * \brief Variable expression.
991 * A variable is evaluated by looking up its range of possible values from an
993 *//*--------------------------------------------------------------------*/
994 template <typename T>
995 class Variable : public Expr<T>
998 typedef typename Expr<T>::IVal IVal;
1000 Variable (const string& name) : m_name (name) {}
1001 string getName (void) const { return m_name; }
1004 void doPrintExpr (ostream& os) const { os << m_name; }
1005 IVal doEvaluate (const EvalContext& ctx) const
1007 return ctx.env.lookup<T>(*this);
1014 template <typename T>
1015 VariableP<T> variable (const string& name)
1017 return VariableP<T>(new Variable<T>(name));
1020 template <typename T>
1021 VariableP<T> bindExpression (const string& name, ExpandContext& ctx, const ExprP<T>& expr)
1023 VariableP<T> var = ctx.genSym<T>(name);
1024 ctx.addStatement(variableDeclaration(var, expr));
1028 /*--------------------------------------------------------------------*//*!
1029 * \brief Constant expression.
1031 * A constant is evaluated by rounding it to a set of possible values allowed
1032 * by the current floating point precision.
1033 *//*--------------------------------------------------------------------*/
1034 template <typename T>
1035 class Constant : public Expr<T>
1038 typedef typename Expr<T>::IVal IVal;
1040 Constant (const T& value) : m_value(value) {}
1043 void doPrintExpr (ostream& os) const { os << m_value; }
1044 IVal doEvaluate (const EvalContext&) const { return makeIVal(m_value); }
1050 template <typename T>
1051 ExprP<T> constant (const T& value)
1053 return exprP(new Constant<T>(value));
1056 //! Return a reference to a singleton void constant.
1057 const ExprP<Void>& voidP (void)
1059 static const ExprP<Void> singleton = constant(Void());
1064 /*--------------------------------------------------------------------*//*!
1065 * \brief Four-element tuple.
1067 * This is used for various things where we need one thing for each possible
1068 * function parameter. Currently the maximum supported number of parameters is
1070 *//*--------------------------------------------------------------------*/
1071 template <typename T0 = Void, typename T1 = Void, typename T2 = Void, typename T3 = Void>
1074 explicit Tuple4 (const T0& e0 = T0(),
1075 const T1& e1 = T1(),
1076 const T2& e2 = T2(),
1077 const T3& e3 = T3())
1091 /*--------------------------------------------------------------------*//*!
1092 * \brief Function signature.
1094 * This is a purely compile-time structure used to bundle all types in a
1095 * function signature together. This makes passing the signature around in
1096 * templates easier, since we only need to take and pass a single Sig instead
1097 * of a bunch of parameter types and a return type.
1099 *//*--------------------------------------------------------------------*/
1100 template <typename R,
1101 typename P0 = Void, typename P1 = Void,
1102 typename P2 = Void, typename P3 = Void>
1110 typedef typename Traits<Ret>::IVal IRet;
1111 typedef typename Traits<Arg0>::IVal IArg0;
1112 typedef typename Traits<Arg1>::IVal IArg1;
1113 typedef typename Traits<Arg2>::IVal IArg2;
1114 typedef typename Traits<Arg3>::IVal IArg3;
1116 typedef Tuple4< const Arg0&, const Arg1&, const Arg2&, const Arg3&> Args;
1117 typedef Tuple4< const IArg0&, const IArg1&, const IArg2&, const IArg3&> IArgs;
1118 typedef Tuple4< ExprP<Arg0>, ExprP<Arg1>, ExprP<Arg2>, ExprP<Arg3> > ArgExprs;
1121 typedef vector<const ExprBase*> BaseArgExprs;
1123 /*--------------------------------------------------------------------*//*!
1124 * \brief Type-independent operations for function objects.
1126 *//*--------------------------------------------------------------------*/
1130 virtual ~FuncBase (void) {}
1131 virtual string getName (void) const = 0;
1132 //! Name of extension that this function requires, or empty.
1133 virtual string getRequiredExtension (void) const { return ""; }
1134 virtual void print (ostream&,
1135 const BaseArgExprs&) const = 0;
1136 //! Index of output parameter, or -1 if none of the parameters is output.
1137 virtual int getOutParamIndex (void) const { return -1; }
1139 void printDefinition (ostream& os) const
1141 doPrintDefinition(os);
1144 void getUsedFuncs (FuncSet& dst) const
1146 this->doGetUsedFuncs(dst);
1150 virtual void doPrintDefinition (ostream& os) const = 0;
1151 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
1154 typedef Tuple4<string, string, string, string> ParamNames;
1156 /*--------------------------------------------------------------------*//*!
1157 * \brief Function objects.
1159 * Each Func object represents a GLSL function. It can be applied to interval
1160 * arguments, and it returns the an interval that is a conservative
1161 * approximation of the image of the GLSL function over the argument
1162 * intervals. That is, it is given a set of possible arguments and it returns
1163 * the set of possible values.
1165 *//*--------------------------------------------------------------------*/
1166 template <typename Sig_>
1167 class Func : public FuncBase
1171 typedef typename Sig::Ret Ret;
1172 typedef typename Sig::Arg0 Arg0;
1173 typedef typename Sig::Arg1 Arg1;
1174 typedef typename Sig::Arg2 Arg2;
1175 typedef typename Sig::Arg3 Arg3;
1176 typedef typename Sig::IRet IRet;
1177 typedef typename Sig::IArg0 IArg0;
1178 typedef typename Sig::IArg1 IArg1;
1179 typedef typename Sig::IArg2 IArg2;
1180 typedef typename Sig::IArg3 IArg3;
1181 typedef typename Sig::Args Args;
1182 typedef typename Sig::IArgs IArgs;
1183 typedef typename Sig::ArgExprs ArgExprs;
1185 void print (ostream& os,
1186 const BaseArgExprs& args) const
1188 this->doPrint(os, args);
1191 IRet apply (const EvalContext& ctx,
1192 const IArg0& arg0 = IArg0(),
1193 const IArg1& arg1 = IArg1(),
1194 const IArg2& arg2 = IArg2(),
1195 const IArg3& arg3 = IArg3()) const
1197 return this->applyArgs(ctx, IArgs(arg0, arg1, arg2, arg3));
1199 IRet applyArgs (const EvalContext& ctx,
1200 const IArgs& args) const
1202 return this->doApply(ctx, args);
1204 ExprP<Ret> operator() (const ExprP<Arg0>& arg0 = voidP(),
1205 const ExprP<Arg1>& arg1 = voidP(),
1206 const ExprP<Arg2>& arg2 = voidP(),
1207 const ExprP<Arg3>& arg3 = voidP()) const;
1209 const ParamNames& getParamNames (void) const
1211 return this->doGetParamNames();
1215 virtual IRet doApply (const EvalContext&,
1216 const IArgs&) const = 0;
1217 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1219 os << getName() << "(";
1221 if (isTypeValid<Arg0>())
1224 if (isTypeValid<Arg1>())
1225 os << ", " << *args[1];
1227 if (isTypeValid<Arg2>())
1228 os << ", " << *args[2];
1230 if (isTypeValid<Arg3>())
1231 os << ", " << *args[3];
1236 virtual const ParamNames& doGetParamNames (void) const
1238 static ParamNames names ("a", "b", "c", "d");
1243 template <typename Sig>
1244 class Apply : public Expr<typename Sig::Ret>
1247 typedef typename Sig::Ret Ret;
1248 typedef typename Sig::Arg0 Arg0;
1249 typedef typename Sig::Arg1 Arg1;
1250 typedef typename Sig::Arg2 Arg2;
1251 typedef typename Sig::Arg3 Arg3;
1252 typedef typename Expr<Ret>::Val Val;
1253 typedef typename Expr<Ret>::IVal IVal;
1254 typedef Func<Sig> ApplyFunc;
1255 typedef typename ApplyFunc::ArgExprs ArgExprs;
1257 Apply (const ApplyFunc& func,
1258 const ExprP<Arg0>& arg0 = voidP(),
1259 const ExprP<Arg1>& arg1 = voidP(),
1260 const ExprP<Arg2>& arg2 = voidP(),
1261 const ExprP<Arg3>& arg3 = voidP())
1263 m_args (arg0, arg1, arg2, arg3) {}
1265 Apply (const ApplyFunc& func,
1266 const ArgExprs& args)
1270 void doPrintExpr (ostream& os) const
1273 args.push_back(m_args.a.get());
1274 args.push_back(m_args.b.get());
1275 args.push_back(m_args.c.get());
1276 args.push_back(m_args.d.get());
1277 m_func.print(os, args);
1280 IVal doEvaluate (const EvalContext& ctx) const
1282 return m_func.apply(ctx,
1283 m_args.a->evaluate(ctx), m_args.b->evaluate(ctx),
1284 m_args.c->evaluate(ctx), m_args.d->evaluate(ctx));
1287 void doGetUsedFuncs (FuncSet& dst) const
1289 m_func.getUsedFuncs(dst);
1290 m_args.a->getUsedFuncs(dst);
1291 m_args.b->getUsedFuncs(dst);
1292 m_args.c->getUsedFuncs(dst);
1293 m_args.d->getUsedFuncs(dst);
1296 const ApplyFunc& m_func;
1300 template<typename T>
1301 class Alternatives : public Func<Signature<T, T, T> >
1304 typedef typename Alternatives::Sig Sig;
1307 typedef typename Alternatives::IRet IRet;
1308 typedef typename Alternatives::IArgs IArgs;
1310 virtual string getName (void) const { return "alternatives"; }
1311 virtual void doPrintDefinition (std::ostream&) const {}
1312 void doGetUsedFuncs (FuncSet&) const {}
1314 virtual IRet doApply (const EvalContext&, const IArgs& args) const
1316 return unionIVal<T>(args.a, args.b);
1319 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1321 os << "{" << *args[0] << " | " << *args[1] << "}";
1325 template <typename Sig>
1326 ExprP<typename Sig::Ret> createApply (const Func<Sig>& func,
1327 const typename Func<Sig>::ArgExprs& args)
1329 return exprP(new Apply<Sig>(func, args));
1332 template <typename Sig>
1333 ExprP<typename Sig::Ret> createApply (
1334 const Func<Sig>& func,
1335 const ExprP<typename Sig::Arg0>& arg0 = voidP(),
1336 const ExprP<typename Sig::Arg1>& arg1 = voidP(),
1337 const ExprP<typename Sig::Arg2>& arg2 = voidP(),
1338 const ExprP<typename Sig::Arg3>& arg3 = voidP())
1340 return exprP(new Apply<Sig>(func, arg0, arg1, arg2, arg3));
1343 template <typename Sig>
1344 ExprP<typename Sig::Ret> Func<Sig>::operator() (const ExprP<typename Sig::Arg0>& arg0,
1345 const ExprP<typename Sig::Arg1>& arg1,
1346 const ExprP<typename Sig::Arg2>& arg2,
1347 const ExprP<typename Sig::Arg3>& arg3) const
1349 return createApply(*this, arg0, arg1, arg2, arg3);
1352 template <typename F>
1353 ExprP<typename F::Ret> app (const ExprP<typename F::Arg0>& arg0 = voidP(),
1354 const ExprP<typename F::Arg1>& arg1 = voidP(),
1355 const ExprP<typename F::Arg2>& arg2 = voidP(),
1356 const ExprP<typename F::Arg3>& arg3 = voidP())
1358 return createApply(instance<F>(), arg0, arg1, arg2, arg3);
1361 template <typename F>
1362 typename F::IRet call (const EvalContext& ctx,
1363 const typename F::IArg0& arg0 = Void(),
1364 const typename F::IArg1& arg1 = Void(),
1365 const typename F::IArg2& arg2 = Void(),
1366 const typename F::IArg3& arg3 = Void())
1368 return instance<F>().apply(ctx, arg0, arg1, arg2, arg3);
1371 template <typename T>
1372 ExprP<T> alternatives (const ExprP<T>& arg0,
1373 const ExprP<T>& arg1)
1375 return createApply<typename Alternatives<T>::Sig>(instance<Alternatives<T> >(), arg0, arg1);
1378 template <typename Sig>
1379 class ApplyVar : public Apply<Sig>
1382 typedef typename Sig::Ret Ret;
1383 typedef typename Sig::Arg0 Arg0;
1384 typedef typename Sig::Arg1 Arg1;
1385 typedef typename Sig::Arg2 Arg2;
1386 typedef typename Sig::Arg3 Arg3;
1387 typedef typename Expr<Ret>::Val Val;
1388 typedef typename Expr<Ret>::IVal IVal;
1389 typedef Func<Sig> ApplyFunc;
1390 typedef typename ApplyFunc::ArgExprs ArgExprs;
1392 ApplyVar (const ApplyFunc& func,
1393 const VariableP<Arg0>& arg0,
1394 const VariableP<Arg1>& arg1,
1395 const VariableP<Arg2>& arg2,
1396 const VariableP<Arg3>& arg3)
1397 : Apply<Sig> (func, arg0, arg1, arg2, arg3) {}
1399 IVal doEvaluate (const EvalContext& ctx) const
1401 const Variable<Arg0>& var0 = static_cast<const Variable<Arg0>&>(*this->m_args.a);
1402 const Variable<Arg1>& var1 = static_cast<const Variable<Arg1>&>(*this->m_args.b);
1403 const Variable<Arg2>& var2 = static_cast<const Variable<Arg2>&>(*this->m_args.c);
1404 const Variable<Arg3>& var3 = static_cast<const Variable<Arg3>&>(*this->m_args.d);
1405 return this->m_func.apply(ctx,
1406 ctx.env.lookup(var0), ctx.env.lookup(var1),
1407 ctx.env.lookup(var2), ctx.env.lookup(var3));
1411 template <typename Sig>
1412 ExprP<typename Sig::Ret> applyVar (const Func<Sig>& func,
1413 const VariableP<typename Sig::Arg0>& arg0,
1414 const VariableP<typename Sig::Arg1>& arg1,
1415 const VariableP<typename Sig::Arg2>& arg2,
1416 const VariableP<typename Sig::Arg3>& arg3)
1418 return exprP(new ApplyVar<Sig>(func, arg0, arg1, arg2, arg3));
1421 template <typename Sig_>
1422 class DerivedFunc : public Func<Sig_>
1425 typedef typename DerivedFunc::ArgExprs ArgExprs;
1426 typedef typename DerivedFunc::IRet IRet;
1427 typedef typename DerivedFunc::IArgs IArgs;
1428 typedef typename DerivedFunc::Ret Ret;
1429 typedef typename DerivedFunc::Arg0 Arg0;
1430 typedef typename DerivedFunc::Arg1 Arg1;
1431 typedef typename DerivedFunc::Arg2 Arg2;
1432 typedef typename DerivedFunc::Arg3 Arg3;
1433 typedef typename DerivedFunc::IArg0 IArg0;
1434 typedef typename DerivedFunc::IArg1 IArg1;
1435 typedef typename DerivedFunc::IArg2 IArg2;
1436 typedef typename DerivedFunc::IArg3 IArg3;
1439 void doPrintDefinition (ostream& os) const
1441 const ParamNames& paramNames = this->getParamNames();
1445 os << dataTypeNameOf<Ret>() << " " << this->getName()
1447 if (isTypeValid<Arg0>())
1448 os << dataTypeNameOf<Arg0>() << " " << paramNames.a;
1449 if (isTypeValid<Arg1>())
1450 os << ", " << dataTypeNameOf<Arg1>() << " " << paramNames.b;
1451 if (isTypeValid<Arg2>())
1452 os << ", " << dataTypeNameOf<Arg2>() << " " << paramNames.c;
1453 if (isTypeValid<Arg3>())
1454 os << ", " << dataTypeNameOf<Arg3>() << " " << paramNames.d;
1457 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1459 os << "return " << *m_ret << ";\n";
1463 IRet doApply (const EvalContext& ctx,
1464 const IArgs& args) const
1467 IArgs& mutArgs = const_cast<IArgs&>(args);
1472 funEnv.bind(*m_var0, args.a);
1473 funEnv.bind(*m_var1, args.b);
1474 funEnv.bind(*m_var2, args.c);
1475 funEnv.bind(*m_var3, args.d);
1478 EvalContext funCtx(ctx.format, ctx.floatPrecision, funEnv, ctx.callDepth);
1480 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1481 m_body[ndx]->execute(funCtx);
1483 ret = m_ret->evaluate(funCtx);
1486 // \todo [lauri] Store references instead of values in environment
1487 const_cast<IArg0&>(mutArgs.a) = funEnv.lookup(*m_var0);
1488 const_cast<IArg1&>(mutArgs.b) = funEnv.lookup(*m_var1);
1489 const_cast<IArg2&>(mutArgs.c) = funEnv.lookup(*m_var2);
1490 const_cast<IArg3&>(mutArgs.d) = funEnv.lookup(*m_var3);
1495 void doGetUsedFuncs (FuncSet& dst) const
1498 if (dst.insert(this).second)
1500 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1501 m_body[ndx]->getUsedFuncs(dst);
1502 m_ret->getUsedFuncs(dst);
1506 virtual ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args_) const = 0;
1508 // These are transparently initialized when first needed. They cannot be
1509 // initialized in the constructor because they depend on the doExpand
1510 // method of the subclass.
1512 mutable VariableP<Arg0> m_var0;
1513 mutable VariableP<Arg1> m_var1;
1514 mutable VariableP<Arg2> m_var2;
1515 mutable VariableP<Arg3> m_var3;
1516 mutable vector<StatementP> m_body;
1517 mutable ExprP<Ret> m_ret;
1521 void initialize (void) const
1525 const ParamNames& paramNames = this->getParamNames();
1527 ExpandContext ctx (symCounter);
1530 args.a = m_var0 = variable<Arg0>(paramNames.a);
1531 args.b = m_var1 = variable<Arg1>(paramNames.b);
1532 args.c = m_var2 = variable<Arg2>(paramNames.c);
1533 args.d = m_var3 = variable<Arg3>(paramNames.d);
1535 m_ret = this->doExpand(ctx, args);
1536 m_body = ctx.getStatements();
1541 template <typename Sig>
1542 class PrimitiveFunc : public Func<Sig>
1545 typedef typename PrimitiveFunc::Ret Ret;
1546 typedef typename PrimitiveFunc::ArgExprs ArgExprs;
1549 void doPrintDefinition (ostream&) const {}
1550 void doGetUsedFuncs (FuncSet&) const {}
1553 template <typename T>
1554 class Cond : public PrimitiveFunc<Signature<T, bool, T, T> >
1557 typedef typename Cond::IArgs IArgs;
1558 typedef typename Cond::IRet IRet;
1560 string getName (void) const
1567 void doPrint (ostream& os, const BaseArgExprs& args) const
1569 os << "(" << *args[0] << " ? " << *args[1] << " : " << *args[2] << ")";
1572 IRet doApply (const EvalContext&, const IArgs& iargs)const
1576 if (iargs.a.contains(true))
1577 ret = unionIVal<T>(ret, iargs.b);
1579 if (iargs.a.contains(false))
1580 ret = unionIVal<T>(ret, iargs.c);
1586 template <typename T>
1587 class CompareOperator : public PrimitiveFunc<Signature<bool, T, T> >
1590 typedef typename CompareOperator::IArgs IArgs;
1591 typedef typename CompareOperator::IArg0 IArg0;
1592 typedef typename CompareOperator::IArg1 IArg1;
1593 typedef typename CompareOperator::IRet IRet;
1596 void doPrint (ostream& os, const BaseArgExprs& args) const
1598 os << "(" << *args[0] << getSymbol() << *args[1] << ")";
1601 Interval doApply (const EvalContext&, const IArgs& iargs) const
1603 const IArg0& arg0 = iargs.a;
1604 const IArg1& arg1 = iargs.b;
1607 if (canSucceed(arg0, arg1))
1609 if (canFail(arg0, arg1))
1615 virtual string getSymbol (void) const = 0;
1616 virtual bool canSucceed (const IArg0&, const IArg1&) const = 0;
1617 virtual bool canFail (const IArg0&, const IArg1&) const = 0;
1620 template <typename T>
1621 class LessThan : public CompareOperator<T>
1624 string getName (void) const { return "lessThan"; }
1627 string getSymbol (void) const { return "<"; }
1629 bool canSucceed (const Interval& a, const Interval& b) const
1631 return (a.lo() < b.hi());
1634 bool canFail (const Interval& a, const Interval& b) const
1636 return !(a.hi() < b.lo());
1640 template <typename T>
1641 ExprP<bool> operator< (const ExprP<T>& a, const ExprP<T>& b)
1643 return app<LessThan<T> >(a, b);
1646 template <typename T>
1647 ExprP<T> cond (const ExprP<bool>& test,
1648 const ExprP<T>& consequent,
1649 const ExprP<T>& alternative)
1651 return app<Cond<T> >(test, consequent, alternative);
1654 /*--------------------------------------------------------------------*//*!
1658 *//*--------------------------------------------------------------------*/
1660 class FloatFunc1 : public PrimitiveFunc<Signature<float, float> >
1663 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1665 return this->applyMonotone(ctx, iargs.a);
1668 Interval applyMonotone (const EvalContext& ctx, const Interval& iarg0) const
1672 TCU_INTERVAL_APPLY_MONOTONE1(ret, arg0, iarg0, val,
1673 TCU_SET_INTERVAL(val, point,
1674 point = this->applyPoint(ctx, arg0)));
1676 ret |= innerExtrema(ctx, iarg0);
1677 ret &= (this->getCodomain() | TCU_NAN);
1679 return ctx.format.convert(ret);
1682 virtual Interval innerExtrema (const EvalContext&, const Interval&) const
1684 return Interval(); // empty interval, i.e. no extrema
1687 virtual Interval applyPoint (const EvalContext& ctx, double arg0) const
1689 const double exact = this->applyExact(arg0);
1690 const double prec = this->precision(ctx, exact, arg0);
1692 return exact + Interval(-prec, prec);
1695 virtual double applyExact (double) const
1697 TCU_THROW(InternalError, "Cannot apply");
1700 virtual Interval getCodomain (void) const
1702 return Interval::unbounded(true);
1705 virtual double precision (const EvalContext& ctx, double, double) const = 0;
1708 class CFloatFunc1 : public FloatFunc1
1711 CFloatFunc1 (const string& name, tcu::DoubleFunc1& func)
1712 : m_name(name), m_func(func) {}
1714 string getName (void) const { return m_name; }
1717 double applyExact (double x) const { return m_func(x); }
1719 const string m_name;
1720 tcu::DoubleFunc1& m_func;
1723 class FloatFunc2 : public PrimitiveFunc<Signature<float, float, float> >
1726 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1728 return this->applyMonotone(ctx, iargs.a, iargs.b);
1731 Interval applyMonotone (const EvalContext& ctx,
1733 const Interval& yi) const
1737 TCU_INTERVAL_APPLY_MONOTONE2(reti, x, xi, y, yi, ret,
1738 TCU_SET_INTERVAL(ret, point,
1739 point = this->applyPoint(ctx, x, y)));
1740 reti |= innerExtrema(ctx, xi, yi);
1741 reti &= (this->getCodomain() | TCU_NAN);
1743 return ctx.format.convert(reti);
1746 virtual Interval innerExtrema (const EvalContext&,
1748 const Interval&) const
1750 return Interval(); // empty interval, i.e. no extrema
1753 virtual Interval applyPoint (const EvalContext& ctx,
1757 const double exact = this->applyExact(x, y);
1758 const double prec = this->precision(ctx, exact, x, y);
1760 return exact + Interval(-prec, prec);
1763 virtual double applyExact (double, double) const
1765 TCU_THROW(InternalError, "Cannot apply");
1768 virtual Interval getCodomain (void) const
1770 return Interval::unbounded(true);
1773 virtual double precision (const EvalContext& ctx,
1776 double y) const = 0;
1779 class CFloatFunc2 : public FloatFunc2
1782 CFloatFunc2 (const string& name,
1783 tcu::DoubleFunc2& func)
1789 string getName (void) const { return m_name; }
1792 double applyExact (double x, double y) const { return m_func(x, y); }
1794 const string m_name;
1795 tcu::DoubleFunc2& m_func;
1798 class InfixOperator : public FloatFunc2
1801 virtual string getSymbol (void) const = 0;
1803 void doPrint (ostream& os, const BaseArgExprs& args) const
1805 os << "(" << *args[0] << " " << getSymbol() << " " << *args[1] << ")";
1808 Interval applyPoint (const EvalContext& ctx,
1812 const double exact = this->applyExact(x, y);
1814 // Allow either representable number on both sides of the exact value,
1815 // but require exactly representable values to be preserved.
1816 return ctx.format.roundOut(exact, !deIsInf(x) && !deIsInf(y));
1819 double precision (const EvalContext&, double, double, double) const
1825 class FloatFunc3 : public PrimitiveFunc<Signature<float, float, float, float> >
1828 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1830 return this->applyMonotone(ctx, iargs.a, iargs.b, iargs.c);
1833 Interval applyMonotone (const EvalContext& ctx,
1836 const Interval& zi) const
1839 TCU_INTERVAL_APPLY_MONOTONE3(reti, x, xi, y, yi, z, zi, ret,
1840 TCU_SET_INTERVAL(ret, point,
1841 point = this->applyPoint(ctx, x, y, z)));
1842 return ctx.format.convert(reti);
1845 virtual Interval applyPoint (const EvalContext& ctx,
1850 const double exact = this->applyExact(x, y, z);
1851 const double prec = this->precision(ctx, exact, x, y, z);
1852 return exact + Interval(-prec, prec);
1855 virtual double applyExact (double, double, double) const
1857 TCU_THROW(InternalError, "Cannot apply");
1860 virtual double precision (const EvalContext& ctx,
1864 double z) const = 0;
1867 // We define syntactic sugar functions for expression constructors. Since
1868 // these have the same names as ordinary mathematical operations (sin, log
1869 // etc.), it's better to give them a dedicated namespace.
1873 using namespace tcu;
1875 class Add : public InfixOperator
1878 string getName (void) const { return "add"; }
1879 string getSymbol (void) const { return "+"; }
1881 Interval doApply (const EvalContext& ctx,
1882 const IArgs& iargs) const
1884 // Fast-path for common case
1885 if (iargs.a.isOrdinary() && iargs.b.isOrdinary())
1888 TCU_SET_INTERVAL_BOUNDS(ret, sum,
1889 sum = iargs.a.lo() + iargs.b.lo(),
1890 sum = iargs.a.hi() + iargs.b.hi());
1891 return ctx.format.convert(ctx.format.roundOut(ret, true));
1893 return this->applyMonotone(ctx, iargs.a, iargs.b);
1897 double applyExact (double x, double y) const { return x + y; }
1900 class Mul : public InfixOperator
1903 string getName (void) const { return "mul"; }
1904 string getSymbol (void) const { return "*"; }
1906 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1908 Interval a = iargs.a;
1909 Interval b = iargs.b;
1911 // Fast-path for common case
1912 if (a.isOrdinary() && b.isOrdinary())
1920 if (a.lo() >= 0 && b.lo() >= 0)
1922 TCU_SET_INTERVAL_BOUNDS(ret, prod,
1923 prod = iargs.a.lo() * iargs.b.lo(),
1924 prod = iargs.a.hi() * iargs.b.hi());
1925 return ctx.format.convert(ctx.format.roundOut(ret, true));
1927 if (a.lo() >= 0 && b.hi() <= 0)
1929 TCU_SET_INTERVAL_BOUNDS(ret, prod,
1930 prod = iargs.a.hi() * iargs.b.lo(),
1931 prod = iargs.a.lo() * iargs.b.hi());
1932 return ctx.format.convert(ctx.format.roundOut(ret, true));
1935 return this->applyMonotone(ctx, iargs.a, iargs.b);
1939 double applyExact (double x, double y) const { return x * y; }
1941 Interval innerExtrema(const EvalContext&, const Interval& xi, const Interval& yi) const
1943 if (((xi.contains(-TCU_INFINITY) || xi.contains(TCU_INFINITY)) && yi.contains(0.0)) ||
1944 ((yi.contains(-TCU_INFINITY) || yi.contains(TCU_INFINITY)) && xi.contains(0.0)))
1945 return Interval(TCU_NAN);
1951 class Sub : public InfixOperator
1954 string getName (void) const { return "sub"; }
1955 string getSymbol (void) const { return "-"; }
1957 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1959 // Fast-path for common case
1960 if (iargs.a.isOrdinary() && iargs.b.isOrdinary())
1964 TCU_SET_INTERVAL_BOUNDS(ret, diff,
1965 diff = iargs.a.lo() - iargs.b.hi(),
1966 diff = iargs.a.hi() - iargs.b.lo());
1967 return ctx.format.convert(ctx.format.roundOut(ret, true));
1972 return this->applyMonotone(ctx, iargs.a, iargs.b);
1977 double applyExact (double x, double y) const { return x - y; }
1980 class Negate : public FloatFunc1
1983 string getName (void) const { return "_negate"; }
1984 void doPrint (ostream& os, const BaseArgExprs& args) const { os << "-" << *args[0]; }
1987 double precision (const EvalContext&, double, double) const { return 0.0; }
1988 double applyExact (double x) const { return -x; }
1991 class Div : public InfixOperator
1994 string getName (void) const { return "div"; }
1997 string getSymbol (void) const { return "/"; }
1999 Interval innerExtrema (const EvalContext&,
2000 const Interval& nom,
2001 const Interval& den) const
2005 if (den.contains(0.0))
2007 if (nom.contains(0.0))
2010 if (nom.lo() < 0.0 || nom.hi() > 0.0)
2011 ret |= Interval::unbounded();
2017 double applyExact (double x, double y) const { return x / y; }
2019 Interval applyPoint (const EvalContext& ctx, double x, double y) const
2021 Interval ret = FloatFunc2::applyPoint(ctx, x, y);
2023 if (!deIsInf(x) && !deIsInf(y) && y != 0.0)
2025 const Interval dst = ctx.format.convert(ret);
2026 if (dst.contains(-TCU_INFINITY)) ret |= -ctx.format.getMaxValue();
2027 if (dst.contains(+TCU_INFINITY)) ret |= +ctx.format.getMaxValue();
2033 double precision (const EvalContext& ctx, double ret, double, double den) const
2035 const FloatFormat& fmt = ctx.format;
2037 // \todo [2014-03-05 lauri] Check that the limits in GLSL 3.10 are actually correct.
2038 // For now, we assume that division's precision is 2.5 ULP when the value is within
2039 // [2^MINEXP, 2^MAXEXP-1]
2042 return 0.0; // Result must be exactly inf
2043 else if (de::inBounds(deAbs(den),
2044 deLdExp(1.0, fmt.getMinExp()),
2045 deLdExp(1.0, fmt.getMaxExp() - 1)))
2046 return fmt.ulp(ret, 2.5);
2048 return TCU_INFINITY; // Can be any number, but must be a number.
2052 class InverseSqrt : public FloatFunc1
2055 string getName (void) const { return "inversesqrt"; }
2058 double applyExact (double x) const { return 1.0 / deSqrt(x); }
2060 double precision (const EvalContext& ctx, double ret, double x) const
2062 return x <= 0 ? TCU_NAN : ctx.format.ulp(ret, 2.0);
2065 Interval getCodomain (void) const
2067 return Interval(0.0, TCU_INFINITY);
2071 class ExpFunc : public CFloatFunc1
2074 ExpFunc (const string& name, DoubleFunc1& func)
2075 : CFloatFunc1(name, func) {}
2077 double precision (const EvalContext& ctx, double ret, double x) const
2079 switch (ctx.floatPrecision)
2081 case glu::PRECISION_HIGHP:
2082 return ctx.format.ulp(ret, 3.0 + 2.0 * deAbs(x));
2083 case glu::PRECISION_MEDIUMP:
2084 return ctx.format.ulp(ret, 2.0 + 2.0 * deAbs(x));
2085 case glu::PRECISION_LOWP:
2086 return ctx.format.ulp(ret, 2.0);
2088 DE_FATAL("Impossible");
2093 Interval getCodomain (void) const
2095 return Interval(0.0, TCU_INFINITY);
2099 class Exp2 : public ExpFunc { public: Exp2 (void) : ExpFunc("exp2", deExp2) {} };
2100 class Exp : public ExpFunc { public: Exp (void) : ExpFunc("exp", deExp) {} };
2102 ExprP<float> exp2 (const ExprP<float>& x) { return app<Exp2>(x); }
2103 ExprP<float> exp (const ExprP<float>& x) { return app<Exp>(x); }
2105 class LogFunc : public CFloatFunc1
2108 LogFunc (const string& name, DoubleFunc1& func)
2109 : CFloatFunc1(name, func) {}
2112 double precision (const EvalContext& ctx, double ret, double x) const
2117 switch (ctx.floatPrecision)
2119 case glu::PRECISION_HIGHP:
2120 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -21) : ctx.format.ulp(ret, 3.0);
2121 case glu::PRECISION_MEDIUMP:
2122 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -7) : ctx.format.ulp(ret, 2.0);
2123 case glu::PRECISION_LOWP:
2124 return ctx.format.ulp(ret, 2.0);
2126 DE_FATAL("Impossible");
2133 class Log2 : public LogFunc { public: Log2 (void) : LogFunc("log2", deLog2) {} };
2134 class Log : public LogFunc { public: Log (void) : LogFunc("log", deLog) {} };
2136 ExprP<float> log2 (const ExprP<float>& x) { return app<Log2>(x); }
2137 ExprP<float> log (const ExprP<float>& x) { return app<Log>(x); }
2139 #define DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0) \
2140 ExprP<TRET> NAME (const ExprP<T0>& arg0) { return app<CLASS>(arg0); }
2142 #define DEFINE_DERIVED1(CLASS, TRET, NAME, T0, ARG0, EXPANSION) \
2143 class CLASS : public DerivedFunc<Signature<TRET, T0> > \
2146 string getName (void) const { return #NAME; } \
2149 ExprP<TRET> doExpand (ExpandContext&, \
2150 const CLASS::ArgExprs& args_) const \
2152 const ExprP<float>& ARG0 = args_.a; \
2156 DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0)
2158 #define DEFINE_DERIVED_FLOAT1(CLASS, NAME, ARG0, EXPANSION) \
2159 DEFINE_DERIVED1(CLASS, float, NAME, float, ARG0, EXPANSION)
2161 #define DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1) \
2162 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1) \
2164 return app<CLASS>(arg0, arg1); \
2167 #define DEFINE_DERIVED2(CLASS, TRET, NAME, T0, Arg0, T1, Arg1, EXPANSION) \
2168 class CLASS : public DerivedFunc<Signature<TRET, T0, T1> > \
2171 string getName (void) const { return #NAME; } \
2174 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2176 const ExprP<T0>& Arg0 = args_.a; \
2177 const ExprP<T1>& Arg1 = args_.b; \
2181 DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1)
2183 #define DEFINE_DERIVED_FLOAT2(CLASS, NAME, Arg0, Arg1, EXPANSION) \
2184 DEFINE_DERIVED2(CLASS, float, NAME, float, Arg0, float, Arg1, EXPANSION)
2186 #define DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2) \
2187 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, const ExprP<T2>& arg2) \
2189 return app<CLASS>(arg0, arg1, arg2); \
2192 #define DEFINE_DERIVED3(CLASS, TRET, NAME, T0, ARG0, T1, ARG1, T2, ARG2, EXPANSION) \
2193 class CLASS : public DerivedFunc<Signature<TRET, T0, T1, T2> > \
2196 string getName (void) const { return #NAME; } \
2199 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2201 const ExprP<T0>& ARG0 = args_.a; \
2202 const ExprP<T1>& ARG1 = args_.b; \
2203 const ExprP<T2>& ARG2 = args_.c; \
2207 DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2)
2209 #define DEFINE_DERIVED_FLOAT3(CLASS, NAME, ARG0, ARG1, ARG2, EXPANSION) \
2210 DEFINE_DERIVED3(CLASS, float, NAME, float, ARG0, float, ARG1, float, ARG2, EXPANSION)
2212 #define DEFINE_CONSTRUCTOR4(CLASS, TRET, NAME, T0, T1, T2, T3) \
2213 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, \
2214 const ExprP<T2>& arg2, const ExprP<T3>& arg3) \
2216 return app<CLASS>(arg0, arg1, arg2, arg3); \
2219 DEFINE_DERIVED_FLOAT1(Sqrt, sqrt, x, constant(1.0f) / app<InverseSqrt>(x));
2220 DEFINE_DERIVED_FLOAT2(Pow, pow, x, y, exp2(y * log2(x)));
2221 DEFINE_DERIVED_FLOAT1(Radians, radians, d, (constant(DE_PI) / constant(180.0f)) * d);
2222 DEFINE_DERIVED_FLOAT1(Degrees, degrees, r, (constant(180.0f) / constant(DE_PI)) * r);
2224 class TrigFunc : public CFloatFunc1
2227 TrigFunc (const string& name,
2229 const Interval& loEx,
2230 const Interval& hiEx)
2231 : CFloatFunc1 (name, func)
2232 , m_loExtremum (loEx)
2233 , m_hiExtremum (hiEx) {}
2236 Interval innerExtrema (const EvalContext&, const Interval& angle) const
2238 const double lo = angle.lo();
2239 const double hi = angle.hi();
2240 const int loSlope = doGetSlope(lo);
2241 const int hiSlope = doGetSlope(hi);
2243 // Detect the high and low values the function can take between the
2244 // interval endpoints.
2245 if (angle.length() >= 2.0 * DE_PI_DOUBLE)
2247 // The interval is longer than a full cycle, so it must get all possible values.
2248 return m_hiExtremum | m_loExtremum;
2250 else if (loSlope == 1 && hiSlope == -1)
2252 // The slope can change from positive to negative only at the maximum value.
2253 return m_hiExtremum;
2255 else if (loSlope == -1 && hiSlope == 1)
2257 // The slope can change from negative to positive only at the maximum value.
2258 return m_loExtremum;
2260 else if (loSlope == hiSlope &&
2261 deIntSign(applyExact(hi) - applyExact(lo)) * loSlope == -1)
2263 // The slope has changed twice between the endpoints, so both extrema are included.
2264 return m_hiExtremum | m_loExtremum;
2270 Interval getCodomain (void) const
2272 // Ensure that result is always within [-1, 1], or NaN (for +-inf)
2273 return Interval(-1.0, 1.0) | TCU_NAN;
2276 double precision (const EvalContext& ctx, double ret, double arg) const
2278 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2280 // Use precision from OpenCL fast relaxed math
2281 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2283 return deLdExp(1.0, -11);
2287 // "larger otherwise", let's pick |x| * 2^-12 , which is slightly over
2288 // 2^-11 at x == pi.
2289 return deLdExp(deAbs(arg), -12);
2292 else if (ctx.floatPrecision == glu::PRECISION_MEDIUMP)
2294 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2296 // from OpenCL half-float extension specification
2297 return ctx.format.ulp(ret, 2.0);
2301 // |x| * 2^-10, slightly larger than 2 ULP at x == pi
2302 return deLdExp(deAbs(arg), -10);
2307 DE_ASSERT(ctx.floatPrecision == glu::PRECISION_LOWP);
2309 // from OpenCL half-float extension specification
2310 return ctx.format.ulp(ret, 2.0);
2314 virtual int doGetSlope (double angle) const = 0;
2316 Interval m_loExtremum;
2317 Interval m_hiExtremum;
2320 class Sin : public TrigFunc
2323 Sin (void) : TrigFunc("sin", deSin, -1.0, 1.0) {}
2326 int doGetSlope (double angle) const { return deIntSign(deCos(angle)); }
2329 ExprP<float> sin (const ExprP<float>& x) { return app<Sin>(x); }
2331 class Cos : public TrigFunc
2334 Cos (void) : TrigFunc("cos", deCos, -1.0, 1.0) {}
2337 int doGetSlope (double angle) const { return -deIntSign(deSin(angle)); }
2340 ExprP<float> cos (const ExprP<float>& x) { return app<Cos>(x); }
2342 DEFINE_DERIVED_FLOAT1(Tan, tan, x, sin(x) * (constant(1.0f) / cos(x)));
2344 class ASin : public CFloatFunc1
2347 ASin (void) : CFloatFunc1("asin", deAsin) {}
2350 double precision (const EvalContext& ctx, double, double x) const
2352 if (!de::inBounds(x, -1.0, 1.0))
2355 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2357 // Absolute error of 2^-11
2358 return deLdExp(1.0, -11);
2362 // Absolute error of 2^-8
2363 return deLdExp(1.0, -8);
2369 class ArcTrigFunc : public CFloatFunc1
2372 ArcTrigFunc (const string& name,
2374 double precisionULPs,
2375 const Interval& domain,
2376 const Interval& codomain)
2377 : CFloatFunc1 (name, func)
2378 , m_precision (precisionULPs)
2380 , m_codomain (codomain) {}
2383 double precision (const EvalContext& ctx, double ret, double x) const
2385 if (!m_domain.contains(x))
2388 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2390 // Use OpenCL's fast relaxed math precision
2391 return ctx.format.ulp(ret, m_precision);
2395 // Use OpenCL half-float spec
2396 return ctx.format.ulp(ret, 2.0);
2400 // We could implement getCodomain with m_codomain, but choose not to,
2401 // because it seems too strict with trascendental constants like pi.
2403 const double m_precision;
2404 const Interval m_domain;
2405 const Interval m_codomain;
2408 class ACos : public ArcTrigFunc
2411 ACos (void) : ArcTrigFunc("acos", deAcos, 4096.0,
2412 Interval(-1.0, 1.0),
2413 Interval(0.0, DE_PI_DOUBLE)) {}
2416 class ATan : public ArcTrigFunc
2419 ATan (void) : ArcTrigFunc("atan", deAtanOver, 4096.0,
2420 Interval::unbounded(),
2421 Interval(-DE_PI_DOUBLE * 0.5, DE_PI_DOUBLE * 0.5)) {}
2424 class ATan2 : public CFloatFunc2
2427 ATan2 (void) : CFloatFunc2 ("atan", deAtan2) {}
2430 Interval innerExtrema (const EvalContext& ctx,
2432 const Interval& xi) const
2436 if (yi.contains(0.0))
2438 if (xi.contains(0.0))
2440 if (xi.intersects(Interval(-TCU_INFINITY, 0.0)))
2441 ret |= Interval(-DE_PI_DOUBLE, DE_PI_DOUBLE);
2444 if (ctx.format.hasInf() != YES && (!yi.isFinite() || !xi.isFinite()))
2446 // Infinities may not be supported, allow anything, including NaN
2453 double precision (const EvalContext& ctx, double ret, double, double) const
2455 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2456 return ctx.format.ulp(ret, 4096.0);
2458 return ctx.format.ulp(ret, 2.0);
2461 // Codomain could be [-pi, pi], but that would probably be too strict.
2464 DEFINE_DERIVED_FLOAT1(Sinh, sinh, x, (exp(x) - exp(-x)) / constant(2.0f));
2465 DEFINE_DERIVED_FLOAT1(Cosh, cosh, x, (exp(x) + exp(-x)) / constant(2.0f));
2466 DEFINE_DERIVED_FLOAT1(Tanh, tanh, x, sinh(x) / cosh(x));
2468 // These are not defined as derived forms in the GLSL ES spec, but
2469 // that gives us a reasonable precision.
2470 DEFINE_DERIVED_FLOAT1(ASinh, asinh, x, log(x + sqrt(x * x + constant(1.0f))));
2471 DEFINE_DERIVED_FLOAT1(ACosh, acosh, x, log(x + sqrt(alternatives((x + constant(1.0f)) * (x - constant(1.0f)),
2472 (x*x - constant(1.0f))))));
2473 DEFINE_DERIVED_FLOAT1(ATanh, atanh, x, constant(0.5f) * log((constant(1.0f) + x) /
2474 (constant(1.0f) - x)));
2476 template <typename T>
2477 class GetComponent : public PrimitiveFunc<Signature<typename T::Element, T, int> >
2480 typedef typename GetComponent::IRet IRet;
2482 string getName (void) const { return "_getComponent"; }
2484 void print (ostream& os,
2485 const BaseArgExprs& args) const
2487 os << *args[0] << "[" << *args[1] << "]";
2491 IRet doApply (const EvalContext&,
2492 const typename GetComponent::IArgs& iargs) const
2496 for (int compNdx = 0; compNdx < T::SIZE; ++compNdx)
2498 if (iargs.b.contains(compNdx))
2499 ret = unionIVal<typename T::Element>(ret, iargs.a[compNdx]);
2507 template <typename T>
2508 ExprP<typename T::Element> getComponent (const ExprP<T>& container, int ndx)
2510 DE_ASSERT(0 <= ndx && ndx < T::SIZE);
2511 return app<GetComponent<T> >(container, constant(ndx));
2514 template <typename T> string vecNamePrefix (void);
2515 template <> string vecNamePrefix<float> (void) { return ""; }
2516 template <> string vecNamePrefix<int> (void) { return "i"; }
2517 template <> string vecNamePrefix<bool> (void) { return "b"; }
2519 template <typename T, int Size>
2520 string vecName (void) { return vecNamePrefix<T>() + "vec" + de::toString(Size); }
2522 template <typename T, int Size> class GenVec;
2524 template <typename T>
2525 class GenVec<T, 1> : public DerivedFunc<Signature<T, T> >
2528 typedef typename GenVec<T, 1>::ArgExprs ArgExprs;
2530 string getName (void) const
2532 return "_" + vecName<T, 1>();
2537 ExprP<T> doExpand (ExpandContext&, const ArgExprs& args) const { return args.a; }
2540 template <typename T>
2541 class GenVec<T, 2> : public PrimitiveFunc<Signature<Vector<T, 2>, T, T> >
2544 typedef typename GenVec::IRet IRet;
2545 typedef typename GenVec::IArgs IArgs;
2547 string getName (void) const
2549 return vecName<T, 2>();
2553 IRet doApply (const EvalContext&, const IArgs& iargs) const
2555 return IRet(iargs.a, iargs.b);
2559 template <typename T>
2560 class GenVec<T, 3> : public PrimitiveFunc<Signature<Vector<T, 3>, T, T, T> >
2563 typedef typename GenVec::IRet IRet;
2564 typedef typename GenVec::IArgs IArgs;
2566 string getName (void) const
2568 return vecName<T, 3>();
2572 IRet doApply (const EvalContext&, const IArgs& iargs) const
2574 return IRet(iargs.a, iargs.b, iargs.c);
2578 template <typename T>
2579 class GenVec<T, 4> : public PrimitiveFunc<Signature<Vector<T, 4>, T, T, T, T> >
2582 typedef typename GenVec::IRet IRet;
2583 typedef typename GenVec::IArgs IArgs;
2585 string getName (void) const { return vecName<T, 4>(); }
2588 IRet doApply (const EvalContext&, const IArgs& iargs) const
2590 return IRet(iargs.a, iargs.b, iargs.c, iargs.d);
2596 template <typename T, int Rows, int Columns>
2599 template <typename T, int Rows>
2600 class GenMat<T, Rows, 2> : public PrimitiveFunc<
2601 Signature<Matrix<T, Rows, 2>, Vector<T, Rows>, Vector<T, Rows> > >
2604 typedef typename GenMat::Ret Ret;
2605 typedef typename GenMat::IRet IRet;
2606 typedef typename GenMat::IArgs IArgs;
2608 string getName (void) const
2610 return dataTypeNameOf<Ret>();
2615 IRet doApply (const EvalContext&, const IArgs& iargs) const
2624 template <typename T, int Rows>
2625 class GenMat<T, Rows, 3> : public PrimitiveFunc<
2626 Signature<Matrix<T, Rows, 3>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
2629 typedef typename GenMat::Ret Ret;
2630 typedef typename GenMat::IRet IRet;
2631 typedef typename GenMat::IArgs IArgs;
2633 string getName (void) const
2635 return dataTypeNameOf<Ret>();
2640 IRet doApply (const EvalContext&, const IArgs& iargs) const
2650 template <typename T, int Rows>
2651 class GenMat<T, Rows, 4> : public PrimitiveFunc<
2652 Signature<Matrix<T, Rows, 4>,
2653 Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
2656 typedef typename GenMat::Ret Ret;
2657 typedef typename GenMat::IRet IRet;
2658 typedef typename GenMat::IArgs IArgs;
2660 string getName (void) const
2662 return dataTypeNameOf<Ret>();
2666 IRet doApply (const EvalContext&, const IArgs& iargs) const
2677 template <typename T, int Rows>
2678 ExprP<Matrix<T, Rows, 2> > mat2 (const ExprP<Vector<T, Rows> >& arg0,
2679 const ExprP<Vector<T, Rows> >& arg1)
2681 return app<GenMat<T, Rows, 2> >(arg0, arg1);
2684 template <typename T, int Rows>
2685 ExprP<Matrix<T, Rows, 3> > mat3 (const ExprP<Vector<T, Rows> >& arg0,
2686 const ExprP<Vector<T, Rows> >& arg1,
2687 const ExprP<Vector<T, Rows> >& arg2)
2689 return app<GenMat<T, Rows, 3> >(arg0, arg1, arg2);
2692 template <typename T, int Rows>
2693 ExprP<Matrix<T, Rows, 4> > mat4 (const ExprP<Vector<T, Rows> >& arg0,
2694 const ExprP<Vector<T, Rows> >& arg1,
2695 const ExprP<Vector<T, Rows> >& arg2,
2696 const ExprP<Vector<T, Rows> >& arg3)
2698 return app<GenMat<T, Rows, 4> >(arg0, arg1, arg2, arg3);
2702 template <int Rows, int Cols>
2703 class MatNeg : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
2704 Matrix<float, Rows, Cols> > >
2707 typedef typename MatNeg::IRet IRet;
2708 typedef typename MatNeg::IArgs IArgs;
2710 string getName (void) const
2716 void doPrint (ostream& os, const BaseArgExprs& args) const
2718 os << "-(" << *args[0] << ")";
2721 IRet doApply (const EvalContext&, const IArgs& iargs) const
2725 for (int col = 0; col < Cols; ++col)
2727 for (int row = 0; row < Rows; ++row)
2728 ret[col][row] = -iargs.a[col][row];
2735 template <typename T, typename Sig>
2736 class CompWiseFunc : public PrimitiveFunc<Sig>
2739 typedef Func<Signature<T, T, T> > ScalarFunc;
2741 string getName (void) const
2743 return doGetScalarFunc().getName();
2746 void doPrint (ostream& os,
2747 const BaseArgExprs& args) const
2749 doGetScalarFunc().print(os, args);
2753 const ScalarFunc& doGetScalarFunc (void) const = 0;
2756 template <int Rows, int Cols>
2757 class CompMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
2758 Matrix<float, Rows, Cols>,
2759 Matrix<float, Rows, Cols> > >
2762 typedef typename CompMatFuncBase::IRet IRet;
2763 typedef typename CompMatFuncBase::IArgs IArgs;
2767 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
2771 for (int col = 0; col < Cols; ++col)
2773 for (int row = 0; row < Rows; ++row)
2774 ret[col][row] = this->doGetScalarFunc().apply(ctx,
2783 template <typename F, int Rows, int Cols>
2784 class CompMatFunc : public CompMatFuncBase<Rows, Cols>
2787 const typename CompMatFunc::ScalarFunc& doGetScalarFunc (void) const
2789 return instance<F>();
2793 class ScalarMatrixCompMult : public Mul
2796 string getName (void) const
2798 return "matrixCompMult";
2801 void doPrint (ostream& os, const BaseArgExprs& args) const
2803 Func<Sig>::doPrint(os, args);
2807 template <int Rows, int Cols>
2808 class MatrixCompMult : public CompMatFunc<ScalarMatrixCompMult, Rows, Cols>
2812 template <int Rows, int Cols>
2813 class ScalarMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
2814 Matrix<float, Rows, Cols>,
2818 typedef typename ScalarMatFuncBase::IRet IRet;
2819 typedef typename ScalarMatFuncBase::IArgs IArgs;
2823 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
2827 for (int col = 0; col < Cols; ++col)
2829 for (int row = 0; row < Rows; ++row)
2830 ret[col][row] = this->doGetScalarFunc().apply(ctx, iargs.a[col][row], iargs.b);
2837 template <typename F, int Rows, int Cols>
2838 class ScalarMatFunc : public ScalarMatFuncBase<Rows, Cols>
2841 const typename ScalarMatFunc::ScalarFunc& doGetScalarFunc (void) const
2843 return instance<F>();
2847 template<typename T, int Size> struct GenXType;
2849 template<typename T>
2850 struct GenXType<T, 1>
2852 static ExprP<T> genXType (const ExprP<T>& x) { return x; }
2855 template<typename T>
2856 struct GenXType<T, 2>
2858 static ExprP<Vector<T, 2> > genXType (const ExprP<T>& x)
2860 return app<GenVec<T, 2> >(x, x);
2864 template<typename T>
2865 struct GenXType<T, 3>
2867 static ExprP<Vector<T, 3> > genXType (const ExprP<T>& x)
2869 return app<GenVec<T, 3> >(x, x, x);
2873 template<typename T>
2874 struct GenXType<T, 4>
2876 static ExprP<Vector<T, 4> > genXType (const ExprP<T>& x)
2878 return app<GenVec<T, 4> >(x, x, x, x);
2882 //! Returns an expression of vector of size `Size` (or scalar if Size == 1),
2883 //! with each element initialized with the expression `x`.
2884 template<typename T, int Size>
2885 ExprP<typename ContainerOf<T, Size>::Container> genXType (const ExprP<T>& x)
2887 return GenXType<T, Size>::genXType(x);
2890 typedef GenVec<float, 2> FloatVec2;
2891 DEFINE_CONSTRUCTOR2(FloatVec2, Vec2, vec2, float, float)
2893 typedef GenVec<float, 3> FloatVec3;
2894 DEFINE_CONSTRUCTOR3(FloatVec3, Vec3, vec3, float, float, float)
2896 typedef GenVec<float, 4> FloatVec4;
2897 DEFINE_CONSTRUCTOR4(FloatVec4, Vec4, vec4, float, float, float, float)
2900 class Dot : public DerivedFunc<Signature<float, Vector<float, Size>, Vector<float, Size> > >
2903 typedef typename Dot::ArgExprs ArgExprs;
2905 string getName (void) const
2911 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2913 ExprP<float> val = args.a[0] * args.b[0];
2915 for (int ndx = 1; ndx < Size; ++ndx)
2916 val = val + args.a[ndx] * args.b[ndx];
2923 class Dot<1> : public DerivedFunc<Signature<float, float, float> >
2926 string getName (void) const
2931 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2933 return args.a * args.b;
2938 ExprP<float> dot (const ExprP<Vector<float, Size> >& x, const ExprP<Vector<float, Size> >& y)
2940 return app<Dot<Size> >(x, y);
2943 ExprP<float> dot (const ExprP<float>& x, const ExprP<float>& y)
2945 return app<Dot<1> >(x, y);
2949 class Length : public DerivedFunc<
2950 Signature<float, typename ContainerOf<float, Size>::Container> >
2953 typedef typename Length::ArgExprs ArgExprs;
2955 string getName (void) const
2961 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2963 return sqrt(dot(args.a, args.a));
2968 ExprP<float> length (const ExprP<typename ContainerOf<float, Size>::Container>& x)
2970 return app<Length<Size> >(x);
2974 class Distance : public DerivedFunc<
2976 typename ContainerOf<float, Size>::Container,
2977 typename ContainerOf<float, Size>::Container> >
2980 typedef typename Distance::Ret Ret;
2981 typedef typename Distance::ArgExprs ArgExprs;
2983 string getName (void) const
2989 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
2991 return length<Size>(args.a - args.b);
2997 class Cross : public DerivedFunc<Signature<Vec3, Vec3, Vec3> >
3000 string getName (void) const
3006 ExprP<Vec3> doExpand (ExpandContext&, const ArgExprs& x) const
3008 return vec3(x.a[1] * x.b[2] - x.b[1] * x.a[2],
3009 x.a[2] * x.b[0] - x.b[2] * x.a[0],
3010 x.a[0] * x.b[1] - x.b[0] * x.a[1]);
3014 DEFINE_CONSTRUCTOR2(Cross, Vec3, cross, Vec3, Vec3)
3017 class Normalize : public DerivedFunc<
3018 Signature<typename ContainerOf<float, Size>::Container,
3019 typename ContainerOf<float, Size>::Container> >
3022 typedef typename Normalize::Ret Ret;
3023 typedef typename Normalize::ArgExprs ArgExprs;
3025 string getName (void) const
3031 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3033 return args.a / length<Size>(args.a);
3038 class FaceForward : public DerivedFunc<
3039 Signature<typename ContainerOf<float, Size>::Container,
3040 typename ContainerOf<float, Size>::Container,
3041 typename ContainerOf<float, Size>::Container,
3042 typename ContainerOf<float, Size>::Container> >
3045 typedef typename FaceForward::Ret Ret;
3046 typedef typename FaceForward::ArgExprs ArgExprs;
3048 string getName (void) const
3050 return "faceforward";
3056 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3058 return cond(dot(args.c, args.b) < constant(0.0f), args.a, -args.a);
3063 class Reflect : public DerivedFunc<
3064 Signature<typename ContainerOf<float, Size>::Container,
3065 typename ContainerOf<float, Size>::Container,
3066 typename ContainerOf<float, Size>::Container> >
3069 typedef typename Reflect::Ret Ret;
3070 typedef typename Reflect::Arg0 Arg0;
3071 typedef typename Reflect::Arg1 Arg1;
3072 typedef typename Reflect::ArgExprs ArgExprs;
3074 string getName (void) const
3080 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3082 const ExprP<Arg0>& i = args.a;
3083 const ExprP<Arg1>& n = args.b;
3084 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3086 return i - alternatives((n * dotNI) * constant(2.0f),
3087 n * (dotNI * constant(2.0f)));
3092 class Refract : public DerivedFunc<
3093 Signature<typename ContainerOf<float, Size>::Container,
3094 typename ContainerOf<float, Size>::Container,
3095 typename ContainerOf<float, Size>::Container,
3099 typedef typename Refract::Ret Ret;
3100 typedef typename Refract::Arg0 Arg0;
3101 typedef typename Refract::Arg1 Arg1;
3102 typedef typename Refract::ArgExprs ArgExprs;
3104 string getName (void) const
3110 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3112 const ExprP<Arg0>& i = args.a;
3113 const ExprP<Arg1>& n = args.b;
3114 const ExprP<float>& eta = args.c;
3115 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3116 const ExprP<float> k = bindExpression("k", ctx, constant(1.0f) - eta * eta *
3117 (constant(1.0f) - dotNI * dotNI));
3119 return cond(k < constant(0.0f),
3120 genXType<float, Size>(constant(0.0f)),
3121 i * eta - n * (eta * dotNI + sqrt(k)));
3125 class PreciseFunc1 : public CFloatFunc1
3128 PreciseFunc1 (const string& name, DoubleFunc1& func) : CFloatFunc1(name, func) {}
3130 double precision (const EvalContext&, double, double) const { return 0.0; }
3133 class Abs : public PreciseFunc1
3136 Abs (void) : PreciseFunc1("abs", deAbs) {}
3139 class Sign : public PreciseFunc1
3142 Sign (void) : PreciseFunc1("sign", deSign) {}
3145 class Floor : public PreciseFunc1
3148 Floor (void) : PreciseFunc1("floor", deFloor) {}
3151 class Trunc : public PreciseFunc1
3154 Trunc (void) : PreciseFunc1("trunc", deTrunc) {}
3157 class Round : public FloatFunc1
3160 string getName (void) const { return "round"; }
3163 Interval applyPoint (const EvalContext&, double x) const
3165 double truncated = 0.0;
3166 const double fract = deModf(x, &truncated);
3169 if (fabs(fract) <= 0.5)
3171 if (fabs(fract) >= 0.5)
3172 ret |= truncated + deSign(fract);
3177 double precision (const EvalContext&, double, double) const { return 0.0; }
3180 class RoundEven : public PreciseFunc1
3183 RoundEven (void) : PreciseFunc1("roundEven", deRoundEven) {}
3186 class Ceil : public PreciseFunc1
3189 Ceil (void) : PreciseFunc1("ceil", deCeil) {}
3192 DEFINE_DERIVED_FLOAT1(Fract, fract, x, x - app<Floor>(x));
3194 class PreciseFunc2 : public CFloatFunc2
3197 PreciseFunc2 (const string& name, DoubleFunc2& func) : CFloatFunc2(name, func) {}
3199 double precision (const EvalContext&, double, double, double) const { return 0.0; }
3202 DEFINE_DERIVED_FLOAT2(Mod, mod, x, y, x - y * app<Floor>(x / y));
3204 class Modf : public PrimitiveFunc<Signature<float, float, float> >
3207 string getName (void) const
3213 IRet doApply (const EvalContext&, const IArgs& iargs) const
3216 Interval& wholeIV = const_cast<Interval&>(iargs.b);
3219 TCU_INTERVAL_APPLY_MONOTONE1(fracIV, x, iargs.a, frac, frac = deModf(x, &intPart));
3220 TCU_INTERVAL_APPLY_MONOTONE1(wholeIV, x, iargs.a, whole,
3221 deModf(x, &intPart); whole = intPart);
3223 if (!iargs.a.isFinite())
3225 // Behavior on modf(Inf) not well-defined, allow anything as a fractional part
3226 // See Khronos bug 13907
3233 int getOutParamIndex (void) const
3239 class Min : public PreciseFunc2 { public: Min (void) : PreciseFunc2("min", deMin) {} };
3240 class Max : public PreciseFunc2 { public: Max (void) : PreciseFunc2("max", deMax) {} };
3242 class Clamp : public FloatFunc3
3245 string getName (void) const { return "clamp"; }
3247 double applyExact (double x, double minVal, double maxVal) const
3249 return de::min(de::max(x, minVal), maxVal);
3252 double precision (const EvalContext&, double, double, double minVal, double maxVal) const
3254 return minVal > maxVal ? TCU_NAN : 0.0;
3258 ExprP<float> clamp(const ExprP<float>& x, const ExprP<float>& minVal, const ExprP<float>& maxVal)
3260 return app<Clamp>(x, minVal, maxVal);
3263 DEFINE_DERIVED_FLOAT3(Mix, mix, x, y, a, alternatives((x * (constant(1.0f) - a)) + y * a,
3266 static double step (double edge, double x)
3268 return x < edge ? 0.0 : 1.0;
3271 class Step : public PreciseFunc2 { public: Step (void) : PreciseFunc2("step", step) {} };
3273 class SmoothStep : public DerivedFunc<Signature<float, float, float, float> >
3276 string getName (void) const
3278 return "smoothstep";
3283 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3285 const ExprP<float>& edge0 = args.a;
3286 const ExprP<float>& edge1 = args.b;
3287 const ExprP<float>& x = args.c;
3288 const ExprP<float> tExpr = clamp((x - edge0) / (edge1 - edge0),
3289 constant(0.0f), constant(1.0f));
3290 const ExprP<float> t = bindExpression("t", ctx, tExpr);
3292 return (t * t * (constant(3.0f) - constant(2.0f) * t));
3296 class FrExp : public PrimitiveFunc<Signature<float, float, int> >
3299 string getName (void) const
3305 IRet doApply (const EvalContext&, const IArgs& iargs) const
3308 const IArg0& x = iargs.a;
3309 IArg1& exponent = const_cast<IArg1&>(iargs.b);
3311 if (x.hasNaN() || x.contains(TCU_INFINITY) || x.contains(-TCU_INFINITY))
3313 // GLSL (in contrast to IEEE) says that result of applying frexp
3314 // to infinity is undefined
3315 ret = Interval::unbounded() | TCU_NAN;
3316 exponent = Interval(-deLdExp(1.0, 31), deLdExp(1.0, 31)-1);
3318 else if (!x.empty())
3321 const double loFrac = deFrExp(x.lo(), &loExp);
3323 const double hiFrac = deFrExp(x.hi(), &hiExp);
3325 if (deSign(loFrac) != deSign(hiFrac))
3327 exponent = Interval(-TCU_INFINITY, de::max(loExp, hiExp));
3329 if (deSign(loFrac) < 0)
3330 ret |= Interval(-1.0 + DBL_EPSILON*0.5, 0.0);
3331 if (deSign(hiFrac) > 0)
3332 ret |= Interval(0.0, 1.0 - DBL_EPSILON*0.5);
3336 exponent = Interval(loExp, hiExp);
3338 ret = Interval(loFrac, hiFrac);
3340 ret = deSign(loFrac) * Interval(0.5, 1.0 - DBL_EPSILON*0.5);
3347 int getOutParamIndex (void) const
3353 class LdExp : public PrimitiveFunc<Signature<float, float, int> >
3356 string getName (void) const
3362 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
3364 Interval ret = call<Exp2>(ctx, iargs.b);
3365 // Khronos bug 11180 consensus: if exp2(exponent) cannot be represented,
3366 // the result is undefined.
3368 if (ret.contains(TCU_INFINITY) | ret.contains(-TCU_INFINITY))
3371 return call<Mul>(ctx, iargs.a, ret);
3375 template<int Rows, int Columns>
3376 class Transpose : public PrimitiveFunc<Signature<Matrix<float, Rows, Columns>,
3377 Matrix<float, Columns, Rows> > >
3380 typedef typename Transpose::IRet IRet;
3381 typedef typename Transpose::IArgs IArgs;
3383 string getName (void) const
3389 IRet doApply (const EvalContext&, const IArgs& iargs) const
3393 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
3395 for (int colNdx = 0; colNdx < Columns; ++colNdx)
3396 ret(rowNdx, colNdx) = iargs.a(colNdx, rowNdx);
3403 template<typename Ret, typename Arg0, typename Arg1>
3404 class MulFunc : public PrimitiveFunc<Signature<Ret, Arg0, Arg1> >
3407 string getName (void) const { return "mul"; }
3410 void doPrint (ostream& os, const BaseArgExprs& args) const
3412 os << "(" << *args[0] << " * " << *args[1] << ")";
3416 template<int LeftRows, int Middle, int RightCols>
3417 class MatMul : public MulFunc<Matrix<float, LeftRows, RightCols>,
3418 Matrix<float, LeftRows, Middle>,
3419 Matrix<float, Middle, RightCols> >
3422 typedef typename MatMul::IRet IRet;
3423 typedef typename MatMul::IArgs IArgs;
3424 typedef typename MatMul::IArg0 IArg0;
3425 typedef typename MatMul::IArg1 IArg1;
3427 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3429 const IArg0& left = iargs.a;
3430 const IArg1& right = iargs.b;
3433 for (int row = 0; row < LeftRows; ++row)
3435 for (int col = 0; col < RightCols; ++col)
3437 Interval element (0.0);
3439 for (int ndx = 0; ndx < Middle; ++ndx)
3440 element = call<Add>(ctx, element,
3441 call<Mul>(ctx, left[ndx][row], right[col][ndx]));
3443 ret[col][row] = element;
3451 template<int Rows, int Cols>
3452 class VecMatMul : public MulFunc<Vector<float, Cols>,
3453 Vector<float, Rows>,
3454 Matrix<float, Rows, Cols> >
3457 typedef typename VecMatMul::IRet IRet;
3458 typedef typename VecMatMul::IArgs IArgs;
3459 typedef typename VecMatMul::IArg0 IArg0;
3460 typedef typename VecMatMul::IArg1 IArg1;
3463 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3465 const IArg0& left = iargs.a;
3466 const IArg1& right = iargs.b;
3469 for (int col = 0; col < Cols; ++col)
3471 Interval element (0.0);
3473 for (int row = 0; row < Rows; ++row)
3474 element = call<Add>(ctx, element, call<Mul>(ctx, left[row], right[col][row]));
3483 template<int Rows, int Cols>
3484 class MatVecMul : public MulFunc<Vector<float, Rows>,
3485 Matrix<float, Rows, Cols>,
3486 Vector<float, Cols> >
3489 typedef typename MatVecMul::IRet IRet;
3490 typedef typename MatVecMul::IArgs IArgs;
3491 typedef typename MatVecMul::IArg0 IArg0;
3492 typedef typename MatVecMul::IArg1 IArg1;
3495 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3497 const IArg0& left = iargs.a;
3498 const IArg1& right = iargs.b;
3500 return call<VecMatMul<Cols, Rows> >(ctx, right,
3501 call<Transpose<Rows, Cols> >(ctx, left));
3505 template<int Rows, int Cols>
3506 class OuterProduct : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
3507 Vector<float, Rows>,
3508 Vector<float, Cols> > >
3511 typedef typename OuterProduct::IRet IRet;
3512 typedef typename OuterProduct::IArgs IArgs;
3514 string getName (void) const
3516 return "outerProduct";
3520 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3524 for (int row = 0; row < Rows; ++row)
3526 for (int col = 0; col < Cols; ++col)
3527 ret[col][row] = call<Mul>(ctx, iargs.a[row], iargs.b[col]);
3534 template<int Rows, int Cols>
3535 ExprP<Matrix<float, Rows, Cols> > outerProduct (const ExprP<Vector<float, Rows> >& left,
3536 const ExprP<Vector<float, Cols> >& right)
3538 return app<OuterProduct<Rows, Cols> >(left, right);
3542 class DeterminantBase : public DerivedFunc<Signature<float, Matrix<float, Size, Size> > >
3545 string getName (void) const { return "determinant"; }
3552 ExprP<float> determinant (ExprP<Matrix<float, Size, Size> > mat)
3554 return app<Determinant<Size> >(mat);
3558 class Determinant<2> : public DeterminantBase<2>
3561 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3563 ExprP<Mat2> mat = args.a;
3565 return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
3570 class Determinant<3> : public DeterminantBase<3>
3573 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3575 ExprP<Mat3> mat = args.a;
3577 return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) +
3578 mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) +
3579 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
3584 class Determinant<4> : public DeterminantBase<4>
3587 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3589 ExprP<Mat4> mat = args.a;
3590 ExprP<Mat3> minors[4];
3592 for (int ndx = 0; ndx < 4; ++ndx)
3594 ExprP<Vec4> minorColumns[3];
3595 ExprP<Vec3> columns[3];
3597 for (int col = 0; col < 3; ++col)
3598 minorColumns[col] = mat[col < ndx ? col : col + 1];
3600 for (int col = 0; col < 3; ++col)
3601 columns[col] = vec3(minorColumns[0][col+1],
3602 minorColumns[1][col+1],
3603 minorColumns[2][col+1]);
3605 minors[ndx] = bindExpression("minor", ctx,
3606 mat3(columns[0], columns[1], columns[2]));
3609 return (mat[0][0] * determinant(minors[0]) -
3610 mat[1][0] * determinant(minors[1]) +
3611 mat[2][0] * determinant(minors[2]) -
3612 mat[3][0] * determinant(minors[3]));
3616 template<int Size> class Inverse;
3619 ExprP<Matrix<float, Size, Size> > inverse (ExprP<Matrix<float, Size, Size> > mat)
3621 return app<Inverse<Size> >(mat);
3625 class Inverse<2> : public DerivedFunc<Signature<Mat2, Mat2> >
3628 string getName (void) const
3634 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3636 ExprP<Mat2> mat = args.a;
3637 ExprP<float> det = bindExpression("det", ctx, determinant(mat));
3639 return mat2(vec2(mat[1][1] / det, -mat[0][1] / det),
3640 vec2(-mat[1][0] / det, mat[0][0] / det));
3645 class Inverse<3> : public DerivedFunc<Signature<Mat3, Mat3> >
3648 string getName (void) const
3654 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3656 ExprP<Mat3> mat = args.a;
3657 ExprP<Mat2> invA = bindExpression("invA", ctx,
3658 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3659 vec2(mat[1][0], mat[1][1]))));
3661 ExprP<Vec2> matB = bindExpression("matB", ctx, vec2(mat[2][0], mat[2][1]));
3662 ExprP<Vec2> matC = bindExpression("matC", ctx, vec2(mat[0][2], mat[1][2]));
3663 ExprP<float> matD = bindExpression("matD", ctx, mat[2][2]);
3665 ExprP<float> schur = bindExpression("schur", ctx,
3667 (matD - dot(matC * invA, matB)));
3669 ExprP<Vec2> t1 = invA * matB;
3670 ExprP<Vec2> t2 = t1 * schur;
3671 ExprP<Mat2> t3 = outerProduct(t2, matC);
3672 ExprP<Mat2> t4 = t3 * invA;
3673 ExprP<Mat2> t5 = invA + t4;
3674 ExprP<Mat2> blockA = bindExpression("blockA", ctx, t5);
3675 ExprP<Vec2> blockB = bindExpression("blockB", ctx,
3676 (invA * matB) * -schur);
3677 ExprP<Vec2> blockC = bindExpression("blockC", ctx,
3678 (matC * invA) * -schur);
3680 return mat3(vec3(blockA[0][0], blockA[0][1], blockC[0]),
3681 vec3(blockA[1][0], blockA[1][1], blockC[1]),
3682 vec3(blockB[0], blockB[1], schur));
3687 class Inverse<4> : public DerivedFunc<Signature<Mat4, Mat4> >
3690 string getName (void) const { return "inverse"; }
3693 ExprP<Ret> doExpand (ExpandContext& ctx,
3694 const ArgExprs& args) const
3696 ExprP<Mat4> mat = args.a;
3697 ExprP<Mat2> invA = bindExpression("invA", ctx,
3698 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3699 vec2(mat[1][0], mat[1][1]))));
3700 ExprP<Mat2> matB = bindExpression("matB", ctx,
3701 mat2(vec2(mat[2][0], mat[2][1]),
3702 vec2(mat[3][0], mat[3][1])));
3703 ExprP<Mat2> matC = bindExpression("matC", ctx,
3704 mat2(vec2(mat[0][2], mat[0][3]),
3705 vec2(mat[1][2], mat[1][3])));
3706 ExprP<Mat2> matD = bindExpression("matD", ctx,
3707 mat2(vec2(mat[2][2], mat[2][3]),
3708 vec2(mat[3][2], mat[3][3])));
3709 ExprP<Mat2> schur = bindExpression("schur", ctx,
3710 inverse(matD + -(matC * invA * matB)));
3711 ExprP<Mat2> blockA = bindExpression("blockA", ctx,
3712 invA + (invA * matB * schur * matC * invA));
3713 ExprP<Mat2> blockB = bindExpression("blockB", ctx,
3714 (-invA) * matB * schur);
3715 ExprP<Mat2> blockC = bindExpression("blockC", ctx,
3716 (-schur) * matC * invA);
3718 return mat4(vec4(blockA[0][0], blockA[0][1], blockC[0][0], blockC[0][1]),
3719 vec4(blockA[1][0], blockA[1][1], blockC[1][0], blockC[1][1]),
3720 vec4(blockB[0][0], blockB[0][1], schur[0][0], schur[0][1]),
3721 vec4(blockB[1][0], blockB[1][1], schur[1][0], schur[1][1]));
3725 class Fma : public DerivedFunc<Signature<float, float, float, float> >
3728 string getName (void) const
3733 string getRequiredExtension (void) const
3735 return "GL_EXT_gpu_shader5";
3739 ExprP<float> doExpand (ExpandContext&, const ArgExprs& x) const
3741 return x.a * x.b + x.c;
3747 using namespace Functions;
3749 template <typename T>
3750 ExprP<typename T::Element> ContainerExprPBase<T>::operator[] (int i) const
3752 return Functions::getComponent(exprP<T>(*this), i);
3755 ExprP<float> operator+ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3757 return app<Add>(arg0, arg1);
3760 ExprP<float> operator- (const ExprP<float>& arg0, const ExprP<float>& arg1)
3762 return app<Sub>(arg0, arg1);
3765 ExprP<float> operator- (const ExprP<float>& arg0)
3767 return app<Negate>(arg0);
3770 ExprP<float> operator* (const ExprP<float>& arg0, const ExprP<float>& arg1)
3772 return app<Mul>(arg0, arg1);
3775 ExprP<float> operator/ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3777 return app<Div>(arg0, arg1);
3780 template <typename Sig_, int Size>
3781 class GenFunc : public PrimitiveFunc<Signature<
3782 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3783 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3784 typename ContainerOf<typename Sig_::Arg1, Size>::Container,
3785 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
3786 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
3789 typedef typename GenFunc::IArgs IArgs;
3790 typedef typename GenFunc::IRet IRet;
3792 GenFunc (const Func<Sig_>& scalarFunc) : m_func (scalarFunc) {}
3794 string getName (void) const
3796 return m_func.getName();
3799 int getOutParamIndex (void) const
3801 return m_func.getOutParamIndex();
3804 string getRequiredExtension (void) const
3806 return m_func.getRequiredExtension();
3810 void doPrint (ostream& os, const BaseArgExprs& args) const
3812 m_func.print(os, args);
3815 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3819 for (int ndx = 0; ndx < Size; ++ndx)
3822 m_func.apply(ctx, iargs.a[ndx], iargs.b[ndx], iargs.c[ndx], iargs.d[ndx]);
3828 void doGetUsedFuncs (FuncSet& dst) const
3830 m_func.getUsedFuncs(dst);
3833 const Func<Sig_>& m_func;
3836 template <typename F, int Size>
3837 class VectorizedFunc : public GenFunc<typename F::Sig, Size>
3840 VectorizedFunc (void) : GenFunc<typename F::Sig, Size>(instance<F>()) {}
3845 template <typename Sig_, int Size>
3846 class FixedGenFunc : public PrimitiveFunc <Signature<
3847 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3848 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3849 typename Sig_::Arg1,
3850 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
3851 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
3854 typedef typename FixedGenFunc::IArgs IArgs;
3855 typedef typename FixedGenFunc::IRet IRet;
3857 string getName (void) const
3859 return this->doGetScalarFunc().getName();
3863 void doPrint (ostream& os, const BaseArgExprs& args) const
3865 this->doGetScalarFunc().print(os, args);
3868 IRet doApply (const EvalContext& ctx,
3869 const IArgs& iargs) const
3872 const Func<Sig_>& func = this->doGetScalarFunc();
3874 for (int ndx = 0; ndx < Size; ++ndx)
3875 ret[ndx] = func.apply(ctx, iargs.a[ndx], iargs.b, iargs.c[ndx], iargs.d[ndx]);
3880 virtual const Func<Sig_>& doGetScalarFunc (void) const = 0;
3883 template <typename F, int Size>
3884 class FixedVecFunc : public FixedGenFunc<typename F::Sig, Size>
3887 const Func<typename F::Sig>& doGetScalarFunc (void) const { return instance<F>(); }
3890 template<typename Sig>
3893 GenFuncs (const Func<Sig>& func_,
3894 const GenFunc<Sig, 2>& func2_,
3895 const GenFunc<Sig, 3>& func3_,
3896 const GenFunc<Sig, 4>& func4_)
3903 const Func<Sig>& func;
3904 const GenFunc<Sig, 2>& func2;
3905 const GenFunc<Sig, 3>& func3;
3906 const GenFunc<Sig, 4>& func4;
3909 template<typename F>
3910 GenFuncs<typename F::Sig> makeVectorizedFuncs (void)
3912 return GenFuncs<typename F::Sig>(instance<F>(),
3913 instance<VectorizedFunc<F, 2> >(),
3914 instance<VectorizedFunc<F, 3> >(),
3915 instance<VectorizedFunc<F, 4> >());
3919 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
3920 const ExprP<Vector<float, Size> >& arg1)
3922 return app<VectorizedFunc<Mul, Size> >(arg0, arg1);
3926 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
3927 const ExprP<float>& arg1)
3929 return app<FixedVecFunc<Mul, Size> >(arg0, arg1);
3933 ExprP<Vector<float, Size> > operator/(const ExprP<Vector<float, Size> >& arg0,
3934 const ExprP<float>& arg1)
3936 return app<FixedVecFunc<Div, Size> >(arg0, arg1);
3940 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0)
3942 return app<VectorizedFunc<Negate, Size> >(arg0);
3946 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
3947 const ExprP<Vector<float, Size> >& arg1)
3949 return app<VectorizedFunc<Sub, Size> >(arg0, arg1);
3952 template<int LeftRows, int Middle, int RightCols>
3953 ExprP<Matrix<float, LeftRows, RightCols> >
3954 operator* (const ExprP<Matrix<float, LeftRows, Middle> >& left,
3955 const ExprP<Matrix<float, Middle, RightCols> >& right)
3957 return app<MatMul<LeftRows, Middle, RightCols> >(left, right);
3960 template<int Rows, int Cols>
3961 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
3962 const ExprP<Matrix<float, Rows, Cols> >& right)
3964 return app<VecMatMul<Rows, Cols> >(left, right);
3967 template<int Rows, int Cols>
3968 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
3969 const ExprP<Vector<float, Rows> >& right)
3971 return app<MatVecMul<Rows, Cols> >(left, right);
3974 template<int Rows, int Cols>
3975 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
3976 const ExprP<float>& right)
3978 return app<ScalarMatFunc<Mul, Rows, Cols> >(left, right);
3981 template<int Rows, int Cols>
3982 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
3983 const ExprP<Matrix<float, Rows, Cols> >& right)
3985 return app<CompMatFunc<Add, Rows, Cols> >(left, right);
3988 template<int Rows, int Cols>
3989 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat)
3991 return app<MatNeg<Rows, Cols> >(mat);
3994 template <typename T>
3998 virtual void genFixeds (const FloatFormat&, vector<T>&) const {}
3999 virtual T genRandom (const FloatFormat&, Precision, Random&) const { return T(); }
4000 virtual double getWeight (void) const { return 0.0; }
4004 class DefaultSampling<Void> : public Sampling<Void>
4007 void genFixeds (const FloatFormat&, vector<Void>& dst) const { dst.push_back(Void()); }
4011 class DefaultSampling<bool> : public Sampling<bool>
4014 void genFixeds (const FloatFormat&, vector<bool>& dst) const
4016 dst.push_back(true);
4017 dst.push_back(false);
4022 class DefaultSampling<int> : public Sampling<int>
4025 int genRandom (const FloatFormat&, Precision prec, Random& rnd) const
4027 const int exp = rnd.getInt(0, getNumBits(prec)-2);
4028 const int sign = rnd.getBool() ? -1 : 1;
4030 return sign * rnd.getInt(0, (deInt32)1 << exp);
4033 void genFixeds (const FloatFormat&, vector<int>& dst) const
4039 double getWeight (void) const { return 1.0; }
4042 static inline int getNumBits (Precision prec)
4046 case glu::PRECISION_LOWP: return 8;
4047 case glu::PRECISION_MEDIUMP: return 16;
4048 case glu::PRECISION_HIGHP: return 32;
4057 class DefaultSampling<float> : public Sampling<float>
4060 float genRandom (const FloatFormat& format, Precision prec, Random& rnd) const;
4061 void genFixeds (const FloatFormat& format, vector<float>& dst) const;
4062 double getWeight (void) const { return 1.0; }
4065 //! Generate a random float from a reasonable general-purpose distribution.
4066 float DefaultSampling<float>::genRandom (const FloatFormat& format,
4070 const int minExp = format.getMinExp();
4071 const int maxExp = format.getMaxExp();
4072 const bool haveSubnormal = format.hasSubnormal() != tcu::NO;
4074 // Choose exponent so that the cumulative distribution is cubic.
4075 // This makes the probability distribution quadratic, with the peak centered on zero.
4076 const double minRoot = deCbrt(minExp - 0.5 - (haveSubnormal ? 1.0 : 0.0));
4077 const double maxRoot = deCbrt(maxExp + 0.5);
4078 const int fractionBits = format.getFractionBits();
4079 const int exp = int(deRoundEven(dePow(rnd.getDouble(minRoot, maxRoot),
4081 float base = 0.0f; // integral power of two
4082 float quantum = 0.0f; // smallest representable difference in the binade
4083 float significand = 0.0f; // Significand.
4085 DE_ASSERT(fractionBits < std::numeric_limits<float>::digits);
4087 // Generate some occasional special numbers
4088 switch (rnd.getInt(0, 64))
4091 case 1: return TCU_INFINITY;
4092 case 2: return -TCU_INFINITY;
4093 case 3: return TCU_NAN;
4100 base = deFloatLdExp(1.0f, exp);
4101 quantum = deFloatLdExp(1.0f, exp - fractionBits);
4107 quantum = deFloatLdExp(1.0f, minExp - fractionBits);
4110 switch (rnd.getInt(0, 16))
4112 case 0: // The highest number in this binade, significand is all bits one.
4113 significand = base - quantum;
4115 case 1: // Significand is one.
4116 significand = quantum;
4118 case 2: // Significand is zero.
4121 default: // Random (evenly distributed) significand.
4123 deUint64 intFraction = rnd.getUint64() & ((1 << fractionBits) - 1);
4124 significand = float(intFraction) * quantum;
4128 // Produce positive numbers more often than negative.
4129 return (rnd.getInt(0,3) == 0 ? -1.0f : 1.0f) * (base + significand);
4132 //! Generate a standard set of floats that should always be tested.
4133 void DefaultSampling<float>::genFixeds (const FloatFormat& format, vector<float>& dst) const
4135 const int minExp = format.getMinExp();
4136 const int maxExp = format.getMaxExp();
4137 const int fractionBits = format.getFractionBits();
4138 const float minQuantum = deFloatLdExp(1.0f, minExp - fractionBits);
4139 const float minNormalized = deFloatLdExp(1.0f, minExp);
4140 const float maxQuantum = deFloatLdExp(1.0f, maxExp - fractionBits);
4143 dst.push_back(TCU_NAN);
4145 dst.push_back(0.0f);
4147 for (int sign = -1; sign <= 1; sign += 2)
4149 // Smallest subnormal
4150 dst.push_back((float)sign * minQuantum);
4152 // Largest subnormal
4153 dst.push_back((float)sign * (minNormalized - minQuantum));
4155 // Smallest normalized
4156 dst.push_back((float)sign * minNormalized);
4158 // Next smallest normalized
4159 dst.push_back((float)sign * (minNormalized + minQuantum));
4161 dst.push_back((float)sign * 0.5f);
4162 dst.push_back((float)sign * 1.0f);
4163 dst.push_back((float)sign * 2.0f);
4166 dst.push_back((float)sign * (deFloatLdExp(1.0f, maxExp) +
4167 (deFloatLdExp(1.0f, maxExp) - maxQuantum)));
4169 dst.push_back((float)sign * TCU_INFINITY);
4173 template <typename T, int Size>
4174 class DefaultSampling<Vector<T, Size> > : public Sampling<Vector<T, Size> >
4177 typedef Vector<T, Size> Value;
4179 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4183 for (int ndx = 0; ndx < Size; ++ndx)
4184 ret[ndx] = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4189 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4193 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4195 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4196 dst.push_back(Value(scalars[scalarNdx]));
4199 double getWeight (void) const
4201 return dePow(instance<DefaultSampling<T> >().getWeight(), Size);
4205 template <typename T, int Rows, int Columns>
4206 class DefaultSampling<Matrix<T, Rows, Columns> > : public Sampling<Matrix<T, Rows, Columns> >
4209 typedef Matrix<T, Rows, Columns> Value;
4211 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4215 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
4216 for (int colNdx = 0; colNdx < Columns; ++colNdx)
4217 ret(rowNdx, colNdx) = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4222 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4226 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4228 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4229 dst.push_back(Value(scalars[scalarNdx]));
4231 if (Columns == Rows)
4236 for (int ndx = 0; ndx < Columns; ++ndx)
4238 mat[Columns-1-ndx][ndx] = x;
4245 double getWeight (void) const
4247 return dePow(instance<DefaultSampling<T> >().getWeight(), Rows * Columns);
4253 CaseContext (const string& name_,
4254 TestContext& testContext_,
4255 const FloatFormat& floatFormat_,
4256 const FloatFormat& highpFormat_,
4257 Precision precision_,
4258 ShaderType shaderType_,
4261 , testContext (testContext_)
4262 , floatFormat (floatFormat_)
4263 , highpFormat (highpFormat_)
4264 , precision (precision_)
4265 , shaderType (shaderType_)
4266 , numRandoms (numRandoms_) {}
4269 TestContext& testContext;
4270 FloatFormat floatFormat;
4271 FloatFormat highpFormat;
4272 Precision precision;
4273 ShaderType shaderType;
4277 template<typename In0_ = Void, typename In1_ = Void, typename In2_ = Void, typename In3_ = Void>
4286 template <typename In>
4287 int numInputs (void)
4289 return (!isTypeValid<typename In::In0>() ? 0 :
4290 !isTypeValid<typename In::In1>() ? 1 :
4291 !isTypeValid<typename In::In2>() ? 2 :
4292 !isTypeValid<typename In::In3>() ? 3 :
4296 template<typename Out0_, typename Out1_ = Void>
4303 template <typename Out>
4304 int numOutputs (void)
4306 return (!isTypeValid<typename Out::Out0>() ? 0 :
4307 !isTypeValid<typename Out::Out1>() ? 1 :
4311 template<typename In>
4314 vector<typename In::In0> in0;
4315 vector<typename In::In1> in1;
4316 vector<typename In::In2> in2;
4317 vector<typename In::In3> in3;
4320 template<typename Out>
4323 Outputs (size_t size) : out0(size), out1(size) {}
4325 vector<typename Out::Out0> out0;
4326 vector<typename Out::Out1> out1;
4329 template<typename In, typename Out>
4332 VariableP<typename In::In0> in0;
4333 VariableP<typename In::In1> in1;
4334 VariableP<typename In::In2> in2;
4335 VariableP<typename In::In3> in3;
4336 VariableP<typename Out::Out0> out0;
4337 VariableP<typename Out::Out1> out1;
4340 template<typename In>
4343 Samplings (const Sampling<typename In::In0>& in0_,
4344 const Sampling<typename In::In1>& in1_,
4345 const Sampling<typename In::In2>& in2_,
4346 const Sampling<typename In::In3>& in3_)
4347 : in0 (in0_), in1 (in1_), in2 (in2_), in3 (in3_) {}
4349 const Sampling<typename In::In0>& in0;
4350 const Sampling<typename In::In1>& in1;
4351 const Sampling<typename In::In2>& in2;
4352 const Sampling<typename In::In3>& in3;
4355 template<typename In>
4356 struct DefaultSamplings : Samplings<In>
4358 DefaultSamplings (void)
4359 : Samplings<In>(instance<DefaultSampling<typename In::In0> >(),
4360 instance<DefaultSampling<typename In::In1> >(),
4361 instance<DefaultSampling<typename In::In2> >(),
4362 instance<DefaultSampling<typename In::In3> >()) {}
4365 template <typename In, typename Out>
4366 class BuiltinPrecisionCaseTestInstance : public TestInstance
4369 BuiltinPrecisionCaseTestInstance (Context& context,
4370 const CaseContext caseCtx,
4371 ShaderExecutor& executor,
4372 const Variables<In, Out> variables,
4373 const Samplings<In>& samplings,
4374 const StatementP stmt)
4375 : TestInstance (context)
4376 , m_caseCtx (caseCtx)
4377 , m_executor (executor)
4378 , m_variables (variables)
4379 , m_samplings (samplings)
4383 virtual tcu::TestStatus iterate (void);
4386 CaseContext m_caseCtx;
4387 ShaderExecutor& m_executor;
4388 Variables<In, Out> m_variables;
4389 const Samplings<In>& m_samplings;
4393 template<class In, class Out>
4394 tcu::TestStatus BuiltinPrecisionCaseTestInstance<In, Out>::iterate (void)
4396 typedef typename In::In0 In0;
4397 typedef typename In::In1 In1;
4398 typedef typename In::In2 In2;
4399 typedef typename In::In3 In3;
4400 typedef typename Out::Out0 Out0;
4401 typedef typename Out::Out1 Out1;
4403 Inputs<In> inputs = generateInputs(m_samplings, m_caseCtx.floatFormat, m_caseCtx.precision, m_caseCtx.numRandoms, 0xdeadbeefu + m_caseCtx.testContext.getCommandLine().getBaseSeed());
4404 const FloatFormat& fmt = m_caseCtx.floatFormat;
4405 const int inCount = numInputs<In>();
4406 const int outCount = numOutputs<Out>();
4407 const size_t numValues = (inCount > 0) ? inputs.in0.size() : 1;
4408 Outputs<Out> outputs (numValues);
4409 const FloatFormat highpFmt = m_caseCtx.highpFormat;
4410 const int maxMsgs = 100;
4412 Environment env; // Hoisted out of the inner loop for optimization.
4413 ResultCollector status;
4414 TestLog& testLog = m_context.getTestContext().getLog();
4416 const void* inputArr[] =
4418 &inputs.in0.front(), &inputs.in1.front(), &inputs.in2.front(), &inputs.in3.front(),
4422 &outputs.out0.front(), &outputs.out1.front(),
4425 // Print out the statement and its definitions
4426 testLog << TestLog::Message << "Statement: " << m_stmt << TestLog::EndMessage;
4431 m_stmt->getUsedFuncs(funcs);
4432 for (FuncSet::const_iterator it = funcs.begin(); it != funcs.end(); ++it)
4434 (*it)->printDefinition(oss);
4437 testLog << TestLog::Message << "Reference definitions:\n" << oss.str()
4438 << TestLog::EndMessage;
4443 case 4: DE_ASSERT(inputs.in3.size() == numValues);
4444 case 3: DE_ASSERT(inputs.in2.size() == numValues);
4445 case 2: DE_ASSERT(inputs.in1.size() == numValues);
4446 case 1: DE_ASSERT(inputs.in0.size() == numValues);
4450 m_executor.execute(m_context, int(numValues), inputArr, outputArr);
4452 // Initialize environment with dummy values so we don't need to bind in inner loop.
4454 const typename Traits<In0>::IVal in0;
4455 const typename Traits<In1>::IVal in1;
4456 const typename Traits<In2>::IVal in2;
4457 const typename Traits<In3>::IVal in3;
4458 const typename Traits<Out0>::IVal reference0;
4459 const typename Traits<Out1>::IVal reference1;
4461 env.bind(*m_variables.in0, in0);
4462 env.bind(*m_variables.in1, in1);
4463 env.bind(*m_variables.in2, in2);
4464 env.bind(*m_variables.in3, in3);
4465 env.bind(*m_variables.out0, reference0);
4466 env.bind(*m_variables.out1, reference1);
4469 // For each input tuple, compute output reference interval and compare
4470 // shader output to the reference.
4471 for (size_t valueNdx = 0; valueNdx < numValues; valueNdx++)
4474 typename Traits<Out0>::IVal reference0;
4475 typename Traits<Out1>::IVal reference1;
4477 env.lookup(*m_variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx]));
4478 env.lookup(*m_variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx]));
4479 env.lookup(*m_variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx]));
4480 env.lookup(*m_variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx]));
4483 EvalContext ctx (fmt, m_caseCtx.precision, env);
4484 m_stmt->execute(ctx);
4490 reference1 = convert<Out1>(highpFmt, env.lookup(*m_variables.out1));
4491 if (!status.check(contains(reference1, outputs.out1[valueNdx]),
4492 "Shader output 1 is outside acceptable range"))
4495 reference0 = convert<Out0>(highpFmt, env.lookup(*m_variables.out0));
4496 if (!status.check(contains(reference0, outputs.out0[valueNdx]),
4497 "Shader output 0 is outside acceptable range"))
4505 if ((!result && numErrors <= maxMsgs) || GLS_LOG_ALL_RESULTS)
4507 MessageBuilder builder = testLog.message();
4509 builder << (result ? "Passed" : "Failed") << " sample:\n";
4513 builder << "\t" << m_variables.in0->getName() << " = "
4514 << valueToString(highpFmt, inputs.in0[valueNdx]) << "\n";
4519 builder << "\t" << m_variables.in1->getName() << " = "
4520 << valueToString(highpFmt, inputs.in1[valueNdx]) << "\n";
4525 builder << "\t" << m_variables.in2->getName() << " = "
4526 << valueToString(highpFmt, inputs.in2[valueNdx]) << "\n";
4531 builder << "\t" << m_variables.in3->getName() << " = "
4532 << valueToString(highpFmt, inputs.in3[valueNdx]) << "\n";
4537 builder << "\t" << m_variables.out0->getName() << " = "
4538 << valueToString(highpFmt, outputs.out0[valueNdx]) << "\n"
4539 << "\tExpected range: "
4540 << intervalToString<typename Out::Out0>(highpFmt, reference0) << "\n";
4545 builder << "\t" << m_variables.out1->getName() << " = "
4546 << valueToString(highpFmt, outputs.out1[valueNdx]) << "\n"
4547 << "\tExpected range: "
4548 << intervalToString<typename Out::Out1>(highpFmt, reference1) << "\n";
4551 builder << TestLog::EndMessage;
4555 if (numErrors > maxMsgs)
4557 testLog << TestLog::Message << "(Skipped " << (numErrors - maxMsgs) << " messages.)"
4558 << TestLog::EndMessage;
4563 testLog << TestLog::Message << "All " << numValues << " inputs passed."
4564 << TestLog::EndMessage;
4568 testLog << TestLog::Message << numErrors << "/" << numValues << " inputs failed."
4569 << TestLog::EndMessage;
4573 return tcu::TestStatus::fail(de::toString(numErrors) + string(" test failed. Check log for the details"));
4575 return tcu::TestStatus::pass("Pass");
4579 class PrecisionCase : public TestCase
4582 PrecisionCase (const CaseContext& context, const string& name, const string& extension = "")
4583 : TestCase (context.testContext, name.c_str(), name.c_str())
4585 , m_extension (extension)
4586 , m_executor (DE_NULL)
4590 virtual void initPrograms (vk::SourceCollections& programCollection) const
4592 m_executor->setShaderSources(programCollection);
4595 const FloatFormat& getFormat (void) const { return m_ctx.floatFormat; }
4597 template <typename In, typename Out>
4598 void testStatement (const Variables<In, Out>& variables, const Statement& stmt);
4600 template<typename T>
4601 Symbol makeSymbol (const Variable<T>& variable)
4603 return Symbol(variable.getName(), getVarTypeOf<T>(m_ctx.precision));
4607 const string m_extension;
4609 de::MovePtr<ShaderExecutor> m_executor;
4612 template <typename In, typename Out>
4613 void PrecisionCase::testStatement (const Variables<In, Out>& variables, const Statement& stmt)
4615 const int inCount = numInputs<In>();
4616 const int outCount = numOutputs<Out>();
4617 Environment env; // Hoisted out of the inner loop for optimization.
4619 // Initialize ShaderSpec from precision, variables and statement.
4622 os << "precision " << glu::getPrecisionName(m_ctx.precision) << " float;\n";
4623 m_spec.globalDeclarations = os.str();
4626 if (!m_extension.empty())
4627 m_spec.globalDeclarations = "#extension " + m_extension + " : require\n";
4629 m_spec.inputs.resize(inCount);
4633 case 4: m_spec.inputs[3] = makeSymbol(*variables.in3);
4634 case 3: m_spec.inputs[2] = makeSymbol(*variables.in2);
4635 case 2: m_spec.inputs[1] = makeSymbol(*variables.in1);
4636 case 1: m_spec.inputs[0] = makeSymbol(*variables.in0);
4640 m_spec.outputs.resize(outCount);
4644 case 2: m_spec.outputs[1] = makeSymbol(*variables.out1);
4645 case 1: m_spec.outputs[0] = makeSymbol(*variables.out0);
4649 m_spec.source = de::toString(stmt);
4651 m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_ctx.shaderType, m_spec));
4654 template <typename T>
4657 bool operator() (const T& val1, const T& val2) const
4663 template <typename T>
4664 bool inputLess (const T& val1, const T& val2)
4666 return InputLess<T>()(val1, val2);
4670 struct InputLess<float>
4672 bool operator() (const float& val1, const float& val2) const
4682 template <typename T, int Size>
4683 struct InputLess<Vector<T, Size> >
4685 bool operator() (const Vector<T, Size>& vec1, const Vector<T, Size>& vec2) const
4687 for (int ndx = 0; ndx < Size; ++ndx)
4689 if (inputLess(vec1[ndx], vec2[ndx]))
4691 if (inputLess(vec2[ndx], vec1[ndx]))
4699 template <typename T, int Rows, int Cols>
4700 struct InputLess<Matrix<T, Rows, Cols> >
4702 bool operator() (const Matrix<T, Rows, Cols>& mat1,
4703 const Matrix<T, Rows, Cols>& mat2) const
4705 for (int col = 0; col < Cols; ++col)
4707 if (inputLess(mat1[col], mat2[col]))
4709 if (inputLess(mat2[col], mat1[col]))
4717 template <typename In>
4719 public Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4721 InTuple (const typename In::In0& in0,
4722 const typename In::In1& in1,
4723 const typename In::In2& in2,
4724 const typename In::In3& in3)
4725 : Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4726 (in0, in1, in2, in3) {}
4729 template <typename In>
4730 struct InputLess<InTuple<In> >
4732 bool operator() (const InTuple<In>& in1, const InTuple<In>& in2) const
4734 if (inputLess(in1.a, in2.a))
4736 if (inputLess(in2.a, in1.a))
4738 if (inputLess(in1.b, in2.b))
4740 if (inputLess(in2.b, in1.b))
4742 if (inputLess(in1.c, in2.c))
4744 if (inputLess(in2.c, in1.c))
4746 if (inputLess(in1.d, in2.d))
4752 template<typename In>
4753 Inputs<In> generateInputs (const Samplings<In>& samplings,
4754 const FloatFormat& floatFormat,
4755 Precision intPrecision,
4761 Inputs<In> fixedInputs;
4762 set<InTuple<In>, InputLess<InTuple<In> > > seenInputs;
4764 samplings.in0.genFixeds(floatFormat, fixedInputs.in0);
4765 samplings.in1.genFixeds(floatFormat, fixedInputs.in1);
4766 samplings.in2.genFixeds(floatFormat, fixedInputs.in2);
4767 samplings.in3.genFixeds(floatFormat, fixedInputs.in3);
4769 for (size_t ndx0 = 0; ndx0 < fixedInputs.in0.size(); ++ndx0)
4771 for (size_t ndx1 = 0; ndx1 < fixedInputs.in1.size(); ++ndx1)
4773 for (size_t ndx2 = 0; ndx2 < fixedInputs.in2.size(); ++ndx2)
4775 for (size_t ndx3 = 0; ndx3 < fixedInputs.in3.size(); ++ndx3)
4777 const InTuple<In> tuple (fixedInputs.in0[ndx0],
4778 fixedInputs.in1[ndx1],
4779 fixedInputs.in2[ndx2],
4780 fixedInputs.in3[ndx3]);
4782 seenInputs.insert(tuple);
4783 ret.in0.push_back(tuple.a);
4784 ret.in1.push_back(tuple.b);
4785 ret.in2.push_back(tuple.c);
4786 ret.in3.push_back(tuple.d);
4792 for (size_t ndx = 0; ndx < numSamples; ++ndx)
4794 const typename In::In0 in0 = samplings.in0.genRandom(floatFormat, intPrecision, rnd);
4795 const typename In::In1 in1 = samplings.in1.genRandom(floatFormat, intPrecision, rnd);
4796 const typename In::In2 in2 = samplings.in2.genRandom(floatFormat, intPrecision, rnd);
4797 const typename In::In3 in3 = samplings.in3.genRandom(floatFormat, intPrecision, rnd);
4798 const InTuple<In> tuple (in0, in1, in2, in3);
4800 if (de::contains(seenInputs, tuple))
4803 seenInputs.insert(tuple);
4804 ret.in0.push_back(in0);
4805 ret.in1.push_back(in1);
4806 ret.in2.push_back(in2);
4807 ret.in3.push_back(in3);
4813 class FuncCaseBase : public PrecisionCase
4816 FuncCaseBase (const CaseContext& context, const string& name, const FuncBase& func)
4817 : PrecisionCase (context, name, func.getRequiredExtension())
4824 template <typename Sig>
4825 class FuncCase : public FuncCaseBase
4828 typedef Func<Sig> CaseFunc;
4829 typedef typename Sig::Ret Ret;
4830 typedef typename Sig::Arg0 Arg0;
4831 typedef typename Sig::Arg1 Arg1;
4832 typedef typename Sig::Arg2 Arg2;
4833 typedef typename Sig::Arg3 Arg3;
4834 typedef InTypes<Arg0, Arg1, Arg2, Arg3> In;
4835 typedef OutTypes<Ret> Out;
4837 FuncCase (const CaseContext& context, const string& name, const CaseFunc& func)
4838 : FuncCaseBase (context, name, func)
4844 virtual TestInstance* createInstance (Context& context) const
4846 return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, getSamplings(), m_stmt);
4850 void buildTest (void);
4851 virtual const Samplings<In>& getSamplings (void) const
4853 return instance<DefaultSamplings<In> >();
4857 const CaseFunc& m_func;
4858 Variables<In, Out> m_variables;
4861 template <typename Sig>
4862 void FuncCase<Sig>::buildTest (void)
4864 m_variables.out0 = variable<Ret>("out0");
4865 m_variables.out1 = variable<Void>("out1");
4866 m_variables.in0 = variable<Arg0>("in0");
4867 m_variables.in1 = variable<Arg1>("in1");
4868 m_variables.in2 = variable<Arg2>("in2");
4869 m_variables.in3 = variable<Arg3>("in3");
4872 ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.in1, m_variables.in2, m_variables.in3);
4873 m_stmt = variableAssignment(m_variables.out0, expr);
4875 this->testStatement(m_variables, *m_stmt);
4879 template <typename Sig>
4880 class InOutFuncCase : public FuncCaseBase
4883 typedef Func<Sig> CaseFunc;
4884 typedef typename Sig::Ret Ret;
4885 typedef typename Sig::Arg0 Arg0;
4886 typedef typename Sig::Arg1 Arg1;
4887 typedef typename Sig::Arg2 Arg2;
4888 typedef typename Sig::Arg3 Arg3;
4889 typedef InTypes<Arg0, Arg2, Arg3> In;
4890 typedef OutTypes<Ret, Arg1> Out;
4892 InOutFuncCase (const CaseContext& context, const string& name, const CaseFunc& func)
4893 : FuncCaseBase (context, name, func)
4898 virtual TestInstance* createInstance (Context& context) const
4900 return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, getSamplings(), m_stmt);
4904 void buildTest (void);
4905 virtual const Samplings<In>& getSamplings (void) const
4907 return instance<DefaultSamplings<In> >();
4911 const CaseFunc& m_func;
4912 Variables<In, Out> m_variables;
4915 template <typename Sig>
4916 void InOutFuncCase<Sig>::buildTest (void)
4919 m_variables.out0 = variable<Ret>("out0");
4920 m_variables.out1 = variable<Arg1>("out1");
4921 m_variables.in0 = variable<Arg0>("in0");
4922 m_variables.in1 = variable<Arg2>("in1");
4923 m_variables.in2 = variable<Arg3>("in2");
4924 m_variables.in3 = variable<Void>("in3");
4927 ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.out1, m_variables.in1, m_variables.in2);
4928 m_stmt = variableAssignment(m_variables.out0, expr);
4930 this->testStatement(m_variables, *m_stmt);
4934 template <typename Sig>
4935 PrecisionCase* createFuncCase (const CaseContext& context, const string& name, const Func<Sig>& func)
4937 switch (func.getOutParamIndex())
4940 return new FuncCase<Sig>(context, name, func);
4942 return new InOutFuncCase<Sig>(context, name, func);
4944 DE_FATAL("Impossible");
4952 virtual ~CaseFactory (void) {}
4953 virtual MovePtr<TestNode> createCase (const CaseContext& ctx) const = 0;
4954 virtual string getName (void) const = 0;
4955 virtual string getDesc (void) const = 0;
4958 class FuncCaseFactory : public CaseFactory
4961 virtual const FuncBase& getFunc (void) const = 0;
4962 string getName (void) const { return de::toLower(getFunc().getName()); }
4963 string getDesc (void) const { return "Function '" + getFunc().getName() + "'"; }
4966 template <typename Sig>
4967 class GenFuncCaseFactory : public CaseFactory
4970 GenFuncCaseFactory (const GenFuncs<Sig>& funcs, const string& name)
4972 , m_name (de::toLower(name))
4976 MovePtr<TestNode> createCase (const CaseContext& ctx) const
4978 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
4980 group->addChild(createFuncCase(ctx, "scalar", m_funcs.func));
4981 group->addChild(createFuncCase(ctx, "vec2", m_funcs.func2));
4982 group->addChild(createFuncCase(ctx, "vec3", m_funcs.func3));
4983 group->addChild(createFuncCase(ctx, "vec4", m_funcs.func4));
4984 return MovePtr<TestNode>(group);
4987 string getName (void) const { return m_name; }
4988 string getDesc (void) const { return "Function '" + m_funcs.func.getName() + "'"; }
4991 const GenFuncs<Sig> m_funcs;
4995 template <template <int> class GenF>
4996 class TemplateFuncCaseFactory : public FuncCaseFactory
4999 MovePtr<TestNode> createCase (const CaseContext& ctx) const
5001 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5003 group->addChild(createFuncCase(ctx, "scalar", instance<GenF<1> >()));
5004 group->addChild(createFuncCase(ctx, "vec2", instance<GenF<2> >()));
5005 group->addChild(createFuncCase(ctx, "vec3", instance<GenF<3> >()));
5006 group->addChild(createFuncCase(ctx, "vec4", instance<GenF<4> >()));
5008 return MovePtr<TestNode>(group);
5011 const FuncBase& getFunc (void) const { return instance<GenF<1> >(); }
5014 template <template <int> class GenF>
5015 class SquareMatrixFuncCaseFactory : public FuncCaseFactory
5018 MovePtr<TestNode> createCase (const CaseContext& ctx) const
5020 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5022 group->addChild(createFuncCase(ctx, "mat2", instance<GenF<2> >()));
5024 // disabled until we get reasonable results
5025 group->addChild(createFuncCase(ctx, "mat3", instance<GenF<3> >()));
5026 group->addChild(createFuncCase(ctx, "mat4", instance<GenF<4> >()));
5029 return MovePtr<TestNode>(group);
5032 const FuncBase& getFunc (void) const { return instance<GenF<2> >(); }
5035 template <template <int, int> class GenF>
5036 class MatrixFuncCaseFactory : public FuncCaseFactory
5039 MovePtr<TestNode> createCase (const CaseContext& ctx) const
5041 TestCaseGroup* const group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5043 this->addCase<2, 2>(ctx, group);
5044 this->addCase<3, 2>(ctx, group);
5045 this->addCase<4, 2>(ctx, group);
5046 this->addCase<2, 3>(ctx, group);
5047 this->addCase<3, 3>(ctx, group);
5048 this->addCase<4, 3>(ctx, group);
5049 this->addCase<2, 4>(ctx, group);
5050 this->addCase<3, 4>(ctx, group);
5051 this->addCase<4, 4>(ctx, group);
5053 return MovePtr<TestNode>(group);
5056 const FuncBase& getFunc (void) const { return instance<GenF<2,2> >(); }
5059 template <int Rows, int Cols>
5060 void addCase (const CaseContext& ctx, TestCaseGroup* group) const
5062 const char* const name = dataTypeNameOf<Matrix<float, Rows, Cols> >();
5063 group->addChild(createFuncCase(ctx, name, instance<GenF<Rows, Cols> >()));
5067 template <typename Sig>
5068 class SimpleFuncCaseFactory : public CaseFactory
5071 SimpleFuncCaseFactory (const Func<Sig>& func) : m_func(func) {}
5073 MovePtr<TestNode> createCase (const CaseContext& ctx) const { return MovePtr<TestNode>(createFuncCase(ctx, ctx.name.c_str(), m_func)); }
5074 string getName (void) const { return de::toLower(m_func.getName()); }
5075 string getDesc (void) const { return "Function '" + getName() + "'"; }
5078 const Func<Sig>& m_func;
5081 template <typename F>
5082 SharedPtr<SimpleFuncCaseFactory<typename F::Sig> > createSimpleFuncCaseFactory (void)
5084 return SharedPtr<SimpleFuncCaseFactory<typename F::Sig> >(new SimpleFuncCaseFactory<typename F::Sig>(instance<F>()));
5090 virtual ~CaseFactories (void) {}
5091 virtual const std::vector<const CaseFactory*> getFactories (void) const = 0;
5094 class BuiltinFuncs : public CaseFactories
5097 const vector<const CaseFactory*> getFactories (void) const
5099 vector<const CaseFactory*> ret;
5101 for (size_t ndx = 0; ndx < m_factories.size(); ++ndx)
5102 ret.push_back(m_factories[ndx].get());
5107 void addFactory (SharedPtr<const CaseFactory> fact) { m_factories.push_back(fact); }
5110 vector<SharedPtr<const CaseFactory> > m_factories;
5113 template <typename F>
5114 void addScalarFactory(BuiltinFuncs& funcs, string name = "")
5117 name = instance<F>().getName();
5119 funcs.addFactory(SharedPtr<const CaseFactory>(new GenFuncCaseFactory<typename F::Sig>(makeVectorizedFuncs<F>(), name)));
5122 MovePtr<const CaseFactories> createComputeOnlyBuiltinCases (void)
5124 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5126 // Tests for ES3 builtins
5128 addScalarFactory<Add>(*funcs);
5129 addScalarFactory<Sub>(*funcs);
5130 addScalarFactory<Mul>(*funcs);
5131 addScalarFactory<Div>(*funcs);
5133 addScalarFactory<Radians>(*funcs);
5134 addScalarFactory<Degrees>(*funcs);
5135 addScalarFactory<Sin>(*funcs);
5136 addScalarFactory<Cos>(*funcs);
5137 addScalarFactory<Tan>(*funcs);
5138 addScalarFactory<ASin>(*funcs);
5139 addScalarFactory<ACos>(*funcs);
5140 addScalarFactory<ATan2>(*funcs, "atan2");
5141 addScalarFactory<ATan>(*funcs);
5142 addScalarFactory<Sinh>(*funcs);
5143 addScalarFactory<Cosh>(*funcs);
5144 addScalarFactory<Tanh>(*funcs);
5145 addScalarFactory<ASinh>(*funcs);
5146 addScalarFactory<ACosh>(*funcs);
5147 addScalarFactory<ATanh>(*funcs);
5149 addScalarFactory<Pow>(*funcs);
5150 addScalarFactory<Exp>(*funcs);
5151 addScalarFactory<Log>(*funcs);
5152 addScalarFactory<Exp2>(*funcs);
5153 addScalarFactory<Log2>(*funcs);
5154 addScalarFactory<Sqrt>(*funcs);
5155 addScalarFactory<InverseSqrt>(*funcs);
5157 addScalarFactory<Abs>(*funcs);
5158 addScalarFactory<Sign>(*funcs);
5159 addScalarFactory<Floor>(*funcs);
5160 addScalarFactory<Trunc>(*funcs);
5161 addScalarFactory<Round>(*funcs);
5162 addScalarFactory<RoundEven>(*funcs);
5163 addScalarFactory<Ceil>(*funcs);
5164 addScalarFactory<Fract>(*funcs);
5165 addScalarFactory<Mod>(*funcs);
5166 funcs->addFactory(createSimpleFuncCaseFactory<Modf>());
5167 addScalarFactory<Min>(*funcs);
5168 addScalarFactory<Max>(*funcs);
5169 addScalarFactory<Clamp>(*funcs);
5170 addScalarFactory<Mix>(*funcs);
5171 addScalarFactory<Step>(*funcs);
5172 addScalarFactory<SmoothStep>(*funcs);
5174 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length>()));
5175 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance>()));
5176 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot>()));
5177 funcs->addFactory(createSimpleFuncCaseFactory<Cross>());
5178 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize>()));
5179 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward>()));
5180 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect>()));
5181 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract>()));
5184 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<MatrixCompMult>()));
5185 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct>()));
5186 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose>()));
5187 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant>()));
5188 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse>()));
5190 return MovePtr<const CaseFactories>(funcs.release());
5193 MovePtr<const CaseFactories> createCompleteBuiltinCases (void)
5195 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5197 // Tests for ES31 builtins
5198 addScalarFactory<FrExp>(*funcs);
5199 addScalarFactory<LdExp>(*funcs);
5200 addScalarFactory<Fma>(*funcs);
5202 return MovePtr<const CaseFactories>(funcs.release());
5205 struct PrecisionTestContext
5207 PrecisionTestContext (TestContext& testCtx_,
5208 const FloatFormat& highp_,
5209 const FloatFormat& mediump_,
5210 const FloatFormat& lowp_,
5211 const vector<ShaderType>& shaderTypes_,
5213 : testCtx (testCtx_)
5214 , shaderTypes (shaderTypes_)
5215 , numRandoms (numRandoms_)
5217 formats[glu::PRECISION_HIGHP] = &highp_;
5218 formats[glu::PRECISION_MEDIUMP] = &mediump_;
5219 formats[glu::PRECISION_LOWP] = &lowp_;
5222 TestContext& testCtx;
5223 const FloatFormat* formats[glu::PRECISION_LAST];
5224 vector<ShaderType> shaderTypes;
5228 TestCaseGroup* createFuncGroup (const PrecisionTestContext& ctx, const CaseFactory& factory)
5230 TestCaseGroup* const group = new TestCaseGroup(ctx.testCtx, factory.getName().c_str(), factory.getDesc().c_str());
5232 for (int precNdx = glu::PRECISION_MEDIUMP; precNdx < glu::PRECISION_LAST; ++precNdx)
5234 const Precision precision = Precision(precNdx);
5235 const string precName (glu::getPrecisionName(precision));
5236 const FloatFormat& fmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats, precNdx);
5237 const FloatFormat& highpFmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats,
5238 glu::PRECISION_HIGHP);
5240 for (size_t shaderNdx = 0; shaderNdx < ctx.shaderTypes.size(); ++shaderNdx)
5242 const ShaderType shaderType = ctx.shaderTypes[shaderNdx];
5243 const string shaderName (glu::getShaderTypeName(shaderType));
5244 const string name = precName + "_" + shaderName;
5245 const CaseContext caseCtx (name, ctx.testCtx, fmt, highpFmt,
5246 precision, shaderType, ctx.numRandoms);
5248 group->addChild(factory.createCase(caseCtx).release());
5255 void addBuiltinPrecisionTests (TestContext& testCtx,
5256 const CaseFactories& cases,
5257 const vector<ShaderType>& shaderTypes,
5258 TestCaseGroup& dstGroup)
5260 const int userRandoms = testCtx.getCommandLine().getTestIterationCount();
5261 const int defRandoms = 16384;
5262 const int numRandoms = userRandoms > 0 ? userRandoms : defRandoms;
5263 const FloatFormat highp (-126, 127, 23, true,
5264 tcu::MAYBE, // subnormals
5265 tcu::YES, // infinities
5267 // \todo [2014-04-01 lauri] Check these once Khronos bug 11840 is resolved.
5268 const FloatFormat mediump (-13, 13, 9, false);
5269 // A fixed-point format is just a floating point format with a fixed
5270 // exponent and support for subnormals.
5271 const FloatFormat lowp (0, 0, 7, false, tcu::YES);
5272 const PrecisionTestContext ctx (testCtx, highp, mediump, lowp,
5273 shaderTypes, numRandoms);
5275 for (size_t ndx = 0; ndx < cases.getFactories().size(); ++ndx)
5276 dstGroup.addChild(createFuncGroup(ctx, *cases.getFactories()[ndx]));
5279 BuiltinPrecisionTests::BuiltinPrecisionTests (tcu::TestContext& testCtx)
5280 : tcu::TestCaseGroup(testCtx, "precision", "Builtin precision tests")
5284 BuiltinPrecisionTests::~BuiltinPrecisionTests (void)
5288 void BuiltinPrecisionTests::init (void)
5290 std::vector<glu::ShaderType> shaderTypes;
5291 de::MovePtr<const CaseFactories> computeOnlyCases = createComputeOnlyBuiltinCases();
5292 de::MovePtr<const CaseFactories> completeCases = createCompleteBuiltinCases();
5294 shaderTypes.push_back(glu::SHADERTYPE_COMPUTE);
5296 addBuiltinPrecisionTests(m_testCtx,
5301 shaderTypes.clear();
5302 shaderTypes.push_back(glu::SHADERTYPE_VERTEX);
5303 shaderTypes.push_back(glu::SHADERTYPE_FRAGMENT);
5304 shaderTypes.push_back(glu::SHADERTYPE_COMPUTE);
5306 addBuiltinPrecisionTests(m_testCtx,