1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7 * Copyright (c) 2016 The Android Open Source Project
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 * \brief Precision and range tests for builtins and types.
25 *//*--------------------------------------------------------------------*/
27 #include "vktShaderBuiltinPrecisionTests.hpp"
28 #include "vktShaderExecutor.hpp"
33 #include "deRandom.hpp"
34 #include "deSTLUtil.hpp"
35 #include "deStringUtil.hpp"
36 #include "deUniquePtr.hpp"
37 #include "deSharedPtr.hpp"
38 #include "deArrayUtil.hpp"
40 #include "tcuCommandLine.hpp"
41 #include "tcuFloatFormat.hpp"
42 #include "tcuInterval.hpp"
43 #include "tcuTestLog.hpp"
44 #include "tcuVector.hpp"
45 #include "tcuMatrix.hpp"
46 #include "tcuResultCollector.hpp"
48 #include "gluContextInfo.hpp"
49 #include "gluVarType.hpp"
50 #include "gluRenderContext.hpp"
51 #include "glwDefs.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
68 namespace shaderexecutor
74 using std::ostringstream;
84 using tcu::FloatFormat;
85 using tcu::MessageBuilder;
92 using glu::ShaderType;
94 /*--------------------------------------------------------------------*//*!
95 * \brief Generic singleton creator.
97 * instance<T>() returns a reference to a unique default-constructed instance
98 * of T. This is mainly used for our GLSL function implementations: each
99 * function is implemented by an object, and each of the objects has a
100 * distinct class. It would be extremely toilsome to maintain a separate
101 * context object that contained individual instances of the function classes,
102 * so we have to resort to global singleton instances.
104 *//*--------------------------------------------------------------------*/
105 template <typename T>
106 const T& instance (void)
108 static const T s_instance = T();
112 /*--------------------------------------------------------------------*//*!
113 * \brief Dummy placeholder type for unused template parameters.
115 * In the precision tests we are dealing with functions of different arities.
116 * To minimize code duplication, we only define templates with the maximum
117 * number of arguments, currently four. If a function's arity is less than the
118 * maximum, Void us used as the type for unused arguments.
120 * Although Voids are not used at run-time, they still must be compilable, so
121 * they must support all operations that other types do.
123 *//*--------------------------------------------------------------------*/
126 typedef Void Element;
132 template <typename T>
133 explicit Void (const T&) {}
135 operator double (void) const { return TCU_NAN; }
137 // These are used to make Voids usable as containers in container-generic code.
138 Void& operator[] (int) { return *this; }
139 const Void& operator[] (int) const { return *this; }
142 ostream& operator<< (ostream& os, Void) { return os << "()"; }
144 //! Returns true for all other types except Void
145 template <typename T> bool isTypeValid (void) { return true; }
146 template <> bool isTypeValid<Void> (void) { return false; }
148 //! Utility function for getting the name of a data type.
149 //! This is used in vector and matrix constructors.
150 template <typename T>
151 const char* dataTypeNameOf (void)
153 return glu::getDataTypeName(glu::dataTypeOf<T>());
157 const char* dataTypeNameOf<Void> (void)
159 DE_FATAL("Impossible");
163 //! A hack to get Void support for VarType.
164 template <typename T>
165 VarType getVarTypeOf (Precision prec = glu::PRECISION_LAST)
167 return glu::varTypeOf<T>(prec);
171 VarType getVarTypeOf<Void> (Precision)
173 DE_FATAL("Impossible");
177 /*--------------------------------------------------------------------*//*!
178 * \brief Type traits for generalized interval types.
180 * We are trying to compute sets of acceptable values not only for
181 * float-valued expressions but also for compound values: vectors and
182 * matrices. We approximate a set of vectors as a vector of intervals and
183 * likewise for matrices.
185 * We now need generalized operations for each type and its interval
186 * approximation. These are given in the type Traits<T>.
188 * The type Traits<T>::IVal is the approximation of T: it is `Interval` for
189 * scalar types, and a vector or matrix of intervals for container types.
191 * To allow template inference to take place, there are function wrappers for
192 * the actual operations in Traits<T>. Hence we can just use:
194 * makeIVal(someFloat)
198 * Traits<float>::doMakeIVal(value)
200 *//*--------------------------------------------------------------------*/
202 template <typename T> struct Traits;
204 //! Create container from elementwise singleton values.
205 template <typename T>
206 typename Traits<T>::IVal makeIVal (const T& value)
208 return Traits<T>::doMakeIVal(value);
211 //! Elementwise union of intervals.
212 template <typename T>
213 typename Traits<T>::IVal unionIVal (const typename Traits<T>::IVal& a,
214 const typename Traits<T>::IVal& b)
216 return Traits<T>::doUnion(a, b);
219 //! Returns true iff every element of `ival` contains the corresponding element of `value`.
220 template <typename T>
221 bool contains (const typename Traits<T>::IVal& ival, const T& value)
223 return Traits<T>::doContains(ival, value);
226 //! Print out an interval with the precision of `fmt`.
227 template <typename T>
228 void printIVal (const FloatFormat& fmt, const typename Traits<T>::IVal& ival, ostream& os)
230 Traits<T>::doPrintIVal(fmt, ival, os);
233 template <typename T>
234 string intervalToString (const FloatFormat& fmt, const typename Traits<T>::IVal& ival)
237 printIVal<T>(fmt, ival, oss);
241 //! Print out a value with the precision of `fmt`.
242 template <typename T>
243 void printValue (const FloatFormat& fmt, const T& value, ostream& os)
245 Traits<T>::doPrintValue(fmt, value, os);
248 template <typename T>
249 string valueToString (const FloatFormat& fmt, const T& val)
252 printValue(fmt, val, oss);
256 //! Approximate `value` elementwise to the float precision defined in `fmt`.
257 //! The resulting interval might not be a singleton if rounding in both
258 //! directions is allowed.
259 template <typename T>
260 typename Traits<T>::IVal round (const FloatFormat& fmt, const T& value)
262 return Traits<T>::doRound(fmt, value);
265 template <typename T>
266 typename Traits<T>::IVal convert (const FloatFormat& fmt,
267 const typename Traits<T>::IVal& value)
269 return Traits<T>::doConvert(fmt, value);
272 //! Common traits for scalar types.
273 template <typename T>
276 typedef Interval IVal;
278 static Interval doMakeIVal (const T& value)
280 // Thankfully all scalar types have a well-defined conversion to `double`,
281 // hence Interval can represent their ranges without problems.
282 return Interval(double(value));
285 static Interval doUnion (const Interval& a, const Interval& b)
290 static bool doContains (const Interval& a, T value)
292 return a.contains(double(value));
295 static Interval doConvert (const FloatFormat& fmt, const IVal& ival)
297 return fmt.convert(ival);
300 static Interval doRound (const FloatFormat& fmt, T value)
302 return fmt.roundOut(double(value), false);
307 struct Traits<float> : ScalarTraits<float>
309 static void doPrintIVal (const FloatFormat& fmt,
310 const Interval& ival,
313 os << fmt.intervalToHex(ival);
316 static void doPrintValue (const FloatFormat& fmt,
320 os << fmt.floatToHex(value);
325 struct Traits<bool> : ScalarTraits<bool>
327 static void doPrintValue (const FloatFormat&,
331 os << (value != 0.0f ? "true" : "false");
334 static void doPrintIVal (const FloatFormat&,
335 const Interval& ival,
339 if (ival.contains(false))
341 if (ival.contains(false) && ival.contains(true))
343 if (ival.contains(true))
350 struct Traits<int> : ScalarTraits<int>
352 static void doPrintValue (const FloatFormat&,
359 static void doPrintIVal (const FloatFormat&,
360 const Interval& ival,
363 os << "[" << int(ival.lo()) << ", " << int(ival.hi()) << "]";
367 //! Common traits for containers, i.e. vectors and matrices.
368 //! T is the container type itself, I is the same type with interval elements.
369 template <typename T, typename I>
370 struct ContainerTraits
372 typedef typename T::Element Element;
375 static IVal doMakeIVal (const T& value)
379 for (int ndx = 0; ndx < T::SIZE; ++ndx)
380 ret[ndx] = makeIVal(value[ndx]);
385 static IVal doUnion (const IVal& a, const IVal& b)
389 for (int ndx = 0; ndx < T::SIZE; ++ndx)
390 ret[ndx] = unionIVal<Element>(a[ndx], b[ndx]);
395 static bool doContains (const IVal& ival, const T& value)
397 for (int ndx = 0; ndx < T::SIZE; ++ndx)
398 if (!contains(ival[ndx], value[ndx]))
404 static void doPrintIVal (const FloatFormat& fmt, const IVal ival, ostream& os)
408 for (int ndx = 0; ndx < T::SIZE; ++ndx)
413 printIVal<Element>(fmt, ival[ndx], os);
419 static void doPrintValue (const FloatFormat& fmt, const T& value, ostream& os)
421 os << dataTypeNameOf<T>() << "(";
423 for (int ndx = 0; ndx < T::SIZE; ++ndx)
428 printValue<Element>(fmt, value[ndx], os);
434 static IVal doConvert (const FloatFormat& fmt, const IVal& value)
438 for (int ndx = 0; ndx < T::SIZE; ++ndx)
439 ret[ndx] = convert<Element>(fmt, value[ndx]);
444 static IVal doRound (const FloatFormat& fmt, T value)
448 for (int ndx = 0; ndx < T::SIZE; ++ndx)
449 ret[ndx] = round(fmt, value[ndx]);
455 template <typename T, int Size>
456 struct Traits<Vector<T, Size> > :
457 ContainerTraits<Vector<T, Size>, Vector<typename Traits<T>::IVal, Size> >
461 template <typename T, int Rows, int Cols>
462 struct Traits<Matrix<T, Rows, Cols> > :
463 ContainerTraits<Matrix<T, Rows, Cols>, Matrix<typename Traits<T>::IVal, Rows, Cols> >
467 //! Void traits. These are just dummies, but technically valid: a Void is a
468 //! unit type with a single possible value.
474 static Void doMakeIVal (const Void& value) { return value; }
475 static Void doUnion (const Void&, const Void&) { return Void(); }
476 static bool doContains (const Void&, Void) { return true; }
477 static Void doRound (const FloatFormat&, const Void& value) { return value; }
478 static Void doConvert (const FloatFormat&, const Void& value) { return value; }
480 static void doPrintValue (const FloatFormat&, const Void&, ostream& os)
485 static void doPrintIVal (const FloatFormat&, const Void&, ostream& os)
491 //! This is needed for container-generic operations.
492 //! We want a scalar type T to be its own "one-element vector".
493 template <typename T, int Size> struct ContainerOf { typedef Vector<T, Size> Container; };
495 template <typename T> struct ContainerOf<T, 1> { typedef T Container; };
496 template <int Size> struct ContainerOf<Void, Size> { typedef Void Container; };
498 // This is a kludge that is only needed to get the ExprP::operator[] syntactic sugar to work.
499 template <typename T> struct ElementOf { typedef typename T::Element Element; };
500 template <> struct ElementOf<float> { typedef void Element; };
501 template <> struct ElementOf<bool> { typedef void Element; };
502 template <> struct ElementOf<int> { typedef void Element; };
504 /*--------------------------------------------------------------------*//*!
506 * \name Abstract syntax for expressions and statements.
508 * We represent GLSL programs as syntax objects: an Expr<T> represents an
509 * expression whose GLSL type corresponds to the C++ type T, and a Statement
510 * represents a statement.
512 * To ease memory management, we use shared pointers to refer to expressions
513 * and statements. ExprP<T> is a shared pointer to an Expr<T>, and StatementP
514 * is a shared pointer to a Statement.
518 *//*--------------------------------------------------------------------*/
525 template <typename T> class ExprP;
526 template <typename T> class Variable;
527 template <typename T> class VariableP;
528 template <typename T> class DefaultSampling;
530 typedef set<const FuncBase*> FuncSet;
532 template <typename T>
533 VariableP<T> variable (const string& name);
534 StatementP compoundStatement (const vector<StatementP>& statements);
536 /*--------------------------------------------------------------------*//*!
537 * \brief A variable environment.
539 * An Environment object maintains the mapping between variables of the
540 * abstract syntax tree and their values.
542 * \todo [2014-03-28 lauri] At least run-time type safety.
544 *//*--------------------------------------------------------------------*/
549 void bind (const Variable<T>& variable,
550 const typename Traits<T>::IVal& value)
552 deUint8* const data = new deUint8[sizeof(value)];
554 deMemcpy(data, &value, sizeof(value));
555 de::insert(m_map, variable.getName(), SharedPtr<deUint8>(data, de::ArrayDeleter<deUint8>()));
559 typename Traits<T>::IVal& lookup (const Variable<T>& variable) const
561 deUint8* const data = de::lookup(m_map, variable.getName()).get();
563 return *reinterpret_cast<typename Traits<T>::IVal*>(data);
567 map<string, SharedPtr<deUint8> > m_map;
570 /*--------------------------------------------------------------------*//*!
571 * \brief Evaluation context.
573 * The evaluation context contains everything that separates one execution of
574 * an expression from the next. Currently this means the desired floating
575 * point precision and the current variable environment.
577 *//*--------------------------------------------------------------------*/
580 EvalContext (const FloatFormat& format_,
581 Precision floatPrecision_,
585 , floatPrecision (floatPrecision_)
587 , callDepth (callDepth_) {}
590 Precision floatPrecision;
595 /*--------------------------------------------------------------------*//*!
596 * \brief Simple incremental counter.
598 * This is used to make sure that different ExpandContexts will not produce
599 * overlapping temporary names.
601 *//*--------------------------------------------------------------------*/
605 Counter (int count = 0) : m_count(count) {}
606 int operator() (void) { return m_count++; }
615 ExpandContext (Counter& symCounter) : m_symCounter(symCounter) {}
616 ExpandContext (const ExpandContext& parent)
617 : m_symCounter(parent.m_symCounter) {}
620 VariableP<T> genSym (const string& baseName)
622 return variable<T>(baseName + de::toString(m_symCounter()));
625 void addStatement (const StatementP& stmt)
627 m_statements.push_back(stmt);
630 vector<StatementP> getStatements (void) const
635 Counter& m_symCounter;
636 vector<StatementP> m_statements;
639 /*--------------------------------------------------------------------*//*!
640 * \brief A statement or declaration.
642 * Statements have no values. Instead, they are executed for their side
643 * effects only: the execute() method should modify at least one variable in
646 * As a bit of a kludge, a Statement object can also represent a declaration:
647 * when it is evaluated, it can add a variable binding to the environment
648 * instead of modifying a current one.
650 *//*--------------------------------------------------------------------*/
654 virtual ~Statement (void) { }
655 //! Execute the statement, modifying the environment of `ctx`
656 void execute (EvalContext& ctx) const { this->doExecute(ctx); }
657 void print (ostream& os) const { this->doPrint(os); }
658 //! Add the functions used in this statement to `dst`.
659 void getUsedFuncs (FuncSet& dst) const { this->doGetUsedFuncs(dst); }
662 virtual void doPrint (ostream& os) const = 0;
663 virtual void doExecute (EvalContext& ctx) const = 0;
664 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
667 ostream& operator<<(ostream& os, const Statement& stmt)
673 /*--------------------------------------------------------------------*//*!
674 * \brief Smart pointer for statements (and declarations)
676 *//*--------------------------------------------------------------------*/
677 class StatementP : public SharedPtr<const Statement>
680 typedef SharedPtr<const Statement> Super;
683 explicit StatementP (const Statement* ptr) : Super(ptr) {}
684 StatementP (const Super& ptr) : Super(ptr) {}
687 /*--------------------------------------------------------------------*//*!
690 * A statement that modifies a variable or a declaration that binds a variable.
692 *//*--------------------------------------------------------------------*/
693 template <typename T>
694 class VariableStatement : public Statement
697 VariableStatement (const VariableP<T>& variable, const ExprP<T>& value,
699 : m_variable (variable)
701 , m_isDeclaration (isDeclaration) {}
704 void doPrint (ostream& os) const
707 os << glu::declare(getVarTypeOf<T>(), m_variable->getName());
709 os << m_variable->getName();
711 os << " = " << *m_value << ";\n";
714 void doExecute (EvalContext& ctx) const
717 ctx.env.bind(*m_variable, m_value->evaluate(ctx));
719 ctx.env.lookup(*m_variable) = m_value->evaluate(ctx);
722 void doGetUsedFuncs (FuncSet& dst) const
724 m_value->getUsedFuncs(dst);
727 VariableP<T> m_variable;
729 bool m_isDeclaration;
732 template <typename T>
733 StatementP variableStatement (const VariableP<T>& variable,
734 const ExprP<T>& value,
737 return StatementP(new VariableStatement<T>(variable, value, isDeclaration));
740 template <typename T>
741 StatementP variableDeclaration (const VariableP<T>& variable, const ExprP<T>& definiens)
743 return variableStatement(variable, definiens, true);
746 template <typename T>
747 StatementP variableAssignment (const VariableP<T>& variable, const ExprP<T>& value)
749 return variableStatement(variable, value, false);
752 /*--------------------------------------------------------------------*//*!
753 * \brief A compound statement, i.e. a block.
755 * A compound statement is executed by executing its constituent statements in
758 *//*--------------------------------------------------------------------*/
759 class CompoundStatement : public Statement
762 CompoundStatement (const vector<StatementP>& statements)
763 : m_statements (statements) {}
766 void doPrint (ostream& os) const
770 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
771 os << *m_statements[ndx];
776 void doExecute (EvalContext& ctx) const
778 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
779 m_statements[ndx]->execute(ctx);
782 void doGetUsedFuncs (FuncSet& dst) const
784 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
785 m_statements[ndx]->getUsedFuncs(dst);
788 vector<StatementP> m_statements;
791 StatementP compoundStatement(const vector<StatementP>& statements)
793 return StatementP(new CompoundStatement(statements));
796 //! Common base class for all expressions regardless of their type.
800 virtual ~ExprBase (void) {}
801 void printExpr (ostream& os) const { this->doPrintExpr(os); }
803 //! Output the functions that this expression refers to
804 void getUsedFuncs (FuncSet& dst) const
806 this->doGetUsedFuncs(dst);
810 virtual void doPrintExpr (ostream&) const {}
811 virtual void doGetUsedFuncs (FuncSet&) const {}
814 //! Type-specific operations for an expression representing type T.
815 template <typename T>
816 class Expr : public ExprBase
820 typedef typename Traits<T>::IVal IVal;
822 IVal evaluate (const EvalContext& ctx) const;
825 virtual IVal doEvaluate (const EvalContext& ctx) const = 0;
828 //! Evaluate an expression with the given context, optionally tracing the calls to stderr.
829 template <typename T>
830 typename Traits<T>::IVal Expr<T>::evaluate (const EvalContext& ctx) const
832 #ifdef GLS_ENABLE_TRACE
833 static const FloatFormat highpFmt (-126, 127, 23, true,
837 EvalContext newCtx (ctx.format, ctx.floatPrecision,
838 ctx.env, ctx.callDepth + 1);
839 const IVal ret = this->doEvaluate(newCtx);
841 if (isTypeValid<T>())
843 std::cerr << string(ctx.callDepth, ' ');
844 this->printExpr(std::cerr);
845 std::cerr << " -> " << intervalToString<T>(highpFmt, ret) << std::endl;
849 return this->doEvaluate(ctx);
853 template <typename T>
854 class ExprPBase : public SharedPtr<const Expr<T> >
859 ostream& operator<< (ostream& os, const ExprBase& expr)
865 /*--------------------------------------------------------------------*//*!
866 * \brief Shared pointer to an expression of a container type.
868 * Container types (i.e. vectors and matrices) support the subscription
869 * operator. This class provides a bit of syntactic sugar to allow us to use
870 * the C++ subscription operator to create a subscription expression.
871 *//*--------------------------------------------------------------------*/
872 template <typename T>
873 class ContainerExprPBase : public ExprPBase<T>
876 ExprP<typename T::Element> operator[] (int i) const;
879 template <typename T>
880 class ExprP : public ExprPBase<T> {};
882 // We treat Voids as containers since the dummy parameters in generalized
883 // vector functions are represented as Voids.
885 class ExprP<Void> : public ContainerExprPBase<Void> {};
887 template <typename T, int Size>
888 class ExprP<Vector<T, Size> > : public ContainerExprPBase<Vector<T, Size> > {};
890 template <typename T, int Rows, int Cols>
891 class ExprP<Matrix<T, Rows, Cols> > : public ContainerExprPBase<Matrix<T, Rows, Cols> > {};
893 template <typename T> ExprP<T> exprP (void)
898 template <typename T>
899 ExprP<T> exprP (const SharedPtr<const Expr<T> >& ptr)
902 static_cast<SharedPtr<const Expr<T> >&>(ret) = ptr;
906 template <typename T>
907 ExprP<T> exprP (const Expr<T>* ptr)
909 return exprP(SharedPtr<const Expr<T> >(ptr));
912 /*--------------------------------------------------------------------*//*!
913 * \brief A shared pointer to a variable expression.
915 * This is just a narrowing of ExprP for the operations that require a variable
916 * instead of an arbitrary expression.
918 *//*--------------------------------------------------------------------*/
919 template <typename T>
920 class VariableP : public SharedPtr<const Variable<T> >
923 typedef SharedPtr<const Variable<T> > Super;
924 explicit VariableP (const Variable<T>* ptr) : Super(ptr) {}
926 VariableP (const Super& ptr) : Super(ptr) {}
928 operator ExprP<T> (void) const { return exprP(SharedPtr<const Expr<T> >(*this)); }
931 /*--------------------------------------------------------------------*//*!
932 * \name Syntactic sugar operators for expressions.
936 * These operators allow the use of C++ syntax to construct GLSL expressions
937 * containing operators: e.g. "a+b" creates an addition expression with
938 * operands a and b, and so on.
940 *//*--------------------------------------------------------------------*/
941 ExprP<float> operator-(const ExprP<float>& arg0);
942 ExprP<float> operator+(const ExprP<float>& arg0,
943 const ExprP<float>& arg1);
944 ExprP<float> operator-(const ExprP<float>& arg0,
945 const ExprP<float>& arg1);
946 ExprP<float> operator*(const ExprP<float>& arg0,
947 const ExprP<float>& arg1);
948 ExprP<float> operator/(const ExprP<float>& arg0,
949 const ExprP<float>& arg1);
951 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0);
953 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
954 const ExprP<float>& arg1);
956 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
957 const ExprP<Vector<float, Size> >& arg1);
959 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
960 const ExprP<Vector<float, Size> >& arg1);
961 template<int Left, int Mid, int Right>
962 ExprP<Matrix<float, Left, Right> > operator* (const ExprP<Matrix<float, Left, Mid> >& left,
963 const ExprP<Matrix<float, Mid, Right> >& right);
964 template<int Rows, int Cols>
965 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
966 const ExprP<Matrix<float, Rows, Cols> >& right);
967 template<int Rows, int Cols>
968 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
969 const ExprP<Vector<float, Rows> >& right);
970 template<int Rows, int Cols>
971 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
972 const ExprP<float>& right);
973 template<int Rows, int Cols>
974 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
975 const ExprP<Matrix<float, Rows, Cols> >& right);
976 template<int Rows, int Cols>
977 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat);
981 /*--------------------------------------------------------------------*//*!
982 * \brief Variable expression.
984 * A variable is evaluated by looking up its range of possible values from an
986 *//*--------------------------------------------------------------------*/
987 template <typename T>
988 class Variable : public Expr<T>
991 typedef typename Expr<T>::IVal IVal;
993 Variable (const string& name) : m_name (name) {}
994 string getName (void) const { return m_name; }
997 void doPrintExpr (ostream& os) const { os << m_name; }
998 IVal doEvaluate (const EvalContext& ctx) const
1000 return ctx.env.lookup<T>(*this);
1007 template <typename T>
1008 VariableP<T> variable (const string& name)
1010 return VariableP<T>(new Variable<T>(name));
1013 template <typename T>
1014 VariableP<T> bindExpression (const string& name, ExpandContext& ctx, const ExprP<T>& expr)
1016 VariableP<T> var = ctx.genSym<T>(name);
1017 ctx.addStatement(variableDeclaration(var, expr));
1021 /*--------------------------------------------------------------------*//*!
1022 * \brief Constant expression.
1024 * A constant is evaluated by rounding it to a set of possible values allowed
1025 * by the current floating point precision.
1026 *//*--------------------------------------------------------------------*/
1027 template <typename T>
1028 class Constant : public Expr<T>
1031 typedef typename Expr<T>::IVal IVal;
1033 Constant (const T& value) : m_value(value) {}
1036 void doPrintExpr (ostream& os) const { os << m_value; }
1037 IVal doEvaluate (const EvalContext&) const { return makeIVal(m_value); }
1043 template <typename T>
1044 ExprP<T> constant (const T& value)
1046 return exprP(new Constant<T>(value));
1049 //! Return a reference to a singleton void constant.
1050 const ExprP<Void>& voidP (void)
1052 static const ExprP<Void> singleton = constant(Void());
1057 /*--------------------------------------------------------------------*//*!
1058 * \brief Four-element tuple.
1060 * This is used for various things where we need one thing for each possible
1061 * function parameter. Currently the maximum supported number of parameters is
1063 *//*--------------------------------------------------------------------*/
1064 template <typename T0 = Void, typename T1 = Void, typename T2 = Void, typename T3 = Void>
1067 explicit Tuple4 (const T0 e0 = T0(),
1084 /*--------------------------------------------------------------------*//*!
1085 * \brief Function signature.
1087 * This is a purely compile-time structure used to bundle all types in a
1088 * function signature together. This makes passing the signature around in
1089 * templates easier, since we only need to take and pass a single Sig instead
1090 * of a bunch of parameter types and a return type.
1092 *//*--------------------------------------------------------------------*/
1093 template <typename R,
1094 typename P0 = Void, typename P1 = Void,
1095 typename P2 = Void, typename P3 = Void>
1103 typedef typename Traits<Ret>::IVal IRet;
1104 typedef typename Traits<Arg0>::IVal IArg0;
1105 typedef typename Traits<Arg1>::IVal IArg1;
1106 typedef typename Traits<Arg2>::IVal IArg2;
1107 typedef typename Traits<Arg3>::IVal IArg3;
1109 typedef Tuple4< const Arg0&, const Arg1&, const Arg2&, const Arg3&> Args;
1110 typedef Tuple4< const IArg0&, const IArg1&, const IArg2&, const IArg3&> IArgs;
1111 typedef Tuple4< ExprP<Arg0>, ExprP<Arg1>, ExprP<Arg2>, ExprP<Arg3> > ArgExprs;
1114 typedef vector<const ExprBase*> BaseArgExprs;
1116 /*--------------------------------------------------------------------*//*!
1117 * \brief Type-independent operations for function objects.
1119 *//*--------------------------------------------------------------------*/
1123 virtual ~FuncBase (void) {}
1124 virtual string getName (void) const = 0;
1125 //! Name of extension that this function requires, or empty.
1126 virtual string getRequiredExtension (void) const { return ""; }
1127 virtual void print (ostream&,
1128 const BaseArgExprs&) const = 0;
1129 //! Index of output parameter, or -1 if none of the parameters is output.
1130 virtual int getOutParamIndex (void) const { return -1; }
1132 void printDefinition (ostream& os) const
1134 doPrintDefinition(os);
1137 void getUsedFuncs (FuncSet& dst) const
1139 this->doGetUsedFuncs(dst);
1143 virtual void doPrintDefinition (ostream& os) const = 0;
1144 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
1147 typedef Tuple4<string, string, string, string> ParamNames;
1149 /*--------------------------------------------------------------------*//*!
1150 * \brief Function objects.
1152 * Each Func object represents a GLSL function. It can be applied to interval
1153 * arguments, and it returns the an interval that is a conservative
1154 * approximation of the image of the GLSL function over the argument
1155 * intervals. That is, it is given a set of possible arguments and it returns
1156 * the set of possible values.
1158 *//*--------------------------------------------------------------------*/
1159 template <typename Sig_>
1160 class Func : public FuncBase
1164 typedef typename Sig::Ret Ret;
1165 typedef typename Sig::Arg0 Arg0;
1166 typedef typename Sig::Arg1 Arg1;
1167 typedef typename Sig::Arg2 Arg2;
1168 typedef typename Sig::Arg3 Arg3;
1169 typedef typename Sig::IRet IRet;
1170 typedef typename Sig::IArg0 IArg0;
1171 typedef typename Sig::IArg1 IArg1;
1172 typedef typename Sig::IArg2 IArg2;
1173 typedef typename Sig::IArg3 IArg3;
1174 typedef typename Sig::Args Args;
1175 typedef typename Sig::IArgs IArgs;
1176 typedef typename Sig::ArgExprs ArgExprs;
1178 void print (ostream& os,
1179 const BaseArgExprs& args) const
1181 this->doPrint(os, args);
1184 IRet apply (const EvalContext& ctx,
1185 const IArg0& arg0 = IArg0(),
1186 const IArg1& arg1 = IArg1(),
1187 const IArg2& arg2 = IArg2(),
1188 const IArg3& arg3 = IArg3()) const
1190 return this->applyArgs(ctx, IArgs(arg0, arg1, arg2, arg3));
1192 IRet applyArgs (const EvalContext& ctx,
1193 const IArgs& args) const
1195 return this->doApply(ctx, args);
1197 ExprP<Ret> operator() (const ExprP<Arg0>& arg0 = voidP(),
1198 const ExprP<Arg1>& arg1 = voidP(),
1199 const ExprP<Arg2>& arg2 = voidP(),
1200 const ExprP<Arg3>& arg3 = voidP()) const;
1202 const ParamNames& getParamNames (void) const
1204 return this->doGetParamNames();
1208 virtual IRet doApply (const EvalContext&,
1209 const IArgs&) const = 0;
1210 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1212 os << getName() << "(";
1214 if (isTypeValid<Arg0>())
1217 if (isTypeValid<Arg1>())
1218 os << ", " << *args[1];
1220 if (isTypeValid<Arg2>())
1221 os << ", " << *args[2];
1223 if (isTypeValid<Arg3>())
1224 os << ", " << *args[3];
1229 virtual const ParamNames& doGetParamNames (void) const
1231 static ParamNames names ("a", "b", "c", "d");
1236 template <typename Sig>
1237 class Apply : public Expr<typename Sig::Ret>
1240 typedef typename Sig::Ret Ret;
1241 typedef typename Sig::Arg0 Arg0;
1242 typedef typename Sig::Arg1 Arg1;
1243 typedef typename Sig::Arg2 Arg2;
1244 typedef typename Sig::Arg3 Arg3;
1245 typedef typename Expr<Ret>::Val Val;
1246 typedef typename Expr<Ret>::IVal IVal;
1247 typedef Func<Sig> ApplyFunc;
1248 typedef typename ApplyFunc::ArgExprs ArgExprs;
1250 Apply (const ApplyFunc& func,
1251 const ExprP<Arg0>& arg0 = voidP(),
1252 const ExprP<Arg1>& arg1 = voidP(),
1253 const ExprP<Arg2>& arg2 = voidP(),
1254 const ExprP<Arg3>& arg3 = voidP())
1256 m_args (arg0, arg1, arg2, arg3) {}
1258 Apply (const ApplyFunc& func,
1259 const ArgExprs& args)
1263 void doPrintExpr (ostream& os) const
1266 args.push_back(m_args.a.get());
1267 args.push_back(m_args.b.get());
1268 args.push_back(m_args.c.get());
1269 args.push_back(m_args.d.get());
1270 m_func.print(os, args);
1273 IVal doEvaluate (const EvalContext& ctx) const
1275 return m_func.apply(ctx,
1276 m_args.a->evaluate(ctx), m_args.b->evaluate(ctx),
1277 m_args.c->evaluate(ctx), m_args.d->evaluate(ctx));
1280 void doGetUsedFuncs (FuncSet& dst) const
1282 m_func.getUsedFuncs(dst);
1283 m_args.a->getUsedFuncs(dst);
1284 m_args.b->getUsedFuncs(dst);
1285 m_args.c->getUsedFuncs(dst);
1286 m_args.d->getUsedFuncs(dst);
1289 const ApplyFunc& m_func;
1293 template<typename T>
1294 class Alternatives : public Func<Signature<T, T, T> >
1297 typedef typename Alternatives::Sig Sig;
1300 typedef typename Alternatives::IRet IRet;
1301 typedef typename Alternatives::IArgs IArgs;
1303 virtual string getName (void) const { return "alternatives"; }
1304 virtual void doPrintDefinition (std::ostream&) const {}
1305 void doGetUsedFuncs (FuncSet&) const {}
1307 virtual IRet doApply (const EvalContext&, const IArgs& args) const
1309 return unionIVal<T>(args.a, args.b);
1312 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1314 os << "{" << *args[0] << " | " << *args[1] << "}";
1318 template <typename Sig>
1319 ExprP<typename Sig::Ret> createApply (const Func<Sig>& func,
1320 const typename Func<Sig>::ArgExprs& args)
1322 return exprP(new Apply<Sig>(func, args));
1325 template <typename Sig>
1326 ExprP<typename Sig::Ret> createApply (
1327 const Func<Sig>& func,
1328 const ExprP<typename Sig::Arg0>& arg0 = voidP(),
1329 const ExprP<typename Sig::Arg1>& arg1 = voidP(),
1330 const ExprP<typename Sig::Arg2>& arg2 = voidP(),
1331 const ExprP<typename Sig::Arg3>& arg3 = voidP())
1333 return exprP(new Apply<Sig>(func, arg0, arg1, arg2, arg3));
1336 template <typename Sig>
1337 ExprP<typename Sig::Ret> Func<Sig>::operator() (const ExprP<typename Sig::Arg0>& arg0,
1338 const ExprP<typename Sig::Arg1>& arg1,
1339 const ExprP<typename Sig::Arg2>& arg2,
1340 const ExprP<typename Sig::Arg3>& arg3) const
1342 return createApply(*this, arg0, arg1, arg2, arg3);
1345 template <typename F>
1346 ExprP<typename F::Ret> app (const ExprP<typename F::Arg0>& arg0 = voidP(),
1347 const ExprP<typename F::Arg1>& arg1 = voidP(),
1348 const ExprP<typename F::Arg2>& arg2 = voidP(),
1349 const ExprP<typename F::Arg3>& arg3 = voidP())
1351 return createApply(instance<F>(), arg0, arg1, arg2, arg3);
1354 template <typename F>
1355 typename F::IRet call (const EvalContext& ctx,
1356 const typename F::IArg0& arg0 = Void(),
1357 const typename F::IArg1& arg1 = Void(),
1358 const typename F::IArg2& arg2 = Void(),
1359 const typename F::IArg3& arg3 = Void())
1361 return instance<F>().apply(ctx, arg0, arg1, arg2, arg3);
1364 template <typename T>
1365 ExprP<T> alternatives (const ExprP<T>& arg0,
1366 const ExprP<T>& arg1)
1368 return createApply<typename Alternatives<T>::Sig>(instance<Alternatives<T> >(), arg0, arg1);
1371 template <typename Sig>
1372 class ApplyVar : public Apply<Sig>
1375 typedef typename Sig::Ret Ret;
1376 typedef typename Sig::Arg0 Arg0;
1377 typedef typename Sig::Arg1 Arg1;
1378 typedef typename Sig::Arg2 Arg2;
1379 typedef typename Sig::Arg3 Arg3;
1380 typedef typename Expr<Ret>::Val Val;
1381 typedef typename Expr<Ret>::IVal IVal;
1382 typedef Func<Sig> ApplyFunc;
1383 typedef typename ApplyFunc::ArgExprs ArgExprs;
1385 ApplyVar (const ApplyFunc& func,
1386 const VariableP<Arg0>& arg0,
1387 const VariableP<Arg1>& arg1,
1388 const VariableP<Arg2>& arg2,
1389 const VariableP<Arg3>& arg3)
1390 : Apply<Sig> (func, arg0, arg1, arg2, arg3) {}
1392 IVal doEvaluate (const EvalContext& ctx) const
1394 const Variable<Arg0>& var0 = static_cast<const Variable<Arg0>&>(*this->m_args.a);
1395 const Variable<Arg1>& var1 = static_cast<const Variable<Arg1>&>(*this->m_args.b);
1396 const Variable<Arg2>& var2 = static_cast<const Variable<Arg2>&>(*this->m_args.c);
1397 const Variable<Arg3>& var3 = static_cast<const Variable<Arg3>&>(*this->m_args.d);
1398 return this->m_func.apply(ctx,
1399 ctx.env.lookup(var0), ctx.env.lookup(var1),
1400 ctx.env.lookup(var2), ctx.env.lookup(var3));
1404 template <typename Sig>
1405 ExprP<typename Sig::Ret> applyVar (const Func<Sig>& func,
1406 const VariableP<typename Sig::Arg0>& arg0,
1407 const VariableP<typename Sig::Arg1>& arg1,
1408 const VariableP<typename Sig::Arg2>& arg2,
1409 const VariableP<typename Sig::Arg3>& arg3)
1411 return exprP(new ApplyVar<Sig>(func, arg0, arg1, arg2, arg3));
1414 template <typename Sig_>
1415 class DerivedFunc : public Func<Sig_>
1418 typedef typename DerivedFunc::ArgExprs ArgExprs;
1419 typedef typename DerivedFunc::IRet IRet;
1420 typedef typename DerivedFunc::IArgs IArgs;
1421 typedef typename DerivedFunc::Ret Ret;
1422 typedef typename DerivedFunc::Arg0 Arg0;
1423 typedef typename DerivedFunc::Arg1 Arg1;
1424 typedef typename DerivedFunc::Arg2 Arg2;
1425 typedef typename DerivedFunc::Arg3 Arg3;
1426 typedef typename DerivedFunc::IArg0 IArg0;
1427 typedef typename DerivedFunc::IArg1 IArg1;
1428 typedef typename DerivedFunc::IArg2 IArg2;
1429 typedef typename DerivedFunc::IArg3 IArg3;
1432 void doPrintDefinition (ostream& os) const
1434 const ParamNames& paramNames = this->getParamNames();
1438 os << dataTypeNameOf<Ret>() << " " << this->getName()
1440 if (isTypeValid<Arg0>())
1441 os << dataTypeNameOf<Arg0>() << " " << paramNames.a;
1442 if (isTypeValid<Arg1>())
1443 os << ", " << dataTypeNameOf<Arg1>() << " " << paramNames.b;
1444 if (isTypeValid<Arg2>())
1445 os << ", " << dataTypeNameOf<Arg2>() << " " << paramNames.c;
1446 if (isTypeValid<Arg3>())
1447 os << ", " << dataTypeNameOf<Arg3>() << " " << paramNames.d;
1450 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1452 os << "return " << *m_ret << ";\n";
1456 IRet doApply (const EvalContext& ctx,
1457 const IArgs& args) const
1460 IArgs& mutArgs = const_cast<IArgs&>(args);
1465 funEnv.bind(*m_var0, args.a);
1466 funEnv.bind(*m_var1, args.b);
1467 funEnv.bind(*m_var2, args.c);
1468 funEnv.bind(*m_var3, args.d);
1471 EvalContext funCtx(ctx.format, ctx.floatPrecision, funEnv, ctx.callDepth);
1473 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1474 m_body[ndx]->execute(funCtx);
1476 ret = m_ret->evaluate(funCtx);
1479 // \todo [lauri] Store references instead of values in environment
1480 const_cast<IArg0&>(mutArgs.a) = funEnv.lookup(*m_var0);
1481 const_cast<IArg1&>(mutArgs.b) = funEnv.lookup(*m_var1);
1482 const_cast<IArg2&>(mutArgs.c) = funEnv.lookup(*m_var2);
1483 const_cast<IArg3&>(mutArgs.d) = funEnv.lookup(*m_var3);
1488 void doGetUsedFuncs (FuncSet& dst) const
1491 if (dst.insert(this).second)
1493 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1494 m_body[ndx]->getUsedFuncs(dst);
1495 m_ret->getUsedFuncs(dst);
1499 virtual ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args_) const = 0;
1501 // These are transparently initialized when first needed. They cannot be
1502 // initialized in the constructor because they depend on the doExpand
1503 // method of the subclass.
1505 mutable VariableP<Arg0> m_var0;
1506 mutable VariableP<Arg1> m_var1;
1507 mutable VariableP<Arg2> m_var2;
1508 mutable VariableP<Arg3> m_var3;
1509 mutable vector<StatementP> m_body;
1510 mutable ExprP<Ret> m_ret;
1514 void initialize (void) const
1518 const ParamNames& paramNames = this->getParamNames();
1520 ExpandContext ctx (symCounter);
1523 args.a = m_var0 = variable<Arg0>(paramNames.a);
1524 args.b = m_var1 = variable<Arg1>(paramNames.b);
1525 args.c = m_var2 = variable<Arg2>(paramNames.c);
1526 args.d = m_var3 = variable<Arg3>(paramNames.d);
1528 m_ret = this->doExpand(ctx, args);
1529 m_body = ctx.getStatements();
1534 template <typename Sig>
1535 class PrimitiveFunc : public Func<Sig>
1538 typedef typename PrimitiveFunc::Ret Ret;
1539 typedef typename PrimitiveFunc::ArgExprs ArgExprs;
1542 void doPrintDefinition (ostream&) const {}
1543 void doGetUsedFuncs (FuncSet&) const {}
1546 template <typename T>
1547 class Cond : public PrimitiveFunc<Signature<T, bool, T, T> >
1550 typedef typename Cond::IArgs IArgs;
1551 typedef typename Cond::IRet IRet;
1553 string getName (void) const
1560 void doPrint (ostream& os, const BaseArgExprs& args) const
1562 os << "(" << *args[0] << " ? " << *args[1] << " : " << *args[2] << ")";
1565 IRet doApply (const EvalContext&, const IArgs& iargs)const
1569 if (iargs.a.contains(true))
1570 ret = unionIVal<T>(ret, iargs.b);
1572 if (iargs.a.contains(false))
1573 ret = unionIVal<T>(ret, iargs.c);
1579 template <typename T>
1580 class CompareOperator : public PrimitiveFunc<Signature<bool, T, T> >
1583 typedef typename CompareOperator::IArgs IArgs;
1584 typedef typename CompareOperator::IArg0 IArg0;
1585 typedef typename CompareOperator::IArg1 IArg1;
1586 typedef typename CompareOperator::IRet IRet;
1589 void doPrint (ostream& os, const BaseArgExprs& args) const
1591 os << "(" << *args[0] << getSymbol() << *args[1] << ")";
1594 Interval doApply (const EvalContext&, const IArgs& iargs) const
1596 const IArg0& arg0 = iargs.a;
1597 const IArg1& arg1 = iargs.b;
1600 if (canSucceed(arg0, arg1))
1602 if (canFail(arg0, arg1))
1608 virtual string getSymbol (void) const = 0;
1609 virtual bool canSucceed (const IArg0&, const IArg1&) const = 0;
1610 virtual bool canFail (const IArg0&, const IArg1&) const = 0;
1613 template <typename T>
1614 class LessThan : public CompareOperator<T>
1617 string getName (void) const { return "lessThan"; }
1620 string getSymbol (void) const { return "<"; }
1622 bool canSucceed (const Interval& a, const Interval& b) const
1624 return (a.lo() < b.hi());
1627 bool canFail (const Interval& a, const Interval& b) const
1629 return !(a.hi() < b.lo());
1633 template <typename T>
1634 ExprP<bool> operator< (const ExprP<T>& a, const ExprP<T>& b)
1636 return app<LessThan<T> >(a, b);
1639 template <typename T>
1640 ExprP<T> cond (const ExprP<bool>& test,
1641 const ExprP<T>& consequent,
1642 const ExprP<T>& alternative)
1644 return app<Cond<T> >(test, consequent, alternative);
1647 /*--------------------------------------------------------------------*//*!
1651 *//*--------------------------------------------------------------------*/
1653 class FloatFunc1 : public PrimitiveFunc<Signature<float, float> >
1656 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1658 return this->applyMonotone(ctx, iargs.a);
1661 Interval applyMonotone (const EvalContext& ctx, const Interval& iarg0) const
1665 TCU_INTERVAL_APPLY_MONOTONE1(ret, arg0, iarg0, val,
1666 TCU_SET_INTERVAL(val, point,
1667 point = this->applyPoint(ctx, arg0)));
1669 ret |= innerExtrema(ctx, iarg0);
1670 ret &= (this->getCodomain() | TCU_NAN);
1672 return ctx.format.convert(ret);
1675 virtual Interval innerExtrema (const EvalContext&, const Interval&) const
1677 return Interval(); // empty interval, i.e. no extrema
1680 virtual Interval applyPoint (const EvalContext& ctx, double arg0) const
1682 const double exact = this->applyExact(arg0);
1683 const double prec = this->precision(ctx, exact, arg0);
1685 return exact + Interval(-prec, prec);
1688 virtual double applyExact (double) const
1690 TCU_THROW(InternalError, "Cannot apply");
1693 virtual Interval getCodomain (void) const
1695 return Interval::unbounded(true);
1698 virtual double precision (const EvalContext& ctx, double, double) const = 0;
1701 class CFloatFunc1 : public FloatFunc1
1704 CFloatFunc1 (const string& name, tcu::DoubleFunc1& func)
1705 : m_name(name), m_func(func) {}
1707 string getName (void) const { return m_name; }
1710 double applyExact (double x) const { return m_func(x); }
1712 const string m_name;
1713 tcu::DoubleFunc1& m_func;
1716 class FloatFunc2 : public PrimitiveFunc<Signature<float, float, float> >
1719 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1721 return this->applyMonotone(ctx, iargs.a, iargs.b);
1724 Interval applyMonotone (const EvalContext& ctx,
1726 const Interval& yi) const
1730 TCU_INTERVAL_APPLY_MONOTONE2(reti, x, xi, y, yi, ret,
1731 TCU_SET_INTERVAL(ret, point,
1732 point = this->applyPoint(ctx, x, y)));
1733 reti |= innerExtrema(ctx, xi, yi);
1734 reti &= (this->getCodomain() | TCU_NAN);
1736 return ctx.format.convert(reti);
1739 virtual Interval innerExtrema (const EvalContext&,
1741 const Interval&) const
1743 return Interval(); // empty interval, i.e. no extrema
1746 virtual Interval applyPoint (const EvalContext& ctx,
1750 const double exact = this->applyExact(x, y);
1751 const double prec = this->precision(ctx, exact, x, y);
1753 return exact + Interval(-prec, prec);
1756 virtual double applyExact (double, double) const
1758 TCU_THROW(InternalError, "Cannot apply");
1761 virtual Interval getCodomain (void) const
1763 return Interval::unbounded(true);
1766 virtual double precision (const EvalContext& ctx,
1769 double y) const = 0;
1772 class CFloatFunc2 : public FloatFunc2
1775 CFloatFunc2 (const string& name,
1776 tcu::DoubleFunc2& func)
1782 string getName (void) const { return m_name; }
1785 double applyExact (double x, double y) const { return m_func(x, y); }
1787 const string m_name;
1788 tcu::DoubleFunc2& m_func;
1791 class InfixOperator : public FloatFunc2
1794 virtual string getSymbol (void) const = 0;
1796 void doPrint (ostream& os, const BaseArgExprs& args) const
1798 os << "(" << *args[0] << " " << getSymbol() << " " << *args[1] << ")";
1801 Interval applyPoint (const EvalContext& ctx,
1805 const double exact = this->applyExact(x, y);
1807 // Allow either representable number on both sides of the exact value,
1808 // but require exactly representable values to be preserved.
1809 return ctx.format.roundOut(exact, !deIsInf(x) && !deIsInf(y));
1812 double precision (const EvalContext&, double, double, double) const
1818 class FloatFunc3 : public PrimitiveFunc<Signature<float, float, float, float> >
1821 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1823 return this->applyMonotone(ctx, iargs.a, iargs.b, iargs.c);
1826 Interval applyMonotone (const EvalContext& ctx,
1829 const Interval& zi) const
1832 TCU_INTERVAL_APPLY_MONOTONE3(reti, x, xi, y, yi, z, zi, ret,
1833 TCU_SET_INTERVAL(ret, point,
1834 point = this->applyPoint(ctx, x, y, z)));
1835 return ctx.format.convert(reti);
1838 virtual Interval applyPoint (const EvalContext& ctx,
1843 const double exact = this->applyExact(x, y, z);
1844 const double prec = this->precision(ctx, exact, x, y, z);
1845 return exact + Interval(-prec, prec);
1848 virtual double applyExact (double, double, double) const
1850 TCU_THROW(InternalError, "Cannot apply");
1853 virtual double precision (const EvalContext& ctx,
1857 double z) const = 0;
1860 // We define syntactic sugar functions for expression constructors. Since
1861 // these have the same names as ordinary mathematical operations (sin, log
1862 // etc.), it's better to give them a dedicated namespace.
1866 using namespace tcu;
1868 class Add : public InfixOperator
1871 string getName (void) const { return "add"; }
1872 string getSymbol (void) const { return "+"; }
1874 Interval doApply (const EvalContext& ctx,
1875 const IArgs& iargs) const
1877 // Fast-path for common case
1878 if (iargs.a.isOrdinary() && iargs.b.isOrdinary())
1881 TCU_SET_INTERVAL_BOUNDS(ret, sum,
1882 sum = iargs.a.lo() + iargs.b.lo(),
1883 sum = iargs.a.hi() + iargs.b.hi());
1884 return ctx.format.convert(ctx.format.roundOut(ret, true));
1886 return this->applyMonotone(ctx, iargs.a, iargs.b);
1890 double applyExact (double x, double y) const { return x + y; }
1893 class Mul : public InfixOperator
1896 string getName (void) const { return "mul"; }
1897 string getSymbol (void) const { return "*"; }
1899 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1901 Interval a = iargs.a;
1902 Interval b = iargs.b;
1904 // Fast-path for common case
1905 if (a.isOrdinary() && b.isOrdinary())
1913 if (a.lo() >= 0 && b.lo() >= 0)
1915 TCU_SET_INTERVAL_BOUNDS(ret, prod,
1916 prod = iargs.a.lo() * iargs.b.lo(),
1917 prod = iargs.a.hi() * iargs.b.hi());
1918 return ctx.format.convert(ctx.format.roundOut(ret, true));
1920 if (a.lo() >= 0 && b.hi() <= 0)
1922 TCU_SET_INTERVAL_BOUNDS(ret, prod,
1923 prod = iargs.a.hi() * iargs.b.lo(),
1924 prod = iargs.a.lo() * iargs.b.hi());
1925 return ctx.format.convert(ctx.format.roundOut(ret, true));
1928 return this->applyMonotone(ctx, iargs.a, iargs.b);
1932 double applyExact (double x, double y) const { return x * y; }
1934 Interval innerExtrema(const EvalContext&, const Interval& xi, const Interval& yi) const
1936 if (((xi.contains(-TCU_INFINITY) || xi.contains(TCU_INFINITY)) && yi.contains(0.0)) ||
1937 ((yi.contains(-TCU_INFINITY) || yi.contains(TCU_INFINITY)) && xi.contains(0.0)))
1938 return Interval(TCU_NAN);
1944 class Sub : public InfixOperator
1947 string getName (void) const { return "sub"; }
1948 string getSymbol (void) const { return "-"; }
1950 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1952 // Fast-path for common case
1953 if (iargs.a.isOrdinary() && iargs.b.isOrdinary())
1957 TCU_SET_INTERVAL_BOUNDS(ret, diff,
1958 diff = iargs.a.lo() - iargs.b.hi(),
1959 diff = iargs.a.hi() - iargs.b.lo());
1960 return ctx.format.convert(ctx.format.roundOut(ret, true));
1965 return this->applyMonotone(ctx, iargs.a, iargs.b);
1970 double applyExact (double x, double y) const { return x - y; }
1973 class Negate : public FloatFunc1
1976 string getName (void) const { return "_negate"; }
1977 void doPrint (ostream& os, const BaseArgExprs& args) const { os << "-" << *args[0]; }
1980 double precision (const EvalContext&, double, double) const { return 0.0; }
1981 double applyExact (double x) const { return -x; }
1984 class Div : public InfixOperator
1987 string getName (void) const { return "div"; }
1990 string getSymbol (void) const { return "/"; }
1992 Interval innerExtrema (const EvalContext&,
1993 const Interval& nom,
1994 const Interval& den) const
1998 if (den.contains(0.0))
2000 if (nom.contains(0.0))
2003 if (nom.lo() < 0.0 || nom.hi() > 0.0)
2004 ret |= Interval::unbounded();
2010 double applyExact (double x, double y) const { return x / y; }
2012 Interval applyPoint (const EvalContext& ctx, double x, double y) const
2014 Interval ret = FloatFunc2::applyPoint(ctx, x, y);
2016 if (!deIsInf(x) && !deIsInf(y) && y != 0.0)
2018 const Interval dst = ctx.format.convert(ret);
2019 if (dst.contains(-TCU_INFINITY)) ret |= -ctx.format.getMaxValue();
2020 if (dst.contains(+TCU_INFINITY)) ret |= +ctx.format.getMaxValue();
2026 double precision (const EvalContext& ctx, double ret, double, double den) const
2028 const FloatFormat& fmt = ctx.format;
2030 // \todo [2014-03-05 lauri] Check that the limits in GLSL 3.10 are actually correct.
2031 // For now, we assume that division's precision is 2.5 ULP when the value is within
2032 // [2^MINEXP, 2^MAXEXP-1]
2035 return 0.0; // Result must be exactly inf
2036 else if (de::inBounds(deAbs(den),
2037 deLdExp(1.0, fmt.getMinExp()),
2038 deLdExp(1.0, fmt.getMaxExp() - 1)))
2039 return fmt.ulp(ret, 2.5);
2041 return TCU_INFINITY; // Can be any number, but must be a number.
2045 class InverseSqrt : public FloatFunc1
2048 string getName (void) const { return "inversesqrt"; }
2051 double applyExact (double x) const { return 1.0 / deSqrt(x); }
2053 double precision (const EvalContext& ctx, double ret, double x) const
2055 return x <= 0 ? TCU_NAN : ctx.format.ulp(ret, 2.0);
2058 Interval getCodomain (void) const
2060 return Interval(0.0, TCU_INFINITY);
2064 class ExpFunc : public CFloatFunc1
2067 ExpFunc (const string& name, DoubleFunc1& func)
2068 : CFloatFunc1(name, func) {}
2070 double precision (const EvalContext& ctx, double ret, double x) const
2072 switch (ctx.floatPrecision)
2074 case glu::PRECISION_HIGHP:
2075 return ctx.format.ulp(ret, 3.0 + 2.0 * deAbs(x));
2076 case glu::PRECISION_MEDIUMP:
2077 return ctx.format.ulp(ret, 2.0 + 2.0 * deAbs(x));
2078 case glu::PRECISION_LOWP:
2079 return ctx.format.ulp(ret, 2.0);
2081 DE_FATAL("Impossible");
2086 Interval getCodomain (void) const
2088 return Interval(0.0, TCU_INFINITY);
2092 class Exp2 : public ExpFunc { public: Exp2 (void) : ExpFunc("exp2", deExp2) {} };
2093 class Exp : public ExpFunc { public: Exp (void) : ExpFunc("exp", deExp) {} };
2095 ExprP<float> exp2 (const ExprP<float>& x) { return app<Exp2>(x); }
2096 ExprP<float> exp (const ExprP<float>& x) { return app<Exp>(x); }
2098 class LogFunc : public CFloatFunc1
2101 LogFunc (const string& name, DoubleFunc1& func)
2102 : CFloatFunc1(name, func) {}
2105 double precision (const EvalContext& ctx, double ret, double x) const
2110 switch (ctx.floatPrecision)
2112 case glu::PRECISION_HIGHP:
2113 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -21) : ctx.format.ulp(ret, 3.0);
2114 case glu::PRECISION_MEDIUMP:
2115 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -7) : ctx.format.ulp(ret, 2.0);
2116 case glu::PRECISION_LOWP:
2117 return ctx.format.ulp(ret, 2.0);
2119 DE_FATAL("Impossible");
2126 class Log2 : public LogFunc { public: Log2 (void) : LogFunc("log2", deLog2) {} };
2127 class Log : public LogFunc { public: Log (void) : LogFunc("log", deLog) {} };
2129 ExprP<float> log2 (const ExprP<float>& x) { return app<Log2>(x); }
2130 ExprP<float> log (const ExprP<float>& x) { return app<Log>(x); }
2132 #define DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0) \
2133 ExprP<TRET> NAME (const ExprP<T0>& arg0) { return app<CLASS>(arg0); }
2135 #define DEFINE_DERIVED1(CLASS, TRET, NAME, T0, ARG0, EXPANSION) \
2136 class CLASS : public DerivedFunc<Signature<TRET, T0> > /* NOLINT(CLASS) */ \
2139 string getName (void) const { return #NAME; } \
2142 ExprP<TRET> doExpand (ExpandContext&, \
2143 const CLASS::ArgExprs& args_) const \
2145 const ExprP<float>& (ARG0) = args_.a; \
2149 DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0)
2151 #define DEFINE_DERIVED_FLOAT1(CLASS, NAME, ARG0, EXPANSION) \
2152 DEFINE_DERIVED1(CLASS, float, NAME, float, ARG0, EXPANSION)
2154 #define DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1) \
2155 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1) \
2157 return app<CLASS>(arg0, arg1); \
2160 #define DEFINE_DERIVED2(CLASS, TRET, NAME, T0, Arg0, T1, Arg1, EXPANSION) \
2161 class CLASS : public DerivedFunc<Signature<TRET, T0, T1> > /* NOLINT(CLASS) */ \
2164 string getName (void) const { return #NAME; } \
2167 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2169 const ExprP<T0>& (Arg0) = args_.a; \
2170 const ExprP<T1>& (Arg1) = args_.b; \
2174 DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1)
2176 #define DEFINE_DERIVED_FLOAT2(CLASS, NAME, Arg0, Arg1, EXPANSION) \
2177 DEFINE_DERIVED2(CLASS, float, NAME, float, Arg0, float, Arg1, EXPANSION)
2179 #define DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2) \
2180 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, const ExprP<T2>& arg2) \
2182 return app<CLASS>(arg0, arg1, arg2); \
2185 #define DEFINE_DERIVED3(CLASS, TRET, NAME, T0, ARG0, T1, ARG1, T2, ARG2, EXPANSION) \
2186 class CLASS : public DerivedFunc<Signature<TRET, T0, T1, T2> > /* NOLINT(CLASS) */ \
2189 string getName (void) const { return #NAME; } \
2192 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2194 const ExprP<T0>& (ARG0) = args_.a; \
2195 const ExprP<T1>& (ARG1) = args_.b; \
2196 const ExprP<T2>& (ARG2) = args_.c; \
2200 DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2)
2202 #define DEFINE_DERIVED_FLOAT3(CLASS, NAME, ARG0, ARG1, ARG2, EXPANSION) \
2203 DEFINE_DERIVED3(CLASS, float, NAME, float, ARG0, float, ARG1, float, ARG2, EXPANSION)
2205 #define DEFINE_CONSTRUCTOR4(CLASS, TRET, NAME, T0, T1, T2, T3) \
2206 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, \
2207 const ExprP<T2>& arg2, const ExprP<T3>& arg3) \
2209 return app<CLASS>(arg0, arg1, arg2, arg3); \
2212 DEFINE_DERIVED_FLOAT1(Sqrt, sqrt, x, constant(1.0f) / app<InverseSqrt>(x));
2213 DEFINE_DERIVED_FLOAT2(Pow, pow, x, y, exp2(y * log2(x)));
2214 DEFINE_DERIVED_FLOAT1(Radians, radians, d, (constant(DE_PI) / constant(180.0f)) * d);
2215 DEFINE_DERIVED_FLOAT1(Degrees, degrees, r, (constant(180.0f) / constant(DE_PI)) * r);
2217 class TrigFunc : public CFloatFunc1
2220 TrigFunc (const string& name,
2222 const Interval& loEx,
2223 const Interval& hiEx)
2224 : CFloatFunc1 (name, func)
2225 , m_loExtremum (loEx)
2226 , m_hiExtremum (hiEx) {}
2229 Interval innerExtrema (const EvalContext&, const Interval& angle) const
2231 const double lo = angle.lo();
2232 const double hi = angle.hi();
2233 const int loSlope = doGetSlope(lo);
2234 const int hiSlope = doGetSlope(hi);
2236 // Detect the high and low values the function can take between the
2237 // interval endpoints.
2238 if (angle.length() >= 2.0 * DE_PI_DOUBLE)
2240 // The interval is longer than a full cycle, so it must get all possible values.
2241 return m_hiExtremum | m_loExtremum;
2243 else if (loSlope == 1 && hiSlope == -1)
2245 // The slope can change from positive to negative only at the maximum value.
2246 return m_hiExtremum;
2248 else if (loSlope == -1 && hiSlope == 1)
2250 // The slope can change from negative to positive only at the maximum value.
2251 return m_loExtremum;
2253 else if (loSlope == hiSlope &&
2254 deIntSign(applyExact(hi) - applyExact(lo)) * loSlope == -1)
2256 // The slope has changed twice between the endpoints, so both extrema are included.
2257 return m_hiExtremum | m_loExtremum;
2263 Interval getCodomain (void) const
2265 // Ensure that result is always within [-1, 1], or NaN (for +-inf)
2266 return Interval(-1.0, 1.0) | TCU_NAN;
2269 double precision (const EvalContext& ctx, double ret, double arg) const
2271 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2273 // Use precision from OpenCL fast relaxed math
2274 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2276 return deLdExp(1.0, -11);
2280 // "larger otherwise", let's pick |x| * 2^-12 , which is slightly over
2281 // 2^-11 at x == pi.
2282 return deLdExp(deAbs(arg), -12);
2285 else if (ctx.floatPrecision == glu::PRECISION_MEDIUMP)
2287 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2289 // from OpenCL half-float extension specification
2290 return ctx.format.ulp(ret, 2.0);
2294 // |x| * 2^-10, slightly larger than 2 ULP at x == pi
2295 return deLdExp(deAbs(arg), -10);
2300 DE_ASSERT(ctx.floatPrecision == glu::PRECISION_LOWP);
2302 // from OpenCL half-float extension specification
2303 return ctx.format.ulp(ret, 2.0);
2307 virtual int doGetSlope (double angle) const = 0;
2309 Interval m_loExtremum;
2310 Interval m_hiExtremum;
2313 class Sin : public TrigFunc
2316 Sin (void) : TrigFunc("sin", deSin, -1.0, 1.0) {}
2319 int doGetSlope (double angle) const { return deIntSign(deCos(angle)); }
2322 ExprP<float> sin (const ExprP<float>& x) { return app<Sin>(x); }
2324 class Cos : public TrigFunc
2327 Cos (void) : TrigFunc("cos", deCos, -1.0, 1.0) {}
2330 int doGetSlope (double angle) const { return -deIntSign(deSin(angle)); }
2333 ExprP<float> cos (const ExprP<float>& x) { return app<Cos>(x); }
2335 DEFINE_DERIVED_FLOAT1(Tan, tan, x, sin(x) * (constant(1.0f) / cos(x)));
2337 class ASin : public CFloatFunc1
2340 ASin (void) : CFloatFunc1("asin", deAsin) {}
2343 double precision (const EvalContext& ctx, double, double x) const
2345 if (!de::inBounds(x, -1.0, 1.0))
2348 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2350 // Absolute error of 2^-11
2351 return deLdExp(1.0, -11);
2355 // Absolute error of 2^-8
2356 return deLdExp(1.0, -8);
2362 class ArcTrigFunc : public CFloatFunc1
2365 ArcTrigFunc (const string& name,
2367 double precisionULPs,
2368 const Interval& domain,
2369 const Interval& codomain)
2370 : CFloatFunc1 (name, func)
2371 , m_precision (precisionULPs)
2373 , m_codomain (codomain) {}
2376 double precision (const EvalContext& ctx, double ret, double x) const
2378 if (!m_domain.contains(x))
2381 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2383 // Use OpenCL's fast relaxed math precision
2384 return ctx.format.ulp(ret, m_precision);
2388 // Use OpenCL half-float spec
2389 return ctx.format.ulp(ret, 2.0);
2393 // We could implement getCodomain with m_codomain, but choose not to,
2394 // because it seems too strict with trascendental constants like pi.
2396 const double m_precision;
2397 const Interval m_domain;
2398 const Interval m_codomain;
2401 class ACos : public ArcTrigFunc
2404 ACos (void) : ArcTrigFunc("acos", deAcos, 4096.0,
2405 Interval(-1.0, 1.0),
2406 Interval(0.0, DE_PI_DOUBLE)) {}
2409 class ATan : public ArcTrigFunc
2412 ATan (void) : ArcTrigFunc("atan", deAtanOver, 4096.0,
2413 Interval::unbounded(),
2414 Interval(-DE_PI_DOUBLE * 0.5, DE_PI_DOUBLE * 0.5)) {}
2417 class ATan2 : public CFloatFunc2
2420 ATan2 (void) : CFloatFunc2 ("atan", deAtan2) {}
2423 Interval innerExtrema (const EvalContext& ctx,
2425 const Interval& xi) const
2429 if (yi.contains(0.0))
2431 if (xi.contains(0.0))
2433 if (xi.intersects(Interval(-TCU_INFINITY, 0.0)))
2434 ret |= ctx.format.roundOut(Interval(-DE_PI_DOUBLE, DE_PI_DOUBLE), true);
2437 if (ctx.format.hasInf() != YES && (!yi.isFinite() || !xi.isFinite()))
2439 // Infinities may not be supported, allow anything, including NaN
2446 double precision (const EvalContext& ctx, double ret, double, double) const
2448 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2449 return ctx.format.ulp(ret, 4096.0);
2451 return ctx.format.ulp(ret, 2.0);
2454 // Codomain could be [-pi, pi], but that would probably be too strict.
2457 DEFINE_DERIVED_FLOAT1(Sinh, sinh, x, (exp(x) - exp(-x)) / constant(2.0f));
2458 DEFINE_DERIVED_FLOAT1(Cosh, cosh, x, (exp(x) + exp(-x)) / constant(2.0f));
2459 DEFINE_DERIVED_FLOAT1(Tanh, tanh, x, sinh(x) / cosh(x));
2461 // These are not defined as derived forms in the GLSL ES spec, but
2462 // that gives us a reasonable precision.
2463 DEFINE_DERIVED_FLOAT1(ASinh, asinh, x, log(x + sqrt(x * x + constant(1.0f))));
2464 DEFINE_DERIVED_FLOAT1(ACosh, acosh, x, log(x + sqrt(alternatives((x + constant(1.0f)) * (x - constant(1.0f)),
2465 (x*x - constant(1.0f))))));
2466 DEFINE_DERIVED_FLOAT1(ATanh, atanh, x, constant(0.5f) * log((constant(1.0f) + x) /
2467 (constant(1.0f) - x)));
2469 template <typename T>
2470 class GetComponent : public PrimitiveFunc<Signature<typename T::Element, T, int> >
2473 typedef typename GetComponent::IRet IRet;
2475 string getName (void) const { return "_getComponent"; }
2477 void print (ostream& os,
2478 const BaseArgExprs& args) const
2480 os << *args[0] << "[" << *args[1] << "]";
2484 IRet doApply (const EvalContext&,
2485 const typename GetComponent::IArgs& iargs) const
2489 for (int compNdx = 0; compNdx < T::SIZE; ++compNdx)
2491 if (iargs.b.contains(compNdx))
2492 ret = unionIVal<typename T::Element>(ret, iargs.a[compNdx]);
2500 template <typename T>
2501 ExprP<typename T::Element> getComponent (const ExprP<T>& container, int ndx)
2503 DE_ASSERT(0 <= ndx && ndx < T::SIZE);
2504 return app<GetComponent<T> >(container, constant(ndx));
2507 template <typename T> string vecNamePrefix (void);
2508 template <> string vecNamePrefix<float> (void) { return ""; }
2509 template <> string vecNamePrefix<int> (void) { return "i"; }
2510 template <> string vecNamePrefix<bool> (void) { return "b"; }
2512 template <typename T, int Size>
2513 string vecName (void) { return vecNamePrefix<T>() + "vec" + de::toString(Size); }
2515 template <typename T, int Size> class GenVec;
2517 template <typename T>
2518 class GenVec<T, 1> : public DerivedFunc<Signature<T, T> >
2521 typedef typename GenVec<T, 1>::ArgExprs ArgExprs;
2523 string getName (void) const
2525 return "_" + vecName<T, 1>();
2530 ExprP<T> doExpand (ExpandContext&, const ArgExprs& args) const { return args.a; }
2533 template <typename T>
2534 class GenVec<T, 2> : public PrimitiveFunc<Signature<Vector<T, 2>, T, T> >
2537 typedef typename GenVec::IRet IRet;
2538 typedef typename GenVec::IArgs IArgs;
2540 string getName (void) const
2542 return vecName<T, 2>();
2546 IRet doApply (const EvalContext&, const IArgs& iargs) const
2548 return IRet(iargs.a, iargs.b);
2552 template <typename T>
2553 class GenVec<T, 3> : public PrimitiveFunc<Signature<Vector<T, 3>, T, T, T> >
2556 typedef typename GenVec::IRet IRet;
2557 typedef typename GenVec::IArgs IArgs;
2559 string getName (void) const
2561 return vecName<T, 3>();
2565 IRet doApply (const EvalContext&, const IArgs& iargs) const
2567 return IRet(iargs.a, iargs.b, iargs.c);
2571 template <typename T>
2572 class GenVec<T, 4> : public PrimitiveFunc<Signature<Vector<T, 4>, T, T, T, T> >
2575 typedef typename GenVec::IRet IRet;
2576 typedef typename GenVec::IArgs IArgs;
2578 string getName (void) const { return vecName<T, 4>(); }
2581 IRet doApply (const EvalContext&, const IArgs& iargs) const
2583 return IRet(iargs.a, iargs.b, iargs.c, iargs.d);
2589 template <typename T, int Rows, int Columns>
2592 template <typename T, int Rows>
2593 class GenMat<T, Rows, 2> : public PrimitiveFunc<
2594 Signature<Matrix<T, Rows, 2>, Vector<T, Rows>, Vector<T, Rows> > >
2597 typedef typename GenMat::Ret Ret;
2598 typedef typename GenMat::IRet IRet;
2599 typedef typename GenMat::IArgs IArgs;
2601 string getName (void) const
2603 return dataTypeNameOf<Ret>();
2608 IRet doApply (const EvalContext&, const IArgs& iargs) const
2617 template <typename T, int Rows>
2618 class GenMat<T, Rows, 3> : public PrimitiveFunc<
2619 Signature<Matrix<T, Rows, 3>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
2622 typedef typename GenMat::Ret Ret;
2623 typedef typename GenMat::IRet IRet;
2624 typedef typename GenMat::IArgs IArgs;
2626 string getName (void) const
2628 return dataTypeNameOf<Ret>();
2633 IRet doApply (const EvalContext&, const IArgs& iargs) const
2643 template <typename T, int Rows>
2644 class GenMat<T, Rows, 4> : public PrimitiveFunc<
2645 Signature<Matrix<T, Rows, 4>,
2646 Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
2649 typedef typename GenMat::Ret Ret;
2650 typedef typename GenMat::IRet IRet;
2651 typedef typename GenMat::IArgs IArgs;
2653 string getName (void) const
2655 return dataTypeNameOf<Ret>();
2659 IRet doApply (const EvalContext&, const IArgs& iargs) const
2670 template <typename T, int Rows>
2671 ExprP<Matrix<T, Rows, 2> > mat2 (const ExprP<Vector<T, Rows> >& arg0,
2672 const ExprP<Vector<T, Rows> >& arg1)
2674 return app<GenMat<T, Rows, 2> >(arg0, arg1);
2677 template <typename T, int Rows>
2678 ExprP<Matrix<T, Rows, 3> > mat3 (const ExprP<Vector<T, Rows> >& arg0,
2679 const ExprP<Vector<T, Rows> >& arg1,
2680 const ExprP<Vector<T, Rows> >& arg2)
2682 return app<GenMat<T, Rows, 3> >(arg0, arg1, arg2);
2685 template <typename T, int Rows>
2686 ExprP<Matrix<T, Rows, 4> > mat4 (const ExprP<Vector<T, Rows> >& arg0,
2687 const ExprP<Vector<T, Rows> >& arg1,
2688 const ExprP<Vector<T, Rows> >& arg2,
2689 const ExprP<Vector<T, Rows> >& arg3)
2691 return app<GenMat<T, Rows, 4> >(arg0, arg1, arg2, arg3);
2695 template <int Rows, int Cols>
2696 class MatNeg : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
2697 Matrix<float, Rows, Cols> > >
2700 typedef typename MatNeg::IRet IRet;
2701 typedef typename MatNeg::IArgs IArgs;
2703 string getName (void) const
2709 void doPrint (ostream& os, const BaseArgExprs& args) const
2711 os << "-(" << *args[0] << ")";
2714 IRet doApply (const EvalContext&, const IArgs& iargs) const
2718 for (int col = 0; col < Cols; ++col)
2720 for (int row = 0; row < Rows; ++row)
2721 ret[col][row] = -iargs.a[col][row];
2728 template <typename T, typename Sig>
2729 class CompWiseFunc : public PrimitiveFunc<Sig>
2732 typedef Func<Signature<T, T, T> > ScalarFunc;
2734 string getName (void) const
2736 return doGetScalarFunc().getName();
2739 void doPrint (ostream& os,
2740 const BaseArgExprs& args) const
2742 doGetScalarFunc().print(os, args);
2746 const ScalarFunc& doGetScalarFunc (void) const = 0;
2749 template <int Rows, int Cols>
2750 class CompMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
2751 Matrix<float, Rows, Cols>,
2752 Matrix<float, Rows, Cols> > >
2755 typedef typename CompMatFuncBase::IRet IRet;
2756 typedef typename CompMatFuncBase::IArgs IArgs;
2760 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
2764 for (int col = 0; col < Cols; ++col)
2766 for (int row = 0; row < Rows; ++row)
2767 ret[col][row] = this->doGetScalarFunc().apply(ctx,
2776 template <typename F, int Rows, int Cols>
2777 class CompMatFunc : public CompMatFuncBase<Rows, Cols>
2780 const typename CompMatFunc::ScalarFunc& doGetScalarFunc (void) const
2782 return instance<F>();
2786 class ScalarMatrixCompMult : public Mul
2789 string getName (void) const
2791 return "matrixCompMult";
2794 void doPrint (ostream& os, const BaseArgExprs& args) const
2796 Func<Sig>::doPrint(os, args);
2800 template <int Rows, int Cols>
2801 class MatrixCompMult : public CompMatFunc<ScalarMatrixCompMult, Rows, Cols>
2805 template <int Rows, int Cols>
2806 class ScalarMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
2807 Matrix<float, Rows, Cols>,
2811 typedef typename ScalarMatFuncBase::IRet IRet;
2812 typedef typename ScalarMatFuncBase::IArgs IArgs;
2816 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
2820 for (int col = 0; col < Cols; ++col)
2822 for (int row = 0; row < Rows; ++row)
2823 ret[col][row] = this->doGetScalarFunc().apply(ctx, iargs.a[col][row], iargs.b);
2830 template <typename F, int Rows, int Cols>
2831 class ScalarMatFunc : public ScalarMatFuncBase<Rows, Cols>
2834 const typename ScalarMatFunc::ScalarFunc& doGetScalarFunc (void) const
2836 return instance<F>();
2840 template<typename T, int Size> struct GenXType;
2842 template<typename T>
2843 struct GenXType<T, 1>
2845 static ExprP<T> genXType (const ExprP<T>& x) { return x; }
2848 template<typename T>
2849 struct GenXType<T, 2>
2851 static ExprP<Vector<T, 2> > genXType (const ExprP<T>& x)
2853 return app<GenVec<T, 2> >(x, x);
2857 template<typename T>
2858 struct GenXType<T, 3>
2860 static ExprP<Vector<T, 3> > genXType (const ExprP<T>& x)
2862 return app<GenVec<T, 3> >(x, x, x);
2866 template<typename T>
2867 struct GenXType<T, 4>
2869 static ExprP<Vector<T, 4> > genXType (const ExprP<T>& x)
2871 return app<GenVec<T, 4> >(x, x, x, x);
2875 //! Returns an expression of vector of size `Size` (or scalar if Size == 1),
2876 //! with each element initialized with the expression `x`.
2877 template<typename T, int Size>
2878 ExprP<typename ContainerOf<T, Size>::Container> genXType (const ExprP<T>& x)
2880 return GenXType<T, Size>::genXType(x);
2883 typedef GenVec<float, 2> FloatVec2;
2884 DEFINE_CONSTRUCTOR2(FloatVec2, Vec2, vec2, float, float)
2886 typedef GenVec<float, 3> FloatVec3;
2887 DEFINE_CONSTRUCTOR3(FloatVec3, Vec3, vec3, float, float, float)
2889 typedef GenVec<float, 4> FloatVec4;
2890 DEFINE_CONSTRUCTOR4(FloatVec4, Vec4, vec4, float, float, float, float)
2893 class Dot : public DerivedFunc<Signature<float, Vector<float, Size>, Vector<float, Size> > >
2896 typedef typename Dot::ArgExprs ArgExprs;
2898 string getName (void) const
2904 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2906 ExprP<float> val = args.a[0] * args.b[0];
2908 for (int ndx = 1; ndx < Size; ++ndx)
2909 val = val + args.a[ndx] * args.b[ndx];
2916 class Dot<1> : public DerivedFunc<Signature<float, float, float> >
2919 string getName (void) const
2924 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2926 return args.a * args.b;
2931 ExprP<float> dot (const ExprP<Vector<float, Size> >& x, const ExprP<Vector<float, Size> >& y)
2933 return app<Dot<Size> >(x, y);
2936 ExprP<float> dot (const ExprP<float>& x, const ExprP<float>& y)
2938 return app<Dot<1> >(x, y);
2942 class Length : public DerivedFunc<
2943 Signature<float, typename ContainerOf<float, Size>::Container> >
2946 typedef typename Length::ArgExprs ArgExprs;
2948 string getName (void) const
2954 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2956 return sqrt(dot(args.a, args.a));
2961 ExprP<float> length (const ExprP<typename ContainerOf<float, Size>::Container>& x)
2963 return app<Length<Size> >(x);
2967 class Distance : public DerivedFunc<
2969 typename ContainerOf<float, Size>::Container,
2970 typename ContainerOf<float, Size>::Container> >
2973 typedef typename Distance::Ret Ret;
2974 typedef typename Distance::ArgExprs ArgExprs;
2976 string getName (void) const
2982 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
2984 return length<Size>(args.a - args.b);
2990 class Cross : public DerivedFunc<Signature<Vec3, Vec3, Vec3> >
2993 string getName (void) const
2999 ExprP<Vec3> doExpand (ExpandContext&, const ArgExprs& x) const
3001 return vec3(x.a[1] * x.b[2] - x.b[1] * x.a[2],
3002 x.a[2] * x.b[0] - x.b[2] * x.a[0],
3003 x.a[0] * x.b[1] - x.b[0] * x.a[1]);
3007 DEFINE_CONSTRUCTOR2(Cross, Vec3, cross, Vec3, Vec3)
3010 class Normalize : public DerivedFunc<
3011 Signature<typename ContainerOf<float, Size>::Container,
3012 typename ContainerOf<float, Size>::Container> >
3015 typedef typename Normalize::Ret Ret;
3016 typedef typename Normalize::ArgExprs ArgExprs;
3018 string getName (void) const
3024 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3026 return args.a / length<Size>(args.a);
3031 class FaceForward : public DerivedFunc<
3032 Signature<typename ContainerOf<float, Size>::Container,
3033 typename ContainerOf<float, Size>::Container,
3034 typename ContainerOf<float, Size>::Container,
3035 typename ContainerOf<float, Size>::Container> >
3038 typedef typename FaceForward::Ret Ret;
3039 typedef typename FaceForward::ArgExprs ArgExprs;
3041 string getName (void) const
3043 return "faceforward";
3049 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3051 return cond(dot(args.c, args.b) < constant(0.0f), args.a, -args.a);
3056 class Reflect : public DerivedFunc<
3057 Signature<typename ContainerOf<float, Size>::Container,
3058 typename ContainerOf<float, Size>::Container,
3059 typename ContainerOf<float, Size>::Container> >
3062 typedef typename Reflect::Ret Ret;
3063 typedef typename Reflect::Arg0 Arg0;
3064 typedef typename Reflect::Arg1 Arg1;
3065 typedef typename Reflect::ArgExprs ArgExprs;
3067 string getName (void) const
3073 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3075 const ExprP<Arg0>& i = args.a;
3076 const ExprP<Arg1>& n = args.b;
3077 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3079 return i - alternatives((n * dotNI) * constant(2.0f),
3080 alternatives(n * (dotNI * constant(2.0f)),
3081 alternatives(n * dot(i * constant(2.0f), n),
3082 n * dot(i, n * constant(2.0f)))));
3087 class Refract : public DerivedFunc<
3088 Signature<typename ContainerOf<float, Size>::Container,
3089 typename ContainerOf<float, Size>::Container,
3090 typename ContainerOf<float, Size>::Container,
3094 typedef typename Refract::Ret Ret;
3095 typedef typename Refract::Arg0 Arg0;
3096 typedef typename Refract::Arg1 Arg1;
3097 typedef typename Refract::ArgExprs ArgExprs;
3099 string getName (void) const
3105 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3107 const ExprP<Arg0>& i = args.a;
3108 const ExprP<Arg1>& n = args.b;
3109 const ExprP<float>& eta = args.c;
3110 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3111 const ExprP<float> k = bindExpression("k", ctx, constant(1.0f) - eta * eta *
3112 (constant(1.0f) - dotNI * dotNI));
3114 return cond(k < constant(0.0f),
3115 genXType<float, Size>(constant(0.0f)),
3116 i * eta - n * (eta * dotNI + sqrt(k)));
3120 class PreciseFunc1 : public CFloatFunc1
3123 PreciseFunc1 (const string& name, DoubleFunc1& func) : CFloatFunc1(name, func) {}
3125 double precision (const EvalContext&, double, double) const { return 0.0; }
3128 class Abs : public PreciseFunc1
3131 Abs (void) : PreciseFunc1("abs", deAbs) {}
3134 class Sign : public PreciseFunc1
3137 Sign (void) : PreciseFunc1("sign", deSign) {}
3140 class Floor : public PreciseFunc1
3143 Floor (void) : PreciseFunc1("floor", deFloor) {}
3146 class Trunc : public PreciseFunc1
3149 Trunc (void) : PreciseFunc1("trunc", deTrunc) {}
3152 class Round : public FloatFunc1
3155 string getName (void) const { return "round"; }
3158 Interval applyPoint (const EvalContext&, double x) const
3160 double truncated = 0.0;
3161 const double fract = deModf(x, &truncated);
3164 if (fabs(fract) <= 0.5)
3166 if (fabs(fract) >= 0.5)
3167 ret |= truncated + deSign(fract);
3172 double precision (const EvalContext&, double, double) const { return 0.0; }
3175 class RoundEven : public PreciseFunc1
3178 RoundEven (void) : PreciseFunc1("roundEven", deRoundEven) {}
3181 class Ceil : public PreciseFunc1
3184 Ceil (void) : PreciseFunc1("ceil", deCeil) {}
3187 DEFINE_DERIVED_FLOAT1(Fract, fract, x, x - app<Floor>(x));
3189 class PreciseFunc2 : public CFloatFunc2
3192 PreciseFunc2 (const string& name, DoubleFunc2& func) : CFloatFunc2(name, func) {}
3194 double precision (const EvalContext&, double, double, double) const { return 0.0; }
3197 DEFINE_DERIVED_FLOAT2(Mod, mod, x, y, x - y * app<Floor>(x / y));
3199 class Modf : public PrimitiveFunc<Signature<float, float, float> >
3202 string getName (void) const
3208 IRet doApply (const EvalContext&, const IArgs& iargs) const
3211 Interval& wholeIV = const_cast<Interval&>(iargs.b);
3214 TCU_INTERVAL_APPLY_MONOTONE1(fracIV, x, iargs.a, frac, frac = deModf(x, &intPart));
3215 TCU_INTERVAL_APPLY_MONOTONE1(wholeIV, x, iargs.a, whole,
3216 deModf(x, &intPart); whole = intPart);
3218 if (!iargs.a.isFinite())
3220 // Behavior on modf(Inf) not well-defined, allow anything as a fractional part
3221 // See Khronos bug 13907
3228 int getOutParamIndex (void) const
3234 class Min : public PreciseFunc2 { public: Min (void) : PreciseFunc2("min", deMin) {} };
3235 class Max : public PreciseFunc2 { public: Max (void) : PreciseFunc2("max", deMax) {} };
3237 class Clamp : public FloatFunc3
3240 string getName (void) const { return "clamp"; }
3242 double applyExact (double x, double minVal, double maxVal) const
3244 return de::min(de::max(x, minVal), maxVal);
3247 double precision (const EvalContext&, double, double, double minVal, double maxVal) const
3249 return minVal > maxVal ? TCU_NAN : 0.0;
3253 ExprP<float> clamp(const ExprP<float>& x, const ExprP<float>& minVal, const ExprP<float>& maxVal)
3255 return app<Clamp>(x, minVal, maxVal);
3258 DEFINE_DERIVED_FLOAT3(Mix, mix, x, y, a, alternatives((x * (constant(1.0f) - a)) + y * a,
3261 static double step (double edge, double x)
3263 return x < edge ? 0.0 : 1.0;
3266 class Step : public PreciseFunc2 { public: Step (void) : PreciseFunc2("step", step) {} };
3268 class SmoothStep : public DerivedFunc<Signature<float, float, float, float> >
3271 string getName (void) const
3273 return "smoothstep";
3278 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3280 const ExprP<float>& edge0 = args.a;
3281 const ExprP<float>& edge1 = args.b;
3282 const ExprP<float>& x = args.c;
3283 const ExprP<float> tExpr = clamp((x - edge0) / (edge1 - edge0),
3284 constant(0.0f), constant(1.0f));
3285 const ExprP<float> t = bindExpression("t", ctx, tExpr);
3287 return (t * t * (constant(3.0f) - constant(2.0f) * t));
3291 class FrExp : public PrimitiveFunc<Signature<float, float, int> >
3294 string getName (void) const
3300 IRet doApply (const EvalContext&, const IArgs& iargs) const
3303 const IArg0& x = iargs.a;
3304 IArg1& exponent = const_cast<IArg1&>(iargs.b);
3306 if (x.hasNaN() || x.contains(TCU_INFINITY) || x.contains(-TCU_INFINITY))
3308 // GLSL (in contrast to IEEE) says that result of applying frexp
3309 // to infinity is undefined
3310 ret = Interval::unbounded() | TCU_NAN;
3311 exponent = Interval(-deLdExp(1.0, 31), deLdExp(1.0, 31)-1);
3313 else if (!x.empty())
3316 const double loFrac = deFrExp(x.lo(), &loExp);
3318 const double hiFrac = deFrExp(x.hi(), &hiExp);
3320 if (deSign(loFrac) != deSign(hiFrac))
3322 exponent = Interval(-TCU_INFINITY, de::max(loExp, hiExp));
3324 if (deSign(loFrac) < 0)
3325 ret |= Interval(-1.0 + DBL_EPSILON*0.5, 0.0);
3326 if (deSign(hiFrac) > 0)
3327 ret |= Interval(0.0, 1.0 - DBL_EPSILON*0.5);
3331 exponent = Interval(loExp, hiExp);
3333 ret = Interval(loFrac, hiFrac);
3335 ret = deSign(loFrac) * Interval(0.5, 1.0 - DBL_EPSILON*0.5);
3342 int getOutParamIndex (void) const
3348 class LdExp : public PrimitiveFunc<Signature<float, float, int> >
3351 string getName (void) const
3357 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
3359 Interval ret = call<Exp2>(ctx, iargs.b);
3360 // Khronos bug 11180 consensus: if exp2(exponent) cannot be represented,
3361 // the result is undefined.
3363 if (ret.contains(TCU_INFINITY) | ret.contains(-TCU_INFINITY))
3366 return call<Mul>(ctx, iargs.a, ret);
3370 template<int Rows, int Columns>
3371 class Transpose : public PrimitiveFunc<Signature<Matrix<float, Rows, Columns>,
3372 Matrix<float, Columns, Rows> > >
3375 typedef typename Transpose::IRet IRet;
3376 typedef typename Transpose::IArgs IArgs;
3378 string getName (void) const
3384 IRet doApply (const EvalContext&, const IArgs& iargs) const
3388 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
3390 for (int colNdx = 0; colNdx < Columns; ++colNdx)
3391 ret(rowNdx, colNdx) = iargs.a(colNdx, rowNdx);
3398 template<typename Ret, typename Arg0, typename Arg1>
3399 class MulFunc : public PrimitiveFunc<Signature<Ret, Arg0, Arg1> >
3402 string getName (void) const { return "mul"; }
3405 void doPrint (ostream& os, const BaseArgExprs& args) const
3407 os << "(" << *args[0] << " * " << *args[1] << ")";
3411 template<int LeftRows, int Middle, int RightCols>
3412 class MatMul : public MulFunc<Matrix<float, LeftRows, RightCols>,
3413 Matrix<float, LeftRows, Middle>,
3414 Matrix<float, Middle, RightCols> >
3417 typedef typename MatMul::IRet IRet;
3418 typedef typename MatMul::IArgs IArgs;
3419 typedef typename MatMul::IArg0 IArg0;
3420 typedef typename MatMul::IArg1 IArg1;
3422 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3424 const IArg0& left = iargs.a;
3425 const IArg1& right = iargs.b;
3428 for (int row = 0; row < LeftRows; ++row)
3430 for (int col = 0; col < RightCols; ++col)
3432 Interval element (0.0);
3434 for (int ndx = 0; ndx < Middle; ++ndx)
3435 element = call<Add>(ctx, element,
3436 call<Mul>(ctx, left[ndx][row], right[col][ndx]));
3438 ret[col][row] = element;
3446 template<int Rows, int Cols>
3447 class VecMatMul : public MulFunc<Vector<float, Cols>,
3448 Vector<float, Rows>,
3449 Matrix<float, Rows, Cols> >
3452 typedef typename VecMatMul::IRet IRet;
3453 typedef typename VecMatMul::IArgs IArgs;
3454 typedef typename VecMatMul::IArg0 IArg0;
3455 typedef typename VecMatMul::IArg1 IArg1;
3458 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3460 const IArg0& left = iargs.a;
3461 const IArg1& right = iargs.b;
3464 for (int col = 0; col < Cols; ++col)
3466 Interval element (0.0);
3468 for (int row = 0; row < Rows; ++row)
3469 element = call<Add>(ctx, element, call<Mul>(ctx, left[row], right[col][row]));
3478 template<int Rows, int Cols>
3479 class MatVecMul : public MulFunc<Vector<float, Rows>,
3480 Matrix<float, Rows, Cols>,
3481 Vector<float, Cols> >
3484 typedef typename MatVecMul::IRet IRet;
3485 typedef typename MatVecMul::IArgs IArgs;
3486 typedef typename MatVecMul::IArg0 IArg0;
3487 typedef typename MatVecMul::IArg1 IArg1;
3490 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3492 const IArg0& left = iargs.a;
3493 const IArg1& right = iargs.b;
3495 return call<VecMatMul<Cols, Rows> >(ctx, right,
3496 call<Transpose<Rows, Cols> >(ctx, left));
3500 template<int Rows, int Cols>
3501 class OuterProduct : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
3502 Vector<float, Rows>,
3503 Vector<float, Cols> > >
3506 typedef typename OuterProduct::IRet IRet;
3507 typedef typename OuterProduct::IArgs IArgs;
3509 string getName (void) const
3511 return "outerProduct";
3515 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3519 for (int row = 0; row < Rows; ++row)
3521 for (int col = 0; col < Cols; ++col)
3522 ret[col][row] = call<Mul>(ctx, iargs.a[row], iargs.b[col]);
3529 template<int Rows, int Cols>
3530 ExprP<Matrix<float, Rows, Cols> > outerProduct (const ExprP<Vector<float, Rows> >& left,
3531 const ExprP<Vector<float, Cols> >& right)
3533 return app<OuterProduct<Rows, Cols> >(left, right);
3537 class DeterminantBase : public DerivedFunc<Signature<float, Matrix<float, Size, Size> > >
3540 string getName (void) const { return "determinant"; }
3547 ExprP<float> determinant (ExprP<Matrix<float, Size, Size> > mat)
3549 return app<Determinant<Size> >(mat);
3553 class Determinant<2> : public DeterminantBase<2>
3556 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3558 ExprP<Mat2> mat = args.a;
3560 return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
3565 class Determinant<3> : public DeterminantBase<3>
3568 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3570 ExprP<Mat3> mat = args.a;
3572 return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) +
3573 mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) +
3574 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
3579 class Determinant<4> : public DeterminantBase<4>
3582 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3584 ExprP<Mat4> mat = args.a;
3585 ExprP<Mat3> minors[4];
3587 for (int ndx = 0; ndx < 4; ++ndx)
3589 ExprP<Vec4> minorColumns[3];
3590 ExprP<Vec3> columns[3];
3592 for (int col = 0; col < 3; ++col)
3593 minorColumns[col] = mat[col < ndx ? col : col + 1];
3595 for (int col = 0; col < 3; ++col)
3596 columns[col] = vec3(minorColumns[0][col+1],
3597 minorColumns[1][col+1],
3598 minorColumns[2][col+1]);
3600 minors[ndx] = bindExpression("minor", ctx,
3601 mat3(columns[0], columns[1], columns[2]));
3604 return (mat[0][0] * determinant(minors[0]) -
3605 mat[1][0] * determinant(minors[1]) +
3606 mat[2][0] * determinant(minors[2]) -
3607 mat[3][0] * determinant(minors[3]));
3611 template<int Size> class Inverse;
3614 ExprP<Matrix<float, Size, Size> > inverse (ExprP<Matrix<float, Size, Size> > mat)
3616 return app<Inverse<Size> >(mat);
3620 class Inverse<2> : public DerivedFunc<Signature<Mat2, Mat2> >
3623 string getName (void) const
3629 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3631 ExprP<Mat2> mat = args.a;
3632 ExprP<float> det = bindExpression("det", ctx, determinant(mat));
3634 return mat2(vec2(mat[1][1] / det, -mat[0][1] / det),
3635 vec2(-mat[1][0] / det, mat[0][0] / det));
3640 class Inverse<3> : public DerivedFunc<Signature<Mat3, Mat3> >
3643 string getName (void) const
3649 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3651 ExprP<Mat3> mat = args.a;
3652 ExprP<Mat2> invA = bindExpression("invA", ctx,
3653 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3654 vec2(mat[1][0], mat[1][1]))));
3656 ExprP<Vec2> matB = bindExpression("matB", ctx, vec2(mat[2][0], mat[2][1]));
3657 ExprP<Vec2> matC = bindExpression("matC", ctx, vec2(mat[0][2], mat[1][2]));
3658 ExprP<float> matD = bindExpression("matD", ctx, mat[2][2]);
3660 ExprP<float> schur = bindExpression("schur", ctx,
3662 (matD - dot(matC * invA, matB)));
3664 ExprP<Vec2> t1 = invA * matB;
3665 ExprP<Vec2> t2 = t1 * schur;
3666 ExprP<Mat2> t3 = outerProduct(t2, matC);
3667 ExprP<Mat2> t4 = t3 * invA;
3668 ExprP<Mat2> t5 = invA + t4;
3669 ExprP<Mat2> blockA = bindExpression("blockA", ctx, t5);
3670 ExprP<Vec2> blockB = bindExpression("blockB", ctx,
3671 (invA * matB) * -schur);
3672 ExprP<Vec2> blockC = bindExpression("blockC", ctx,
3673 (matC * invA) * -schur);
3675 return mat3(vec3(blockA[0][0], blockA[0][1], blockC[0]),
3676 vec3(blockA[1][0], blockA[1][1], blockC[1]),
3677 vec3(blockB[0], blockB[1], schur));
3682 class Inverse<4> : public DerivedFunc<Signature<Mat4, Mat4> >
3685 string getName (void) const { return "inverse"; }
3688 ExprP<Ret> doExpand (ExpandContext& ctx,
3689 const ArgExprs& args) const
3691 ExprP<Mat4> mat = args.a;
3692 ExprP<Mat2> invA = bindExpression("invA", ctx,
3693 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3694 vec2(mat[1][0], mat[1][1]))));
3695 ExprP<Mat2> matB = bindExpression("matB", ctx,
3696 mat2(vec2(mat[2][0], mat[2][1]),
3697 vec2(mat[3][0], mat[3][1])));
3698 ExprP<Mat2> matC = bindExpression("matC", ctx,
3699 mat2(vec2(mat[0][2], mat[0][3]),
3700 vec2(mat[1][2], mat[1][3])));
3701 ExprP<Mat2> matD = bindExpression("matD", ctx,
3702 mat2(vec2(mat[2][2], mat[2][3]),
3703 vec2(mat[3][2], mat[3][3])));
3704 ExprP<Mat2> schur = bindExpression("schur", ctx,
3705 inverse(matD + -(matC * invA * matB)));
3706 ExprP<Mat2> blockA = bindExpression("blockA", ctx,
3707 invA + (invA * matB * schur * matC * invA));
3708 ExprP<Mat2> blockB = bindExpression("blockB", ctx,
3709 (-invA) * matB * schur);
3710 ExprP<Mat2> blockC = bindExpression("blockC", ctx,
3711 (-schur) * matC * invA);
3713 return mat4(vec4(blockA[0][0], blockA[0][1], blockC[0][0], blockC[0][1]),
3714 vec4(blockA[1][0], blockA[1][1], blockC[1][0], blockC[1][1]),
3715 vec4(blockB[0][0], blockB[0][1], schur[0][0], schur[0][1]),
3716 vec4(blockB[1][0], blockB[1][1], schur[1][0], schur[1][1]));
3720 class Fma : public DerivedFunc<Signature<float, float, float, float> >
3723 string getName (void) const
3728 string getRequiredExtension (void) const
3730 return "GL_EXT_gpu_shader5";
3734 ExprP<float> doExpand (ExpandContext&, const ArgExprs& x) const
3736 return x.a * x.b + x.c;
3742 using namespace Functions;
3744 template <typename T>
3745 ExprP<typename T::Element> ContainerExprPBase<T>::operator[] (int i) const
3747 return Functions::getComponent(exprP<T>(*this), i);
3750 ExprP<float> operator+ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3752 return app<Add>(arg0, arg1);
3755 ExprP<float> operator- (const ExprP<float>& arg0, const ExprP<float>& arg1)
3757 return app<Sub>(arg0, arg1);
3760 ExprP<float> operator- (const ExprP<float>& arg0)
3762 return app<Negate>(arg0);
3765 ExprP<float> operator* (const ExprP<float>& arg0, const ExprP<float>& arg1)
3767 return app<Mul>(arg0, arg1);
3770 ExprP<float> operator/ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3772 return app<Div>(arg0, arg1);
3775 template <typename Sig_, int Size>
3776 class GenFunc : public PrimitiveFunc<Signature<
3777 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3778 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3779 typename ContainerOf<typename Sig_::Arg1, Size>::Container,
3780 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
3781 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
3784 typedef typename GenFunc::IArgs IArgs;
3785 typedef typename GenFunc::IRet IRet;
3787 GenFunc (const Func<Sig_>& scalarFunc) : m_func (scalarFunc) {}
3789 string getName (void) const
3791 return m_func.getName();
3794 int getOutParamIndex (void) const
3796 return m_func.getOutParamIndex();
3799 string getRequiredExtension (void) const
3801 return m_func.getRequiredExtension();
3805 void doPrint (ostream& os, const BaseArgExprs& args) const
3807 m_func.print(os, args);
3810 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3814 for (int ndx = 0; ndx < Size; ++ndx)
3817 m_func.apply(ctx, iargs.a[ndx], iargs.b[ndx], iargs.c[ndx], iargs.d[ndx]);
3823 void doGetUsedFuncs (FuncSet& dst) const
3825 m_func.getUsedFuncs(dst);
3828 const Func<Sig_>& m_func;
3831 template <typename F, int Size>
3832 class VectorizedFunc : public GenFunc<typename F::Sig, Size>
3835 VectorizedFunc (void) : GenFunc<typename F::Sig, Size>(instance<F>()) {}
3840 template <typename Sig_, int Size>
3841 class FixedGenFunc : public PrimitiveFunc <Signature<
3842 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3843 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3844 typename Sig_::Arg1,
3845 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
3846 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
3849 typedef typename FixedGenFunc::IArgs IArgs;
3850 typedef typename FixedGenFunc::IRet IRet;
3852 string getName (void) const
3854 return this->doGetScalarFunc().getName();
3858 void doPrint (ostream& os, const BaseArgExprs& args) const
3860 this->doGetScalarFunc().print(os, args);
3863 IRet doApply (const EvalContext& ctx,
3864 const IArgs& iargs) const
3867 const Func<Sig_>& func = this->doGetScalarFunc();
3869 for (int ndx = 0; ndx < Size; ++ndx)
3870 ret[ndx] = func.apply(ctx, iargs.a[ndx], iargs.b, iargs.c[ndx], iargs.d[ndx]);
3875 virtual const Func<Sig_>& doGetScalarFunc (void) const = 0;
3878 template <typename F, int Size>
3879 class FixedVecFunc : public FixedGenFunc<typename F::Sig, Size>
3882 const Func<typename F::Sig>& doGetScalarFunc (void) const { return instance<F>(); }
3885 template<typename Sig>
3888 GenFuncs (const Func<Sig>& func_,
3889 const GenFunc<Sig, 2>& func2_,
3890 const GenFunc<Sig, 3>& func3_,
3891 const GenFunc<Sig, 4>& func4_)
3898 const Func<Sig>& func;
3899 const GenFunc<Sig, 2>& func2;
3900 const GenFunc<Sig, 3>& func3;
3901 const GenFunc<Sig, 4>& func4;
3904 template<typename F>
3905 GenFuncs<typename F::Sig> makeVectorizedFuncs (void)
3907 return GenFuncs<typename F::Sig>(instance<F>(),
3908 instance<VectorizedFunc<F, 2> >(),
3909 instance<VectorizedFunc<F, 3> >(),
3910 instance<VectorizedFunc<F, 4> >());
3914 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
3915 const ExprP<Vector<float, Size> >& arg1)
3917 return app<VectorizedFunc<Mul, Size> >(arg0, arg1);
3921 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
3922 const ExprP<float>& arg1)
3924 return app<FixedVecFunc<Mul, Size> >(arg0, arg1);
3928 ExprP<Vector<float, Size> > operator/(const ExprP<Vector<float, Size> >& arg0,
3929 const ExprP<float>& arg1)
3931 return app<FixedVecFunc<Div, Size> >(arg0, arg1);
3935 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0)
3937 return app<VectorizedFunc<Negate, Size> >(arg0);
3941 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
3942 const ExprP<Vector<float, Size> >& arg1)
3944 return app<VectorizedFunc<Sub, Size> >(arg0, arg1);
3947 template<int LeftRows, int Middle, int RightCols>
3948 ExprP<Matrix<float, LeftRows, RightCols> >
3949 operator* (const ExprP<Matrix<float, LeftRows, Middle> >& left,
3950 const ExprP<Matrix<float, Middle, RightCols> >& right)
3952 return app<MatMul<LeftRows, Middle, RightCols> >(left, right);
3955 template<int Rows, int Cols>
3956 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
3957 const ExprP<Matrix<float, Rows, Cols> >& right)
3959 return app<VecMatMul<Rows, Cols> >(left, right);
3962 template<int Rows, int Cols>
3963 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
3964 const ExprP<Vector<float, Rows> >& right)
3966 return app<MatVecMul<Rows, Cols> >(left, right);
3969 template<int Rows, int Cols>
3970 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
3971 const ExprP<float>& right)
3973 return app<ScalarMatFunc<Mul, Rows, Cols> >(left, right);
3976 template<int Rows, int Cols>
3977 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
3978 const ExprP<Matrix<float, Rows, Cols> >& right)
3980 return app<CompMatFunc<Add, Rows, Cols> >(left, right);
3983 template<int Rows, int Cols>
3984 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat)
3986 return app<MatNeg<Rows, Cols> >(mat);
3989 template <typename T>
3993 virtual void genFixeds (const FloatFormat&, vector<T>&) const {}
3994 virtual T genRandom (const FloatFormat&, Precision, Random&) const { return T(); }
3995 virtual double getWeight (void) const { return 0.0; }
3999 class DefaultSampling<Void> : public Sampling<Void>
4002 void genFixeds (const FloatFormat&, vector<Void>& dst) const { dst.push_back(Void()); }
4006 class DefaultSampling<bool> : public Sampling<bool>
4009 void genFixeds (const FloatFormat&, vector<bool>& dst) const
4011 dst.push_back(true);
4012 dst.push_back(false);
4017 class DefaultSampling<int> : public Sampling<int>
4020 int genRandom (const FloatFormat&, Precision prec, Random& rnd) const
4022 const int exp = rnd.getInt(0, getNumBits(prec)-2);
4023 const int sign = rnd.getBool() ? -1 : 1;
4025 return sign * rnd.getInt(0, (deInt32)1 << exp);
4028 void genFixeds (const FloatFormat&, vector<int>& dst) const
4034 double getWeight (void) const { return 1.0; }
4037 static inline int getNumBits (Precision prec)
4041 case glu::PRECISION_LOWP: return 8;
4042 case glu::PRECISION_MEDIUMP: return 16;
4043 case glu::PRECISION_HIGHP: return 32;
4052 class DefaultSampling<float> : public Sampling<float>
4055 float genRandom (const FloatFormat& format, Precision prec, Random& rnd) const;
4056 void genFixeds (const FloatFormat& format, vector<float>& dst) const;
4057 double getWeight (void) const { return 1.0; }
4060 //! Generate a random float from a reasonable general-purpose distribution.
4061 float DefaultSampling<float>::genRandom (const FloatFormat& format,
4065 const int minExp = format.getMinExp();
4066 const int maxExp = format.getMaxExp();
4067 const bool haveSubnormal = format.hasSubnormal() != tcu::NO;
4069 // Choose exponent so that the cumulative distribution is cubic.
4070 // This makes the probability distribution quadratic, with the peak centered on zero.
4071 const double minRoot = deCbrt(minExp - 0.5 - (haveSubnormal ? 1.0 : 0.0));
4072 const double maxRoot = deCbrt(maxExp + 0.5);
4073 const int fractionBits = format.getFractionBits();
4074 const int exp = int(deRoundEven(dePow(rnd.getDouble(minRoot, maxRoot),
4076 float base = 0.0f; // integral power of two
4077 float quantum = 0.0f; // smallest representable difference in the binade
4078 float significand = 0.0f; // Significand.
4080 DE_ASSERT(fractionBits < std::numeric_limits<float>::digits);
4082 // Generate some occasional special numbers
4083 switch (rnd.getInt(0, 64))
4086 case 1: return TCU_INFINITY;
4087 case 2: return -TCU_INFINITY;
4088 case 3: return TCU_NAN;
4095 base = deFloatLdExp(1.0f, exp);
4096 quantum = deFloatLdExp(1.0f, exp - fractionBits);
4102 quantum = deFloatLdExp(1.0f, minExp - fractionBits);
4105 switch (rnd.getInt(0, 16))
4107 case 0: // The highest number in this binade, significand is all bits one.
4108 significand = base - quantum;
4110 case 1: // Significand is one.
4111 significand = quantum;
4113 case 2: // Significand is zero.
4116 default: // Random (evenly distributed) significand.
4118 deUint64 intFraction = rnd.getUint64() & ((1 << fractionBits) - 1);
4119 significand = float(intFraction) * quantum;
4123 // Produce positive numbers more often than negative.
4124 return (rnd.getInt(0,3) == 0 ? -1.0f : 1.0f) * (base + significand);
4127 //! Generate a standard set of floats that should always be tested.
4128 void DefaultSampling<float>::genFixeds (const FloatFormat& format, vector<float>& dst) const
4130 const int minExp = format.getMinExp();
4131 const int maxExp = format.getMaxExp();
4132 const int fractionBits = format.getFractionBits();
4133 const float minQuantum = deFloatLdExp(1.0f, minExp - fractionBits);
4134 const float minNormalized = deFloatLdExp(1.0f, minExp);
4135 const float maxQuantum = deFloatLdExp(1.0f, maxExp - fractionBits);
4138 dst.push_back(TCU_NAN);
4140 dst.push_back(0.0f);
4142 for (int sign = -1; sign <= 1; sign += 2)
4144 // Smallest subnormal
4145 dst.push_back((float)sign * minQuantum);
4147 // Largest subnormal
4148 dst.push_back((float)sign * (minNormalized - minQuantum));
4150 // Smallest normalized
4151 dst.push_back((float)sign * minNormalized);
4153 // Next smallest normalized
4154 dst.push_back((float)sign * (minNormalized + minQuantum));
4156 dst.push_back((float)sign * 0.5f);
4157 dst.push_back((float)sign * 1.0f);
4158 dst.push_back((float)sign * 2.0f);
4161 dst.push_back((float)sign * (deFloatLdExp(1.0f, maxExp) +
4162 (deFloatLdExp(1.0f, maxExp) - maxQuantum)));
4164 dst.push_back((float)sign * TCU_INFINITY);
4168 template <typename T, int Size>
4169 class DefaultSampling<Vector<T, Size> > : public Sampling<Vector<T, Size> >
4172 typedef Vector<T, Size> Value;
4174 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4178 for (int ndx = 0; ndx < Size; ++ndx)
4179 ret[ndx] = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4184 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4188 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4190 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4191 dst.push_back(Value(scalars[scalarNdx]));
4194 double getWeight (void) const
4196 return dePow(instance<DefaultSampling<T> >().getWeight(), Size);
4200 template <typename T, int Rows, int Columns>
4201 class DefaultSampling<Matrix<T, Rows, Columns> > : public Sampling<Matrix<T, Rows, Columns> >
4204 typedef Matrix<T, Rows, Columns> Value;
4206 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4210 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
4211 for (int colNdx = 0; colNdx < Columns; ++colNdx)
4212 ret(rowNdx, colNdx) = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4217 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4221 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4223 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4224 dst.push_back(Value(scalars[scalarNdx]));
4226 if (Columns == Rows)
4231 for (int ndx = 0; ndx < Columns; ++ndx)
4233 mat[Columns-1-ndx][ndx] = x;
4240 double getWeight (void) const
4242 return dePow(instance<DefaultSampling<T> >().getWeight(), Rows * Columns);
4248 CaseContext (const string& name_,
4249 TestContext& testContext_,
4250 const FloatFormat& floatFormat_,
4251 const FloatFormat& highpFormat_,
4252 Precision precision_,
4253 ShaderType shaderType_,
4256 , testContext (testContext_)
4257 , floatFormat (floatFormat_)
4258 , highpFormat (highpFormat_)
4259 , precision (precision_)
4260 , shaderType (shaderType_)
4261 , numRandoms (numRandoms_) {}
4264 TestContext& testContext;
4265 FloatFormat floatFormat;
4266 FloatFormat highpFormat;
4267 Precision precision;
4268 ShaderType shaderType;
4272 template<typename In0_ = Void, typename In1_ = Void, typename In2_ = Void, typename In3_ = Void>
4281 template <typename In>
4282 int numInputs (void)
4284 return (!isTypeValid<typename In::In0>() ? 0 :
4285 !isTypeValid<typename In::In1>() ? 1 :
4286 !isTypeValid<typename In::In2>() ? 2 :
4287 !isTypeValid<typename In::In3>() ? 3 :
4291 template<typename Out0_, typename Out1_ = Void>
4298 template <typename Out>
4299 int numOutputs (void)
4301 return (!isTypeValid<typename Out::Out0>() ? 0 :
4302 !isTypeValid<typename Out::Out1>() ? 1 :
4306 template<typename In>
4309 vector<typename In::In0> in0;
4310 vector<typename In::In1> in1;
4311 vector<typename In::In2> in2;
4312 vector<typename In::In3> in3;
4315 template<typename Out>
4318 Outputs (size_t size) : out0(size), out1(size) {}
4320 vector<typename Out::Out0> out0;
4321 vector<typename Out::Out1> out1;
4324 template<typename In, typename Out>
4327 VariableP<typename In::In0> in0;
4328 VariableP<typename In::In1> in1;
4329 VariableP<typename In::In2> in2;
4330 VariableP<typename In::In3> in3;
4331 VariableP<typename Out::Out0> out0;
4332 VariableP<typename Out::Out1> out1;
4335 template<typename In>
4338 Samplings (const Sampling<typename In::In0>& in0_,
4339 const Sampling<typename In::In1>& in1_,
4340 const Sampling<typename In::In2>& in2_,
4341 const Sampling<typename In::In3>& in3_)
4342 : in0 (in0_), in1 (in1_), in2 (in2_), in3 (in3_) {}
4344 const Sampling<typename In::In0>& in0;
4345 const Sampling<typename In::In1>& in1;
4346 const Sampling<typename In::In2>& in2;
4347 const Sampling<typename In::In3>& in3;
4350 template<typename In>
4351 struct DefaultSamplings : Samplings<In>
4353 DefaultSamplings (void)
4354 : Samplings<In>(instance<DefaultSampling<typename In::In0> >(),
4355 instance<DefaultSampling<typename In::In1> >(),
4356 instance<DefaultSampling<typename In::In2> >(),
4357 instance<DefaultSampling<typename In::In3> >()) {}
4360 template <typename In, typename Out>
4361 class BuiltinPrecisionCaseTestInstance : public TestInstance
4364 BuiltinPrecisionCaseTestInstance (Context& context,
4365 const CaseContext caseCtx,
4366 const ShaderSpec& shaderSpec,
4367 const Variables<In, Out> variables,
4368 const Samplings<In>& samplings,
4369 const StatementP stmt)
4370 : TestInstance (context)
4371 , m_caseCtx (caseCtx)
4372 , m_variables (variables)
4373 , m_samplings (samplings)
4375 , m_executor (createExecutor(context, caseCtx.shaderType, shaderSpec))
4378 virtual tcu::TestStatus iterate (void);
4381 CaseContext m_caseCtx;
4382 Variables<In, Out> m_variables;
4383 const Samplings<In>& m_samplings;
4385 de::UniquePtr<ShaderExecutor> m_executor;
4388 template<class In, class Out>
4389 tcu::TestStatus BuiltinPrecisionCaseTestInstance<In, Out>::iterate (void)
4391 typedef typename In::In0 In0;
4392 typedef typename In::In1 In1;
4393 typedef typename In::In2 In2;
4394 typedef typename In::In3 In3;
4395 typedef typename Out::Out0 Out0;
4396 typedef typename Out::Out1 Out1;
4398 Inputs<In> inputs = generateInputs(m_samplings, m_caseCtx.floatFormat, m_caseCtx.precision, m_caseCtx.numRandoms, 0xdeadbeefu + m_caseCtx.testContext.getCommandLine().getBaseSeed());
4399 const FloatFormat& fmt = m_caseCtx.floatFormat;
4400 const int inCount = numInputs<In>();
4401 const int outCount = numOutputs<Out>();
4402 const size_t numValues = (inCount > 0) ? inputs.in0.size() : 1;
4403 Outputs<Out> outputs (numValues);
4404 const FloatFormat highpFmt = m_caseCtx.highpFormat;
4405 const int maxMsgs = 100;
4407 Environment env; // Hoisted out of the inner loop for optimization.
4408 ResultCollector status;
4409 TestLog& testLog = m_context.getTestContext().getLog();
4411 const void* inputArr[] =
4413 &inputs.in0.front(), &inputs.in1.front(), &inputs.in2.front(), &inputs.in3.front(),
4417 &outputs.out0.front(), &outputs.out1.front(),
4420 // Print out the statement and its definitions
4421 testLog << TestLog::Message << "Statement: " << m_stmt << TestLog::EndMessage;
4426 m_stmt->getUsedFuncs(funcs);
4427 for (FuncSet::const_iterator it = funcs.begin(); it != funcs.end(); ++it)
4429 (*it)->printDefinition(oss);
4432 testLog << TestLog::Message << "Reference definitions:\n" << oss.str()
4433 << TestLog::EndMessage;
4438 case 4: DE_ASSERT(inputs.in3.size() == numValues);
4439 case 3: DE_ASSERT(inputs.in2.size() == numValues);
4440 case 2: DE_ASSERT(inputs.in1.size() == numValues);
4441 case 1: DE_ASSERT(inputs.in0.size() == numValues);
4445 m_executor->execute(int(numValues), inputArr, outputArr);
4447 // Initialize environment with dummy values so we don't need to bind in inner loop.
4449 const typename Traits<In0>::IVal in0;
4450 const typename Traits<In1>::IVal in1;
4451 const typename Traits<In2>::IVal in2;
4452 const typename Traits<In3>::IVal in3;
4453 const typename Traits<Out0>::IVal reference0;
4454 const typename Traits<Out1>::IVal reference1;
4456 env.bind(*m_variables.in0, in0);
4457 env.bind(*m_variables.in1, in1);
4458 env.bind(*m_variables.in2, in2);
4459 env.bind(*m_variables.in3, in3);
4460 env.bind(*m_variables.out0, reference0);
4461 env.bind(*m_variables.out1, reference1);
4464 // For each input tuple, compute output reference interval and compare
4465 // shader output to the reference.
4466 for (size_t valueNdx = 0; valueNdx < numValues; valueNdx++)
4469 typename Traits<Out0>::IVal reference0;
4470 typename Traits<Out1>::IVal reference1;
4472 env.lookup(*m_variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx]));
4473 env.lookup(*m_variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx]));
4474 env.lookup(*m_variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx]));
4475 env.lookup(*m_variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx]));
4478 EvalContext ctx (fmt, m_caseCtx.precision, env);
4479 m_stmt->execute(ctx);
4485 reference1 = convert<Out1>(highpFmt, env.lookup(*m_variables.out1));
4486 if (!status.check(contains(reference1, outputs.out1[valueNdx]),
4487 "Shader output 1 is outside acceptable range"))
4490 reference0 = convert<Out0>(highpFmt, env.lookup(*m_variables.out0));
4491 if (!status.check(contains(reference0, outputs.out0[valueNdx]),
4492 "Shader output 0 is outside acceptable range"))
4500 if ((!result && numErrors <= maxMsgs) || GLS_LOG_ALL_RESULTS)
4502 MessageBuilder builder = testLog.message();
4504 builder << (result ? "Passed" : "Failed") << " sample:\n";
4508 builder << "\t" << m_variables.in0->getName() << " = "
4509 << valueToString(highpFmt, inputs.in0[valueNdx]) << "\n";
4514 builder << "\t" << m_variables.in1->getName() << " = "
4515 << valueToString(highpFmt, inputs.in1[valueNdx]) << "\n";
4520 builder << "\t" << m_variables.in2->getName() << " = "
4521 << valueToString(highpFmt, inputs.in2[valueNdx]) << "\n";
4526 builder << "\t" << m_variables.in3->getName() << " = "
4527 << valueToString(highpFmt, inputs.in3[valueNdx]) << "\n";
4532 builder << "\t" << m_variables.out0->getName() << " = "
4533 << valueToString(highpFmt, outputs.out0[valueNdx]) << "\n"
4534 << "\tExpected range: "
4535 << intervalToString<typename Out::Out0>(highpFmt, reference0) << "\n";
4540 builder << "\t" << m_variables.out1->getName() << " = "
4541 << valueToString(highpFmt, outputs.out1[valueNdx]) << "\n"
4542 << "\tExpected range: "
4543 << intervalToString<typename Out::Out1>(highpFmt, reference1) << "\n";
4546 builder << TestLog::EndMessage;
4550 if (numErrors > maxMsgs)
4552 testLog << TestLog::Message << "(Skipped " << (numErrors - maxMsgs) << " messages.)"
4553 << TestLog::EndMessage;
4558 testLog << TestLog::Message << "All " << numValues << " inputs passed."
4559 << TestLog::EndMessage;
4563 testLog << TestLog::Message << numErrors << "/" << numValues << " inputs failed."
4564 << TestLog::EndMessage;
4568 return tcu::TestStatus::fail(de::toString(numErrors) + string(" test failed. Check log for the details"));
4570 return tcu::TestStatus::pass("Pass");
4574 class PrecisionCase : public TestCase
4577 PrecisionCase (const CaseContext& context, const string& name, const string& extension = "")
4578 : TestCase (context.testContext, name.c_str(), name.c_str())
4580 , m_extension (extension)
4584 virtual void initPrograms (vk::SourceCollections& programCollection) const
4586 generateSources(m_ctx.shaderType, m_spec, programCollection);
4589 const FloatFormat& getFormat (void) const { return m_ctx.floatFormat; }
4591 template <typename In, typename Out>
4592 void testStatement (const Variables<In, Out>& variables, const Statement& stmt);
4594 template<typename T>
4595 Symbol makeSymbol (const Variable<T>& variable)
4597 return Symbol(variable.getName(), getVarTypeOf<T>(m_ctx.precision));
4601 const string m_extension;
4605 template <typename In, typename Out>
4606 void PrecisionCase::testStatement (const Variables<In, Out>& variables, const Statement& stmt)
4608 const int inCount = numInputs<In>();
4609 const int outCount = numOutputs<Out>();
4610 Environment env; // Hoisted out of the inner loop for optimization.
4612 // Initialize ShaderSpec from precision, variables and statement.
4615 os << "precision " << glu::getPrecisionName(m_ctx.precision) << " float;\n";
4616 m_spec.globalDeclarations = os.str();
4619 if (!m_extension.empty())
4620 m_spec.globalDeclarations = "#extension " + m_extension + " : require\n";
4622 m_spec.inputs.resize(inCount);
4626 case 4: m_spec.inputs[3] = makeSymbol(*variables.in3);
4627 case 3: m_spec.inputs[2] = makeSymbol(*variables.in2);
4628 case 2: m_spec.inputs[1] = makeSymbol(*variables.in1);
4629 case 1: m_spec.inputs[0] = makeSymbol(*variables.in0);
4633 m_spec.outputs.resize(outCount);
4637 case 2: m_spec.outputs[1] = makeSymbol(*variables.out1);
4638 case 1: m_spec.outputs[0] = makeSymbol(*variables.out0);
4642 m_spec.source = de::toString(stmt);
4645 template <typename T>
4648 bool operator() (const T& val1, const T& val2) const
4654 template <typename T>
4655 bool inputLess (const T& val1, const T& val2)
4657 return InputLess<T>()(val1, val2);
4661 struct InputLess<float>
4663 bool operator() (const float& val1, const float& val2) const
4673 template <typename T, int Size>
4674 struct InputLess<Vector<T, Size> >
4676 bool operator() (const Vector<T, Size>& vec1, const Vector<T, Size>& vec2) const
4678 for (int ndx = 0; ndx < Size; ++ndx)
4680 if (inputLess(vec1[ndx], vec2[ndx]))
4682 if (inputLess(vec2[ndx], vec1[ndx]))
4690 template <typename T, int Rows, int Cols>
4691 struct InputLess<Matrix<T, Rows, Cols> >
4693 bool operator() (const Matrix<T, Rows, Cols>& mat1,
4694 const Matrix<T, Rows, Cols>& mat2) const
4696 for (int col = 0; col < Cols; ++col)
4698 if (inputLess(mat1[col], mat2[col]))
4700 if (inputLess(mat2[col], mat1[col]))
4708 template <typename In>
4710 public Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4712 InTuple (const typename In::In0& in0,
4713 const typename In::In1& in1,
4714 const typename In::In2& in2,
4715 const typename In::In3& in3)
4716 : Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4717 (in0, in1, in2, in3) {}
4720 template <typename In>
4721 struct InputLess<InTuple<In> >
4723 bool operator() (const InTuple<In>& in1, const InTuple<In>& in2) const
4725 if (inputLess(in1.a, in2.a))
4727 if (inputLess(in2.a, in1.a))
4729 if (inputLess(in1.b, in2.b))
4731 if (inputLess(in2.b, in1.b))
4733 if (inputLess(in1.c, in2.c))
4735 if (inputLess(in2.c, in1.c))
4737 if (inputLess(in1.d, in2.d))
4743 template<typename In>
4744 Inputs<In> generateInputs (const Samplings<In>& samplings,
4745 const FloatFormat& floatFormat,
4746 Precision intPrecision,
4752 Inputs<In> fixedInputs;
4753 set<InTuple<In>, InputLess<InTuple<In> > > seenInputs;
4755 samplings.in0.genFixeds(floatFormat, fixedInputs.in0);
4756 samplings.in1.genFixeds(floatFormat, fixedInputs.in1);
4757 samplings.in2.genFixeds(floatFormat, fixedInputs.in2);
4758 samplings.in3.genFixeds(floatFormat, fixedInputs.in3);
4760 for (size_t ndx0 = 0; ndx0 < fixedInputs.in0.size(); ++ndx0)
4762 for (size_t ndx1 = 0; ndx1 < fixedInputs.in1.size(); ++ndx1)
4764 for (size_t ndx2 = 0; ndx2 < fixedInputs.in2.size(); ++ndx2)
4766 for (size_t ndx3 = 0; ndx3 < fixedInputs.in3.size(); ++ndx3)
4768 const InTuple<In> tuple (fixedInputs.in0[ndx0],
4769 fixedInputs.in1[ndx1],
4770 fixedInputs.in2[ndx2],
4771 fixedInputs.in3[ndx3]);
4773 seenInputs.insert(tuple);
4774 ret.in0.push_back(tuple.a);
4775 ret.in1.push_back(tuple.b);
4776 ret.in2.push_back(tuple.c);
4777 ret.in3.push_back(tuple.d);
4783 for (size_t ndx = 0; ndx < numSamples; ++ndx)
4785 const typename In::In0 in0 = samplings.in0.genRandom(floatFormat, intPrecision, rnd);
4786 const typename In::In1 in1 = samplings.in1.genRandom(floatFormat, intPrecision, rnd);
4787 const typename In::In2 in2 = samplings.in2.genRandom(floatFormat, intPrecision, rnd);
4788 const typename In::In3 in3 = samplings.in3.genRandom(floatFormat, intPrecision, rnd);
4789 const InTuple<In> tuple (in0, in1, in2, in3);
4791 if (de::contains(seenInputs, tuple))
4794 seenInputs.insert(tuple);
4795 ret.in0.push_back(in0);
4796 ret.in1.push_back(in1);
4797 ret.in2.push_back(in2);
4798 ret.in3.push_back(in3);
4804 class FuncCaseBase : public PrecisionCase
4807 FuncCaseBase (const CaseContext& context, const string& name, const FuncBase& func)
4808 : PrecisionCase (context, name, func.getRequiredExtension())
4815 template <typename Sig>
4816 class FuncCase : public FuncCaseBase
4819 typedef Func<Sig> CaseFunc;
4820 typedef typename Sig::Ret Ret;
4821 typedef typename Sig::Arg0 Arg0;
4822 typedef typename Sig::Arg1 Arg1;
4823 typedef typename Sig::Arg2 Arg2;
4824 typedef typename Sig::Arg3 Arg3;
4825 typedef InTypes<Arg0, Arg1, Arg2, Arg3> In;
4826 typedef OutTypes<Ret> Out;
4828 FuncCase (const CaseContext& context, const string& name, const CaseFunc& func)
4829 : FuncCaseBase (context, name, func)
4835 virtual TestInstance* createInstance (Context& context) const
4837 return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, m_spec, m_variables, getSamplings(), m_stmt);
4841 void buildTest (void);
4842 virtual const Samplings<In>& getSamplings (void) const
4844 return instance<DefaultSamplings<In> >();
4848 const CaseFunc& m_func;
4849 Variables<In, Out> m_variables;
4852 template <typename Sig>
4853 void FuncCase<Sig>::buildTest (void)
4855 m_variables.out0 = variable<Ret>("out0");
4856 m_variables.out1 = variable<Void>("out1");
4857 m_variables.in0 = variable<Arg0>("in0");
4858 m_variables.in1 = variable<Arg1>("in1");
4859 m_variables.in2 = variable<Arg2>("in2");
4860 m_variables.in3 = variable<Arg3>("in3");
4863 ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.in1, m_variables.in2, m_variables.in3);
4864 m_stmt = variableAssignment(m_variables.out0, expr);
4866 this->testStatement(m_variables, *m_stmt);
4870 template <typename Sig>
4871 class InOutFuncCase : public FuncCaseBase
4874 typedef Func<Sig> CaseFunc;
4875 typedef typename Sig::Ret Ret;
4876 typedef typename Sig::Arg0 Arg0;
4877 typedef typename Sig::Arg1 Arg1;
4878 typedef typename Sig::Arg2 Arg2;
4879 typedef typename Sig::Arg3 Arg3;
4880 typedef InTypes<Arg0, Arg2, Arg3> In;
4881 typedef OutTypes<Ret, Arg1> Out;
4883 InOutFuncCase (const CaseContext& context, const string& name, const CaseFunc& func)
4884 : FuncCaseBase (context, name, func)
4889 virtual TestInstance* createInstance (Context& context) const
4891 return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, m_spec, m_variables, getSamplings(), m_stmt);
4895 void buildTest (void);
4896 virtual const Samplings<In>& getSamplings (void) const
4898 return instance<DefaultSamplings<In> >();
4902 const CaseFunc& m_func;
4903 Variables<In, Out> m_variables;
4906 template <typename Sig>
4907 void InOutFuncCase<Sig>::buildTest (void)
4910 m_variables.out0 = variable<Ret>("out0");
4911 m_variables.out1 = variable<Arg1>("out1");
4912 m_variables.in0 = variable<Arg0>("in0");
4913 m_variables.in1 = variable<Arg2>("in1");
4914 m_variables.in2 = variable<Arg3>("in2");
4915 m_variables.in3 = variable<Void>("in3");
4918 ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.out1, m_variables.in1, m_variables.in2);
4919 m_stmt = variableAssignment(m_variables.out0, expr);
4921 this->testStatement(m_variables, *m_stmt);
4925 template <typename Sig>
4926 PrecisionCase* createFuncCase (const CaseContext& context, const string& name, const Func<Sig>& func)
4928 switch (func.getOutParamIndex())
4931 return new FuncCase<Sig>(context, name, func);
4933 return new InOutFuncCase<Sig>(context, name, func);
4935 DE_FATAL("Impossible");
4943 virtual ~CaseFactory (void) {}
4944 virtual MovePtr<TestNode> createCase (const CaseContext& ctx) const = 0;
4945 virtual string getName (void) const = 0;
4946 virtual string getDesc (void) const = 0;
4949 class FuncCaseFactory : public CaseFactory
4952 virtual const FuncBase& getFunc (void) const = 0;
4953 string getName (void) const { return de::toLower(getFunc().getName()); }
4954 string getDesc (void) const { return "Function '" + getFunc().getName() + "'"; }
4957 template <typename Sig>
4958 class GenFuncCaseFactory : public CaseFactory
4961 GenFuncCaseFactory (const GenFuncs<Sig>& funcs, const string& name)
4963 , m_name (de::toLower(name))
4967 MovePtr<TestNode> createCase (const CaseContext& ctx) const
4969 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
4971 group->addChild(createFuncCase(ctx, "scalar", m_funcs.func));
4972 group->addChild(createFuncCase(ctx, "vec2", m_funcs.func2));
4973 group->addChild(createFuncCase(ctx, "vec3", m_funcs.func3));
4974 group->addChild(createFuncCase(ctx, "vec4", m_funcs.func4));
4975 return MovePtr<TestNode>(group);
4978 string getName (void) const { return m_name; }
4979 string getDesc (void) const { return "Function '" + m_funcs.func.getName() + "'"; }
4982 const GenFuncs<Sig> m_funcs;
4986 template <template <int> class GenF>
4987 class TemplateFuncCaseFactory : public FuncCaseFactory
4990 MovePtr<TestNode> createCase (const CaseContext& ctx) const
4992 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
4994 group->addChild(createFuncCase(ctx, "scalar", instance<GenF<1> >()));
4995 group->addChild(createFuncCase(ctx, "vec2", instance<GenF<2> >()));
4996 group->addChild(createFuncCase(ctx, "vec3", instance<GenF<3> >()));
4997 group->addChild(createFuncCase(ctx, "vec4", instance<GenF<4> >()));
4999 return MovePtr<TestNode>(group);
5002 const FuncBase& getFunc (void) const { return instance<GenF<1> >(); }
5005 template <template <int> class GenF>
5006 class SquareMatrixFuncCaseFactory : public FuncCaseFactory
5009 MovePtr<TestNode> createCase (const CaseContext& ctx) const
5011 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5013 group->addChild(createFuncCase(ctx, "mat2", instance<GenF<2> >()));
5015 // disabled until we get reasonable results
5016 group->addChild(createFuncCase(ctx, "mat3", instance<GenF<3> >()));
5017 group->addChild(createFuncCase(ctx, "mat4", instance<GenF<4> >()));
5020 return MovePtr<TestNode>(group);
5023 const FuncBase& getFunc (void) const { return instance<GenF<2> >(); }
5026 template <template <int, int> class GenF>
5027 class MatrixFuncCaseFactory : public FuncCaseFactory
5030 MovePtr<TestNode> createCase (const CaseContext& ctx) const
5032 TestCaseGroup* const group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5034 this->addCase<2, 2>(ctx, group);
5035 this->addCase<3, 2>(ctx, group);
5036 this->addCase<4, 2>(ctx, group);
5037 this->addCase<2, 3>(ctx, group);
5038 this->addCase<3, 3>(ctx, group);
5039 this->addCase<4, 3>(ctx, group);
5040 this->addCase<2, 4>(ctx, group);
5041 this->addCase<3, 4>(ctx, group);
5042 this->addCase<4, 4>(ctx, group);
5044 return MovePtr<TestNode>(group);
5047 const FuncBase& getFunc (void) const { return instance<GenF<2,2> >(); }
5050 template <int Rows, int Cols>
5051 void addCase (const CaseContext& ctx, TestCaseGroup* group) const
5053 const char* const name = dataTypeNameOf<Matrix<float, Rows, Cols> >();
5054 group->addChild(createFuncCase(ctx, name, instance<GenF<Rows, Cols> >()));
5058 template <typename Sig>
5059 class SimpleFuncCaseFactory : public CaseFactory
5062 SimpleFuncCaseFactory (const Func<Sig>& func) : m_func(func) {}
5064 MovePtr<TestNode> createCase (const CaseContext& ctx) const { return MovePtr<TestNode>(createFuncCase(ctx, ctx.name.c_str(), m_func)); }
5065 string getName (void) const { return de::toLower(m_func.getName()); }
5066 string getDesc (void) const { return "Function '" + getName() + "'"; }
5069 const Func<Sig>& m_func;
5072 template <typename F>
5073 SharedPtr<SimpleFuncCaseFactory<typename F::Sig> > createSimpleFuncCaseFactory (void)
5075 return SharedPtr<SimpleFuncCaseFactory<typename F::Sig> >(new SimpleFuncCaseFactory<typename F::Sig>(instance<F>()));
5081 virtual ~CaseFactories (void) {}
5082 virtual const std::vector<const CaseFactory*> getFactories (void) const = 0;
5085 class BuiltinFuncs : public CaseFactories
5088 const vector<const CaseFactory*> getFactories (void) const
5090 vector<const CaseFactory*> ret;
5092 for (size_t ndx = 0; ndx < m_factories.size(); ++ndx)
5093 ret.push_back(m_factories[ndx].get());
5098 void addFactory (SharedPtr<const CaseFactory> fact) { m_factories.push_back(fact); }
5101 vector<SharedPtr<const CaseFactory> > m_factories;
5104 template <typename F>
5105 void addScalarFactory(BuiltinFuncs& funcs, string name = "")
5108 name = instance<F>().getName();
5110 funcs.addFactory(SharedPtr<const CaseFactory>(new GenFuncCaseFactory<typename F::Sig>(makeVectorizedFuncs<F>(), name)));
5113 MovePtr<const CaseFactories> createComputeOnlyBuiltinCases (void)
5115 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5117 // Tests for ES3 builtins
5119 addScalarFactory<Add>(*funcs);
5120 addScalarFactory<Sub>(*funcs);
5121 addScalarFactory<Mul>(*funcs);
5122 addScalarFactory<Div>(*funcs);
5124 addScalarFactory<Radians>(*funcs);
5125 addScalarFactory<Degrees>(*funcs);
5126 addScalarFactory<Sin>(*funcs);
5127 addScalarFactory<Cos>(*funcs);
5128 addScalarFactory<Tan>(*funcs);
5129 addScalarFactory<ASin>(*funcs);
5130 addScalarFactory<ACos>(*funcs);
5131 addScalarFactory<ATan2>(*funcs, "atan2");
5132 addScalarFactory<ATan>(*funcs);
5133 addScalarFactory<Sinh>(*funcs);
5134 addScalarFactory<Cosh>(*funcs);
5135 addScalarFactory<Tanh>(*funcs);
5136 addScalarFactory<ASinh>(*funcs);
5137 addScalarFactory<ACosh>(*funcs);
5138 addScalarFactory<ATanh>(*funcs);
5140 addScalarFactory<Pow>(*funcs);
5141 addScalarFactory<Exp>(*funcs);
5142 addScalarFactory<Log>(*funcs);
5143 addScalarFactory<Exp2>(*funcs);
5144 addScalarFactory<Log2>(*funcs);
5145 addScalarFactory<Sqrt>(*funcs);
5146 addScalarFactory<InverseSqrt>(*funcs);
5148 addScalarFactory<Abs>(*funcs);
5149 addScalarFactory<Sign>(*funcs);
5150 addScalarFactory<Floor>(*funcs);
5151 addScalarFactory<Trunc>(*funcs);
5152 addScalarFactory<Round>(*funcs);
5153 addScalarFactory<RoundEven>(*funcs);
5154 addScalarFactory<Ceil>(*funcs);
5155 addScalarFactory<Fract>(*funcs);
5156 addScalarFactory<Mod>(*funcs);
5157 funcs->addFactory(createSimpleFuncCaseFactory<Modf>());
5158 addScalarFactory<Min>(*funcs);
5159 addScalarFactory<Max>(*funcs);
5160 addScalarFactory<Clamp>(*funcs);
5161 addScalarFactory<Mix>(*funcs);
5162 addScalarFactory<Step>(*funcs);
5163 addScalarFactory<SmoothStep>(*funcs);
5165 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length>()));
5166 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance>()));
5167 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot>()));
5168 funcs->addFactory(createSimpleFuncCaseFactory<Cross>());
5169 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize>()));
5170 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward>()));
5171 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect>()));
5172 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract>()));
5175 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<MatrixCompMult>()));
5176 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct>()));
5177 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose>()));
5178 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant>()));
5179 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse>()));
5181 return MovePtr<const CaseFactories>(funcs.release());
5184 MovePtr<const CaseFactories> createCompleteBuiltinCases (void)
5186 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5188 // Tests for ES31 builtins
5189 addScalarFactory<FrExp>(*funcs);
5190 addScalarFactory<LdExp>(*funcs);
5191 addScalarFactory<Fma>(*funcs);
5193 return MovePtr<const CaseFactories>(funcs.release());
5196 struct PrecisionTestContext
5198 PrecisionTestContext (TestContext& testCtx_,
5199 const FloatFormat& highp_,
5200 const FloatFormat& mediump_,
5201 const FloatFormat& lowp_,
5202 const vector<ShaderType>& shaderTypes_,
5204 : testCtx (testCtx_)
5205 , shaderTypes (shaderTypes_)
5206 , numRandoms (numRandoms_)
5208 formats[glu::PRECISION_HIGHP] = &highp_;
5209 formats[glu::PRECISION_MEDIUMP] = &mediump_;
5210 formats[glu::PRECISION_LOWP] = &lowp_;
5213 TestContext& testCtx;
5214 const FloatFormat* formats[glu::PRECISION_LAST];
5215 vector<ShaderType> shaderTypes;
5219 TestCaseGroup* createFuncGroup (const PrecisionTestContext& ctx, const CaseFactory& factory)
5221 TestCaseGroup* const group = new TestCaseGroup(ctx.testCtx, factory.getName().c_str(), factory.getDesc().c_str());
5223 for (int precNdx = glu::PRECISION_MEDIUMP; precNdx < glu::PRECISION_LAST; ++precNdx)
5225 const Precision precision = Precision(precNdx);
5226 const string precName (glu::getPrecisionName(precision));
5227 const FloatFormat& fmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats, precNdx);
5228 const FloatFormat& highpFmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats,
5229 glu::PRECISION_HIGHP);
5231 for (size_t shaderNdx = 0; shaderNdx < ctx.shaderTypes.size(); ++shaderNdx)
5233 const ShaderType shaderType = ctx.shaderTypes[shaderNdx];
5234 const string shaderName (glu::getShaderTypeName(shaderType));
5235 const string name = precName + "_" + shaderName;
5236 const CaseContext caseCtx (name, ctx.testCtx, fmt, highpFmt,
5237 precision, shaderType, ctx.numRandoms);
5239 group->addChild(factory.createCase(caseCtx).release());
5246 void addBuiltinPrecisionTests (TestContext& testCtx,
5247 const CaseFactories& cases,
5248 const vector<ShaderType>& shaderTypes,
5249 TestCaseGroup& dstGroup)
5251 const int userRandoms = testCtx.getCommandLine().getTestIterationCount();
5252 const int defRandoms = 16384;
5253 const int numRandoms = userRandoms > 0 ? userRandoms : defRandoms;
5254 const FloatFormat highp (-126, 127, 23, true,
5255 tcu::MAYBE, // subnormals
5256 tcu::YES, // infinities
5258 // \todo [2014-04-01 lauri] Check these once Khronos bug 11840 is resolved.
5259 const FloatFormat mediump (-13, 13, 9, false);
5260 // A fixed-point format is just a floating point format with a fixed
5261 // exponent and support for subnormals.
5262 const FloatFormat lowp (0, 0, 7, false, tcu::YES);
5263 const PrecisionTestContext ctx (testCtx, highp, mediump, lowp,
5264 shaderTypes, numRandoms);
5266 for (size_t ndx = 0; ndx < cases.getFactories().size(); ++ndx)
5267 dstGroup.addChild(createFuncGroup(ctx, *cases.getFactories()[ndx]));
5270 BuiltinPrecisionTests::BuiltinPrecisionTests (tcu::TestContext& testCtx)
5271 : tcu::TestCaseGroup(testCtx, "precision", "Builtin precision tests")
5275 BuiltinPrecisionTests::~BuiltinPrecisionTests (void)
5279 void BuiltinPrecisionTests::init (void)
5281 std::vector<glu::ShaderType> shaderTypes;
5282 de::MovePtr<const CaseFactories> computeOnlyCases = createComputeOnlyBuiltinCases();
5283 de::MovePtr<const CaseFactories> completeCases = createCompleteBuiltinCases();
5285 shaderTypes.push_back(glu::SHADERTYPE_COMPUTE);
5287 addBuiltinPrecisionTests(m_testCtx,
5292 shaderTypes.clear();
5293 shaderTypes.push_back(glu::SHADERTYPE_VERTEX);
5294 shaderTypes.push_back(glu::SHADERTYPE_FRAGMENT);
5295 shaderTypes.push_back(glu::SHADERTYPE_COMPUTE);
5297 addBuiltinPrecisionTests(m_testCtx,