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(),
1068 const T1& e1 = T1(),
1069 const T2& e2 = T2(),
1070 const T3& e3 = T3())
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 |= Interval(-DE_PI_DOUBLE, DE_PI_DOUBLE);
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 n * (dotNI * constant(2.0f)));
3085 class Refract : public DerivedFunc<
3086 Signature<typename ContainerOf<float, Size>::Container,
3087 typename ContainerOf<float, Size>::Container,
3088 typename ContainerOf<float, Size>::Container,
3092 typedef typename Refract::Ret Ret;
3093 typedef typename Refract::Arg0 Arg0;
3094 typedef typename Refract::Arg1 Arg1;
3095 typedef typename Refract::ArgExprs ArgExprs;
3097 string getName (void) const
3103 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3105 const ExprP<Arg0>& i = args.a;
3106 const ExprP<Arg1>& n = args.b;
3107 const ExprP<float>& eta = args.c;
3108 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3109 const ExprP<float> k = bindExpression("k", ctx, constant(1.0f) - eta * eta *
3110 (constant(1.0f) - dotNI * dotNI));
3112 return cond(k < constant(0.0f),
3113 genXType<float, Size>(constant(0.0f)),
3114 i * eta - n * (eta * dotNI + sqrt(k)));
3118 class PreciseFunc1 : public CFloatFunc1
3121 PreciseFunc1 (const string& name, DoubleFunc1& func) : CFloatFunc1(name, func) {}
3123 double precision (const EvalContext&, double, double) const { return 0.0; }
3126 class Abs : public PreciseFunc1
3129 Abs (void) : PreciseFunc1("abs", deAbs) {}
3132 class Sign : public PreciseFunc1
3135 Sign (void) : PreciseFunc1("sign", deSign) {}
3138 class Floor : public PreciseFunc1
3141 Floor (void) : PreciseFunc1("floor", deFloor) {}
3144 class Trunc : public PreciseFunc1
3147 Trunc (void) : PreciseFunc1("trunc", deTrunc) {}
3150 class Round : public FloatFunc1
3153 string getName (void) const { return "round"; }
3156 Interval applyPoint (const EvalContext&, double x) const
3158 double truncated = 0.0;
3159 const double fract = deModf(x, &truncated);
3162 if (fabs(fract) <= 0.5)
3164 if (fabs(fract) >= 0.5)
3165 ret |= truncated + deSign(fract);
3170 double precision (const EvalContext&, double, double) const { return 0.0; }
3173 class RoundEven : public PreciseFunc1
3176 RoundEven (void) : PreciseFunc1("roundEven", deRoundEven) {}
3179 class Ceil : public PreciseFunc1
3182 Ceil (void) : PreciseFunc1("ceil", deCeil) {}
3185 DEFINE_DERIVED_FLOAT1(Fract, fract, x, x - app<Floor>(x));
3187 class PreciseFunc2 : public CFloatFunc2
3190 PreciseFunc2 (const string& name, DoubleFunc2& func) : CFloatFunc2(name, func) {}
3192 double precision (const EvalContext&, double, double, double) const { return 0.0; }
3195 DEFINE_DERIVED_FLOAT2(Mod, mod, x, y, x - y * app<Floor>(x / y));
3197 class Modf : public PrimitiveFunc<Signature<float, float, float> >
3200 string getName (void) const
3206 IRet doApply (const EvalContext&, const IArgs& iargs) const
3209 Interval& wholeIV = const_cast<Interval&>(iargs.b);
3212 TCU_INTERVAL_APPLY_MONOTONE1(fracIV, x, iargs.a, frac, frac = deModf(x, &intPart));
3213 TCU_INTERVAL_APPLY_MONOTONE1(wholeIV, x, iargs.a, whole,
3214 deModf(x, &intPart); whole = intPart);
3216 if (!iargs.a.isFinite())
3218 // Behavior on modf(Inf) not well-defined, allow anything as a fractional part
3219 // See Khronos bug 13907
3226 int getOutParamIndex (void) const
3232 class Min : public PreciseFunc2 { public: Min (void) : PreciseFunc2("min", deMin) {} };
3233 class Max : public PreciseFunc2 { public: Max (void) : PreciseFunc2("max", deMax) {} };
3235 class Clamp : public FloatFunc3
3238 string getName (void) const { return "clamp"; }
3240 double applyExact (double x, double minVal, double maxVal) const
3242 return de::min(de::max(x, minVal), maxVal);
3245 double precision (const EvalContext&, double, double, double minVal, double maxVal) const
3247 return minVal > maxVal ? TCU_NAN : 0.0;
3251 ExprP<float> clamp(const ExprP<float>& x, const ExprP<float>& minVal, const ExprP<float>& maxVal)
3253 return app<Clamp>(x, minVal, maxVal);
3256 DEFINE_DERIVED_FLOAT3(Mix, mix, x, y, a, alternatives((x * (constant(1.0f) - a)) + y * a,
3259 static double step (double edge, double x)
3261 return x < edge ? 0.0 : 1.0;
3264 class Step : public PreciseFunc2 { public: Step (void) : PreciseFunc2("step", step) {} };
3266 class SmoothStep : public DerivedFunc<Signature<float, float, float, float> >
3269 string getName (void) const
3271 return "smoothstep";
3276 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3278 const ExprP<float>& edge0 = args.a;
3279 const ExprP<float>& edge1 = args.b;
3280 const ExprP<float>& x = args.c;
3281 const ExprP<float> tExpr = clamp((x - edge0) / (edge1 - edge0),
3282 constant(0.0f), constant(1.0f));
3283 const ExprP<float> t = bindExpression("t", ctx, tExpr);
3285 return (t * t * (constant(3.0f) - constant(2.0f) * t));
3289 class FrExp : public PrimitiveFunc<Signature<float, float, int> >
3292 string getName (void) const
3298 IRet doApply (const EvalContext&, const IArgs& iargs) const
3301 const IArg0& x = iargs.a;
3302 IArg1& exponent = const_cast<IArg1&>(iargs.b);
3304 if (x.hasNaN() || x.contains(TCU_INFINITY) || x.contains(-TCU_INFINITY))
3306 // GLSL (in contrast to IEEE) says that result of applying frexp
3307 // to infinity is undefined
3308 ret = Interval::unbounded() | TCU_NAN;
3309 exponent = Interval(-deLdExp(1.0, 31), deLdExp(1.0, 31)-1);
3311 else if (!x.empty())
3314 const double loFrac = deFrExp(x.lo(), &loExp);
3316 const double hiFrac = deFrExp(x.hi(), &hiExp);
3318 if (deSign(loFrac) != deSign(hiFrac))
3320 exponent = Interval(-TCU_INFINITY, de::max(loExp, hiExp));
3322 if (deSign(loFrac) < 0)
3323 ret |= Interval(-1.0 + DBL_EPSILON*0.5, 0.0);
3324 if (deSign(hiFrac) > 0)
3325 ret |= Interval(0.0, 1.0 - DBL_EPSILON*0.5);
3329 exponent = Interval(loExp, hiExp);
3331 ret = Interval(loFrac, hiFrac);
3333 ret = deSign(loFrac) * Interval(0.5, 1.0 - DBL_EPSILON*0.5);
3340 int getOutParamIndex (void) const
3346 class LdExp : public PrimitiveFunc<Signature<float, float, int> >
3349 string getName (void) const
3355 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
3357 Interval ret = call<Exp2>(ctx, iargs.b);
3358 // Khronos bug 11180 consensus: if exp2(exponent) cannot be represented,
3359 // the result is undefined.
3361 if (ret.contains(TCU_INFINITY) | ret.contains(-TCU_INFINITY))
3364 return call<Mul>(ctx, iargs.a, ret);
3368 template<int Rows, int Columns>
3369 class Transpose : public PrimitiveFunc<Signature<Matrix<float, Rows, Columns>,
3370 Matrix<float, Columns, Rows> > >
3373 typedef typename Transpose::IRet IRet;
3374 typedef typename Transpose::IArgs IArgs;
3376 string getName (void) const
3382 IRet doApply (const EvalContext&, const IArgs& iargs) const
3386 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
3388 for (int colNdx = 0; colNdx < Columns; ++colNdx)
3389 ret(rowNdx, colNdx) = iargs.a(colNdx, rowNdx);
3396 template<typename Ret, typename Arg0, typename Arg1>
3397 class MulFunc : public PrimitiveFunc<Signature<Ret, Arg0, Arg1> >
3400 string getName (void) const { return "mul"; }
3403 void doPrint (ostream& os, const BaseArgExprs& args) const
3405 os << "(" << *args[0] << " * " << *args[1] << ")";
3409 template<int LeftRows, int Middle, int RightCols>
3410 class MatMul : public MulFunc<Matrix<float, LeftRows, RightCols>,
3411 Matrix<float, LeftRows, Middle>,
3412 Matrix<float, Middle, RightCols> >
3415 typedef typename MatMul::IRet IRet;
3416 typedef typename MatMul::IArgs IArgs;
3417 typedef typename MatMul::IArg0 IArg0;
3418 typedef typename MatMul::IArg1 IArg1;
3420 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3422 const IArg0& left = iargs.a;
3423 const IArg1& right = iargs.b;
3426 for (int row = 0; row < LeftRows; ++row)
3428 for (int col = 0; col < RightCols; ++col)
3430 Interval element (0.0);
3432 for (int ndx = 0; ndx < Middle; ++ndx)
3433 element = call<Add>(ctx, element,
3434 call<Mul>(ctx, left[ndx][row], right[col][ndx]));
3436 ret[col][row] = element;
3444 template<int Rows, int Cols>
3445 class VecMatMul : public MulFunc<Vector<float, Cols>,
3446 Vector<float, Rows>,
3447 Matrix<float, Rows, Cols> >
3450 typedef typename VecMatMul::IRet IRet;
3451 typedef typename VecMatMul::IArgs IArgs;
3452 typedef typename VecMatMul::IArg0 IArg0;
3453 typedef typename VecMatMul::IArg1 IArg1;
3456 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3458 const IArg0& left = iargs.a;
3459 const IArg1& right = iargs.b;
3462 for (int col = 0; col < Cols; ++col)
3464 Interval element (0.0);
3466 for (int row = 0; row < Rows; ++row)
3467 element = call<Add>(ctx, element, call<Mul>(ctx, left[row], right[col][row]));
3476 template<int Rows, int Cols>
3477 class MatVecMul : public MulFunc<Vector<float, Rows>,
3478 Matrix<float, Rows, Cols>,
3479 Vector<float, Cols> >
3482 typedef typename MatVecMul::IRet IRet;
3483 typedef typename MatVecMul::IArgs IArgs;
3484 typedef typename MatVecMul::IArg0 IArg0;
3485 typedef typename MatVecMul::IArg1 IArg1;
3488 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3490 const IArg0& left = iargs.a;
3491 const IArg1& right = iargs.b;
3493 return call<VecMatMul<Cols, Rows> >(ctx, right,
3494 call<Transpose<Rows, Cols> >(ctx, left));
3498 template<int Rows, int Cols>
3499 class OuterProduct : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
3500 Vector<float, Rows>,
3501 Vector<float, Cols> > >
3504 typedef typename OuterProduct::IRet IRet;
3505 typedef typename OuterProduct::IArgs IArgs;
3507 string getName (void) const
3509 return "outerProduct";
3513 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3517 for (int row = 0; row < Rows; ++row)
3519 for (int col = 0; col < Cols; ++col)
3520 ret[col][row] = call<Mul>(ctx, iargs.a[row], iargs.b[col]);
3527 template<int Rows, int Cols>
3528 ExprP<Matrix<float, Rows, Cols> > outerProduct (const ExprP<Vector<float, Rows> >& left,
3529 const ExprP<Vector<float, Cols> >& right)
3531 return app<OuterProduct<Rows, Cols> >(left, right);
3535 class DeterminantBase : public DerivedFunc<Signature<float, Matrix<float, Size, Size> > >
3538 string getName (void) const { return "determinant"; }
3545 ExprP<float> determinant (ExprP<Matrix<float, Size, Size> > mat)
3547 return app<Determinant<Size> >(mat);
3551 class Determinant<2> : public DeterminantBase<2>
3554 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3556 ExprP<Mat2> mat = args.a;
3558 return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
3563 class Determinant<3> : public DeterminantBase<3>
3566 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3568 ExprP<Mat3> mat = args.a;
3570 return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) +
3571 mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) +
3572 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
3577 class Determinant<4> : public DeterminantBase<4>
3580 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3582 ExprP<Mat4> mat = args.a;
3583 ExprP<Mat3> minors[4];
3585 for (int ndx = 0; ndx < 4; ++ndx)
3587 ExprP<Vec4> minorColumns[3];
3588 ExprP<Vec3> columns[3];
3590 for (int col = 0; col < 3; ++col)
3591 minorColumns[col] = mat[col < ndx ? col : col + 1];
3593 for (int col = 0; col < 3; ++col)
3594 columns[col] = vec3(minorColumns[0][col+1],
3595 minorColumns[1][col+1],
3596 minorColumns[2][col+1]);
3598 minors[ndx] = bindExpression("minor", ctx,
3599 mat3(columns[0], columns[1], columns[2]));
3602 return (mat[0][0] * determinant(minors[0]) -
3603 mat[1][0] * determinant(minors[1]) +
3604 mat[2][0] * determinant(minors[2]) -
3605 mat[3][0] * determinant(minors[3]));
3609 template<int Size> class Inverse;
3612 ExprP<Matrix<float, Size, Size> > inverse (ExprP<Matrix<float, Size, Size> > mat)
3614 return app<Inverse<Size> >(mat);
3618 class Inverse<2> : public DerivedFunc<Signature<Mat2, Mat2> >
3621 string getName (void) const
3627 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3629 ExprP<Mat2> mat = args.a;
3630 ExprP<float> det = bindExpression("det", ctx, determinant(mat));
3632 return mat2(vec2(mat[1][1] / det, -mat[0][1] / det),
3633 vec2(-mat[1][0] / det, mat[0][0] / det));
3638 class Inverse<3> : public DerivedFunc<Signature<Mat3, Mat3> >
3641 string getName (void) const
3647 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3649 ExprP<Mat3> mat = args.a;
3650 ExprP<Mat2> invA = bindExpression("invA", ctx,
3651 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3652 vec2(mat[1][0], mat[1][1]))));
3654 ExprP<Vec2> matB = bindExpression("matB", ctx, vec2(mat[2][0], mat[2][1]));
3655 ExprP<Vec2> matC = bindExpression("matC", ctx, vec2(mat[0][2], mat[1][2]));
3656 ExprP<float> matD = bindExpression("matD", ctx, mat[2][2]);
3658 ExprP<float> schur = bindExpression("schur", ctx,
3660 (matD - dot(matC * invA, matB)));
3662 ExprP<Vec2> t1 = invA * matB;
3663 ExprP<Vec2> t2 = t1 * schur;
3664 ExprP<Mat2> t3 = outerProduct(t2, matC);
3665 ExprP<Mat2> t4 = t3 * invA;
3666 ExprP<Mat2> t5 = invA + t4;
3667 ExprP<Mat2> blockA = bindExpression("blockA", ctx, t5);
3668 ExprP<Vec2> blockB = bindExpression("blockB", ctx,
3669 (invA * matB) * -schur);
3670 ExprP<Vec2> blockC = bindExpression("blockC", ctx,
3671 (matC * invA) * -schur);
3673 return mat3(vec3(blockA[0][0], blockA[0][1], blockC[0]),
3674 vec3(blockA[1][0], blockA[1][1], blockC[1]),
3675 vec3(blockB[0], blockB[1], schur));
3680 class Inverse<4> : public DerivedFunc<Signature<Mat4, Mat4> >
3683 string getName (void) const { return "inverse"; }
3686 ExprP<Ret> doExpand (ExpandContext& ctx,
3687 const ArgExprs& args) const
3689 ExprP<Mat4> mat = args.a;
3690 ExprP<Mat2> invA = bindExpression("invA", ctx,
3691 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3692 vec2(mat[1][0], mat[1][1]))));
3693 ExprP<Mat2> matB = bindExpression("matB", ctx,
3694 mat2(vec2(mat[2][0], mat[2][1]),
3695 vec2(mat[3][0], mat[3][1])));
3696 ExprP<Mat2> matC = bindExpression("matC", ctx,
3697 mat2(vec2(mat[0][2], mat[0][3]),
3698 vec2(mat[1][2], mat[1][3])));
3699 ExprP<Mat2> matD = bindExpression("matD", ctx,
3700 mat2(vec2(mat[2][2], mat[2][3]),
3701 vec2(mat[3][2], mat[3][3])));
3702 ExprP<Mat2> schur = bindExpression("schur", ctx,
3703 inverse(matD + -(matC * invA * matB)));
3704 ExprP<Mat2> blockA = bindExpression("blockA", ctx,
3705 invA + (invA * matB * schur * matC * invA));
3706 ExprP<Mat2> blockB = bindExpression("blockB", ctx,
3707 (-invA) * matB * schur);
3708 ExprP<Mat2> blockC = bindExpression("blockC", ctx,
3709 (-schur) * matC * invA);
3711 return mat4(vec4(blockA[0][0], blockA[0][1], blockC[0][0], blockC[0][1]),
3712 vec4(blockA[1][0], blockA[1][1], blockC[1][0], blockC[1][1]),
3713 vec4(blockB[0][0], blockB[0][1], schur[0][0], schur[0][1]),
3714 vec4(blockB[1][0], blockB[1][1], schur[1][0], schur[1][1]));
3718 class Fma : public DerivedFunc<Signature<float, float, float, float> >
3721 string getName (void) const
3726 string getRequiredExtension (void) const
3728 return "GL_EXT_gpu_shader5";
3732 ExprP<float> doExpand (ExpandContext&, const ArgExprs& x) const
3734 return x.a * x.b + x.c;
3740 using namespace Functions;
3742 template <typename T>
3743 ExprP<typename T::Element> ContainerExprPBase<T>::operator[] (int i) const
3745 return Functions::getComponent(exprP<T>(*this), i);
3748 ExprP<float> operator+ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3750 return app<Add>(arg0, arg1);
3753 ExprP<float> operator- (const ExprP<float>& arg0, const ExprP<float>& arg1)
3755 return app<Sub>(arg0, arg1);
3758 ExprP<float> operator- (const ExprP<float>& arg0)
3760 return app<Negate>(arg0);
3763 ExprP<float> operator* (const ExprP<float>& arg0, const ExprP<float>& arg1)
3765 return app<Mul>(arg0, arg1);
3768 ExprP<float> operator/ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3770 return app<Div>(arg0, arg1);
3773 template <typename Sig_, int Size>
3774 class GenFunc : public PrimitiveFunc<Signature<
3775 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3776 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3777 typename ContainerOf<typename Sig_::Arg1, Size>::Container,
3778 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
3779 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
3782 typedef typename GenFunc::IArgs IArgs;
3783 typedef typename GenFunc::IRet IRet;
3785 GenFunc (const Func<Sig_>& scalarFunc) : m_func (scalarFunc) {}
3787 string getName (void) const
3789 return m_func.getName();
3792 int getOutParamIndex (void) const
3794 return m_func.getOutParamIndex();
3797 string getRequiredExtension (void) const
3799 return m_func.getRequiredExtension();
3803 void doPrint (ostream& os, const BaseArgExprs& args) const
3805 m_func.print(os, args);
3808 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3812 for (int ndx = 0; ndx < Size; ++ndx)
3815 m_func.apply(ctx, iargs.a[ndx], iargs.b[ndx], iargs.c[ndx], iargs.d[ndx]);
3821 void doGetUsedFuncs (FuncSet& dst) const
3823 m_func.getUsedFuncs(dst);
3826 const Func<Sig_>& m_func;
3829 template <typename F, int Size>
3830 class VectorizedFunc : public GenFunc<typename F::Sig, Size>
3833 VectorizedFunc (void) : GenFunc<typename F::Sig, Size>(instance<F>()) {}
3838 template <typename Sig_, int Size>
3839 class FixedGenFunc : public PrimitiveFunc <Signature<
3840 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3841 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3842 typename Sig_::Arg1,
3843 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
3844 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
3847 typedef typename FixedGenFunc::IArgs IArgs;
3848 typedef typename FixedGenFunc::IRet IRet;
3850 string getName (void) const
3852 return this->doGetScalarFunc().getName();
3856 void doPrint (ostream& os, const BaseArgExprs& args) const
3858 this->doGetScalarFunc().print(os, args);
3861 IRet doApply (const EvalContext& ctx,
3862 const IArgs& iargs) const
3865 const Func<Sig_>& func = this->doGetScalarFunc();
3867 for (int ndx = 0; ndx < Size; ++ndx)
3868 ret[ndx] = func.apply(ctx, iargs.a[ndx], iargs.b, iargs.c[ndx], iargs.d[ndx]);
3873 virtual const Func<Sig_>& doGetScalarFunc (void) const = 0;
3876 template <typename F, int Size>
3877 class FixedVecFunc : public FixedGenFunc<typename F::Sig, Size>
3880 const Func<typename F::Sig>& doGetScalarFunc (void) const { return instance<F>(); }
3883 template<typename Sig>
3886 GenFuncs (const Func<Sig>& func_,
3887 const GenFunc<Sig, 2>& func2_,
3888 const GenFunc<Sig, 3>& func3_,
3889 const GenFunc<Sig, 4>& func4_)
3896 const Func<Sig>& func;
3897 const GenFunc<Sig, 2>& func2;
3898 const GenFunc<Sig, 3>& func3;
3899 const GenFunc<Sig, 4>& func4;
3902 template<typename F>
3903 GenFuncs<typename F::Sig> makeVectorizedFuncs (void)
3905 return GenFuncs<typename F::Sig>(instance<F>(),
3906 instance<VectorizedFunc<F, 2> >(),
3907 instance<VectorizedFunc<F, 3> >(),
3908 instance<VectorizedFunc<F, 4> >());
3912 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
3913 const ExprP<Vector<float, Size> >& arg1)
3915 return app<VectorizedFunc<Mul, Size> >(arg0, arg1);
3919 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
3920 const ExprP<float>& arg1)
3922 return app<FixedVecFunc<Mul, Size> >(arg0, arg1);
3926 ExprP<Vector<float, Size> > operator/(const ExprP<Vector<float, Size> >& arg0,
3927 const ExprP<float>& arg1)
3929 return app<FixedVecFunc<Div, Size> >(arg0, arg1);
3933 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0)
3935 return app<VectorizedFunc<Negate, Size> >(arg0);
3939 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
3940 const ExprP<Vector<float, Size> >& arg1)
3942 return app<VectorizedFunc<Sub, Size> >(arg0, arg1);
3945 template<int LeftRows, int Middle, int RightCols>
3946 ExprP<Matrix<float, LeftRows, RightCols> >
3947 operator* (const ExprP<Matrix<float, LeftRows, Middle> >& left,
3948 const ExprP<Matrix<float, Middle, RightCols> >& right)
3950 return app<MatMul<LeftRows, Middle, RightCols> >(left, right);
3953 template<int Rows, int Cols>
3954 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
3955 const ExprP<Matrix<float, Rows, Cols> >& right)
3957 return app<VecMatMul<Rows, Cols> >(left, right);
3960 template<int Rows, int Cols>
3961 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
3962 const ExprP<Vector<float, Rows> >& right)
3964 return app<MatVecMul<Rows, Cols> >(left, right);
3967 template<int Rows, int Cols>
3968 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
3969 const ExprP<float>& right)
3971 return app<ScalarMatFunc<Mul, Rows, Cols> >(left, right);
3974 template<int Rows, int Cols>
3975 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
3976 const ExprP<Matrix<float, Rows, Cols> >& right)
3978 return app<CompMatFunc<Add, Rows, Cols> >(left, right);
3981 template<int Rows, int Cols>
3982 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat)
3984 return app<MatNeg<Rows, Cols> >(mat);
3987 template <typename T>
3991 virtual void genFixeds (const FloatFormat&, vector<T>&) const {}
3992 virtual T genRandom (const FloatFormat&, Precision, Random&) const { return T(); }
3993 virtual double getWeight (void) const { return 0.0; }
3997 class DefaultSampling<Void> : public Sampling<Void>
4000 void genFixeds (const FloatFormat&, vector<Void>& dst) const { dst.push_back(Void()); }
4004 class DefaultSampling<bool> : public Sampling<bool>
4007 void genFixeds (const FloatFormat&, vector<bool>& dst) const
4009 dst.push_back(true);
4010 dst.push_back(false);
4015 class DefaultSampling<int> : public Sampling<int>
4018 int genRandom (const FloatFormat&, Precision prec, Random& rnd) const
4020 const int exp = rnd.getInt(0, getNumBits(prec)-2);
4021 const int sign = rnd.getBool() ? -1 : 1;
4023 return sign * rnd.getInt(0, (deInt32)1 << exp);
4026 void genFixeds (const FloatFormat&, vector<int>& dst) const
4032 double getWeight (void) const { return 1.0; }
4035 static inline int getNumBits (Precision prec)
4039 case glu::PRECISION_LOWP: return 8;
4040 case glu::PRECISION_MEDIUMP: return 16;
4041 case glu::PRECISION_HIGHP: return 32;
4050 class DefaultSampling<float> : public Sampling<float>
4053 float genRandom (const FloatFormat& format, Precision prec, Random& rnd) const;
4054 void genFixeds (const FloatFormat& format, vector<float>& dst) const;
4055 double getWeight (void) const { return 1.0; }
4058 //! Generate a random float from a reasonable general-purpose distribution.
4059 float DefaultSampling<float>::genRandom (const FloatFormat& format,
4063 const int minExp = format.getMinExp();
4064 const int maxExp = format.getMaxExp();
4065 const bool haveSubnormal = format.hasSubnormal() != tcu::NO;
4067 // Choose exponent so that the cumulative distribution is cubic.
4068 // This makes the probability distribution quadratic, with the peak centered on zero.
4069 const double minRoot = deCbrt(minExp - 0.5 - (haveSubnormal ? 1.0 : 0.0));
4070 const double maxRoot = deCbrt(maxExp + 0.5);
4071 const int fractionBits = format.getFractionBits();
4072 const int exp = int(deRoundEven(dePow(rnd.getDouble(minRoot, maxRoot),
4074 float base = 0.0f; // integral power of two
4075 float quantum = 0.0f; // smallest representable difference in the binade
4076 float significand = 0.0f; // Significand.
4078 DE_ASSERT(fractionBits < std::numeric_limits<float>::digits);
4080 // Generate some occasional special numbers
4081 switch (rnd.getInt(0, 64))
4084 case 1: return TCU_INFINITY;
4085 case 2: return -TCU_INFINITY;
4086 case 3: return TCU_NAN;
4093 base = deFloatLdExp(1.0f, exp);
4094 quantum = deFloatLdExp(1.0f, exp - fractionBits);
4100 quantum = deFloatLdExp(1.0f, minExp - fractionBits);
4103 switch (rnd.getInt(0, 16))
4105 case 0: // The highest number in this binade, significand is all bits one.
4106 significand = base - quantum;
4108 case 1: // Significand is one.
4109 significand = quantum;
4111 case 2: // Significand is zero.
4114 default: // Random (evenly distributed) significand.
4116 deUint64 intFraction = rnd.getUint64() & ((1 << fractionBits) - 1);
4117 significand = float(intFraction) * quantum;
4121 // Produce positive numbers more often than negative.
4122 return (rnd.getInt(0,3) == 0 ? -1.0f : 1.0f) * (base + significand);
4125 //! Generate a standard set of floats that should always be tested.
4126 void DefaultSampling<float>::genFixeds (const FloatFormat& format, vector<float>& dst) const
4128 const int minExp = format.getMinExp();
4129 const int maxExp = format.getMaxExp();
4130 const int fractionBits = format.getFractionBits();
4131 const float minQuantum = deFloatLdExp(1.0f, minExp - fractionBits);
4132 const float minNormalized = deFloatLdExp(1.0f, minExp);
4133 const float maxQuantum = deFloatLdExp(1.0f, maxExp - fractionBits);
4136 dst.push_back(TCU_NAN);
4138 dst.push_back(0.0f);
4140 for (int sign = -1; sign <= 1; sign += 2)
4142 // Smallest subnormal
4143 dst.push_back((float)sign * minQuantum);
4145 // Largest subnormal
4146 dst.push_back((float)sign * (minNormalized - minQuantum));
4148 // Smallest normalized
4149 dst.push_back((float)sign * minNormalized);
4151 // Next smallest normalized
4152 dst.push_back((float)sign * (minNormalized + minQuantum));
4154 dst.push_back((float)sign * 0.5f);
4155 dst.push_back((float)sign * 1.0f);
4156 dst.push_back((float)sign * 2.0f);
4159 dst.push_back((float)sign * (deFloatLdExp(1.0f, maxExp) +
4160 (deFloatLdExp(1.0f, maxExp) - maxQuantum)));
4162 dst.push_back((float)sign * TCU_INFINITY);
4166 template <typename T, int Size>
4167 class DefaultSampling<Vector<T, Size> > : public Sampling<Vector<T, Size> >
4170 typedef Vector<T, Size> Value;
4172 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4176 for (int ndx = 0; ndx < Size; ++ndx)
4177 ret[ndx] = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4182 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4186 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4188 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4189 dst.push_back(Value(scalars[scalarNdx]));
4192 double getWeight (void) const
4194 return dePow(instance<DefaultSampling<T> >().getWeight(), Size);
4198 template <typename T, int Rows, int Columns>
4199 class DefaultSampling<Matrix<T, Rows, Columns> > : public Sampling<Matrix<T, Rows, Columns> >
4202 typedef Matrix<T, Rows, Columns> Value;
4204 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4208 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
4209 for (int colNdx = 0; colNdx < Columns; ++colNdx)
4210 ret(rowNdx, colNdx) = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4215 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4219 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4221 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4222 dst.push_back(Value(scalars[scalarNdx]));
4224 if (Columns == Rows)
4229 for (int ndx = 0; ndx < Columns; ++ndx)
4231 mat[Columns-1-ndx][ndx] = x;
4238 double getWeight (void) const
4240 return dePow(instance<DefaultSampling<T> >().getWeight(), Rows * Columns);
4246 CaseContext (const string& name_,
4247 TestContext& testContext_,
4248 const FloatFormat& floatFormat_,
4249 const FloatFormat& highpFormat_,
4250 Precision precision_,
4251 ShaderType shaderType_,
4254 , testContext (testContext_)
4255 , floatFormat (floatFormat_)
4256 , highpFormat (highpFormat_)
4257 , precision (precision_)
4258 , shaderType (shaderType_)
4259 , numRandoms (numRandoms_) {}
4262 TestContext& testContext;
4263 FloatFormat floatFormat;
4264 FloatFormat highpFormat;
4265 Precision precision;
4266 ShaderType shaderType;
4270 template<typename In0_ = Void, typename In1_ = Void, typename In2_ = Void, typename In3_ = Void>
4279 template <typename In>
4280 int numInputs (void)
4282 return (!isTypeValid<typename In::In0>() ? 0 :
4283 !isTypeValid<typename In::In1>() ? 1 :
4284 !isTypeValid<typename In::In2>() ? 2 :
4285 !isTypeValid<typename In::In3>() ? 3 :
4289 template<typename Out0_, typename Out1_ = Void>
4296 template <typename Out>
4297 int numOutputs (void)
4299 return (!isTypeValid<typename Out::Out0>() ? 0 :
4300 !isTypeValid<typename Out::Out1>() ? 1 :
4304 template<typename In>
4307 vector<typename In::In0> in0;
4308 vector<typename In::In1> in1;
4309 vector<typename In::In2> in2;
4310 vector<typename In::In3> in3;
4313 template<typename Out>
4316 Outputs (size_t size) : out0(size), out1(size) {}
4318 vector<typename Out::Out0> out0;
4319 vector<typename Out::Out1> out1;
4322 template<typename In, typename Out>
4325 VariableP<typename In::In0> in0;
4326 VariableP<typename In::In1> in1;
4327 VariableP<typename In::In2> in2;
4328 VariableP<typename In::In3> in3;
4329 VariableP<typename Out::Out0> out0;
4330 VariableP<typename Out::Out1> out1;
4333 template<typename In>
4336 Samplings (const Sampling<typename In::In0>& in0_,
4337 const Sampling<typename In::In1>& in1_,
4338 const Sampling<typename In::In2>& in2_,
4339 const Sampling<typename In::In3>& in3_)
4340 : in0 (in0_), in1 (in1_), in2 (in2_), in3 (in3_) {}
4342 const Sampling<typename In::In0>& in0;
4343 const Sampling<typename In::In1>& in1;
4344 const Sampling<typename In::In2>& in2;
4345 const Sampling<typename In::In3>& in3;
4348 template<typename In>
4349 struct DefaultSamplings : Samplings<In>
4351 DefaultSamplings (void)
4352 : Samplings<In>(instance<DefaultSampling<typename In::In0> >(),
4353 instance<DefaultSampling<typename In::In1> >(),
4354 instance<DefaultSampling<typename In::In2> >(),
4355 instance<DefaultSampling<typename In::In3> >()) {}
4358 template <typename In, typename Out>
4359 class BuiltinPrecisionCaseTestInstance : public TestInstance
4362 BuiltinPrecisionCaseTestInstance (Context& context,
4363 const CaseContext caseCtx,
4364 ShaderExecutor& executor,
4365 const Variables<In, Out> variables,
4366 const Samplings<In>& samplings,
4367 const StatementP stmt)
4368 : TestInstance (context)
4369 , m_caseCtx (caseCtx)
4370 , m_executor (executor)
4371 , m_variables (variables)
4372 , m_samplings (samplings)
4376 virtual tcu::TestStatus iterate (void);
4379 CaseContext m_caseCtx;
4380 ShaderExecutor& m_executor;
4381 Variables<In, Out> m_variables;
4382 const Samplings<In>& m_samplings;
4386 template<class In, class Out>
4387 tcu::TestStatus BuiltinPrecisionCaseTestInstance<In, Out>::iterate (void)
4389 typedef typename In::In0 In0;
4390 typedef typename In::In1 In1;
4391 typedef typename In::In2 In2;
4392 typedef typename In::In3 In3;
4393 typedef typename Out::Out0 Out0;
4394 typedef typename Out::Out1 Out1;
4396 Inputs<In> inputs = generateInputs(m_samplings, m_caseCtx.floatFormat, m_caseCtx.precision, m_caseCtx.numRandoms, 0xdeadbeefu + m_caseCtx.testContext.getCommandLine().getBaseSeed());
4397 const FloatFormat& fmt = m_caseCtx.floatFormat;
4398 const int inCount = numInputs<In>();
4399 const int outCount = numOutputs<Out>();
4400 const size_t numValues = (inCount > 0) ? inputs.in0.size() : 1;
4401 Outputs<Out> outputs (numValues);
4402 const FloatFormat highpFmt = m_caseCtx.highpFormat;
4403 const int maxMsgs = 100;
4405 Environment env; // Hoisted out of the inner loop for optimization.
4406 ResultCollector status;
4407 TestLog& testLog = m_context.getTestContext().getLog();
4409 const void* inputArr[] =
4411 &inputs.in0.front(), &inputs.in1.front(), &inputs.in2.front(), &inputs.in3.front(),
4415 &outputs.out0.front(), &outputs.out1.front(),
4418 // Print out the statement and its definitions
4419 testLog << TestLog::Message << "Statement: " << m_stmt << TestLog::EndMessage;
4424 m_stmt->getUsedFuncs(funcs);
4425 for (FuncSet::const_iterator it = funcs.begin(); it != funcs.end(); ++it)
4427 (*it)->printDefinition(oss);
4430 testLog << TestLog::Message << "Reference definitions:\n" << oss.str()
4431 << TestLog::EndMessage;
4436 case 4: DE_ASSERT(inputs.in3.size() == numValues);
4437 case 3: DE_ASSERT(inputs.in2.size() == numValues);
4438 case 2: DE_ASSERT(inputs.in1.size() == numValues);
4439 case 1: DE_ASSERT(inputs.in0.size() == numValues);
4443 m_executor.execute(m_context, int(numValues), inputArr, outputArr);
4445 // Initialize environment with dummy values so we don't need to bind in inner loop.
4447 const typename Traits<In0>::IVal in0;
4448 const typename Traits<In1>::IVal in1;
4449 const typename Traits<In2>::IVal in2;
4450 const typename Traits<In3>::IVal in3;
4451 const typename Traits<Out0>::IVal reference0;
4452 const typename Traits<Out1>::IVal reference1;
4454 env.bind(*m_variables.in0, in0);
4455 env.bind(*m_variables.in1, in1);
4456 env.bind(*m_variables.in2, in2);
4457 env.bind(*m_variables.in3, in3);
4458 env.bind(*m_variables.out0, reference0);
4459 env.bind(*m_variables.out1, reference1);
4462 // For each input tuple, compute output reference interval and compare
4463 // shader output to the reference.
4464 for (size_t valueNdx = 0; valueNdx < numValues; valueNdx++)
4467 typename Traits<Out0>::IVal reference0;
4468 typename Traits<Out1>::IVal reference1;
4470 env.lookup(*m_variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx]));
4471 env.lookup(*m_variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx]));
4472 env.lookup(*m_variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx]));
4473 env.lookup(*m_variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx]));
4476 EvalContext ctx (fmt, m_caseCtx.precision, env);
4477 m_stmt->execute(ctx);
4483 reference1 = convert<Out1>(highpFmt, env.lookup(*m_variables.out1));
4484 if (!status.check(contains(reference1, outputs.out1[valueNdx]),
4485 "Shader output 1 is outside acceptable range"))
4488 reference0 = convert<Out0>(highpFmt, env.lookup(*m_variables.out0));
4489 if (!status.check(contains(reference0, outputs.out0[valueNdx]),
4490 "Shader output 0 is outside acceptable range"))
4498 if ((!result && numErrors <= maxMsgs) || GLS_LOG_ALL_RESULTS)
4500 MessageBuilder builder = testLog.message();
4502 builder << (result ? "Passed" : "Failed") << " sample:\n";
4506 builder << "\t" << m_variables.in0->getName() << " = "
4507 << valueToString(highpFmt, inputs.in0[valueNdx]) << "\n";
4512 builder << "\t" << m_variables.in1->getName() << " = "
4513 << valueToString(highpFmt, inputs.in1[valueNdx]) << "\n";
4518 builder << "\t" << m_variables.in2->getName() << " = "
4519 << valueToString(highpFmt, inputs.in2[valueNdx]) << "\n";
4524 builder << "\t" << m_variables.in3->getName() << " = "
4525 << valueToString(highpFmt, inputs.in3[valueNdx]) << "\n";
4530 builder << "\t" << m_variables.out0->getName() << " = "
4531 << valueToString(highpFmt, outputs.out0[valueNdx]) << "\n"
4532 << "\tExpected range: "
4533 << intervalToString<typename Out::Out0>(highpFmt, reference0) << "\n";
4538 builder << "\t" << m_variables.out1->getName() << " = "
4539 << valueToString(highpFmt, outputs.out1[valueNdx]) << "\n"
4540 << "\tExpected range: "
4541 << intervalToString<typename Out::Out1>(highpFmt, reference1) << "\n";
4544 builder << TestLog::EndMessage;
4548 if (numErrors > maxMsgs)
4550 testLog << TestLog::Message << "(Skipped " << (numErrors - maxMsgs) << " messages.)"
4551 << TestLog::EndMessage;
4556 testLog << TestLog::Message << "All " << numValues << " inputs passed."
4557 << TestLog::EndMessage;
4561 testLog << TestLog::Message << numErrors << "/" << numValues << " inputs failed."
4562 << TestLog::EndMessage;
4566 return tcu::TestStatus::fail(de::toString(numErrors) + string(" test failed. Check log for the details"));
4568 return tcu::TestStatus::pass("Pass");
4572 class PrecisionCase : public TestCase
4575 PrecisionCase (const CaseContext& context, const string& name, const string& extension = "")
4576 : TestCase (context.testContext, name.c_str(), name.c_str())
4578 , m_extension (extension)
4579 , m_executor (DE_NULL)
4583 virtual void initPrograms (vk::SourceCollections& programCollection) const
4585 m_executor->setShaderSources(programCollection);
4588 const FloatFormat& getFormat (void) const { return m_ctx.floatFormat; }
4590 template <typename In, typename Out>
4591 void testStatement (const Variables<In, Out>& variables, const Statement& stmt);
4593 template<typename T>
4594 Symbol makeSymbol (const Variable<T>& variable)
4596 return Symbol(variable.getName(), getVarTypeOf<T>(m_ctx.precision));
4600 const string m_extension;
4602 de::MovePtr<ShaderExecutor> m_executor;
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);
4644 m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_ctx.shaderType, m_spec));
4647 template <typename T>
4650 bool operator() (const T& val1, const T& val2) const
4656 template <typename T>
4657 bool inputLess (const T& val1, const T& val2)
4659 return InputLess<T>()(val1, val2);
4663 struct InputLess<float>
4665 bool operator() (const float& val1, const float& val2) const
4675 template <typename T, int Size>
4676 struct InputLess<Vector<T, Size> >
4678 bool operator() (const Vector<T, Size>& vec1, const Vector<T, Size>& vec2) const
4680 for (int ndx = 0; ndx < Size; ++ndx)
4682 if (inputLess(vec1[ndx], vec2[ndx]))
4684 if (inputLess(vec2[ndx], vec1[ndx]))
4692 template <typename T, int Rows, int Cols>
4693 struct InputLess<Matrix<T, Rows, Cols> >
4695 bool operator() (const Matrix<T, Rows, Cols>& mat1,
4696 const Matrix<T, Rows, Cols>& mat2) const
4698 for (int col = 0; col < Cols; ++col)
4700 if (inputLess(mat1[col], mat2[col]))
4702 if (inputLess(mat2[col], mat1[col]))
4710 template <typename In>
4712 public Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4714 InTuple (const typename In::In0& in0,
4715 const typename In::In1& in1,
4716 const typename In::In2& in2,
4717 const typename In::In3& in3)
4718 : Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4719 (in0, in1, in2, in3) {}
4722 template <typename In>
4723 struct InputLess<InTuple<In> >
4725 bool operator() (const InTuple<In>& in1, const InTuple<In>& in2) const
4727 if (inputLess(in1.a, in2.a))
4729 if (inputLess(in2.a, in1.a))
4731 if (inputLess(in1.b, in2.b))
4733 if (inputLess(in2.b, in1.b))
4735 if (inputLess(in1.c, in2.c))
4737 if (inputLess(in2.c, in1.c))
4739 if (inputLess(in1.d, in2.d))
4745 template<typename In>
4746 Inputs<In> generateInputs (const Samplings<In>& samplings,
4747 const FloatFormat& floatFormat,
4748 Precision intPrecision,
4754 Inputs<In> fixedInputs;
4755 set<InTuple<In>, InputLess<InTuple<In> > > seenInputs;
4757 samplings.in0.genFixeds(floatFormat, fixedInputs.in0);
4758 samplings.in1.genFixeds(floatFormat, fixedInputs.in1);
4759 samplings.in2.genFixeds(floatFormat, fixedInputs.in2);
4760 samplings.in3.genFixeds(floatFormat, fixedInputs.in3);
4762 for (size_t ndx0 = 0; ndx0 < fixedInputs.in0.size(); ++ndx0)
4764 for (size_t ndx1 = 0; ndx1 < fixedInputs.in1.size(); ++ndx1)
4766 for (size_t ndx2 = 0; ndx2 < fixedInputs.in2.size(); ++ndx2)
4768 for (size_t ndx3 = 0; ndx3 < fixedInputs.in3.size(); ++ndx3)
4770 const InTuple<In> tuple (fixedInputs.in0[ndx0],
4771 fixedInputs.in1[ndx1],
4772 fixedInputs.in2[ndx2],
4773 fixedInputs.in3[ndx3]);
4775 seenInputs.insert(tuple);
4776 ret.in0.push_back(tuple.a);
4777 ret.in1.push_back(tuple.b);
4778 ret.in2.push_back(tuple.c);
4779 ret.in3.push_back(tuple.d);
4785 for (size_t ndx = 0; ndx < numSamples; ++ndx)
4787 const typename In::In0 in0 = samplings.in0.genRandom(floatFormat, intPrecision, rnd);
4788 const typename In::In1 in1 = samplings.in1.genRandom(floatFormat, intPrecision, rnd);
4789 const typename In::In2 in2 = samplings.in2.genRandom(floatFormat, intPrecision, rnd);
4790 const typename In::In3 in3 = samplings.in3.genRandom(floatFormat, intPrecision, rnd);
4791 const InTuple<In> tuple (in0, in1, in2, in3);
4793 if (de::contains(seenInputs, tuple))
4796 seenInputs.insert(tuple);
4797 ret.in0.push_back(in0);
4798 ret.in1.push_back(in1);
4799 ret.in2.push_back(in2);
4800 ret.in3.push_back(in3);
4806 class FuncCaseBase : public PrecisionCase
4809 FuncCaseBase (const CaseContext& context, const string& name, const FuncBase& func)
4810 : PrecisionCase (context, name, func.getRequiredExtension())
4817 template <typename Sig>
4818 class FuncCase : public FuncCaseBase
4821 typedef Func<Sig> CaseFunc;
4822 typedef typename Sig::Ret Ret;
4823 typedef typename Sig::Arg0 Arg0;
4824 typedef typename Sig::Arg1 Arg1;
4825 typedef typename Sig::Arg2 Arg2;
4826 typedef typename Sig::Arg3 Arg3;
4827 typedef InTypes<Arg0, Arg1, Arg2, Arg3> In;
4828 typedef OutTypes<Ret> Out;
4830 FuncCase (const CaseContext& context, const string& name, const CaseFunc& func)
4831 : FuncCaseBase (context, name, func)
4837 virtual TestInstance* createInstance (Context& context) const
4839 return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, getSamplings(), m_stmt);
4843 void buildTest (void);
4844 virtual const Samplings<In>& getSamplings (void) const
4846 return instance<DefaultSamplings<In> >();
4850 const CaseFunc& m_func;
4851 Variables<In, Out> m_variables;
4854 template <typename Sig>
4855 void FuncCase<Sig>::buildTest (void)
4857 m_variables.out0 = variable<Ret>("out0");
4858 m_variables.out1 = variable<Void>("out1");
4859 m_variables.in0 = variable<Arg0>("in0");
4860 m_variables.in1 = variable<Arg1>("in1");
4861 m_variables.in2 = variable<Arg2>("in2");
4862 m_variables.in3 = variable<Arg3>("in3");
4865 ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.in1, m_variables.in2, m_variables.in3);
4866 m_stmt = variableAssignment(m_variables.out0, expr);
4868 this->testStatement(m_variables, *m_stmt);
4872 template <typename Sig>
4873 class InOutFuncCase : public FuncCaseBase
4876 typedef Func<Sig> CaseFunc;
4877 typedef typename Sig::Ret Ret;
4878 typedef typename Sig::Arg0 Arg0;
4879 typedef typename Sig::Arg1 Arg1;
4880 typedef typename Sig::Arg2 Arg2;
4881 typedef typename Sig::Arg3 Arg3;
4882 typedef InTypes<Arg0, Arg2, Arg3> In;
4883 typedef OutTypes<Ret, Arg1> Out;
4885 InOutFuncCase (const CaseContext& context, const string& name, const CaseFunc& func)
4886 : FuncCaseBase (context, name, func)
4891 virtual TestInstance* createInstance (Context& context) const
4893 return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, getSamplings(), m_stmt);
4897 void buildTest (void);
4898 virtual const Samplings<In>& getSamplings (void) const
4900 return instance<DefaultSamplings<In> >();
4904 const CaseFunc& m_func;
4905 Variables<In, Out> m_variables;
4908 template <typename Sig>
4909 void InOutFuncCase<Sig>::buildTest (void)
4912 m_variables.out0 = variable<Ret>("out0");
4913 m_variables.out1 = variable<Arg1>("out1");
4914 m_variables.in0 = variable<Arg0>("in0");
4915 m_variables.in1 = variable<Arg2>("in1");
4916 m_variables.in2 = variable<Arg3>("in2");
4917 m_variables.in3 = variable<Void>("in3");
4920 ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.out1, m_variables.in1, m_variables.in2);
4921 m_stmt = variableAssignment(m_variables.out0, expr);
4923 this->testStatement(m_variables, *m_stmt);
4927 template <typename Sig>
4928 PrecisionCase* createFuncCase (const CaseContext& context, const string& name, const Func<Sig>& func)
4930 switch (func.getOutParamIndex())
4933 return new FuncCase<Sig>(context, name, func);
4935 return new InOutFuncCase<Sig>(context, name, func);
4937 DE_FATAL("Impossible");
4945 virtual ~CaseFactory (void) {}
4946 virtual MovePtr<TestNode> createCase (const CaseContext& ctx) const = 0;
4947 virtual string getName (void) const = 0;
4948 virtual string getDesc (void) const = 0;
4951 class FuncCaseFactory : public CaseFactory
4954 virtual const FuncBase& getFunc (void) const = 0;
4955 string getName (void) const { return de::toLower(getFunc().getName()); }
4956 string getDesc (void) const { return "Function '" + getFunc().getName() + "'"; }
4959 template <typename Sig>
4960 class GenFuncCaseFactory : public CaseFactory
4963 GenFuncCaseFactory (const GenFuncs<Sig>& funcs, const string& name)
4965 , m_name (de::toLower(name))
4969 MovePtr<TestNode> createCase (const CaseContext& ctx) const
4971 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
4973 group->addChild(createFuncCase(ctx, "scalar", m_funcs.func));
4974 group->addChild(createFuncCase(ctx, "vec2", m_funcs.func2));
4975 group->addChild(createFuncCase(ctx, "vec3", m_funcs.func3));
4976 group->addChild(createFuncCase(ctx, "vec4", m_funcs.func4));
4977 return MovePtr<TestNode>(group);
4980 string getName (void) const { return m_name; }
4981 string getDesc (void) const { return "Function '" + m_funcs.func.getName() + "'"; }
4984 const GenFuncs<Sig> m_funcs;
4988 template <template <int> class GenF>
4989 class TemplateFuncCaseFactory : public FuncCaseFactory
4992 MovePtr<TestNode> createCase (const CaseContext& ctx) const
4994 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
4996 group->addChild(createFuncCase(ctx, "scalar", instance<GenF<1> >()));
4997 group->addChild(createFuncCase(ctx, "vec2", instance<GenF<2> >()));
4998 group->addChild(createFuncCase(ctx, "vec3", instance<GenF<3> >()));
4999 group->addChild(createFuncCase(ctx, "vec4", instance<GenF<4> >()));
5001 return MovePtr<TestNode>(group);
5004 const FuncBase& getFunc (void) const { return instance<GenF<1> >(); }
5007 template <template <int> class GenF>
5008 class SquareMatrixFuncCaseFactory : public FuncCaseFactory
5011 MovePtr<TestNode> createCase (const CaseContext& ctx) const
5013 TestCaseGroup* group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5015 group->addChild(createFuncCase(ctx, "mat2", instance<GenF<2> >()));
5017 // disabled until we get reasonable results
5018 group->addChild(createFuncCase(ctx, "mat3", instance<GenF<3> >()));
5019 group->addChild(createFuncCase(ctx, "mat4", instance<GenF<4> >()));
5022 return MovePtr<TestNode>(group);
5025 const FuncBase& getFunc (void) const { return instance<GenF<2> >(); }
5028 template <template <int, int> class GenF>
5029 class MatrixFuncCaseFactory : public FuncCaseFactory
5032 MovePtr<TestNode> createCase (const CaseContext& ctx) const
5034 TestCaseGroup* const group = new TestCaseGroup(ctx.testContext, ctx.name.c_str(), ctx.name.c_str());
5036 this->addCase<2, 2>(ctx, group);
5037 this->addCase<3, 2>(ctx, group);
5038 this->addCase<4, 2>(ctx, group);
5039 this->addCase<2, 3>(ctx, group);
5040 this->addCase<3, 3>(ctx, group);
5041 this->addCase<4, 3>(ctx, group);
5042 this->addCase<2, 4>(ctx, group);
5043 this->addCase<3, 4>(ctx, group);
5044 this->addCase<4, 4>(ctx, group);
5046 return MovePtr<TestNode>(group);
5049 const FuncBase& getFunc (void) const { return instance<GenF<2,2> >(); }
5052 template <int Rows, int Cols>
5053 void addCase (const CaseContext& ctx, TestCaseGroup* group) const
5055 const char* const name = dataTypeNameOf<Matrix<float, Rows, Cols> >();
5056 group->addChild(createFuncCase(ctx, name, instance<GenF<Rows, Cols> >()));
5060 template <typename Sig>
5061 class SimpleFuncCaseFactory : public CaseFactory
5064 SimpleFuncCaseFactory (const Func<Sig>& func) : m_func(func) {}
5066 MovePtr<TestNode> createCase (const CaseContext& ctx) const { return MovePtr<TestNode>(createFuncCase(ctx, ctx.name.c_str(), m_func)); }
5067 string getName (void) const { return de::toLower(m_func.getName()); }
5068 string getDesc (void) const { return "Function '" + getName() + "'"; }
5071 const Func<Sig>& m_func;
5074 template <typename F>
5075 SharedPtr<SimpleFuncCaseFactory<typename F::Sig> > createSimpleFuncCaseFactory (void)
5077 return SharedPtr<SimpleFuncCaseFactory<typename F::Sig> >(new SimpleFuncCaseFactory<typename F::Sig>(instance<F>()));
5083 virtual ~CaseFactories (void) {}
5084 virtual const std::vector<const CaseFactory*> getFactories (void) const = 0;
5087 class BuiltinFuncs : public CaseFactories
5090 const vector<const CaseFactory*> getFactories (void) const
5092 vector<const CaseFactory*> ret;
5094 for (size_t ndx = 0; ndx < m_factories.size(); ++ndx)
5095 ret.push_back(m_factories[ndx].get());
5100 void addFactory (SharedPtr<const CaseFactory> fact) { m_factories.push_back(fact); }
5103 vector<SharedPtr<const CaseFactory> > m_factories;
5106 template <typename F>
5107 void addScalarFactory(BuiltinFuncs& funcs, string name = "")
5110 name = instance<F>().getName();
5112 funcs.addFactory(SharedPtr<const CaseFactory>(new GenFuncCaseFactory<typename F::Sig>(makeVectorizedFuncs<F>(), name)));
5115 MovePtr<const CaseFactories> createComputeOnlyBuiltinCases (void)
5117 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5119 // Tests for ES3 builtins
5121 addScalarFactory<Add>(*funcs);
5122 addScalarFactory<Sub>(*funcs);
5123 addScalarFactory<Mul>(*funcs);
5124 addScalarFactory<Div>(*funcs);
5126 addScalarFactory<Radians>(*funcs);
5127 addScalarFactory<Degrees>(*funcs);
5128 addScalarFactory<Sin>(*funcs);
5129 addScalarFactory<Cos>(*funcs);
5130 addScalarFactory<Tan>(*funcs);
5131 addScalarFactory<ASin>(*funcs);
5132 addScalarFactory<ACos>(*funcs);
5133 addScalarFactory<ATan2>(*funcs, "atan2");
5134 addScalarFactory<ATan>(*funcs);
5135 addScalarFactory<Sinh>(*funcs);
5136 addScalarFactory<Cosh>(*funcs);
5137 addScalarFactory<Tanh>(*funcs);
5138 addScalarFactory<ASinh>(*funcs);
5139 addScalarFactory<ACosh>(*funcs);
5140 addScalarFactory<ATanh>(*funcs);
5142 addScalarFactory<Pow>(*funcs);
5143 addScalarFactory<Exp>(*funcs);
5144 addScalarFactory<Log>(*funcs);
5145 addScalarFactory<Exp2>(*funcs);
5146 addScalarFactory<Log2>(*funcs);
5147 addScalarFactory<Sqrt>(*funcs);
5148 addScalarFactory<InverseSqrt>(*funcs);
5150 addScalarFactory<Abs>(*funcs);
5151 addScalarFactory<Sign>(*funcs);
5152 addScalarFactory<Floor>(*funcs);
5153 addScalarFactory<Trunc>(*funcs);
5154 addScalarFactory<Round>(*funcs);
5155 addScalarFactory<RoundEven>(*funcs);
5156 addScalarFactory<Ceil>(*funcs);
5157 addScalarFactory<Fract>(*funcs);
5158 addScalarFactory<Mod>(*funcs);
5159 funcs->addFactory(createSimpleFuncCaseFactory<Modf>());
5160 addScalarFactory<Min>(*funcs);
5161 addScalarFactory<Max>(*funcs);
5162 addScalarFactory<Clamp>(*funcs);
5163 addScalarFactory<Mix>(*funcs);
5164 addScalarFactory<Step>(*funcs);
5165 addScalarFactory<SmoothStep>(*funcs);
5167 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length>()));
5168 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance>()));
5169 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot>()));
5170 funcs->addFactory(createSimpleFuncCaseFactory<Cross>());
5171 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize>()));
5172 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward>()));
5173 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect>()));
5174 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract>()));
5177 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<MatrixCompMult>()));
5178 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct>()));
5179 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose>()));
5180 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant>()));
5181 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse>()));
5183 return MovePtr<const CaseFactories>(funcs.release());
5186 MovePtr<const CaseFactories> createCompleteBuiltinCases (void)
5188 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5190 // Tests for ES31 builtins
5191 addScalarFactory<FrExp>(*funcs);
5192 addScalarFactory<LdExp>(*funcs);
5193 addScalarFactory<Fma>(*funcs);
5195 return MovePtr<const CaseFactories>(funcs.release());
5198 struct PrecisionTestContext
5200 PrecisionTestContext (TestContext& testCtx_,
5201 const FloatFormat& highp_,
5202 const FloatFormat& mediump_,
5203 const FloatFormat& lowp_,
5204 const vector<ShaderType>& shaderTypes_,
5206 : testCtx (testCtx_)
5207 , shaderTypes (shaderTypes_)
5208 , numRandoms (numRandoms_)
5210 formats[glu::PRECISION_HIGHP] = &highp_;
5211 formats[glu::PRECISION_MEDIUMP] = &mediump_;
5212 formats[glu::PRECISION_LOWP] = &lowp_;
5215 TestContext& testCtx;
5216 const FloatFormat* formats[glu::PRECISION_LAST];
5217 vector<ShaderType> shaderTypes;
5221 TestCaseGroup* createFuncGroup (const PrecisionTestContext& ctx, const CaseFactory& factory)
5223 TestCaseGroup* const group = new TestCaseGroup(ctx.testCtx, factory.getName().c_str(), factory.getDesc().c_str());
5225 for (int precNdx = glu::PRECISION_MEDIUMP; precNdx < glu::PRECISION_LAST; ++precNdx)
5227 const Precision precision = Precision(precNdx);
5228 const string precName (glu::getPrecisionName(precision));
5229 const FloatFormat& fmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats, precNdx);
5230 const FloatFormat& highpFmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats,
5231 glu::PRECISION_HIGHP);
5233 for (size_t shaderNdx = 0; shaderNdx < ctx.shaderTypes.size(); ++shaderNdx)
5235 const ShaderType shaderType = ctx.shaderTypes[shaderNdx];
5236 const string shaderName (glu::getShaderTypeName(shaderType));
5237 const string name = precName + "_" + shaderName;
5238 const CaseContext caseCtx (name, ctx.testCtx, fmt, highpFmt,
5239 precision, shaderType, ctx.numRandoms);
5241 group->addChild(factory.createCase(caseCtx).release());
5248 void addBuiltinPrecisionTests (TestContext& testCtx,
5249 const CaseFactories& cases,
5250 const vector<ShaderType>& shaderTypes,
5251 TestCaseGroup& dstGroup)
5253 const int userRandoms = testCtx.getCommandLine().getTestIterationCount();
5254 const int defRandoms = 16384;
5255 const int numRandoms = userRandoms > 0 ? userRandoms : defRandoms;
5256 const FloatFormat highp (-126, 127, 23, true,
5257 tcu::MAYBE, // subnormals
5258 tcu::YES, // infinities
5260 // \todo [2014-04-01 lauri] Check these once Khronos bug 11840 is resolved.
5261 const FloatFormat mediump (-13, 13, 9, false);
5262 // A fixed-point format is just a floating point format with a fixed
5263 // exponent and support for subnormals.
5264 const FloatFormat lowp (0, 0, 7, false, tcu::YES);
5265 const PrecisionTestContext ctx (testCtx, highp, mediump, lowp,
5266 shaderTypes, numRandoms);
5268 for (size_t ndx = 0; ndx < cases.getFactories().size(); ++ndx)
5269 dstGroup.addChild(createFuncGroup(ctx, *cases.getFactories()[ndx]));
5272 BuiltinPrecisionTests::BuiltinPrecisionTests (tcu::TestContext& testCtx)
5273 : tcu::TestCaseGroup(testCtx, "precision", "Builtin precision tests")
5277 BuiltinPrecisionTests::~BuiltinPrecisionTests (void)
5281 void BuiltinPrecisionTests::init (void)
5283 std::vector<glu::ShaderType> shaderTypes;
5284 de::MovePtr<const CaseFactories> computeOnlyCases = createComputeOnlyBuiltinCases();
5285 de::MovePtr<const CaseFactories> completeCases = createCompleteBuiltinCases();
5287 shaderTypes.push_back(glu::SHADERTYPE_COMPUTE);
5289 addBuiltinPrecisionTests(m_testCtx,
5294 shaderTypes.clear();
5295 shaderTypes.push_back(glu::SHADERTYPE_VERTEX);
5296 shaderTypes.push_back(glu::SHADERTYPE_FRAGMENT);
5297 shaderTypes.push_back(glu::SHADERTYPE_COMPUTE);
5299 addBuiltinPrecisionTests(m_testCtx,