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