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