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