1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) Module
3 * -----------------------------------------------
5 * Copyright 2014 The Android Open Source Project
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 * \brief Precision and range tests for GLSL builtins and types.
23 *//*--------------------------------------------------------------------*/
25 #include "glsBuiltinPrecisionTests.hpp"
30 #include "deRandom.hpp"
31 #include "deSTLUtil.hpp"
32 #include "deStringUtil.hpp"
33 #include "deUniquePtr.hpp"
34 #include "deSharedPtr.hpp"
35 #include "deArrayUtil.hpp"
37 #include "tcuCommandLine.hpp"
38 #include "tcuFloatFormat.hpp"
39 #include "tcuInterval.hpp"
40 #include "tcuTestCase.hpp"
41 #include "tcuTestLog.hpp"
42 #include "tcuVector.hpp"
43 #include "tcuMatrix.hpp"
44 #include "tcuResultCollector.hpp"
46 #include "gluContextInfo.hpp"
47 #include "gluVarType.hpp"
48 #include "gluRenderContext.hpp"
49 #include "glwDefs.hpp"
51 #include "glsShaderExecUtil.hpp"
60 // Uncomment this to get evaluation trace dumps to std::cerr
61 // #define GLS_ENABLE_TRACE
63 // set this to true to dump even passing results
64 #define GLS_LOG_ALL_RESULTS false
70 namespace BuiltinPrecisionTests
76 using std::ostringstream;
86 using tcu::FloatFormat;
87 using tcu::MessageBuilder;
92 namespace matrix = tcu::matrix;
94 using glu::RenderContext;
97 using glu::ShaderType;
98 using glu::ContextInfo;
99 using gls::ShaderExecUtil::Symbol;
101 typedef TestCase::IterateResult IterateResult;
106 /*--------------------------------------------------------------------*//*!
107 * \brief Generic singleton creator.
109 * instance<T>() returns a reference to a unique default-constructed instance
110 * of T. This is mainly used for our GLSL function implementations: each
111 * function is implemented by an object, and each of the objects has a
112 * distinct class. It would be extremely toilsome to maintain a separate
113 * context object that contained individual instances of the function classes,
114 * so we have to resort to global singleton instances.
116 *//*--------------------------------------------------------------------*/
117 template <typename T>
118 const T& instance (void)
120 static const T s_instance = T();
124 /*--------------------------------------------------------------------*//*!
125 * \brief Dummy placeholder type for unused template parameters.
127 * In the precision tests we are dealing with functions of different arities.
128 * To minimize code duplication, we only define templates with the maximum
129 * number of arguments, currently four. If a function's arity is less than the
130 * maximum, Void us used as the type for unused arguments.
132 * Although Voids are not used at run-time, they still must be compilable, so
133 * they must support all operations that other types do.
135 *//*--------------------------------------------------------------------*/
138 typedef Void Element;
144 template <typename T>
145 explicit Void (const T&) {}
147 operator double (void) const { return TCU_NAN; }
149 // These are used to make Voids usable as containers in container-generic code.
150 Void& operator[] (int) { return *this; }
151 const Void& operator[] (int) const { return *this; }
154 ostream& operator<< (ostream& os, Void) { return os << "()"; }
156 //! Returns true for all other types except Void
157 template <typename T> bool isTypeValid (void) { return true; }
158 template <> bool isTypeValid<Void> (void) { return false; }
160 //! Utility function for getting the name of a data type.
161 //! This is used in vector and matrix constructors.
162 template <typename T>
163 const char* dataTypeNameOf (void)
165 return glu::getDataTypeName(glu::dataTypeOf<T>());
169 const char* dataTypeNameOf<Void> (void)
171 DE_FATAL("Impossible");
175 //! A hack to get Void support for VarType.
176 template <typename T>
177 VarType getVarTypeOf (Precision prec = glu::PRECISION_LAST)
179 return glu::varTypeOf<T>(prec);
183 VarType getVarTypeOf<Void> (Precision)
185 DE_FATAL("Impossible");
189 /*--------------------------------------------------------------------*//*!
190 * \brief Type traits for generalized interval types.
192 * We are trying to compute sets of acceptable values not only for
193 * float-valued expressions but also for compound values: vectors and
194 * matrices. We approximate a set of vectors as a vector of intervals and
195 * likewise for matrices.
197 * We now need generalized operations for each type and its interval
198 * approximation. These are given in the type Traits<T>.
200 * The type Traits<T>::IVal is the approximation of T: it is `Interval` for
201 * scalar types, and a vector or matrix of intervals for container types.
203 * To allow template inference to take place, there are function wrappers for
204 * the actual operations in Traits<T>. Hence we can just use:
206 * makeIVal(someFloat)
210 * Traits<float>::doMakeIVal(value)
212 *//*--------------------------------------------------------------------*/
214 template <typename T> struct Traits;
216 //! Create container from elementwise singleton values.
217 template <typename T>
218 typename Traits<T>::IVal makeIVal (const T& value)
220 return Traits<T>::doMakeIVal(value);
223 //! Elementwise union of intervals.
224 template <typename T>
225 typename Traits<T>::IVal unionIVal (const typename Traits<T>::IVal& a,
226 const typename Traits<T>::IVal& b)
228 return Traits<T>::doUnion(a, b);
231 //! Returns true iff every element of `ival` contains the corresponding element of `value`.
232 template <typename T>
233 bool contains (const typename Traits<T>::IVal& ival, const T& value)
235 return Traits<T>::doContains(ival, value);
238 //! Print out an interval with the precision of `fmt`.
239 template <typename T>
240 void printIVal (const FloatFormat& fmt, const typename Traits<T>::IVal& ival, ostream& os)
242 Traits<T>::doPrintIVal(fmt, ival, os);
245 template <typename T>
246 string intervalToString (const FloatFormat& fmt, const typename Traits<T>::IVal& ival)
249 printIVal<T>(fmt, ival, oss);
253 //! Print out a value with the precision of `fmt`.
254 template <typename T>
255 void printValue (const FloatFormat& fmt, const T& value, ostream& os)
257 Traits<T>::doPrintValue(fmt, value, os);
260 template <typename T>
261 string valueToString (const FloatFormat& fmt, const T& val)
264 printValue(fmt, val, oss);
268 //! Approximate `value` elementwise to the float precision defined in `fmt`.
269 //! The resulting interval might not be a singleton if rounding in both
270 //! directions is allowed.
271 template <typename T>
272 typename Traits<T>::IVal round (const FloatFormat& fmt, const T& value)
274 return Traits<T>::doRound(fmt, value);
277 template <typename T>
278 typename Traits<T>::IVal convert (const FloatFormat& fmt,
279 const typename Traits<T>::IVal& value)
281 return Traits<T>::doConvert(fmt, value);
284 //! Common traits for scalar types.
285 template <typename T>
288 typedef Interval IVal;
290 static Interval doMakeIVal (const T& value)
292 // Thankfully all scalar types have a well-defined conversion to `double`,
293 // hence Interval can represent their ranges without problems.
294 return Interval(double(value));
297 static Interval doUnion (const Interval& a, const Interval& b)
302 static bool doContains (const Interval& a, T value)
304 return a.contains(double(value));
307 static Interval doConvert (const FloatFormat& fmt, const IVal& ival)
309 return fmt.convert(ival);
312 static Interval doRound (const FloatFormat& fmt, T value)
314 return fmt.roundOut(double(value), false);
319 struct Traits<float> : ScalarTraits<float>
321 static void doPrintIVal (const FloatFormat& fmt,
322 const Interval& ival,
325 os << fmt.intervalToHex(ival);
328 static void doPrintValue (const FloatFormat& fmt,
332 os << fmt.floatToHex(value);
337 struct Traits<bool> : ScalarTraits<bool>
339 static void doPrintValue (const FloatFormat&,
343 os << (value != 0.0f ? "true" : "false");
346 static void doPrintIVal (const FloatFormat&,
347 const Interval& ival,
351 if (ival.contains(false))
353 if (ival.contains(false) && ival.contains(true))
355 if (ival.contains(true))
362 struct Traits<int> : ScalarTraits<int>
364 static void doPrintValue (const FloatFormat&,
371 static void doPrintIVal (const FloatFormat&,
372 const Interval& ival,
375 os << "[" << int(ival.lo()) << ", " << int(ival.hi()) << "]";
379 //! Common traits for containers, i.e. vectors and matrices.
380 //! T is the container type itself, I is the same type with interval elements.
381 template <typename T, typename I>
382 struct ContainerTraits
384 typedef typename T::Element Element;
387 static IVal doMakeIVal (const T& value)
391 for (int ndx = 0; ndx < T::SIZE; ++ndx)
392 ret[ndx] = makeIVal(value[ndx]);
397 static IVal doUnion (const IVal& a, const IVal& b)
401 for (int ndx = 0; ndx < T::SIZE; ++ndx)
402 ret[ndx] = unionIVal<Element>(a[ndx], b[ndx]);
407 static bool doContains (const IVal& ival, const T& value)
409 for (int ndx = 0; ndx < T::SIZE; ++ndx)
410 if (!contains(ival[ndx], value[ndx]))
416 static void doPrintIVal (const FloatFormat& fmt, const IVal ival, ostream& os)
420 for (int ndx = 0; ndx < T::SIZE; ++ndx)
425 printIVal<Element>(fmt, ival[ndx], os);
431 static void doPrintValue (const FloatFormat& fmt, const T& value, ostream& os)
433 os << dataTypeNameOf<T>() << "(";
435 for (int ndx = 0; ndx < T::SIZE; ++ndx)
440 printValue<Element>(fmt, value[ndx], os);
446 static IVal doConvert (const FloatFormat& fmt, const IVal& value)
450 for (int ndx = 0; ndx < T::SIZE; ++ndx)
451 ret[ndx] = convert<Element>(fmt, value[ndx]);
456 static IVal doRound (const FloatFormat& fmt, T value)
460 for (int ndx = 0; ndx < T::SIZE; ++ndx)
461 ret[ndx] = round(fmt, value[ndx]);
467 template <typename T, int Size>
468 struct Traits<Vector<T, Size> > :
469 ContainerTraits<Vector<T, Size>, Vector<typename Traits<T>::IVal, Size> >
473 template <typename T, int Rows, int Cols>
474 struct Traits<Matrix<T, Rows, Cols> > :
475 ContainerTraits<Matrix<T, Rows, Cols>, Matrix<typename Traits<T>::IVal, Rows, Cols> >
479 //! Void traits. These are just dummies, but technically valid: a Void is a
480 //! unit type with a single possible value.
486 static Void doMakeIVal (const Void& value) { return value; }
487 static Void doUnion (const Void&, const Void&) { return Void(); }
488 static bool doContains (const Void&, Void) { return true; }
489 static Void doRound (const FloatFormat&, const Void& value) { return value; }
490 static Void doConvert (const FloatFormat&, const Void& value) { return value; }
492 static void doPrintValue (const FloatFormat&, const Void&, ostream& os)
497 static void doPrintIVal (const FloatFormat&, const Void&, ostream& os)
503 //! This is needed for container-generic operations.
504 //! We want a scalar type T to be its own "one-element vector".
505 template <typename T, int Size> struct ContainerOf { typedef Vector<T, Size> Container; };
507 template <typename T> struct ContainerOf<T, 1> { typedef T Container; };
508 template <int Size> struct ContainerOf<Void, Size> { typedef Void Container; };
510 // This is a kludge that is only needed to get the ExprP::operator[] syntactic sugar to work.
511 template <typename T> struct ElementOf { typedef typename T::Element Element; };
512 template <> struct ElementOf<float> { typedef void Element; };
513 template <> struct ElementOf<bool> { typedef void Element; };
514 template <> struct ElementOf<int> { typedef void Element; };
516 /*--------------------------------------------------------------------*//*!
518 * \name Abstract syntax for expressions and statements.
520 * We represent GLSL programs as syntax objects: an Expr<T> represents an
521 * expression whose GLSL type corresponds to the C++ type T, and a Statement
522 * represents a statement.
524 * To ease memory management, we use shared pointers to refer to expressions
525 * and statements. ExprP<T> is a shared pointer to an Expr<T>, and StatementP
526 * is a shared pointer to a Statement.
530 *//*--------------------------------------------------------------------*/
537 template <typename T> class ExprP;
538 template <typename T> class Variable;
539 template <typename T> class VariableP;
540 template <typename T> class DefaultSampling;
542 typedef set<const FuncBase*> FuncSet;
544 template <typename T>
545 VariableP<T> variable (const string& name);
546 StatementP compoundStatement (const vector<StatementP>& statements);
548 /*--------------------------------------------------------------------*//*!
549 * \brief A variable environment.
551 * An Environment object maintains the mapping between variables of the
552 * abstract syntax tree and their values.
554 * \todo [2014-03-28 lauri] At least run-time type safety.
556 *//*--------------------------------------------------------------------*/
561 void bind (const Variable<T>& variable,
562 const typename Traits<T>::IVal& value)
564 deUint8* const data = new deUint8[sizeof(value)];
566 deMemcpy(data, &value, sizeof(value));
567 de::insert(m_map, variable.getName(), SharedPtr<deUint8>(data, de::ArrayDeleter<deUint8>()));
571 typename Traits<T>::IVal& lookup (const Variable<T>& variable) const
573 deUint8* const data = de::lookup(m_map, variable.getName()).get();
575 return *reinterpret_cast<typename Traits<T>::IVal*>(data);
579 map<string, SharedPtr<deUint8> > m_map;
582 /*--------------------------------------------------------------------*//*!
583 * \brief Evaluation context.
585 * The evaluation context contains everything that separates one execution of
586 * an expression from the next. Currently this means the desired floating
587 * point precision and the current variable environment.
589 *//*--------------------------------------------------------------------*/
592 EvalContext (const FloatFormat& format_,
593 Precision floatPrecision_,
597 , floatPrecision (floatPrecision_)
599 , callDepth (callDepth_) {}
602 Precision floatPrecision;
607 /*--------------------------------------------------------------------*//*!
608 * \brief Simple incremental counter.
610 * This is used to make sure that different ExpandContexts will not produce
611 * overlapping temporary names.
613 *//*--------------------------------------------------------------------*/
617 Counter (int count = 0) : m_count(count) {}
618 int operator() (void) { return m_count++; }
627 ExpandContext (Counter& symCounter) : m_symCounter(symCounter) {}
628 ExpandContext (const ExpandContext& parent)
629 : m_symCounter(parent.m_symCounter) {}
632 VariableP<T> genSym (const string& baseName)
634 return variable<T>(baseName + de::toString(m_symCounter()));
637 void addStatement (const StatementP& stmt)
639 m_statements.push_back(stmt);
642 vector<StatementP> getStatements (void) const
647 Counter& m_symCounter;
648 vector<StatementP> m_statements;
651 /*--------------------------------------------------------------------*//*!
652 * \brief A statement or declaration.
654 * Statements have no values. Instead, they are executed for their side
655 * effects only: the execute() method should modify at least one variable in
658 * As a bit of a kludge, a Statement object can also represent a declaration:
659 * when it is evaluated, it can add a variable binding to the environment
660 * instead of modifying a current one.
662 *//*--------------------------------------------------------------------*/
666 virtual ~Statement (void) { }
667 //! Execute the statement, modifying the environment of `ctx`
668 void execute (EvalContext& ctx) const { this->doExecute(ctx); }
669 void print (ostream& os) const { this->doPrint(os); }
670 //! Add the functions used in this statement to `dst`.
671 void getUsedFuncs (FuncSet& dst) const { this->doGetUsedFuncs(dst); }
674 virtual void doPrint (ostream& os) const = 0;
675 virtual void doExecute (EvalContext& ctx) const = 0;
676 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
679 ostream& operator<<(ostream& os, const Statement& stmt)
685 /*--------------------------------------------------------------------*//*!
686 * \brief Smart pointer for statements (and declarations)
688 *//*--------------------------------------------------------------------*/
689 class StatementP : public SharedPtr<const Statement>
692 typedef SharedPtr<const Statement> Super;
695 explicit StatementP (const Statement* ptr) : Super(ptr) {}
696 StatementP (const Super& ptr) : Super(ptr) {}
699 /*--------------------------------------------------------------------*//*!
702 * A statement that modifies a variable or a declaration that binds a variable.
704 *//*--------------------------------------------------------------------*/
705 template <typename T>
706 class VariableStatement : public Statement
709 VariableStatement (const VariableP<T>& variable, const ExprP<T>& value,
711 : m_variable (variable)
713 , m_isDeclaration (isDeclaration) {}
716 void doPrint (ostream& os) const
719 os << glu::declare(getVarTypeOf<T>(), m_variable->getName());
721 os << m_variable->getName();
723 os << " = " << *m_value << ";\n";
726 void doExecute (EvalContext& ctx) const
729 ctx.env.bind(*m_variable, m_value->evaluate(ctx));
731 ctx.env.lookup(*m_variable) = m_value->evaluate(ctx);
734 void doGetUsedFuncs (FuncSet& dst) const
736 m_value->getUsedFuncs(dst);
739 VariableP<T> m_variable;
741 bool m_isDeclaration;
744 template <typename T>
745 StatementP variableStatement (const VariableP<T>& variable,
746 const ExprP<T>& value,
749 return StatementP(new VariableStatement<T>(variable, value, isDeclaration));
752 template <typename T>
753 StatementP variableDeclaration (const VariableP<T>& variable, const ExprP<T>& definiens)
755 return variableStatement(variable, definiens, true);
758 template <typename T>
759 StatementP variableAssignment (const VariableP<T>& variable, const ExprP<T>& value)
761 return variableStatement(variable, value, false);
764 /*--------------------------------------------------------------------*//*!
765 * \brief A compound statement, i.e. a block.
767 * A compound statement is executed by executing its constituent statements in
770 *//*--------------------------------------------------------------------*/
771 class CompoundStatement : public Statement
774 CompoundStatement (const vector<StatementP>& statements)
775 : m_statements (statements) {}
778 void doPrint (ostream& os) const
782 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
783 os << *m_statements[ndx];
788 void doExecute (EvalContext& ctx) const
790 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
791 m_statements[ndx]->execute(ctx);
794 void doGetUsedFuncs (FuncSet& dst) const
796 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
797 m_statements[ndx]->getUsedFuncs(dst);
800 vector<StatementP> m_statements;
803 StatementP compoundStatement(const vector<StatementP>& statements)
805 return StatementP(new CompoundStatement(statements));
808 //! Common base class for all expressions regardless of their type.
812 virtual ~ExprBase (void) {}
813 void printExpr (ostream& os) const { this->doPrintExpr(os); }
815 //! Output the functions that this expression refers to
816 void getUsedFuncs (FuncSet& dst) const
818 this->doGetUsedFuncs(dst);
822 virtual void doPrintExpr (ostream&) const {}
823 virtual void doGetUsedFuncs (FuncSet&) const {}
826 //! Type-specific operations for an expression representing type T.
827 template <typename T>
828 class Expr : public ExprBase
832 typedef typename Traits<T>::IVal IVal;
834 IVal evaluate (const EvalContext& ctx) const;
837 virtual IVal doEvaluate (const EvalContext& ctx) const = 0;
840 //! Evaluate an expression with the given context, optionally tracing the calls to stderr.
841 template <typename T>
842 typename Traits<T>::IVal Expr<T>::evaluate (const EvalContext& ctx) const
844 #ifdef GLS_ENABLE_TRACE
845 static const FloatFormat highpFmt (-126, 127, 23, true,
849 EvalContext newCtx (ctx.format, ctx.floatPrecision,
850 ctx.env, ctx.callDepth + 1);
851 const IVal ret = this->doEvaluate(newCtx);
853 if (isTypeValid<T>())
855 std::cerr << string(ctx.callDepth, ' ');
856 this->printExpr(std::cerr);
857 std::cerr << " -> " << intervalToString<T>(highpFmt, ret) << std::endl;
861 return this->doEvaluate(ctx);
865 template <typename T>
866 class ExprPBase : public SharedPtr<const Expr<T> >
871 ostream& operator<< (ostream& os, const ExprBase& expr)
877 /*--------------------------------------------------------------------*//*!
878 * \brief Shared pointer to an expression of a container type.
880 * Container types (i.e. vectors and matrices) support the subscription
881 * operator. This class provides a bit of syntactic sugar to allow us to use
882 * the C++ subscription operator to create a subscription expression.
883 *//*--------------------------------------------------------------------*/
884 template <typename T>
885 class ContainerExprPBase : public ExprPBase<T>
888 ExprP<typename T::Element> operator[] (int i) const;
891 template <typename T>
892 class ExprP : public ExprPBase<T> {};
894 // We treat Voids as containers since the dummy parameters in generalized
895 // vector functions are represented as Voids.
897 class ExprP<Void> : public ContainerExprPBase<Void> {};
899 template <typename T, int Size>
900 class ExprP<Vector<T, Size> > : public ContainerExprPBase<Vector<T, Size> > {};
902 template <typename T, int Rows, int Cols>
903 class ExprP<Matrix<T, Rows, Cols> > : public ContainerExprPBase<Matrix<T, Rows, Cols> > {};
905 template <typename T> ExprP<T> exprP (void)
910 template <typename T>
911 ExprP<T> exprP (const SharedPtr<const Expr<T> >& ptr)
914 static_cast<SharedPtr<const Expr<T> >&>(ret) = ptr;
918 template <typename T>
919 ExprP<T> exprP (const Expr<T>* ptr)
921 return exprP(SharedPtr<const Expr<T> >(ptr));
924 /*--------------------------------------------------------------------*//*!
925 * \brief A shared pointer to a variable expression.
927 * This is just a narrowing of ExprP for the operations that require a variable
928 * instead of an arbitrary expression.
930 *//*--------------------------------------------------------------------*/
931 template <typename T>
932 class VariableP : public SharedPtr<const Variable<T> >
935 typedef SharedPtr<const Variable<T> > Super;
936 explicit VariableP (const Variable<T>* ptr) : Super(ptr) {}
938 VariableP (const Super& ptr) : Super(ptr) {}
940 operator ExprP<T> (void) const { return exprP(SharedPtr<const Expr<T> >(*this)); }
943 /*--------------------------------------------------------------------*//*!
944 * \name Syntactic sugar operators for expressions.
948 * These operators allow the use of C++ syntax to construct GLSL expressions
949 * containing operators: e.g. "a+b" creates an addition expression with
950 * operands a and b, and so on.
952 *//*--------------------------------------------------------------------*/
953 ExprP<float> operator-(const ExprP<float>& arg0);
954 ExprP<float> operator+(const ExprP<float>& arg0,
955 const ExprP<float>& arg1);
956 ExprP<float> operator-(const ExprP<float>& arg0,
957 const ExprP<float>& arg1);
958 ExprP<float> operator*(const ExprP<float>& arg0,
959 const ExprP<float>& arg1);
960 ExprP<float> operator/(const ExprP<float>& arg0,
961 const ExprP<float>& arg1);
963 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0);
965 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
966 const ExprP<float>& arg1);
968 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
969 const ExprP<Vector<float, Size> >& arg1);
971 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
972 const ExprP<Vector<float, Size> >& arg1);
973 template<int Left, int Mid, int Right>
974 ExprP<Matrix<float, Left, Right> > operator* (const ExprP<Matrix<float, Left, Mid> >& left,
975 const ExprP<Matrix<float, Mid, Right> >& right);
976 template<int Rows, int Cols>
977 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
978 const ExprP<Matrix<float, Rows, Cols> >& right);
979 template<int Rows, int Cols>
980 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
981 const ExprP<Vector<float, Rows> >& right);
982 template<int Rows, int Cols>
983 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
984 const ExprP<float>& right);
985 template<int Rows, int Cols>
986 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
987 const ExprP<Matrix<float, Rows, Cols> >& right);
988 template<int Rows, int Cols>
989 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat);
993 /*--------------------------------------------------------------------*//*!
994 * \brief Variable expression.
996 * A variable is evaluated by looking up its range of possible values from an
998 *//*--------------------------------------------------------------------*/
999 template <typename T>
1000 class Variable : public Expr<T>
1003 typedef typename Expr<T>::IVal IVal;
1005 Variable (const string& name) : m_name (name) {}
1006 string getName (void) const { return m_name; }
1009 void doPrintExpr (ostream& os) const { os << m_name; }
1010 IVal doEvaluate (const EvalContext& ctx) const
1012 return ctx.env.lookup<T>(*this);
1019 template <typename T>
1020 VariableP<T> variable (const string& name)
1022 return VariableP<T>(new Variable<T>(name));
1025 template <typename T>
1026 VariableP<T> bindExpression (const string& name, ExpandContext& ctx, const ExprP<T>& expr)
1028 VariableP<T> var = ctx.genSym<T>(name);
1029 ctx.addStatement(variableDeclaration(var, expr));
1033 /*--------------------------------------------------------------------*//*!
1034 * \brief Constant expression.
1036 * A constant is evaluated by rounding it to a set of possible values allowed
1037 * by the current floating point precision.
1038 *//*--------------------------------------------------------------------*/
1039 template <typename T>
1040 class Constant : public Expr<T>
1043 typedef typename Expr<T>::IVal IVal;
1045 Constant (const T& value) : m_value(value) {}
1048 void doPrintExpr (ostream& os) const { os << m_value; }
1049 IVal doEvaluate (const EvalContext&) const { return makeIVal(m_value); }
1055 template <typename T>
1056 ExprP<T> constant (const T& value)
1058 return exprP(new Constant<T>(value));
1061 //! Return a reference to a singleton void constant.
1062 const ExprP<Void>& voidP (void)
1064 static const ExprP<Void> singleton = constant(Void());
1069 /*--------------------------------------------------------------------*//*!
1070 * \brief Four-element tuple.
1072 * This is used for various things where we need one thing for each possible
1073 * function parameter. Currently the maximum supported number of parameters is
1075 *//*--------------------------------------------------------------------*/
1076 template <typename T0 = Void, typename T1 = Void, typename T2 = Void, typename T3 = Void>
1079 explicit Tuple4 (const T0& e0 = T0(),
1080 const T1& e1 = T1(),
1081 const T2& e2 = T2(),
1082 const T3& e3 = T3())
1096 /*--------------------------------------------------------------------*//*!
1097 * \brief Function signature.
1099 * This is a purely compile-time structure used to bundle all types in a
1100 * function signature together. This makes passing the signature around in
1101 * templates easier, since we only need to take and pass a single Sig instead
1102 * of a bunch of parameter types and a return type.
1104 *//*--------------------------------------------------------------------*/
1105 template <typename R,
1106 typename P0 = Void, typename P1 = Void,
1107 typename P2 = Void, typename P3 = Void>
1115 typedef typename Traits<Ret>::IVal IRet;
1116 typedef typename Traits<Arg0>::IVal IArg0;
1117 typedef typename Traits<Arg1>::IVal IArg1;
1118 typedef typename Traits<Arg2>::IVal IArg2;
1119 typedef typename Traits<Arg3>::IVal IArg3;
1121 typedef Tuple4< const Arg0&, const Arg1&, const Arg2&, const Arg3&> Args;
1122 typedef Tuple4< const IArg0&, const IArg1&, const IArg2&, const IArg3&> IArgs;
1123 typedef Tuple4< ExprP<Arg0>, ExprP<Arg1>, ExprP<Arg2>, ExprP<Arg3> > ArgExprs;
1126 typedef vector<const ExprBase*> BaseArgExprs;
1128 /*--------------------------------------------------------------------*//*!
1129 * \brief Type-independent operations for function objects.
1131 *//*--------------------------------------------------------------------*/
1135 virtual ~FuncBase (void) {}
1136 virtual string getName (void) const = 0;
1137 //! Name of extension that this function requires, or empty.
1138 virtual string getRequiredExtension (void) const { return ""; }
1139 virtual void print (ostream&,
1140 const BaseArgExprs&) const = 0;
1141 //! Index of output parameter, or -1 if none of the parameters is output.
1142 virtual int getOutParamIndex (void) const { return -1; }
1144 void printDefinition (ostream& os) const
1146 doPrintDefinition(os);
1149 void getUsedFuncs (FuncSet& dst) const
1151 this->doGetUsedFuncs(dst);
1155 virtual void doPrintDefinition (ostream& os) const = 0;
1156 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
1159 typedef Tuple4<string, string, string, string> ParamNames;
1161 /*--------------------------------------------------------------------*//*!
1162 * \brief Function objects.
1164 * Each Func object represents a GLSL function. It can be applied to interval
1165 * arguments, and it returns the an interval that is a conservative
1166 * approximation of the image of the GLSL function over the argument
1167 * intervals. That is, it is given a set of possible arguments and it returns
1168 * the set of possible values.
1170 *//*--------------------------------------------------------------------*/
1171 template <typename Sig_>
1172 class Func : public FuncBase
1176 typedef typename Sig::Ret Ret;
1177 typedef typename Sig::Arg0 Arg0;
1178 typedef typename Sig::Arg1 Arg1;
1179 typedef typename Sig::Arg2 Arg2;
1180 typedef typename Sig::Arg3 Arg3;
1181 typedef typename Sig::IRet IRet;
1182 typedef typename Sig::IArg0 IArg0;
1183 typedef typename Sig::IArg1 IArg1;
1184 typedef typename Sig::IArg2 IArg2;
1185 typedef typename Sig::IArg3 IArg3;
1186 typedef typename Sig::Args Args;
1187 typedef typename Sig::IArgs IArgs;
1188 typedef typename Sig::ArgExprs ArgExprs;
1190 void print (ostream& os,
1191 const BaseArgExprs& args) const
1193 this->doPrint(os, args);
1196 IRet apply (const EvalContext& ctx,
1197 const IArg0& arg0 = IArg0(),
1198 const IArg1& arg1 = IArg1(),
1199 const IArg2& arg2 = IArg2(),
1200 const IArg3& arg3 = IArg3()) const
1202 return this->applyArgs(ctx, IArgs(arg0, arg1, arg2, arg3));
1204 IRet applyArgs (const EvalContext& ctx,
1205 const IArgs& args) const
1207 return this->doApply(ctx, args);
1209 ExprP<Ret> operator() (const ExprP<Arg0>& arg0 = voidP(),
1210 const ExprP<Arg1>& arg1 = voidP(),
1211 const ExprP<Arg2>& arg2 = voidP(),
1212 const ExprP<Arg3>& arg3 = voidP()) const;
1214 const ParamNames& getParamNames (void) const
1216 return this->doGetParamNames();
1220 virtual IRet doApply (const EvalContext&,
1221 const IArgs&) const = 0;
1222 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1224 os << getName() << "(";
1226 if (isTypeValid<Arg0>())
1229 if (isTypeValid<Arg1>())
1230 os << ", " << *args[1];
1232 if (isTypeValid<Arg2>())
1233 os << ", " << *args[2];
1235 if (isTypeValid<Arg3>())
1236 os << ", " << *args[3];
1241 virtual const ParamNames& doGetParamNames (void) const
1243 static ParamNames names ("a", "b", "c", "d");
1248 template <typename Sig>
1249 class Apply : public Expr<typename Sig::Ret>
1252 typedef typename Sig::Ret Ret;
1253 typedef typename Sig::Arg0 Arg0;
1254 typedef typename Sig::Arg1 Arg1;
1255 typedef typename Sig::Arg2 Arg2;
1256 typedef typename Sig::Arg3 Arg3;
1257 typedef typename Expr<Ret>::Val Val;
1258 typedef typename Expr<Ret>::IVal IVal;
1259 typedef Func<Sig> ApplyFunc;
1260 typedef typename ApplyFunc::ArgExprs ArgExprs;
1262 Apply (const ApplyFunc& func,
1263 const ExprP<Arg0>& arg0 = voidP(),
1264 const ExprP<Arg1>& arg1 = voidP(),
1265 const ExprP<Arg2>& arg2 = voidP(),
1266 const ExprP<Arg3>& arg3 = voidP())
1268 m_args (arg0, arg1, arg2, arg3) {}
1270 Apply (const ApplyFunc& func,
1271 const ArgExprs& args)
1275 void doPrintExpr (ostream& os) const
1278 args.push_back(m_args.a.get());
1279 args.push_back(m_args.b.get());
1280 args.push_back(m_args.c.get());
1281 args.push_back(m_args.d.get());
1282 m_func.print(os, args);
1285 IVal doEvaluate (const EvalContext& ctx) const
1287 return m_func.apply(ctx,
1288 m_args.a->evaluate(ctx), m_args.b->evaluate(ctx),
1289 m_args.c->evaluate(ctx), m_args.d->evaluate(ctx));
1292 void doGetUsedFuncs (FuncSet& dst) const
1294 m_func.getUsedFuncs(dst);
1295 m_args.a->getUsedFuncs(dst);
1296 m_args.b->getUsedFuncs(dst);
1297 m_args.c->getUsedFuncs(dst);
1298 m_args.d->getUsedFuncs(dst);
1301 const ApplyFunc& m_func;
1305 template<typename T>
1306 class Alternatives : public Func<Signature<T, T, T> >
1309 typedef typename Alternatives::Sig Sig;
1312 typedef typename Alternatives::IRet IRet;
1313 typedef typename Alternatives::IArgs IArgs;
1315 virtual string getName (void) const { return "alternatives"; }
1316 virtual void doPrintDefinition (std::ostream&) const {}
1317 void doGetUsedFuncs (FuncSet&) const {}
1319 virtual IRet doApply (const EvalContext&, const IArgs& args) const
1321 return unionIVal<T>(args.a, args.b);
1324 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1326 os << "{" << *args[0] << " | " << *args[1] << "}";
1330 template <typename Sig>
1331 ExprP<typename Sig::Ret> createApply (const Func<Sig>& func,
1332 const typename Func<Sig>::ArgExprs& args)
1334 return exprP(new Apply<Sig>(func, args));
1337 template <typename Sig>
1338 ExprP<typename Sig::Ret> createApply (
1339 const Func<Sig>& func,
1340 const ExprP<typename Sig::Arg0>& arg0 = voidP(),
1341 const ExprP<typename Sig::Arg1>& arg1 = voidP(),
1342 const ExprP<typename Sig::Arg2>& arg2 = voidP(),
1343 const ExprP<typename Sig::Arg3>& arg3 = voidP())
1345 return exprP(new Apply<Sig>(func, arg0, arg1, arg2, arg3));
1348 template <typename Sig>
1349 ExprP<typename Sig::Ret> Func<Sig>::operator() (const ExprP<typename Sig::Arg0>& arg0,
1350 const ExprP<typename Sig::Arg1>& arg1,
1351 const ExprP<typename Sig::Arg2>& arg2,
1352 const ExprP<typename Sig::Arg3>& arg3) const
1354 return createApply(*this, arg0, arg1, arg2, arg3);
1357 template <typename F>
1358 ExprP<typename F::Ret> app (const ExprP<typename F::Arg0>& arg0 = voidP(),
1359 const ExprP<typename F::Arg1>& arg1 = voidP(),
1360 const ExprP<typename F::Arg2>& arg2 = voidP(),
1361 const ExprP<typename F::Arg3>& arg3 = voidP())
1363 return createApply(instance<F>(), arg0, arg1, arg2, arg3);
1366 template <typename F>
1367 typename F::IRet call (const EvalContext& ctx,
1368 const typename F::IArg0& arg0 = Void(),
1369 const typename F::IArg1& arg1 = Void(),
1370 const typename F::IArg2& arg2 = Void(),
1371 const typename F::IArg3& arg3 = Void())
1373 return instance<F>().apply(ctx, arg0, arg1, arg2, arg3);
1376 template <typename T>
1377 ExprP<T> alternatives (const ExprP<T>& arg0,
1378 const ExprP<T>& arg1)
1380 return createApply<typename Alternatives<T>::Sig>(instance<Alternatives<T> >(), arg0, arg1);
1383 template <typename Sig>
1384 class ApplyVar : public Apply<Sig>
1387 typedef typename Sig::Ret Ret;
1388 typedef typename Sig::Arg0 Arg0;
1389 typedef typename Sig::Arg1 Arg1;
1390 typedef typename Sig::Arg2 Arg2;
1391 typedef typename Sig::Arg3 Arg3;
1392 typedef typename Expr<Ret>::Val Val;
1393 typedef typename Expr<Ret>::IVal IVal;
1394 typedef Func<Sig> ApplyFunc;
1395 typedef typename ApplyFunc::ArgExprs ArgExprs;
1397 ApplyVar (const ApplyFunc& func,
1398 const VariableP<Arg0>& arg0,
1399 const VariableP<Arg1>& arg1,
1400 const VariableP<Arg2>& arg2,
1401 const VariableP<Arg3>& arg3)
1402 : Apply<Sig> (func, arg0, arg1, arg2, arg3) {}
1404 IVal doEvaluate (const EvalContext& ctx) const
1406 const Variable<Arg0>& var0 = static_cast<const Variable<Arg0>&>(*this->m_args.a);
1407 const Variable<Arg1>& var1 = static_cast<const Variable<Arg1>&>(*this->m_args.b);
1408 const Variable<Arg2>& var2 = static_cast<const Variable<Arg2>&>(*this->m_args.c);
1409 const Variable<Arg3>& var3 = static_cast<const Variable<Arg3>&>(*this->m_args.d);
1410 return this->m_func.apply(ctx,
1411 ctx.env.lookup(var0), ctx.env.lookup(var1),
1412 ctx.env.lookup(var2), ctx.env.lookup(var3));
1416 template <typename Sig>
1417 ExprP<typename Sig::Ret> applyVar (const Func<Sig>& func,
1418 const VariableP<typename Sig::Arg0>& arg0,
1419 const VariableP<typename Sig::Arg1>& arg1,
1420 const VariableP<typename Sig::Arg2>& arg2,
1421 const VariableP<typename Sig::Arg3>& arg3)
1423 return exprP(new ApplyVar<Sig>(func, arg0, arg1, arg2, arg3));
1426 template <typename Sig_>
1427 class DerivedFunc : public Func<Sig_>
1430 typedef typename DerivedFunc::ArgExprs ArgExprs;
1431 typedef typename DerivedFunc::IRet IRet;
1432 typedef typename DerivedFunc::IArgs IArgs;
1433 typedef typename DerivedFunc::Ret Ret;
1434 typedef typename DerivedFunc::Arg0 Arg0;
1435 typedef typename DerivedFunc::Arg1 Arg1;
1436 typedef typename DerivedFunc::Arg2 Arg2;
1437 typedef typename DerivedFunc::Arg3 Arg3;
1438 typedef typename DerivedFunc::IArg0 IArg0;
1439 typedef typename DerivedFunc::IArg1 IArg1;
1440 typedef typename DerivedFunc::IArg2 IArg2;
1441 typedef typename DerivedFunc::IArg3 IArg3;
1444 void doPrintDefinition (ostream& os) const
1446 const ParamNames& paramNames = this->getParamNames();
1450 os << dataTypeNameOf<Ret>() << " " << this->getName()
1452 if (isTypeValid<Arg0>())
1453 os << dataTypeNameOf<Arg0>() << " " << paramNames.a;
1454 if (isTypeValid<Arg1>())
1455 os << ", " << dataTypeNameOf<Arg1>() << " " << paramNames.b;
1456 if (isTypeValid<Arg2>())
1457 os << ", " << dataTypeNameOf<Arg2>() << " " << paramNames.c;
1458 if (isTypeValid<Arg3>())
1459 os << ", " << dataTypeNameOf<Arg3>() << " " << paramNames.d;
1462 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1464 os << "return " << *m_ret << ";\n";
1468 IRet doApply (const EvalContext& ctx,
1469 const IArgs& args) const
1472 IArgs& mutArgs = const_cast<IArgs&>(args);
1477 funEnv.bind(*m_var0, args.a);
1478 funEnv.bind(*m_var1, args.b);
1479 funEnv.bind(*m_var2, args.c);
1480 funEnv.bind(*m_var3, args.d);
1483 EvalContext funCtx(ctx.format, ctx.floatPrecision, funEnv, ctx.callDepth);
1485 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1486 m_body[ndx]->execute(funCtx);
1488 ret = m_ret->evaluate(funCtx);
1491 // \todo [lauri] Store references instead of values in environment
1492 const_cast<IArg0&>(mutArgs.a) = funEnv.lookup(*m_var0);
1493 const_cast<IArg1&>(mutArgs.b) = funEnv.lookup(*m_var1);
1494 const_cast<IArg2&>(mutArgs.c) = funEnv.lookup(*m_var2);
1495 const_cast<IArg3&>(mutArgs.d) = funEnv.lookup(*m_var3);
1500 void doGetUsedFuncs (FuncSet& dst) const
1503 if (dst.insert(this).second)
1505 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1506 m_body[ndx]->getUsedFuncs(dst);
1507 m_ret->getUsedFuncs(dst);
1511 virtual ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args_) const = 0;
1513 // These are transparently initialized when first needed. They cannot be
1514 // initialized in the constructor because they depend on the doExpand
1515 // method of the subclass.
1517 mutable VariableP<Arg0> m_var0;
1518 mutable VariableP<Arg1> m_var1;
1519 mutable VariableP<Arg2> m_var2;
1520 mutable VariableP<Arg3> m_var3;
1521 mutable vector<StatementP> m_body;
1522 mutable ExprP<Ret> m_ret;
1526 void initialize (void) const
1530 const ParamNames& paramNames = this->getParamNames();
1532 ExpandContext ctx (symCounter);
1535 args.a = m_var0 = variable<Arg0>(paramNames.a);
1536 args.b = m_var1 = variable<Arg1>(paramNames.b);
1537 args.c = m_var2 = variable<Arg2>(paramNames.c);
1538 args.d = m_var3 = variable<Arg3>(paramNames.d);
1540 m_ret = this->doExpand(ctx, args);
1541 m_body = ctx.getStatements();
1546 template <typename Sig>
1547 class PrimitiveFunc : public Func<Sig>
1550 typedef typename PrimitiveFunc::Ret Ret;
1551 typedef typename PrimitiveFunc::ArgExprs ArgExprs;
1554 void doPrintDefinition (ostream&) const {}
1555 void doGetUsedFuncs (FuncSet&) const {}
1558 template <typename T>
1559 class Cond : public PrimitiveFunc<Signature<T, bool, T, T> >
1562 typedef typename Cond::IArgs IArgs;
1563 typedef typename Cond::IRet IRet;
1565 string getName (void) const
1572 void doPrint (ostream& os, const BaseArgExprs& args) const
1574 os << "(" << *args[0] << " ? " << *args[1] << " : " << *args[2] << ")";
1577 IRet doApply (const EvalContext&, const IArgs& iargs)const
1581 if (iargs.a.contains(true))
1582 ret = unionIVal<T>(ret, iargs.b);
1584 if (iargs.a.contains(false))
1585 ret = unionIVal<T>(ret, iargs.c);
1591 template <typename T>
1592 class CompareOperator : public PrimitiveFunc<Signature<bool, T, T> >
1595 typedef typename CompareOperator::IArgs IArgs;
1596 typedef typename CompareOperator::IArg0 IArg0;
1597 typedef typename CompareOperator::IArg1 IArg1;
1598 typedef typename CompareOperator::IRet IRet;
1601 void doPrint (ostream& os, const BaseArgExprs& args) const
1603 os << "(" << *args[0] << getSymbol() << *args[1] << ")";
1606 Interval doApply (const EvalContext&, const IArgs& iargs) const
1608 const IArg0& arg0 = iargs.a;
1609 const IArg1& arg1 = iargs.b;
1612 if (canSucceed(arg0, arg1))
1614 if (canFail(arg0, arg1))
1620 virtual string getSymbol (void) const = 0;
1621 virtual bool canSucceed (const IArg0&, const IArg1&) const = 0;
1622 virtual bool canFail (const IArg0&, const IArg1&) const = 0;
1625 template <typename T>
1626 class LessThan : public CompareOperator<T>
1629 string getName (void) const { return "lessThan"; }
1632 string getSymbol (void) const { return "<"; }
1634 bool canSucceed (const Interval& a, const Interval& b) const
1636 return (a.lo() < b.hi());
1639 bool canFail (const Interval& a, const Interval& b) const
1641 return !(a.hi() < b.lo());
1645 template <typename T>
1646 ExprP<bool> operator< (const ExprP<T>& a, const ExprP<T>& b)
1648 return app<LessThan<T> >(a, b);
1651 template <typename T>
1652 ExprP<T> cond (const ExprP<bool>& test,
1653 const ExprP<T>& consequent,
1654 const ExprP<T>& alternative)
1656 return app<Cond<T> >(test, consequent, alternative);
1659 /*--------------------------------------------------------------------*//*!
1663 *//*--------------------------------------------------------------------*/
1665 class FloatFunc1 : public PrimitiveFunc<Signature<float, float> >
1668 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1670 return this->applyMonotone(ctx, iargs.a);
1673 Interval applyMonotone (const EvalContext& ctx, const Interval& iarg0) const
1677 TCU_INTERVAL_APPLY_MONOTONE1(ret, arg0, iarg0, val,
1678 TCU_SET_INTERVAL(val, point,
1679 point = this->applyPoint(ctx, arg0)));
1681 ret |= innerExtrema(ctx, iarg0);
1682 ret &= (this->getCodomain() | TCU_NAN);
1684 return ctx.format.convert(ret);
1687 virtual Interval innerExtrema (const EvalContext&, const Interval&) const
1689 return Interval(); // empty interval, i.e. no extrema
1692 virtual Interval applyPoint (const EvalContext& ctx, double arg0) const
1694 const double exact = this->applyExact(arg0);
1695 const double prec = this->precision(ctx, exact, arg0);
1697 return exact + Interval(-prec, prec);
1700 virtual double applyExact (double) const
1702 TCU_THROW(InternalError, "Cannot apply");
1705 virtual Interval getCodomain (void) const
1707 return Interval::unbounded(true);
1710 virtual double precision (const EvalContext& ctx, double, double) const = 0;
1713 class CFloatFunc1 : public FloatFunc1
1716 CFloatFunc1 (const string& name, DoubleFunc1& func)
1717 : m_name(name), m_func(func) {}
1719 string getName (void) const { return m_name; }
1722 double applyExact (double x) const { return m_func(x); }
1724 const string m_name;
1725 DoubleFunc1& m_func;
1728 class FloatFunc2 : public PrimitiveFunc<Signature<float, float, float> >
1731 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1733 return this->applyMonotone(ctx, iargs.a, iargs.b);
1736 Interval applyMonotone (const EvalContext& ctx,
1738 const Interval& yi) const
1742 TCU_INTERVAL_APPLY_MONOTONE2(reti, x, xi, y, yi, ret,
1743 TCU_SET_INTERVAL(ret, point,
1744 point = this->applyPoint(ctx, x, y)));
1745 reti |= innerExtrema(ctx, xi, yi);
1746 reti &= (this->getCodomain() | TCU_NAN);
1748 return ctx.format.convert(reti);
1751 virtual Interval innerExtrema (const EvalContext&,
1753 const Interval&) const
1755 return Interval(); // empty interval, i.e. no extrema
1758 virtual Interval applyPoint (const EvalContext& ctx,
1762 const double exact = this->applyExact(x, y);
1763 const double prec = this->precision(ctx, exact, x, y);
1765 return exact + Interval(-prec, prec);
1768 virtual double applyExact (double, double) const
1770 TCU_THROW(InternalError, "Cannot apply");
1773 virtual Interval getCodomain (void) const
1775 return Interval::unbounded(true);
1778 virtual double precision (const EvalContext& ctx,
1781 double y) const = 0;
1784 class CFloatFunc2 : public FloatFunc2
1787 CFloatFunc2 (const string& name,
1794 string getName (void) const { return m_name; }
1797 double applyExact (double x, double y) const { return m_func(x, y); }
1799 const string m_name;
1800 DoubleFunc2& m_func;
1803 class InfixOperator : public FloatFunc2
1806 virtual string getSymbol (void) const = 0;
1808 void doPrint (ostream& os, const BaseArgExprs& args) const
1810 os << "(" << *args[0] << " " << getSymbol() << " " << *args[1] << ")";
1813 Interval applyPoint (const EvalContext& ctx,
1817 const double exact = this->applyExact(x, y);
1819 // Allow either representable number on both sides of the exact value,
1820 // but require exactly representable values to be preserved.
1821 return ctx.format.roundOut(exact, !deIsInf(x) && !deIsInf(y));
1824 double precision (const EvalContext&, double, double, double) const
1830 class FloatFunc3 : public PrimitiveFunc<Signature<float, float, float, float> >
1833 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1835 return this->applyMonotone(ctx, iargs.a, iargs.b, iargs.c);
1838 Interval applyMonotone (const EvalContext& ctx,
1841 const Interval& zi) const
1844 TCU_INTERVAL_APPLY_MONOTONE3(reti, x, xi, y, yi, z, zi, ret,
1845 TCU_SET_INTERVAL(ret, point,
1846 point = this->applyPoint(ctx, x, y, z)));
1847 return ctx.format.convert(reti);
1850 virtual Interval applyPoint (const EvalContext& ctx,
1855 const double exact = this->applyExact(x, y, z);
1856 const double prec = this->precision(ctx, exact, x, y, z);
1857 return exact + Interval(-prec, prec);
1860 virtual double applyExact (double, double, double) const
1862 TCU_THROW(InternalError, "Cannot apply");
1865 virtual double precision (const EvalContext& ctx,
1869 double z) const = 0;
1872 // We define syntactic sugar functions for expression constructors. Since
1873 // these have the same names as ordinary mathematical operations (sin, log
1874 // etc.), it's better to give them a dedicated namespace.
1878 using namespace tcu;
1880 class Add : public InfixOperator
1883 string getName (void) const { return "add"; }
1884 string getSymbol (void) const { return "+"; }
1886 Interval doApply (const EvalContext& ctx,
1887 const IArgs& iargs) const
1889 // Fast-path for common case
1890 if (iargs.a.isOrdinary() && iargs.b.isOrdinary())
1893 TCU_SET_INTERVAL_BOUNDS(ret, sum,
1894 sum = iargs.a.lo() + iargs.b.lo(),
1895 sum = iargs.a.hi() + iargs.b.hi());
1896 return ctx.format.convert(ctx.format.roundOut(ret, true));
1898 return this->applyMonotone(ctx, iargs.a, iargs.b);
1902 double applyExact (double x, double y) const { return x + y; }
1905 class Mul : public InfixOperator
1908 string getName (void) const { return "mul"; }
1909 string getSymbol (void) const { return "*"; }
1911 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1913 Interval a = iargs.a;
1914 Interval b = iargs.b;
1916 // Fast-path for common case
1917 if (a.isOrdinary() && b.isOrdinary())
1925 if (a.lo() >= 0 && b.lo() >= 0)
1927 TCU_SET_INTERVAL_BOUNDS(ret, prod,
1928 prod = iargs.a.lo() * iargs.b.lo(),
1929 prod = iargs.a.hi() * iargs.b.hi());
1930 return ctx.format.convert(ctx.format.roundOut(ret, true));
1932 if (a.lo() >= 0 && b.hi() <= 0)
1934 TCU_SET_INTERVAL_BOUNDS(ret, prod,
1935 prod = iargs.a.hi() * iargs.b.lo(),
1936 prod = iargs.a.lo() * iargs.b.hi());
1937 return ctx.format.convert(ctx.format.roundOut(ret, true));
1940 return this->applyMonotone(ctx, iargs.a, iargs.b);
1944 double applyExact (double x, double y) const { return x * y; }
1946 Interval innerExtrema(const EvalContext&, const Interval& xi, const Interval& yi) const
1948 if (((xi.contains(-TCU_INFINITY) || xi.contains(TCU_INFINITY)) && yi.contains(0.0)) ||
1949 ((yi.contains(-TCU_INFINITY) || yi.contains(TCU_INFINITY)) && xi.contains(0.0)))
1950 return Interval(TCU_NAN);
1956 class Sub : public InfixOperator
1959 string getName (void) const { return "sub"; }
1960 string getSymbol (void) const { return "-"; }
1962 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1964 // Fast-path for common case
1965 if (iargs.a.isOrdinary() && iargs.b.isOrdinary())
1969 TCU_SET_INTERVAL_BOUNDS(ret, diff,
1970 diff = iargs.a.lo() - iargs.b.hi(),
1971 diff = iargs.a.hi() - iargs.b.lo());
1972 return ctx.format.convert(ctx.format.roundOut(ret, true));
1977 return this->applyMonotone(ctx, iargs.a, iargs.b);
1982 double applyExact (double x, double y) const { return x - y; }
1985 class Negate : public FloatFunc1
1988 string getName (void) const { return "_negate"; }
1989 void doPrint (ostream& os, const BaseArgExprs& args) const { os << "-" << *args[0]; }
1992 double precision (const EvalContext&, double, double) const { return 0.0; }
1993 double applyExact (double x) const { return -x; }
1996 class Div : public InfixOperator
1999 string getName (void) const { return "div"; }
2002 string getSymbol (void) const { return "/"; }
2004 Interval innerExtrema (const EvalContext&,
2005 const Interval& nom,
2006 const Interval& den) const
2010 if (den.contains(0.0))
2012 if (nom.contains(0.0))
2015 if (nom.lo() < 0.0 || nom.hi() > 0.0)
2016 ret |= Interval::unbounded();
2022 double applyExact (double x, double y) const { return x / y; }
2024 Interval applyPoint (const EvalContext& ctx, double x, double y) const
2026 Interval ret = FloatFunc2::applyPoint(ctx, x, y);
2028 if (!deIsInf(x) && !deIsInf(y) && y != 0.0)
2030 const Interval dst = ctx.format.convert(ret);
2031 if (dst.contains(-TCU_INFINITY)) ret |= -ctx.format.getMaxValue();
2032 if (dst.contains(+TCU_INFINITY)) ret |= +ctx.format.getMaxValue();
2038 double precision (const EvalContext& ctx, double ret, double, double den) const
2040 const FloatFormat& fmt = ctx.format;
2042 // \todo [2014-03-05 lauri] Check that the limits in GLSL 3.10 are actually correct.
2043 // For now, we assume that division's precision is 2.5 ULP when the value is within
2044 // [2^MINEXP, 2^MAXEXP-1]
2047 return 0.0; // Result must be exactly inf
2048 else if (de::inBounds(deAbs(den),
2049 deLdExp(1.0, fmt.getMinExp()),
2050 deLdExp(1.0, fmt.getMaxExp() - 1)))
2051 return fmt.ulp(ret, 2.5);
2053 return TCU_INFINITY; // Can be any number, but must be a number.
2057 class InverseSqrt : public FloatFunc1
2060 string getName (void) const { return "inversesqrt"; }
2063 double applyExact (double x) const { return 1.0 / deSqrt(x); }
2065 double precision (const EvalContext& ctx, double ret, double x) const
2067 return x <= 0 ? TCU_NAN : ctx.format.ulp(ret, 2.0);
2070 Interval getCodomain (void) const
2072 return Interval(0.0, TCU_INFINITY);
2076 class ExpFunc : public CFloatFunc1
2079 ExpFunc (const string& name, DoubleFunc1& func)
2080 : CFloatFunc1(name, func) {}
2082 double precision (const EvalContext& ctx, double ret, double x) const
2084 switch (ctx.floatPrecision)
2086 case glu::PRECISION_HIGHP:
2087 return ctx.format.ulp(ret, 3.0 + 2.0 * deAbs(x));
2088 case glu::PRECISION_MEDIUMP:
2089 return ctx.format.ulp(ret, 2.0 + 2.0 * deAbs(x));
2090 case glu::PRECISION_LOWP:
2091 return ctx.format.ulp(ret, 2.0);
2093 DE_FATAL("Impossible");
2098 Interval getCodomain (void) const
2100 return Interval(0.0, TCU_INFINITY);
2104 class Exp2 : public ExpFunc { public: Exp2 (void) : ExpFunc("exp2", deExp2) {} };
2105 class Exp : public ExpFunc { public: Exp (void) : ExpFunc("exp", deExp) {} };
2107 ExprP<float> exp2 (const ExprP<float>& x) { return app<Exp2>(x); }
2108 ExprP<float> exp (const ExprP<float>& x) { return app<Exp>(x); }
2110 class LogFunc : public CFloatFunc1
2113 LogFunc (const string& name, DoubleFunc1& func)
2114 : CFloatFunc1(name, func) {}
2117 double precision (const EvalContext& ctx, double ret, double x) const
2122 switch (ctx.floatPrecision)
2124 case glu::PRECISION_HIGHP:
2125 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -21) : ctx.format.ulp(ret, 3.0);
2126 case glu::PRECISION_MEDIUMP:
2127 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -7) : ctx.format.ulp(ret, 2.0);
2128 case glu::PRECISION_LOWP:
2129 return ctx.format.ulp(ret, 2.0);
2131 DE_FATAL("Impossible");
2138 class Log2 : public LogFunc { public: Log2 (void) : LogFunc("log2", deLog2) {} };
2139 class Log : public LogFunc { public: Log (void) : LogFunc("log", deLog) {} };
2141 ExprP<float> log2 (const ExprP<float>& x) { return app<Log2>(x); }
2142 ExprP<float> log (const ExprP<float>& x) { return app<Log>(x); }
2144 #define DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0) \
2145 ExprP<TRET> NAME (const ExprP<T0>& arg0) { return app<CLASS>(arg0); }
2147 #define DEFINE_DERIVED1(CLASS, TRET, NAME, T0, ARG0, EXPANSION) \
2148 class CLASS : public DerivedFunc<Signature<TRET, T0> > \
2151 string getName (void) const { return #NAME; } \
2154 ExprP<TRET> doExpand (ExpandContext&, \
2155 const CLASS::ArgExprs& args_) const \
2157 const ExprP<float>& ARG0 = args_.a; \
2161 DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0)
2163 #define DEFINE_DERIVED_FLOAT1(CLASS, NAME, ARG0, EXPANSION) \
2164 DEFINE_DERIVED1(CLASS, float, NAME, float, ARG0, EXPANSION)
2166 #define DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1) \
2167 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1) \
2169 return app<CLASS>(arg0, arg1); \
2172 #define DEFINE_DERIVED2(CLASS, TRET, NAME, T0, Arg0, T1, Arg1, EXPANSION) \
2173 class CLASS : public DerivedFunc<Signature<TRET, T0, T1> > \
2176 string getName (void) const { return #NAME; } \
2179 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2181 const ExprP<T0>& Arg0 = args_.a; \
2182 const ExprP<T1>& Arg1 = args_.b; \
2186 DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1)
2188 #define DEFINE_DERIVED_FLOAT2(CLASS, NAME, Arg0, Arg1, EXPANSION) \
2189 DEFINE_DERIVED2(CLASS, float, NAME, float, Arg0, float, Arg1, EXPANSION)
2191 #define DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2) \
2192 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, const ExprP<T2>& arg2) \
2194 return app<CLASS>(arg0, arg1, arg2); \
2197 #define DEFINE_DERIVED3(CLASS, TRET, NAME, T0, ARG0, T1, ARG1, T2, ARG2, EXPANSION) \
2198 class CLASS : public DerivedFunc<Signature<TRET, T0, T1, T2> > \
2201 string getName (void) const { return #NAME; } \
2204 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2206 const ExprP<T0>& ARG0 = args_.a; \
2207 const ExprP<T1>& ARG1 = args_.b; \
2208 const ExprP<T2>& ARG2 = args_.c; \
2212 DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2)
2214 #define DEFINE_DERIVED_FLOAT3(CLASS, NAME, ARG0, ARG1, ARG2, EXPANSION) \
2215 DEFINE_DERIVED3(CLASS, float, NAME, float, ARG0, float, ARG1, float, ARG2, EXPANSION)
2217 #define DEFINE_CONSTRUCTOR4(CLASS, TRET, NAME, T0, T1, T2, T3) \
2218 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, \
2219 const ExprP<T2>& arg2, const ExprP<T3>& arg3) \
2221 return app<CLASS>(arg0, arg1, arg2, arg3); \
2224 DEFINE_DERIVED_FLOAT1(Sqrt, sqrt, x, constant(1.0f) / app<InverseSqrt>(x));
2225 DEFINE_DERIVED_FLOAT2(Pow, pow, x, y, exp2(y * log2(x)));
2226 DEFINE_DERIVED_FLOAT1(Radians, radians, d, (constant(DE_PI) / constant(180.0f)) * d);
2227 DEFINE_DERIVED_FLOAT1(Degrees, degrees, r, (constant(180.0f) / constant(DE_PI)) * r);
2229 class TrigFunc : public CFloatFunc1
2232 TrigFunc (const string& name,
2234 const Interval& loEx,
2235 const Interval& hiEx)
2236 : CFloatFunc1 (name, func)
2237 , m_loExtremum (loEx)
2238 , m_hiExtremum (hiEx) {}
2241 Interval innerExtrema (const EvalContext&, const Interval& angle) const
2243 const double lo = angle.lo();
2244 const double hi = angle.hi();
2245 const int loSlope = doGetSlope(lo);
2246 const int hiSlope = doGetSlope(hi);
2248 // Detect the high and low values the function can take between the
2249 // interval endpoints.
2250 if (angle.length() >= 2.0 * DE_PI_DOUBLE)
2252 // The interval is longer than a full cycle, so it must get all possible values.
2253 return m_hiExtremum | m_loExtremum;
2255 else if (loSlope == 1 && hiSlope == -1)
2257 // The slope can change from positive to negative only at the maximum value.
2258 return m_hiExtremum;
2260 else if (loSlope == -1 && hiSlope == 1)
2262 // The slope can change from negative to positive only at the maximum value.
2263 return m_loExtremum;
2265 else if (loSlope == hiSlope &&
2266 deIntSign(applyExact(hi) - applyExact(lo)) * loSlope == -1)
2268 // The slope has changed twice between the endpoints, so both extrema are included.
2269 return m_hiExtremum | m_loExtremum;
2275 Interval getCodomain (void) const
2277 // Ensure that result is always within [-1, 1], or NaN (for +-inf)
2278 return Interval(-1.0, 1.0) | TCU_NAN;
2281 double precision (const EvalContext& ctx, double ret, double arg) const
2283 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2285 // Use precision from OpenCL fast relaxed math
2286 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2288 return deLdExp(1.0, -11);
2292 // "larger otherwise", let's pick |x| * 2^-12 , which is slightly over
2293 // 2^-11 at x == pi.
2294 return deLdExp(deAbs(arg), -12);
2297 else if (ctx.floatPrecision == glu::PRECISION_MEDIUMP)
2299 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2301 // from OpenCL half-float extension specification
2302 return ctx.format.ulp(ret, 2.0);
2306 // |x| * 2^-10, slightly larger than 2 ULP at x == pi
2307 return deLdExp(deAbs(arg), -10);
2312 DE_ASSERT(ctx.floatPrecision == glu::PRECISION_LOWP);
2314 // from OpenCL half-float extension specification
2315 return ctx.format.ulp(ret, 2.0);
2319 virtual int doGetSlope (double angle) const = 0;
2321 Interval m_loExtremum;
2322 Interval m_hiExtremum;
2325 class Sin : public TrigFunc
2328 Sin (void) : TrigFunc("sin", deSin, -1.0, 1.0) {}
2331 int doGetSlope (double angle) const { return deIntSign(deCos(angle)); }
2334 ExprP<float> sin (const ExprP<float>& x) { return app<Sin>(x); }
2336 class Cos : public TrigFunc
2339 Cos (void) : TrigFunc("cos", deCos, -1.0, 1.0) {}
2342 int doGetSlope (double angle) const { return -deIntSign(deSin(angle)); }
2345 ExprP<float> cos (const ExprP<float>& x) { return app<Cos>(x); }
2347 DEFINE_DERIVED_FLOAT1(Tan, tan, x, sin(x) * (constant(1.0f) / cos(x)));
2349 class ASin : public CFloatFunc1
2352 ASin (void) : CFloatFunc1("asin", deAsin) {}
2355 double precision (const EvalContext& ctx, double, double x) const
2357 if (!de::inBounds(x, -1.0, 1.0))
2360 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2362 // Absolute error of 2^-11
2363 return deLdExp(1.0, -11);
2367 // Absolute error of 2^-8
2368 return deLdExp(1.0, -8);
2374 class ArcTrigFunc : public CFloatFunc1
2377 ArcTrigFunc (const string& name,
2379 double precisionULPs,
2380 const Interval& domain,
2381 const Interval& codomain)
2382 : CFloatFunc1 (name, func)
2383 , m_precision (precisionULPs)
2385 , m_codomain (codomain) {}
2388 double precision (const EvalContext& ctx, double ret, double x) const
2390 if (!m_domain.contains(x))
2393 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2395 // Use OpenCL's fast relaxed math precision
2396 return ctx.format.ulp(ret, m_precision);
2400 // Use OpenCL half-float spec
2401 return ctx.format.ulp(ret, 2.0);
2405 // We could implement getCodomain with m_codomain, but choose not to,
2406 // because it seems too strict with trascendental constants like pi.
2408 const double m_precision;
2409 const Interval m_domain;
2410 const Interval m_codomain;
2413 class ACos : public ArcTrigFunc
2416 ACos (void) : ArcTrigFunc("acos", deAcos, 4096.0,
2417 Interval(-1.0, 1.0),
2418 Interval(0.0, DE_PI_DOUBLE)) {}
2421 class ATan : public ArcTrigFunc
2424 ATan (void) : ArcTrigFunc("atan", deAtanOver, 4096.0,
2425 Interval::unbounded(),
2426 Interval(-DE_PI_DOUBLE * 0.5, DE_PI_DOUBLE * 0.5)) {}
2429 class ATan2 : public CFloatFunc2
2432 ATan2 (void) : CFloatFunc2 ("atan", deAtan2) {}
2435 Interval innerExtrema (const EvalContext& ctx,
2437 const Interval& xi) const
2441 if (yi.contains(0.0))
2443 if (xi.contains(0.0))
2445 if (xi.intersects(Interval(-TCU_INFINITY, 0.0)))
2446 ret |= Interval(-DE_PI_DOUBLE, DE_PI_DOUBLE);
2449 if (ctx.format.hasInf() != YES && (!yi.isFinite() || !xi.isFinite()))
2451 // Infinities may not be supported, allow anything, including NaN
2458 double precision (const EvalContext& ctx, double ret, double, double) const
2460 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2461 return ctx.format.ulp(ret, 4096.0);
2463 return ctx.format.ulp(ret, 2.0);
2466 // Codomain could be [-pi, pi], but that would probably be too strict.
2469 DEFINE_DERIVED_FLOAT1(Sinh, sinh, x, (exp(x) - exp(-x)) / constant(2.0f));
2470 DEFINE_DERIVED_FLOAT1(Cosh, cosh, x, (exp(x) + exp(-x)) / constant(2.0f));
2471 DEFINE_DERIVED_FLOAT1(Tanh, tanh, x, sinh(x) / cosh(x));
2473 // These are not defined as derived forms in the GLSL ES spec, but
2474 // that gives us a reasonable precision.
2475 DEFINE_DERIVED_FLOAT1(ASinh, asinh, x, log(x + sqrt(x * x + constant(1.0f))));
2476 DEFINE_DERIVED_FLOAT1(ACosh, acosh, x, log(x + sqrt(alternatives((x + constant(1.0f)) * (x - constant(1.0f)),
2477 (x*x - constant(1.0f))))));
2478 DEFINE_DERIVED_FLOAT1(ATanh, atanh, x, constant(0.5f) * log((constant(1.0f) + x) /
2479 (constant(1.0f) - x)));
2481 template <typename T>
2482 class GetComponent : public PrimitiveFunc<Signature<typename T::Element, T, int> >
2485 typedef typename GetComponent::IRet IRet;
2487 string getName (void) const { return "_getComponent"; }
2489 void print (ostream& os,
2490 const BaseArgExprs& args) const
2492 os << *args[0] << "[" << *args[1] << "]";
2496 IRet doApply (const EvalContext&,
2497 const typename GetComponent::IArgs& iargs) const
2501 for (int compNdx = 0; compNdx < T::SIZE; ++compNdx)
2503 if (iargs.b.contains(compNdx))
2504 ret = unionIVal<typename T::Element>(ret, iargs.a[compNdx]);
2512 template <typename T>
2513 ExprP<typename T::Element> getComponent (const ExprP<T>& container, int ndx)
2515 DE_ASSERT(0 <= ndx && ndx < T::SIZE);
2516 return app<GetComponent<T> >(container, constant(ndx));
2519 template <typename T> string vecNamePrefix (void);
2520 template <> string vecNamePrefix<float> (void) { return ""; }
2521 template <> string vecNamePrefix<int> (void) { return "i"; }
2522 template <> string vecNamePrefix<bool> (void) { return "b"; }
2524 template <typename T, int Size>
2525 string vecName (void) { return vecNamePrefix<T>() + "vec" + de::toString(Size); }
2527 template <typename T, int Size> class GenVec;
2529 template <typename T>
2530 class GenVec<T, 1> : public DerivedFunc<Signature<T, T> >
2533 typedef typename GenVec<T, 1>::ArgExprs ArgExprs;
2535 string getName (void) const
2537 return "_" + vecName<T, 1>();
2542 ExprP<T> doExpand (ExpandContext&, const ArgExprs& args) const { return args.a; }
2545 template <typename T>
2546 class GenVec<T, 2> : public PrimitiveFunc<Signature<Vector<T, 2>, T, T> >
2549 typedef typename GenVec::IRet IRet;
2550 typedef typename GenVec::IArgs IArgs;
2552 string getName (void) const
2554 return vecName<T, 2>();
2558 IRet doApply (const EvalContext&, const IArgs& iargs) const
2560 return IRet(iargs.a, iargs.b);
2564 template <typename T>
2565 class GenVec<T, 3> : public PrimitiveFunc<Signature<Vector<T, 3>, T, T, T> >
2568 typedef typename GenVec::IRet IRet;
2569 typedef typename GenVec::IArgs IArgs;
2571 string getName (void) const
2573 return vecName<T, 3>();
2577 IRet doApply (const EvalContext&, const IArgs& iargs) const
2579 return IRet(iargs.a, iargs.b, iargs.c);
2583 template <typename T>
2584 class GenVec<T, 4> : public PrimitiveFunc<Signature<Vector<T, 4>, T, T, T, T> >
2587 typedef typename GenVec::IRet IRet;
2588 typedef typename GenVec::IArgs IArgs;
2590 string getName (void) const { return vecName<T, 4>(); }
2593 IRet doApply (const EvalContext&, const IArgs& iargs) const
2595 return IRet(iargs.a, iargs.b, iargs.c, iargs.d);
2601 template <typename T, int Rows, int Columns>
2604 template <typename T, int Rows>
2605 class GenMat<T, Rows, 2> : public PrimitiveFunc<
2606 Signature<Matrix<T, Rows, 2>, Vector<T, Rows>, Vector<T, Rows> > >
2609 typedef typename GenMat::Ret Ret;
2610 typedef typename GenMat::IRet IRet;
2611 typedef typename GenMat::IArgs IArgs;
2613 string getName (void) const
2615 return dataTypeNameOf<Ret>();
2620 IRet doApply (const EvalContext&, const IArgs& iargs) const
2629 template <typename T, int Rows>
2630 class GenMat<T, Rows, 3> : public PrimitiveFunc<
2631 Signature<Matrix<T, Rows, 3>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
2634 typedef typename GenMat::Ret Ret;
2635 typedef typename GenMat::IRet IRet;
2636 typedef typename GenMat::IArgs IArgs;
2638 string getName (void) const
2640 return dataTypeNameOf<Ret>();
2645 IRet doApply (const EvalContext&, const IArgs& iargs) const
2655 template <typename T, int Rows>
2656 class GenMat<T, Rows, 4> : public PrimitiveFunc<
2657 Signature<Matrix<T, Rows, 4>,
2658 Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
2661 typedef typename GenMat::Ret Ret;
2662 typedef typename GenMat::IRet IRet;
2663 typedef typename GenMat::IArgs IArgs;
2665 string getName (void) const
2667 return dataTypeNameOf<Ret>();
2671 IRet doApply (const EvalContext&, const IArgs& iargs) const
2682 template <typename T, int Rows>
2683 ExprP<Matrix<T, Rows, 2> > mat2 (const ExprP<Vector<T, Rows> >& arg0,
2684 const ExprP<Vector<T, Rows> >& arg1)
2686 return app<GenMat<T, Rows, 2> >(arg0, arg1);
2689 template <typename T, int Rows>
2690 ExprP<Matrix<T, Rows, 3> > mat3 (const ExprP<Vector<T, Rows> >& arg0,
2691 const ExprP<Vector<T, Rows> >& arg1,
2692 const ExprP<Vector<T, Rows> >& arg2)
2694 return app<GenMat<T, Rows, 3> >(arg0, arg1, arg2);
2697 template <typename T, int Rows>
2698 ExprP<Matrix<T, Rows, 4> > mat4 (const ExprP<Vector<T, Rows> >& arg0,
2699 const ExprP<Vector<T, Rows> >& arg1,
2700 const ExprP<Vector<T, Rows> >& arg2,
2701 const ExprP<Vector<T, Rows> >& arg3)
2703 return app<GenMat<T, Rows, 4> >(arg0, arg1, arg2, arg3);
2707 template <int Rows, int Cols>
2708 class MatNeg : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
2709 Matrix<float, Rows, Cols> > >
2712 typedef typename MatNeg::IRet IRet;
2713 typedef typename MatNeg::IArgs IArgs;
2715 string getName (void) const
2721 void doPrint (ostream& os, const BaseArgExprs& args) const
2723 os << "-(" << *args[0] << ")";
2726 IRet doApply (const EvalContext&, const IArgs& iargs) const
2730 for (int col = 0; col < Cols; ++col)
2732 for (int row = 0; row < Rows; ++row)
2733 ret[col][row] = -iargs.a[col][row];
2740 template <typename T, typename Sig>
2741 class CompWiseFunc : public PrimitiveFunc<Sig>
2744 typedef Func<Signature<T, T, T> > ScalarFunc;
2746 string getName (void) const
2748 return doGetScalarFunc().getName();
2751 void doPrint (ostream& os,
2752 const BaseArgExprs& args) const
2754 doGetScalarFunc().print(os, args);
2758 const ScalarFunc& doGetScalarFunc (void) const = 0;
2761 template <int Rows, int Cols>
2762 class CompMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
2763 Matrix<float, Rows, Cols>,
2764 Matrix<float, Rows, Cols> > >
2767 typedef typename CompMatFuncBase::IRet IRet;
2768 typedef typename CompMatFuncBase::IArgs IArgs;
2772 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
2776 for (int col = 0; col < Cols; ++col)
2778 for (int row = 0; row < Rows; ++row)
2779 ret[col][row] = this->doGetScalarFunc().apply(ctx,
2788 template <typename F, int Rows, int Cols>
2789 class CompMatFunc : public CompMatFuncBase<Rows, Cols>
2792 const typename CompMatFunc::ScalarFunc& doGetScalarFunc (void) const
2794 return instance<F>();
2798 class ScalarMatrixCompMult : public Mul
2801 string getName (void) const
2803 return "matrixCompMult";
2806 void doPrint (ostream& os, const BaseArgExprs& args) const
2808 Func<Sig>::doPrint(os, args);
2812 template <int Rows, int Cols>
2813 class MatrixCompMult : public CompMatFunc<ScalarMatrixCompMult, Rows, Cols>
2817 template <int Rows, int Cols>
2818 class ScalarMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
2819 Matrix<float, Rows, Cols>,
2823 typedef typename ScalarMatFuncBase::IRet IRet;
2824 typedef typename ScalarMatFuncBase::IArgs IArgs;
2828 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
2832 for (int col = 0; col < Cols; ++col)
2834 for (int row = 0; row < Rows; ++row)
2835 ret[col][row] = this->doGetScalarFunc().apply(ctx, iargs.a[col][row], iargs.b);
2842 template <typename F, int Rows, int Cols>
2843 class ScalarMatFunc : public ScalarMatFuncBase<Rows, Cols>
2846 const typename ScalarMatFunc::ScalarFunc& doGetScalarFunc (void) const
2848 return instance<F>();
2852 template<typename T, int Size> struct GenXType;
2854 template<typename T>
2855 struct GenXType<T, 1>
2857 static ExprP<T> genXType (const ExprP<T>& x) { return x; }
2860 template<typename T>
2861 struct GenXType<T, 2>
2863 static ExprP<Vector<T, 2> > genXType (const ExprP<T>& x)
2865 return app<GenVec<T, 2> >(x, x);
2869 template<typename T>
2870 struct GenXType<T, 3>
2872 static ExprP<Vector<T, 3> > genXType (const ExprP<T>& x)
2874 return app<GenVec<T, 3> >(x, x, x);
2878 template<typename T>
2879 struct GenXType<T, 4>
2881 static ExprP<Vector<T, 4> > genXType (const ExprP<T>& x)
2883 return app<GenVec<T, 4> >(x, x, x, x);
2887 //! Returns an expression of vector of size `Size` (or scalar if Size == 1),
2888 //! with each element initialized with the expression `x`.
2889 template<typename T, int Size>
2890 ExprP<typename ContainerOf<T, Size>::Container> genXType (const ExprP<T>& x)
2892 return GenXType<T, Size>::genXType(x);
2895 typedef GenVec<float, 2> FloatVec2;
2896 DEFINE_CONSTRUCTOR2(FloatVec2, Vec2, vec2, float, float)
2898 typedef GenVec<float, 3> FloatVec3;
2899 DEFINE_CONSTRUCTOR3(FloatVec3, Vec3, vec3, float, float, float)
2901 typedef GenVec<float, 4> FloatVec4;
2902 DEFINE_CONSTRUCTOR4(FloatVec4, Vec4, vec4, float, float, float, float)
2905 class Dot : public DerivedFunc<Signature<float, Vector<float, Size>, Vector<float, Size> > >
2908 typedef typename Dot::ArgExprs ArgExprs;
2910 string getName (void) const
2916 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2918 ExprP<float> val = args.a[0] * args.b[0];
2920 for (int ndx = 1; ndx < Size; ++ndx)
2921 val = val + args.a[ndx] * args.b[ndx];
2928 class Dot<1> : public DerivedFunc<Signature<float, float, float> >
2931 string getName (void) const
2936 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2938 return args.a * args.b;
2943 ExprP<float> dot (const ExprP<Vector<float, Size> >& x, const ExprP<Vector<float, Size> >& y)
2945 return app<Dot<Size> >(x, y);
2948 ExprP<float> dot (const ExprP<float>& x, const ExprP<float>& y)
2950 return app<Dot<1> >(x, y);
2954 class Length : public DerivedFunc<
2955 Signature<float, typename ContainerOf<float, Size>::Container> >
2958 typedef typename Length::ArgExprs ArgExprs;
2960 string getName (void) const
2966 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2968 return sqrt(dot(args.a, args.a));
2973 ExprP<float> length (const ExprP<typename ContainerOf<float, Size>::Container>& x)
2975 return app<Length<Size> >(x);
2979 class Distance : public DerivedFunc<
2981 typename ContainerOf<float, Size>::Container,
2982 typename ContainerOf<float, Size>::Container> >
2985 typedef typename Distance::Ret Ret;
2986 typedef typename Distance::ArgExprs ArgExprs;
2988 string getName (void) const
2994 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
2996 return length<Size>(args.a - args.b);
3002 class Cross : public DerivedFunc<Signature<Vec3, Vec3, Vec3> >
3005 string getName (void) const
3011 ExprP<Vec3> doExpand (ExpandContext&, const ArgExprs& x) const
3013 return vec3(x.a[1] * x.b[2] - x.b[1] * x.a[2],
3014 x.a[2] * x.b[0] - x.b[2] * x.a[0],
3015 x.a[0] * x.b[1] - x.b[0] * x.a[1]);
3019 DEFINE_CONSTRUCTOR2(Cross, Vec3, cross, Vec3, Vec3)
3022 class Normalize : public DerivedFunc<
3023 Signature<typename ContainerOf<float, Size>::Container,
3024 typename ContainerOf<float, Size>::Container> >
3027 typedef typename Normalize::Ret Ret;
3028 typedef typename Normalize::ArgExprs ArgExprs;
3030 string getName (void) const
3036 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3038 return args.a / length<Size>(args.a);
3043 class FaceForward : public DerivedFunc<
3044 Signature<typename ContainerOf<float, Size>::Container,
3045 typename ContainerOf<float, Size>::Container,
3046 typename ContainerOf<float, Size>::Container,
3047 typename ContainerOf<float, Size>::Container> >
3050 typedef typename FaceForward::Ret Ret;
3051 typedef typename FaceForward::ArgExprs ArgExprs;
3053 string getName (void) const
3055 return "faceforward";
3061 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3063 return cond(dot(args.c, args.b) < constant(0.0f), args.a, -args.a);
3068 class Reflect : public DerivedFunc<
3069 Signature<typename ContainerOf<float, Size>::Container,
3070 typename ContainerOf<float, Size>::Container,
3071 typename ContainerOf<float, Size>::Container> >
3074 typedef typename Reflect::Ret Ret;
3075 typedef typename Reflect::Arg0 Arg0;
3076 typedef typename Reflect::Arg1 Arg1;
3077 typedef typename Reflect::ArgExprs ArgExprs;
3079 string getName (void) const
3085 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3087 const ExprP<Arg0>& i = args.a;
3088 const ExprP<Arg1>& n = args.b;
3089 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3091 return i - alternatives((n * dotNI) * constant(2.0f),
3092 n * (dotNI * constant(2.0f)));
3097 class Refract : public DerivedFunc<
3098 Signature<typename ContainerOf<float, Size>::Container,
3099 typename ContainerOf<float, Size>::Container,
3100 typename ContainerOf<float, Size>::Container,
3104 typedef typename Refract::Ret Ret;
3105 typedef typename Refract::Arg0 Arg0;
3106 typedef typename Refract::Arg1 Arg1;
3107 typedef typename Refract::ArgExprs ArgExprs;
3109 string getName (void) const
3115 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3117 const ExprP<Arg0>& i = args.a;
3118 const ExprP<Arg1>& n = args.b;
3119 const ExprP<float>& eta = args.c;
3120 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3121 const ExprP<float> k = bindExpression("k", ctx, constant(1.0f) - eta * eta *
3122 (constant(1.0f) - dotNI * dotNI));
3124 return cond(k < constant(0.0f),
3125 genXType<float, Size>(constant(0.0f)),
3126 i * eta - n * (eta * dotNI + sqrt(k)));
3130 class PreciseFunc1 : public CFloatFunc1
3133 PreciseFunc1 (const string& name, DoubleFunc1& func) : CFloatFunc1(name, func) {}
3135 double precision (const EvalContext&, double, double) const { return 0.0; }
3138 class Abs : public PreciseFunc1
3141 Abs (void) : PreciseFunc1("abs", deAbs) {}
3144 class Sign : public PreciseFunc1
3147 Sign (void) : PreciseFunc1("sign", deSign) {}
3150 class Floor : public PreciseFunc1
3153 Floor (void) : PreciseFunc1("floor", deFloor) {}
3156 class Trunc : public PreciseFunc1
3159 Trunc (void) : PreciseFunc1("trunc", deTrunc) {}
3162 class Round : public FloatFunc1
3165 string getName (void) const { return "round"; }
3168 Interval applyPoint (const EvalContext&, double x) const
3170 double truncated = 0.0;
3171 const double fract = deModf(x, &truncated);
3174 if (fabs(fract) <= 0.5)
3176 if (fabs(fract) >= 0.5)
3177 ret |= truncated + deSign(fract);
3182 double precision (const EvalContext&, double, double) const { return 0.0; }
3185 class RoundEven : public PreciseFunc1
3188 RoundEven (void) : PreciseFunc1("roundEven", deRoundEven) {}
3191 class Ceil : public PreciseFunc1
3194 Ceil (void) : PreciseFunc1("ceil", deCeil) {}
3197 DEFINE_DERIVED_FLOAT1(Fract, fract, x, x - app<Floor>(x));
3199 class PreciseFunc2 : public CFloatFunc2
3202 PreciseFunc2 (const string& name, DoubleFunc2& func) : CFloatFunc2(name, func) {}
3204 double precision (const EvalContext&, double, double, double) const { return 0.0; }
3207 DEFINE_DERIVED_FLOAT2(Mod, mod, x, y, x - y * app<Floor>(x / y));
3209 class Modf : public PrimitiveFunc<Signature<float, float, float> >
3212 string getName (void) const
3218 IRet doApply (const EvalContext&, const IArgs& iargs) const
3221 Interval& wholeIV = const_cast<Interval&>(iargs.b);
3224 TCU_INTERVAL_APPLY_MONOTONE1(fracIV, x, iargs.a, frac, frac = deModf(x, &intPart));
3225 TCU_INTERVAL_APPLY_MONOTONE1(wholeIV, x, iargs.a, whole,
3226 deModf(x, &intPart); whole = intPart);
3228 if (!iargs.a.isFinite())
3230 // Behavior on modf(Inf) not well-defined, allow anything as a fractional part
3231 // See Khronos bug 13907
3238 int getOutParamIndex (void) const
3244 class Min : public PreciseFunc2 { public: Min (void) : PreciseFunc2("min", deMin) {} };
3245 class Max : public PreciseFunc2 { public: Max (void) : PreciseFunc2("max", deMax) {} };
3247 class Clamp : public FloatFunc3
3250 string getName (void) const { return "clamp"; }
3252 double applyExact (double x, double minVal, double maxVal) const
3254 return de::min(de::max(x, minVal), maxVal);
3257 double precision (const EvalContext&, double, double, double minVal, double maxVal) const
3259 return minVal > maxVal ? TCU_NAN : 0.0;
3263 ExprP<float> clamp(const ExprP<float>& x, const ExprP<float>& minVal, const ExprP<float>& maxVal)
3265 return app<Clamp>(x, minVal, maxVal);
3268 DEFINE_DERIVED_FLOAT3(Mix, mix, x, y, a, alternatives((x * (constant(1.0f) - a)) + y * a,
3271 static double step (double edge, double x)
3273 return x < edge ? 0.0 : 1.0;
3276 class Step : public PreciseFunc2 { public: Step (void) : PreciseFunc2("step", step) {} };
3278 class SmoothStep : public DerivedFunc<Signature<float, float, float, float> >
3281 string getName (void) const
3283 return "smoothstep";
3288 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3290 const ExprP<float>& edge0 = args.a;
3291 const ExprP<float>& edge1 = args.b;
3292 const ExprP<float>& x = args.c;
3293 const ExprP<float> tExpr = clamp((x - edge0) / (edge1 - edge0),
3294 constant(0.0f), constant(1.0f));
3295 const ExprP<float> t = bindExpression("t", ctx, tExpr);
3297 return (t * t * (constant(3.0f) - constant(2.0f) * t));
3301 class FrExp : public PrimitiveFunc<Signature<float, float, int> >
3304 string getName (void) const
3310 IRet doApply (const EvalContext&, const IArgs& iargs) const
3313 const IArg0& x = iargs.a;
3314 IArg1& exponent = const_cast<IArg1&>(iargs.b);
3316 if (x.hasNaN() || x.contains(TCU_INFINITY) || x.contains(-TCU_INFINITY))
3318 // GLSL (in contrast to IEEE) says that result of applying frexp
3319 // to infinity is undefined
3320 ret = Interval::unbounded() | TCU_NAN;
3321 exponent = Interval(-deLdExp(1.0, 31), deLdExp(1.0, 31)-1);
3323 else if (!x.empty())
3326 const double loFrac = deFrExp(x.lo(), &loExp);
3328 const double hiFrac = deFrExp(x.hi(), &hiExp);
3330 if (deSign(loFrac) != deSign(hiFrac))
3332 exponent = Interval(-TCU_INFINITY, de::max(loExp, hiExp));
3334 if (deSign(loFrac) < 0)
3335 ret |= Interval(-1.0 + DBL_EPSILON*0.5, 0.0);
3336 if (deSign(hiFrac) > 0)
3337 ret |= Interval(0.0, 1.0 - DBL_EPSILON*0.5);
3341 exponent = Interval(loExp, hiExp);
3343 ret = Interval(loFrac, hiFrac);
3345 ret = deSign(loFrac) * Interval(0.5, 1.0 - DBL_EPSILON*0.5);
3352 int getOutParamIndex (void) const
3358 class LdExp : public PrimitiveFunc<Signature<float, float, int> >
3361 string getName (void) const
3367 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
3369 Interval ret = call<Exp2>(ctx, iargs.b);
3370 // Khronos bug 11180 consensus: if exp2(exponent) cannot be represented,
3371 // the result is undefined.
3373 if (ret.contains(TCU_INFINITY) | ret.contains(-TCU_INFINITY))
3376 return call<Mul>(ctx, iargs.a, ret);
3380 template<int Rows, int Columns>
3381 class Transpose : public PrimitiveFunc<Signature<Matrix<float, Rows, Columns>,
3382 Matrix<float, Columns, Rows> > >
3385 typedef typename Transpose::IRet IRet;
3386 typedef typename Transpose::IArgs IArgs;
3388 string getName (void) const
3394 IRet doApply (const EvalContext&, const IArgs& iargs) const
3398 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
3400 for (int colNdx = 0; colNdx < Columns; ++colNdx)
3401 ret(rowNdx, colNdx) = iargs.a(colNdx, rowNdx);
3408 template<typename Ret, typename Arg0, typename Arg1>
3409 class MulFunc : public PrimitiveFunc<Signature<Ret, Arg0, Arg1> >
3412 string getName (void) const { return "mul"; }
3415 void doPrint (ostream& os, const BaseArgExprs& args) const
3417 os << "(" << *args[0] << " * " << *args[1] << ")";
3421 template<int LeftRows, int Middle, int RightCols>
3422 class MatMul : public MulFunc<Matrix<float, LeftRows, RightCols>,
3423 Matrix<float, LeftRows, Middle>,
3424 Matrix<float, Middle, RightCols> >
3427 typedef typename MatMul::IRet IRet;
3428 typedef typename MatMul::IArgs IArgs;
3429 typedef typename MatMul::IArg0 IArg0;
3430 typedef typename MatMul::IArg1 IArg1;
3432 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3434 const IArg0& left = iargs.a;
3435 const IArg1& right = iargs.b;
3438 for (int row = 0; row < LeftRows; ++row)
3440 for (int col = 0; col < RightCols; ++col)
3442 Interval element (0.0);
3444 for (int ndx = 0; ndx < Middle; ++ndx)
3445 element = call<Add>(ctx, element,
3446 call<Mul>(ctx, left[ndx][row], right[col][ndx]));
3448 ret[col][row] = element;
3456 template<int Rows, int Cols>
3457 class VecMatMul : public MulFunc<Vector<float, Cols>,
3458 Vector<float, Rows>,
3459 Matrix<float, Rows, Cols> >
3462 typedef typename VecMatMul::IRet IRet;
3463 typedef typename VecMatMul::IArgs IArgs;
3464 typedef typename VecMatMul::IArg0 IArg0;
3465 typedef typename VecMatMul::IArg1 IArg1;
3468 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3470 const IArg0& left = iargs.a;
3471 const IArg1& right = iargs.b;
3474 for (int col = 0; col < Cols; ++col)
3476 Interval element (0.0);
3478 for (int row = 0; row < Rows; ++row)
3479 element = call<Add>(ctx, element, call<Mul>(ctx, left[row], right[col][row]));
3488 template<int Rows, int Cols>
3489 class MatVecMul : public MulFunc<Vector<float, Rows>,
3490 Matrix<float, Rows, Cols>,
3491 Vector<float, Cols> >
3494 typedef typename MatVecMul::IRet IRet;
3495 typedef typename MatVecMul::IArgs IArgs;
3496 typedef typename MatVecMul::IArg0 IArg0;
3497 typedef typename MatVecMul::IArg1 IArg1;
3500 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3502 const IArg0& left = iargs.a;
3503 const IArg1& right = iargs.b;
3505 return call<VecMatMul<Cols, Rows> >(ctx, right,
3506 call<Transpose<Rows, Cols> >(ctx, left));
3510 template<int Rows, int Cols>
3511 class OuterProduct : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
3512 Vector<float, Rows>,
3513 Vector<float, Cols> > >
3516 typedef typename OuterProduct::IRet IRet;
3517 typedef typename OuterProduct::IArgs IArgs;
3519 string getName (void) const
3521 return "outerProduct";
3525 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3529 for (int row = 0; row < Rows; ++row)
3531 for (int col = 0; col < Cols; ++col)
3532 ret[col][row] = call<Mul>(ctx, iargs.a[row], iargs.b[col]);
3539 template<int Rows, int Cols>
3540 ExprP<Matrix<float, Rows, Cols> > outerProduct (const ExprP<Vector<float, Rows> >& left,
3541 const ExprP<Vector<float, Cols> >& right)
3543 return app<OuterProduct<Rows, Cols> >(left, right);
3547 class DeterminantBase : public DerivedFunc<Signature<float, Matrix<float, Size, Size> > >
3550 string getName (void) const { return "determinant"; }
3557 ExprP<float> determinant (ExprP<Matrix<float, Size, Size> > mat)
3559 return app<Determinant<Size> >(mat);
3563 class Determinant<2> : public DeterminantBase<2>
3566 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3568 ExprP<Mat2> mat = args.a;
3570 return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
3575 class Determinant<3> : public DeterminantBase<3>
3578 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3580 ExprP<Mat3> mat = args.a;
3582 return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) +
3583 mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) +
3584 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
3589 class Determinant<4> : public DeterminantBase<4>
3592 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3594 ExprP<Mat4> mat = args.a;
3595 ExprP<Mat3> minors[4];
3597 for (int ndx = 0; ndx < 4; ++ndx)
3599 ExprP<Vec4> minorColumns[3];
3600 ExprP<Vec3> columns[3];
3602 for (int col = 0; col < 3; ++col)
3603 minorColumns[col] = mat[col < ndx ? col : col + 1];
3605 for (int col = 0; col < 3; ++col)
3606 columns[col] = vec3(minorColumns[0][col+1],
3607 minorColumns[1][col+1],
3608 minorColumns[2][col+1]);
3610 minors[ndx] = bindExpression("minor", ctx,
3611 mat3(columns[0], columns[1], columns[2]));
3614 return (mat[0][0] * determinant(minors[0]) -
3615 mat[1][0] * determinant(minors[1]) +
3616 mat[2][0] * determinant(minors[2]) -
3617 mat[3][0] * determinant(minors[3]));
3621 template<int Size> class Inverse;
3624 ExprP<Matrix<float, Size, Size> > inverse (ExprP<Matrix<float, Size, Size> > mat)
3626 return app<Inverse<Size> >(mat);
3630 class Inverse<2> : public DerivedFunc<Signature<Mat2, Mat2> >
3633 string getName (void) const
3639 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3641 ExprP<Mat2> mat = args.a;
3642 ExprP<float> det = bindExpression("det", ctx, determinant(mat));
3644 return mat2(vec2(mat[1][1] / det, -mat[0][1] / det),
3645 vec2(-mat[1][0] / det, mat[0][0] / det));
3650 class Inverse<3> : public DerivedFunc<Signature<Mat3, Mat3> >
3653 string getName (void) const
3659 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3661 ExprP<Mat3> mat = args.a;
3662 ExprP<Mat2> invA = bindExpression("invA", ctx,
3663 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3664 vec2(mat[1][0], mat[1][1]))));
3666 ExprP<Vec2> matB = bindExpression("matB", ctx, vec2(mat[2][0], mat[2][1]));
3667 ExprP<Vec2> matC = bindExpression("matC", ctx, vec2(mat[0][2], mat[1][2]));
3668 ExprP<float> matD = bindExpression("matD", ctx, mat[2][2]);
3670 ExprP<float> schur = bindExpression("schur", ctx,
3672 (matD - dot(matC * invA, matB)));
3674 ExprP<Vec2> t1 = invA * matB;
3675 ExprP<Vec2> t2 = t1 * schur;
3676 ExprP<Mat2> t3 = outerProduct(t2, matC);
3677 ExprP<Mat2> t4 = t3 * invA;
3678 ExprP<Mat2> t5 = invA + t4;
3679 ExprP<Mat2> blockA = bindExpression("blockA", ctx, t5);
3680 ExprP<Vec2> blockB = bindExpression("blockB", ctx,
3681 (invA * matB) * -schur);
3682 ExprP<Vec2> blockC = bindExpression("blockC", ctx,
3683 (matC * invA) * -schur);
3685 return mat3(vec3(blockA[0][0], blockA[0][1], blockC[0]),
3686 vec3(blockA[1][0], blockA[1][1], blockC[1]),
3687 vec3(blockB[0], blockB[1], schur));
3692 class Inverse<4> : public DerivedFunc<Signature<Mat4, Mat4> >
3695 string getName (void) const { return "inverse"; }
3698 ExprP<Ret> doExpand (ExpandContext& ctx,
3699 const ArgExprs& args) const
3701 ExprP<Mat4> mat = args.a;
3702 ExprP<Mat2> invA = bindExpression("invA", ctx,
3703 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3704 vec2(mat[1][0], mat[1][1]))));
3705 ExprP<Mat2> matB = bindExpression("matB", ctx,
3706 mat2(vec2(mat[2][0], mat[2][1]),
3707 vec2(mat[3][0], mat[3][1])));
3708 ExprP<Mat2> matC = bindExpression("matC", ctx,
3709 mat2(vec2(mat[0][2], mat[0][3]),
3710 vec2(mat[1][2], mat[1][3])));
3711 ExprP<Mat2> matD = bindExpression("matD", ctx,
3712 mat2(vec2(mat[2][2], mat[2][3]),
3713 vec2(mat[3][2], mat[3][3])));
3714 ExprP<Mat2> schur = bindExpression("schur", ctx,
3715 inverse(matD + -(matC * invA * matB)));
3716 ExprP<Mat2> blockA = bindExpression("blockA", ctx,
3717 invA + (invA * matB * schur * matC * invA));
3718 ExprP<Mat2> blockB = bindExpression("blockB", ctx,
3719 (-invA) * matB * schur);
3720 ExprP<Mat2> blockC = bindExpression("blockC", ctx,
3721 (-schur) * matC * invA);
3723 return mat4(vec4(blockA[0][0], blockA[0][1], blockC[0][0], blockC[0][1]),
3724 vec4(blockA[1][0], blockA[1][1], blockC[1][0], blockC[1][1]),
3725 vec4(blockB[0][0], blockB[0][1], schur[0][0], schur[0][1]),
3726 vec4(blockB[1][0], blockB[1][1], schur[1][0], schur[1][1]));
3730 class Fma : public DerivedFunc<Signature<float, float, float, float> >
3733 string getName (void) const
3738 string getRequiredExtension (void) const
3740 return "GL_EXT_gpu_shader5";
3744 ExprP<float> doExpand (ExpandContext&, const ArgExprs& x) const
3746 return x.a * x.b + x.c;
3752 using namespace Functions;
3754 template <typename T>
3755 ExprP<typename T::Element> ContainerExprPBase<T>::operator[] (int i) const
3757 return Functions::getComponent(exprP<T>(*this), i);
3760 ExprP<float> operator+ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3762 return app<Add>(arg0, arg1);
3765 ExprP<float> operator- (const ExprP<float>& arg0, const ExprP<float>& arg1)
3767 return app<Sub>(arg0, arg1);
3770 ExprP<float> operator- (const ExprP<float>& arg0)
3772 return app<Negate>(arg0);
3775 ExprP<float> operator* (const ExprP<float>& arg0, const ExprP<float>& arg1)
3777 return app<Mul>(arg0, arg1);
3780 ExprP<float> operator/ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3782 return app<Div>(arg0, arg1);
3785 template <typename Sig_, int Size>
3786 class GenFunc : public PrimitiveFunc<Signature<
3787 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3788 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3789 typename ContainerOf<typename Sig_::Arg1, Size>::Container,
3790 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
3791 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
3794 typedef typename GenFunc::IArgs IArgs;
3795 typedef typename GenFunc::IRet IRet;
3797 GenFunc (const Func<Sig_>& scalarFunc) : m_func (scalarFunc) {}
3799 string getName (void) const
3801 return m_func.getName();
3804 int getOutParamIndex (void) const
3806 return m_func.getOutParamIndex();
3809 string getRequiredExtension (void) const
3811 return m_func.getRequiredExtension();
3815 void doPrint (ostream& os, const BaseArgExprs& args) const
3817 m_func.print(os, args);
3820 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3824 for (int ndx = 0; ndx < Size; ++ndx)
3827 m_func.apply(ctx, iargs.a[ndx], iargs.b[ndx], iargs.c[ndx], iargs.d[ndx]);
3833 void doGetUsedFuncs (FuncSet& dst) const
3835 m_func.getUsedFuncs(dst);
3838 const Func<Sig_>& m_func;
3841 template <typename F, int Size>
3842 class VectorizedFunc : public GenFunc<typename F::Sig, Size>
3845 VectorizedFunc (void) : GenFunc<typename F::Sig, Size>(instance<F>()) {}
3850 template <typename Sig_, int Size>
3851 class FixedGenFunc : public PrimitiveFunc <Signature<
3852 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3853 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3854 typename Sig_::Arg1,
3855 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
3856 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
3859 typedef typename FixedGenFunc::IArgs IArgs;
3860 typedef typename FixedGenFunc::IRet IRet;
3862 string getName (void) const
3864 return this->doGetScalarFunc().getName();
3868 void doPrint (ostream& os, const BaseArgExprs& args) const
3870 this->doGetScalarFunc().print(os, args);
3873 IRet doApply (const EvalContext& ctx,
3874 const IArgs& iargs) const
3877 const Func<Sig_>& func = this->doGetScalarFunc();
3879 for (int ndx = 0; ndx < Size; ++ndx)
3880 ret[ndx] = func.apply(ctx, iargs.a[ndx], iargs.b, iargs.c[ndx], iargs.d[ndx]);
3885 virtual const Func<Sig_>& doGetScalarFunc (void) const = 0;
3888 template <typename F, int Size>
3889 class FixedVecFunc : public FixedGenFunc<typename F::Sig, Size>
3892 const Func<typename F::Sig>& doGetScalarFunc (void) const { return instance<F>(); }
3895 template<typename Sig>
3898 GenFuncs (const Func<Sig>& func_,
3899 const GenFunc<Sig, 2>& func2_,
3900 const GenFunc<Sig, 3>& func3_,
3901 const GenFunc<Sig, 4>& func4_)
3908 const Func<Sig>& func;
3909 const GenFunc<Sig, 2>& func2;
3910 const GenFunc<Sig, 3>& func3;
3911 const GenFunc<Sig, 4>& func4;
3914 template<typename F>
3915 GenFuncs<typename F::Sig> makeVectorizedFuncs (void)
3917 return GenFuncs<typename F::Sig>(instance<F>(),
3918 instance<VectorizedFunc<F, 2> >(),
3919 instance<VectorizedFunc<F, 3> >(),
3920 instance<VectorizedFunc<F, 4> >());
3924 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
3925 const ExprP<Vector<float, Size> >& arg1)
3927 return app<VectorizedFunc<Mul, Size> >(arg0, arg1);
3931 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
3932 const ExprP<float>& arg1)
3934 return app<FixedVecFunc<Mul, Size> >(arg0, arg1);
3938 ExprP<Vector<float, Size> > operator/(const ExprP<Vector<float, Size> >& arg0,
3939 const ExprP<float>& arg1)
3941 return app<FixedVecFunc<Div, Size> >(arg0, arg1);
3945 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0)
3947 return app<VectorizedFunc<Negate, Size> >(arg0);
3951 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
3952 const ExprP<Vector<float, Size> >& arg1)
3954 return app<VectorizedFunc<Sub, Size> >(arg0, arg1);
3957 template<int LeftRows, int Middle, int RightCols>
3958 ExprP<Matrix<float, LeftRows, RightCols> >
3959 operator* (const ExprP<Matrix<float, LeftRows, Middle> >& left,
3960 const ExprP<Matrix<float, Middle, RightCols> >& right)
3962 return app<MatMul<LeftRows, Middle, RightCols> >(left, right);
3965 template<int Rows, int Cols>
3966 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
3967 const ExprP<Matrix<float, Rows, Cols> >& right)
3969 return app<VecMatMul<Rows, Cols> >(left, right);
3972 template<int Rows, int Cols>
3973 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
3974 const ExprP<Vector<float, Rows> >& right)
3976 return app<MatVecMul<Rows, Cols> >(left, right);
3979 template<int Rows, int Cols>
3980 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
3981 const ExprP<float>& right)
3983 return app<ScalarMatFunc<Mul, Rows, Cols> >(left, right);
3986 template<int Rows, int Cols>
3987 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
3988 const ExprP<Matrix<float, Rows, Cols> >& right)
3990 return app<CompMatFunc<Add, Rows, Cols> >(left, right);
3993 template<int Rows, int Cols>
3994 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat)
3996 return app<MatNeg<Rows, Cols> >(mat);
3999 template <typename T>
4003 virtual void genFixeds (const FloatFormat&, vector<T>&) const {}
4004 virtual T genRandom (const FloatFormat&, Precision, Random&) const { return T(); }
4005 virtual double getWeight (void) const { return 0.0; }
4009 class DefaultSampling<Void> : public Sampling<Void>
4012 void genFixeds (const FloatFormat&, vector<Void>& dst) const { dst.push_back(Void()); }
4016 class DefaultSampling<bool> : public Sampling<bool>
4019 void genFixeds (const FloatFormat&, vector<bool>& dst) const
4021 dst.push_back(true);
4022 dst.push_back(false);
4027 class DefaultSampling<int> : public Sampling<int>
4030 int genRandom (const FloatFormat&, Precision prec, Random& rnd) const
4032 const int exp = rnd.getInt(0, getNumBits(prec)-2);
4033 const int sign = rnd.getBool() ? -1 : 1;
4035 return sign * rnd.getInt(0, (deInt32)1 << exp);
4038 void genFixeds (const FloatFormat&, vector<int>& dst) const
4044 double getWeight (void) const { return 1.0; }
4047 static inline int getNumBits (Precision prec)
4051 case glu::PRECISION_LOWP: return 8;
4052 case glu::PRECISION_MEDIUMP: return 16;
4053 case glu::PRECISION_HIGHP: return 32;
4062 class DefaultSampling<float> : public Sampling<float>
4065 float genRandom (const FloatFormat& format, Precision prec, Random& rnd) const;
4066 void genFixeds (const FloatFormat& format, vector<float>& dst) const;
4067 double getWeight (void) const { return 1.0; }
4070 //! Generate a random float from a reasonable general-purpose distribution.
4071 float DefaultSampling<float>::genRandom (const FloatFormat& format,
4075 const int minExp = format.getMinExp();
4076 const int maxExp = format.getMaxExp();
4077 const bool haveSubnormal = format.hasSubnormal() != tcu::NO;
4079 // Choose exponent so that the cumulative distribution is cubic.
4080 // This makes the probability distribution quadratic, with the peak centered on zero.
4081 const double minRoot = deCbrt(minExp - 0.5 - (haveSubnormal ? 1.0 : 0.0));
4082 const double maxRoot = deCbrt(maxExp + 0.5);
4083 const int fractionBits = format.getFractionBits();
4084 const int exp = int(deRoundEven(dePow(rnd.getDouble(minRoot, maxRoot),
4086 float base = 0.0f; // integral power of two
4087 float quantum = 0.0f; // smallest representable difference in the binade
4088 float significand = 0.0f; // Significand.
4090 DE_ASSERT(fractionBits < std::numeric_limits<float>::digits);
4092 // Generate some occasional special numbers
4093 switch (rnd.getInt(0, 64))
4096 case 1: return TCU_INFINITY;
4097 case 2: return -TCU_INFINITY;
4098 case 3: return TCU_NAN;
4105 base = deFloatLdExp(1.0f, exp);
4106 quantum = deFloatLdExp(1.0f, exp - fractionBits);
4112 quantum = deFloatLdExp(1.0f, minExp - fractionBits);
4115 switch (rnd.getInt(0, 16))
4117 case 0: // The highest number in this binade, significand is all bits one.
4118 significand = base - quantum;
4120 case 1: // Significand is one.
4121 significand = quantum;
4123 case 2: // Significand is zero.
4126 default: // Random (evenly distributed) significand.
4128 deUint64 intFraction = rnd.getUint64() & ((1 << fractionBits) - 1);
4129 significand = float(intFraction) * quantum;
4133 // Produce positive numbers more often than negative.
4134 return (rnd.getInt(0,3) == 0 ? -1.0f : 1.0f) * (base + significand);
4137 //! Generate a standard set of floats that should always be tested.
4138 void DefaultSampling<float>::genFixeds (const FloatFormat& format, vector<float>& dst) const
4140 const int minExp = format.getMinExp();
4141 const int maxExp = format.getMaxExp();
4142 const int fractionBits = format.getFractionBits();
4143 const float minQuantum = deFloatLdExp(1.0f, minExp - fractionBits);
4144 const float minNormalized = deFloatLdExp(1.0f, minExp);
4145 const float maxQuantum = deFloatLdExp(1.0f, maxExp - fractionBits);
4148 dst.push_back(TCU_NAN);
4150 dst.push_back(0.0f);
4152 for (int sign = -1; sign <= 1; sign += 2)
4154 // Smallest subnormal
4155 dst.push_back((float)sign * minQuantum);
4157 // Largest subnormal
4158 dst.push_back((float)sign * (minNormalized - minQuantum));
4160 // Smallest normalized
4161 dst.push_back((float)sign * minNormalized);
4163 // Next smallest normalized
4164 dst.push_back((float)sign * (minNormalized + minQuantum));
4166 dst.push_back((float)sign * 0.5f);
4167 dst.push_back((float)sign * 1.0f);
4168 dst.push_back((float)sign * 2.0f);
4171 dst.push_back((float)sign * (deFloatLdExp(1.0f, maxExp) +
4172 (deFloatLdExp(1.0f, maxExp) - maxQuantum)));
4174 dst.push_back((float)sign * TCU_INFINITY);
4178 template <typename T, int Size>
4179 class DefaultSampling<Vector<T, Size> > : public Sampling<Vector<T, Size> >
4182 typedef Vector<T, Size> Value;
4184 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4188 for (int ndx = 0; ndx < Size; ++ndx)
4189 ret[ndx] = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4194 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4198 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4200 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4201 dst.push_back(Value(scalars[scalarNdx]));
4204 double getWeight (void) const
4206 return dePow(instance<DefaultSampling<T> >().getWeight(), Size);
4210 template <typename T, int Rows, int Columns>
4211 class DefaultSampling<Matrix<T, Rows, Columns> > : public Sampling<Matrix<T, Rows, Columns> >
4214 typedef Matrix<T, Rows, Columns> Value;
4216 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4220 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
4221 for (int colNdx = 0; colNdx < Columns; ++colNdx)
4222 ret(rowNdx, colNdx) = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4227 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4231 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4233 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4234 dst.push_back(Value(scalars[scalarNdx]));
4236 if (Columns == Rows)
4241 for (int ndx = 0; ndx < Columns; ++ndx)
4243 mat[Columns-1-ndx][ndx] = x;
4250 double getWeight (void) const
4252 return dePow(instance<DefaultSampling<T> >().getWeight(), Rows * Columns);
4258 Context (const string& name_,
4259 TestContext& testContext_,
4260 RenderContext& renderContext_,
4261 const FloatFormat& floatFormat_,
4262 const FloatFormat& highpFormat_,
4263 Precision precision_,
4264 ShaderType shaderType_,
4267 , testContext (testContext_)
4268 , renderContext (renderContext_)
4269 , floatFormat (floatFormat_)
4270 , highpFormat (highpFormat_)
4271 , precision (precision_)
4272 , shaderType (shaderType_)
4273 , numRandoms (numRandoms_) {}
4276 TestContext& testContext;
4277 RenderContext& renderContext;
4278 FloatFormat floatFormat;
4279 FloatFormat highpFormat;
4280 Precision precision;
4281 ShaderType shaderType;
4285 template<typename In0_ = Void, typename In1_ = Void, typename In2_ = Void, typename In3_ = Void>
4294 template <typename In>
4295 int numInputs (void)
4297 return (!isTypeValid<typename In::In0>() ? 0 :
4298 !isTypeValid<typename In::In1>() ? 1 :
4299 !isTypeValid<typename In::In2>() ? 2 :
4300 !isTypeValid<typename In::In3>() ? 3 :
4304 template<typename Out0_, typename Out1_ = Void>
4311 template <typename Out>
4312 int numOutputs (void)
4314 return (!isTypeValid<typename Out::Out0>() ? 0 :
4315 !isTypeValid<typename Out::Out1>() ? 1 :
4319 template<typename In>
4322 vector<typename In::In0> in0;
4323 vector<typename In::In1> in1;
4324 vector<typename In::In2> in2;
4325 vector<typename In::In3> in3;
4328 template<typename Out>
4331 Outputs (size_t size) : out0(size), out1(size) {}
4333 vector<typename Out::Out0> out0;
4334 vector<typename Out::Out1> out1;
4337 template<typename In, typename Out>
4340 VariableP<typename In::In0> in0;
4341 VariableP<typename In::In1> in1;
4342 VariableP<typename In::In2> in2;
4343 VariableP<typename In::In3> in3;
4344 VariableP<typename Out::Out0> out0;
4345 VariableP<typename Out::Out1> out1;
4348 template<typename In>
4351 Samplings (const Sampling<typename In::In0>& in0_,
4352 const Sampling<typename In::In1>& in1_,
4353 const Sampling<typename In::In2>& in2_,
4354 const Sampling<typename In::In3>& in3_)
4355 : in0 (in0_), in1 (in1_), in2 (in2_), in3 (in3_) {}
4357 const Sampling<typename In::In0>& in0;
4358 const Sampling<typename In::In1>& in1;
4359 const Sampling<typename In::In2>& in2;
4360 const Sampling<typename In::In3>& in3;
4363 template<typename In>
4364 struct DefaultSamplings : Samplings<In>
4366 DefaultSamplings (void)
4367 : Samplings<In>(instance<DefaultSampling<typename In::In0> >(),
4368 instance<DefaultSampling<typename In::In1> >(),
4369 instance<DefaultSampling<typename In::In2> >(),
4370 instance<DefaultSampling<typename In::In3> >()) {}
4373 class PrecisionCase : public TestCase
4376 IterateResult iterate (void);
4379 PrecisionCase (const Context& context,
4381 const string& extension = "")
4382 : TestCase (context.testContext,
4387 , m_rnd (0xdeadbeefu +
4388 context.testContext.getCommandLine().getBaseSeed())
4389 , m_extension (extension)
4393 RenderContext& getRenderContext(void) const { return m_ctx.renderContext; }
4395 const FloatFormat& getFormat (void) const { return m_ctx.floatFormat; }
4397 TestLog& log (void) const { return m_testCtx.getLog(); }
4399 virtual void runTest (void) = 0;
4401 template <typename In, typename Out>
4402 void testStatement (const Variables<In, Out>& variables,
4403 const Inputs<In>& inputs,
4404 const Statement& stmt);
4406 template<typename T>
4407 Symbol makeSymbol (const Variable<T>& variable)
4409 return Symbol(variable.getName(), getVarTypeOf<T>(m_ctx.precision));
4413 ResultCollector m_status;
4415 const string m_extension;
4418 IterateResult PrecisionCase::iterate (void)
4421 m_status.setTestContextResult(m_testCtx);
4425 template <typename In, typename Out>
4426 void PrecisionCase::testStatement (const Variables<In, Out>& variables,
4427 const Inputs<In>& inputs,
4428 const Statement& stmt)
4430 using namespace ShaderExecUtil;
4432 typedef typename In::In0 In0;
4433 typedef typename In::In1 In1;
4434 typedef typename In::In2 In2;
4435 typedef typename In::In3 In3;
4436 typedef typename Out::Out0 Out0;
4437 typedef typename Out::Out1 Out1;
4439 const FloatFormat& fmt = getFormat();
4440 const int inCount = numInputs<In>();
4441 const int outCount = numOutputs<Out>();
4442 const size_t numValues = (inCount > 0) ? inputs.in0.size() : 1;
4443 Outputs<Out> outputs (numValues);
4445 const FloatFormat highpFmt = m_ctx.highpFormat;
4446 const int maxMsgs = 100;
4448 Environment env; // Hoisted out of the inner loop for optimization.
4452 case 4: DE_ASSERT(inputs.in3.size() == numValues);
4453 case 3: DE_ASSERT(inputs.in2.size() == numValues);
4454 case 2: DE_ASSERT(inputs.in1.size() == numValues);
4455 case 1: DE_ASSERT(inputs.in0.size() == numValues);
4459 // Print out the statement and its definitions
4460 log() << TestLog::Message << "Statement: " << stmt << TestLog::EndMessage;
4465 stmt.getUsedFuncs(funcs);
4466 for (FuncSet::const_iterator it = funcs.begin(); it != funcs.end(); ++it)
4468 (*it)->printDefinition(oss);
4471 log() << TestLog::Message << "Reference definitions:\n" << oss.str()
4472 << TestLog::EndMessage;
4475 // Initialize ShaderSpec from precision, variables and statement.
4478 os << "precision " << glu::getPrecisionName(m_ctx.precision) << " float;\n";
4479 spec.globalDeclarations = os.str();
4482 spec.version = getContextTypeGLSLVersion(getRenderContext().getType());
4484 if (!m_extension.empty())
4485 spec.globalDeclarations = "#extension " + m_extension + " : require\n";
4487 spec.inputs.resize(inCount);
4491 case 4: spec.inputs[3] = makeSymbol(*variables.in3);
4492 case 3: spec.inputs[2] = makeSymbol(*variables.in2);
4493 case 2: spec.inputs[1] = makeSymbol(*variables.in1);
4494 case 1: spec.inputs[0] = makeSymbol(*variables.in0);
4498 spec.outputs.resize(outCount);
4502 case 2: spec.outputs[1] = makeSymbol(*variables.out1);
4503 case 1: spec.outputs[0] = makeSymbol(*variables.out0);
4507 spec.source = de::toString(stmt);
4509 // Run the shader with inputs.
4511 UniquePtr<ShaderExecutor> executor (createExecutor(getRenderContext(),
4514 const void* inputArr[] =
4516 &inputs.in0.front(), &inputs.in1.front(), &inputs.in2.front(), &inputs.in3.front(),
4520 &outputs.out0.front(), &outputs.out1.front(),
4523 executor->log(log());
4524 if (!executor->isOk())
4525 TCU_FAIL("Shader compilation failed");
4527 executor->useProgram();
4528 executor->execute(int(numValues), inputArr, outputArr);
4531 // Initialize environment with dummy values so we don't need to bind in inner loop.
4533 const typename Traits<In0>::IVal in0;
4534 const typename Traits<In1>::IVal in1;
4535 const typename Traits<In2>::IVal in2;
4536 const typename Traits<In3>::IVal in3;
4537 const typename Traits<Out0>::IVal reference0;
4538 const typename Traits<Out1>::IVal reference1;
4540 env.bind(*variables.in0, in0);
4541 env.bind(*variables.in1, in1);
4542 env.bind(*variables.in2, in2);
4543 env.bind(*variables.in3, in3);
4544 env.bind(*variables.out0, reference0);
4545 env.bind(*variables.out1, reference1);
4548 // For each input tuple, compute output reference interval and compare
4549 // shader output to the reference.
4550 for (size_t valueNdx = 0; valueNdx < numValues; valueNdx++)
4553 typename Traits<Out0>::IVal reference0;
4554 typename Traits<Out1>::IVal reference1;
4556 env.lookup(*variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx]));
4557 env.lookup(*variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx]));
4558 env.lookup(*variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx]));
4559 env.lookup(*variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx]));
4562 EvalContext ctx (fmt, m_ctx.precision, env);
4569 reference1 = convert<Out1>(highpFmt, env.lookup(*variables.out1));
4570 if (!m_status.check(contains(reference1, outputs.out1[valueNdx]),
4571 "Shader output 1 is outside acceptable range"))
4574 reference0 = convert<Out0>(highpFmt, env.lookup(*variables.out0));
4575 if (!m_status.check(contains(reference0, outputs.out0[valueNdx]),
4576 "Shader output 0 is outside acceptable range"))
4584 if ((!result && numErrors <= maxMsgs) || GLS_LOG_ALL_RESULTS)
4586 MessageBuilder builder = log().message();
4588 builder << (result ? "Passed" : "Failed") << " sample:\n";
4592 builder << "\t" << variables.in0->getName() << " = "
4593 << valueToString(highpFmt, inputs.in0[valueNdx]) << "\n";
4598 builder << "\t" << variables.in1->getName() << " = "
4599 << valueToString(highpFmt, inputs.in1[valueNdx]) << "\n";
4604 builder << "\t" << variables.in2->getName() << " = "
4605 << valueToString(highpFmt, inputs.in2[valueNdx]) << "\n";
4610 builder << "\t" << variables.in3->getName() << " = "
4611 << valueToString(highpFmt, inputs.in3[valueNdx]) << "\n";
4616 builder << "\t" << variables.out0->getName() << " = "
4617 << valueToString(highpFmt, outputs.out0[valueNdx]) << "\n"
4618 << "\tExpected range: "
4619 << intervalToString<typename Out::Out0>(highpFmt, reference0) << "\n";
4624 builder << "\t" << variables.out1->getName() << " = "
4625 << valueToString(highpFmt, outputs.out1[valueNdx]) << "\n"
4626 << "\tExpected range: "
4627 << intervalToString<typename Out::Out1>(highpFmt, reference1) << "\n";
4630 builder << TestLog::EndMessage;
4634 if (numErrors > maxMsgs)
4636 log() << TestLog::Message << "(Skipped " << (numErrors - maxMsgs) << " messages.)"
4637 << TestLog::EndMessage;
4642 log() << TestLog::Message << "All " << numValues << " inputs passed."
4643 << TestLog::EndMessage;
4647 log() << TestLog::Message << numErrors << "/" << numValues << " inputs failed."
4648 << TestLog::EndMessage;
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,
4760 Inputs<In> fixedInputs;
4761 set<InTuple<In>, InputLess<InTuple<In> > > seenInputs;
4763 samplings.in0.genFixeds(floatFormat, fixedInputs.in0);
4764 samplings.in1.genFixeds(floatFormat, fixedInputs.in1);
4765 samplings.in2.genFixeds(floatFormat, fixedInputs.in2);
4766 samplings.in3.genFixeds(floatFormat, fixedInputs.in3);
4768 for (size_t ndx0 = 0; ndx0 < fixedInputs.in0.size(); ++ndx0)
4770 for (size_t ndx1 = 0; ndx1 < fixedInputs.in1.size(); ++ndx1)
4772 for (size_t ndx2 = 0; ndx2 < fixedInputs.in2.size(); ++ndx2)
4774 for (size_t ndx3 = 0; ndx3 < fixedInputs.in3.size(); ++ndx3)
4776 const InTuple<In> tuple (fixedInputs.in0[ndx0],
4777 fixedInputs.in1[ndx1],
4778 fixedInputs.in2[ndx2],
4779 fixedInputs.in3[ndx3]);
4781 seenInputs.insert(tuple);
4782 ret.in0.push_back(tuple.a);
4783 ret.in1.push_back(tuple.b);
4784 ret.in2.push_back(tuple.c);
4785 ret.in3.push_back(tuple.d);
4791 for (size_t ndx = 0; ndx < numSamples; ++ndx)
4793 const typename In::In0 in0 = samplings.in0.genRandom(floatFormat, intPrecision, rnd);
4794 const typename In::In1 in1 = samplings.in1.genRandom(floatFormat, intPrecision, rnd);
4795 const typename In::In2 in2 = samplings.in2.genRandom(floatFormat, intPrecision, rnd);
4796 const typename In::In3 in3 = samplings.in3.genRandom(floatFormat, intPrecision, rnd);
4797 const InTuple<In> tuple (in0, in1, in2, in3);
4799 if (de::contains(seenInputs, tuple))
4802 seenInputs.insert(tuple);
4803 ret.in0.push_back(in0);
4804 ret.in1.push_back(in1);
4805 ret.in2.push_back(in2);
4806 ret.in3.push_back(in3);
4812 class FuncCaseBase : public PrecisionCase
4815 IterateResult iterate (void);
4818 FuncCaseBase (const Context& context,
4820 const FuncBase& func)
4821 : PrecisionCase (context, name, func.getRequiredExtension()) {}
4824 IterateResult FuncCaseBase::iterate (void)
4826 MovePtr<ContextInfo> info (ContextInfo::create(getRenderContext()));
4828 if (!m_extension.empty() && !info->isExtensionSupported(m_extension.c_str()))
4829 throw NotSupportedError("Unsupported extension: " + m_extension);
4833 m_status.setTestContextResult(m_testCtx);
4837 template <typename Sig>
4838 class FuncCase : public FuncCaseBase
4841 typedef Func<Sig> CaseFunc;
4842 typedef typename Sig::Ret Ret;
4843 typedef typename Sig::Arg0 Arg0;
4844 typedef typename Sig::Arg1 Arg1;
4845 typedef typename Sig::Arg2 Arg2;
4846 typedef typename Sig::Arg3 Arg3;
4847 typedef InTypes<Arg0, Arg1, Arg2, Arg3> In;
4848 typedef OutTypes<Ret> Out;
4850 FuncCase (const Context& context,
4852 const CaseFunc& func)
4853 : FuncCaseBase (context, name, func)
4857 void runTest (void);
4859 virtual const Samplings<In>& getSamplings (void)
4861 return instance<DefaultSamplings<In> >();
4865 const CaseFunc& m_func;
4868 template <typename Sig>
4869 void FuncCase<Sig>::runTest (void)
4871 const Inputs<In> inputs (generateInputs(getSamplings(),
4876 Variables<In, Out> variables;
4878 variables.out0 = variable<Ret>("out0");
4879 variables.out1 = variable<Void>("out1");
4880 variables.in0 = variable<Arg0>("in0");
4881 variables.in1 = variable<Arg1>("in1");
4882 variables.in2 = variable<Arg2>("in2");
4883 variables.in3 = variable<Arg3>("in3");
4886 ExprP<Ret> expr = applyVar(m_func,
4887 variables.in0, variables.in1,
4888 variables.in2, variables.in3);
4889 StatementP stmt = variableAssignment(variables.out0, expr);
4891 this->testStatement(variables, inputs, *stmt);
4895 template <typename Sig>
4896 class InOutFuncCase : public FuncCaseBase
4899 typedef Func<Sig> CaseFunc;
4900 typedef typename Sig::Ret Ret;
4901 typedef typename Sig::Arg0 Arg0;
4902 typedef typename Sig::Arg1 Arg1;
4903 typedef typename Sig::Arg2 Arg2;
4904 typedef typename Sig::Arg3 Arg3;
4905 typedef InTypes<Arg0, Arg2, Arg3> In;
4906 typedef OutTypes<Ret, Arg1> Out;
4908 InOutFuncCase (const Context& context,
4910 const CaseFunc& func)
4911 : FuncCaseBase (context, name, func)
4915 void runTest (void);
4917 virtual const Samplings<In>& getSamplings (void)
4919 return instance<DefaultSamplings<In> >();
4923 const CaseFunc& m_func;
4926 template <typename Sig>
4927 void InOutFuncCase<Sig>::runTest (void)
4929 const Inputs<In> inputs (generateInputs(getSamplings(),
4934 Variables<In, Out> variables;
4936 variables.out0 = variable<Ret>("out0");
4937 variables.out1 = variable<Arg1>("out1");
4938 variables.in0 = variable<Arg0>("in0");
4939 variables.in1 = variable<Arg2>("in1");
4940 variables.in2 = variable<Arg3>("in2");
4941 variables.in3 = variable<Void>("in3");
4944 ExprP<Ret> expr = applyVar(m_func,
4945 variables.in0, variables.out1,
4946 variables.in1, variables.in2);
4947 StatementP stmt = variableAssignment(variables.out0, expr);
4949 this->testStatement(variables, inputs, *stmt);
4953 template <typename Sig>
4954 PrecisionCase* createFuncCase (const Context& context,
4956 const Func<Sig>& func)
4958 switch (func.getOutParamIndex())
4961 return new FuncCase<Sig>(context, name, func);
4963 return new InOutFuncCase<Sig>(context, name, func);
4965 DE_FATAL("Impossible");
4973 virtual ~CaseFactory (void) {}
4974 virtual MovePtr<TestNode> createCase (const Context& ctx) const = 0;
4975 virtual string getName (void) const = 0;
4976 virtual string getDesc (void) const = 0;
4979 class FuncCaseFactory : public CaseFactory
4982 virtual const FuncBase& getFunc (void) const = 0;
4984 string getName (void) const
4986 return de::toLower(getFunc().getName());
4989 string getDesc (void) const
4991 return "Function '" + getFunc().getName() + "'";
4995 template <typename Sig>
4996 class GenFuncCaseFactory : public CaseFactory
5000 GenFuncCaseFactory (const GenFuncs<Sig>& funcs,
5003 , m_name (de::toLower(name)) {}
5005 MovePtr<TestNode> createCase (const Context& ctx) const
5007 TestCaseGroup* group = new TestCaseGroup(ctx.testContext,
5008 ctx.name.c_str(), ctx.name.c_str());
5010 group->addChild(createFuncCase(ctx, "scalar", m_funcs.func));
5011 group->addChild(createFuncCase(ctx, "vec2", m_funcs.func2));
5012 group->addChild(createFuncCase(ctx, "vec3", m_funcs.func3));
5013 group->addChild(createFuncCase(ctx, "vec4", m_funcs.func4));
5015 return MovePtr<TestNode>(group);
5018 string getName (void) const
5023 string getDesc (void) const
5025 return "Function '" + m_funcs.func.getName() + "'";
5029 const GenFuncs<Sig> m_funcs;
5033 template <template <int> class GenF>
5034 class TemplateFuncCaseFactory : public FuncCaseFactory
5037 MovePtr<TestNode> createCase (const Context& ctx) const
5039 TestCaseGroup* group = new TestCaseGroup(ctx.testContext,
5040 ctx.name.c_str(), ctx.name.c_str());
5041 group->addChild(createFuncCase(ctx, "scalar", instance<GenF<1> >()));
5042 group->addChild(createFuncCase(ctx, "vec2", instance<GenF<2> >()));
5043 group->addChild(createFuncCase(ctx, "vec3", instance<GenF<3> >()));
5044 group->addChild(createFuncCase(ctx, "vec4", instance<GenF<4> >()));
5046 return MovePtr<TestNode>(group);
5049 const FuncBase& getFunc (void) const { return instance<GenF<1> >(); }
5052 template <template <int> class GenF>
5053 class SquareMatrixFuncCaseFactory : public FuncCaseFactory
5056 MovePtr<TestNode> createCase (const Context& ctx) const
5058 TestCaseGroup* group = new TestCaseGroup(ctx.testContext,
5059 ctx.name.c_str(), ctx.name.c_str());
5060 group->addChild(createFuncCase(ctx, "mat2", instance<GenF<2> >()));
5062 // disabled until we get reasonable results
5063 group->addChild(createFuncCase(ctx, "mat3", instance<GenF<3> >()));
5064 group->addChild(createFuncCase(ctx, "mat4", instance<GenF<4> >()));
5067 return MovePtr<TestNode>(group);
5070 const FuncBase& getFunc (void) const { return instance<GenF<2> >(); }
5073 template <template <int, int> class GenF>
5074 class MatrixFuncCaseFactory : public FuncCaseFactory
5077 MovePtr<TestNode> createCase (const Context& ctx) const
5079 TestCaseGroup* const group = new TestCaseGroup(ctx.testContext,
5080 ctx.name.c_str(), ctx.name.c_str());
5082 this->addCase<2, 2>(ctx, group);
5083 this->addCase<3, 2>(ctx, group);
5084 this->addCase<4, 2>(ctx, group);
5085 this->addCase<2, 3>(ctx, group);
5086 this->addCase<3, 3>(ctx, group);
5087 this->addCase<4, 3>(ctx, group);
5088 this->addCase<2, 4>(ctx, group);
5089 this->addCase<3, 4>(ctx, group);
5090 this->addCase<4, 4>(ctx, group);
5092 return MovePtr<TestNode>(group);
5095 const FuncBase& getFunc (void) const { return instance<GenF<2,2> >(); }
5098 template <int Rows, int Cols>
5099 void addCase (const Context& ctx, TestCaseGroup* group) const
5101 const char* const name = dataTypeNameOf<Matrix<float, Rows, Cols> >();
5103 group->addChild(createFuncCase(ctx, name, instance<GenF<Rows, Cols> >()));
5107 template <typename Sig>
5108 class SimpleFuncCaseFactory : public CaseFactory
5111 SimpleFuncCaseFactory (const Func<Sig>& func) : m_func(func) {}
5113 MovePtr<TestNode> createCase (const Context& ctx) const
5115 return MovePtr<TestNode>(createFuncCase(ctx, ctx.name.c_str(), m_func));
5118 string getName (void) const
5120 return de::toLower(m_func.getName());
5123 string getDesc (void) const
5125 return "Function '" + getName() + "'";
5129 const Func<Sig>& m_func;
5132 template <typename F>
5133 SharedPtr<SimpleFuncCaseFactory<typename F::Sig> > createSimpleFuncCaseFactory (void)
5135 return SharedPtr<SimpleFuncCaseFactory<typename F::Sig> >(
5136 new SimpleFuncCaseFactory<typename F::Sig>(instance<F>()));
5139 class BuiltinFuncs : public CaseFactories
5142 const vector<const CaseFactory*> getFactories (void) const
5144 vector<const CaseFactory*> ret;
5146 for (size_t ndx = 0; ndx < m_factories.size(); ++ndx)
5147 ret.push_back(m_factories[ndx].get());
5152 void addFactory (SharedPtr<const CaseFactory> fact)
5154 m_factories.push_back(fact);
5158 vector<SharedPtr<const CaseFactory> > m_factories;
5161 template <typename F>
5162 void addScalarFactory(BuiltinFuncs& funcs, string name = "")
5165 name = instance<F>().getName();
5167 funcs.addFactory(SharedPtr<const CaseFactory>(new GenFuncCaseFactory<typename F::Sig>(
5168 makeVectorizedFuncs<F>(), name)));
5171 MovePtr<const CaseFactories> createES3BuiltinCases (void)
5173 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5175 addScalarFactory<Add>(*funcs);
5176 addScalarFactory<Sub>(*funcs);
5177 addScalarFactory<Mul>(*funcs);
5178 addScalarFactory<Div>(*funcs);
5180 addScalarFactory<Radians>(*funcs);
5181 addScalarFactory<Degrees>(*funcs);
5182 addScalarFactory<Sin>(*funcs);
5183 addScalarFactory<Cos>(*funcs);
5184 addScalarFactory<Tan>(*funcs);
5185 addScalarFactory<ASin>(*funcs);
5186 addScalarFactory<ACos>(*funcs);
5187 addScalarFactory<ATan2>(*funcs, "atan2");
5188 addScalarFactory<ATan>(*funcs);
5189 addScalarFactory<Sinh>(*funcs);
5190 addScalarFactory<Cosh>(*funcs);
5191 addScalarFactory<Tanh>(*funcs);
5192 addScalarFactory<ASinh>(*funcs);
5193 addScalarFactory<ACosh>(*funcs);
5194 addScalarFactory<ATanh>(*funcs);
5196 addScalarFactory<Pow>(*funcs);
5197 addScalarFactory<Exp>(*funcs);
5198 addScalarFactory<Log>(*funcs);
5199 addScalarFactory<Exp2>(*funcs);
5200 addScalarFactory<Log2>(*funcs);
5201 addScalarFactory<Sqrt>(*funcs);
5202 addScalarFactory<InverseSqrt>(*funcs);
5204 addScalarFactory<Abs>(*funcs);
5205 addScalarFactory<Sign>(*funcs);
5206 addScalarFactory<Floor>(*funcs);
5207 addScalarFactory<Trunc>(*funcs);
5208 addScalarFactory<Round>(*funcs);
5209 addScalarFactory<RoundEven>(*funcs);
5210 addScalarFactory<Ceil>(*funcs);
5211 addScalarFactory<Fract>(*funcs);
5212 addScalarFactory<Mod>(*funcs);
5213 funcs->addFactory(createSimpleFuncCaseFactory<Modf>());
5214 addScalarFactory<Min>(*funcs);
5215 addScalarFactory<Max>(*funcs);
5216 addScalarFactory<Clamp>(*funcs);
5217 addScalarFactory<Mix>(*funcs);
5218 addScalarFactory<Step>(*funcs);
5219 addScalarFactory<SmoothStep>(*funcs);
5221 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length>()));
5222 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance>()));
5223 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot>()));
5224 funcs->addFactory(createSimpleFuncCaseFactory<Cross>());
5225 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize>()));
5226 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward>()));
5227 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect>()));
5228 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract>()));
5231 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<MatrixCompMult>()));
5232 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct>()));
5233 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose>()));
5234 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant>()));
5235 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse>()));
5237 return MovePtr<const CaseFactories>(funcs.release());
5240 MovePtr<const CaseFactories> createES31BuiltinCases (void)
5242 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5244 addScalarFactory<FrExp>(*funcs);
5245 addScalarFactory<LdExp>(*funcs);
5246 addScalarFactory<Fma>(*funcs);
5248 return MovePtr<const CaseFactories>(funcs.release());
5251 struct PrecisionTestContext
5253 PrecisionTestContext (TestContext& testCtx_,
5254 RenderContext& renderCtx_,
5255 const FloatFormat& highp_,
5256 const FloatFormat& mediump_,
5257 const FloatFormat& lowp_,
5258 const vector<ShaderType>& shaderTypes_,
5260 : testCtx (testCtx_)
5261 , renderCtx (renderCtx_)
5262 , shaderTypes (shaderTypes_)
5263 , numRandoms (numRandoms_)
5265 formats[glu::PRECISION_HIGHP] = &highp_;
5266 formats[glu::PRECISION_MEDIUMP] = &mediump_;
5267 formats[glu::PRECISION_LOWP] = &lowp_;
5270 TestContext& testCtx;
5271 RenderContext& renderCtx;
5272 const FloatFormat* formats[glu::PRECISION_LAST];
5273 vector<ShaderType> shaderTypes;
5277 TestCaseGroup* createFuncGroup (const PrecisionTestContext& ctx,
5278 const CaseFactory& factory)
5280 TestCaseGroup* const group = new TestCaseGroup(ctx.testCtx,
5281 factory.getName().c_str(),
5282 factory.getDesc().c_str());
5284 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; ++precNdx)
5286 const Precision precision = Precision(precNdx);
5287 const string precName (glu::getPrecisionName(precision));
5288 const FloatFormat& fmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats, precNdx);
5289 const FloatFormat& highpFmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats,
5290 glu::PRECISION_HIGHP);
5292 for (size_t shaderNdx = 0; shaderNdx < ctx.shaderTypes.size(); ++shaderNdx)
5294 const ShaderType shaderType = ctx.shaderTypes[shaderNdx];
5295 const string shaderName (glu::getShaderTypeName(shaderType));
5296 const string name = precName + "_" + shaderName;
5297 const Context caseCtx (name, ctx.testCtx, ctx.renderCtx, fmt, highpFmt,
5298 precision, shaderType, ctx.numRandoms);
5300 group->addChild(factory.createCase(caseCtx).release());
5307 void addBuiltinPrecisionTests (TestContext& testCtx,
5308 RenderContext& renderCtx,
5309 const CaseFactories& cases,
5310 const vector<ShaderType>& shaderTypes,
5311 TestCaseGroup& dstGroup)
5313 const int userRandoms = testCtx.getCommandLine().getTestIterationCount();
5314 const int defRandoms = 16384;
5315 const int numRandoms = userRandoms > 0 ? userRandoms : defRandoms;
5316 const FloatFormat highp (-126, 127, 23, true,
5317 tcu::MAYBE, // subnormals
5318 tcu::YES, // infinities
5320 // \todo [2014-04-01 lauri] Check these once Khronos bug 11840 is resolved.
5321 const FloatFormat mediump (-13, 13, 9, false);
5322 // A fixed-point format is just a floating point format with a fixed
5323 // exponent and support for subnormals.
5324 const FloatFormat lowp (0, 0, 7, false, tcu::YES);
5325 const PrecisionTestContext ctx (testCtx, renderCtx, highp, mediump, lowp,
5326 shaderTypes, numRandoms);
5328 for (size_t ndx = 0; ndx < cases.getFactories().size(); ++ndx)
5329 dstGroup.addChild(createFuncGroup(ctx, *cases.getFactories()[ndx]));
5332 } // BuiltinPrecisionTests