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