1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) Module
3 * -----------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Precision and range tests for GLSL builtins and types.
22 *
23 *//*--------------------------------------------------------------------*/
24
25 #include "glsBuiltinPrecisionTests.hpp"
26
27 #include "deMath.h"
28 #include "deMemory.h"
29 #include "deDefs.hpp"
30 #include "deRandom.hpp"
31 #include "deSTLUtil.hpp"
32 #include "deStringUtil.hpp"
33 #include "deUniquePtr.hpp"
34 #include "deSharedPtr.hpp"
35 #include "deArrayUtil.hpp"
36
37 #include "tcuCommandLine.hpp"
38 #include "tcuFloatFormat.hpp"
39 #include "tcuInterval.hpp"
40 #include "tcuTestCase.hpp"
41 #include "tcuTestLog.hpp"
42 #include "tcuVector.hpp"
43 #include "tcuMatrix.hpp"
44 #include "tcuResultCollector.hpp"
45
46 #include "gluContextInfo.hpp"
47 #include "gluVarType.hpp"
48 #include "gluRenderContext.hpp"
49 #include "glwDefs.hpp"
50
51 #include "glsShaderExecUtil.hpp"
52
53 #include <cmath>
54 #include <string>
55 #include <sstream>
56 #include <iostream>
57 #include <map>
58 #include <utility>
59
60 // Uncomment this to get evaluation trace dumps to std::cerr
61 // #define GLS_ENABLE_TRACE
62
63 // set this to true to dump even passing results
64 #define GLS_LOG_ALL_RESULTS false
65
66 namespace deqp
67 {
68 namespace gls
69 {
70 namespace BuiltinPrecisionTests
71 {
72
73 using std::string;
74 using std::map;
75 using std::ostream;
76 using std::ostringstream;
77 using std::pair;
78 using std::vector;
79 using std::set;
80
81 using de::MovePtr;
82 using de::Random;
83 using de::SharedPtr;
84 using de::UniquePtr;
85 using tcu::Interval;
86 using tcu::FloatFormat;
87 using tcu::MessageBuilder;
88 using tcu::TestCase;
89 using tcu::TestLog;
90 using tcu::Vector;
91 using tcu::Matrix;
92 namespace matrix = tcu::matrix;
93 using glu::Precision;
94 using glu::RenderContext;
95 using glu::VarType;
96 using glu::DataType;
97 using glu::ShaderType;
98 using glu::ContextInfo;
99 using gls::ShaderExecUtil::Symbol;
100
101 typedef TestCase::IterateResult IterateResult;
102
103 using namespace glw;
104 using namespace tcu;
105
106 /*--------------------------------------------------------------------*//*!
107 * \brief Generic singleton creator.
108 *
109 * instance<T>() returns a reference to a unique default-constructed instance
110 * of T. This is mainly used for our GLSL function implementations: each
111 * function is implemented by an object, and each of the objects has a
112 * distinct class. It would be extremely toilsome to maintain a separate
113 * context object that contained individual instances of the function classes,
114 * so we have to resort to global singleton instances.
115 *
116 *//*--------------------------------------------------------------------*/
117 template <typename T>
instance(void)118 const T& instance (void)
119 {
120 static const T s_instance = T();
121 return s_instance;
122 }
123
124 /*--------------------------------------------------------------------*//*!
125 * \brief Dummy placeholder type for unused template parameters.
126 *
127 * In the precision tests we are dealing with functions of different arities.
128 * To minimize code duplication, we only define templates with the maximum
129 * number of arguments, currently four. If a function's arity is less than the
130 * maximum, Void us used as the type for unused arguments.
131 *
132 * Although Voids are not used at run-time, they still must be compilable, so
133 * they must support all operations that other types do.
134 *
135 *//*--------------------------------------------------------------------*/
136 struct Void
137 {
138 typedef Void Element;
139 enum
140 {
141 SIZE = 0,
142 };
143
144 template <typename T>
Voiddeqp::gls::BuiltinPrecisionTests::Void145 explicit Void (const T&) {}
Voiddeqp::gls::BuiltinPrecisionTests::Void146 Void (void) {}
operator doubledeqp::gls::BuiltinPrecisionTests::Void147 operator double (void) const { return TCU_NAN; }
148
149 // These are used to make Voids usable as containers in container-generic code.
operator []deqp::gls::BuiltinPrecisionTests::Void150 Void& operator[] (int) { return *this; }
operator []deqp::gls::BuiltinPrecisionTests::Void151 const Void& operator[] (int) const { return *this; }
152 };
153
operator <<(ostream & os,Void)154 ostream& operator<< (ostream& os, Void) { return os << "()"; }
155
156 //! Returns true for all other types except Void
isTypeValid(void)157 template <typename T> bool isTypeValid (void) { return true; }
isTypeValid(void)158 template <> bool isTypeValid<Void> (void) { return false; }
159
160 //! Utility function for getting the name of a data type.
161 //! This is used in vector and matrix constructors.
162 template <typename T>
dataTypeNameOf(void)163 const char* dataTypeNameOf (void)
164 {
165 return glu::getDataTypeName(glu::dataTypeOf<T>());
166 }
167
168 template <>
dataTypeNameOf(void)169 const char* dataTypeNameOf<Void> (void)
170 {
171 DE_ASSERT(!"Impossible");
172 return DE_NULL;
173 }
174
175 //! A hack to get Void support for VarType.
176 template <typename T>
getVarTypeOf(Precision prec=glu::PRECISION_LAST)177 VarType getVarTypeOf (Precision prec = glu::PRECISION_LAST)
178 {
179 return glu::varTypeOf<T>(prec);
180 }
181
182 template <>
getVarTypeOf(Precision)183 VarType getVarTypeOf<Void> (Precision)
184 {
185 DE_ASSERT(!"Impossible");
186 return VarType();
187 }
188
189 /*--------------------------------------------------------------------*//*!
190 * \brief Type traits for generalized interval types.
191 *
192 * We are trying to compute sets of acceptable values not only for
193 * float-valued expressions but also for compound values: vectors and
194 * matrices. We approximate a set of vectors as a vector of intervals and
195 * likewise for matrices.
196 *
197 * We now need generalized operations for each type and its interval
198 * approximation. These are given in the type Traits<T>.
199 *
200 * The type Traits<T>::IVal is the approximation of T: it is `Interval` for
201 * scalar types, and a vector or matrix of intervals for container types.
202 *
203 * To allow template inference to take place, there are function wrappers for
204 * the actual operations in Traits<T>. Hence we can just use:
205 *
206 * makeIVal(someFloat)
207 *
208 * instead of:
209 *
210 * Traits<float>::doMakeIVal(value)
211 *
212 *//*--------------------------------------------------------------------*/
213
214 template <typename T> struct Traits;
215
216 //! Create container from elementwise singleton values.
217 template <typename T>
makeIVal(const T & value)218 typename Traits<T>::IVal makeIVal (const T& value)
219 {
220 return Traits<T>::doMakeIVal(value);
221 }
222
223 //! Elementwise union of intervals.
224 template <typename T>
unionIVal(const typename Traits<T>::IVal & a,const typename Traits<T>::IVal & b)225 typename Traits<T>::IVal unionIVal (const typename Traits<T>::IVal& a,
226 const typename Traits<T>::IVal& b)
227 {
228 return Traits<T>::doUnion(a, b);
229 }
230
231 //! Returns true iff every element of `ival` contains the corresponding element of `value`.
232 template <typename T>
contains(const typename Traits<T>::IVal & ival,const T & value)233 bool contains (const typename Traits<T>::IVal& ival, const T& value)
234 {
235 return Traits<T>::doContains(ival, value);
236 }
237
238 //! Print out an interval with the precision of `fmt`.
239 template <typename T>
printIVal(const FloatFormat & fmt,const typename Traits<T>::IVal & ival,ostream & os)240 void printIVal (const FloatFormat& fmt, const typename Traits<T>::IVal& ival, ostream& os)
241 {
242 Traits<T>::doPrintIVal(fmt, ival, os);
243 }
244
245 template <typename T>
intervalToString(const FloatFormat & fmt,const typename Traits<T>::IVal & ival)246 string intervalToString (const FloatFormat& fmt, const typename Traits<T>::IVal& ival)
247 {
248 ostringstream oss;
249 printIVal<T>(fmt, ival, oss);
250 return oss.str();
251 }
252
253 //! Print out a value with the precision of `fmt`.
254 template <typename T>
printValue(const FloatFormat & fmt,const T & value,ostream & os)255 void printValue (const FloatFormat& fmt, const T& value, ostream& os)
256 {
257 Traits<T>::doPrintValue(fmt, value, os);
258 }
259
260 template <typename T>
valueToString(const FloatFormat & fmt,const T & val)261 string valueToString (const FloatFormat& fmt, const T& val)
262 {
263 ostringstream oss;
264 printValue(fmt, val, oss);
265 return oss.str();
266 }
267
268 //! Approximate `value` elementwise to the float precision defined in `fmt`.
269 //! The resulting interval might not be a singleton if rounding in both
270 //! directions is allowed.
271 template <typename T>
round(const FloatFormat & fmt,const T & value)272 typename Traits<T>::IVal round (const FloatFormat& fmt, const T& value)
273 {
274 return Traits<T>::doRound(fmt, value);
275 }
276
277 template <typename T>
convert(const FloatFormat & fmt,const typename Traits<T>::IVal & value)278 typename Traits<T>::IVal convert (const FloatFormat& fmt,
279 const typename Traits<T>::IVal& value)
280 {
281 return Traits<T>::doConvert(fmt, value);
282 }
283
284 //! Common traits for scalar types.
285 template <typename T>
286 struct ScalarTraits
287 {
288 typedef Interval IVal;
289
doMakeIValdeqp::gls::BuiltinPrecisionTests::ScalarTraits290 static Interval doMakeIVal (const T& value)
291 {
292 // Thankfully all scalar types have a well-defined conversion to `double`,
293 // hence Interval can represent their ranges without problems.
294 return Interval(double(value));
295 }
296
doUniondeqp::gls::BuiltinPrecisionTests::ScalarTraits297 static Interval doUnion (const Interval& a, const Interval& b)
298 {
299 return a | b;
300 }
301
doContainsdeqp::gls::BuiltinPrecisionTests::ScalarTraits302 static bool doContains (const Interval& a, T value)
303 {
304 return a.contains(double(value));
305 }
306
doConvertdeqp::gls::BuiltinPrecisionTests::ScalarTraits307 static Interval doConvert (const FloatFormat& fmt, const IVal& ival)
308 {
309 return fmt.convert(ival);
310 }
311
doRounddeqp::gls::BuiltinPrecisionTests::ScalarTraits312 static Interval doRound (const FloatFormat& fmt, T value)
313 {
314 return fmt.roundOut(double(value), false);
315 }
316 };
317
318 template<>
319 struct Traits<float> : ScalarTraits<float>
320 {
doPrintIValdeqp::gls::BuiltinPrecisionTests::Traits321 static void doPrintIVal (const FloatFormat& fmt,
322 const Interval& ival,
323 ostream& os)
324 {
325 os << fmt.intervalToHex(ival);
326 }
327
doPrintValuedeqp::gls::BuiltinPrecisionTests::Traits328 static void doPrintValue (const FloatFormat& fmt,
329 const float& value,
330 ostream& os)
331 {
332 os << fmt.floatToHex(value);
333 }
334 };
335
336 template<>
337 struct Traits<bool> : ScalarTraits<bool>
338 {
doPrintValuedeqp::gls::BuiltinPrecisionTests::Traits339 static void doPrintValue (const FloatFormat&,
340 const float& value,
341 ostream& os)
342 {
343 os << (value ? "true" : "false");
344 }
345
doPrintIValdeqp::gls::BuiltinPrecisionTests::Traits346 static void doPrintIVal (const FloatFormat&,
347 const Interval& ival,
348 ostream& os)
349 {
350 os << "{";
351 if (ival.contains(false))
352 os << "false";
353 if (ival.contains(false) && ival.contains(true))
354 os << ", ";
355 if (ival.contains(true))
356 os << "true";
357 os << "}";
358 }
359 };
360
361 template<>
362 struct Traits<int> : ScalarTraits<int>
363 {
doPrintValuedeqp::gls::BuiltinPrecisionTests::Traits364 static void doPrintValue (const FloatFormat&,
365 const int& value,
366 ostream& os)
367 {
368 os << value;
369 }
370
doPrintIValdeqp::gls::BuiltinPrecisionTests::Traits371 static void doPrintIVal (const FloatFormat&,
372 const Interval& ival,
373 ostream& os)
374 {
375 os << "[" << int(ival.lo()) << ", " << int(ival.hi()) << "]";
376 }
377 };
378
379 //! Common traits for containers, i.e. vectors and matrices.
380 //! T is the container type itself, I is the same type with interval elements.
381 template <typename T, typename I>
382 struct ContainerTraits
383 {
384 typedef typename T::Element Element;
385 typedef I IVal;
386
doMakeIValdeqp::gls::BuiltinPrecisionTests::ContainerTraits387 static IVal doMakeIVal (const T& value)
388 {
389 IVal ret;
390
391 for (int ndx = 0; ndx < T::SIZE; ++ndx)
392 ret[ndx] = makeIVal(value[ndx]);
393
394 return ret;
395 }
396
doUniondeqp::gls::BuiltinPrecisionTests::ContainerTraits397 static IVal doUnion (const IVal& a, const IVal& b)
398 {
399 IVal ret;
400
401 for (int ndx = 0; ndx < T::SIZE; ++ndx)
402 ret[ndx] = unionIVal<Element>(a[ndx], b[ndx]);
403
404 return ret;
405 }
406
doContainsdeqp::gls::BuiltinPrecisionTests::ContainerTraits407 static bool doContains (const IVal& ival, const T& value)
408 {
409 for (int ndx = 0; ndx < T::SIZE; ++ndx)
410 if (!contains(ival[ndx], value[ndx]))
411 return false;
412
413 return true;
414 }
415
doPrintIValdeqp::gls::BuiltinPrecisionTests::ContainerTraits416 static void doPrintIVal (const FloatFormat& fmt, const IVal ival, ostream& os)
417 {
418 os << "(";
419
420 for (int ndx = 0; ndx < T::SIZE; ++ndx)
421 {
422 if (ndx > 0)
423 os << ", ";
424
425 printIVal<Element>(fmt, ival[ndx], os);
426 }
427
428 os << ")";
429 }
430
doPrintValuedeqp::gls::BuiltinPrecisionTests::ContainerTraits431 static void doPrintValue (const FloatFormat& fmt, const T& value, ostream& os)
432 {
433 os << dataTypeNameOf<T>() << "(";
434
435 for (int ndx = 0; ndx < T::SIZE; ++ndx)
436 {
437 if (ndx > 0)
438 os << ", ";
439
440 printValue<Element>(fmt, value[ndx], os);
441 }
442
443 os << ")";
444 }
445
doConvertdeqp::gls::BuiltinPrecisionTests::ContainerTraits446 static IVal doConvert (const FloatFormat& fmt, const IVal& value)
447 {
448 IVal ret;
449
450 for (int ndx = 0; ndx < T::SIZE; ++ndx)
451 ret[ndx] = convert<Element>(fmt, value[ndx]);
452
453 return ret;
454 }
455
doRounddeqp::gls::BuiltinPrecisionTests::ContainerTraits456 static IVal doRound (const FloatFormat& fmt, T value)
457 {
458 IVal ret;
459
460 for (int ndx = 0; ndx < T::SIZE; ++ndx)
461 ret[ndx] = round(fmt, value[ndx]);
462
463 return ret;
464 }
465 };
466
467 template <typename T, int Size>
468 struct Traits<Vector<T, Size> > :
469 ContainerTraits<Vector<T, Size>, Vector<typename Traits<T>::IVal, Size> >
470 {
471 };
472
473 template <typename T, int Rows, int Cols>
474 struct Traits<Matrix<T, Rows, Cols> > :
475 ContainerTraits<Matrix<T, Rows, Cols>, Matrix<typename Traits<T>::IVal, Rows, Cols> >
476 {
477 };
478
479 //! Void traits. These are just dummies, but technically valid: a Void is a
480 //! unit type with a single possible value.
481 template<>
482 struct Traits<Void>
483 {
484 typedef Void IVal;
485
doMakeIValdeqp::gls::BuiltinPrecisionTests::Traits486 static Void doMakeIVal (const Void& value) { return value; }
doUniondeqp::gls::BuiltinPrecisionTests::Traits487 static Void doUnion (const Void&, const Void&) { return Void(); }
doContainsdeqp::gls::BuiltinPrecisionTests::Traits488 static bool doContains (const Void&, Void) { return true; }
doRounddeqp::gls::BuiltinPrecisionTests::Traits489 static Void doRound (const FloatFormat&, const Void& value) { return value; }
doConvertdeqp::gls::BuiltinPrecisionTests::Traits490 static Void doConvert (const FloatFormat&, const Void& value) { return value; }
491
doPrintValuedeqp::gls::BuiltinPrecisionTests::Traits492 static void doPrintValue (const FloatFormat&, const Void&, ostream& os)
493 {
494 os << "()";
495 }
496
doPrintIValdeqp::gls::BuiltinPrecisionTests::Traits497 static void doPrintIVal (const FloatFormat&, const Void&, ostream& os)
498 {
499 os << "()";
500 }
501 };
502
503 //! This is needed for container-generic operations.
504 //! We want a scalar type T to be its own "one-element vector".
505 template <typename T, int Size> struct ContainerOf { typedef Vector<T, Size> Container; };
506
507 template <typename T> struct ContainerOf<T, 1> { typedef T Container; };
508 template <int Size> struct ContainerOf<Void, Size> { typedef Void Container; };
509
510 // This is a kludge that is only needed to get the ExprP::operator[] syntactic sugar to work.
511 template <typename T> struct ElementOf { typedef typename T::Element Element; };
512 template <> struct ElementOf<float> { typedef void Element; };
513 template <> struct ElementOf<bool> { typedef void Element; };
514 template <> struct ElementOf<int> { typedef void Element; };
515
516 /*--------------------------------------------------------------------*//*!
517 *
518 * \name Abstract syntax for expressions and statements.
519 *
520 * We represent GLSL programs as syntax objects: an Expr<T> represents an
521 * expression whose GLSL type corresponds to the C++ type T, and a Statement
522 * represents a statement.
523 *
524 * To ease memory management, we use shared pointers to refer to expressions
525 * and statements. ExprP<T> is a shared pointer to an Expr<T>, and StatementP
526 * is a shared pointer to a Statement.
527 *
528 * \{
529 *
530 *//*--------------------------------------------------------------------*/
531
532 class ExprBase;
533 class ExpandContext;
534 class Statement;
535 class StatementP;
536 class FuncBase;
537 template <typename T> class ExprP;
538 template <typename T> class Variable;
539 template <typename T> class VariableP;
540 template <typename T> class DefaultSampling;
541
542 typedef set<const FuncBase*> FuncSet;
543
544 template <typename T>
545 VariableP<T> variable (const string& name);
546 StatementP compoundStatement (const vector<StatementP>& statements);
547
548 /*--------------------------------------------------------------------*//*!
549 * \brief A variable environment.
550 *
551 * An Environment object maintains the mapping between variables of the
552 * abstract syntax tree and their values.
553 *
554 * \todo [2014-03-28 lauri] At least run-time type safety.
555 *
556 *//*--------------------------------------------------------------------*/
557 class Environment
558 {
559 public:
560 template<typename T>
bind(const Variable<T> & variable,const typename Traits<T>::IVal & value)561 void bind (const Variable<T>& variable,
562 const typename Traits<T>::IVal& value)
563 {
564 deUint8* const data = new deUint8[sizeof(value)];
565
566 deMemcpy(data, &value, sizeof(value));
567 de::insert(m_map, variable.getName(), SharedPtr<deUint8>(data, de::ArrayDeleter<deUint8>()));
568 }
569
570 template<typename T>
lookup(const Variable<T> & variable) const571 typename Traits<T>::IVal& lookup (const Variable<T>& variable) const
572 {
573 deUint8* const data = de::lookup(m_map, variable.getName()).get();
574
575 return *reinterpret_cast<typename Traits<T>::IVal*>(data);
576 }
577
578 private:
579 map<string, SharedPtr<deUint8> > m_map;
580 };
581
582 /*--------------------------------------------------------------------*//*!
583 * \brief Evaluation context.
584 *
585 * The evaluation context contains everything that separates one execution of
586 * an expression from the next. Currently this means the desired floating
587 * point precision and the current variable environment.
588 *
589 *//*--------------------------------------------------------------------*/
590 struct EvalContext
591 {
EvalContextdeqp::gls::BuiltinPrecisionTests::EvalContext592 EvalContext (const FloatFormat& format_,
593 Precision floatPrecision_,
594 Environment& env_,
595 int callDepth_ = 0)
596 : format (format_)
597 , floatPrecision (floatPrecision_)
598 , env (env_)
599 , callDepth (callDepth_) {}
600
601 FloatFormat format;
602 Precision floatPrecision;
603 Environment& env;
604 int callDepth;
605 };
606
607 /*--------------------------------------------------------------------*//*!
608 * \brief Simple incremental counter.
609 *
610 * This is used to make sure that different ExpandContexts will not produce
611 * overlapping temporary names.
612 *
613 *//*--------------------------------------------------------------------*/
614 class Counter
615 {
616 public:
Counter(int count=0)617 Counter (int count = 0) : m_count(count) {}
operator ()(void)618 int operator() (void) { return m_count++; }
619
620 private:
621 int m_count;
622 };
623
624 class ExpandContext
625 {
626 public:
ExpandContext(Counter & symCounter)627 ExpandContext (Counter& symCounter) : m_symCounter(symCounter) {}
ExpandContext(const ExpandContext & parent)628 ExpandContext (const ExpandContext& parent)
629 : m_symCounter(parent.m_symCounter) {}
630
631 template<typename T>
genSym(const string & baseName)632 VariableP<T> genSym (const string& baseName)
633 {
634 return variable<T>(baseName + de::toString(m_symCounter()));
635 }
636
addStatement(const StatementP & stmt)637 void addStatement (const StatementP& stmt)
638 {
639 m_statements.push_back(stmt);
640 }
641
getStatements(void) const642 vector<StatementP> getStatements (void) const
643 {
644 return m_statements;
645 }
646 private:
647 Counter& m_symCounter;
648 vector<StatementP> m_statements;
649 };
650
651 /*--------------------------------------------------------------------*//*!
652 * \brief A statement or declaration.
653 *
654 * Statements have no values. Instead, they are executed for their side
655 * effects only: the execute() method should modify at least one variable in
656 * the environment.
657 *
658 * As a bit of a kludge, a Statement object can also represent a declaration:
659 * when it is evaluated, it can add a variable binding to the environment
660 * instead of modifying a current one.
661 *
662 *//*--------------------------------------------------------------------*/
663 class Statement
664 {
665 public:
~Statement(void)666 virtual ~Statement (void) { }
667 //! Execute the statement, modifying the environment of `ctx`
execute(EvalContext & ctx) const668 void execute (EvalContext& ctx) const { this->doExecute(ctx); }
print(ostream & os) const669 void print (ostream& os) const { this->doPrint(os); }
670 //! Add the functions used in this statement to `dst`.
getUsedFuncs(FuncSet & dst) const671 void getUsedFuncs (FuncSet& dst) const { this->doGetUsedFuncs(dst); }
672
673 protected:
674 virtual void doPrint (ostream& os) const = 0;
675 virtual void doExecute (EvalContext& ctx) const = 0;
676 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
677 };
678
operator <<(ostream & os,const Statement & stmt)679 ostream& operator<<(ostream& os, const Statement& stmt)
680 {
681 stmt.print(os);
682 return os;
683 }
684
685 /*--------------------------------------------------------------------*//*!
686 * \brief Smart pointer for statements (and declarations)
687 *
688 *//*--------------------------------------------------------------------*/
689 class StatementP : public SharedPtr<const Statement>
690 {
691 public:
692 typedef SharedPtr<const Statement> Super;
693
StatementP(void)694 StatementP (void) {}
StatementP(const Statement * ptr)695 explicit StatementP (const Statement* ptr) : Super(ptr) {}
StatementP(const Super & ptr)696 StatementP (const Super& ptr) : Super(ptr) {}
697 };
698
699 /*--------------------------------------------------------------------*//*!
700 * \brief
701 *
702 * A statement that modifies a variable or a declaration that binds a variable.
703 *
704 *//*--------------------------------------------------------------------*/
705 template <typename T>
706 class VariableStatement : public Statement
707 {
708 public:
VariableStatement(const VariableP<T> & variable,const ExprP<T> & value,bool isDeclaration)709 VariableStatement (const VariableP<T>& variable, const ExprP<T>& value,
710 bool isDeclaration)
711 : m_variable (variable)
712 , m_value (value)
713 , m_isDeclaration (isDeclaration) {}
714
715 protected:
doPrint(ostream & os) const716 void doPrint (ostream& os) const
717 {
718 if (m_isDeclaration)
719 os << glu::declare(getVarTypeOf<T>(), m_variable->getName());
720 else
721 os << m_variable->getName();
722
723 os << " = " << *m_value << ";\n";
724 }
725
doExecute(EvalContext & ctx) const726 void doExecute (EvalContext& ctx) const
727 {
728 if (m_isDeclaration)
729 ctx.env.bind(*m_variable, m_value->evaluate(ctx));
730 else
731 ctx.env.lookup(*m_variable) = m_value->evaluate(ctx);
732 }
733
doGetUsedFuncs(FuncSet & dst) const734 void doGetUsedFuncs (FuncSet& dst) const
735 {
736 m_value->getUsedFuncs(dst);
737 }
738
739 VariableP<T> m_variable;
740 ExprP<T> m_value;
741 bool m_isDeclaration;
742 };
743
744 template <typename T>
variableStatement(const VariableP<T> & variable,const ExprP<T> & value,bool isDeclaration)745 StatementP variableStatement (const VariableP<T>& variable,
746 const ExprP<T>& value,
747 bool isDeclaration)
748 {
749 return StatementP(new VariableStatement<T>(variable, value, isDeclaration));
750 }
751
752 template <typename T>
variableDeclaration(const VariableP<T> & variable,const ExprP<T> & definiens)753 StatementP variableDeclaration (const VariableP<T>& variable, const ExprP<T>& definiens)
754 {
755 return variableStatement(variable, definiens, true);
756 }
757
758 template <typename T>
variableAssignment(const VariableP<T> & variable,const ExprP<T> & value)759 StatementP variableAssignment (const VariableP<T>& variable, const ExprP<T>& value)
760 {
761 return variableStatement(variable, value, false);
762 }
763
764 /*--------------------------------------------------------------------*//*!
765 * \brief A compound statement, i.e. a block.
766 *
767 * A compound statement is executed by executing its constituent statements in
768 * sequence.
769 *
770 *//*--------------------------------------------------------------------*/
771 class CompoundStatement : public Statement
772 {
773 public:
CompoundStatement(const vector<StatementP> & statements)774 CompoundStatement (const vector<StatementP>& statements)
775 : m_statements (statements) {}
776
777 protected:
doPrint(ostream & os) const778 void doPrint (ostream& os) const
779 {
780 os << "{\n";
781
782 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
783 os << *m_statements[ndx];
784
785 os << "}\n";
786 }
787
doExecute(EvalContext & ctx) const788 void doExecute (EvalContext& ctx) const
789 {
790 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
791 m_statements[ndx]->execute(ctx);
792 }
793
doGetUsedFuncs(FuncSet & dst) const794 void doGetUsedFuncs (FuncSet& dst) const
795 {
796 for (size_t ndx = 0; ndx < m_statements.size(); ++ndx)
797 m_statements[ndx]->getUsedFuncs(dst);
798 }
799
800 vector<StatementP> m_statements;
801 };
802
compoundStatement(const vector<StatementP> & statements)803 StatementP compoundStatement(const vector<StatementP>& statements)
804 {
805 return StatementP(new CompoundStatement(statements));
806 }
807
808 //! Common base class for all expressions regardless of their type.
809 class ExprBase
810 {
811 public:
~ExprBase(void)812 virtual ~ExprBase (void) {}
printExpr(ostream & os) const813 void printExpr (ostream& os) const { this->doPrintExpr(os); }
814
815 //! Output the functions that this expression refers to
getUsedFuncs(FuncSet & dst) const816 void getUsedFuncs (FuncSet& dst) const
817 {
818 this->doGetUsedFuncs(dst);
819 }
820
821 protected:
doPrintExpr(ostream &) const822 virtual void doPrintExpr (ostream&) const {}
doGetUsedFuncs(FuncSet &) const823 virtual void doGetUsedFuncs (FuncSet&) const {}
824 };
825
826 //! Type-specific operations for an expression representing type T.
827 template <typename T>
828 class Expr : public ExprBase
829 {
830 public:
831 typedef T Val;
832 typedef typename Traits<T>::IVal IVal;
833
834 IVal evaluate (const EvalContext& ctx) const;
835
836 protected:
837 virtual IVal doEvaluate (const EvalContext& ctx) const = 0;
838 };
839
840 //! Evaluate an expression with the given context, optionally tracing the calls to stderr.
841 template <typename T>
evaluate(const EvalContext & ctx) const842 typename Traits<T>::IVal Expr<T>::evaluate (const EvalContext& ctx) const
843 {
844 #ifdef GLS_ENABLE_TRACE
845 static const FloatFormat highpFmt (-126, 127, 23, true,
846 tcu::MAYBE,
847 tcu::YES,
848 tcu::MAYBE);
849 EvalContext newCtx (ctx.format, ctx.floatPrecision,
850 ctx.env, ctx.callDepth + 1);
851 const IVal ret = this->doEvaluate(newCtx);
852
853 if (isTypeValid<T>())
854 {
855 std::cerr << string(ctx.callDepth, ' ');
856 this->printExpr(std::cerr);
857 std::cerr << " -> " << intervalToString<T>(highpFmt, ret) << std::endl;
858 }
859 return ret;
860 #else
861 return this->doEvaluate(ctx);
862 #endif
863 }
864
865 template <typename T>
866 class ExprPBase : public SharedPtr<const Expr<T> >
867 {
868 public:
869 };
870
operator <<(ostream & os,const ExprBase & expr)871 ostream& operator<< (ostream& os, const ExprBase& expr)
872 {
873 expr.printExpr(os);
874 return os;
875 }
876
877 /*--------------------------------------------------------------------*//*!
878 * \brief Shared pointer to an expression of a container type.
879 *
880 * Container types (i.e. vectors and matrices) support the subscription
881 * operator. This class provides a bit of syntactic sugar to allow us to use
882 * the C++ subscription operator to create a subscription expression.
883 *//*--------------------------------------------------------------------*/
884 template <typename T>
885 class ContainerExprPBase : public ExprPBase<T>
886 {
887 public:
888 ExprP<typename T::Element> operator[] (int i) const;
889 };
890
891 template <typename T>
892 class ExprP : public ExprPBase<T> {};
893
894 // We treat Voids as containers since the dummy parameters in generalized
895 // vector functions are represented as Voids.
896 template <>
897 class ExprP<Void> : public ContainerExprPBase<Void> {};
898
899 template <typename T, int Size>
900 class ExprP<Vector<T, Size> > : public ContainerExprPBase<Vector<T, Size> > {};
901
902 template <typename T, int Rows, int Cols>
903 class ExprP<Matrix<T, Rows, Cols> > : public ContainerExprPBase<Matrix<T, Rows, Cols> > {};
904
exprP(void)905 template <typename T> ExprP<T> exprP (void)
906 {
907 return ExprP<T>();
908 }
909
910 template <typename T>
exprP(const SharedPtr<const Expr<T>> & ptr)911 ExprP<T> exprP (const SharedPtr<const Expr<T> >& ptr)
912 {
913 ExprP<T> ret;
914 static_cast<SharedPtr<const Expr<T> >&>(ret) = ptr;
915 return ret;
916 }
917
918 template <typename T>
exprP(const Expr<T> * ptr)919 ExprP<T> exprP (const Expr<T>* ptr)
920 {
921 return exprP(SharedPtr<const Expr<T> >(ptr));
922 }
923
924 /*--------------------------------------------------------------------*//*!
925 * \brief A shared pointer to a variable expression.
926 *
927 * This is just a narrowing of ExprP for the operations that require a variable
928 * instead of an arbitrary expression.
929 *
930 *//*--------------------------------------------------------------------*/
931 template <typename T>
932 class VariableP : public SharedPtr<const Variable<T> >
933 {
934 public:
935 typedef SharedPtr<const Variable<T> > Super;
VariableP(const Variable<T> * ptr)936 explicit VariableP (const Variable<T>* ptr) : Super(ptr) {}
VariableP(void)937 VariableP (void) {}
VariableP(const Super & ptr)938 VariableP (const Super& ptr) : Super(ptr) {}
939
operator ExprP<T>(void) const940 operator ExprP<T> (void) const { return exprP(SharedPtr<const Expr<T> >(*this)); }
941 };
942
943 /*--------------------------------------------------------------------*//*!
944 * \name Syntactic sugar operators for expressions.
945 *
946 * @{
947 *
948 * These operators allow the use of C++ syntax to construct GLSL expressions
949 * containing operators: e.g. "a+b" creates an addition expression with
950 * operands a and b, and so on.
951 *
952 *//*--------------------------------------------------------------------*/
953 ExprP<float> operator-(const ExprP<float>& arg0);
954 ExprP<float> operator+(const ExprP<float>& arg0,
955 const ExprP<float>& arg1);
956 ExprP<float> operator-(const ExprP<float>& arg0,
957 const ExprP<float>& arg1);
958 ExprP<float> operator*(const ExprP<float>& arg0,
959 const ExprP<float>& arg1);
960 ExprP<float> operator/(const ExprP<float>& arg0,
961 const ExprP<float>& arg1);
962 template<int Size>
963 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0);
964 template<int Size>
965 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
966 const ExprP<float>& arg1);
967 template<int Size>
968 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
969 const ExprP<Vector<float, Size> >& arg1);
970 template<int Size>
971 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
972 const ExprP<Vector<float, Size> >& arg1);
973 template<int Left, int Mid, int Right>
974 ExprP<Matrix<float, Left, Right> > operator* (const ExprP<Matrix<float, Left, Mid> >& left,
975 const ExprP<Matrix<float, Mid, Right> >& right);
976 template<int Rows, int Cols>
977 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
978 const ExprP<Matrix<float, Rows, Cols> >& right);
979 template<int Rows, int Cols>
980 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
981 const ExprP<Vector<float, Rows> >& right);
982 template<int Rows, int Cols>
983 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
984 const ExprP<float>& right);
985 template<int Rows, int Cols>
986 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
987 const ExprP<Matrix<float, Rows, Cols> >& right);
988 template<int Rows, int Cols>
989 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat);
990
991 //! @}
992
993 /*--------------------------------------------------------------------*//*!
994 * \brief Variable expression.
995 *
996 * A variable is evaluated by looking up its range of possible values from an
997 * environment.
998 *//*--------------------------------------------------------------------*/
999 template <typename T>
1000 class Variable : public Expr<T>
1001 {
1002 public:
1003 typedef typename Expr<T>::IVal IVal;
1004
Variable(const string & name)1005 Variable (const string& name) : m_name (name) {}
getName(void) const1006 string getName (void) const { return m_name; }
1007
1008 protected:
doPrintExpr(ostream & os) const1009 void doPrintExpr (ostream& os) const { os << m_name; }
doEvaluate(const EvalContext & ctx) const1010 IVal doEvaluate (const EvalContext& ctx) const
1011 {
1012 return ctx.env.lookup<T>(*this);
1013 }
1014
1015 private:
1016 string m_name;
1017 };
1018
1019 template <typename T>
variable(const string & name)1020 VariableP<T> variable (const string& name)
1021 {
1022 return VariableP<T>(new Variable<T>(name));
1023 }
1024
1025 template <typename T>
bindExpression(const string & name,ExpandContext & ctx,const ExprP<T> & expr)1026 VariableP<T> bindExpression (const string& name, ExpandContext& ctx, const ExprP<T>& expr)
1027 {
1028 VariableP<T> var = ctx.genSym<T>(name);
1029 ctx.addStatement(variableDeclaration(var, expr));
1030 return var;
1031 }
1032
1033 /*--------------------------------------------------------------------*//*!
1034 * \brief Constant expression.
1035 *
1036 * A constant is evaluated by rounding it to a set of possible values allowed
1037 * by the current floating point precision.
1038 *//*--------------------------------------------------------------------*/
1039 template <typename T>
1040 class Constant : public Expr<T>
1041 {
1042 public:
1043 typedef typename Expr<T>::IVal IVal;
1044
Constant(const T & value)1045 Constant (const T& value) : m_value(value) {}
1046
1047 protected:
doPrintExpr(ostream & os) const1048 void doPrintExpr (ostream& os) const { os << m_value; }
doEvaluate(const EvalContext &) const1049 IVal doEvaluate (const EvalContext&) const { return makeIVal(m_value); }
1050
1051 private:
1052 T m_value;
1053 };
1054
1055 template <typename T>
constant(const T & value)1056 ExprP<T> constant (const T& value)
1057 {
1058 return exprP(new Constant<T>(value));
1059 }
1060
1061 //! Return a reference to a singleton void constant.
voidP(void)1062 const ExprP<Void>& voidP (void)
1063 {
1064 static const ExprP<Void> singleton = constant(Void());
1065
1066 return singleton;
1067 }
1068
1069 /*--------------------------------------------------------------------*//*!
1070 * \brief Four-element tuple.
1071 *
1072 * This is used for various things where we need one thing for each possible
1073 * function parameter. Currently the maximum supported number of parameters is
1074 * four.
1075 *//*--------------------------------------------------------------------*/
1076 template <typename T0 = Void, typename T1 = Void, typename T2 = Void, typename T3 = Void>
1077 struct Tuple4
1078 {
Tuple4deqp::gls::BuiltinPrecisionTests::Tuple41079 explicit Tuple4 (const T0& e0 = T0(),
1080 const T1& e1 = T1(),
1081 const T2& e2 = T2(),
1082 const T3& e3 = T3())
1083 : a (e0)
1084 , b (e1)
1085 , c (e2)
1086 , d (e3)
1087 {
1088 }
1089
1090 T0 a;
1091 T1 b;
1092 T2 c;
1093 T3 d;
1094 };
1095
1096 /*--------------------------------------------------------------------*//*!
1097 * \brief Function signature.
1098 *
1099 * This is a purely compile-time structure used to bundle all types in a
1100 * function signature together. This makes passing the signature around in
1101 * templates easier, since we only need to take and pass a single Sig instead
1102 * of a bunch of parameter types and a return type.
1103 *
1104 *//*--------------------------------------------------------------------*/
1105 template <typename R,
1106 typename P0 = Void, typename P1 = Void,
1107 typename P2 = Void, typename P3 = Void>
1108 struct Signature
1109 {
1110 typedef R Ret;
1111 typedef P0 Arg0;
1112 typedef P1 Arg1;
1113 typedef P2 Arg2;
1114 typedef P3 Arg3;
1115 typedef typename Traits<Ret>::IVal IRet;
1116 typedef typename Traits<Arg0>::IVal IArg0;
1117 typedef typename Traits<Arg1>::IVal IArg1;
1118 typedef typename Traits<Arg2>::IVal IArg2;
1119 typedef typename Traits<Arg3>::IVal IArg3;
1120
1121 typedef Tuple4< const Arg0&, const Arg1&, const Arg2&, const Arg3&> Args;
1122 typedef Tuple4< const IArg0&, const IArg1&, const IArg2&, const IArg3&> IArgs;
1123 typedef Tuple4< ExprP<Arg0>, ExprP<Arg1>, ExprP<Arg2>, ExprP<Arg3> > ArgExprs;
1124 };
1125
1126 typedef vector<const ExprBase*> BaseArgExprs;
1127
1128 /*--------------------------------------------------------------------*//*!
1129 * \brief Type-independent operations for function objects.
1130 *
1131 *//*--------------------------------------------------------------------*/
1132 class FuncBase
1133 {
1134 public:
~FuncBase(void)1135 virtual ~FuncBase (void) {}
1136 virtual string getName (void) const = 0;
1137 //! Name of extension that this function requires, or empty.
getRequiredExtension(void) const1138 virtual string getRequiredExtension (void) const { return ""; }
1139 virtual void print (ostream&,
1140 const BaseArgExprs&) const = 0;
1141 //! Index of output parameter, or -1 if none of the parameters is output.
getOutParamIndex(void) const1142 virtual int getOutParamIndex (void) const { return -1; }
1143
printDefinition(ostream & os) const1144 void printDefinition (ostream& os) const
1145 {
1146 doPrintDefinition(os);
1147 }
1148
getUsedFuncs(FuncSet & dst) const1149 void getUsedFuncs (FuncSet& dst) const
1150 {
1151 this->doGetUsedFuncs(dst);
1152 }
1153
1154 protected:
1155 virtual void doPrintDefinition (ostream& os) const = 0;
1156 virtual void doGetUsedFuncs (FuncSet& dst) const = 0;
1157 };
1158
1159 typedef Tuple4<string, string, string, string> ParamNames;
1160
1161 /*--------------------------------------------------------------------*//*!
1162 * \brief Function objects.
1163 *
1164 * Each Func object represents a GLSL function. It can be applied to interval
1165 * arguments, and it returns the an interval that is a conservative
1166 * approximation of the image of the GLSL function over the argument
1167 * intervals. That is, it is given a set of possible arguments and it returns
1168 * the set of possible values.
1169 *
1170 *//*--------------------------------------------------------------------*/
1171 template <typename Sig_>
1172 class Func : public FuncBase
1173 {
1174 public:
1175 typedef Sig_ Sig;
1176 typedef typename Sig::Ret Ret;
1177 typedef typename Sig::Arg0 Arg0;
1178 typedef typename Sig::Arg1 Arg1;
1179 typedef typename Sig::Arg2 Arg2;
1180 typedef typename Sig::Arg3 Arg3;
1181 typedef typename Sig::IRet IRet;
1182 typedef typename Sig::IArg0 IArg0;
1183 typedef typename Sig::IArg1 IArg1;
1184 typedef typename Sig::IArg2 IArg2;
1185 typedef typename Sig::IArg3 IArg3;
1186 typedef typename Sig::Args Args;
1187 typedef typename Sig::IArgs IArgs;
1188 typedef typename Sig::ArgExprs ArgExprs;
1189
print(ostream & os,const BaseArgExprs & args) const1190 void print (ostream& os,
1191 const BaseArgExprs& args) const
1192 {
1193 this->doPrint(os, args);
1194 }
1195
apply(const EvalContext & ctx,const IArg0 & arg0=IArg0 (),const IArg1 & arg1=IArg1 (),const IArg2 & arg2=IArg2 (),const IArg3 & arg3=IArg3 ()) const1196 IRet apply (const EvalContext& ctx,
1197 const IArg0& arg0 = IArg0(),
1198 const IArg1& arg1 = IArg1(),
1199 const IArg2& arg2 = IArg2(),
1200 const IArg3& arg3 = IArg3()) const
1201 {
1202 return this->applyArgs(ctx, IArgs(arg0, arg1, arg2, arg3));
1203 }
applyArgs(const EvalContext & ctx,const IArgs & args) const1204 IRet applyArgs (const EvalContext& ctx,
1205 const IArgs& args) const
1206 {
1207 return this->doApply(ctx, args);
1208 }
1209 ExprP<Ret> operator() (const ExprP<Arg0>& arg0 = voidP(),
1210 const ExprP<Arg1>& arg1 = voidP(),
1211 const ExprP<Arg2>& arg2 = voidP(),
1212 const ExprP<Arg3>& arg3 = voidP()) const;
1213
getParamNames(void) const1214 const ParamNames& getParamNames (void) const
1215 {
1216 return this->doGetParamNames();
1217 }
1218
1219 protected:
1220 virtual IRet doApply (const EvalContext&,
1221 const IArgs&) const = 0;
doPrint(ostream & os,const BaseArgExprs & args) const1222 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1223 {
1224 os << getName() << "(";
1225
1226 if (isTypeValid<Arg0>())
1227 os << *args[0];
1228
1229 if (isTypeValid<Arg1>())
1230 os << ", " << *args[1];
1231
1232 if (isTypeValid<Arg2>())
1233 os << ", " << *args[2];
1234
1235 if (isTypeValid<Arg3>())
1236 os << ", " << *args[3];
1237
1238 os << ")";
1239 }
1240
doGetParamNames(void) const1241 virtual const ParamNames& doGetParamNames (void) const
1242 {
1243 static ParamNames names ("a", "b", "c", "d");
1244 return names;
1245 }
1246 };
1247
1248 template <typename Sig>
1249 class Apply : public Expr<typename Sig::Ret>
1250 {
1251 public:
1252 typedef typename Sig::Ret Ret;
1253 typedef typename Sig::Arg0 Arg0;
1254 typedef typename Sig::Arg1 Arg1;
1255 typedef typename Sig::Arg2 Arg2;
1256 typedef typename Sig::Arg3 Arg3;
1257 typedef typename Expr<Ret>::Val Val;
1258 typedef typename Expr<Ret>::IVal IVal;
1259 typedef Func<Sig> ApplyFunc;
1260 typedef typename ApplyFunc::ArgExprs ArgExprs;
1261
Apply(const ApplyFunc & func,const ExprP<Arg0> & arg0=voidP (),const ExprP<Arg1> & arg1=voidP (),const ExprP<Arg2> & arg2=voidP (),const ExprP<Arg3> & arg3=voidP ())1262 Apply (const ApplyFunc& func,
1263 const ExprP<Arg0>& arg0 = voidP(),
1264 const ExprP<Arg1>& arg1 = voidP(),
1265 const ExprP<Arg2>& arg2 = voidP(),
1266 const ExprP<Arg3>& arg3 = voidP())
1267 : m_func (func),
1268 m_args (arg0, arg1, arg2, arg3) {}
1269
Apply(const ApplyFunc & func,const ArgExprs & args)1270 Apply (const ApplyFunc& func,
1271 const ArgExprs& args)
1272 : m_func (func),
1273 m_args (args) {}
1274 protected:
doPrintExpr(ostream & os) const1275 void doPrintExpr (ostream& os) const
1276 {
1277 BaseArgExprs args;
1278 args.push_back(m_args.a.get());
1279 args.push_back(m_args.b.get());
1280 args.push_back(m_args.c.get());
1281 args.push_back(m_args.d.get());
1282 m_func.print(os, args);
1283 }
1284
doEvaluate(const EvalContext & ctx) const1285 IVal doEvaluate (const EvalContext& ctx) const
1286 {
1287 return m_func.apply(ctx,
1288 m_args.a->evaluate(ctx), m_args.b->evaluate(ctx),
1289 m_args.c->evaluate(ctx), m_args.d->evaluate(ctx));
1290 }
1291
doGetUsedFuncs(FuncSet & dst) const1292 void doGetUsedFuncs (FuncSet& dst) const
1293 {
1294 m_func.getUsedFuncs(dst);
1295 m_args.a->getUsedFuncs(dst);
1296 m_args.b->getUsedFuncs(dst);
1297 m_args.c->getUsedFuncs(dst);
1298 m_args.d->getUsedFuncs(dst);
1299 }
1300
1301 const ApplyFunc& m_func;
1302 ArgExprs m_args;
1303 };
1304
1305 template<typename T>
1306 class Alternatives : public Func<Signature<T, T, T> >
1307 {
1308 public:
1309 typedef typename Alternatives::Sig Sig;
1310
1311 protected:
1312 typedef typename Alternatives::IRet IRet;
1313 typedef typename Alternatives::IArgs IArgs;
1314
getName(void) const1315 virtual string getName (void) const { return "alternatives"; }
doPrintDefinition(std::ostream &) const1316 virtual void doPrintDefinition (std::ostream&) const {}
doGetUsedFuncs(FuncSet &) const1317 void doGetUsedFuncs (FuncSet&) const {}
1318
doApply(const EvalContext &,const IArgs & args) const1319 virtual IRet doApply (const EvalContext&, const IArgs& args) const
1320 {
1321 return unionIVal<T>(args.a, args.b);
1322 }
1323
doPrint(ostream & os,const BaseArgExprs & args) const1324 virtual void doPrint (ostream& os, const BaseArgExprs& args) const
1325 {
1326 os << "{" << *args[0] << " | " << *args[1] << "}";
1327 }
1328 };
1329
1330 template <typename Sig>
createApply(const Func<Sig> & func,const typename Func<Sig>::ArgExprs & args)1331 ExprP<typename Sig::Ret> createApply (const Func<Sig>& func,
1332 const typename Func<Sig>::ArgExprs& args)
1333 {
1334 return exprP(new Apply<Sig>(func, args));
1335 }
1336
1337 template <typename Sig>
createApply(const Func<Sig> & func,const ExprP<typename Sig::Arg0> & arg0=voidP (),const ExprP<typename Sig::Arg1> & arg1=voidP (),const ExprP<typename Sig::Arg2> & arg2=voidP (),const ExprP<typename Sig::Arg3> & arg3=voidP ())1338 ExprP<typename Sig::Ret> createApply (
1339 const Func<Sig>& func,
1340 const ExprP<typename Sig::Arg0>& arg0 = voidP(),
1341 const ExprP<typename Sig::Arg1>& arg1 = voidP(),
1342 const ExprP<typename Sig::Arg2>& arg2 = voidP(),
1343 const ExprP<typename Sig::Arg3>& arg3 = voidP())
1344 {
1345 return exprP(new Apply<Sig>(func, arg0, arg1, arg2, arg3));
1346 }
1347
1348 template <typename Sig>
operator ()(const ExprP<typename Sig::Arg0> & arg0,const ExprP<typename Sig::Arg1> & arg1,const ExprP<typename Sig::Arg2> & arg2,const ExprP<typename Sig::Arg3> & arg3) const1349 ExprP<typename Sig::Ret> Func<Sig>::operator() (const ExprP<typename Sig::Arg0>& arg0,
1350 const ExprP<typename Sig::Arg1>& arg1,
1351 const ExprP<typename Sig::Arg2>& arg2,
1352 const ExprP<typename Sig::Arg3>& arg3) const
1353 {
1354 return createApply(*this, arg0, arg1, arg2, arg3);
1355 }
1356
1357 template <typename F>
app(const ExprP<typename F::Arg0> & arg0=voidP (),const ExprP<typename F::Arg1> & arg1=voidP (),const ExprP<typename F::Arg2> & arg2=voidP (),const ExprP<typename F::Arg3> & arg3=voidP ())1358 ExprP<typename F::Ret> app (const ExprP<typename F::Arg0>& arg0 = voidP(),
1359 const ExprP<typename F::Arg1>& arg1 = voidP(),
1360 const ExprP<typename F::Arg2>& arg2 = voidP(),
1361 const ExprP<typename F::Arg3>& arg3 = voidP())
1362 {
1363 return createApply(instance<F>(), arg0, arg1, arg2, arg3);
1364 }
1365
1366 template <typename F>
call(const EvalContext & ctx,const typename F::IArg0 & arg0=Void (),const typename F::IArg1 & arg1=Void (),const typename F::IArg2 & arg2=Void (),const typename F::IArg3 & arg3=Void ())1367 typename F::IRet call (const EvalContext& ctx,
1368 const typename F::IArg0& arg0 = Void(),
1369 const typename F::IArg1& arg1 = Void(),
1370 const typename F::IArg2& arg2 = Void(),
1371 const typename F::IArg3& arg3 = Void())
1372 {
1373 return instance<F>().apply(ctx, arg0, arg1, arg2, arg3);
1374 }
1375
1376 template <typename T>
alternatives(const ExprP<T> & arg0,const ExprP<T> & arg1)1377 ExprP<T> alternatives (const ExprP<T>& arg0,
1378 const ExprP<T>& arg1)
1379 {
1380 return createApply<typename Alternatives<T>::Sig>(instance<Alternatives<T> >(), arg0, arg1);
1381 }
1382
1383 template <typename Sig>
1384 class ApplyVar : public Apply<Sig>
1385 {
1386 public:
1387 typedef typename Sig::Ret Ret;
1388 typedef typename Sig::Arg0 Arg0;
1389 typedef typename Sig::Arg1 Arg1;
1390 typedef typename Sig::Arg2 Arg2;
1391 typedef typename Sig::Arg3 Arg3;
1392 typedef typename Expr<Ret>::Val Val;
1393 typedef typename Expr<Ret>::IVal IVal;
1394 typedef Func<Sig> ApplyFunc;
1395 typedef typename ApplyFunc::ArgExprs ArgExprs;
1396
ApplyVar(const ApplyFunc & func,const VariableP<Arg0> & arg0,const VariableP<Arg1> & arg1,const VariableP<Arg2> & arg2,const VariableP<Arg3> & arg3)1397 ApplyVar (const ApplyFunc& func,
1398 const VariableP<Arg0>& arg0,
1399 const VariableP<Arg1>& arg1,
1400 const VariableP<Arg2>& arg2,
1401 const VariableP<Arg3>& arg3)
1402 : Apply<Sig> (func, arg0, arg1, arg2, arg3) {}
1403 protected:
doEvaluate(const EvalContext & ctx) const1404 IVal doEvaluate (const EvalContext& ctx) const
1405 {
1406 const Variable<Arg0>& var0 = static_cast<const Variable<Arg0>&>(*this->m_args.a);
1407 const Variable<Arg1>& var1 = static_cast<const Variable<Arg1>&>(*this->m_args.b);
1408 const Variable<Arg2>& var2 = static_cast<const Variable<Arg2>&>(*this->m_args.c);
1409 const Variable<Arg3>& var3 = static_cast<const Variable<Arg3>&>(*this->m_args.d);
1410 return this->m_func.apply(ctx,
1411 ctx.env.lookup(var0), ctx.env.lookup(var1),
1412 ctx.env.lookup(var2), ctx.env.lookup(var3));
1413 }
1414 };
1415
1416 template <typename Sig>
applyVar(const Func<Sig> & func,const VariableP<typename Sig::Arg0> & arg0,const VariableP<typename Sig::Arg1> & arg1,const VariableP<typename Sig::Arg2> & arg2,const VariableP<typename Sig::Arg3> & arg3)1417 ExprP<typename Sig::Ret> applyVar (const Func<Sig>& func,
1418 const VariableP<typename Sig::Arg0>& arg0,
1419 const VariableP<typename Sig::Arg1>& arg1,
1420 const VariableP<typename Sig::Arg2>& arg2,
1421 const VariableP<typename Sig::Arg3>& arg3)
1422 {
1423 return exprP(new ApplyVar<Sig>(func, arg0, arg1, arg2, arg3));
1424 }
1425
1426 template <typename Sig_>
1427 class DerivedFunc : public Func<Sig_>
1428 {
1429 public:
1430 typedef typename DerivedFunc::ArgExprs ArgExprs;
1431 typedef typename DerivedFunc::IRet IRet;
1432 typedef typename DerivedFunc::IArgs IArgs;
1433 typedef typename DerivedFunc::Ret Ret;
1434 typedef typename DerivedFunc::Arg0 Arg0;
1435 typedef typename DerivedFunc::Arg1 Arg1;
1436 typedef typename DerivedFunc::Arg2 Arg2;
1437 typedef typename DerivedFunc::Arg3 Arg3;
1438 typedef typename DerivedFunc::IArg0 IArg0;
1439 typedef typename DerivedFunc::IArg1 IArg1;
1440 typedef typename DerivedFunc::IArg2 IArg2;
1441 typedef typename DerivedFunc::IArg3 IArg3;
1442
1443 protected:
doPrintDefinition(ostream & os) const1444 void doPrintDefinition (ostream& os) const
1445 {
1446 const ParamNames& paramNames = this->getParamNames();
1447
1448 initialize();
1449
1450 os << dataTypeNameOf<Ret>() << " " << this->getName()
1451 << "(";
1452 if (isTypeValid<Arg0>())
1453 os << dataTypeNameOf<Arg0>() << " " << paramNames.a;
1454 if (isTypeValid<Arg1>())
1455 os << ", " << dataTypeNameOf<Arg1>() << " " << paramNames.b;
1456 if (isTypeValid<Arg2>())
1457 os << ", " << dataTypeNameOf<Arg2>() << " " << paramNames.c;
1458 if (isTypeValid<Arg3>())
1459 os << ", " << dataTypeNameOf<Arg3>() << " " << paramNames.d;
1460 os << ")\n{\n";
1461
1462 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1463 os << *m_body[ndx];
1464 os << "return " << *m_ret << ";\n";
1465 os << "}\n";
1466 }
1467
doApply(const EvalContext & ctx,const IArgs & args) const1468 IRet doApply (const EvalContext& ctx,
1469 const IArgs& args) const
1470 {
1471 Environment funEnv;
1472 IArgs& mutArgs = const_cast<IArgs&>(args);
1473 IRet ret;
1474
1475 initialize();
1476
1477 funEnv.bind(*m_var0, args.a);
1478 funEnv.bind(*m_var1, args.b);
1479 funEnv.bind(*m_var2, args.c);
1480 funEnv.bind(*m_var3, args.d);
1481
1482 {
1483 EvalContext funCtx(ctx.format, ctx.floatPrecision, funEnv, ctx.callDepth);
1484
1485 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1486 m_body[ndx]->execute(funCtx);
1487
1488 ret = m_ret->evaluate(funCtx);
1489 }
1490
1491 // \todo [lauri] Store references instead of values in environment
1492 const_cast<IArg0&>(mutArgs.a) = funEnv.lookup(*m_var0);
1493 const_cast<IArg1&>(mutArgs.b) = funEnv.lookup(*m_var1);
1494 const_cast<IArg2&>(mutArgs.c) = funEnv.lookup(*m_var2);
1495 const_cast<IArg3&>(mutArgs.d) = funEnv.lookup(*m_var3);
1496
1497 return ret;
1498 }
1499
doGetUsedFuncs(FuncSet & dst) const1500 void doGetUsedFuncs (FuncSet& dst) const
1501 {
1502 initialize();
1503 if (dst.insert(this).second)
1504 {
1505 for (size_t ndx = 0; ndx < m_body.size(); ++ndx)
1506 m_body[ndx]->getUsedFuncs(dst);
1507 m_ret->getUsedFuncs(dst);
1508 }
1509 }
1510
1511 virtual ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args_) const = 0;
1512
1513 // These are transparently initialized when first needed. They cannot be
1514 // initialized in the constructor because they depend on the doExpand
1515 // method of the subclass.
1516
1517 mutable VariableP<Arg0> m_var0;
1518 mutable VariableP<Arg1> m_var1;
1519 mutable VariableP<Arg2> m_var2;
1520 mutable VariableP<Arg3> m_var3;
1521 mutable vector<StatementP> m_body;
1522 mutable ExprP<Ret> m_ret;
1523
1524 private:
1525
initialize(void) const1526 void initialize (void) const
1527 {
1528 if (!m_ret)
1529 {
1530 const ParamNames& paramNames = this->getParamNames();
1531 Counter symCounter;
1532 ExpandContext ctx (symCounter);
1533 ArgExprs args;
1534
1535 args.a = m_var0 = variable<Arg0>(paramNames.a);
1536 args.b = m_var1 = variable<Arg1>(paramNames.b);
1537 args.c = m_var2 = variable<Arg2>(paramNames.c);
1538 args.d = m_var3 = variable<Arg3>(paramNames.d);
1539
1540 m_ret = this->doExpand(ctx, args);
1541 m_body = ctx.getStatements();
1542 }
1543 }
1544 };
1545
1546 template <typename Sig>
1547 class PrimitiveFunc : public Func<Sig>
1548 {
1549 public:
1550 typedef typename PrimitiveFunc::Ret Ret;
1551 typedef typename PrimitiveFunc::ArgExprs ArgExprs;
1552
1553 protected:
doPrintDefinition(ostream &) const1554 void doPrintDefinition (ostream&) const {}
doGetUsedFuncs(FuncSet &) const1555 void doGetUsedFuncs (FuncSet&) const {}
1556 };
1557
1558 template <typename T>
1559 class Cond : public PrimitiveFunc<Signature<T, bool, T, T> >
1560 {
1561 public:
1562 typedef typename Cond::IArgs IArgs;
1563 typedef typename Cond::IRet IRet;
1564
getName(void) const1565 string getName (void) const
1566 {
1567 return "_cond";
1568 }
1569
1570 protected:
1571
doPrint(ostream & os,const BaseArgExprs & args) const1572 void doPrint (ostream& os, const BaseArgExprs& args) const
1573 {
1574 os << "(" << *args[0] << " ? " << *args[1] << " : " << *args[2] << ")";
1575 }
1576
doApply(const EvalContext &,const IArgs & iargs) const1577 IRet doApply (const EvalContext&, const IArgs& iargs)const
1578 {
1579 IRet ret;
1580
1581 if (iargs.a.contains(true))
1582 ret = unionIVal<T>(ret, iargs.b);
1583
1584 if (iargs.a.contains(false))
1585 ret = unionIVal<T>(ret, iargs.c);
1586
1587 return ret;
1588 }
1589 };
1590
1591 template <typename T>
1592 class CompareOperator : public PrimitiveFunc<Signature<bool, T, T> >
1593 {
1594 public:
1595 typedef typename CompareOperator::IArgs IArgs;
1596 typedef typename CompareOperator::IArg0 IArg0;
1597 typedef typename CompareOperator::IArg1 IArg1;
1598 typedef typename CompareOperator::IRet IRet;
1599
1600 protected:
doPrint(ostream & os,const BaseArgExprs & args) const1601 void doPrint (ostream& os, const BaseArgExprs& args) const
1602 {
1603 os << "(" << *args[0] << getSymbol() << *args[1] << ")";
1604 }
1605
doApply(const EvalContext &,const IArgs & iargs) const1606 Interval doApply (const EvalContext&, const IArgs& iargs) const
1607 {
1608 const IArg0& arg0 = iargs.a;
1609 const IArg1& arg1 = iargs.b;
1610 IRet ret;
1611
1612 if (canSucceed(arg0, arg1))
1613 ret |= true;
1614 if (canFail(arg0, arg1))
1615 ret |= false;
1616
1617 return ret;
1618 }
1619
1620 virtual string getSymbol (void) const = 0;
1621 virtual bool canSucceed (const IArg0&, const IArg1&) const = 0;
1622 virtual bool canFail (const IArg0&, const IArg1&) const = 0;
1623 };
1624
1625 template <typename T>
1626 class LessThan : public CompareOperator<T>
1627 {
1628 public:
getName(void) const1629 string getName (void) const { return "lessThan"; }
1630
1631 protected:
getSymbol(void) const1632 string getSymbol (void) const { return "<"; }
1633
canSucceed(const Interval & a,const Interval & b) const1634 bool canSucceed (const Interval& a, const Interval& b) const
1635 {
1636 return (a.lo() < b.hi());
1637 }
1638
canFail(const Interval & a,const Interval & b) const1639 bool canFail (const Interval& a, const Interval& b) const
1640 {
1641 return !(a.hi() < b.lo());
1642 }
1643 };
1644
1645 template <typename T>
operator <(const ExprP<T> & a,const ExprP<T> & b)1646 ExprP<bool> operator< (const ExprP<T>& a, const ExprP<T>& b)
1647 {
1648 return app<LessThan<T> >(a, b);
1649 }
1650
1651 template <typename T>
cond(const ExprP<bool> & test,const ExprP<T> & consequent,const ExprP<T> & alternative)1652 ExprP<T> cond (const ExprP<bool>& test,
1653 const ExprP<T>& consequent,
1654 const ExprP<T>& alternative)
1655 {
1656 return app<Cond<T> >(test, consequent, alternative);
1657 }
1658
1659 /*--------------------------------------------------------------------*//*!
1660 *
1661 * @}
1662 *
1663 *//*--------------------------------------------------------------------*/
1664
1665 class FloatFunc1 : public PrimitiveFunc<Signature<float, float> >
1666 {
1667 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const1668 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1669 {
1670 return this->applyMonotone(ctx, iargs.a);
1671 }
1672
applyMonotone(const EvalContext & ctx,const Interval & iarg0) const1673 Interval applyMonotone (const EvalContext& ctx, const Interval& iarg0) const
1674 {
1675 Interval ret;
1676
1677 TCU_INTERVAL_APPLY_MONOTONE1(ret, arg0, iarg0, val,
1678 TCU_SET_INTERVAL(val, point,
1679 point = this->applyPoint(ctx, arg0)));
1680
1681 ret |= innerExtrema(ctx, iarg0);
1682 ret &= (this->getCodomain() | TCU_NAN);
1683
1684 return ctx.format.convert(ret);
1685 }
1686
innerExtrema(const EvalContext &,const Interval &) const1687 virtual Interval innerExtrema (const EvalContext&, const Interval&) const
1688 {
1689 return Interval(); // empty interval, i.e. no extrema
1690 }
1691
applyPoint(const EvalContext & ctx,double arg0) const1692 virtual Interval applyPoint (const EvalContext& ctx, double arg0) const
1693 {
1694 const double exact = this->applyExact(arg0);
1695 const double prec = this->precision(ctx, exact, arg0);
1696
1697 return exact + Interval(-prec, prec);
1698 }
1699
applyExact(double) const1700 virtual double applyExact (double) const
1701 {
1702 TCU_THROW(InternalError, "Cannot apply");
1703 }
1704
getCodomain(void) const1705 virtual Interval getCodomain (void) const
1706 {
1707 return Interval::unbounded(true);
1708 }
1709
1710 virtual double precision (const EvalContext& ctx, double, double) const = 0;
1711 };
1712
1713 class CFloatFunc1 : public FloatFunc1
1714 {
1715 public:
CFloatFunc1(const string & name,DoubleFunc1 & func)1716 CFloatFunc1 (const string& name, DoubleFunc1& func)
1717 : m_name(name), m_func(func) {}
1718
getName(void) const1719 string getName (void) const { return m_name; }
1720
1721 protected:
applyExact(double x) const1722 double applyExact (double x) const { return m_func(x); }
1723
1724 const string m_name;
1725 DoubleFunc1& m_func;
1726 };
1727
1728 class FloatFunc2 : public PrimitiveFunc<Signature<float, float, float> >
1729 {
1730 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const1731 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1732 {
1733 return this->applyMonotone(ctx, iargs.a, iargs.b);
1734 }
1735
applyMonotone(const EvalContext & ctx,const Interval & xi,const Interval & yi) const1736 Interval applyMonotone (const EvalContext& ctx,
1737 const Interval& xi,
1738 const Interval& yi) const
1739 {
1740 Interval reti;
1741
1742 TCU_INTERVAL_APPLY_MONOTONE2(reti, x, xi, y, yi, ret,
1743 TCU_SET_INTERVAL(ret, point,
1744 point = this->applyPoint(ctx, x, y)));
1745 reti |= innerExtrema(ctx, xi, yi);
1746 reti &= (this->getCodomain() | TCU_NAN);
1747
1748 return ctx.format.convert(reti);
1749 }
1750
innerExtrema(const EvalContext &,const Interval &,const Interval &) const1751 virtual Interval innerExtrema (const EvalContext&,
1752 const Interval&,
1753 const Interval&) const
1754 {
1755 return Interval(); // empty interval, i.e. no extrema
1756 }
1757
applyPoint(const EvalContext & ctx,double x,double y) const1758 virtual Interval applyPoint (const EvalContext& ctx,
1759 double x,
1760 double y) const
1761 {
1762 const double exact = this->applyExact(x, y);
1763 const double prec = this->precision(ctx, exact, x, y);
1764
1765 return exact + Interval(-prec, prec);
1766 }
1767
applyExact(double,double) const1768 virtual double applyExact (double, double) const
1769 {
1770 TCU_THROW(InternalError, "Cannot apply");
1771 }
1772
getCodomain(void) const1773 virtual Interval getCodomain (void) const
1774 {
1775 return Interval::unbounded(true);
1776 }
1777
1778 virtual double precision (const EvalContext& ctx,
1779 double ret,
1780 double x,
1781 double y) const = 0;
1782 };
1783
1784 class CFloatFunc2 : public FloatFunc2
1785 {
1786 public:
CFloatFunc2(const string & name,DoubleFunc2 & func)1787 CFloatFunc2 (const string& name,
1788 DoubleFunc2& func)
1789 : m_name(name)
1790 , m_func(func)
1791 {
1792 }
1793
getName(void) const1794 string getName (void) const { return m_name; }
1795
1796 protected:
applyExact(double x,double y) const1797 double applyExact (double x, double y) const { return m_func(x, y); }
1798
1799 const string m_name;
1800 DoubleFunc2& m_func;
1801 };
1802
1803 class InfixOperator : public FloatFunc2
1804 {
1805 protected:
1806 virtual string getSymbol (void) const = 0;
1807
doPrint(ostream & os,const BaseArgExprs & args) const1808 void doPrint (ostream& os, const BaseArgExprs& args) const
1809 {
1810 os << "(" << *args[0] << " " << getSymbol() << " " << *args[1] << ")";
1811 }
1812
applyPoint(const EvalContext & ctx,double x,double y) const1813 Interval applyPoint (const EvalContext& ctx,
1814 double x,
1815 double y) const
1816 {
1817 const double exact = this->applyExact(x, y);
1818
1819 // Allow either representable number on both sides of the exact value,
1820 // but require exactly representable values to be preserved.
1821 return ctx.format.roundOut(exact, !deIsInf(x) && !deIsInf(y));
1822 }
1823
precision(const EvalContext &,double,double,double) const1824 double precision (const EvalContext&, double, double, double) const
1825 {
1826 return 0.0;
1827 }
1828 };
1829
1830 class FloatFunc3 : public PrimitiveFunc<Signature<float, float, float, float> >
1831 {
1832 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const1833 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1834 {
1835 return this->applyMonotone(ctx, iargs.a, iargs.b, iargs.c);
1836 }
1837
applyMonotone(const EvalContext & ctx,const Interval & xi,const Interval & yi,const Interval & zi) const1838 Interval applyMonotone (const EvalContext& ctx,
1839 const Interval& xi,
1840 const Interval& yi,
1841 const Interval& zi) const
1842 {
1843 Interval reti;
1844 TCU_INTERVAL_APPLY_MONOTONE3(reti, x, xi, y, yi, z, zi, ret,
1845 TCU_SET_INTERVAL(ret, point,
1846 point = this->applyPoint(ctx, x, y, z)));
1847 return ctx.format.convert(reti);
1848 }
1849
applyPoint(const EvalContext & ctx,double x,double y,double z) const1850 virtual Interval applyPoint (const EvalContext& ctx,
1851 double x,
1852 double y,
1853 double z) const
1854 {
1855 const double exact = this->applyExact(x, y, z);
1856 const double prec = this->precision(ctx, exact, x, y, z);
1857 return exact + Interval(-prec, prec);
1858 }
1859
applyExact(double,double,double) const1860 virtual double applyExact (double, double, double) const
1861 {
1862 TCU_THROW(InternalError, "Cannot apply");
1863 }
1864
1865 virtual double precision (const EvalContext& ctx,
1866 double result,
1867 double x,
1868 double y,
1869 double z) const = 0;
1870 };
1871
1872 // We define syntactic sugar functions for expression constructors. Since
1873 // these have the same names as ordinary mathematical operations (sin, log
1874 // etc.), it's better to give them a dedicated namespace.
1875 namespace Functions
1876 {
1877
1878 using namespace tcu;
1879
1880 class Add : public InfixOperator
1881 {
1882 public:
getName(void) const1883 string getName (void) const { return "add"; }
getSymbol(void) const1884 string getSymbol (void) const { return "+"; }
1885
doApply(const EvalContext & ctx,const IArgs & iargs) const1886 Interval doApply (const EvalContext& ctx,
1887 const IArgs& iargs) const
1888 {
1889 // Fast-path for common case
1890 if (iargs.a.isOrdinary() && iargs.b.isOrdinary())
1891 {
1892 Interval ret;
1893 TCU_SET_INTERVAL_BOUNDS(ret, sum,
1894 sum = iargs.a.lo() + iargs.b.lo(),
1895 sum = iargs.a.hi() + iargs.b.hi());
1896 return ctx.format.convert(ctx.format.roundOut(ret, true));
1897 }
1898 return this->applyMonotone(ctx, iargs.a, iargs.b);
1899 }
1900
1901 protected:
applyExact(double x,double y) const1902 double applyExact (double x, double y) const { return x + y; }
1903 };
1904
1905 class Mul : public InfixOperator
1906 {
1907 public:
getName(void) const1908 string getName (void) const { return "mul"; }
getSymbol(void) const1909 string getSymbol (void) const { return "*"; }
1910
doApply(const EvalContext & ctx,const IArgs & iargs) const1911 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1912 {
1913 Interval a = iargs.a;
1914 Interval b = iargs.b;
1915
1916 // Fast-path for common case
1917 if (a.isOrdinary() && b.isOrdinary())
1918 {
1919 Interval ret;
1920 if (a.hi() < 0)
1921 {
1922 a = -a;
1923 b = -b;
1924 }
1925 if (a.lo() >= 0 && b.lo() >= 0)
1926 {
1927 TCU_SET_INTERVAL_BOUNDS(ret, prod,
1928 prod = iargs.a.lo() * iargs.b.lo(),
1929 prod = iargs.a.hi() * iargs.b.hi());
1930 return ctx.format.convert(ctx.format.roundOut(ret, true));
1931 }
1932 if (a.lo() >= 0 && b.hi() <= 0)
1933 {
1934 TCU_SET_INTERVAL_BOUNDS(ret, prod,
1935 prod = iargs.a.hi() * iargs.b.lo(),
1936 prod = iargs.a.lo() * iargs.b.hi());
1937 return ctx.format.convert(ctx.format.roundOut(ret, true));
1938 }
1939 }
1940 return this->applyMonotone(ctx, iargs.a, iargs.b);
1941 }
1942
1943 protected:
applyExact(double x,double y) const1944 double applyExact (double x, double y) const { return x * y; }
1945
innerExtrema(const EvalContext &,const Interval & xi,const Interval & yi) const1946 Interval innerExtrema(const EvalContext&, const Interval& xi, const Interval& yi) const
1947 {
1948 if (((xi.contains(-TCU_INFINITY) || xi.contains(TCU_INFINITY)) && yi.contains(0.0)) ||
1949 ((yi.contains(-TCU_INFINITY) || yi.contains(TCU_INFINITY)) && xi.contains(0.0)))
1950 return Interval(TCU_NAN);
1951
1952 return Interval();
1953 }
1954 };
1955
1956 class Sub : public InfixOperator
1957 {
1958 public:
getName(void) const1959 string getName (void) const { return "sub"; }
getSymbol(void) const1960 string getSymbol (void) const { return "-"; }
1961
doApply(const EvalContext & ctx,const IArgs & iargs) const1962 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
1963 {
1964 // Fast-path for common case
1965 if (iargs.a.isOrdinary() && iargs.b.isOrdinary())
1966 {
1967 Interval ret;
1968
1969 TCU_SET_INTERVAL_BOUNDS(ret, diff,
1970 diff = iargs.a.lo() - iargs.b.hi(),
1971 diff = iargs.a.hi() - iargs.b.lo());
1972 return ctx.format.convert(ctx.format.roundOut(ret, true));
1973
1974 }
1975 else
1976 {
1977 return this->applyMonotone(ctx, iargs.a, iargs.b);
1978 }
1979 }
1980
1981 protected:
applyExact(double x,double y) const1982 double applyExact (double x, double y) const { return x - y; }
1983 };
1984
1985 class Negate : public FloatFunc1
1986 {
1987 public:
getName(void) const1988 string getName (void) const { return "_negate"; }
doPrint(ostream & os,const BaseArgExprs & args) const1989 void doPrint (ostream& os, const BaseArgExprs& args) const { os << "-" << *args[0]; }
1990
1991 protected:
precision(const EvalContext &,double,double) const1992 double precision (const EvalContext&, double, double) const { return 0.0; }
applyExact(double x) const1993 double applyExact (double x) const { return -x; }
1994 };
1995
1996 class Div : public InfixOperator
1997 {
1998 public:
getName(void) const1999 string getName (void) const { return "div"; }
2000
2001 protected:
getSymbol(void) const2002 string getSymbol (void) const { return "/"; }
2003
innerExtrema(const EvalContext &,const Interval & nom,const Interval & den) const2004 Interval innerExtrema (const EvalContext&,
2005 const Interval& nom,
2006 const Interval& den) const
2007 {
2008 Interval ret;
2009
2010 if (den.contains(0.0))
2011 {
2012 if (nom.contains(0.0))
2013 ret |= TCU_NAN;
2014
2015 if (nom.lo() < 0.0 || nom.hi() > 0.0)
2016 ret |= Interval::unbounded();
2017 }
2018
2019 return ret;
2020 }
2021
applyExact(double x,double y) const2022 double applyExact (double x, double y) const { return x / y; }
2023
applyPoint(const EvalContext & ctx,double x,double y) const2024 Interval applyPoint (const EvalContext& ctx, double x, double y) const
2025 {
2026 Interval ret = FloatFunc2::applyPoint(ctx, x, y);
2027
2028 if (!deIsInf(x) && !deIsInf(y) && y != 0.0)
2029 {
2030 const Interval dst = ctx.format.convert(ret);
2031 if (dst.contains(-TCU_INFINITY)) ret |= -ctx.format.getMaxValue();
2032 if (dst.contains(+TCU_INFINITY)) ret |= +ctx.format.getMaxValue();
2033 }
2034
2035 return ret;
2036 }
2037
precision(const EvalContext & ctx,double ret,double,double den) const2038 double precision (const EvalContext& ctx, double ret, double, double den) const
2039 {
2040 const FloatFormat& fmt = ctx.format;
2041
2042 // \todo [2014-03-05 lauri] Check that the limits in GLSL 3.10 are actually correct.
2043 // For now, we assume that division's precision is 2.5 ULP when the value is within
2044 // [2^MINEXP, 2^MAXEXP-1]
2045
2046 if (den == 0.0)
2047 return 0.0; // Result must be exactly inf
2048 else if (de::inBounds(deAbs(den),
2049 deLdExp(1.0, fmt.getMinExp()),
2050 deLdExp(1.0, fmt.getMaxExp() - 1)))
2051 return fmt.ulp(ret, 2.5);
2052 else
2053 return TCU_INFINITY; // Can be any number, but must be a number.
2054 }
2055 };
2056
2057 class InverseSqrt : public FloatFunc1
2058 {
2059 public:
getName(void) const2060 string getName (void) const { return "inversesqrt"; }
2061
2062 protected:
applyExact(double x) const2063 double applyExact (double x) const { return 1.0 / deSqrt(x); }
2064
precision(const EvalContext & ctx,double ret,double x) const2065 double precision (const EvalContext& ctx, double ret, double x) const
2066 {
2067 return x <= 0 ? TCU_NAN : ctx.format.ulp(ret, 2.0);
2068 }
2069
getCodomain(void) const2070 Interval getCodomain (void) const
2071 {
2072 return Interval(0.0, TCU_INFINITY);
2073 }
2074 };
2075
2076 class ExpFunc : public CFloatFunc1
2077 {
2078 public:
ExpFunc(const string & name,DoubleFunc1 & func)2079 ExpFunc (const string& name, DoubleFunc1& func)
2080 : CFloatFunc1(name, func) {}
2081 protected:
precision(const EvalContext & ctx,double ret,double x) const2082 double precision (const EvalContext& ctx, double ret, double x) const
2083 {
2084 switch (ctx.floatPrecision)
2085 {
2086 case glu::PRECISION_HIGHP:
2087 return ctx.format.ulp(ret, 3.0 + 2.0 * deAbs(x));
2088 case glu::PRECISION_MEDIUMP:
2089 return ctx.format.ulp(ret, 2.0 + 2.0 * deAbs(x));
2090 case glu::PRECISION_LOWP:
2091 return ctx.format.ulp(ret, 2.0);
2092 default:
2093 DE_ASSERT(!"Impossible");
2094 }
2095 return 0;
2096 }
2097
getCodomain(void) const2098 Interval getCodomain (void) const
2099 {
2100 return Interval(0.0, TCU_INFINITY);
2101 }
2102 };
2103
Exp2(void)2104 class Exp2 : public ExpFunc { public: Exp2 (void) : ExpFunc("exp2", deExp2) {} };
Exp(void)2105 class Exp : public ExpFunc { public: Exp (void) : ExpFunc("exp", deExp) {} };
2106
exp2(const ExprP<float> & x)2107 ExprP<float> exp2 (const ExprP<float>& x) { return app<Exp2>(x); }
exp(const ExprP<float> & x)2108 ExprP<float> exp (const ExprP<float>& x) { return app<Exp>(x); }
2109
2110 class LogFunc : public CFloatFunc1
2111 {
2112 public:
LogFunc(const string & name,DoubleFunc1 & func)2113 LogFunc (const string& name, DoubleFunc1& func)
2114 : CFloatFunc1(name, func) {}
2115
2116 protected:
precision(const EvalContext & ctx,double ret,double x) const2117 double precision (const EvalContext& ctx, double ret, double x) const
2118 {
2119 if (x <= 0)
2120 return TCU_NAN;
2121
2122 switch (ctx.floatPrecision)
2123 {
2124 case glu::PRECISION_HIGHP:
2125 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -21) : ctx.format.ulp(ret, 3.0);
2126 case glu::PRECISION_MEDIUMP:
2127 return (0.5 <= x && x <= 2.0) ? deLdExp(1.0, -7) : ctx.format.ulp(ret, 2.0);
2128 case glu::PRECISION_LOWP:
2129 return ctx.format.ulp(ret, 2.0);
2130 default:
2131 DE_ASSERT(!"Impossible");
2132 }
2133
2134 return 0;
2135 }
2136 };
2137
Log2(void)2138 class Log2 : public LogFunc { public: Log2 (void) : LogFunc("log2", deLog2) {} };
Log(void)2139 class Log : public LogFunc { public: Log (void) : LogFunc("log", deLog) {} };
2140
log2(const ExprP<float> & x)2141 ExprP<float> log2 (const ExprP<float>& x) { return app<Log2>(x); }
log(const ExprP<float> & x)2142 ExprP<float> log (const ExprP<float>& x) { return app<Log>(x); }
2143
2144 #define DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0) \
2145 ExprP<TRET> NAME (const ExprP<T0>& arg0) { return app<CLASS>(arg0); }
2146
2147 #define DEFINE_DERIVED1(CLASS, TRET, NAME, T0, ARG0, EXPANSION) \
2148 class CLASS : public DerivedFunc<Signature<TRET, T0> > \
2149 { \
2150 public: \
2151 string getName (void) const { return #NAME; } \
2152 \
2153 protected: \
2154 ExprP<TRET> doExpand (ExpandContext&, \
2155 const CLASS::ArgExprs& args_) const \
2156 { \
2157 const ExprP<float>& ARG0 = args_.a; \
2158 return EXPANSION; \
2159 } \
2160 }; \
2161 DEFINE_CONSTRUCTOR1(CLASS, TRET, NAME, T0)
2162
2163 #define DEFINE_DERIVED_FLOAT1(CLASS, NAME, ARG0, EXPANSION) \
2164 DEFINE_DERIVED1(CLASS, float, NAME, float, ARG0, EXPANSION)
2165
2166 #define DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1) \
2167 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1) \
2168 { \
2169 return app<CLASS>(arg0, arg1); \
2170 }
2171
2172 #define DEFINE_DERIVED2(CLASS, TRET, NAME, T0, Arg0, T1, Arg1, EXPANSION) \
2173 class CLASS : public DerivedFunc<Signature<TRET, T0, T1> > \
2174 { \
2175 public: \
2176 string getName (void) const { return #NAME; } \
2177 \
2178 protected: \
2179 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2180 { \
2181 const ExprP<T0>& Arg0 = args_.a; \
2182 const ExprP<T1>& Arg1 = args_.b; \
2183 return EXPANSION; \
2184 } \
2185 }; \
2186 DEFINE_CONSTRUCTOR2(CLASS, TRET, NAME, T0, T1)
2187
2188 #define DEFINE_DERIVED_FLOAT2(CLASS, NAME, Arg0, Arg1, EXPANSION) \
2189 DEFINE_DERIVED2(CLASS, float, NAME, float, Arg0, float, Arg1, EXPANSION)
2190
2191 #define DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2) \
2192 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, const ExprP<T2>& arg2) \
2193 { \
2194 return app<CLASS>(arg0, arg1, arg2); \
2195 }
2196
2197 #define DEFINE_DERIVED3(CLASS, TRET, NAME, T0, ARG0, T1, ARG1, T2, ARG2, EXPANSION) \
2198 class CLASS : public DerivedFunc<Signature<TRET, T0, T1, T2> > \
2199 { \
2200 public: \
2201 string getName (void) const { return #NAME; } \
2202 \
2203 protected: \
2204 ExprP<TRET> doExpand (ExpandContext&, const ArgExprs& args_) const \
2205 { \
2206 const ExprP<T0>& ARG0 = args_.a; \
2207 const ExprP<T1>& ARG1 = args_.b; \
2208 const ExprP<T2>& ARG2 = args_.c; \
2209 return EXPANSION; \
2210 } \
2211 }; \
2212 DEFINE_CONSTRUCTOR3(CLASS, TRET, NAME, T0, T1, T2)
2213
2214 #define DEFINE_DERIVED_FLOAT3(CLASS, NAME, ARG0, ARG1, ARG2, EXPANSION) \
2215 DEFINE_DERIVED3(CLASS, float, NAME, float, ARG0, float, ARG1, float, ARG2, EXPANSION)
2216
2217 #define DEFINE_CONSTRUCTOR4(CLASS, TRET, NAME, T0, T1, T2, T3) \
2218 ExprP<TRET> NAME (const ExprP<T0>& arg0, const ExprP<T1>& arg1, \
2219 const ExprP<T2>& arg2, const ExprP<T3>& arg3) \
2220 { \
2221 return app<CLASS>(arg0, arg1, arg2, arg3); \
2222 }
2223
2224 DEFINE_DERIVED_FLOAT1(Sqrt, sqrt, x, constant(1.0f) / app<InverseSqrt>(x));
2225 DEFINE_DERIVED_FLOAT2(Pow, pow, x, y, exp2(y * log2(x)));
2226 DEFINE_DERIVED_FLOAT1(Radians, radians, d, (constant(DE_PI) / constant(180.0f)) * d);
2227 DEFINE_DERIVED_FLOAT1(Degrees, degrees, r, (constant(180.0f) / constant(DE_PI)) * r);
2228
2229 class TrigFunc : public CFloatFunc1
2230 {
2231 public:
TrigFunc(const string & name,DoubleFunc1 & func,const Interval & loEx,const Interval & hiEx)2232 TrigFunc (const string& name,
2233 DoubleFunc1& func,
2234 const Interval& loEx,
2235 const Interval& hiEx)
2236 : CFloatFunc1 (name, func)
2237 , m_loExtremum (loEx)
2238 , m_hiExtremum (hiEx) {}
2239
2240 protected:
innerExtrema(const EvalContext &,const Interval & angle) const2241 Interval innerExtrema (const EvalContext&, const Interval& angle) const
2242 {
2243 const double lo = angle.lo();
2244 const double hi = angle.hi();
2245 const int loSlope = doGetSlope(lo);
2246 const int hiSlope = doGetSlope(hi);
2247
2248 // Detect the high and low values the function can take between the
2249 // interval endpoints.
2250 if (angle.length() >= 2.0 * DE_PI_DOUBLE)
2251 {
2252 // The interval is longer than a full cycle, so it must get all possible values.
2253 return m_hiExtremum | m_loExtremum;
2254 }
2255 else if (loSlope == 1 && hiSlope == -1)
2256 {
2257 // The slope can change from positive to negative only at the maximum value.
2258 return m_hiExtremum;
2259 }
2260 else if (loSlope == -1 && hiSlope == 1)
2261 {
2262 // The slope can change from negative to positive only at the maximum value.
2263 return m_loExtremum;
2264 }
2265 else if (loSlope == hiSlope &&
2266 deIntSign(applyExact(hi) - applyExact(lo)) * loSlope == -1)
2267 {
2268 // The slope has changed twice between the endpoints, so both extrema are included.
2269 return m_hiExtremum | m_loExtremum;
2270 }
2271
2272 return Interval();
2273 }
2274
getCodomain(void) const2275 Interval getCodomain (void) const
2276 {
2277 // Ensure that result is always within [-1, 1], or NaN (for +-inf)
2278 return Interval(-1.0, 1.0) | TCU_NAN;
2279 }
2280
precision(const EvalContext & ctx,double ret,double arg) const2281 double precision (const EvalContext& ctx, double ret, double arg) const
2282 {
2283 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2284 {
2285 // Use precision from OpenCL fast relaxed math
2286 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2287 {
2288 return deLdExp(1.0, -11);
2289 }
2290 else
2291 {
2292 // "larger otherwise", let's pick |x| * 2^-12 , which is slightly over
2293 // 2^-11 at x == pi.
2294 return deLdExp(deAbs(arg), -12);
2295 }
2296 }
2297 else if (ctx.floatPrecision == glu::PRECISION_MEDIUMP)
2298 {
2299 if (-DE_PI_DOUBLE <= arg && arg <= DE_PI_DOUBLE)
2300 {
2301 // from OpenCL half-float extension specification
2302 return ctx.format.ulp(ret, 2.0);
2303 }
2304 else
2305 {
2306 // |x| * 2^-10, slightly larger than 2 ULP at x == pi
2307 return deLdExp(deAbs(arg), -10);
2308 }
2309 }
2310 else
2311 {
2312 DE_ASSERT(ctx.floatPrecision == glu::PRECISION_LOWP);
2313
2314 // from OpenCL half-float extension specification
2315 return ctx.format.ulp(ret, 2.0);
2316 }
2317 }
2318
2319 virtual int doGetSlope (double angle) const = 0;
2320
2321 Interval m_loExtremum;
2322 Interval m_hiExtremum;
2323 };
2324
2325 class Sin : public TrigFunc
2326 {
2327 public:
Sin(void)2328 Sin (void) : TrigFunc("sin", deSin, -1.0, 1.0) {}
2329
2330 protected:
doGetSlope(double angle) const2331 int doGetSlope (double angle) const { return deIntSign(deCos(angle)); }
2332 };
2333
sin(const ExprP<float> & x)2334 ExprP<float> sin (const ExprP<float>& x) { return app<Sin>(x); }
2335
2336 class Cos : public TrigFunc
2337 {
2338 public:
Cos(void)2339 Cos (void) : TrigFunc("cos", deCos, -1.0, 1.0) {}
2340
2341 protected:
doGetSlope(double angle) const2342 int doGetSlope (double angle) const { return -deIntSign(deSin(angle)); }
2343 };
2344
cos(const ExprP<float> & x)2345 ExprP<float> cos (const ExprP<float>& x) { return app<Cos>(x); }
2346
2347 DEFINE_DERIVED_FLOAT1(Tan, tan, x, sin(x) * (constant(1.0f) / cos(x)));
2348
2349 class ASin : public CFloatFunc1
2350 {
2351 public:
ASin(void)2352 ASin (void) : CFloatFunc1("asin", deAsin) {}
2353
2354 protected:
precision(const EvalContext & ctx,double,double x) const2355 double precision (const EvalContext& ctx, double, double x) const
2356 {
2357 if (!de::inBounds(x, -1.0, 1.0))
2358 return TCU_NAN;
2359
2360 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2361 {
2362 // Absolute error of 2^-11
2363 return deLdExp(1.0, -11);
2364 }
2365 else
2366 {
2367 // Absolute error of 2^-8
2368 return deLdExp(1.0, -8);
2369 }
2370
2371 }
2372 };
2373
2374 class ArcTrigFunc : public CFloatFunc1
2375 {
2376 public:
ArcTrigFunc(const string & name,DoubleFunc1 & func,double precisionULPs,const Interval & domain,const Interval & codomain)2377 ArcTrigFunc (const string& name,
2378 DoubleFunc1& func,
2379 double precisionULPs,
2380 const Interval& domain,
2381 const Interval& codomain)
2382 : CFloatFunc1 (name, func)
2383 , m_precision (precisionULPs)
2384 , m_domain (domain)
2385 , m_codomain (codomain) {}
2386
2387 protected:
precision(const EvalContext & ctx,double ret,double x) const2388 double precision (const EvalContext& ctx, double ret, double x) const
2389 {
2390 if (!m_domain.contains(x))
2391 return TCU_NAN;
2392
2393 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2394 {
2395 // Use OpenCL's fast relaxed math precision
2396 return ctx.format.ulp(ret, m_precision);
2397 }
2398 else
2399 {
2400 // Use OpenCL half-float spec
2401 return ctx.format.ulp(ret, 2.0);
2402 }
2403 }
2404
2405 // We could implement getCodomain with m_codomain, but choose not to,
2406 // because it seems too strict with trascendental constants like pi.
2407
2408 const double m_precision;
2409 const Interval m_domain;
2410 const Interval m_codomain;
2411 };
2412
2413 class ACos : public ArcTrigFunc
2414 {
2415 public:
ACos(void)2416 ACos (void) : ArcTrigFunc("acos", deAcos, 4096.0,
2417 Interval(-1.0, 1.0),
2418 Interval(0.0, DE_PI_DOUBLE)) {}
2419 };
2420
2421 class ATan : public ArcTrigFunc
2422 {
2423 public:
ATan(void)2424 ATan (void) : ArcTrigFunc("atan", deAtanOver, 4096.0,
2425 Interval::unbounded(),
2426 Interval(-DE_PI_DOUBLE * 0.5, DE_PI_DOUBLE * 0.5)) {}
2427 };
2428
2429 class ATan2 : public CFloatFunc2
2430 {
2431 public:
ATan2(void)2432 ATan2 (void) : CFloatFunc2 ("atan", deAtan2) {}
2433
2434 protected:
innerExtrema(const EvalContext & ctx,const Interval & yi,const Interval & xi) const2435 Interval innerExtrema (const EvalContext& ctx,
2436 const Interval& yi,
2437 const Interval& xi) const
2438 {
2439 Interval ret;
2440
2441 if (yi.contains(0.0))
2442 {
2443 if (xi.contains(0.0))
2444 ret |= TCU_NAN;
2445 if (xi.intersects(Interval(-TCU_INFINITY, 0.0)))
2446 ret |= Interval(-DE_PI_DOUBLE, DE_PI_DOUBLE);
2447 }
2448
2449 if (ctx.format.hasInf() != YES && (!yi.isFinite() || !xi.isFinite()))
2450 {
2451 // Infinities may not be supported, allow anything, including NaN
2452 ret |= TCU_NAN;
2453 }
2454
2455 return ret;
2456 }
2457
precision(const EvalContext & ctx,double ret,double,double) const2458 double precision (const EvalContext& ctx, double ret, double, double) const
2459 {
2460 if (ctx.floatPrecision == glu::PRECISION_HIGHP)
2461 return ctx.format.ulp(ret, 4096.0);
2462 else
2463 return ctx.format.ulp(ret, 2.0);
2464 }
2465
2466 // Codomain could be [-pi, pi], but that would probably be too strict.
2467 };
2468
2469 DEFINE_DERIVED_FLOAT1(Sinh, sinh, x, (exp(x) - exp(-x)) / constant(2.0f));
2470 DEFINE_DERIVED_FLOAT1(Cosh, cosh, x, (exp(x) + exp(-x)) / constant(2.0f));
2471 DEFINE_DERIVED_FLOAT1(Tanh, tanh, x, sinh(x) / cosh(x));
2472
2473 // These are not defined as derived forms in the GLSL ES spec, but
2474 // that gives us a reasonable precision.
2475 DEFINE_DERIVED_FLOAT1(ASinh, asinh, x, log(x + sqrt(x * x + constant(1.0f))));
2476 DEFINE_DERIVED_FLOAT1(ACosh, acosh, x, log(x + sqrt((x + constant(1.0f)) *
2477 (x - constant(1.0f)))));
2478 DEFINE_DERIVED_FLOAT1(ATanh, atanh, x, constant(0.5f) * log((constant(1.0f) + x) /
2479 (constant(1.0f) - x)));
2480
2481 template <typename T>
2482 class GetComponent : public PrimitiveFunc<Signature<typename T::Element, T, int> >
2483 {
2484 public:
2485 typedef typename GetComponent::IRet IRet;
2486
getName(void) const2487 string getName (void) const { return "_getComponent"; }
2488
print(ostream & os,const BaseArgExprs & args) const2489 void print (ostream& os,
2490 const BaseArgExprs& args) const
2491 {
2492 os << *args[0] << "[" << *args[1] << "]";
2493 }
2494
2495 protected:
doApply(const EvalContext &,const typename GetComponent::IArgs & iargs) const2496 IRet doApply (const EvalContext&,
2497 const typename GetComponent::IArgs& iargs) const
2498 {
2499 IRet ret;
2500
2501 for (int compNdx = 0; compNdx < T::SIZE; ++compNdx)
2502 {
2503 if (iargs.b.contains(compNdx))
2504 ret = unionIVal<typename T::Element>(ret, iargs.a[compNdx]);
2505 }
2506
2507 return ret;
2508 }
2509
2510 };
2511
2512 template <typename T>
getComponent(const ExprP<T> & container,int ndx)2513 ExprP<typename T::Element> getComponent (const ExprP<T>& container, int ndx)
2514 {
2515 DE_ASSERT(0 <= ndx && ndx < T::SIZE);
2516 return app<GetComponent<T> >(container, constant(ndx));
2517 }
2518
2519 template <typename T> string vecNamePrefix (void);
vecNamePrefix(void)2520 template <> string vecNamePrefix<float> (void) { return ""; }
vecNamePrefix(void)2521 template <> string vecNamePrefix<int> (void) { return "i"; }
vecNamePrefix(void)2522 template <> string vecNamePrefix<bool> (void) { return "b"; }
2523
2524 template <typename T, int Size>
vecName(void)2525 string vecName (void) { return vecNamePrefix<T>() + "vec" + de::toString(Size); }
2526
2527 template <typename T, int Size> class GenVec;
2528
2529 template <typename T>
2530 class GenVec<T, 1> : public DerivedFunc<Signature<T, T> >
2531 {
2532 public:
2533 typedef typename GenVec<T, 1>::ArgExprs ArgExprs;
2534
getName(void) const2535 string getName (void) const
2536 {
2537 return "_" + vecName<T, 1>();
2538 }
2539
2540 protected:
2541
doExpand(ExpandContext &,const ArgExprs & args) const2542 ExprP<T> doExpand (ExpandContext&, const ArgExprs& args) const { return args.a; }
2543 };
2544
2545 template <typename T>
2546 class GenVec<T, 2> : public PrimitiveFunc<Signature<Vector<T, 2>, T, T> >
2547 {
2548 public:
2549 typedef typename GenVec::IRet IRet;
2550 typedef typename GenVec::IArgs IArgs;
2551
getName(void) const2552 string getName (void) const
2553 {
2554 return vecName<T, 2>();
2555 }
2556
2557 protected:
doApply(const EvalContext &,const IArgs & iargs) const2558 IRet doApply (const EvalContext&, const IArgs& iargs) const
2559 {
2560 return IRet(iargs.a, iargs.b);
2561 }
2562 };
2563
2564 template <typename T>
2565 class GenVec<T, 3> : public PrimitiveFunc<Signature<Vector<T, 3>, T, T, T> >
2566 {
2567 public:
2568 typedef typename GenVec::IRet IRet;
2569 typedef typename GenVec::IArgs IArgs;
2570
getName(void) const2571 string getName (void) const
2572 {
2573 return vecName<T, 3>();
2574 }
2575
2576 protected:
doApply(const EvalContext &,const IArgs & iargs) const2577 IRet doApply (const EvalContext&, const IArgs& iargs) const
2578 {
2579 return IRet(iargs.a, iargs.b, iargs.c);
2580 }
2581 };
2582
2583 template <typename T>
2584 class GenVec<T, 4> : public PrimitiveFunc<Signature<Vector<T, 4>, T, T, T, T> >
2585 {
2586 public:
2587 typedef typename GenVec::IRet IRet;
2588 typedef typename GenVec::IArgs IArgs;
2589
getName(void) const2590 string getName (void) const { return vecName<T, 4>(); }
2591
2592 protected:
doApply(const EvalContext &,const IArgs & iargs) const2593 IRet doApply (const EvalContext&, const IArgs& iargs) const
2594 {
2595 return IRet(iargs.a, iargs.b, iargs.c, iargs.d);
2596 }
2597 };
2598
2599
2600
2601 template <typename T, int Rows, int Columns>
2602 class GenMat;
2603
2604 template <typename T, int Rows>
2605 class GenMat<T, Rows, 2> : public PrimitiveFunc<
2606 Signature<Matrix<T, Rows, 2>, Vector<T, Rows>, Vector<T, Rows> > >
2607 {
2608 public:
2609 typedef typename GenMat::Ret Ret;
2610 typedef typename GenMat::IRet IRet;
2611 typedef typename GenMat::IArgs IArgs;
2612
getName(void) const2613 string getName (void) const
2614 {
2615 return dataTypeNameOf<Ret>();
2616 }
2617
2618 protected:
2619
doApply(const EvalContext &,const IArgs & iargs) const2620 IRet doApply (const EvalContext&, const IArgs& iargs) const
2621 {
2622 IRet ret;
2623 ret[0] = iargs.a;
2624 ret[1] = iargs.b;
2625 return ret;
2626 }
2627 };
2628
2629 template <typename T, int Rows>
2630 class GenMat<T, Rows, 3> : public PrimitiveFunc<
2631 Signature<Matrix<T, Rows, 3>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
2632 {
2633 public:
2634 typedef typename GenMat::Ret Ret;
2635 typedef typename GenMat::IRet IRet;
2636 typedef typename GenMat::IArgs IArgs;
2637
getName(void) const2638 string getName (void) const
2639 {
2640 return dataTypeNameOf<Ret>();
2641 }
2642
2643 protected:
2644
doApply(const EvalContext &,const IArgs & iargs) const2645 IRet doApply (const EvalContext&, const IArgs& iargs) const
2646 {
2647 IRet ret;
2648 ret[0] = iargs.a;
2649 ret[1] = iargs.b;
2650 ret[2] = iargs.c;
2651 return ret;
2652 }
2653 };
2654
2655 template <typename T, int Rows>
2656 class GenMat<T, Rows, 4> : public PrimitiveFunc<
2657 Signature<Matrix<T, Rows, 4>,
2658 Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows>, Vector<T, Rows> > >
2659 {
2660 public:
2661 typedef typename GenMat::Ret Ret;
2662 typedef typename GenMat::IRet IRet;
2663 typedef typename GenMat::IArgs IArgs;
2664
getName(void) const2665 string getName (void) const
2666 {
2667 return dataTypeNameOf<Ret>();
2668 }
2669
2670 protected:
doApply(const EvalContext &,const IArgs & iargs) const2671 IRet doApply (const EvalContext&, const IArgs& iargs) const
2672 {
2673 IRet ret;
2674 ret[0] = iargs.a;
2675 ret[1] = iargs.b;
2676 ret[2] = iargs.c;
2677 ret[3] = iargs.d;
2678 return ret;
2679 }
2680 };
2681
2682 template <typename T, int Rows>
mat2(const ExprP<Vector<T,Rows>> & arg0,const ExprP<Vector<T,Rows>> & arg1)2683 ExprP<Matrix<T, Rows, 2> > mat2 (const ExprP<Vector<T, Rows> >& arg0,
2684 const ExprP<Vector<T, Rows> >& arg1)
2685 {
2686 return app<GenMat<T, Rows, 2> >(arg0, arg1);
2687 }
2688
2689 template <typename T, int Rows>
mat3(const ExprP<Vector<T,Rows>> & arg0,const ExprP<Vector<T,Rows>> & arg1,const ExprP<Vector<T,Rows>> & arg2)2690 ExprP<Matrix<T, Rows, 3> > mat3 (const ExprP<Vector<T, Rows> >& arg0,
2691 const ExprP<Vector<T, Rows> >& arg1,
2692 const ExprP<Vector<T, Rows> >& arg2)
2693 {
2694 return app<GenMat<T, Rows, 3> >(arg0, arg1, arg2);
2695 }
2696
2697 template <typename T, int Rows>
mat4(const ExprP<Vector<T,Rows>> & arg0,const ExprP<Vector<T,Rows>> & arg1,const ExprP<Vector<T,Rows>> & arg2,const ExprP<Vector<T,Rows>> & arg3)2698 ExprP<Matrix<T, Rows, 4> > mat4 (const ExprP<Vector<T, Rows> >& arg0,
2699 const ExprP<Vector<T, Rows> >& arg1,
2700 const ExprP<Vector<T, Rows> >& arg2,
2701 const ExprP<Vector<T, Rows> >& arg3)
2702 {
2703 return app<GenMat<T, Rows, 4> >(arg0, arg1, arg2, arg3);
2704 }
2705
2706
2707 template <int Rows, int Cols>
2708 class MatNeg : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
2709 Matrix<float, Rows, Cols> > >
2710 {
2711 public:
2712 typedef typename MatNeg::IRet IRet;
2713 typedef typename MatNeg::IArgs IArgs;
2714
getName(void) const2715 string getName (void) const
2716 {
2717 return "_matNeg";
2718 }
2719
2720 protected:
doPrint(ostream & os,const BaseArgExprs & args) const2721 void doPrint (ostream& os, const BaseArgExprs& args) const
2722 {
2723 os << "-(" << *args[0] << ")";
2724 }
2725
doApply(const EvalContext &,const IArgs & iargs) const2726 IRet doApply (const EvalContext&, const IArgs& iargs) const
2727 {
2728 IRet ret;
2729
2730 for (int col = 0; col < Cols; ++col)
2731 {
2732 for (int row = 0; row < Rows; ++row)
2733 ret[col][row] = -iargs.a[col][row];
2734 }
2735
2736 return ret;
2737 }
2738 };
2739
2740 template <typename T, typename Sig>
2741 class CompWiseFunc : public PrimitiveFunc<Sig>
2742 {
2743 public:
2744 typedef Func<Signature<T, T, T> > ScalarFunc;
2745
getName(void) const2746 string getName (void) const
2747 {
2748 return doGetScalarFunc().getName();
2749 }
2750 protected:
doPrint(ostream & os,const BaseArgExprs & args) const2751 void doPrint (ostream& os,
2752 const BaseArgExprs& args) const
2753 {
2754 doGetScalarFunc().print(os, args);
2755 }
2756
2757 virtual
2758 const ScalarFunc& doGetScalarFunc (void) const = 0;
2759 };
2760
2761 template <int Rows, int Cols>
2762 class CompMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
2763 Matrix<float, Rows, Cols>,
2764 Matrix<float, Rows, Cols> > >
2765 {
2766 public:
2767 typedef typename CompMatFuncBase::IRet IRet;
2768 typedef typename CompMatFuncBase::IArgs IArgs;
2769
2770 protected:
2771
doApply(const EvalContext & ctx,const IArgs & iargs) const2772 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
2773 {
2774 IRet ret;
2775
2776 for (int col = 0; col < Cols; ++col)
2777 {
2778 for (int row = 0; row < Rows; ++row)
2779 ret[col][row] = this->doGetScalarFunc().apply(ctx,
2780 iargs.a[col][row],
2781 iargs.b[col][row]);
2782 }
2783
2784 return ret;
2785 }
2786 };
2787
2788 template <typename F, int Rows, int Cols>
2789 class CompMatFunc : public CompMatFuncBase<Rows, Cols>
2790 {
2791 protected:
doGetScalarFunc(void) const2792 const typename CompMatFunc::ScalarFunc& doGetScalarFunc (void) const
2793 {
2794 return instance<F>();
2795 }
2796 };
2797
2798 class ScalarMatrixCompMult : public Mul
2799 {
2800 public:
getName(void) const2801 string getName (void) const
2802 {
2803 return "matrixCompMult";
2804 }
2805
doPrint(ostream & os,const BaseArgExprs & args) const2806 void doPrint (ostream& os, const BaseArgExprs& args) const
2807 {
2808 Func<Sig>::doPrint(os, args);
2809 }
2810 };
2811
2812 template <int Rows, int Cols>
2813 class MatrixCompMult : public CompMatFunc<ScalarMatrixCompMult, Rows, Cols>
2814 {
2815 };
2816
2817 template <int Rows, int Cols>
2818 class ScalarMatFuncBase : public CompWiseFunc<float, Signature<Matrix<float, Rows, Cols>,
2819 Matrix<float, Rows, Cols>,
2820 float> >
2821 {
2822 public:
2823 typedef typename ScalarMatFuncBase::IRet IRet;
2824 typedef typename ScalarMatFuncBase::IArgs IArgs;
2825
2826 protected:
2827
doApply(const EvalContext & ctx,const IArgs & iargs) const2828 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
2829 {
2830 IRet ret;
2831
2832 for (int col = 0; col < Cols; ++col)
2833 {
2834 for (int row = 0; row < Rows; ++row)
2835 ret[col][row] = this->doGetScalarFunc().apply(ctx, iargs.a[col][row], iargs.b);
2836 }
2837
2838 return ret;
2839 }
2840 };
2841
2842 template <typename F, int Rows, int Cols>
2843 class ScalarMatFunc : public ScalarMatFuncBase<Rows, Cols>
2844 {
2845 protected:
doGetScalarFunc(void) const2846 const typename ScalarMatFunc::ScalarFunc& doGetScalarFunc (void) const
2847 {
2848 return instance<F>();
2849 }
2850 };
2851
2852 template<typename T, int Size> struct GenXType;
2853
2854 template<typename T>
2855 struct GenXType<T, 1>
2856 {
genXTypedeqp::gls::BuiltinPrecisionTests::Functions::GenXType2857 static ExprP<T> genXType (const ExprP<T>& x) { return x; }
2858 };
2859
2860 template<typename T>
2861 struct GenXType<T, 2>
2862 {
genXTypedeqp::gls::BuiltinPrecisionTests::Functions::GenXType2863 static ExprP<Vector<T, 2> > genXType (const ExprP<T>& x)
2864 {
2865 return app<GenVec<T, 2> >(x, x);
2866 }
2867 };
2868
2869 template<typename T>
2870 struct GenXType<T, 3>
2871 {
genXTypedeqp::gls::BuiltinPrecisionTests::Functions::GenXType2872 static ExprP<Vector<T, 3> > genXType (const ExprP<T>& x)
2873 {
2874 return app<GenVec<T, 3> >(x, x, x);
2875 }
2876 };
2877
2878 template<typename T>
2879 struct GenXType<T, 4>
2880 {
genXTypedeqp::gls::BuiltinPrecisionTests::Functions::GenXType2881 static ExprP<Vector<T, 4> > genXType (const ExprP<T>& x)
2882 {
2883 return app<GenVec<T, 4> >(x, x, x, x);
2884 }
2885 };
2886
2887 //! Returns an expression of vector of size `Size` (or scalar if Size == 1),
2888 //! with each element initialized with the expression `x`.
2889 template<typename T, int Size>
genXType(const ExprP<T> & x)2890 ExprP<typename ContainerOf<T, Size>::Container> genXType (const ExprP<T>& x)
2891 {
2892 return GenXType<T, Size>::genXType(x);
2893 }
2894
2895 typedef GenVec<float, 2> FloatVec2;
2896 DEFINE_CONSTRUCTOR2(FloatVec2, Vec2, vec2, float, float)
2897
2898 typedef GenVec<float, 3> FloatVec3;
2899 DEFINE_CONSTRUCTOR3(FloatVec3, Vec3, vec3, float, float, float)
2900
2901 typedef GenVec<float, 4> FloatVec4;
2902 DEFINE_CONSTRUCTOR4(FloatVec4, Vec4, vec4, float, float, float, float)
2903
2904 template <int Size>
2905 class Dot : public DerivedFunc<Signature<float, Vector<float, Size>, Vector<float, Size> > >
2906 {
2907 public:
2908 typedef typename Dot::ArgExprs ArgExprs;
2909
getName(void) const2910 string getName (void) const
2911 {
2912 return "dot";
2913 }
2914
2915 protected:
doExpand(ExpandContext &,const ArgExprs & args) const2916 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2917 {
2918 ExprP<float> val = args.a[0] * args.b[0];
2919
2920 for (int ndx = 1; ndx < Size; ++ndx)
2921 val = val + args.a[ndx] * args.b[ndx];
2922
2923 return val;
2924 }
2925 };
2926
2927 template <>
2928 class Dot<1> : public DerivedFunc<Signature<float, float, float> >
2929 {
2930 public:
getName(void) const2931 string getName (void) const
2932 {
2933 return "dot";
2934 }
2935
doExpand(ExpandContext &,const ArgExprs & args) const2936 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2937 {
2938 return args.a * args.b;
2939 }
2940 };
2941
2942 template <int Size>
dot(const ExprP<Vector<float,Size>> & x,const ExprP<Vector<float,Size>> & y)2943 ExprP<float> dot (const ExprP<Vector<float, Size> >& x, const ExprP<Vector<float, Size> >& y)
2944 {
2945 return app<Dot<Size> >(x, y);
2946 }
2947
dot(const ExprP<float> & x,const ExprP<float> & y)2948 ExprP<float> dot (const ExprP<float>& x, const ExprP<float>& y)
2949 {
2950 return app<Dot<1> >(x, y);
2951 }
2952
2953 template <int Size>
2954 class Length : public DerivedFunc<
2955 Signature<float, typename ContainerOf<float, Size>::Container> >
2956 {
2957 public:
2958 typedef typename Length::ArgExprs ArgExprs;
2959
getName(void) const2960 string getName (void) const
2961 {
2962 return "length";
2963 }
2964
2965 protected:
doExpand(ExpandContext &,const ArgExprs & args) const2966 ExprP<float> doExpand (ExpandContext&, const ArgExprs& args) const
2967 {
2968 return sqrt(dot(args.a, args.a));
2969 }
2970 };
2971
2972 template <int Size>
length(const ExprP<typename ContainerOf<float,Size>::Container> & x)2973 ExprP<float> length (const ExprP<typename ContainerOf<float, Size>::Container>& x)
2974 {
2975 return app<Length<Size> >(x);
2976 }
2977
2978 template <int Size>
2979 class Distance : public DerivedFunc<
2980 Signature<float,
2981 typename ContainerOf<float, Size>::Container,
2982 typename ContainerOf<float, Size>::Container> >
2983 {
2984 public:
2985 typedef typename Distance::Ret Ret;
2986 typedef typename Distance::ArgExprs ArgExprs;
2987
getName(void) const2988 string getName (void) const
2989 {
2990 return "distance";
2991 }
2992
2993 protected:
doExpand(ExpandContext &,const ArgExprs & args) const2994 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
2995 {
2996 return length<Size>(args.a - args.b);
2997 }
2998 };
2999
3000 // cross
3001
3002 class Cross : public DerivedFunc<Signature<Vec3, Vec3, Vec3> >
3003 {
3004 public:
getName(void) const3005 string getName (void) const
3006 {
3007 return "cross";
3008 }
3009
3010 protected:
doExpand(ExpandContext &,const ArgExprs & x) const3011 ExprP<Vec3> doExpand (ExpandContext&, const ArgExprs& x) const
3012 {
3013 return vec3(x.a[1] * x.b[2] - x.b[1] * x.a[2],
3014 x.a[2] * x.b[0] - x.b[2] * x.a[0],
3015 x.a[0] * x.b[1] - x.b[0] * x.a[1]);
3016 }
3017 };
3018
3019 DEFINE_CONSTRUCTOR2(Cross, Vec3, cross, Vec3, Vec3)
3020
3021 template<int Size>
3022 class Normalize : public DerivedFunc<
3023 Signature<typename ContainerOf<float, Size>::Container,
3024 typename ContainerOf<float, Size>::Container> >
3025 {
3026 public:
3027 typedef typename Normalize::Ret Ret;
3028 typedef typename Normalize::ArgExprs ArgExprs;
3029
getName(void) const3030 string getName (void) const
3031 {
3032 return "normalize";
3033 }
3034
3035 protected:
doExpand(ExpandContext &,const ArgExprs & args) const3036 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3037 {
3038 return args.a / length<Size>(args.a);
3039 }
3040 };
3041
3042 template <int Size>
3043 class FaceForward : public DerivedFunc<
3044 Signature<typename ContainerOf<float, Size>::Container,
3045 typename ContainerOf<float, Size>::Container,
3046 typename ContainerOf<float, Size>::Container,
3047 typename ContainerOf<float, Size>::Container> >
3048 {
3049 public:
3050 typedef typename FaceForward::Ret Ret;
3051 typedef typename FaceForward::ArgExprs ArgExprs;
3052
getName(void) const3053 string getName (void) const
3054 {
3055 return "faceforward";
3056 }
3057
3058 protected:
3059
3060
doExpand(ExpandContext &,const ArgExprs & args) const3061 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3062 {
3063 return cond(dot(args.c, args.b) < constant(0.0f), args.a, -args.a);
3064 }
3065 };
3066
3067 template <int Size>
3068 class Reflect : public DerivedFunc<
3069 Signature<typename ContainerOf<float, Size>::Container,
3070 typename ContainerOf<float, Size>::Container,
3071 typename ContainerOf<float, Size>::Container> >
3072 {
3073 public:
3074 typedef typename Reflect::Ret Ret;
3075 typedef typename Reflect::Arg0 Arg0;
3076 typedef typename Reflect::Arg1 Arg1;
3077 typedef typename Reflect::ArgExprs ArgExprs;
3078
getName(void) const3079 string getName (void) const
3080 {
3081 return "reflect";
3082 }
3083
3084 protected:
doExpand(ExpandContext & ctx,const ArgExprs & args) const3085 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3086 {
3087 const ExprP<Arg0>& i = args.a;
3088 const ExprP<Arg1>& n = args.b;
3089 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3090
3091 return i - alternatives((n * dotNI) * constant(2.0f),
3092 n * (dotNI * constant(2.0f)));
3093 }
3094 };
3095
3096 template <int Size>
3097 class Refract : public DerivedFunc<
3098 Signature<typename ContainerOf<float, Size>::Container,
3099 typename ContainerOf<float, Size>::Container,
3100 typename ContainerOf<float, Size>::Container,
3101 float> >
3102 {
3103 public:
3104 typedef typename Refract::Ret Ret;
3105 typedef typename Refract::Arg0 Arg0;
3106 typedef typename Refract::Arg1 Arg1;
3107 typedef typename Refract::ArgExprs ArgExprs;
3108
getName(void) const3109 string getName (void) const
3110 {
3111 return "refract";
3112 }
3113
3114 protected:
doExpand(ExpandContext & ctx,const ArgExprs & args) const3115 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3116 {
3117 const ExprP<Arg0>& i = args.a;
3118 const ExprP<Arg1>& n = args.b;
3119 const ExprP<float>& eta = args.c;
3120 const ExprP<float> dotNI = bindExpression("dotNI", ctx, dot(n, i));
3121 const ExprP<float> k = bindExpression("k", ctx, constant(1.0f) - eta * eta *
3122 (constant(1.0f) - dotNI * dotNI));
3123
3124 return cond(k < constant(0.0f),
3125 genXType<float, Size>(constant(0.0f)),
3126 i * eta - n * (eta * dotNI + sqrt(k)));
3127 }
3128 };
3129
3130 class PreciseFunc1 : public CFloatFunc1
3131 {
3132 public:
PreciseFunc1(const string & name,DoubleFunc1 & func)3133 PreciseFunc1 (const string& name, DoubleFunc1& func) : CFloatFunc1(name, func) {}
3134 protected:
precision(const EvalContext &,double,double) const3135 double precision (const EvalContext&, double, double) const { return 0.0; }
3136 };
3137
3138 class Abs : public PreciseFunc1
3139 {
3140 public:
Abs(void)3141 Abs (void) : PreciseFunc1("abs", deAbs) {}
3142 };
3143
3144 class Sign : public PreciseFunc1
3145 {
3146 public:
Sign(void)3147 Sign (void) : PreciseFunc1("sign", deSign) {}
3148 };
3149
3150 class Floor : public PreciseFunc1
3151 {
3152 public:
Floor(void)3153 Floor (void) : PreciseFunc1("floor", deFloor) {}
3154 };
3155
3156 class Trunc : public PreciseFunc1
3157 {
3158 public:
Trunc(void)3159 Trunc (void) : PreciseFunc1("trunc", deTrunc) {}
3160 };
3161
3162 class Round : public FloatFunc1
3163 {
3164 public:
getName(void) const3165 string getName (void) const { return "round"; }
3166
3167 protected:
applyPoint(const EvalContext &,double x) const3168 Interval applyPoint (const EvalContext&, double x) const
3169 {
3170 double truncated = 0.0;
3171 const double fract = deModf(x, &truncated);
3172 Interval ret;
3173
3174 if (fabs(fract) <= 0.5)
3175 ret |= truncated;
3176 if (fabs(fract) >= 0.5)
3177 ret |= truncated + deSign(fract);
3178
3179 return ret;
3180 }
3181
precision(const EvalContext &,double,double) const3182 double precision (const EvalContext&, double, double) const { return 0.0; }
3183 };
3184
3185 class RoundEven : public PreciseFunc1
3186 {
3187 public:
RoundEven(void)3188 RoundEven (void) : PreciseFunc1("roundEven", deRoundEven) {}
3189 };
3190
3191 class Ceil : public PreciseFunc1
3192 {
3193 public:
Ceil(void)3194 Ceil (void) : PreciseFunc1("ceil", deCeil) {}
3195 };
3196
3197 DEFINE_DERIVED_FLOAT1(Fract, fract, x, x - app<Floor>(x));
3198
3199 class PreciseFunc2 : public CFloatFunc2
3200 {
3201 public:
PreciseFunc2(const string & name,DoubleFunc2 & func)3202 PreciseFunc2 (const string& name, DoubleFunc2& func) : CFloatFunc2(name, func) {}
3203 protected:
precision(const EvalContext &,double,double,double) const3204 double precision (const EvalContext&, double, double, double) const { return 0.0; }
3205 };
3206
3207 DEFINE_DERIVED_FLOAT2(Mod, mod, x, y, x - y * app<Floor>(x / y));
3208
3209 class Modf : public PrimitiveFunc<Signature<float, float, float> >
3210 {
3211 public:
getName(void) const3212 string getName (void) const
3213 {
3214 return "modf";
3215 }
3216
3217 protected:
doApply(const EvalContext &,const IArgs & iargs) const3218 IRet doApply (const EvalContext&, const IArgs& iargs) const
3219 {
3220 Interval fracIV;
3221 Interval& wholeIV = const_cast<Interval&>(iargs.b);
3222 double intPart = 0;
3223
3224 TCU_INTERVAL_APPLY_MONOTONE1(fracIV, x, iargs.a, frac, frac = deModf(x, &intPart));
3225 TCU_INTERVAL_APPLY_MONOTONE1(wholeIV, x, iargs.a, whole,
3226 deModf(x, &intPart); whole = intPart);
3227
3228 if (!iargs.a.isFinite())
3229 {
3230 // Behavior on modf(Inf) not well-defined, allow anything as a fractional part
3231 // See Khronos bug 13907
3232 fracIV |= TCU_NAN;
3233 }
3234
3235 return fracIV;
3236 }
3237
getOutParamIndex(void) const3238 int getOutParamIndex (void) const
3239 {
3240 return 1;
3241 }
3242 };
3243
Min(void)3244 class Min : public PreciseFunc2 { public: Min (void) : PreciseFunc2("min", deMin) {} };
Max(void)3245 class Max : public PreciseFunc2 { public: Max (void) : PreciseFunc2("max", deMax) {} };
3246
3247 class Clamp : public FloatFunc3
3248 {
3249 public:
getName(void) const3250 string getName (void) const { return "clamp"; }
3251
applyExact(double x,double minVal,double maxVal) const3252 double applyExact (double x, double minVal, double maxVal) const
3253 {
3254 return de::min(de::max(x, minVal), maxVal);
3255 }
3256
precision(const EvalContext &,double,double,double minVal,double maxVal) const3257 double precision (const EvalContext&, double, double, double minVal, double maxVal) const
3258 {
3259 return minVal > maxVal ? TCU_NAN : 0.0;
3260 }
3261 };
3262
clamp(const ExprP<float> & x,const ExprP<float> & minVal,const ExprP<float> & maxVal)3263 ExprP<float> clamp(const ExprP<float>& x, const ExprP<float>& minVal, const ExprP<float>& maxVal)
3264 {
3265 return app<Clamp>(x, minVal, maxVal);
3266 }
3267
3268 DEFINE_DERIVED_FLOAT3(Mix, mix, x, y, a, alternatives((x * (constant(1.0f) - a)) + y * a,
3269 x + (y - x) * a));
3270
step(double edge,double x)3271 static double step (double edge, double x)
3272 {
3273 return x < edge ? 0.0 : 1.0;
3274 }
3275
Step(void)3276 class Step : public PreciseFunc2 { public: Step (void) : PreciseFunc2("step", step) {} };
3277
3278 class SmoothStep : public DerivedFunc<Signature<float, float, float, float> >
3279 {
3280 public:
getName(void) const3281 string getName (void) const
3282 {
3283 return "smoothstep";
3284 }
3285
3286 protected:
3287
doExpand(ExpandContext & ctx,const ArgExprs & args) const3288 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3289 {
3290 const ExprP<float>& edge0 = args.a;
3291 const ExprP<float>& edge1 = args.b;
3292 const ExprP<float>& x = args.c;
3293 const ExprP<float> tExpr = clamp((x - edge0) / (edge1 - edge0),
3294 constant(0.0f), constant(1.0f));
3295 const ExprP<float> t = bindExpression("t", ctx, tExpr);
3296
3297 return (t * t * (constant(3.0f) - constant(2.0f) * t));
3298 }
3299 };
3300
3301 class FrExp : public PrimitiveFunc<Signature<float, float, int> >
3302 {
3303 public:
getName(void) const3304 string getName (void) const
3305 {
3306 return "frexp";
3307 }
3308
3309 protected:
doApply(const EvalContext &,const IArgs & iargs) const3310 IRet doApply (const EvalContext&, const IArgs& iargs) const
3311 {
3312 IRet ret;
3313 const IArg0& x = iargs.a;
3314 IArg1& exponent = const_cast<IArg1&>(iargs.b);
3315
3316 if (x.hasNaN() || x.contains(TCU_INFINITY) || x.contains(-TCU_INFINITY))
3317 {
3318 // GLSL (in contrast to IEEE) says that result of applying frexp
3319 // to infinity is undefined
3320 ret = Interval::unbounded() | TCU_NAN;
3321 exponent = Interval(-deLdExp(1.0, 31), deLdExp(1.0, 31)-1);
3322 }
3323 else if (!x.empty())
3324 {
3325 int loExp = 0;
3326 const double loFrac = deFrExp(x.lo(), &loExp);
3327 int hiExp = 0;
3328 const double hiFrac = deFrExp(x.hi(), &hiExp);
3329
3330 if (deSign(loFrac) != deSign(hiFrac))
3331 {
3332 exponent = Interval(-TCU_INFINITY, de::max(loExp, hiExp));
3333 ret = Interval();
3334 if (deSign(loFrac) < 0)
3335 ret |= Interval(-1.0 + DBL_EPSILON*0.5, 0.0);
3336 if (deSign(hiFrac) > 0)
3337 ret |= Interval(0.0, 1.0 - DBL_EPSILON*0.5);
3338 }
3339 else
3340 {
3341 exponent = Interval(loExp, hiExp);
3342 if (loExp == hiExp)
3343 ret = Interval(loFrac, hiFrac);
3344 else
3345 ret = deSign(loFrac) * Interval(0.5, 1.0 - DBL_EPSILON*0.5);
3346 }
3347 }
3348
3349 return ret;
3350 }
3351
getOutParamIndex(void) const3352 int getOutParamIndex (void) const
3353 {
3354 return 1;
3355 }
3356 };
3357
3358 class LdExp : public PrimitiveFunc<Signature<float, float, int> >
3359 {
3360 public:
getName(void) const3361 string getName (void) const
3362 {
3363 return "ldexp";
3364 }
3365
3366 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const3367 Interval doApply (const EvalContext& ctx, const IArgs& iargs) const
3368 {
3369 Interval ret = call<Exp2>(ctx, iargs.b);
3370 // Khronos bug 11180 consensus: if exp2(exponent) cannot be represented,
3371 // the result is undefined.
3372
3373 if (ret.contains(TCU_INFINITY) | ret.contains(-TCU_INFINITY))
3374 ret |= TCU_NAN;
3375
3376 return call<Mul>(ctx, iargs.a, ret);
3377 }
3378 };
3379
3380 template<int Rows, int Columns>
3381 class Transpose : public PrimitiveFunc<Signature<Matrix<float, Rows, Columns>,
3382 Matrix<float, Columns, Rows> > >
3383 {
3384 public:
3385 typedef typename Transpose::IRet IRet;
3386 typedef typename Transpose::IArgs IArgs;
3387
getName(void) const3388 string getName (void) const
3389 {
3390 return "transpose";
3391 }
3392
3393 protected:
doApply(const EvalContext &,const IArgs & iargs) const3394 IRet doApply (const EvalContext&, const IArgs& iargs) const
3395 {
3396 IRet ret;
3397
3398 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
3399 {
3400 for (int colNdx = 0; colNdx < Columns; ++colNdx)
3401 ret(rowNdx, colNdx) = iargs.a(colNdx, rowNdx);
3402 }
3403
3404 return ret;
3405 }
3406 };
3407
3408 template<typename Ret, typename Arg0, typename Arg1>
3409 class MulFunc : public PrimitiveFunc<Signature<Ret, Arg0, Arg1> >
3410 {
3411 public:
getName(void) const3412 string getName (void) const { return "mul"; }
3413
3414 protected:
doPrint(ostream & os,const BaseArgExprs & args) const3415 void doPrint (ostream& os, const BaseArgExprs& args) const
3416 {
3417 os << "(" << *args[0] << " * " << *args[1] << ")";
3418 }
3419 };
3420
3421 template<int LeftRows, int Middle, int RightCols>
3422 class MatMul : public MulFunc<Matrix<float, LeftRows, RightCols>,
3423 Matrix<float, LeftRows, Middle>,
3424 Matrix<float, Middle, RightCols> >
3425 {
3426 protected:
3427 typedef typename MatMul::IRet IRet;
3428 typedef typename MatMul::IArgs IArgs;
3429 typedef typename MatMul::IArg0 IArg0;
3430 typedef typename MatMul::IArg1 IArg1;
3431
doApply(const EvalContext & ctx,const IArgs & iargs) const3432 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3433 {
3434 const IArg0& left = iargs.a;
3435 const IArg1& right = iargs.b;
3436 IRet ret;
3437
3438 for (int row = 0; row < LeftRows; ++row)
3439 {
3440 for (int col = 0; col < RightCols; ++col)
3441 {
3442 Interval element (0.0);
3443
3444 for (int ndx = 0; ndx < Middle; ++ndx)
3445 element = call<Add>(ctx, element,
3446 call<Mul>(ctx, left[ndx][row], right[col][ndx]));
3447
3448 ret[col][row] = element;
3449 }
3450 }
3451
3452 return ret;
3453 }
3454 };
3455
3456 template<int Rows, int Cols>
3457 class VecMatMul : public MulFunc<Vector<float, Cols>,
3458 Vector<float, Rows>,
3459 Matrix<float, Rows, Cols> >
3460 {
3461 public:
3462 typedef typename VecMatMul::IRet IRet;
3463 typedef typename VecMatMul::IArgs IArgs;
3464 typedef typename VecMatMul::IArg0 IArg0;
3465 typedef typename VecMatMul::IArg1 IArg1;
3466
3467 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const3468 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3469 {
3470 const IArg0& left = iargs.a;
3471 const IArg1& right = iargs.b;
3472 IRet ret;
3473
3474 for (int col = 0; col < Cols; ++col)
3475 {
3476 Interval element (0.0);
3477
3478 for (int row = 0; row < Rows; ++row)
3479 element = call<Add>(ctx, element, call<Mul>(ctx, left[row], right[col][row]));
3480
3481 ret[col] = element;
3482 }
3483
3484 return ret;
3485 }
3486 };
3487
3488 template<int Rows, int Cols>
3489 class MatVecMul : public MulFunc<Vector<float, Rows>,
3490 Matrix<float, Rows, Cols>,
3491 Vector<float, Cols> >
3492 {
3493 public:
3494 typedef typename MatVecMul::IRet IRet;
3495 typedef typename MatVecMul::IArgs IArgs;
3496 typedef typename MatVecMul::IArg0 IArg0;
3497 typedef typename MatVecMul::IArg1 IArg1;
3498
3499 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const3500 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3501 {
3502 const IArg0& left = iargs.a;
3503 const IArg1& right = iargs.b;
3504
3505 return call<VecMatMul<Cols, Rows> >(ctx, right,
3506 call<Transpose<Rows, Cols> >(ctx, left));
3507 }
3508 };
3509
3510 template<int Rows, int Cols>
3511 class OuterProduct : public PrimitiveFunc<Signature<Matrix<float, Rows, Cols>,
3512 Vector<float, Rows>,
3513 Vector<float, Cols> > >
3514 {
3515 public:
3516 typedef typename OuterProduct::IRet IRet;
3517 typedef typename OuterProduct::IArgs IArgs;
3518
getName(void) const3519 string getName (void) const
3520 {
3521 return "outerProduct";
3522 }
3523
3524 protected:
doApply(const EvalContext & ctx,const IArgs & iargs) const3525 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3526 {
3527 IRet ret;
3528
3529 for (int row = 0; row < Rows; ++row)
3530 {
3531 for (int col = 0; col < Cols; ++col)
3532 ret[col][row] = call<Mul>(ctx, iargs.a[row], iargs.b[col]);
3533 }
3534
3535 return ret;
3536 }
3537 };
3538
3539 template<int Rows, int Cols>
outerProduct(const ExprP<Vector<float,Rows>> & left,const ExprP<Vector<float,Cols>> & right)3540 ExprP<Matrix<float, Rows, Cols> > outerProduct (const ExprP<Vector<float, Rows> >& left,
3541 const ExprP<Vector<float, Cols> >& right)
3542 {
3543 return app<OuterProduct<Rows, Cols> >(left, right);
3544 }
3545
3546 template<int Size>
3547 class DeterminantBase : public DerivedFunc<Signature<float, Matrix<float, Size, Size> > >
3548 {
3549 public:
getName(void) const3550 string getName (void) const { return "determinant"; }
3551 };
3552
3553 template<int Size>
3554 class Determinant;
3555
3556 template<int Size>
determinant(ExprP<Matrix<float,Size,Size>> mat)3557 ExprP<float> determinant (ExprP<Matrix<float, Size, Size> > mat)
3558 {
3559 return app<Determinant<Size> >(mat);
3560 }
3561
3562 template<>
3563 class Determinant<2> : public DeterminantBase<2>
3564 {
3565 protected:
doExpand(ExpandContext &,const ArgExprs & args) const3566 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3567 {
3568 ExprP<Mat2> mat = args.a;
3569
3570 return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
3571 }
3572 };
3573
3574 template<>
3575 class Determinant<3> : public DeterminantBase<3>
3576 {
3577 protected:
doExpand(ExpandContext &,const ArgExprs & args) const3578 ExprP<Ret> doExpand (ExpandContext&, const ArgExprs& args) const
3579 {
3580 ExprP<Mat3> mat = args.a;
3581
3582 return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) +
3583 mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) +
3584 mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
3585 }
3586 };
3587
3588 template<>
3589 class Determinant<4> : public DeterminantBase<4>
3590 {
3591 protected:
doExpand(ExpandContext & ctx,const ArgExprs & args) const3592 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3593 {
3594 ExprP<Mat4> mat = args.a;
3595 ExprP<Mat3> minors[4];
3596
3597 for (int ndx = 0; ndx < 4; ++ndx)
3598 {
3599 ExprP<Vec4> minorColumns[3];
3600 ExprP<Vec3> columns[3];
3601
3602 for (int col = 0; col < 3; ++col)
3603 minorColumns[col] = mat[col < ndx ? col : col + 1];
3604
3605 for (int col = 0; col < 3; ++col)
3606 columns[col] = vec3(minorColumns[0][col+1],
3607 minorColumns[1][col+1],
3608 minorColumns[2][col+1]);
3609
3610 minors[ndx] = bindExpression("minor", ctx,
3611 mat3(columns[0], columns[1], columns[2]));
3612 }
3613
3614 return (mat[0][0] * determinant(minors[0]) -
3615 mat[1][0] * determinant(minors[1]) +
3616 mat[2][0] * determinant(minors[2]) -
3617 mat[3][0] * determinant(minors[3]));
3618 }
3619 };
3620
3621 template<int Size> class Inverse;
3622
3623 template <int Size>
inverse(ExprP<Matrix<float,Size,Size>> mat)3624 ExprP<Matrix<float, Size, Size> > inverse (ExprP<Matrix<float, Size, Size> > mat)
3625 {
3626 return app<Inverse<Size> >(mat);
3627 }
3628
3629 template<>
3630 class Inverse<2> : public DerivedFunc<Signature<Mat2, Mat2> >
3631 {
3632 public:
getName(void) const3633 string getName (void) const
3634 {
3635 return "inverse";
3636 }
3637
3638 protected:
doExpand(ExpandContext & ctx,const ArgExprs & args) const3639 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3640 {
3641 ExprP<Mat2> mat = args.a;
3642 ExprP<float> det = bindExpression("det", ctx, determinant(mat));
3643
3644 return mat2(vec2(mat[1][1] / det, -mat[0][1] / det),
3645 vec2(-mat[1][0] / det, mat[0][0] / det));
3646 }
3647 };
3648
3649 template<>
3650 class Inverse<3> : public DerivedFunc<Signature<Mat3, Mat3> >
3651 {
3652 public:
getName(void) const3653 string getName (void) const
3654 {
3655 return "inverse";
3656 }
3657
3658 protected:
doExpand(ExpandContext & ctx,const ArgExprs & args) const3659 ExprP<Ret> doExpand (ExpandContext& ctx, const ArgExprs& args) const
3660 {
3661 ExprP<Mat3> mat = args.a;
3662 ExprP<Mat2> invA = bindExpression("invA", ctx,
3663 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3664 vec2(mat[1][0], mat[1][1]))));
3665
3666 ExprP<Vec2> matB = bindExpression("matB", ctx, vec2(mat[2][0], mat[2][1]));
3667 ExprP<Vec2> matC = bindExpression("matC", ctx, vec2(mat[0][2], mat[1][2]));
3668 ExprP<float> matD = bindExpression("matD", ctx, mat[2][2]);
3669
3670 ExprP<float> schur = bindExpression("schur", ctx,
3671 constant(1.0f) /
3672 (matD - dot(matC * invA, matB)));
3673
3674 ExprP<Vec2> t1 = invA * matB;
3675 ExprP<Vec2> t2 = t1 * schur;
3676 ExprP<Mat2> t3 = outerProduct(t2, matC);
3677 ExprP<Mat2> t4 = t3 * invA;
3678 ExprP<Mat2> t5 = invA + t4;
3679 ExprP<Mat2> blockA = bindExpression("blockA", ctx, t5);
3680 ExprP<Vec2> blockB = bindExpression("blockB", ctx,
3681 (invA * matB) * -schur);
3682 ExprP<Vec2> blockC = bindExpression("blockC", ctx,
3683 (matC * invA) * -schur);
3684
3685 return mat3(vec3(blockA[0][0], blockA[0][1], blockC[0]),
3686 vec3(blockA[1][0], blockA[1][1], blockC[1]),
3687 vec3(blockB[0], blockB[1], schur));
3688 }
3689 };
3690
3691 template<>
3692 class Inverse<4> : public DerivedFunc<Signature<Mat4, Mat4> >
3693 {
3694 public:
getName(void) const3695 string getName (void) const { return "inverse"; }
3696
3697 protected:
doExpand(ExpandContext & ctx,const ArgExprs & args) const3698 ExprP<Ret> doExpand (ExpandContext& ctx,
3699 const ArgExprs& args) const
3700 {
3701 ExprP<Mat4> mat = args.a;
3702 ExprP<Mat2> invA = bindExpression("invA", ctx,
3703 inverse(mat2(vec2(mat[0][0], mat[0][1]),
3704 vec2(mat[1][0], mat[1][1]))));
3705 ExprP<Mat2> matB = bindExpression("matB", ctx,
3706 mat2(vec2(mat[2][0], mat[2][1]),
3707 vec2(mat[3][0], mat[3][1])));
3708 ExprP<Mat2> matC = bindExpression("matC", ctx,
3709 mat2(vec2(mat[0][2], mat[0][3]),
3710 vec2(mat[1][2], mat[1][3])));
3711 ExprP<Mat2> matD = bindExpression("matD", ctx,
3712 mat2(vec2(mat[2][2], mat[2][3]),
3713 vec2(mat[3][2], mat[3][3])));
3714 ExprP<Mat2> schur = bindExpression("schur", ctx,
3715 inverse(matD + -(matC * invA * matB)));
3716 ExprP<Mat2> blockA = bindExpression("blockA", ctx,
3717 invA + (invA * matB * schur * matC * invA));
3718 ExprP<Mat2> blockB = bindExpression("blockB", ctx,
3719 (-invA) * matB * schur);
3720 ExprP<Mat2> blockC = bindExpression("blockC", ctx,
3721 (-schur) * matC * invA);
3722
3723 return mat4(vec4(blockA[0][0], blockA[0][1], blockC[0][0], blockC[0][1]),
3724 vec4(blockA[1][0], blockA[1][1], blockC[1][0], blockC[1][1]),
3725 vec4(blockB[0][0], blockB[0][1], schur[0][0], schur[0][1]),
3726 vec4(blockB[1][0], blockB[1][1], schur[1][0], schur[1][1]));
3727 }
3728 };
3729
3730 class Fma : public DerivedFunc<Signature<float, float, float, float> >
3731 {
3732 public:
getName(void) const3733 string getName (void) const
3734 {
3735 return "fma";
3736 }
3737
getRequiredExtension(void) const3738 string getRequiredExtension (void) const
3739 {
3740 return "GL_EXT_gpu_shader5";
3741 }
3742
3743 protected:
doExpand(ExpandContext &,const ArgExprs & x) const3744 ExprP<float> doExpand (ExpandContext&, const ArgExprs& x) const
3745 {
3746 return x.a * x.b + x.c;
3747 }
3748 };
3749
3750 } // Functions
3751
3752 using namespace Functions;
3753
3754 template <typename T>
operator [](int i) const3755 ExprP<typename T::Element> ContainerExprPBase<T>::operator[] (int i) const
3756 {
3757 return Functions::getComponent(exprP<T>(*this), i);
3758 }
3759
operator +(const ExprP<float> & arg0,const ExprP<float> & arg1)3760 ExprP<float> operator+ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3761 {
3762 return app<Add>(arg0, arg1);
3763 }
3764
operator -(const ExprP<float> & arg0,const ExprP<float> & arg1)3765 ExprP<float> operator- (const ExprP<float>& arg0, const ExprP<float>& arg1)
3766 {
3767 return app<Sub>(arg0, arg1);
3768 }
3769
operator -(const ExprP<float> & arg0)3770 ExprP<float> operator- (const ExprP<float>& arg0)
3771 {
3772 return app<Negate>(arg0);
3773 }
3774
operator *(const ExprP<float> & arg0,const ExprP<float> & arg1)3775 ExprP<float> operator* (const ExprP<float>& arg0, const ExprP<float>& arg1)
3776 {
3777 return app<Mul>(arg0, arg1);
3778 }
3779
operator /(const ExprP<float> & arg0,const ExprP<float> & arg1)3780 ExprP<float> operator/ (const ExprP<float>& arg0, const ExprP<float>& arg1)
3781 {
3782 return app<Div>(arg0, arg1);
3783 }
3784
3785 template <typename Sig_, int Size>
3786 class GenFunc : public PrimitiveFunc<Signature<
3787 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3788 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3789 typename ContainerOf<typename Sig_::Arg1, Size>::Container,
3790 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
3791 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
3792 {
3793 public:
3794 typedef typename GenFunc::IArgs IArgs;
3795 typedef typename GenFunc::IRet IRet;
3796
GenFunc(const Func<Sig_> & scalarFunc)3797 GenFunc (const Func<Sig_>& scalarFunc) : m_func (scalarFunc) {}
3798
getName(void) const3799 string getName (void) const
3800 {
3801 return m_func.getName();
3802 }
3803
getOutParamIndex(void) const3804 int getOutParamIndex (void) const
3805 {
3806 return m_func.getOutParamIndex();
3807 }
3808
getRequiredExtension(void) const3809 string getRequiredExtension (void) const
3810 {
3811 return m_func.getRequiredExtension();
3812 }
3813
3814 protected:
doPrint(ostream & os,const BaseArgExprs & args) const3815 void doPrint (ostream& os, const BaseArgExprs& args) const
3816 {
3817 m_func.print(os, args);
3818 }
3819
doApply(const EvalContext & ctx,const IArgs & iargs) const3820 IRet doApply (const EvalContext& ctx, const IArgs& iargs) const
3821 {
3822 IRet ret;
3823
3824 for (int ndx = 0; ndx < Size; ++ndx)
3825 {
3826 ret[ndx] =
3827 m_func.apply(ctx, iargs.a[ndx], iargs.b[ndx], iargs.c[ndx], iargs.d[ndx]);
3828 }
3829
3830 return ret;
3831 }
3832
doGetUsedFuncs(FuncSet & dst) const3833 void doGetUsedFuncs (FuncSet& dst) const
3834 {
3835 m_func.getUsedFuncs(dst);
3836 }
3837
3838 const Func<Sig_>& m_func;
3839 };
3840
3841 template <typename F, int Size>
3842 class VectorizedFunc : public GenFunc<typename F::Sig, Size>
3843 {
3844 public:
VectorizedFunc(void)3845 VectorizedFunc (void) : GenFunc<typename F::Sig, Size>(instance<F>()) {}
3846 };
3847
3848
3849
3850 template <typename Sig_, int Size>
3851 class FixedGenFunc : public PrimitiveFunc <Signature<
3852 typename ContainerOf<typename Sig_::Ret, Size>::Container,
3853 typename ContainerOf<typename Sig_::Arg0, Size>::Container,
3854 typename Sig_::Arg1,
3855 typename ContainerOf<typename Sig_::Arg2, Size>::Container,
3856 typename ContainerOf<typename Sig_::Arg3, Size>::Container> >
3857 {
3858 public:
3859 typedef typename FixedGenFunc::IArgs IArgs;
3860 typedef typename FixedGenFunc::IRet IRet;
3861
getName(void) const3862 string getName (void) const
3863 {
3864 return this->doGetScalarFunc().getName();
3865 }
3866
3867 protected:
doPrint(ostream & os,const BaseArgExprs & args) const3868 void doPrint (ostream& os, const BaseArgExprs& args) const
3869 {
3870 this->doGetScalarFunc().print(os, args);
3871 }
3872
doApply(const EvalContext & ctx,const IArgs & iargs) const3873 IRet doApply (const EvalContext& ctx,
3874 const IArgs& iargs) const
3875 {
3876 IRet ret;
3877 const Func<Sig_>& func = this->doGetScalarFunc();
3878
3879 for (int ndx = 0; ndx < Size; ++ndx)
3880 ret[ndx] = func.apply(ctx, iargs.a[ndx], iargs.b, iargs.c[ndx], iargs.d[ndx]);
3881
3882 return ret;
3883 }
3884
3885 virtual const Func<Sig_>& doGetScalarFunc (void) const = 0;
3886 };
3887
3888 template <typename F, int Size>
3889 class FixedVecFunc : public FixedGenFunc<typename F::Sig, Size>
3890 {
3891 protected:
doGetScalarFunc(void) const3892 const Func<typename F::Sig>& doGetScalarFunc (void) const { return instance<F>(); }
3893 };
3894
3895 template<typename Sig>
3896 struct GenFuncs
3897 {
GenFuncsdeqp::gls::BuiltinPrecisionTests::GenFuncs3898 GenFuncs (const Func<Sig>& func_,
3899 const GenFunc<Sig, 2>& func2_,
3900 const GenFunc<Sig, 3>& func3_,
3901 const GenFunc<Sig, 4>& func4_)
3902 : func (func_)
3903 , func2 (func2_)
3904 , func3 (func3_)
3905 , func4 (func4_)
3906 {}
3907
3908 const Func<Sig>& func;
3909 const GenFunc<Sig, 2>& func2;
3910 const GenFunc<Sig, 3>& func3;
3911 const GenFunc<Sig, 4>& func4;
3912 };
3913
3914 template<typename F>
makeVectorizedFuncs(void)3915 GenFuncs<typename F::Sig> makeVectorizedFuncs (void)
3916 {
3917 return GenFuncs<typename F::Sig>(instance<F>(),
3918 instance<VectorizedFunc<F, 2> >(),
3919 instance<VectorizedFunc<F, 3> >(),
3920 instance<VectorizedFunc<F, 4> >());
3921 }
3922
3923 template<int Size>
operator *(const ExprP<Vector<float,Size>> & arg0,const ExprP<Vector<float,Size>> & arg1)3924 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
3925 const ExprP<Vector<float, Size> >& arg1)
3926 {
3927 return app<VectorizedFunc<Mul, Size> >(arg0, arg1);
3928 }
3929
3930 template<int Size>
operator *(const ExprP<Vector<float,Size>> & arg0,const ExprP<float> & arg1)3931 ExprP<Vector<float, Size> > operator*(const ExprP<Vector<float, Size> >& arg0,
3932 const ExprP<float>& arg1)
3933 {
3934 return app<FixedVecFunc<Mul, Size> >(arg0, arg1);
3935 }
3936
3937 template<int Size>
operator /(const ExprP<Vector<float,Size>> & arg0,const ExprP<float> & arg1)3938 ExprP<Vector<float, Size> > operator/(const ExprP<Vector<float, Size> >& arg0,
3939 const ExprP<float>& arg1)
3940 {
3941 return app<FixedVecFunc<Div, Size> >(arg0, arg1);
3942 }
3943
3944 template<int Size>
operator -(const ExprP<Vector<float,Size>> & arg0)3945 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0)
3946 {
3947 return app<VectorizedFunc<Negate, Size> >(arg0);
3948 }
3949
3950 template<int Size>
operator -(const ExprP<Vector<float,Size>> & arg0,const ExprP<Vector<float,Size>> & arg1)3951 ExprP<Vector<float, Size> > operator-(const ExprP<Vector<float, Size> >& arg0,
3952 const ExprP<Vector<float, Size> >& arg1)
3953 {
3954 return app<VectorizedFunc<Sub, Size> >(arg0, arg1);
3955 }
3956
3957 template<int LeftRows, int Middle, int RightCols>
3958 ExprP<Matrix<float, LeftRows, RightCols> >
operator *(const ExprP<Matrix<float,LeftRows,Middle>> & left,const ExprP<Matrix<float,Middle,RightCols>> & right)3959 operator* (const ExprP<Matrix<float, LeftRows, Middle> >& left,
3960 const ExprP<Matrix<float, Middle, RightCols> >& right)
3961 {
3962 return app<MatMul<LeftRows, Middle, RightCols> >(left, right);
3963 }
3964
3965 template<int Rows, int Cols>
operator *(const ExprP<Vector<float,Cols>> & left,const ExprP<Matrix<float,Rows,Cols>> & right)3966 ExprP<Vector<float, Rows> > operator* (const ExprP<Vector<float, Cols> >& left,
3967 const ExprP<Matrix<float, Rows, Cols> >& right)
3968 {
3969 return app<VecMatMul<Rows, Cols> >(left, right);
3970 }
3971
3972 template<int Rows, int Cols>
operator *(const ExprP<Matrix<float,Rows,Cols>> & left,const ExprP<Vector<float,Rows>> & right)3973 ExprP<Vector<float, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
3974 const ExprP<Vector<float, Rows> >& right)
3975 {
3976 return app<MatVecMul<Rows, Cols> >(left, right);
3977 }
3978
3979 template<int Rows, int Cols>
operator *(const ExprP<Matrix<float,Rows,Cols>> & left,const ExprP<float> & right)3980 ExprP<Matrix<float, Rows, Cols> > operator* (const ExprP<Matrix<float, Rows, Cols> >& left,
3981 const ExprP<float>& right)
3982 {
3983 return app<ScalarMatFunc<Mul, Rows, Cols> >(left, right);
3984 }
3985
3986 template<int Rows, int Cols>
operator +(const ExprP<Matrix<float,Rows,Cols>> & left,const ExprP<Matrix<float,Rows,Cols>> & right)3987 ExprP<Matrix<float, Rows, Cols> > operator+ (const ExprP<Matrix<float, Rows, Cols> >& left,
3988 const ExprP<Matrix<float, Rows, Cols> >& right)
3989 {
3990 return app<CompMatFunc<Add, Rows, Cols> >(left, right);
3991 }
3992
3993 template<int Rows, int Cols>
operator -(const ExprP<Matrix<float,Rows,Cols>> & mat)3994 ExprP<Matrix<float, Rows, Cols> > operator- (const ExprP<Matrix<float, Rows, Cols> >& mat)
3995 {
3996 return app<MatNeg<Rows, Cols> >(mat);
3997 }
3998
3999 template <typename T>
4000 class Sampling
4001 {
4002 public:
genFixeds(const FloatFormat &,vector<T> &) const4003 virtual void genFixeds (const FloatFormat&, vector<T>&) const {}
genRandom(const FloatFormat &,Precision,Random &) const4004 virtual T genRandom (const FloatFormat&, Precision, Random&) const { return T(); }
getWeight(void) const4005 virtual double getWeight (void) const { return 0.0; }
4006 };
4007
4008 template <>
4009 class DefaultSampling<Void> : public Sampling<Void>
4010 {
4011 public:
genFixeds(const FloatFormat &,vector<Void> & dst) const4012 void genFixeds (const FloatFormat&, vector<Void>& dst) const { dst.push_back(Void()); }
4013 };
4014
4015 template <>
4016 class DefaultSampling<bool> : public Sampling<bool>
4017 {
4018 public:
genFixeds(const FloatFormat &,vector<bool> & dst) const4019 void genFixeds (const FloatFormat&, vector<bool>& dst) const
4020 {
4021 dst.push_back(true);
4022 dst.push_back(false);
4023 }
4024 };
4025
4026 template <>
4027 class DefaultSampling<int> : public Sampling<int>
4028 {
4029 public:
genRandom(const FloatFormat &,Precision prec,Random & rnd) const4030 int genRandom (const FloatFormat&, Precision prec, Random& rnd) const
4031 {
4032 const int exp = rnd.getInt(0, getNumBits(prec)-2);
4033 const int sign = rnd.getBool() ? -1 : 1;
4034
4035 return sign * rnd.getInt(0, 1L << exp);
4036 }
4037
genFixeds(const FloatFormat &,vector<int> & dst) const4038 void genFixeds (const FloatFormat&, vector<int>& dst) const
4039 {
4040 dst.push_back(0);
4041 dst.push_back(-1);
4042 dst.push_back(1);
4043 }
getWeight(void) const4044 double getWeight (void) const { return 1.0; }
4045
4046 private:
getNumBits(Precision prec)4047 static inline int getNumBits (Precision prec)
4048 {
4049 switch (prec)
4050 {
4051 case glu::PRECISION_LOWP: return 8;
4052 case glu::PRECISION_MEDIUMP: return 16;
4053 case glu::PRECISION_HIGHP: return 32;
4054 default:
4055 DE_ASSERT(false);
4056 return 0;
4057 }
4058 }
4059 };
4060
4061 template <>
4062 class DefaultSampling<float> : public Sampling<float>
4063 {
4064 public:
4065 float genRandom (const FloatFormat& format, Precision prec, Random& rnd) const;
4066 void genFixeds (const FloatFormat& format, vector<float>& dst) const;
getWeight(void) const4067 double getWeight (void) const { return 1.0; }
4068 };
4069
4070 //! Generate a random float from a reasonable general-purpose distribution.
genRandom(const FloatFormat & format,Precision,Random & rnd) const4071 float DefaultSampling<float>::genRandom (const FloatFormat& format,
4072 Precision,
4073 Random& rnd) const
4074 {
4075 const int minExp = format.getMinExp();
4076 const int maxExp = format.getMaxExp();
4077 const bool haveSubnormal = format.hasSubnormal() != tcu::NO;
4078
4079 // Choose exponent so that the cumulative distribution is cubic.
4080 // This makes the probability distribution quadratic, with the peak centered on zero.
4081 const double minRoot = deCbrt(minExp - 0.5 - (haveSubnormal ? 1.0 : 0.0));
4082 const double maxRoot = deCbrt(maxExp + 0.5);
4083 const int fractionBits = format.getFractionBits();
4084 const int exp = int(deRoundEven(dePow(rnd.getDouble(minRoot, maxRoot),
4085 3.0)));
4086 float base = 0.0f; // integral power of two
4087 float quantum = 0.0f; // smallest representable difference in the binade
4088 float significand = 0.0f; // Significand.
4089
4090 DE_ASSERT(fractionBits < std::numeric_limits<float>::digits);
4091
4092 // Generate some occasional special numbers
4093 switch (rnd.getInt(0, 64))
4094 {
4095 case 0: return 0;
4096 case 1: return TCU_INFINITY;
4097 case 2: return -TCU_INFINITY;
4098 case 3: return TCU_NAN;
4099 default: break;
4100 }
4101
4102 if (exp >= minExp)
4103 {
4104 // Normal number
4105 base = deFloatLdExp(1.0f, exp);
4106 quantum = deFloatLdExp(1.0f, exp - fractionBits);
4107 }
4108 else
4109 {
4110 // Subnormal
4111 base = 0.0f;
4112 quantum = deFloatLdExp(1.0f, minExp - fractionBits);
4113 }
4114
4115 switch (rnd.getInt(0, 16))
4116 {
4117 case 0: // The highest number in this binade, significand is all bits one.
4118 significand = base - quantum;
4119 break;
4120 case 1: // Significand is one.
4121 significand = quantum;
4122 break;
4123 case 2: // Significand is zero.
4124 significand = 0.0;
4125 break;
4126 default: // Random (evenly distributed) significand.
4127 {
4128 deUint64 intFraction = rnd.getUint64() & ((1 << fractionBits) - 1);
4129 significand = float(intFraction) * quantum;
4130 }
4131 }
4132
4133 // Produce positive numbers more often than negative.
4134 return (rnd.getInt(0,3) == 0 ? -1.0f : 1.0f) * (base + significand);
4135 }
4136
4137 //! Generate a standard set of floats that should always be tested.
genFixeds(const FloatFormat & format,vector<float> & dst) const4138 void DefaultSampling<float>::genFixeds (const FloatFormat& format, vector<float>& dst) const
4139 {
4140 const int minExp = format.getMinExp();
4141 const int maxExp = format.getMaxExp();
4142 const int fractionBits = format.getFractionBits();
4143 const float minQuantum = deFloatLdExp(1.0f, minExp - fractionBits);
4144 const float minNormalized = deFloatLdExp(1.0f, minExp);
4145 const float maxQuantum = deFloatLdExp(1.0f, maxExp - fractionBits);
4146
4147 // NaN
4148 dst.push_back(TCU_NAN);
4149 // Zero
4150 dst.push_back(0.0f);
4151
4152 for (int sign = -1; sign <= 1; sign += 2)
4153 {
4154 // Smallest subnormal
4155 dst.push_back(sign * minQuantum);
4156
4157 // Largest subnormal
4158 dst.push_back(sign * (minNormalized - minQuantum));
4159
4160 // Smallest normalized
4161 dst.push_back(sign * minNormalized);
4162
4163 // Next smallest normalized
4164 dst.push_back(sign * (minNormalized + minQuantum));
4165
4166 dst.push_back(sign * 0.5f);
4167 dst.push_back(sign * 1.0f);
4168 dst.push_back(sign * 2.0f);
4169
4170 // Largest number
4171 dst.push_back(sign * (deFloatLdExp(1.0f, maxExp) +
4172 (deFloatLdExp(1.0f, maxExp) - maxQuantum)));
4173
4174 dst.push_back(sign * TCU_INFINITY);
4175 }
4176 }
4177
4178 template <typename T, int Size>
4179 class DefaultSampling<Vector<T, Size> > : public Sampling<Vector<T, Size> >
4180 {
4181 public:
4182 typedef Vector<T, Size> Value;
4183
genRandom(const FloatFormat & fmt,Precision prec,Random & rnd) const4184 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4185 {
4186 Value ret;
4187
4188 for (int ndx = 0; ndx < Size; ++ndx)
4189 ret[ndx] = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4190
4191 return ret;
4192 }
4193
genFixeds(const FloatFormat & fmt,vector<Value> & dst) const4194 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4195 {
4196 vector<T> scalars;
4197
4198 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4199
4200 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4201 dst.push_back(Value(scalars[scalarNdx]));
4202 }
4203
getWeight(void) const4204 double getWeight (void) const
4205 {
4206 return dePow(instance<DefaultSampling<T> >().getWeight(), Size);
4207 }
4208 };
4209
4210 template <typename T, int Rows, int Columns>
4211 class DefaultSampling<Matrix<T, Rows, Columns> > : public Sampling<Matrix<T, Rows, Columns> >
4212 {
4213 public:
4214 typedef Matrix<T, Rows, Columns> Value;
4215
genRandom(const FloatFormat & fmt,Precision prec,Random & rnd) const4216 Value genRandom (const FloatFormat& fmt, Precision prec, Random& rnd) const
4217 {
4218 Value ret;
4219
4220 for (int rowNdx = 0; rowNdx < Rows; ++rowNdx)
4221 for (int colNdx = 0; colNdx < Columns; ++colNdx)
4222 ret(rowNdx, colNdx) = instance<DefaultSampling<T> >().genRandom(fmt, prec, rnd);
4223
4224 return ret;
4225 }
4226
genFixeds(const FloatFormat & fmt,vector<Value> & dst) const4227 void genFixeds (const FloatFormat& fmt, vector<Value>& dst) const
4228 {
4229 vector<T> scalars;
4230
4231 instance<DefaultSampling<T> >().genFixeds(fmt, scalars);
4232
4233 for (size_t scalarNdx = 0; scalarNdx < scalars.size(); ++scalarNdx)
4234 dst.push_back(Value(scalars[scalarNdx]));
4235
4236 if (Columns == Rows)
4237 {
4238 Value mat (0.0);
4239 T x = T(1.0f);
4240 mat[0][0] = x;
4241 for (int ndx = 0; ndx < Columns; ++ndx)
4242 {
4243 mat[Columns-1-ndx][ndx] = x;
4244 x *= T(2.0f);
4245 }
4246 dst.push_back(mat);
4247 }
4248 }
4249
getWeight(void) const4250 double getWeight (void) const
4251 {
4252 return dePow(instance<DefaultSampling<T> >().getWeight(), Rows * Columns);
4253 }
4254 };
4255
4256 struct Context
4257 {
Contextdeqp::gls::BuiltinPrecisionTests::Context4258 Context (const string& name_,
4259 TestContext& testContext_,
4260 RenderContext& renderContext_,
4261 const FloatFormat& floatFormat_,
4262 const FloatFormat& highpFormat_,
4263 Precision precision_,
4264 ShaderType shaderType_,
4265 size_t numRandoms_)
4266 : name (name_)
4267 , testContext (testContext_)
4268 , renderContext (renderContext_)
4269 , floatFormat (floatFormat_)
4270 , highpFormat (highpFormat_)
4271 , precision (precision_)
4272 , shaderType (shaderType_)
4273 , numRandoms (numRandoms_) {}
4274
4275 string name;
4276 TestContext& testContext;
4277 RenderContext& renderContext;
4278 FloatFormat floatFormat;
4279 FloatFormat highpFormat;
4280 Precision precision;
4281 ShaderType shaderType;
4282 size_t numRandoms;
4283 };
4284
4285 template<typename In0_ = Void, typename In1_ = Void, typename In2_ = Void, typename In3_ = Void>
4286 struct InTypes
4287 {
4288 typedef In0_ In0;
4289 typedef In1_ In1;
4290 typedef In2_ In2;
4291 typedef In3_ In3;
4292 };
4293
4294 template <typename In>
numInputs(void)4295 int numInputs (void)
4296 {
4297 return (!isTypeValid<typename In::In0>() ? 0 :
4298 !isTypeValid<typename In::In1>() ? 1 :
4299 !isTypeValid<typename In::In2>() ? 2 :
4300 !isTypeValid<typename In::In3>() ? 3 :
4301 4);
4302 }
4303
4304 template<typename Out0_, typename Out1_ = Void>
4305 struct OutTypes
4306 {
4307 typedef Out0_ Out0;
4308 typedef Out1_ Out1;
4309 };
4310
4311 template <typename Out>
numOutputs(void)4312 int numOutputs (void)
4313 {
4314 return (!isTypeValid<typename Out::Out0>() ? 0 :
4315 !isTypeValid<typename Out::Out1>() ? 1 :
4316 2);
4317 }
4318
4319 template<typename In>
4320 struct Inputs
4321 {
4322 vector<typename In::In0> in0;
4323 vector<typename In::In1> in1;
4324 vector<typename In::In2> in2;
4325 vector<typename In::In3> in3;
4326 };
4327
4328 template<typename Out>
4329 struct Outputs
4330 {
Outputsdeqp::gls::BuiltinPrecisionTests::Outputs4331 Outputs (size_t size) : out0(size), out1(size) {}
4332
4333 vector<typename Out::Out0> out0;
4334 vector<typename Out::Out1> out1;
4335 };
4336
4337 template<typename In, typename Out>
4338 struct Variables
4339 {
4340 VariableP<typename In::In0> in0;
4341 VariableP<typename In::In1> in1;
4342 VariableP<typename In::In2> in2;
4343 VariableP<typename In::In3> in3;
4344 VariableP<typename Out::Out0> out0;
4345 VariableP<typename Out::Out1> out1;
4346 };
4347
4348 template<typename In>
4349 struct Samplings
4350 {
Samplingsdeqp::gls::BuiltinPrecisionTests::Samplings4351 Samplings (const Sampling<typename In::In0>& in0_,
4352 const Sampling<typename In::In1>& in1_,
4353 const Sampling<typename In::In2>& in2_,
4354 const Sampling<typename In::In3>& in3_)
4355 : in0 (in0_), in1 (in1_), in2 (in2_), in3 (in3_) {}
4356
4357 const Sampling<typename In::In0>& in0;
4358 const Sampling<typename In::In1>& in1;
4359 const Sampling<typename In::In2>& in2;
4360 const Sampling<typename In::In3>& in3;
4361 };
4362
4363 template<typename In>
4364 struct DefaultSamplings : Samplings<In>
4365 {
DefaultSamplingsdeqp::gls::BuiltinPrecisionTests::DefaultSamplings4366 DefaultSamplings (void)
4367 : Samplings<In>(instance<DefaultSampling<typename In::In0> >(),
4368 instance<DefaultSampling<typename In::In1> >(),
4369 instance<DefaultSampling<typename In::In2> >(),
4370 instance<DefaultSampling<typename In::In3> >()) {}
4371 };
4372
4373 class PrecisionCase : public TestCase
4374 {
4375 public:
4376 IterateResult iterate (void);
4377
4378 protected:
PrecisionCase(const Context & context,const string & name,const string & extension="")4379 PrecisionCase (const Context& context,
4380 const string& name,
4381 const string& extension = "")
4382 : TestCase (context.testContext,
4383 name.c_str(),
4384 name.c_str())
4385 , m_ctx (context)
4386 , m_status ()
4387 , m_rnd (0xdeadbeefu +
4388 context.testContext.getCommandLine().getBaseSeed())
4389 , m_extension (extension)
4390 {
4391 }
4392
getRenderContext(void) const4393 RenderContext& getRenderContext(void) const { return m_ctx.renderContext; }
4394
getFormat(void) const4395 const FloatFormat& getFormat (void) const { return m_ctx.floatFormat; }
4396
log(void) const4397 TestLog& log (void) const { return m_testCtx.getLog(); }
4398
4399 virtual void runTest (void) = 0;
4400
4401 template <typename In, typename Out>
4402 void testStatement (const Variables<In, Out>& variables,
4403 const Inputs<In>& inputs,
4404 const Statement& stmt);
4405
4406 template<typename T>
makeSymbol(const Variable<T> & variable)4407 Symbol makeSymbol (const Variable<T>& variable)
4408 {
4409 return Symbol(variable.getName(), getVarTypeOf<T>(m_ctx.precision));
4410 }
4411
4412 Context m_ctx;
4413 ResultCollector m_status;
4414 Random m_rnd;
4415 const string m_extension;
4416 };
4417
iterate(void)4418 IterateResult PrecisionCase::iterate (void)
4419 {
4420 runTest();
4421 m_status.setTestContextResult(m_testCtx);
4422 return STOP;
4423 }
4424
4425 template <typename In, typename Out>
testStatement(const Variables<In,Out> & variables,const Inputs<In> & inputs,const Statement & stmt)4426 void PrecisionCase::testStatement (const Variables<In, Out>& variables,
4427 const Inputs<In>& inputs,
4428 const Statement& stmt)
4429 {
4430 using namespace ShaderExecUtil;
4431
4432 typedef typename In::In0 In0;
4433 typedef typename In::In1 In1;
4434 typedef typename In::In2 In2;
4435 typedef typename In::In3 In3;
4436 typedef typename Out::Out0 Out0;
4437 typedef typename Out::Out1 Out1;
4438
4439 const FloatFormat& fmt = getFormat();
4440 const int inCount = numInputs<In>();
4441 const int outCount = numOutputs<Out>();
4442 const size_t numValues = (inCount > 0) ? inputs.in0.size() : 1;
4443 Outputs<Out> outputs (numValues);
4444 ShaderSpec spec;
4445 const FloatFormat highpFmt = m_ctx.highpFormat;
4446 const int maxMsgs = 100;
4447 int numErrors = 0;
4448 Environment env; // Hoisted out of the inner loop for optimization.
4449
4450 switch (inCount)
4451 {
4452 case 4: DE_ASSERT(inputs.in3.size() == numValues);
4453 case 3: DE_ASSERT(inputs.in2.size() == numValues);
4454 case 2: DE_ASSERT(inputs.in1.size() == numValues);
4455 case 1: DE_ASSERT(inputs.in0.size() == numValues);
4456 default: break;
4457 }
4458
4459 // Print out the statement and its definitions
4460 log() << TestLog::Message << "Statement: " << stmt << TestLog::EndMessage;
4461 {
4462 ostringstream oss;
4463 FuncSet funcs;
4464
4465 stmt.getUsedFuncs(funcs);
4466 for (FuncSet::const_iterator it = funcs.begin(); it != funcs.end(); ++it)
4467 {
4468 (*it)->printDefinition(oss);
4469 }
4470 if (!funcs.empty())
4471 log() << TestLog::Message << "Reference definitions:\n" << oss.str()
4472 << TestLog::EndMessage;
4473 }
4474
4475 // Initialize ShaderSpec from precision, variables and statement.
4476 {
4477 ostringstream os;
4478 os << "precision " << glu::getPrecisionName(m_ctx.precision) << " float;\n";
4479 spec.globalDeclarations = os.str();
4480 }
4481
4482 spec.version = getContextTypeGLSLVersion(getRenderContext().getType());
4483
4484 if (!m_extension.empty())
4485 spec.globalDeclarations = "#extension " + m_extension + " : require\n";
4486
4487 spec.inputs.resize(inCount);
4488
4489 switch (inCount)
4490 {
4491 case 4: spec.inputs[3] = makeSymbol(*variables.in3);
4492 case 3: spec.inputs[2] = makeSymbol(*variables.in2);
4493 case 2: spec.inputs[1] = makeSymbol(*variables.in1);
4494 case 1: spec.inputs[0] = makeSymbol(*variables.in0);
4495 default: break;
4496 }
4497
4498 spec.outputs.resize(outCount);
4499
4500 switch (outCount)
4501 {
4502 case 2: spec.outputs[1] = makeSymbol(*variables.out1);
4503 case 1: spec.outputs[0] = makeSymbol(*variables.out0);
4504 default: break;
4505 }
4506
4507 spec.source = de::toString(stmt);
4508
4509 // Run the shader with inputs.
4510 {
4511 UniquePtr<ShaderExecutor> executor (createExecutor(getRenderContext(),
4512 m_ctx.shaderType,
4513 spec));
4514 const void* inputArr[] =
4515 {
4516 &inputs.in0.front(), &inputs.in1.front(), &inputs.in2.front(), &inputs.in3.front(),
4517 };
4518 void* outputArr[] =
4519 {
4520 &outputs.out0.front(), &outputs.out1.front(),
4521 };
4522
4523 executor->log(log());
4524 if (!executor->isOk())
4525 TCU_FAIL("Shader compilation failed");
4526
4527 executor->useProgram();
4528 executor->execute(int(numValues), inputArr, outputArr);
4529 }
4530
4531 // Initialize environment with dummy values so we don't need to bind in inner loop.
4532 {
4533 const typename Traits<In0>::IVal in0;
4534 const typename Traits<In1>::IVal in1;
4535 const typename Traits<In2>::IVal in2;
4536 const typename Traits<In3>::IVal in3;
4537 const typename Traits<Out0>::IVal reference0;
4538 const typename Traits<Out1>::IVal reference1;
4539
4540 env.bind(*variables.in0, in0);
4541 env.bind(*variables.in1, in1);
4542 env.bind(*variables.in2, in2);
4543 env.bind(*variables.in3, in3);
4544 env.bind(*variables.out0, reference0);
4545 env.bind(*variables.out1, reference1);
4546 }
4547
4548 // For each input tuple, compute output reference interval and compare
4549 // shader output to the reference.
4550 for (size_t valueNdx = 0; valueNdx < numValues; valueNdx++)
4551 {
4552 bool result = true;
4553 typename Traits<Out0>::IVal reference0;
4554 typename Traits<Out1>::IVal reference1;
4555
4556 env.lookup(*variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx]));
4557 env.lookup(*variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx]));
4558 env.lookup(*variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx]));
4559 env.lookup(*variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx]));
4560
4561 {
4562 EvalContext ctx (fmt, m_ctx.precision, env);
4563 stmt.execute(ctx);
4564 }
4565
4566 switch (outCount)
4567 {
4568 case 2:
4569 reference1 = convert<Out1>(highpFmt, env.lookup(*variables.out1));
4570 if (!m_status.check(contains(reference1, outputs.out1[valueNdx]),
4571 "Shader output 1 is outside acceptable range"))
4572 result = false;
4573 case 1:
4574 reference0 = convert<Out0>(highpFmt, env.lookup(*variables.out0));
4575 if (!m_status.check(contains(reference0, outputs.out0[valueNdx]),
4576 "Shader output 0 is outside acceptable range"))
4577 result = false;
4578 default: break;
4579 }
4580
4581 if (!result)
4582 ++numErrors;
4583
4584 if ((!result && numErrors <= maxMsgs) || GLS_LOG_ALL_RESULTS)
4585 {
4586 MessageBuilder builder = log().message();
4587
4588 builder << (result ? "Passed" : "Failed") << " sample:\n";
4589
4590 if (inCount > 0)
4591 {
4592 builder << "\t" << variables.in0->getName() << " = "
4593 << valueToString(highpFmt, inputs.in0[valueNdx]) << "\n";
4594 }
4595
4596 if (inCount > 1)
4597 {
4598 builder << "\t" << variables.in1->getName() << " = "
4599 << valueToString(highpFmt, inputs.in1[valueNdx]) << "\n";
4600 }
4601
4602 if (inCount > 2)
4603 {
4604 builder << "\t" << variables.in2->getName() << " = "
4605 << valueToString(highpFmt, inputs.in2[valueNdx]) << "\n";
4606 }
4607
4608 if (inCount > 3)
4609 {
4610 builder << "\t" << variables.in3->getName() << " = "
4611 << valueToString(highpFmt, inputs.in3[valueNdx]) << "\n";
4612 }
4613
4614 if (outCount > 0)
4615 {
4616 builder << "\t" << variables.out0->getName() << " = "
4617 << valueToString(highpFmt, outputs.out0[valueNdx]) << "\n"
4618 << "\tExpected range: "
4619 << intervalToString<typename Out::Out0>(highpFmt, reference0) << "\n";
4620 }
4621
4622 if (outCount > 1)
4623 {
4624 builder << "\t" << variables.out1->getName() << " = "
4625 << valueToString(highpFmt, outputs.out1[valueNdx]) << "\n"
4626 << "\tExpected range: "
4627 << intervalToString<typename Out::Out1>(highpFmt, reference1) << "\n";
4628 }
4629
4630 builder << TestLog::EndMessage;
4631 }
4632 }
4633
4634 if (numErrors > maxMsgs)
4635 {
4636 log() << TestLog::Message << "(Skipped " << (numErrors - maxMsgs) << " messages.)"
4637 << TestLog::EndMessage;
4638 }
4639
4640 if (numErrors == 0)
4641 {
4642 log() << TestLog::Message << "All " << numValues << " inputs passed."
4643 << TestLog::EndMessage;
4644 }
4645 else
4646 {
4647 log() << TestLog::Message << numErrors << "/" << numValues << " inputs failed."
4648 << TestLog::EndMessage;
4649 }
4650 }
4651
4652
4653
4654 template <typename T>
4655 struct InputLess
4656 {
operator ()deqp::gls::BuiltinPrecisionTests::InputLess4657 bool operator() (const T& val1, const T& val2) const
4658 {
4659 return val1 < val2;
4660 }
4661 };
4662
4663 template <typename T>
inputLess(const T & val1,const T & val2)4664 bool inputLess (const T& val1, const T& val2)
4665 {
4666 return InputLess<T>()(val1, val2);
4667 }
4668
4669 template <>
4670 struct InputLess<float>
4671 {
operator ()deqp::gls::BuiltinPrecisionTests::InputLess4672 bool operator() (const float& val1, const float& val2) const
4673 {
4674 if (deIsNaN(val1))
4675 return false;
4676 if (deIsNaN(val2))
4677 return true;
4678 return val1 < val2;
4679 }
4680 };
4681
4682 template <typename T, int Size>
4683 struct InputLess<Vector<T, Size> >
4684 {
operator ()deqp::gls::BuiltinPrecisionTests::InputLess4685 bool operator() (const Vector<T, Size>& vec1, const Vector<T, Size>& vec2) const
4686 {
4687 for (int ndx = 0; ndx < Size; ++ndx)
4688 {
4689 if (inputLess(vec1[ndx], vec2[ndx]))
4690 return true;
4691 if (inputLess(vec2[ndx], vec1[ndx]))
4692 return false;
4693 }
4694
4695 return false;
4696 }
4697 };
4698
4699 template <typename T, int Rows, int Cols>
4700 struct InputLess<Matrix<T, Rows, Cols> >
4701 {
operator ()deqp::gls::BuiltinPrecisionTests::InputLess4702 bool operator() (const Matrix<T, Rows, Cols>& mat1,
4703 const Matrix<T, Rows, Cols>& mat2) const
4704 {
4705 for (int col = 0; col < Cols; ++col)
4706 {
4707 if (inputLess(mat1[col], mat2[col]))
4708 return true;
4709 if (inputLess(mat2[col], mat1[col]))
4710 return false;
4711 }
4712
4713 return false;
4714 }
4715 };
4716
4717 template <typename In>
4718 struct InTuple :
4719 public Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4720 {
InTupledeqp::gls::BuiltinPrecisionTests::InTuple4721 InTuple (const typename In::In0& in0,
4722 const typename In::In1& in1,
4723 const typename In::In2& in2,
4724 const typename In::In3& in3)
4725 : Tuple4<typename In::In0, typename In::In1, typename In::In2, typename In::In3>
4726 (in0, in1, in2, in3) {}
4727 };
4728
4729 template <typename In>
4730 struct InputLess<InTuple<In> >
4731 {
operator ()deqp::gls::BuiltinPrecisionTests::InputLess4732 bool operator() (const InTuple<In>& in1, const InTuple<In>& in2) const
4733 {
4734 if (inputLess(in1.a, in2.a))
4735 return true;
4736 if (inputLess(in2.a, in1.a))
4737 return false;
4738 if (inputLess(in1.b, in2.b))
4739 return true;
4740 if (inputLess(in2.b, in1.b))
4741 return false;
4742 if (inputLess(in1.c, in2.c))
4743 return true;
4744 if (inputLess(in2.c, in1.c))
4745 return false;
4746 if (inputLess(in1.d, in2.d))
4747 return true;
4748 return false;
4749 };
4750 };
4751
4752 template<typename In>
generateInputs(const Samplings<In> & samplings,const FloatFormat & floatFormat,Precision intPrecision,size_t numSamples,Random & rnd)4753 Inputs<In> generateInputs (const Samplings<In>& samplings,
4754 const FloatFormat& floatFormat,
4755 Precision intPrecision,
4756 size_t numSamples,
4757 Random& rnd)
4758 {
4759 Inputs<In> ret;
4760 Inputs<In> fixedInputs;
4761 set<InTuple<In>, InputLess<InTuple<In> > > seenInputs;
4762
4763 samplings.in0.genFixeds(floatFormat, fixedInputs.in0);
4764 samplings.in1.genFixeds(floatFormat, fixedInputs.in1);
4765 samplings.in2.genFixeds(floatFormat, fixedInputs.in2);
4766 samplings.in3.genFixeds(floatFormat, fixedInputs.in3);
4767
4768 for (size_t ndx0 = 0; ndx0 < fixedInputs.in0.size(); ++ndx0)
4769 {
4770 for (size_t ndx1 = 0; ndx1 < fixedInputs.in1.size(); ++ndx1)
4771 {
4772 for (size_t ndx2 = 0; ndx2 < fixedInputs.in2.size(); ++ndx2)
4773 {
4774 for (size_t ndx3 = 0; ndx3 < fixedInputs.in3.size(); ++ndx3)
4775 {
4776 const InTuple<In> tuple (fixedInputs.in0[ndx0],
4777 fixedInputs.in1[ndx1],
4778 fixedInputs.in2[ndx2],
4779 fixedInputs.in3[ndx3]);
4780
4781 seenInputs.insert(tuple);
4782 ret.in0.push_back(tuple.a);
4783 ret.in1.push_back(tuple.b);
4784 ret.in2.push_back(tuple.c);
4785 ret.in3.push_back(tuple.d);
4786 }
4787 }
4788 }
4789 }
4790
4791 for (size_t ndx = 0; ndx < numSamples; ++ndx)
4792 {
4793 const typename In::In0 in0 = samplings.in0.genRandom(floatFormat, intPrecision, rnd);
4794 const typename In::In1 in1 = samplings.in1.genRandom(floatFormat, intPrecision, rnd);
4795 const typename In::In2 in2 = samplings.in2.genRandom(floatFormat, intPrecision, rnd);
4796 const typename In::In3 in3 = samplings.in3.genRandom(floatFormat, intPrecision, rnd);
4797 const InTuple<In> tuple (in0, in1, in2, in3);
4798
4799 if (de::contains(seenInputs, tuple))
4800 continue;
4801
4802 seenInputs.insert(tuple);
4803 ret.in0.push_back(in0);
4804 ret.in1.push_back(in1);
4805 ret.in2.push_back(in2);
4806 ret.in3.push_back(in3);
4807 }
4808
4809 return ret;
4810 }
4811
4812 class FuncCaseBase : public PrecisionCase
4813 {
4814 public:
4815 IterateResult iterate (void);
4816
4817 protected:
FuncCaseBase(const Context & context,const string & name,const FuncBase & func)4818 FuncCaseBase (const Context& context,
4819 const string& name,
4820 const FuncBase& func)
4821 : PrecisionCase (context, name, func.getRequiredExtension()) {}
4822 };
4823
iterate(void)4824 IterateResult FuncCaseBase::iterate (void)
4825 {
4826 MovePtr<ContextInfo> info (ContextInfo::create(getRenderContext()));
4827
4828 if (!m_extension.empty() && !info->isExtensionSupported(m_extension.c_str()))
4829 throw NotSupportedError("Unsupported extension: " + m_extension);
4830
4831 runTest();
4832
4833 m_status.setTestContextResult(m_testCtx);
4834 return STOP;
4835 }
4836
4837 template <typename Sig>
4838 class FuncCase : public FuncCaseBase
4839 {
4840 public:
4841 typedef Func<Sig> CaseFunc;
4842 typedef typename Sig::Ret Ret;
4843 typedef typename Sig::Arg0 Arg0;
4844 typedef typename Sig::Arg1 Arg1;
4845 typedef typename Sig::Arg2 Arg2;
4846 typedef typename Sig::Arg3 Arg3;
4847 typedef InTypes<Arg0, Arg1, Arg2, Arg3> In;
4848 typedef OutTypes<Ret> Out;
4849
FuncCase(const Context & context,const string & name,const CaseFunc & func)4850 FuncCase (const Context& context,
4851 const string& name,
4852 const CaseFunc& func)
4853 : FuncCaseBase (context, name, func)
4854 , m_func (func) {}
4855
4856 protected:
4857 void runTest (void);
4858
getSamplings(void)4859 virtual const Samplings<In>& getSamplings (void)
4860 {
4861 return instance<DefaultSamplings<In> >();
4862 }
4863
4864 private:
4865 const CaseFunc& m_func;
4866 };
4867
4868 template <typename Sig>
runTest(void)4869 void FuncCase<Sig>::runTest (void)
4870 {
4871 const Inputs<In> inputs (generateInputs(getSamplings(),
4872 m_ctx.floatFormat,
4873 m_ctx.precision,
4874 m_ctx.numRandoms,
4875 m_rnd));
4876 Variables<In, Out> variables;
4877
4878 variables.out0 = variable<Ret>("out0");
4879 variables.out1 = variable<Void>("out1");
4880 variables.in0 = variable<Arg0>("in0");
4881 variables.in1 = variable<Arg1>("in1");
4882 variables.in2 = variable<Arg2>("in2");
4883 variables.in3 = variable<Arg3>("in3");
4884
4885 {
4886 ExprP<Ret> expr = applyVar(m_func,
4887 variables.in0, variables.in1,
4888 variables.in2, variables.in3);
4889 StatementP stmt = variableAssignment(variables.out0, expr);
4890
4891 this->testStatement(variables, inputs, *stmt);
4892 }
4893 }
4894
4895 template <typename Sig>
4896 class InOutFuncCase : public FuncCaseBase
4897 {
4898 public:
4899 typedef Func<Sig> CaseFunc;
4900 typedef typename Sig::Ret Ret;
4901 typedef typename Sig::Arg0 Arg0;
4902 typedef typename Sig::Arg1 Arg1;
4903 typedef typename Sig::Arg2 Arg2;
4904 typedef typename Sig::Arg3 Arg3;
4905 typedef InTypes<Arg0, Arg2, Arg3> In;
4906 typedef OutTypes<Ret, Arg1> Out;
4907
InOutFuncCase(const Context & context,const string & name,const CaseFunc & func)4908 InOutFuncCase (const Context& context,
4909 const string& name,
4910 const CaseFunc& func)
4911 : FuncCaseBase (context, name, func)
4912 , m_func (func) {}
4913
4914 protected:
4915 void runTest (void);
4916
getSamplings(void)4917 virtual const Samplings<In>& getSamplings (void)
4918 {
4919 return instance<DefaultSamplings<In> >();
4920 }
4921
4922 private:
4923 const CaseFunc& m_func;
4924 };
4925
4926 template <typename Sig>
runTest(void)4927 void InOutFuncCase<Sig>::runTest (void)
4928 {
4929 const Inputs<In> inputs (generateInputs(getSamplings(),
4930 m_ctx.floatFormat,
4931 m_ctx.precision,
4932 m_ctx.numRandoms,
4933 m_rnd));
4934 Variables<In, Out> variables;
4935
4936 variables.out0 = variable<Ret>("out0");
4937 variables.out1 = variable<Arg1>("out1");
4938 variables.in0 = variable<Arg0>("in0");
4939 variables.in1 = variable<Arg2>("in1");
4940 variables.in2 = variable<Arg3>("in2");
4941 variables.in3 = variable<Void>("in3");
4942
4943 {
4944 ExprP<Ret> expr = applyVar(m_func,
4945 variables.in0, variables.out1,
4946 variables.in1, variables.in2);
4947 StatementP stmt = variableAssignment(variables.out0, expr);
4948
4949 this->testStatement(variables, inputs, *stmt);
4950 }
4951 }
4952
4953 template <typename Sig>
createFuncCase(const Context & context,const string & name,const Func<Sig> & func)4954 PrecisionCase* createFuncCase (const Context& context,
4955 const string& name,
4956 const Func<Sig>& func)
4957 {
4958 switch (func.getOutParamIndex())
4959 {
4960 case -1:
4961 return new FuncCase<Sig>(context, name, func);
4962 case 1:
4963 return new InOutFuncCase<Sig>(context, name, func);
4964 default:
4965 DE_ASSERT(!"Impossible");
4966 }
4967 return DE_NULL;
4968 }
4969
4970 class CaseFactory
4971 {
4972 public:
~CaseFactory(void)4973 virtual ~CaseFactory (void) {}
4974 virtual MovePtr<TestNode> createCase (const Context& ctx) const = 0;
4975 virtual string getName (void) const = 0;
4976 virtual string getDesc (void) const = 0;
4977 };
4978
4979 class FuncCaseFactory : public CaseFactory
4980 {
4981 public:
4982 virtual const FuncBase& getFunc (void) const = 0;
4983
getName(void) const4984 string getName (void) const
4985 {
4986 return de::toLower(getFunc().getName());
4987 }
4988
getDesc(void) const4989 string getDesc (void) const
4990 {
4991 return "Function '" + getFunc().getName() + "'";
4992 }
4993 };
4994
4995 template <typename Sig>
4996 class GenFuncCaseFactory : public CaseFactory
4997 {
4998 public:
4999
GenFuncCaseFactory(const GenFuncs<Sig> & funcs,const string & name)5000 GenFuncCaseFactory (const GenFuncs<Sig>& funcs,
5001 const string& name)
5002 : m_funcs (funcs)
5003 , m_name (de::toLower(name)) {}
5004
createCase(const Context & ctx) const5005 MovePtr<TestNode> createCase (const Context& ctx) const
5006 {
5007 TestCaseGroup* group = new TestCaseGroup(ctx.testContext,
5008 ctx.name.c_str(), ctx.name.c_str());
5009
5010 group->addChild(createFuncCase(ctx, "scalar", m_funcs.func));
5011 group->addChild(createFuncCase(ctx, "vec2", m_funcs.func2));
5012 group->addChild(createFuncCase(ctx, "vec3", m_funcs.func3));
5013 group->addChild(createFuncCase(ctx, "vec4", m_funcs.func4));
5014
5015 return MovePtr<TestNode>(group);
5016 }
5017
getName(void) const5018 string getName (void) const
5019 {
5020 return m_name;
5021 }
5022
getDesc(void) const5023 string getDesc (void) const
5024 {
5025 return "Function '" + m_funcs.func.getName() + "'";
5026 }
5027
5028 private:
5029 const GenFuncs<Sig> m_funcs;
5030 string m_name;
5031 };
5032
5033 template <template <int> class GenF>
5034 class TemplateFuncCaseFactory : public FuncCaseFactory
5035 {
5036 public:
createCase(const Context & ctx) const5037 MovePtr<TestNode> createCase (const Context& ctx) const
5038 {
5039 TestCaseGroup* group = new TestCaseGroup(ctx.testContext,
5040 ctx.name.c_str(), ctx.name.c_str());
5041 group->addChild(createFuncCase(ctx, "scalar", instance<GenF<1> >()));
5042 group->addChild(createFuncCase(ctx, "vec2", instance<GenF<2> >()));
5043 group->addChild(createFuncCase(ctx, "vec3", instance<GenF<3> >()));
5044 group->addChild(createFuncCase(ctx, "vec4", instance<GenF<4> >()));
5045
5046 return MovePtr<TestNode>(group);
5047 }
5048
getFunc(void) const5049 const FuncBase& getFunc (void) const { return instance<GenF<1> >(); }
5050 };
5051
5052 template <template <int> class GenF>
5053 class SquareMatrixFuncCaseFactory : public FuncCaseFactory
5054 {
5055 public:
createCase(const Context & ctx) const5056 MovePtr<TestNode> createCase (const Context& ctx) const
5057 {
5058 TestCaseGroup* group = new TestCaseGroup(ctx.testContext,
5059 ctx.name.c_str(), ctx.name.c_str());
5060 group->addChild(createFuncCase(ctx, "mat2", instance<GenF<2> >()));
5061 #if 0
5062 // disabled until we get reasonable results
5063 group->addChild(createFuncCase(ctx, "mat3", instance<GenF<3> >()));
5064 group->addChild(createFuncCase(ctx, "mat4", instance<GenF<4> >()));
5065 #endif
5066
5067 return MovePtr<TestNode>(group);
5068 }
5069
getFunc(void) const5070 const FuncBase& getFunc (void) const { return instance<GenF<2> >(); }
5071 };
5072
5073 template <template <int, int> class GenF>
5074 class MatrixFuncCaseFactory : public FuncCaseFactory
5075 {
5076 public:
createCase(const Context & ctx) const5077 MovePtr<TestNode> createCase (const Context& ctx) const
5078 {
5079 TestCaseGroup* const group = new TestCaseGroup(ctx.testContext,
5080 ctx.name.c_str(), ctx.name.c_str());
5081
5082 this->addCase<2, 2>(ctx, group);
5083 this->addCase<3, 2>(ctx, group);
5084 this->addCase<4, 2>(ctx, group);
5085 this->addCase<2, 3>(ctx, group);
5086 this->addCase<3, 3>(ctx, group);
5087 this->addCase<4, 3>(ctx, group);
5088 this->addCase<2, 4>(ctx, group);
5089 this->addCase<3, 4>(ctx, group);
5090 this->addCase<4, 4>(ctx, group);
5091
5092 return MovePtr<TestNode>(group);
5093 }
5094
getFunc(void) const5095 const FuncBase& getFunc (void) const { return instance<GenF<2,2> >(); }
5096
5097 private:
5098 template <int Rows, int Cols>
addCase(const Context & ctx,TestCaseGroup * group) const5099 void addCase (const Context& ctx, TestCaseGroup* group) const
5100 {
5101 const char* const name = dataTypeNameOf<Matrix<float, Rows, Cols> >();
5102
5103 group->addChild(createFuncCase(ctx, name, instance<GenF<Rows, Cols> >()));
5104 }
5105 };
5106
5107 template <typename Sig>
5108 class SimpleFuncCaseFactory : public CaseFactory
5109 {
5110 public:
SimpleFuncCaseFactory(const Func<Sig> & func)5111 SimpleFuncCaseFactory (const Func<Sig>& func) : m_func(func) {}
5112
createCase(const Context & ctx) const5113 MovePtr<TestNode> createCase (const Context& ctx) const
5114 {
5115 return MovePtr<TestNode>(createFuncCase(ctx, ctx.name.c_str(), m_func));
5116 }
5117
getName(void) const5118 string getName (void) const
5119 {
5120 return de::toLower(m_func.getName());
5121 }
5122
getDesc(void) const5123 string getDesc (void) const
5124 {
5125 return "Function '" + getName() + "'";
5126 }
5127
5128 private:
5129 const Func<Sig>& m_func;
5130 };
5131
5132 template <typename F>
createSimpleFuncCaseFactory(void)5133 SharedPtr<SimpleFuncCaseFactory<typename F::Sig> > createSimpleFuncCaseFactory (void)
5134 {
5135 return SharedPtr<SimpleFuncCaseFactory<typename F::Sig> >(
5136 new SimpleFuncCaseFactory<typename F::Sig>(instance<F>()));
5137 }
5138
5139 class BuiltinFuncs : public CaseFactories
5140 {
5141 public:
getFactories(void) const5142 const vector<const CaseFactory*> getFactories (void) const
5143 {
5144 vector<const CaseFactory*> ret;
5145
5146 for (size_t ndx = 0; ndx < m_factories.size(); ++ndx)
5147 ret.push_back(m_factories[ndx].get());
5148
5149 return ret;
5150 }
5151
addFactory(SharedPtr<const CaseFactory> fact)5152 void addFactory (SharedPtr<const CaseFactory> fact)
5153 {
5154 m_factories.push_back(fact);
5155 }
5156
5157 private:
5158 vector<SharedPtr<const CaseFactory> > m_factories;
5159 };
5160
5161 template <typename F>
addScalarFactory(BuiltinFuncs & funcs,string name="")5162 void addScalarFactory(BuiltinFuncs& funcs, string name = "")
5163 {
5164 if (name.empty())
5165 name = instance<F>().getName();
5166
5167 funcs.addFactory(SharedPtr<const CaseFactory>(new GenFuncCaseFactory<typename F::Sig>(
5168 makeVectorizedFuncs<F>(), name)));
5169 }
5170
createES3BuiltinCases(void)5171 MovePtr<const CaseFactories> createES3BuiltinCases (void)
5172 {
5173 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5174
5175 addScalarFactory<Add>(*funcs);
5176 addScalarFactory<Sub>(*funcs);
5177 addScalarFactory<Mul>(*funcs);
5178 addScalarFactory<Div>(*funcs);
5179
5180 addScalarFactory<Radians>(*funcs);
5181 addScalarFactory<Degrees>(*funcs);
5182 addScalarFactory<Sin>(*funcs);
5183 addScalarFactory<Cos>(*funcs);
5184 addScalarFactory<Tan>(*funcs);
5185 addScalarFactory<ASin>(*funcs);
5186 addScalarFactory<ACos>(*funcs);
5187 addScalarFactory<ATan2>(*funcs, "atan2");
5188 addScalarFactory<ATan>(*funcs);
5189 addScalarFactory<Sinh>(*funcs);
5190 addScalarFactory<Cosh>(*funcs);
5191 addScalarFactory<Tanh>(*funcs);
5192 addScalarFactory<ASinh>(*funcs);
5193 addScalarFactory<ACosh>(*funcs);
5194 addScalarFactory<ATanh>(*funcs);
5195
5196 addScalarFactory<Pow>(*funcs);
5197 addScalarFactory<Exp>(*funcs);
5198 addScalarFactory<Log>(*funcs);
5199 addScalarFactory<Exp2>(*funcs);
5200 addScalarFactory<Log2>(*funcs);
5201 addScalarFactory<Sqrt>(*funcs);
5202 addScalarFactory<InverseSqrt>(*funcs);
5203
5204 addScalarFactory<Abs>(*funcs);
5205 addScalarFactory<Sign>(*funcs);
5206 addScalarFactory<Floor>(*funcs);
5207 addScalarFactory<Trunc>(*funcs);
5208 addScalarFactory<Round>(*funcs);
5209 addScalarFactory<RoundEven>(*funcs);
5210 addScalarFactory<Ceil>(*funcs);
5211 addScalarFactory<Fract>(*funcs);
5212 addScalarFactory<Mod>(*funcs);
5213 funcs->addFactory(createSimpleFuncCaseFactory<Modf>());
5214 addScalarFactory<Min>(*funcs);
5215 addScalarFactory<Max>(*funcs);
5216 addScalarFactory<Clamp>(*funcs);
5217 addScalarFactory<Mix>(*funcs);
5218 addScalarFactory<Step>(*funcs);
5219 addScalarFactory<SmoothStep>(*funcs);
5220
5221 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Length>()));
5222 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Distance>()));
5223 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Dot>()));
5224 funcs->addFactory(createSimpleFuncCaseFactory<Cross>());
5225 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Normalize>()));
5226 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<FaceForward>()));
5227 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Reflect>()));
5228 funcs->addFactory(SharedPtr<const CaseFactory>(new TemplateFuncCaseFactory<Refract>()));
5229
5230
5231 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<MatrixCompMult>()));
5232 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<OuterProduct>()));
5233 funcs->addFactory(SharedPtr<const CaseFactory>(new MatrixFuncCaseFactory<Transpose>()));
5234 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Determinant>()));
5235 funcs->addFactory(SharedPtr<const CaseFactory>(new SquareMatrixFuncCaseFactory<Inverse>()));
5236
5237 return MovePtr<const CaseFactories>(funcs.release());
5238 }
5239
createES31BuiltinCases(void)5240 MovePtr<const CaseFactories> createES31BuiltinCases (void)
5241 {
5242 MovePtr<BuiltinFuncs> funcs (new BuiltinFuncs());
5243
5244 addScalarFactory<FrExp>(*funcs);
5245 addScalarFactory<LdExp>(*funcs);
5246 addScalarFactory<Fma>(*funcs);
5247
5248 return MovePtr<const CaseFactories>(funcs.release());
5249 }
5250
5251 struct PrecisionTestContext
5252 {
PrecisionTestContextdeqp::gls::BuiltinPrecisionTests::PrecisionTestContext5253 PrecisionTestContext (TestContext& testCtx_,
5254 RenderContext& renderCtx_,
5255 const FloatFormat& highp_,
5256 const FloatFormat& mediump_,
5257 const FloatFormat& lowp_,
5258 const vector<ShaderType>& shaderTypes_,
5259 int numRandoms_)
5260 : testCtx (testCtx_)
5261 , renderCtx (renderCtx_)
5262 , shaderTypes (shaderTypes_)
5263 , numRandoms (numRandoms_)
5264 {
5265 formats[glu::PRECISION_HIGHP] = &highp_;
5266 formats[glu::PRECISION_MEDIUMP] = &mediump_;
5267 formats[glu::PRECISION_LOWP] = &lowp_;
5268 }
5269
5270 TestContext& testCtx;
5271 RenderContext& renderCtx;
5272 const FloatFormat* formats[glu::PRECISION_LAST];
5273 vector<ShaderType> shaderTypes;
5274 int numRandoms;
5275 };
5276
createFuncGroup(const PrecisionTestContext & ctx,const CaseFactory & factory)5277 TestCaseGroup* createFuncGroup (const PrecisionTestContext& ctx,
5278 const CaseFactory& factory)
5279 {
5280 TestCaseGroup* const group = new TestCaseGroup(ctx.testCtx,
5281 factory.getName().c_str(),
5282 factory.getDesc().c_str());
5283
5284 for (int precNdx = 0; precNdx < glu::PRECISION_LAST; ++precNdx)
5285 {
5286 const Precision precision = Precision(precNdx);
5287 const string precName (glu::getPrecisionName(precision));
5288 const FloatFormat& fmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats, precNdx);
5289 const FloatFormat& highpFmt = *de::getSizedArrayElement<glu::PRECISION_LAST>(ctx.formats,
5290 glu::PRECISION_HIGHP);
5291
5292 for (size_t shaderNdx = 0; shaderNdx < ctx.shaderTypes.size(); ++shaderNdx)
5293 {
5294 const ShaderType shaderType = ctx.shaderTypes[shaderNdx];
5295 const string shaderName (glu::getShaderTypeName(shaderType));
5296 const string name = precName + "_" + shaderName;
5297 const Context caseCtx (name, ctx.testCtx, ctx.renderCtx, fmt, highpFmt,
5298 precision, shaderType, ctx.numRandoms);
5299
5300 group->addChild(factory.createCase(caseCtx).release());
5301 }
5302 }
5303
5304 return group;
5305 }
5306
addBuiltinPrecisionTests(TestContext & testCtx,RenderContext & renderCtx,const CaseFactories & cases,const vector<ShaderType> & shaderTypes,TestCaseGroup & dstGroup)5307 void addBuiltinPrecisionTests (TestContext& testCtx,
5308 RenderContext& renderCtx,
5309 const CaseFactories& cases,
5310 const vector<ShaderType>& shaderTypes,
5311 TestCaseGroup& dstGroup)
5312 {
5313 const int userRandoms = testCtx.getCommandLine().getTestIterationCount();
5314 const int defRandoms = 16384;
5315 const int numRandoms = userRandoms > 0 ? userRandoms : defRandoms;
5316 const FloatFormat highp (-126, 127, 23, true,
5317 tcu::MAYBE, // subnormals
5318 tcu::YES, // infinities
5319 tcu::MAYBE); // NaN
5320 // \todo [2014-04-01 lauri] Check these once Khronos bug 11840 is resolved.
5321 const FloatFormat mediump (-13, 13, 9, false);
5322 // A fixed-point format is just a floating point format with a fixed
5323 // exponent and support for subnormals.
5324 const FloatFormat lowp (0, 0, 7, false, tcu::YES);
5325 const PrecisionTestContext ctx (testCtx, renderCtx, highp, mediump, lowp,
5326 shaderTypes, numRandoms);
5327
5328 for (size_t ndx = 0; ndx < cases.getFactories().size(); ++ndx)
5329 dstGroup.addChild(createFuncGroup(ctx, *cases.getFactories()[ndx]));
5330 }
5331
5332 } // BuiltinPrecisionTests
5333 } // gls
5334 } // deqp
5335