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