xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fShaderCommonFunctionTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1*35238bceSAndroid Build Coastguard Worker /*-------------------------------------------------------------------------
2*35238bceSAndroid Build Coastguard Worker  * drawElements Quality Program OpenGL ES 3.1 Module
3*35238bceSAndroid Build Coastguard Worker  * -------------------------------------------------
4*35238bceSAndroid Build Coastguard Worker  *
5*35238bceSAndroid Build Coastguard Worker  * Copyright 2014 The Android Open Source Project
6*35238bceSAndroid Build Coastguard Worker  *
7*35238bceSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
8*35238bceSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
9*35238bceSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
10*35238bceSAndroid Build Coastguard Worker  *
11*35238bceSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
12*35238bceSAndroid Build Coastguard Worker  *
13*35238bceSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
14*35238bceSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
15*35238bceSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*35238bceSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
17*35238bceSAndroid Build Coastguard Worker  * limitations under the License.
18*35238bceSAndroid Build Coastguard Worker  *
19*35238bceSAndroid Build Coastguard Worker  *//*!
20*35238bceSAndroid Build Coastguard Worker  * \file
21*35238bceSAndroid Build Coastguard Worker  * \brief Common built-in function tests.
22*35238bceSAndroid Build Coastguard Worker  *//*--------------------------------------------------------------------*/
23*35238bceSAndroid Build Coastguard Worker 
24*35238bceSAndroid Build Coastguard Worker #include "es31fShaderCommonFunctionTests.hpp"
25*35238bceSAndroid Build Coastguard Worker #include "gluContextInfo.hpp"
26*35238bceSAndroid Build Coastguard Worker #include "glsShaderExecUtil.hpp"
27*35238bceSAndroid Build Coastguard Worker #include "tcuTestLog.hpp"
28*35238bceSAndroid Build Coastguard Worker #include "tcuFormatUtil.hpp"
29*35238bceSAndroid Build Coastguard Worker #include "tcuFloat.hpp"
30*35238bceSAndroid Build Coastguard Worker #include "tcuInterval.hpp"
31*35238bceSAndroid Build Coastguard Worker #include "tcuFloatFormat.hpp"
32*35238bceSAndroid Build Coastguard Worker #include "tcuVectorUtil.hpp"
33*35238bceSAndroid Build Coastguard Worker #include "deRandom.hpp"
34*35238bceSAndroid Build Coastguard Worker #include "deMath.h"
35*35238bceSAndroid Build Coastguard Worker #include "deString.h"
36*35238bceSAndroid Build Coastguard Worker #include "deArrayUtil.hpp"
37*35238bceSAndroid Build Coastguard Worker 
38*35238bceSAndroid Build Coastguard Worker namespace deqp
39*35238bceSAndroid Build Coastguard Worker {
40*35238bceSAndroid Build Coastguard Worker namespace gles31
41*35238bceSAndroid Build Coastguard Worker {
42*35238bceSAndroid Build Coastguard Worker namespace Functional
43*35238bceSAndroid Build Coastguard Worker {
44*35238bceSAndroid Build Coastguard Worker 
45*35238bceSAndroid Build Coastguard Worker using std::string;
46*35238bceSAndroid Build Coastguard Worker using std::vector;
47*35238bceSAndroid Build Coastguard Worker using tcu::TestLog;
48*35238bceSAndroid Build Coastguard Worker using namespace gls::ShaderExecUtil;
49*35238bceSAndroid Build Coastguard Worker 
50*35238bceSAndroid Build Coastguard Worker using tcu::IVec2;
51*35238bceSAndroid Build Coastguard Worker using tcu::IVec3;
52*35238bceSAndroid Build Coastguard Worker using tcu::IVec4;
53*35238bceSAndroid Build Coastguard Worker using tcu::Vec2;
54*35238bceSAndroid Build Coastguard Worker using tcu::Vec3;
55*35238bceSAndroid Build Coastguard Worker using tcu::Vec4;
56*35238bceSAndroid Build Coastguard Worker 
57*35238bceSAndroid Build Coastguard Worker // Utilities
58*35238bceSAndroid Build Coastguard Worker 
59*35238bceSAndroid Build Coastguard Worker template <typename T, int Size>
60*35238bceSAndroid Build Coastguard Worker struct VecArrayAccess
61*35238bceSAndroid Build Coastguard Worker {
62*35238bceSAndroid Build Coastguard Worker public:
VecArrayAccessdeqp::gles31::Functional::VecArrayAccess63*35238bceSAndroid Build Coastguard Worker     VecArrayAccess(const void *ptr) : m_array((tcu::Vector<T, Size> *)ptr)
64*35238bceSAndroid Build Coastguard Worker     {
65*35238bceSAndroid Build Coastguard Worker     }
~VecArrayAccessdeqp::gles31::Functional::VecArrayAccess66*35238bceSAndroid Build Coastguard Worker     ~VecArrayAccess(void)
67*35238bceSAndroid Build Coastguard Worker     {
68*35238bceSAndroid Build Coastguard Worker     }
69*35238bceSAndroid Build Coastguard Worker 
operator []deqp::gles31::Functional::VecArrayAccess70*35238bceSAndroid Build Coastguard Worker     const tcu::Vector<T, Size> &operator[](size_t offset) const
71*35238bceSAndroid Build Coastguard Worker     {
72*35238bceSAndroid Build Coastguard Worker         return m_array[offset];
73*35238bceSAndroid Build Coastguard Worker     }
operator []deqp::gles31::Functional::VecArrayAccess74*35238bceSAndroid Build Coastguard Worker     tcu::Vector<T, Size> &operator[](size_t offset)
75*35238bceSAndroid Build Coastguard Worker     {
76*35238bceSAndroid Build Coastguard Worker         return m_array[offset];
77*35238bceSAndroid Build Coastguard Worker     }
78*35238bceSAndroid Build Coastguard Worker 
79*35238bceSAndroid Build Coastguard Worker private:
80*35238bceSAndroid Build Coastguard Worker     tcu::Vector<T, Size> *m_array;
81*35238bceSAndroid Build Coastguard Worker };
82*35238bceSAndroid Build Coastguard Worker 
83*35238bceSAndroid Build Coastguard Worker template <typename T, int Size>
fillRandomVectors(de::Random & rnd,const tcu::Vector<T,Size> & minValue,const tcu::Vector<T,Size> & maxValue,void * dst,int numValues,int offset=0)84*35238bceSAndroid Build Coastguard Worker static void fillRandomVectors(de::Random &rnd, const tcu::Vector<T, Size> &minValue,
85*35238bceSAndroid Build Coastguard Worker                               const tcu::Vector<T, Size> &maxValue, void *dst, int numValues, int offset = 0)
86*35238bceSAndroid Build Coastguard Worker {
87*35238bceSAndroid Build Coastguard Worker     VecArrayAccess<T, Size> access(dst);
88*35238bceSAndroid Build Coastguard Worker     for (int ndx = 0; ndx < numValues; ndx++)
89*35238bceSAndroid Build Coastguard Worker         access[offset + ndx] = tcu::randomVector<T, Size>(rnd, minValue, maxValue);
90*35238bceSAndroid Build Coastguard Worker }
91*35238bceSAndroid Build Coastguard Worker 
92*35238bceSAndroid Build Coastguard Worker template <typename T>
fillRandomScalars(de::Random & rnd,T minValue,T maxValue,void * dst,int numValues,int offset=0)93*35238bceSAndroid Build Coastguard Worker static void fillRandomScalars(de::Random &rnd, T minValue, T maxValue, void *dst, int numValues, int offset = 0)
94*35238bceSAndroid Build Coastguard Worker {
95*35238bceSAndroid Build Coastguard Worker     T *typedPtr = (T *)dst;
96*35238bceSAndroid Build Coastguard Worker     for (int ndx = 0; ndx < numValues; ndx++)
97*35238bceSAndroid Build Coastguard Worker         typedPtr[offset + ndx] = de::randomScalar<T>(rnd, minValue, maxValue);
98*35238bceSAndroid Build Coastguard Worker }
99*35238bceSAndroid Build Coastguard Worker 
numBitsLostInOp(float input,float output)100*35238bceSAndroid Build Coastguard Worker inline int numBitsLostInOp(float input, float output)
101*35238bceSAndroid Build Coastguard Worker {
102*35238bceSAndroid Build Coastguard Worker     const int inExp  = tcu::Float32(input).exponent();
103*35238bceSAndroid Build Coastguard Worker     const int outExp = tcu::Float32(output).exponent();
104*35238bceSAndroid Build Coastguard Worker 
105*35238bceSAndroid Build Coastguard Worker     return de::max(0, inExp - outExp); // Lost due to mantissa shift.
106*35238bceSAndroid Build Coastguard Worker }
107*35238bceSAndroid Build Coastguard Worker 
getUlpDiff(float a,float b)108*35238bceSAndroid Build Coastguard Worker inline uint32_t getUlpDiff(float a, float b)
109*35238bceSAndroid Build Coastguard Worker {
110*35238bceSAndroid Build Coastguard Worker     const uint32_t aBits = tcu::Float32(a).bits();
111*35238bceSAndroid Build Coastguard Worker     const uint32_t bBits = tcu::Float32(b).bits();
112*35238bceSAndroid Build Coastguard Worker     return aBits > bBits ? aBits - bBits : bBits - aBits;
113*35238bceSAndroid Build Coastguard Worker }
114*35238bceSAndroid Build Coastguard Worker 
getUlpDiffIgnoreZeroSign(float a,float b)115*35238bceSAndroid Build Coastguard Worker inline uint32_t getUlpDiffIgnoreZeroSign(float a, float b)
116*35238bceSAndroid Build Coastguard Worker {
117*35238bceSAndroid Build Coastguard Worker     if (tcu::Float32(a).isZero())
118*35238bceSAndroid Build Coastguard Worker         return getUlpDiff(tcu::Float32::construct(tcu::Float32(b).sign(), 0, 0).asFloat(), b);
119*35238bceSAndroid Build Coastguard Worker     else if (tcu::Float32(b).isZero())
120*35238bceSAndroid Build Coastguard Worker         return getUlpDiff(a, tcu::Float32::construct(tcu::Float32(a).sign(), 0, 0).asFloat());
121*35238bceSAndroid Build Coastguard Worker     else
122*35238bceSAndroid Build Coastguard Worker         return getUlpDiff(a, b);
123*35238bceSAndroid Build Coastguard Worker }
124*35238bceSAndroid Build Coastguard Worker 
supportsSignedZero(glu::Precision precision)125*35238bceSAndroid Build Coastguard Worker inline bool supportsSignedZero(glu::Precision precision)
126*35238bceSAndroid Build Coastguard Worker {
127*35238bceSAndroid Build Coastguard Worker     // \note GLSL ES 3.1 doesn't really require support for -0, but we require it for highp
128*35238bceSAndroid Build Coastguard Worker     //         as it is very widely supported.
129*35238bceSAndroid Build Coastguard Worker     return precision == glu::PRECISION_HIGHP;
130*35238bceSAndroid Build Coastguard Worker }
131*35238bceSAndroid Build Coastguard Worker 
getEpsFromMaxUlpDiff(float value,uint32_t ulpDiff)132*35238bceSAndroid Build Coastguard Worker inline float getEpsFromMaxUlpDiff(float value, uint32_t ulpDiff)
133*35238bceSAndroid Build Coastguard Worker {
134*35238bceSAndroid Build Coastguard Worker     const int exp = tcu::Float32(value).exponent();
135*35238bceSAndroid Build Coastguard Worker     return tcu::Float32::construct(+1, exp, (1u << 23) | ulpDiff).asFloat() -
136*35238bceSAndroid Build Coastguard Worker            tcu::Float32::construct(+1, exp, 1u << 23).asFloat();
137*35238bceSAndroid Build Coastguard Worker }
138*35238bceSAndroid Build Coastguard Worker 
getMaxUlpDiffFromBits(int numAccurateBits)139*35238bceSAndroid Build Coastguard Worker inline uint32_t getMaxUlpDiffFromBits(int numAccurateBits)
140*35238bceSAndroid Build Coastguard Worker {
141*35238bceSAndroid Build Coastguard Worker     const int numGarbageBits = 23 - numAccurateBits;
142*35238bceSAndroid Build Coastguard Worker     const uint32_t mask      = (1u << numGarbageBits) - 1u;
143*35238bceSAndroid Build Coastguard Worker 
144*35238bceSAndroid Build Coastguard Worker     return mask;
145*35238bceSAndroid Build Coastguard Worker }
146*35238bceSAndroid Build Coastguard Worker 
getEpsFromBits(float value,int numAccurateBits)147*35238bceSAndroid Build Coastguard Worker inline float getEpsFromBits(float value, int numAccurateBits)
148*35238bceSAndroid Build Coastguard Worker {
149*35238bceSAndroid Build Coastguard Worker     return getEpsFromMaxUlpDiff(value, getMaxUlpDiffFromBits(numAccurateBits));
150*35238bceSAndroid Build Coastguard Worker }
151*35238bceSAndroid Build Coastguard Worker 
getMinMantissaBits(glu::Precision precision)152*35238bceSAndroid Build Coastguard Worker static int getMinMantissaBits(glu::Precision precision)
153*35238bceSAndroid Build Coastguard Worker {
154*35238bceSAndroid Build Coastguard Worker     const int bits[] = {
155*35238bceSAndroid Build Coastguard Worker         7,  // lowp
156*35238bceSAndroid Build Coastguard Worker         10, // mediump
157*35238bceSAndroid Build Coastguard Worker         23  // highp
158*35238bceSAndroid Build Coastguard Worker     };
159*35238bceSAndroid Build Coastguard Worker     DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(bits) == glu::PRECISION_LAST);
160*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(bits)));
161*35238bceSAndroid Build Coastguard Worker     return bits[precision];
162*35238bceSAndroid Build Coastguard Worker }
163*35238bceSAndroid Build Coastguard Worker 
getMaxNormalizedValueExponent(glu::Precision precision)164*35238bceSAndroid Build Coastguard Worker static int getMaxNormalizedValueExponent(glu::Precision precision)
165*35238bceSAndroid Build Coastguard Worker {
166*35238bceSAndroid Build Coastguard Worker     const int exponent[] = {
167*35238bceSAndroid Build Coastguard Worker         0,  // lowp
168*35238bceSAndroid Build Coastguard Worker         13, // mediump
169*35238bceSAndroid Build Coastguard Worker         127 // highp
170*35238bceSAndroid Build Coastguard Worker     };
171*35238bceSAndroid Build Coastguard Worker     DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(exponent) == glu::PRECISION_LAST);
172*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(exponent)));
173*35238bceSAndroid Build Coastguard Worker     return exponent[precision];
174*35238bceSAndroid Build Coastguard Worker }
175*35238bceSAndroid Build Coastguard Worker 
getMinNormalizedValueExponent(glu::Precision precision)176*35238bceSAndroid Build Coastguard Worker static int getMinNormalizedValueExponent(glu::Precision precision)
177*35238bceSAndroid Build Coastguard Worker {
178*35238bceSAndroid Build Coastguard Worker     const int exponent[] = {
179*35238bceSAndroid Build Coastguard Worker         -7,  // lowp
180*35238bceSAndroid Build Coastguard Worker         -13, // mediump
181*35238bceSAndroid Build Coastguard Worker         -126 // highp
182*35238bceSAndroid Build Coastguard Worker     };
183*35238bceSAndroid Build Coastguard Worker     DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(exponent) == glu::PRECISION_LAST);
184*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(exponent)));
185*35238bceSAndroid Build Coastguard Worker     return exponent[precision];
186*35238bceSAndroid Build Coastguard Worker }
187*35238bceSAndroid Build Coastguard Worker 
makeFloatRepresentable(float f,glu::Precision precision)188*35238bceSAndroid Build Coastguard Worker static float makeFloatRepresentable(float f, glu::Precision precision)
189*35238bceSAndroid Build Coastguard Worker {
190*35238bceSAndroid Build Coastguard Worker     if (precision == glu::PRECISION_HIGHP)
191*35238bceSAndroid Build Coastguard Worker     {
192*35238bceSAndroid Build Coastguard Worker         // \note: assuming f is not extended-precision
193*35238bceSAndroid Build Coastguard Worker         return f;
194*35238bceSAndroid Build Coastguard Worker     }
195*35238bceSAndroid Build Coastguard Worker     else
196*35238bceSAndroid Build Coastguard Worker     {
197*35238bceSAndroid Build Coastguard Worker         const int numMantissaBits                = getMinMantissaBits(precision);
198*35238bceSAndroid Build Coastguard Worker         const int maxNormalizedValueExponent     = getMaxNormalizedValueExponent(precision);
199*35238bceSAndroid Build Coastguard Worker         const int minNormalizedValueExponent     = getMinNormalizedValueExponent(precision);
200*35238bceSAndroid Build Coastguard Worker         const uint32_t representableMantissaMask = ((uint32_t(1) << numMantissaBits) - 1)
201*35238bceSAndroid Build Coastguard Worker                                                    << (23 - (uint32_t)numMantissaBits);
202*35238bceSAndroid Build Coastguard Worker         const float largestRepresentableValue =
203*35238bceSAndroid Build Coastguard Worker             tcu::Float32::constructBits(+1, maxNormalizedValueExponent,
204*35238bceSAndroid Build Coastguard Worker                                         ((1u << numMantissaBits) - 1u) << (23u - (uint32_t)numMantissaBits))
205*35238bceSAndroid Build Coastguard Worker                 .asFloat();
206*35238bceSAndroid Build Coastguard Worker         const bool zeroNotRepresentable = (precision == glu::PRECISION_LOWP);
207*35238bceSAndroid Build Coastguard Worker 
208*35238bceSAndroid Build Coastguard Worker         // if zero is not required to be representable, use smallest positive non-subnormal value
209*35238bceSAndroid Build Coastguard Worker         const float zeroValue = (zeroNotRepresentable) ?
210*35238bceSAndroid Build Coastguard Worker                                     (tcu::Float32::constructBits(+1, minNormalizedValueExponent, 1).asFloat()) :
211*35238bceSAndroid Build Coastguard Worker                                     (0.0f);
212*35238bceSAndroid Build Coastguard Worker 
213*35238bceSAndroid Build Coastguard Worker         const tcu::Float32 float32Representation(f);
214*35238bceSAndroid Build Coastguard Worker 
215*35238bceSAndroid Build Coastguard Worker         if (float32Representation.exponent() < minNormalizedValueExponent)
216*35238bceSAndroid Build Coastguard Worker         {
217*35238bceSAndroid Build Coastguard Worker             // flush too small values to zero
218*35238bceSAndroid Build Coastguard Worker             return zeroValue;
219*35238bceSAndroid Build Coastguard Worker         }
220*35238bceSAndroid Build Coastguard Worker         else if (float32Representation.exponent() > maxNormalizedValueExponent)
221*35238bceSAndroid Build Coastguard Worker         {
222*35238bceSAndroid Build Coastguard Worker             // clamp too large values
223*35238bceSAndroid Build Coastguard Worker             return (float32Representation.sign() == +1) ? (largestRepresentableValue) : (-largestRepresentableValue);
224*35238bceSAndroid Build Coastguard Worker         }
225*35238bceSAndroid Build Coastguard Worker         else
226*35238bceSAndroid Build Coastguard Worker         {
227*35238bceSAndroid Build Coastguard Worker             // remove unrepresentable mantissa bits
228*35238bceSAndroid Build Coastguard Worker             const tcu::Float32 targetRepresentation(
229*35238bceSAndroid Build Coastguard Worker                 tcu::Float32::constructBits(float32Representation.sign(), float32Representation.exponent(),
230*35238bceSAndroid Build Coastguard Worker                                             float32Representation.mantissaBits() & representableMantissaMask));
231*35238bceSAndroid Build Coastguard Worker 
232*35238bceSAndroid Build Coastguard Worker             return targetRepresentation.asFloat();
233*35238bceSAndroid Build Coastguard Worker         }
234*35238bceSAndroid Build Coastguard Worker     }
235*35238bceSAndroid Build Coastguard Worker }
236*35238bceSAndroid Build Coastguard Worker 
237*35238bceSAndroid Build Coastguard Worker // CommonFunctionCase
238*35238bceSAndroid Build Coastguard Worker 
239*35238bceSAndroid Build Coastguard Worker class CommonFunctionCase : public TestCase
240*35238bceSAndroid Build Coastguard Worker {
241*35238bceSAndroid Build Coastguard Worker public:
242*35238bceSAndroid Build Coastguard Worker     CommonFunctionCase(Context &context, const char *name, const char *description, glu::ShaderType shaderType);
243*35238bceSAndroid Build Coastguard Worker     ~CommonFunctionCase(void);
244*35238bceSAndroid Build Coastguard Worker 
245*35238bceSAndroid Build Coastguard Worker     void init(void);
246*35238bceSAndroid Build Coastguard Worker     void deinit(void);
247*35238bceSAndroid Build Coastguard Worker     IterateResult iterate(void);
248*35238bceSAndroid Build Coastguard Worker 
249*35238bceSAndroid Build Coastguard Worker protected:
250*35238bceSAndroid Build Coastguard Worker     CommonFunctionCase(const CommonFunctionCase &other);
251*35238bceSAndroid Build Coastguard Worker     CommonFunctionCase &operator=(const CommonFunctionCase &other);
252*35238bceSAndroid Build Coastguard Worker 
253*35238bceSAndroid Build Coastguard Worker     virtual void getInputValues(int numValues, void *const *values) const       = 0;
254*35238bceSAndroid Build Coastguard Worker     virtual bool compare(const void *const *inputs, const void *const *outputs) = 0;
255*35238bceSAndroid Build Coastguard Worker 
256*35238bceSAndroid Build Coastguard Worker     glu::ShaderType m_shaderType;
257*35238bceSAndroid Build Coastguard Worker     ShaderSpec m_spec;
258*35238bceSAndroid Build Coastguard Worker     int m_numValues;
259*35238bceSAndroid Build Coastguard Worker 
260*35238bceSAndroid Build Coastguard Worker     std::ostringstream m_failMsg; //!< Comparison failure help message.
261*35238bceSAndroid Build Coastguard Worker 
262*35238bceSAndroid Build Coastguard Worker private:
263*35238bceSAndroid Build Coastguard Worker     ShaderExecutor *m_executor;
264*35238bceSAndroid Build Coastguard Worker };
265*35238bceSAndroid Build Coastguard Worker 
CommonFunctionCase(Context & context,const char * name,const char * description,glu::ShaderType shaderType)266*35238bceSAndroid Build Coastguard Worker CommonFunctionCase::CommonFunctionCase(Context &context, const char *name, const char *description,
267*35238bceSAndroid Build Coastguard Worker                                        glu::ShaderType shaderType)
268*35238bceSAndroid Build Coastguard Worker     : TestCase(context, name, description)
269*35238bceSAndroid Build Coastguard Worker     , m_shaderType(shaderType)
270*35238bceSAndroid Build Coastguard Worker     , m_numValues(100)
271*35238bceSAndroid Build Coastguard Worker     , m_executor(DE_NULL)
272*35238bceSAndroid Build Coastguard Worker {
273*35238bceSAndroid Build Coastguard Worker }
274*35238bceSAndroid Build Coastguard Worker 
~CommonFunctionCase(void)275*35238bceSAndroid Build Coastguard Worker CommonFunctionCase::~CommonFunctionCase(void)
276*35238bceSAndroid Build Coastguard Worker {
277*35238bceSAndroid Build Coastguard Worker     CommonFunctionCase::deinit();
278*35238bceSAndroid Build Coastguard Worker }
279*35238bceSAndroid Build Coastguard Worker 
init(void)280*35238bceSAndroid Build Coastguard Worker void CommonFunctionCase::init(void)
281*35238bceSAndroid Build Coastguard Worker {
282*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(!m_executor);
283*35238bceSAndroid Build Coastguard Worker 
284*35238bceSAndroid Build Coastguard Worker     glu::ContextType contextType = m_context.getRenderContext().getType();
285*35238bceSAndroid Build Coastguard Worker     m_spec.version               = glu::getContextTypeGLSLVersion(contextType);
286*35238bceSAndroid Build Coastguard Worker 
287*35238bceSAndroid Build Coastguard Worker     m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec);
288*35238bceSAndroid Build Coastguard Worker     m_testCtx.getLog() << m_executor;
289*35238bceSAndroid Build Coastguard Worker 
290*35238bceSAndroid Build Coastguard Worker     if (!m_executor->isOk())
291*35238bceSAndroid Build Coastguard Worker         throw tcu::TestError("Compile failed");
292*35238bceSAndroid Build Coastguard Worker }
293*35238bceSAndroid Build Coastguard Worker 
deinit(void)294*35238bceSAndroid Build Coastguard Worker void CommonFunctionCase::deinit(void)
295*35238bceSAndroid Build Coastguard Worker {
296*35238bceSAndroid Build Coastguard Worker     delete m_executor;
297*35238bceSAndroid Build Coastguard Worker     m_executor = DE_NULL;
298*35238bceSAndroid Build Coastguard Worker }
299*35238bceSAndroid Build Coastguard Worker 
getScalarSizes(const vector<Symbol> & symbols)300*35238bceSAndroid Build Coastguard Worker static vector<int> getScalarSizes(const vector<Symbol> &symbols)
301*35238bceSAndroid Build Coastguard Worker {
302*35238bceSAndroid Build Coastguard Worker     vector<int> sizes(symbols.size());
303*35238bceSAndroid Build Coastguard Worker     for (int ndx = 0; ndx < (int)symbols.size(); ++ndx)
304*35238bceSAndroid Build Coastguard Worker         sizes[ndx] = symbols[ndx].varType.getScalarSize();
305*35238bceSAndroid Build Coastguard Worker     return sizes;
306*35238bceSAndroid Build Coastguard Worker }
307*35238bceSAndroid Build Coastguard Worker 
computeTotalScalarSize(const vector<Symbol> & symbols)308*35238bceSAndroid Build Coastguard Worker static int computeTotalScalarSize(const vector<Symbol> &symbols)
309*35238bceSAndroid Build Coastguard Worker {
310*35238bceSAndroid Build Coastguard Worker     int totalSize = 0;
311*35238bceSAndroid Build Coastguard Worker     for (vector<Symbol>::const_iterator sym = symbols.begin(); sym != symbols.end(); ++sym)
312*35238bceSAndroid Build Coastguard Worker         totalSize += sym->varType.getScalarSize();
313*35238bceSAndroid Build Coastguard Worker     return totalSize;
314*35238bceSAndroid Build Coastguard Worker }
315*35238bceSAndroid Build Coastguard Worker 
getInputOutputPointers(const vector<Symbol> & symbols,vector<uint32_t> & data,const int numValues)316*35238bceSAndroid Build Coastguard Worker static vector<void *> getInputOutputPointers(const vector<Symbol> &symbols, vector<uint32_t> &data, const int numValues)
317*35238bceSAndroid Build Coastguard Worker {
318*35238bceSAndroid Build Coastguard Worker     vector<void *> pointers(symbols.size());
319*35238bceSAndroid Build Coastguard Worker     int curScalarOffset = 0;
320*35238bceSAndroid Build Coastguard Worker 
321*35238bceSAndroid Build Coastguard Worker     for (int varNdx = 0; varNdx < (int)symbols.size(); ++varNdx)
322*35238bceSAndroid Build Coastguard Worker     {
323*35238bceSAndroid Build Coastguard Worker         const Symbol &var    = symbols[varNdx];
324*35238bceSAndroid Build Coastguard Worker         const int scalarSize = var.varType.getScalarSize();
325*35238bceSAndroid Build Coastguard Worker 
326*35238bceSAndroid Build Coastguard Worker         // Uses planar layout as input/output specs do not support strides.
327*35238bceSAndroid Build Coastguard Worker         pointers[varNdx] = &data[curScalarOffset];
328*35238bceSAndroid Build Coastguard Worker         curScalarOffset += scalarSize * numValues;
329*35238bceSAndroid Build Coastguard Worker     }
330*35238bceSAndroid Build Coastguard Worker 
331*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(curScalarOffset == (int)data.size());
332*35238bceSAndroid Build Coastguard Worker 
333*35238bceSAndroid Build Coastguard Worker     return pointers;
334*35238bceSAndroid Build Coastguard Worker }
335*35238bceSAndroid Build Coastguard Worker 
336*35238bceSAndroid Build Coastguard Worker // \todo [2013-08-08 pyry] Make generic utility and move to glu?
337*35238bceSAndroid Build Coastguard Worker 
338*35238bceSAndroid Build Coastguard Worker struct HexFloat
339*35238bceSAndroid Build Coastguard Worker {
340*35238bceSAndroid Build Coastguard Worker     const float value;
HexFloatdeqp::gles31::Functional::HexFloat341*35238bceSAndroid Build Coastguard Worker     HexFloat(const float value_) : value(value_)
342*35238bceSAndroid Build Coastguard Worker     {
343*35238bceSAndroid Build Coastguard Worker     }
344*35238bceSAndroid Build Coastguard Worker };
345*35238bceSAndroid Build Coastguard Worker 
operator <<(std::ostream & str,const HexFloat & v)346*35238bceSAndroid Build Coastguard Worker std::ostream &operator<<(std::ostream &str, const HexFloat &v)
347*35238bceSAndroid Build Coastguard Worker {
348*35238bceSAndroid Build Coastguard Worker     return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
349*35238bceSAndroid Build Coastguard Worker }
350*35238bceSAndroid Build Coastguard Worker 
351*35238bceSAndroid Build Coastguard Worker struct HexBool
352*35238bceSAndroid Build Coastguard Worker {
353*35238bceSAndroid Build Coastguard Worker     const uint32_t value;
HexBooldeqp::gles31::Functional::HexBool354*35238bceSAndroid Build Coastguard Worker     HexBool(const uint32_t value_) : value(value_)
355*35238bceSAndroid Build Coastguard Worker     {
356*35238bceSAndroid Build Coastguard Worker     }
357*35238bceSAndroid Build Coastguard Worker };
358*35238bceSAndroid Build Coastguard Worker 
operator <<(std::ostream & str,const HexBool & v)359*35238bceSAndroid Build Coastguard Worker std::ostream &operator<<(std::ostream &str, const HexBool &v)
360*35238bceSAndroid Build Coastguard Worker {
361*35238bceSAndroid Build Coastguard Worker     return str << (v.value ? "true" : "false") << " / " << tcu::toHex(v.value);
362*35238bceSAndroid Build Coastguard Worker }
363*35238bceSAndroid Build Coastguard Worker 
364*35238bceSAndroid Build Coastguard Worker struct VarValue
365*35238bceSAndroid Build Coastguard Worker {
366*35238bceSAndroid Build Coastguard Worker     const glu::VarType &type;
367*35238bceSAndroid Build Coastguard Worker     const void *value;
368*35238bceSAndroid Build Coastguard Worker 
VarValuedeqp::gles31::Functional::VarValue369*35238bceSAndroid Build Coastguard Worker     VarValue(const glu::VarType &type_, const void *value_) : type(type_), value(value_)
370*35238bceSAndroid Build Coastguard Worker     {
371*35238bceSAndroid Build Coastguard Worker     }
372*35238bceSAndroid Build Coastguard Worker };
373*35238bceSAndroid Build Coastguard Worker 
operator <<(std::ostream & str,const VarValue & varValue)374*35238bceSAndroid Build Coastguard Worker std::ostream &operator<<(std::ostream &str, const VarValue &varValue)
375*35238bceSAndroid Build Coastguard Worker {
376*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(varValue.type.isBasicType());
377*35238bceSAndroid Build Coastguard Worker 
378*35238bceSAndroid Build Coastguard Worker     const glu::DataType basicType  = varValue.type.getBasicType();
379*35238bceSAndroid Build Coastguard Worker     const glu::DataType scalarType = glu::getDataTypeScalarType(basicType);
380*35238bceSAndroid Build Coastguard Worker     const int numComponents        = glu::getDataTypeScalarSize(basicType);
381*35238bceSAndroid Build Coastguard Worker 
382*35238bceSAndroid Build Coastguard Worker     if (numComponents > 1)
383*35238bceSAndroid Build Coastguard Worker         str << glu::getDataTypeName(basicType) << "(";
384*35238bceSAndroid Build Coastguard Worker 
385*35238bceSAndroid Build Coastguard Worker     for (int compNdx = 0; compNdx < numComponents; compNdx++)
386*35238bceSAndroid Build Coastguard Worker     {
387*35238bceSAndroid Build Coastguard Worker         if (compNdx != 0)
388*35238bceSAndroid Build Coastguard Worker             str << ", ";
389*35238bceSAndroid Build Coastguard Worker 
390*35238bceSAndroid Build Coastguard Worker         switch (scalarType)
391*35238bceSAndroid Build Coastguard Worker         {
392*35238bceSAndroid Build Coastguard Worker         case glu::TYPE_FLOAT:
393*35238bceSAndroid Build Coastguard Worker             str << HexFloat(((const float *)varValue.value)[compNdx]);
394*35238bceSAndroid Build Coastguard Worker             break;
395*35238bceSAndroid Build Coastguard Worker         case glu::TYPE_INT:
396*35238bceSAndroid Build Coastguard Worker             str << ((const int32_t *)varValue.value)[compNdx];
397*35238bceSAndroid Build Coastguard Worker             break;
398*35238bceSAndroid Build Coastguard Worker         case glu::TYPE_UINT:
399*35238bceSAndroid Build Coastguard Worker             str << tcu::toHex(((const uint32_t *)varValue.value)[compNdx]);
400*35238bceSAndroid Build Coastguard Worker             break;
401*35238bceSAndroid Build Coastguard Worker         case glu::TYPE_BOOL:
402*35238bceSAndroid Build Coastguard Worker             str << HexBool(((const uint32_t *)varValue.value)[compNdx]);
403*35238bceSAndroid Build Coastguard Worker             break;
404*35238bceSAndroid Build Coastguard Worker 
405*35238bceSAndroid Build Coastguard Worker         default:
406*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(false);
407*35238bceSAndroid Build Coastguard Worker         }
408*35238bceSAndroid Build Coastguard Worker     }
409*35238bceSAndroid Build Coastguard Worker 
410*35238bceSAndroid Build Coastguard Worker     if (numComponents > 1)
411*35238bceSAndroid Build Coastguard Worker         str << ")";
412*35238bceSAndroid Build Coastguard Worker 
413*35238bceSAndroid Build Coastguard Worker     return str;
414*35238bceSAndroid Build Coastguard Worker }
415*35238bceSAndroid Build Coastguard Worker 
iterate(void)416*35238bceSAndroid Build Coastguard Worker CommonFunctionCase::IterateResult CommonFunctionCase::iterate(void)
417*35238bceSAndroid Build Coastguard Worker {
418*35238bceSAndroid Build Coastguard Worker     const int numInputScalars  = computeTotalScalarSize(m_spec.inputs);
419*35238bceSAndroid Build Coastguard Worker     const int numOutputScalars = computeTotalScalarSize(m_spec.outputs);
420*35238bceSAndroid Build Coastguard Worker     vector<uint32_t> inputData(numInputScalars * m_numValues);
421*35238bceSAndroid Build Coastguard Worker     vector<uint32_t> outputData(numOutputScalars * m_numValues);
422*35238bceSAndroid Build Coastguard Worker     const vector<void *> inputPointers  = getInputOutputPointers(m_spec.inputs, inputData, m_numValues);
423*35238bceSAndroid Build Coastguard Worker     const vector<void *> outputPointers = getInputOutputPointers(m_spec.outputs, outputData, m_numValues);
424*35238bceSAndroid Build Coastguard Worker 
425*35238bceSAndroid Build Coastguard Worker     // Initialize input data.
426*35238bceSAndroid Build Coastguard Worker     getInputValues(m_numValues, &inputPointers[0]);
427*35238bceSAndroid Build Coastguard Worker 
428*35238bceSAndroid Build Coastguard Worker     // Execute shader.
429*35238bceSAndroid Build Coastguard Worker     m_executor->useProgram();
430*35238bceSAndroid Build Coastguard Worker     m_executor->execute(m_numValues, &inputPointers[0], &outputPointers[0]);
431*35238bceSAndroid Build Coastguard Worker 
432*35238bceSAndroid Build Coastguard Worker     // Compare results.
433*35238bceSAndroid Build Coastguard Worker     {
434*35238bceSAndroid Build Coastguard Worker         const vector<int> inScalarSizes  = getScalarSizes(m_spec.inputs);
435*35238bceSAndroid Build Coastguard Worker         const vector<int> outScalarSizes = getScalarSizes(m_spec.outputs);
436*35238bceSAndroid Build Coastguard Worker         vector<void *> curInputPtr(inputPointers.size());
437*35238bceSAndroid Build Coastguard Worker         vector<void *> curOutputPtr(outputPointers.size());
438*35238bceSAndroid Build Coastguard Worker         int numFailed = 0;
439*35238bceSAndroid Build Coastguard Worker 
440*35238bceSAndroid Build Coastguard Worker         for (int valNdx = 0; valNdx < m_numValues; valNdx++)
441*35238bceSAndroid Build Coastguard Worker         {
442*35238bceSAndroid Build Coastguard Worker             // Set up pointers for comparison.
443*35238bceSAndroid Build Coastguard Worker             for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx)
444*35238bceSAndroid Build Coastguard Worker                 curInputPtr[inNdx] = (uint32_t *)inputPointers[inNdx] + inScalarSizes[inNdx] * valNdx;
445*35238bceSAndroid Build Coastguard Worker 
446*35238bceSAndroid Build Coastguard Worker             for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx)
447*35238bceSAndroid Build Coastguard Worker                 curOutputPtr[outNdx] = (uint32_t *)outputPointers[outNdx] + outScalarSizes[outNdx] * valNdx;
448*35238bceSAndroid Build Coastguard Worker 
449*35238bceSAndroid Build Coastguard Worker             if (!compare(&curInputPtr[0], &curOutputPtr[0]))
450*35238bceSAndroid Build Coastguard Worker             {
451*35238bceSAndroid Build Coastguard Worker                 // \todo [2013-08-08 pyry] We probably want to log reference value as well?
452*35238bceSAndroid Build Coastguard Worker 
453*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n  "
454*35238bceSAndroid Build Coastguard Worker                                    << m_failMsg.str() << TestLog::EndMessage;
455*35238bceSAndroid Build Coastguard Worker 
456*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "  inputs:" << TestLog::EndMessage;
457*35238bceSAndroid Build Coastguard Worker                 for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++)
458*35238bceSAndroid Build Coastguard Worker                     m_testCtx.getLog() << TestLog::Message << "    " << m_spec.inputs[inNdx].name << " = "
459*35238bceSAndroid Build Coastguard Worker                                        << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx])
460*35238bceSAndroid Build Coastguard Worker                                        << TestLog::EndMessage;
461*35238bceSAndroid Build Coastguard Worker 
462*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "  outputs:" << TestLog::EndMessage;
463*35238bceSAndroid Build Coastguard Worker                 for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++)
464*35238bceSAndroid Build Coastguard Worker                     m_testCtx.getLog() << TestLog::Message << "    " << m_spec.outputs[outNdx].name << " = "
465*35238bceSAndroid Build Coastguard Worker                                        << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx])
466*35238bceSAndroid Build Coastguard Worker                                        << TestLog::EndMessage;
467*35238bceSAndroid Build Coastguard Worker 
468*35238bceSAndroid Build Coastguard Worker                 m_failMsg.str("");
469*35238bceSAndroid Build Coastguard Worker                 m_failMsg.clear();
470*35238bceSAndroid Build Coastguard Worker                 numFailed += 1;
471*35238bceSAndroid Build Coastguard Worker             }
472*35238bceSAndroid Build Coastguard Worker         }
473*35238bceSAndroid Build Coastguard Worker 
474*35238bceSAndroid Build Coastguard Worker         m_testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed"
475*35238bceSAndroid Build Coastguard Worker                            << TestLog::EndMessage;
476*35238bceSAndroid Build Coastguard Worker 
477*35238bceSAndroid Build Coastguard Worker         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
478*35238bceSAndroid Build Coastguard Worker                                 numFailed == 0 ? "Pass" : "Result comparison failed");
479*35238bceSAndroid Build Coastguard Worker     }
480*35238bceSAndroid Build Coastguard Worker 
481*35238bceSAndroid Build Coastguard Worker     return STOP;
482*35238bceSAndroid Build Coastguard Worker }
483*35238bceSAndroid Build Coastguard Worker 
getCommonFuncCaseName(glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)484*35238bceSAndroid Build Coastguard Worker static std::string getCommonFuncCaseName(glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
485*35238bceSAndroid Build Coastguard Worker {
486*35238bceSAndroid Build Coastguard Worker     return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType);
487*35238bceSAndroid Build Coastguard Worker }
488*35238bceSAndroid Build Coastguard Worker 
489*35238bceSAndroid Build Coastguard Worker class AbsCase : public CommonFunctionCase
490*35238bceSAndroid Build Coastguard Worker {
491*35238bceSAndroid Build Coastguard Worker public:
AbsCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)492*35238bceSAndroid Build Coastguard Worker     AbsCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
493*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "abs", shaderType)
494*35238bceSAndroid Build Coastguard Worker     {
495*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
496*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
497*35238bceSAndroid Build Coastguard Worker         m_spec.source = "out0 = abs(in0);";
498*35238bceSAndroid Build Coastguard Worker     }
499*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const500*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
501*35238bceSAndroid Build Coastguard Worker     {
502*35238bceSAndroid Build Coastguard Worker         const Vec2 floatRanges[] = {
503*35238bceSAndroid Build Coastguard Worker             Vec2(-2.0f, 2.0f), // lowp
504*35238bceSAndroid Build Coastguard Worker             Vec2(-1e3f, 1e3f), // mediump
505*35238bceSAndroid Build Coastguard Worker             Vec2(-1e7f, 1e7f)  // highp
506*35238bceSAndroid Build Coastguard Worker         };
507*35238bceSAndroid Build Coastguard Worker         const IVec2 intRanges[] = {IVec2(-(1 << 7) + 1, (1 << 7) - 1), IVec2(-(1 << 15) + 1, (1 << 15) - 1),
508*35238bceSAndroid Build Coastguard Worker                                    IVec2(0x80000001, 0x7fffffff)};
509*35238bceSAndroid Build Coastguard Worker 
510*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0x235facu);
511*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
512*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
513*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
514*35238bceSAndroid Build Coastguard Worker 
515*35238bceSAndroid Build Coastguard Worker         if (glu::isDataTypeFloatOrVec(type))
516*35238bceSAndroid Build Coastguard Worker             fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), values[0],
517*35238bceSAndroid Build Coastguard Worker                               numValues * scalarSize);
518*35238bceSAndroid Build Coastguard Worker         else
519*35238bceSAndroid Build Coastguard Worker             fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), values[0],
520*35238bceSAndroid Build Coastguard Worker                               numValues * scalarSize);
521*35238bceSAndroid Build Coastguard Worker     }
522*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)523*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
524*35238bceSAndroid Build Coastguard Worker     {
525*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
526*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
527*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
528*35238bceSAndroid Build Coastguard Worker 
529*35238bceSAndroid Build Coastguard Worker         if (glu::isDataTypeFloatOrVec(type))
530*35238bceSAndroid Build Coastguard Worker         {
531*35238bceSAndroid Build Coastguard Worker             const int mantissaBits    = getMinMantissaBits(precision);
532*35238bceSAndroid Build Coastguard Worker             const uint32_t maxUlpDiff = (1u << (23 - mantissaBits)) - 1u;
533*35238bceSAndroid Build Coastguard Worker 
534*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
535*35238bceSAndroid Build Coastguard Worker             {
536*35238bceSAndroid Build Coastguard Worker                 const float in0         = ((const float *)inputs[0])[compNdx];
537*35238bceSAndroid Build Coastguard Worker                 const float out0        = ((const float *)outputs[0])[compNdx];
538*35238bceSAndroid Build Coastguard Worker                 const float ref0        = de::abs(in0);
539*35238bceSAndroid Build Coastguard Worker                 const uint32_t ulpDiff0 = getUlpDiff(out0, ref0);
540*35238bceSAndroid Build Coastguard Worker 
541*35238bceSAndroid Build Coastguard Worker                 if (ulpDiff0 > maxUlpDiff)
542*35238bceSAndroid Build Coastguard Worker                 {
543*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold "
544*35238bceSAndroid Build Coastguard Worker                               << maxUlpDiff << ", got ULP diff " << ulpDiff0;
545*35238bceSAndroid Build Coastguard Worker                     return false;
546*35238bceSAndroid Build Coastguard Worker                 }
547*35238bceSAndroid Build Coastguard Worker             }
548*35238bceSAndroid Build Coastguard Worker         }
549*35238bceSAndroid Build Coastguard Worker         else
550*35238bceSAndroid Build Coastguard Worker         {
551*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
552*35238bceSAndroid Build Coastguard Worker             {
553*35238bceSAndroid Build Coastguard Worker                 const int in0  = ((const int *)inputs[0])[compNdx];
554*35238bceSAndroid Build Coastguard Worker                 const int out0 = ((const int *)outputs[0])[compNdx];
555*35238bceSAndroid Build Coastguard Worker                 const int ref0 = de::abs(in0);
556*35238bceSAndroid Build Coastguard Worker 
557*35238bceSAndroid Build Coastguard Worker                 if (out0 != ref0)
558*35238bceSAndroid Build Coastguard Worker                 {
559*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = " << ref0;
560*35238bceSAndroid Build Coastguard Worker                     return false;
561*35238bceSAndroid Build Coastguard Worker                 }
562*35238bceSAndroid Build Coastguard Worker             }
563*35238bceSAndroid Build Coastguard Worker         }
564*35238bceSAndroid Build Coastguard Worker 
565*35238bceSAndroid Build Coastguard Worker         return true;
566*35238bceSAndroid Build Coastguard Worker     }
567*35238bceSAndroid Build Coastguard Worker };
568*35238bceSAndroid Build Coastguard Worker 
569*35238bceSAndroid Build Coastguard Worker class SignCase : public CommonFunctionCase
570*35238bceSAndroid Build Coastguard Worker {
571*35238bceSAndroid Build Coastguard Worker public:
SignCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)572*35238bceSAndroid Build Coastguard Worker     SignCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
573*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "sign",
574*35238bceSAndroid Build Coastguard Worker                              shaderType)
575*35238bceSAndroid Build Coastguard Worker     {
576*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
577*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
578*35238bceSAndroid Build Coastguard Worker         m_spec.source = "out0 = sign(in0);";
579*35238bceSAndroid Build Coastguard Worker     }
580*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const581*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
582*35238bceSAndroid Build Coastguard Worker     {
583*35238bceSAndroid Build Coastguard Worker         const Vec2 floatRanges[] = {
584*35238bceSAndroid Build Coastguard Worker             Vec2(-2.0f, 2.0f), // lowp
585*35238bceSAndroid Build Coastguard Worker             Vec2(-1e4f, 1e4f), // mediump    - note: may end up as inf
586*35238bceSAndroid Build Coastguard Worker             Vec2(-1e8f, 1e8f)  // highp    - note: may end up as inf
587*35238bceSAndroid Build Coastguard Worker         };
588*35238bceSAndroid Build Coastguard Worker         const IVec2 intRanges[] = {IVec2(-(1 << 7), (1 << 7) - 1), IVec2(-(1 << 15), (1 << 15) - 1),
589*35238bceSAndroid Build Coastguard Worker                                    IVec2(0x80000000, 0x7fffffff)};
590*35238bceSAndroid Build Coastguard Worker 
591*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0x324u);
592*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
593*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
594*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
595*35238bceSAndroid Build Coastguard Worker 
596*35238bceSAndroid Build Coastguard Worker         if (glu::isDataTypeFloatOrVec(type))
597*35238bceSAndroid Build Coastguard Worker         {
598*35238bceSAndroid Build Coastguard Worker             // Special cases.
599*35238bceSAndroid Build Coastguard Worker             std::fill((float *)values[0], (float *)values[0] + scalarSize, +1.0f);
600*35238bceSAndroid Build Coastguard Worker             std::fill((float *)values[0] + scalarSize * 1, (float *)values[0] + scalarSize * 2, -1.0f);
601*35238bceSAndroid Build Coastguard Worker             std::fill((float *)values[0] + scalarSize * 2, (float *)values[0] + scalarSize * 3, 0.0f);
602*35238bceSAndroid Build Coastguard Worker             fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(),
603*35238bceSAndroid Build Coastguard Worker                               (float *)values[0] + scalarSize * 3, (numValues - 3) * scalarSize);
604*35238bceSAndroid Build Coastguard Worker         }
605*35238bceSAndroid Build Coastguard Worker         else
606*35238bceSAndroid Build Coastguard Worker         {
607*35238bceSAndroid Build Coastguard Worker             std::fill((int *)values[0], (int *)values[0] + scalarSize, +1);
608*35238bceSAndroid Build Coastguard Worker             std::fill((int *)values[0] + scalarSize * 1, (int *)values[0] + scalarSize * 2, -1);
609*35238bceSAndroid Build Coastguard Worker             std::fill((int *)values[0] + scalarSize * 2, (int *)values[0] + scalarSize * 3, 0);
610*35238bceSAndroid Build Coastguard Worker             fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(),
611*35238bceSAndroid Build Coastguard Worker                               (int *)values[0] + scalarSize * 3, (numValues - 3) * scalarSize);
612*35238bceSAndroid Build Coastguard Worker         }
613*35238bceSAndroid Build Coastguard Worker     }
614*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)615*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
616*35238bceSAndroid Build Coastguard Worker     {
617*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
618*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
619*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
620*35238bceSAndroid Build Coastguard Worker 
621*35238bceSAndroid Build Coastguard Worker         if (glu::isDataTypeFloatOrVec(type))
622*35238bceSAndroid Build Coastguard Worker         {
623*35238bceSAndroid Build Coastguard Worker             // Both highp and mediump should be able to represent -1, 0, and +1 exactly
624*35238bceSAndroid Build Coastguard Worker             const uint32_t maxUlpDiff =
625*35238bceSAndroid Build Coastguard Worker                 precision == glu::PRECISION_LOWP ? getMaxUlpDiffFromBits(getMinMantissaBits(precision)) : 0;
626*35238bceSAndroid Build Coastguard Worker 
627*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
628*35238bceSAndroid Build Coastguard Worker             {
629*35238bceSAndroid Build Coastguard Worker                 const float in0         = ((const float *)inputs[0])[compNdx];
630*35238bceSAndroid Build Coastguard Worker                 const float out0        = ((const float *)outputs[0])[compNdx];
631*35238bceSAndroid Build Coastguard Worker                 const float ref0        = in0 < 0.0f ? -1.0f : in0 > 0.0f ? +1.0f : 0.0f;
632*35238bceSAndroid Build Coastguard Worker                 const uint32_t ulpDiff0 = getUlpDiff(out0, ref0);
633*35238bceSAndroid Build Coastguard Worker 
634*35238bceSAndroid Build Coastguard Worker                 if (ulpDiff0 > maxUlpDiff)
635*35238bceSAndroid Build Coastguard Worker                 {
636*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold "
637*35238bceSAndroid Build Coastguard Worker                               << maxUlpDiff << ", got ULP diff " << ulpDiff0;
638*35238bceSAndroid Build Coastguard Worker                     return false;
639*35238bceSAndroid Build Coastguard Worker                 }
640*35238bceSAndroid Build Coastguard Worker             }
641*35238bceSAndroid Build Coastguard Worker         }
642*35238bceSAndroid Build Coastguard Worker         else
643*35238bceSAndroid Build Coastguard Worker         {
644*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
645*35238bceSAndroid Build Coastguard Worker             {
646*35238bceSAndroid Build Coastguard Worker                 const int in0  = ((const int *)inputs[0])[compNdx];
647*35238bceSAndroid Build Coastguard Worker                 const int out0 = ((const int *)outputs[0])[compNdx];
648*35238bceSAndroid Build Coastguard Worker                 const int ref0 = in0 < 0 ? -1 : in0 > 0 ? +1 : 0;
649*35238bceSAndroid Build Coastguard Worker 
650*35238bceSAndroid Build Coastguard Worker                 if (out0 != ref0)
651*35238bceSAndroid Build Coastguard Worker                 {
652*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = " << ref0;
653*35238bceSAndroid Build Coastguard Worker                     return false;
654*35238bceSAndroid Build Coastguard Worker                 }
655*35238bceSAndroid Build Coastguard Worker             }
656*35238bceSAndroid Build Coastguard Worker         }
657*35238bceSAndroid Build Coastguard Worker 
658*35238bceSAndroid Build Coastguard Worker         return true;
659*35238bceSAndroid Build Coastguard Worker     }
660*35238bceSAndroid Build Coastguard Worker };
661*35238bceSAndroid Build Coastguard Worker 
roundEven(float v)662*35238bceSAndroid Build Coastguard Worker static float roundEven(float v)
663*35238bceSAndroid Build Coastguard Worker {
664*35238bceSAndroid Build Coastguard Worker     const float q       = deFloatFrac(v);
665*35238bceSAndroid Build Coastguard Worker     const int truncated = int(v - q);
666*35238bceSAndroid Build Coastguard Worker     const int        rounded = (q > 0.5f)                            ? (truncated + 1) : // Rounded up
667*35238bceSAndroid Build Coastguard Worker                                     (q == 0.5f && (truncated % 2 != 0))    ? (truncated + 1) : // Round to nearest even at 0.5
668*35238bceSAndroid Build Coastguard Worker                                     truncated;                                                // Rounded down
669*35238bceSAndroid Build Coastguard Worker 
670*35238bceSAndroid Build Coastguard Worker     return float(rounded);
671*35238bceSAndroid Build Coastguard Worker }
672*35238bceSAndroid Build Coastguard Worker 
673*35238bceSAndroid Build Coastguard Worker class RoundEvenCase : public CommonFunctionCase
674*35238bceSAndroid Build Coastguard Worker {
675*35238bceSAndroid Build Coastguard Worker public:
RoundEvenCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)676*35238bceSAndroid Build Coastguard Worker     RoundEvenCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
677*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "roundEven",
678*35238bceSAndroid Build Coastguard Worker                              shaderType)
679*35238bceSAndroid Build Coastguard Worker     {
680*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
681*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
682*35238bceSAndroid Build Coastguard Worker         m_spec.source = "out0 = roundEven(in0);";
683*35238bceSAndroid Build Coastguard Worker     }
684*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const685*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
686*35238bceSAndroid Build Coastguard Worker     {
687*35238bceSAndroid Build Coastguard Worker         const Vec2 ranges[] = {
688*35238bceSAndroid Build Coastguard Worker             Vec2(-2.0f, 2.0f), // lowp
689*35238bceSAndroid Build Coastguard Worker             Vec2(-1e3f, 1e3f), // mediump
690*35238bceSAndroid Build Coastguard Worker             Vec2(-1e7f, 1e7f)  // highp
691*35238bceSAndroid Build Coastguard Worker         };
692*35238bceSAndroid Build Coastguard Worker 
693*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0xac23fu);
694*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
695*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
696*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
697*35238bceSAndroid Build Coastguard Worker         int numSpecialCases            = 0;
698*35238bceSAndroid Build Coastguard Worker 
699*35238bceSAndroid Build Coastguard Worker         // Special cases.
700*35238bceSAndroid Build Coastguard Worker         if (precision != glu::PRECISION_LOWP)
701*35238bceSAndroid Build Coastguard Worker         {
702*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(numValues >= 20);
703*35238bceSAndroid Build Coastguard Worker             for (int ndx = 0; ndx < 20; ndx++)
704*35238bceSAndroid Build Coastguard Worker             {
705*35238bceSAndroid Build Coastguard Worker                 const float v = de::clamp(float(ndx) - 10.5f, ranges[precision].x(), ranges[precision].y());
706*35238bceSAndroid Build Coastguard Worker                 std::fill((float *)values[0], (float *)values[0] + scalarSize, v);
707*35238bceSAndroid Build Coastguard Worker                 numSpecialCases += 1;
708*35238bceSAndroid Build Coastguard Worker             }
709*35238bceSAndroid Build Coastguard Worker         }
710*35238bceSAndroid Build Coastguard Worker 
711*35238bceSAndroid Build Coastguard Worker         // Random cases.
712*35238bceSAndroid Build Coastguard Worker         fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(),
713*35238bceSAndroid Build Coastguard Worker                           (float *)values[0] + numSpecialCases * scalarSize,
714*35238bceSAndroid Build Coastguard Worker                           (numValues - numSpecialCases) * scalarSize);
715*35238bceSAndroid Build Coastguard Worker 
716*35238bceSAndroid Build Coastguard Worker         // If precision is mediump, make sure values can be represented in fp16 exactly
717*35238bceSAndroid Build Coastguard Worker         if (precision == glu::PRECISION_MEDIUMP)
718*35238bceSAndroid Build Coastguard Worker         {
719*35238bceSAndroid Build Coastguard Worker             for (int ndx = 0; ndx < numValues * scalarSize; ndx++)
720*35238bceSAndroid Build Coastguard Worker                 ((float *)values[0])[ndx] = tcu::Float16(((float *)values[0])[ndx]).asFloat();
721*35238bceSAndroid Build Coastguard Worker         }
722*35238bceSAndroid Build Coastguard Worker     }
723*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)724*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
725*35238bceSAndroid Build Coastguard Worker     {
726*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
727*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
728*35238bceSAndroid Build Coastguard Worker         const bool hasSignedZero       = supportsSignedZero(precision);
729*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
730*35238bceSAndroid Build Coastguard Worker 
731*35238bceSAndroid Build Coastguard Worker         if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
732*35238bceSAndroid Build Coastguard Worker         {
733*35238bceSAndroid Build Coastguard Worker             // Require exact rounding result.
734*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
735*35238bceSAndroid Build Coastguard Worker             {
736*35238bceSAndroid Build Coastguard Worker                 const float in0  = ((const float *)inputs[0])[compNdx];
737*35238bceSAndroid Build Coastguard Worker                 const float out0 = ((const float *)outputs[0])[compNdx];
738*35238bceSAndroid Build Coastguard Worker                 const float ref  = roundEven(in0);
739*35238bceSAndroid Build Coastguard Worker 
740*35238bceSAndroid Build Coastguard Worker                 const uint32_t ulpDiff = hasSignedZero ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
741*35238bceSAndroid Build Coastguard Worker 
742*35238bceSAndroid Build Coastguard Worker                 if (ulpDiff > 0)
743*35238bceSAndroid Build Coastguard Worker                 {
744*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff "
745*35238bceSAndroid Build Coastguard Worker                               << tcu::toHex(ulpDiff);
746*35238bceSAndroid Build Coastguard Worker                     return false;
747*35238bceSAndroid Build Coastguard Worker                 }
748*35238bceSAndroid Build Coastguard Worker             }
749*35238bceSAndroid Build Coastguard Worker         }
750*35238bceSAndroid Build Coastguard Worker         else
751*35238bceSAndroid Build Coastguard Worker         {
752*35238bceSAndroid Build Coastguard Worker             const int mantissaBits    = getMinMantissaBits(precision);
753*35238bceSAndroid Build Coastguard Worker             const uint32_t maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value.
754*35238bceSAndroid Build Coastguard Worker             const float eps           = getEpsFromBits(1.0f, mantissaBits);  // epsilon for rounding bounds
755*35238bceSAndroid Build Coastguard Worker 
756*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
757*35238bceSAndroid Build Coastguard Worker             {
758*35238bceSAndroid Build Coastguard Worker                 const float in0  = ((const float *)inputs[0])[compNdx];
759*35238bceSAndroid Build Coastguard Worker                 const float out0 = ((const float *)outputs[0])[compNdx];
760*35238bceSAndroid Build Coastguard Worker                 const int minRes = int(roundEven(in0 - eps));
761*35238bceSAndroid Build Coastguard Worker                 const int maxRes = int(roundEven(in0 + eps));
762*35238bceSAndroid Build Coastguard Worker                 bool anyOk       = false;
763*35238bceSAndroid Build Coastguard Worker 
764*35238bceSAndroid Build Coastguard Worker                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
765*35238bceSAndroid Build Coastguard Worker                 {
766*35238bceSAndroid Build Coastguard Worker                     const uint32_t ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
767*35238bceSAndroid Build Coastguard Worker 
768*35238bceSAndroid Build Coastguard Worker                     if (ulpDiff <= maxUlpDiff)
769*35238bceSAndroid Build Coastguard Worker                     {
770*35238bceSAndroid Build Coastguard Worker                         anyOk = true;
771*35238bceSAndroid Build Coastguard Worker                         break;
772*35238bceSAndroid Build Coastguard Worker                     }
773*35238bceSAndroid Build Coastguard Worker                 }
774*35238bceSAndroid Build Coastguard Worker 
775*35238bceSAndroid Build Coastguard Worker                 if (!anyOk)
776*35238bceSAndroid Build Coastguard Worker                 {
777*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes
778*35238bceSAndroid Build Coastguard Worker                               << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
779*35238bceSAndroid Build Coastguard Worker                     return false;
780*35238bceSAndroid Build Coastguard Worker                 }
781*35238bceSAndroid Build Coastguard Worker             }
782*35238bceSAndroid Build Coastguard Worker         }
783*35238bceSAndroid Build Coastguard Worker 
784*35238bceSAndroid Build Coastguard Worker         return true;
785*35238bceSAndroid Build Coastguard Worker     }
786*35238bceSAndroid Build Coastguard Worker };
787*35238bceSAndroid Build Coastguard Worker 
788*35238bceSAndroid Build Coastguard Worker class ModfCase : public CommonFunctionCase
789*35238bceSAndroid Build Coastguard Worker {
790*35238bceSAndroid Build Coastguard Worker public:
ModfCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)791*35238bceSAndroid Build Coastguard Worker     ModfCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
792*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "modf",
793*35238bceSAndroid Build Coastguard Worker                              shaderType)
794*35238bceSAndroid Build Coastguard Worker     {
795*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
796*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
797*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out1", glu::VarType(baseType, precision)));
798*35238bceSAndroid Build Coastguard Worker         m_spec.source = "out0 = modf(in0, out1);";
799*35238bceSAndroid Build Coastguard Worker     }
800*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const801*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
802*35238bceSAndroid Build Coastguard Worker     {
803*35238bceSAndroid Build Coastguard Worker         const Vec2 ranges[] = {
804*35238bceSAndroid Build Coastguard Worker             Vec2(-2.0f, 2.0f), // lowp
805*35238bceSAndroid Build Coastguard Worker             Vec2(-1e3f, 1e3f), // mediump
806*35238bceSAndroid Build Coastguard Worker             Vec2(-1e7f, 1e7f)  // highp
807*35238bceSAndroid Build Coastguard Worker         };
808*35238bceSAndroid Build Coastguard Worker 
809*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0xac23fu);
810*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
811*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
812*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
813*35238bceSAndroid Build Coastguard Worker 
814*35238bceSAndroid Build Coastguard Worker         fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues * scalarSize);
815*35238bceSAndroid Build Coastguard Worker     }
816*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)817*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
818*35238bceSAndroid Build Coastguard Worker     {
819*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
820*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
821*35238bceSAndroid Build Coastguard Worker         const bool hasZeroSign         = supportsSignedZero(precision);
822*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
823*35238bceSAndroid Build Coastguard Worker 
824*35238bceSAndroid Build Coastguard Worker         const int mantissaBits = getMinMantissaBits(precision);
825*35238bceSAndroid Build Coastguard Worker 
826*35238bceSAndroid Build Coastguard Worker         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
827*35238bceSAndroid Build Coastguard Worker         {
828*35238bceSAndroid Build Coastguard Worker             const float in0  = ((const float *)inputs[0])[compNdx];
829*35238bceSAndroid Build Coastguard Worker             const float out0 = ((const float *)outputs[0])[compNdx];
830*35238bceSAndroid Build Coastguard Worker             const float out1 = ((const float *)outputs[1])[compNdx];
831*35238bceSAndroid Build Coastguard Worker 
832*35238bceSAndroid Build Coastguard Worker             const float refOut1 = float(int(in0));
833*35238bceSAndroid Build Coastguard Worker             const float refOut0 = in0 - refOut1;
834*35238bceSAndroid Build Coastguard Worker 
835*35238bceSAndroid Build Coastguard Worker             const int bitsLost        = precision != glu::PRECISION_HIGHP ? numBitsLostInOp(in0, refOut0) : 0;
836*35238bceSAndroid Build Coastguard Worker             const uint32_t maxUlpDiff = getMaxUlpDiffFromBits(de::max(mantissaBits - bitsLost, 0));
837*35238bceSAndroid Build Coastguard Worker 
838*35238bceSAndroid Build Coastguard Worker             const float resSum = out0 + out1;
839*35238bceSAndroid Build Coastguard Worker 
840*35238bceSAndroid Build Coastguard Worker             const uint32_t ulpDiff = hasZeroSign ? getUlpDiff(resSum, in0) : getUlpDiffIgnoreZeroSign(resSum, in0);
841*35238bceSAndroid Build Coastguard Worker 
842*35238bceSAndroid Build Coastguard Worker             if (ulpDiff > maxUlpDiff)
843*35238bceSAndroid Build Coastguard Worker             {
844*35238bceSAndroid Build Coastguard Worker                 m_failMsg << "Expected [" << compNdx << "] = (" << HexFloat(refOut0) << ") + (" << HexFloat(refOut1)
845*35238bceSAndroid Build Coastguard Worker                           << ") = " << HexFloat(in0) << " with ULP threshold " << tcu::toHex(maxUlpDiff)
846*35238bceSAndroid Build Coastguard Worker                           << ", got ULP diff " << tcu::toHex(ulpDiff);
847*35238bceSAndroid Build Coastguard Worker                 return false;
848*35238bceSAndroid Build Coastguard Worker             }
849*35238bceSAndroid Build Coastguard Worker         }
850*35238bceSAndroid Build Coastguard Worker 
851*35238bceSAndroid Build Coastguard Worker         return true;
852*35238bceSAndroid Build Coastguard Worker     }
853*35238bceSAndroid Build Coastguard Worker };
854*35238bceSAndroid Build Coastguard Worker 
855*35238bceSAndroid Build Coastguard Worker class IsnanCase : public CommonFunctionCase
856*35238bceSAndroid Build Coastguard Worker {
857*35238bceSAndroid Build Coastguard Worker public:
IsnanCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)858*35238bceSAndroid Build Coastguard Worker     IsnanCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
859*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isnan",
860*35238bceSAndroid Build Coastguard Worker                              shaderType)
861*35238bceSAndroid Build Coastguard Worker     {
862*35238bceSAndroid Build Coastguard Worker         DE_ASSERT(glu::isDataTypeFloatOrVec(baseType));
863*35238bceSAndroid Build Coastguard Worker 
864*35238bceSAndroid Build Coastguard Worker         const int vecSize            = glu::getDataTypeScalarSize(baseType);
865*35238bceSAndroid Build Coastguard Worker         const glu::DataType boolType = vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
866*35238bceSAndroid Build Coastguard Worker 
867*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
868*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
869*35238bceSAndroid Build Coastguard Worker         m_spec.source = "out0 = isnan(in0);";
870*35238bceSAndroid Build Coastguard Worker     }
871*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const872*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
873*35238bceSAndroid Build Coastguard Worker     {
874*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0xc2a39fu);
875*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
876*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
877*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
878*35238bceSAndroid Build Coastguard Worker         const int mantissaBits         = getMinMantissaBits(precision);
879*35238bceSAndroid Build Coastguard Worker         const uint32_t mantissaMask    = ~getMaxUlpDiffFromBits(mantissaBits) & ((1u << 23) - 1u);
880*35238bceSAndroid Build Coastguard Worker 
881*35238bceSAndroid Build Coastguard Worker         for (int valNdx = 0; valNdx < numValues * scalarSize; valNdx++)
882*35238bceSAndroid Build Coastguard Worker         {
883*35238bceSAndroid Build Coastguard Worker             const bool isNan        = rnd.getFloat() > 0.3f;
884*35238bceSAndroid Build Coastguard Worker             const bool isInf        = !isNan && rnd.getFloat() > 0.4f;
885*35238bceSAndroid Build Coastguard Worker             const uint32_t mantissa = !isInf ? ((1u << 22) | (rnd.getUint32() & mantissaMask)) : 0;
886*35238bceSAndroid Build Coastguard Worker             const uint32_t exp      = !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu;
887*35238bceSAndroid Build Coastguard Worker             const uint32_t sign     = rnd.getUint32() & 0x1u;
888*35238bceSAndroid Build Coastguard Worker             const uint32_t value    = (sign << 31) | (exp << 23) | mantissa;
889*35238bceSAndroid Build Coastguard Worker 
890*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan);
891*35238bceSAndroid Build Coastguard Worker 
892*35238bceSAndroid Build Coastguard Worker             ((uint32_t *)values[0])[valNdx] = value;
893*35238bceSAndroid Build Coastguard Worker         }
894*35238bceSAndroid Build Coastguard Worker     }
895*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)896*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
897*35238bceSAndroid Build Coastguard Worker     {
898*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
899*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
900*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
901*35238bceSAndroid Build Coastguard Worker 
902*35238bceSAndroid Build Coastguard Worker         if (precision == glu::PRECISION_HIGHP)
903*35238bceSAndroid Build Coastguard Worker         {
904*35238bceSAndroid Build Coastguard Worker             // Only highp is required to support inf/nan
905*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
906*35238bceSAndroid Build Coastguard Worker             {
907*35238bceSAndroid Build Coastguard Worker                 const float in0 = ((const float *)inputs[0])[compNdx];
908*35238bceSAndroid Build Coastguard Worker                 const bool out0 = ((const uint32_t *)outputs[0])[compNdx] != 0;
909*35238bceSAndroid Build Coastguard Worker                 const bool ref  = tcu::Float32(in0).isNaN();
910*35238bceSAndroid Build Coastguard Worker 
911*35238bceSAndroid Build Coastguard Worker                 if (out0 != ref)
912*35238bceSAndroid Build Coastguard Worker                 {
913*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
914*35238bceSAndroid Build Coastguard Worker                     return false;
915*35238bceSAndroid Build Coastguard Worker                 }
916*35238bceSAndroid Build Coastguard Worker             }
917*35238bceSAndroid Build Coastguard Worker         }
918*35238bceSAndroid Build Coastguard Worker         else if (precision == glu::PRECISION_MEDIUMP || precision == glu::PRECISION_LOWP)
919*35238bceSAndroid Build Coastguard Worker         {
920*35238bceSAndroid Build Coastguard Worker             // NaN support is optional, check that inputs that are not NaN don't result in true.
921*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
922*35238bceSAndroid Build Coastguard Worker             {
923*35238bceSAndroid Build Coastguard Worker                 const float in0 = ((const float *)inputs[0])[compNdx];
924*35238bceSAndroid Build Coastguard Worker                 const bool out0 = ((const uint32_t *)outputs[0])[compNdx] != 0;
925*35238bceSAndroid Build Coastguard Worker                 const bool ref  = tcu::Float32(in0).isNaN();
926*35238bceSAndroid Build Coastguard Worker 
927*35238bceSAndroid Build Coastguard Worker                 if (!ref && out0)
928*35238bceSAndroid Build Coastguard Worker                 {
929*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
930*35238bceSAndroid Build Coastguard Worker                     return false;
931*35238bceSAndroid Build Coastguard Worker                 }
932*35238bceSAndroid Build Coastguard Worker             }
933*35238bceSAndroid Build Coastguard Worker         }
934*35238bceSAndroid Build Coastguard Worker 
935*35238bceSAndroid Build Coastguard Worker         return true;
936*35238bceSAndroid Build Coastguard Worker     }
937*35238bceSAndroid Build Coastguard Worker };
938*35238bceSAndroid Build Coastguard Worker 
939*35238bceSAndroid Build Coastguard Worker class IsinfCase : public CommonFunctionCase
940*35238bceSAndroid Build Coastguard Worker {
941*35238bceSAndroid Build Coastguard Worker public:
IsinfCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)942*35238bceSAndroid Build Coastguard Worker     IsinfCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
943*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isinf",
944*35238bceSAndroid Build Coastguard Worker                              shaderType)
945*35238bceSAndroid Build Coastguard Worker     {
946*35238bceSAndroid Build Coastguard Worker         DE_ASSERT(glu::isDataTypeFloatOrVec(baseType));
947*35238bceSAndroid Build Coastguard Worker 
948*35238bceSAndroid Build Coastguard Worker         const int vecSize            = glu::getDataTypeScalarSize(baseType);
949*35238bceSAndroid Build Coastguard Worker         const glu::DataType boolType = vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
950*35238bceSAndroid Build Coastguard Worker 
951*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
952*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
953*35238bceSAndroid Build Coastguard Worker         m_spec.source = "out0 = isinf(in0);";
954*35238bceSAndroid Build Coastguard Worker     }
955*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const956*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
957*35238bceSAndroid Build Coastguard Worker     {
958*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0xc2a39fu);
959*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
960*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
961*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
962*35238bceSAndroid Build Coastguard Worker         const int mantissaBits         = getMinMantissaBits(precision);
963*35238bceSAndroid Build Coastguard Worker         const uint32_t mantissaMask    = ~getMaxUlpDiffFromBits(mantissaBits) & ((1u << 23) - 1u);
964*35238bceSAndroid Build Coastguard Worker 
965*35238bceSAndroid Build Coastguard Worker         for (int valNdx = 0; valNdx < numValues * scalarSize; valNdx++)
966*35238bceSAndroid Build Coastguard Worker         {
967*35238bceSAndroid Build Coastguard Worker             const bool isInf        = rnd.getFloat() > 0.3f;
968*35238bceSAndroid Build Coastguard Worker             const bool isNan        = !isInf && rnd.getFloat() > 0.4f;
969*35238bceSAndroid Build Coastguard Worker             const uint32_t mantissa = !isInf ? ((1u << 22) | (rnd.getUint32() & mantissaMask)) : 0;
970*35238bceSAndroid Build Coastguard Worker             const uint32_t exp      = !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu;
971*35238bceSAndroid Build Coastguard Worker             const uint32_t sign     = rnd.getUint32() & 0x1u;
972*35238bceSAndroid Build Coastguard Worker             const uint32_t value    = (sign << 31) | (exp << 23) | mantissa;
973*35238bceSAndroid Build Coastguard Worker 
974*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan);
975*35238bceSAndroid Build Coastguard Worker 
976*35238bceSAndroid Build Coastguard Worker             ((uint32_t *)values[0])[valNdx] = value;
977*35238bceSAndroid Build Coastguard Worker         }
978*35238bceSAndroid Build Coastguard Worker     }
979*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)980*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
981*35238bceSAndroid Build Coastguard Worker     {
982*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
983*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
984*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
985*35238bceSAndroid Build Coastguard Worker 
986*35238bceSAndroid Build Coastguard Worker         if (precision == glu::PRECISION_HIGHP)
987*35238bceSAndroid Build Coastguard Worker         {
988*35238bceSAndroid Build Coastguard Worker             // Only highp is required to support inf/nan
989*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
990*35238bceSAndroid Build Coastguard Worker             {
991*35238bceSAndroid Build Coastguard Worker                 const float in0 = ((const float *)inputs[0])[compNdx];
992*35238bceSAndroid Build Coastguard Worker                 const bool out0 = ((const uint32_t *)outputs[0])[compNdx] != 0;
993*35238bceSAndroid Build Coastguard Worker                 const bool ref  = tcu::Float32(in0).isInf();
994*35238bceSAndroid Build Coastguard Worker 
995*35238bceSAndroid Build Coastguard Worker                 if (out0 != ref)
996*35238bceSAndroid Build Coastguard Worker                 {
997*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = " << HexBool(ref);
998*35238bceSAndroid Build Coastguard Worker                     return false;
999*35238bceSAndroid Build Coastguard Worker                 }
1000*35238bceSAndroid Build Coastguard Worker             }
1001*35238bceSAndroid Build Coastguard Worker         }
1002*35238bceSAndroid Build Coastguard Worker         else if (precision == glu::PRECISION_MEDIUMP)
1003*35238bceSAndroid Build Coastguard Worker         {
1004*35238bceSAndroid Build Coastguard Worker             // Inf support is optional, check that inputs that are not Inf in mediump don't result in true.
1005*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1006*35238bceSAndroid Build Coastguard Worker             {
1007*35238bceSAndroid Build Coastguard Worker                 const float in0 = ((const float *)inputs[0])[compNdx];
1008*35238bceSAndroid Build Coastguard Worker                 const bool out0 = ((const uint32_t *)outputs[0])[compNdx] != 0;
1009*35238bceSAndroid Build Coastguard Worker                 const bool ref  = tcu::Float16(in0).isInf();
1010*35238bceSAndroid Build Coastguard Worker 
1011*35238bceSAndroid Build Coastguard Worker                 if (!ref && out0)
1012*35238bceSAndroid Build Coastguard Worker                 {
1013*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
1014*35238bceSAndroid Build Coastguard Worker                     return false;
1015*35238bceSAndroid Build Coastguard Worker                 }
1016*35238bceSAndroid Build Coastguard Worker             }
1017*35238bceSAndroid Build Coastguard Worker         }
1018*35238bceSAndroid Build Coastguard Worker         // else: no verification can be performed
1019*35238bceSAndroid Build Coastguard Worker 
1020*35238bceSAndroid Build Coastguard Worker         return true;
1021*35238bceSAndroid Build Coastguard Worker     }
1022*35238bceSAndroid Build Coastguard Worker };
1023*35238bceSAndroid Build Coastguard Worker 
1024*35238bceSAndroid Build Coastguard Worker class FloatBitsToUintIntCase : public CommonFunctionCase
1025*35238bceSAndroid Build Coastguard Worker {
1026*35238bceSAndroid Build Coastguard Worker public:
FloatBitsToUintIntCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType,bool outIsSigned)1027*35238bceSAndroid Build Coastguard Worker     FloatBitsToUintIntCase(Context &context, glu::DataType baseType, glu::Precision precision,
1028*35238bceSAndroid Build Coastguard Worker                            glu::ShaderType shaderType, bool outIsSigned)
1029*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(),
1030*35238bceSAndroid Build Coastguard Worker                              outIsSigned ? "floatBitsToInt" : "floatBitsToUint", shaderType)
1031*35238bceSAndroid Build Coastguard Worker     {
1032*35238bceSAndroid Build Coastguard Worker         const int vecSize           = glu::getDataTypeScalarSize(baseType);
1033*35238bceSAndroid Build Coastguard Worker         const glu::DataType intType = outIsSigned ? (vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT) :
1034*35238bceSAndroid Build Coastguard Worker                                                     (vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT);
1035*35238bceSAndroid Build Coastguard Worker 
1036*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1037*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(intType, glu::PRECISION_HIGHP)));
1038*35238bceSAndroid Build Coastguard Worker         m_spec.source = outIsSigned ? "out0 = floatBitsToInt(in0);" : "out0 = floatBitsToUint(in0);";
1039*35238bceSAndroid Build Coastguard Worker     }
1040*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const1041*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
1042*35238bceSAndroid Build Coastguard Worker     {
1043*35238bceSAndroid Build Coastguard Worker         const Vec2 ranges[] = {
1044*35238bceSAndroid Build Coastguard Worker             Vec2(-2.0f, 2.0f), // lowp
1045*35238bceSAndroid Build Coastguard Worker             Vec2(-1e3f, 1e3f), // mediump
1046*35238bceSAndroid Build Coastguard Worker             Vec2(-1e7f, 1e7f)  // highp
1047*35238bceSAndroid Build Coastguard Worker         };
1048*35238bceSAndroid Build Coastguard Worker 
1049*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0x2790au);
1050*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1051*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1052*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1053*35238bceSAndroid Build Coastguard Worker 
1054*35238bceSAndroid Build Coastguard Worker         fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues * scalarSize);
1055*35238bceSAndroid Build Coastguard Worker     }
1056*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)1057*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
1058*35238bceSAndroid Build Coastguard Worker     {
1059*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1060*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1061*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1062*35238bceSAndroid Build Coastguard Worker 
1063*35238bceSAndroid Build Coastguard Worker         const int mantissaBits = getMinMantissaBits(precision);
1064*35238bceSAndroid Build Coastguard Worker         const int maxUlpDiff   = getMaxUlpDiffFromBits(mantissaBits);
1065*35238bceSAndroid Build Coastguard Worker 
1066*35238bceSAndroid Build Coastguard Worker         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1067*35238bceSAndroid Build Coastguard Worker         {
1068*35238bceSAndroid Build Coastguard Worker             const float in0        = ((const float *)inputs[0])[compNdx];
1069*35238bceSAndroid Build Coastguard Worker             const uint32_t out0    = ((const uint32_t *)outputs[0])[compNdx];
1070*35238bceSAndroid Build Coastguard Worker             const uint32_t refOut0 = tcu::Float32(in0).bits();
1071*35238bceSAndroid Build Coastguard Worker             const int ulpDiff      = de::abs((int)out0 - (int)refOut0);
1072*35238bceSAndroid Build Coastguard Worker 
1073*35238bceSAndroid Build Coastguard Worker             if (ulpDiff > maxUlpDiff)
1074*35238bceSAndroid Build Coastguard Worker             {
1075*35238bceSAndroid Build Coastguard Worker                 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(refOut0) << " with threshold "
1076*35238bceSAndroid Build Coastguard Worker                           << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
1077*35238bceSAndroid Build Coastguard Worker                 return false;
1078*35238bceSAndroid Build Coastguard Worker             }
1079*35238bceSAndroid Build Coastguard Worker         }
1080*35238bceSAndroid Build Coastguard Worker 
1081*35238bceSAndroid Build Coastguard Worker         return true;
1082*35238bceSAndroid Build Coastguard Worker     }
1083*35238bceSAndroid Build Coastguard Worker };
1084*35238bceSAndroid Build Coastguard Worker 
1085*35238bceSAndroid Build Coastguard Worker class FloatBitsToIntCase : public FloatBitsToUintIntCase
1086*35238bceSAndroid Build Coastguard Worker {
1087*35238bceSAndroid Build Coastguard Worker public:
FloatBitsToIntCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1088*35238bceSAndroid Build Coastguard Worker     FloatBitsToIntCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1089*35238bceSAndroid Build Coastguard Worker         : FloatBitsToUintIntCase(context, baseType, precision, shaderType, true)
1090*35238bceSAndroid Build Coastguard Worker     {
1091*35238bceSAndroid Build Coastguard Worker     }
1092*35238bceSAndroid Build Coastguard Worker };
1093*35238bceSAndroid Build Coastguard Worker 
1094*35238bceSAndroid Build Coastguard Worker class FloatBitsToUintCase : public FloatBitsToUintIntCase
1095*35238bceSAndroid Build Coastguard Worker {
1096*35238bceSAndroid Build Coastguard Worker public:
FloatBitsToUintCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1097*35238bceSAndroid Build Coastguard Worker     FloatBitsToUintCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1098*35238bceSAndroid Build Coastguard Worker         : FloatBitsToUintIntCase(context, baseType, precision, shaderType, false)
1099*35238bceSAndroid Build Coastguard Worker     {
1100*35238bceSAndroid Build Coastguard Worker     }
1101*35238bceSAndroid Build Coastguard Worker };
1102*35238bceSAndroid Build Coastguard Worker 
1103*35238bceSAndroid Build Coastguard Worker class BitsToFloatCase : public CommonFunctionCase
1104*35238bceSAndroid Build Coastguard Worker {
1105*35238bceSAndroid Build Coastguard Worker public:
BitsToFloatCase(Context & context,glu::DataType baseType,glu::ShaderType shaderType)1106*35238bceSAndroid Build Coastguard Worker     BitsToFloatCase(Context &context, glu::DataType baseType, glu::ShaderType shaderType)
1107*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, glu::PRECISION_HIGHP, shaderType).c_str(),
1108*35238bceSAndroid Build Coastguard Worker                              glu::isDataTypeIntOrIVec(baseType) ? "intBitsToFloat" : "uintBitsToFloat", shaderType)
1109*35238bceSAndroid Build Coastguard Worker     {
1110*35238bceSAndroid Build Coastguard Worker         const bool inIsSigned         = glu::isDataTypeIntOrIVec(baseType);
1111*35238bceSAndroid Build Coastguard Worker         const int vecSize             = glu::getDataTypeScalarSize(baseType);
1112*35238bceSAndroid Build Coastguard Worker         const glu::DataType floatType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1113*35238bceSAndroid Build Coastguard Worker 
1114*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
1115*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(floatType, glu::PRECISION_HIGHP)));
1116*35238bceSAndroid Build Coastguard Worker         m_spec.source = inIsSigned ? "out0 = intBitsToFloat(in0);" : "out0 = uintBitsToFloat(in0);";
1117*35238bceSAndroid Build Coastguard Worker     }
1118*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const1119*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
1120*35238bceSAndroid Build Coastguard Worker     {
1121*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0xbbb225u);
1122*35238bceSAndroid Build Coastguard Worker         const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
1123*35238bceSAndroid Build Coastguard Worker         const int scalarSize     = glu::getDataTypeScalarSize(type);
1124*35238bceSAndroid Build Coastguard Worker         const Vec2 range(-1e8f, +1e8f);
1125*35238bceSAndroid Build Coastguard Worker 
1126*35238bceSAndroid Build Coastguard Worker         // \note Filled as floats.
1127*35238bceSAndroid Build Coastguard Worker         fillRandomScalars(rnd, range.x(), range.y(), values[0], numValues * scalarSize);
1128*35238bceSAndroid Build Coastguard Worker     }
1129*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)1130*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
1131*35238bceSAndroid Build Coastguard Worker     {
1132*35238bceSAndroid Build Coastguard Worker         const glu::DataType type  = m_spec.inputs[0].varType.getBasicType();
1133*35238bceSAndroid Build Coastguard Worker         const int scalarSize      = glu::getDataTypeScalarSize(type);
1134*35238bceSAndroid Build Coastguard Worker         const uint32_t maxUlpDiff = 0;
1135*35238bceSAndroid Build Coastguard Worker 
1136*35238bceSAndroid Build Coastguard Worker         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1137*35238bceSAndroid Build Coastguard Worker         {
1138*35238bceSAndroid Build Coastguard Worker             const float in0        = ((const float *)inputs[0])[compNdx];
1139*35238bceSAndroid Build Coastguard Worker             const float out0       = ((const float *)outputs[0])[compNdx];
1140*35238bceSAndroid Build Coastguard Worker             const uint32_t ulpDiff = getUlpDiff(in0, out0);
1141*35238bceSAndroid Build Coastguard Worker 
1142*35238bceSAndroid Build Coastguard Worker             if (ulpDiff > maxUlpDiff)
1143*35238bceSAndroid Build Coastguard Worker             {
1144*35238bceSAndroid Build Coastguard Worker                 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(tcu::Float32(in0).bits())
1145*35238bceSAndroid Build Coastguard Worker                           << " with ULP threshold " << tcu::toHex(maxUlpDiff) << ", got ULP diff "
1146*35238bceSAndroid Build Coastguard Worker                           << tcu::toHex(ulpDiff);
1147*35238bceSAndroid Build Coastguard Worker                 return false;
1148*35238bceSAndroid Build Coastguard Worker             }
1149*35238bceSAndroid Build Coastguard Worker         }
1150*35238bceSAndroid Build Coastguard Worker 
1151*35238bceSAndroid Build Coastguard Worker         return true;
1152*35238bceSAndroid Build Coastguard Worker     }
1153*35238bceSAndroid Build Coastguard Worker };
1154*35238bceSAndroid Build Coastguard Worker 
1155*35238bceSAndroid Build Coastguard Worker class FloorCase : public CommonFunctionCase
1156*35238bceSAndroid Build Coastguard Worker {
1157*35238bceSAndroid Build Coastguard Worker public:
FloorCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1158*35238bceSAndroid Build Coastguard Worker     FloorCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1159*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "floor",
1160*35238bceSAndroid Build Coastguard Worker                              shaderType)
1161*35238bceSAndroid Build Coastguard Worker     {
1162*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1163*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1164*35238bceSAndroid Build Coastguard Worker         m_spec.source = "out0 = floor(in0);";
1165*35238bceSAndroid Build Coastguard Worker     }
1166*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const1167*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
1168*35238bceSAndroid Build Coastguard Worker     {
1169*35238bceSAndroid Build Coastguard Worker         const Vec2 ranges[] = {
1170*35238bceSAndroid Build Coastguard Worker             Vec2(-2.0f, 2.0f), // lowp
1171*35238bceSAndroid Build Coastguard Worker             Vec2(-1e3f, 1e3f), // mediump
1172*35238bceSAndroid Build Coastguard Worker             Vec2(-1e7f, 1e7f)  // highp
1173*35238bceSAndroid Build Coastguard Worker         };
1174*35238bceSAndroid Build Coastguard Worker 
1175*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0xac23fu);
1176*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1177*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1178*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1179*35238bceSAndroid Build Coastguard Worker         // Random cases.
1180*35238bceSAndroid Build Coastguard Worker         fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float *)values[0],
1181*35238bceSAndroid Build Coastguard Worker                           numValues * scalarSize);
1182*35238bceSAndroid Build Coastguard Worker 
1183*35238bceSAndroid Build Coastguard Worker         // If precision is mediump, make sure values can be represented in fp16 exactly
1184*35238bceSAndroid Build Coastguard Worker         if (precision == glu::PRECISION_MEDIUMP)
1185*35238bceSAndroid Build Coastguard Worker         {
1186*35238bceSAndroid Build Coastguard Worker             for (int ndx = 0; ndx < numValues * scalarSize; ndx++)
1187*35238bceSAndroid Build Coastguard Worker                 ((float *)values[0])[ndx] = tcu::Float16(((float *)values[0])[ndx]).asFloat();
1188*35238bceSAndroid Build Coastguard Worker         }
1189*35238bceSAndroid Build Coastguard Worker     }
1190*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)1191*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
1192*35238bceSAndroid Build Coastguard Worker     {
1193*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1194*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1195*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1196*35238bceSAndroid Build Coastguard Worker 
1197*35238bceSAndroid Build Coastguard Worker         if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1198*35238bceSAndroid Build Coastguard Worker         {
1199*35238bceSAndroid Build Coastguard Worker             // Require exact result.
1200*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1201*35238bceSAndroid Build Coastguard Worker             {
1202*35238bceSAndroid Build Coastguard Worker                 const float in0  = ((const float *)inputs[0])[compNdx];
1203*35238bceSAndroid Build Coastguard Worker                 const float out0 = ((const float *)outputs[0])[compNdx];
1204*35238bceSAndroid Build Coastguard Worker                 const float ref  = deFloatFloor(in0);
1205*35238bceSAndroid Build Coastguard Worker 
1206*35238bceSAndroid Build Coastguard Worker                 const uint32_t ulpDiff = getUlpDiff(out0, ref);
1207*35238bceSAndroid Build Coastguard Worker 
1208*35238bceSAndroid Build Coastguard Worker                 if (ulpDiff > 0)
1209*35238bceSAndroid Build Coastguard Worker                 {
1210*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff "
1211*35238bceSAndroid Build Coastguard Worker                               << tcu::toHex(ulpDiff);
1212*35238bceSAndroid Build Coastguard Worker                     return false;
1213*35238bceSAndroid Build Coastguard Worker                 }
1214*35238bceSAndroid Build Coastguard Worker             }
1215*35238bceSAndroid Build Coastguard Worker         }
1216*35238bceSAndroid Build Coastguard Worker         else
1217*35238bceSAndroid Build Coastguard Worker         {
1218*35238bceSAndroid Build Coastguard Worker             const int mantissaBits    = getMinMantissaBits(precision);
1219*35238bceSAndroid Build Coastguard Worker             const uint32_t maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value.
1220*35238bceSAndroid Build Coastguard Worker             const float eps           = getEpsFromBits(1.0f, mantissaBits);  // epsilon for rounding bounds
1221*35238bceSAndroid Build Coastguard Worker 
1222*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1223*35238bceSAndroid Build Coastguard Worker             {
1224*35238bceSAndroid Build Coastguard Worker                 const float in0  = ((const float *)inputs[0])[compNdx];
1225*35238bceSAndroid Build Coastguard Worker                 const float out0 = ((const float *)outputs[0])[compNdx];
1226*35238bceSAndroid Build Coastguard Worker                 const int minRes = int(deFloatFloor(in0 - eps));
1227*35238bceSAndroid Build Coastguard Worker                 const int maxRes = int(deFloatFloor(in0 + eps));
1228*35238bceSAndroid Build Coastguard Worker                 bool anyOk       = false;
1229*35238bceSAndroid Build Coastguard Worker 
1230*35238bceSAndroid Build Coastguard Worker                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1231*35238bceSAndroid Build Coastguard Worker                 {
1232*35238bceSAndroid Build Coastguard Worker                     const uint32_t ulpDiff = getUlpDiff(out0, float(roundedVal));
1233*35238bceSAndroid Build Coastguard Worker 
1234*35238bceSAndroid Build Coastguard Worker                     if (ulpDiff <= maxUlpDiff)
1235*35238bceSAndroid Build Coastguard Worker                     {
1236*35238bceSAndroid Build Coastguard Worker                         anyOk = true;
1237*35238bceSAndroid Build Coastguard Worker                         break;
1238*35238bceSAndroid Build Coastguard Worker                     }
1239*35238bceSAndroid Build Coastguard Worker                 }
1240*35238bceSAndroid Build Coastguard Worker 
1241*35238bceSAndroid Build Coastguard Worker                 if (!anyOk)
1242*35238bceSAndroid Build Coastguard Worker                 {
1243*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes
1244*35238bceSAndroid Build Coastguard Worker                               << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1245*35238bceSAndroid Build Coastguard Worker                     return false;
1246*35238bceSAndroid Build Coastguard Worker                 }
1247*35238bceSAndroid Build Coastguard Worker             }
1248*35238bceSAndroid Build Coastguard Worker         }
1249*35238bceSAndroid Build Coastguard Worker 
1250*35238bceSAndroid Build Coastguard Worker         return true;
1251*35238bceSAndroid Build Coastguard Worker     }
1252*35238bceSAndroid Build Coastguard Worker };
1253*35238bceSAndroid Build Coastguard Worker 
1254*35238bceSAndroid Build Coastguard Worker class TruncCase : public CommonFunctionCase
1255*35238bceSAndroid Build Coastguard Worker {
1256*35238bceSAndroid Build Coastguard Worker public:
TruncCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1257*35238bceSAndroid Build Coastguard Worker     TruncCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1258*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "trunc",
1259*35238bceSAndroid Build Coastguard Worker                              shaderType)
1260*35238bceSAndroid Build Coastguard Worker     {
1261*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1262*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1263*35238bceSAndroid Build Coastguard Worker         m_spec.source = "out0 = trunc(in0);";
1264*35238bceSAndroid Build Coastguard Worker     }
1265*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const1266*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
1267*35238bceSAndroid Build Coastguard Worker     {
1268*35238bceSAndroid Build Coastguard Worker         const Vec2 ranges[] = {
1269*35238bceSAndroid Build Coastguard Worker             Vec2(-2.0f, 2.0f), // lowp
1270*35238bceSAndroid Build Coastguard Worker             Vec2(-1e3f, 1e3f), // mediump
1271*35238bceSAndroid Build Coastguard Worker             Vec2(-1e7f, 1e7f)  // highp
1272*35238bceSAndroid Build Coastguard Worker         };
1273*35238bceSAndroid Build Coastguard Worker 
1274*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0xac23fu);
1275*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1276*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1277*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1278*35238bceSAndroid Build Coastguard Worker         const float specialCases[]     = {0.0f, -0.0f, -0.9f, 0.9f, 1.0f, -1.0f};
1279*35238bceSAndroid Build Coastguard Worker         const int numSpecialCases      = DE_LENGTH_OF_ARRAY(specialCases);
1280*35238bceSAndroid Build Coastguard Worker 
1281*35238bceSAndroid Build Coastguard Worker         // Special cases
1282*35238bceSAndroid Build Coastguard Worker         for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++)
1283*35238bceSAndroid Build Coastguard Worker         {
1284*35238bceSAndroid Build Coastguard Worker             for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1285*35238bceSAndroid Build Coastguard Worker                 ((float *)values[0])[caseNdx * scalarSize + scalarNdx] = specialCases[caseNdx];
1286*35238bceSAndroid Build Coastguard Worker         }
1287*35238bceSAndroid Build Coastguard Worker 
1288*35238bceSAndroid Build Coastguard Worker         // Random cases.
1289*35238bceSAndroid Build Coastguard Worker         fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(),
1290*35238bceSAndroid Build Coastguard Worker                           (float *)values[0] + scalarSize * numSpecialCases,
1291*35238bceSAndroid Build Coastguard Worker                           (numValues - numSpecialCases) * scalarSize);
1292*35238bceSAndroid Build Coastguard Worker 
1293*35238bceSAndroid Build Coastguard Worker         // If precision is mediump, make sure values can be represented in fp16 exactly
1294*35238bceSAndroid Build Coastguard Worker         if (precision == glu::PRECISION_MEDIUMP)
1295*35238bceSAndroid Build Coastguard Worker         {
1296*35238bceSAndroid Build Coastguard Worker             for (int ndx = 0; ndx < numValues * scalarSize; ndx++)
1297*35238bceSAndroid Build Coastguard Worker                 ((float *)values[0])[ndx] = tcu::Float16(((float *)values[0])[ndx]).asFloat();
1298*35238bceSAndroid Build Coastguard Worker         }
1299*35238bceSAndroid Build Coastguard Worker     }
1300*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)1301*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
1302*35238bceSAndroid Build Coastguard Worker     {
1303*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1304*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1305*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1306*35238bceSAndroid Build Coastguard Worker 
1307*35238bceSAndroid Build Coastguard Worker         if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1308*35238bceSAndroid Build Coastguard Worker         {
1309*35238bceSAndroid Build Coastguard Worker             // Require exact result.
1310*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1311*35238bceSAndroid Build Coastguard Worker             {
1312*35238bceSAndroid Build Coastguard Worker                 const float in0  = ((const float *)inputs[0])[compNdx];
1313*35238bceSAndroid Build Coastguard Worker                 const float out0 = ((const float *)outputs[0])[compNdx];
1314*35238bceSAndroid Build Coastguard Worker                 const bool isNeg = tcu::Float32(in0).sign() < 0;
1315*35238bceSAndroid Build Coastguard Worker                 const float ref  = isNeg ? (-float(int(-in0))) : float(int(in0));
1316*35238bceSAndroid Build Coastguard Worker 
1317*35238bceSAndroid Build Coastguard Worker                 // \note: trunc() function definition is a bit broad on negative zeros. Ignore result sign if zero.
1318*35238bceSAndroid Build Coastguard Worker                 const uint32_t ulpDiff = getUlpDiffIgnoreZeroSign(out0, ref);
1319*35238bceSAndroid Build Coastguard Worker 
1320*35238bceSAndroid Build Coastguard Worker                 if (ulpDiff > 0)
1321*35238bceSAndroid Build Coastguard Worker                 {
1322*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff "
1323*35238bceSAndroid Build Coastguard Worker                               << tcu::toHex(ulpDiff);
1324*35238bceSAndroid Build Coastguard Worker                     return false;
1325*35238bceSAndroid Build Coastguard Worker                 }
1326*35238bceSAndroid Build Coastguard Worker             }
1327*35238bceSAndroid Build Coastguard Worker         }
1328*35238bceSAndroid Build Coastguard Worker         else
1329*35238bceSAndroid Build Coastguard Worker         {
1330*35238bceSAndroid Build Coastguard Worker             const int mantissaBits    = getMinMantissaBits(precision);
1331*35238bceSAndroid Build Coastguard Worker             const uint32_t maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value.
1332*35238bceSAndroid Build Coastguard Worker             const float eps           = getEpsFromBits(1.0f, mantissaBits);  // epsilon for rounding bounds
1333*35238bceSAndroid Build Coastguard Worker 
1334*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1335*35238bceSAndroid Build Coastguard Worker             {
1336*35238bceSAndroid Build Coastguard Worker                 const float in0  = ((const float *)inputs[0])[compNdx];
1337*35238bceSAndroid Build Coastguard Worker                 const float out0 = ((const float *)outputs[0])[compNdx];
1338*35238bceSAndroid Build Coastguard Worker                 const int minRes = int(in0 - eps);
1339*35238bceSAndroid Build Coastguard Worker                 const int maxRes = int(in0 + eps);
1340*35238bceSAndroid Build Coastguard Worker                 bool anyOk       = false;
1341*35238bceSAndroid Build Coastguard Worker 
1342*35238bceSAndroid Build Coastguard Worker                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1343*35238bceSAndroid Build Coastguard Worker                 {
1344*35238bceSAndroid Build Coastguard Worker                     const uint32_t ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1345*35238bceSAndroid Build Coastguard Worker 
1346*35238bceSAndroid Build Coastguard Worker                     if (ulpDiff <= maxUlpDiff)
1347*35238bceSAndroid Build Coastguard Worker                     {
1348*35238bceSAndroid Build Coastguard Worker                         anyOk = true;
1349*35238bceSAndroid Build Coastguard Worker                         break;
1350*35238bceSAndroid Build Coastguard Worker                     }
1351*35238bceSAndroid Build Coastguard Worker                 }
1352*35238bceSAndroid Build Coastguard Worker 
1353*35238bceSAndroid Build Coastguard Worker                 if (!anyOk)
1354*35238bceSAndroid Build Coastguard Worker                 {
1355*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes
1356*35238bceSAndroid Build Coastguard Worker                               << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1357*35238bceSAndroid Build Coastguard Worker                     return false;
1358*35238bceSAndroid Build Coastguard Worker                 }
1359*35238bceSAndroid Build Coastguard Worker             }
1360*35238bceSAndroid Build Coastguard Worker         }
1361*35238bceSAndroid Build Coastguard Worker 
1362*35238bceSAndroid Build Coastguard Worker         return true;
1363*35238bceSAndroid Build Coastguard Worker     }
1364*35238bceSAndroid Build Coastguard Worker };
1365*35238bceSAndroid Build Coastguard Worker 
1366*35238bceSAndroid Build Coastguard Worker class RoundCase : public CommonFunctionCase
1367*35238bceSAndroid Build Coastguard Worker {
1368*35238bceSAndroid Build Coastguard Worker public:
RoundCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1369*35238bceSAndroid Build Coastguard Worker     RoundCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1370*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "round",
1371*35238bceSAndroid Build Coastguard Worker                              shaderType)
1372*35238bceSAndroid Build Coastguard Worker     {
1373*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1374*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1375*35238bceSAndroid Build Coastguard Worker         m_spec.source = "out0 = round(in0);";
1376*35238bceSAndroid Build Coastguard Worker     }
1377*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const1378*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
1379*35238bceSAndroid Build Coastguard Worker     {
1380*35238bceSAndroid Build Coastguard Worker         const Vec2 ranges[] = {
1381*35238bceSAndroid Build Coastguard Worker             Vec2(-2.0f, 2.0f), // lowp
1382*35238bceSAndroid Build Coastguard Worker             Vec2(-1e3f, 1e3f), // mediump
1383*35238bceSAndroid Build Coastguard Worker             Vec2(-1e7f, 1e7f)  // highp
1384*35238bceSAndroid Build Coastguard Worker         };
1385*35238bceSAndroid Build Coastguard Worker 
1386*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0xac23fu);
1387*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1388*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1389*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1390*35238bceSAndroid Build Coastguard Worker         int numSpecialCases            = 0;
1391*35238bceSAndroid Build Coastguard Worker 
1392*35238bceSAndroid Build Coastguard Worker         // Special cases.
1393*35238bceSAndroid Build Coastguard Worker         if (precision != glu::PRECISION_LOWP)
1394*35238bceSAndroid Build Coastguard Worker         {
1395*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(numValues >= 10);
1396*35238bceSAndroid Build Coastguard Worker             for (int ndx = 0; ndx < 10; ndx++)
1397*35238bceSAndroid Build Coastguard Worker             {
1398*35238bceSAndroid Build Coastguard Worker                 const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y());
1399*35238bceSAndroid Build Coastguard Worker                 std::fill((float *)values[0], (float *)values[0] + scalarSize, v);
1400*35238bceSAndroid Build Coastguard Worker                 numSpecialCases += 1;
1401*35238bceSAndroid Build Coastguard Worker             }
1402*35238bceSAndroid Build Coastguard Worker         }
1403*35238bceSAndroid Build Coastguard Worker 
1404*35238bceSAndroid Build Coastguard Worker         // Random cases.
1405*35238bceSAndroid Build Coastguard Worker         fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(),
1406*35238bceSAndroid Build Coastguard Worker                           (float *)values[0] + numSpecialCases * scalarSize,
1407*35238bceSAndroid Build Coastguard Worker                           (numValues - numSpecialCases) * scalarSize);
1408*35238bceSAndroid Build Coastguard Worker 
1409*35238bceSAndroid Build Coastguard Worker         // If precision is mediump, make sure values can be represented in fp16 exactly
1410*35238bceSAndroid Build Coastguard Worker         if (precision == glu::PRECISION_MEDIUMP)
1411*35238bceSAndroid Build Coastguard Worker         {
1412*35238bceSAndroid Build Coastguard Worker             for (int ndx = 0; ndx < numValues * scalarSize; ndx++)
1413*35238bceSAndroid Build Coastguard Worker                 ((float *)values[0])[ndx] = tcu::Float16(((float *)values[0])[ndx]).asFloat();
1414*35238bceSAndroid Build Coastguard Worker         }
1415*35238bceSAndroid Build Coastguard Worker     }
1416*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)1417*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
1418*35238bceSAndroid Build Coastguard Worker     {
1419*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1420*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1421*35238bceSAndroid Build Coastguard Worker         const bool hasZeroSign         = supportsSignedZero(precision);
1422*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1423*35238bceSAndroid Build Coastguard Worker 
1424*35238bceSAndroid Build Coastguard Worker         if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1425*35238bceSAndroid Build Coastguard Worker         {
1426*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1427*35238bceSAndroid Build Coastguard Worker             {
1428*35238bceSAndroid Build Coastguard Worker                 const float in0  = ((const float *)inputs[0])[compNdx];
1429*35238bceSAndroid Build Coastguard Worker                 const float out0 = ((const float *)outputs[0])[compNdx];
1430*35238bceSAndroid Build Coastguard Worker 
1431*35238bceSAndroid Build Coastguard Worker                 if (deFloatFrac(in0) == 0.5f)
1432*35238bceSAndroid Build Coastguard Worker                 {
1433*35238bceSAndroid Build Coastguard Worker                     // Allow both ceil(in) and floor(in)
1434*35238bceSAndroid Build Coastguard Worker                     const float ref0 = deFloatFloor(in0);
1435*35238bceSAndroid Build Coastguard Worker                     const float ref1 = deFloatCeil(in0);
1436*35238bceSAndroid Build Coastguard Worker                     const uint32_t ulpDiff0 =
1437*35238bceSAndroid Build Coastguard Worker                         hasZeroSign ? getUlpDiff(out0, ref0) : getUlpDiffIgnoreZeroSign(out0, ref0);
1438*35238bceSAndroid Build Coastguard Worker                     const uint32_t ulpDiff1 =
1439*35238bceSAndroid Build Coastguard Worker                         hasZeroSign ? getUlpDiff(out0, ref1) : getUlpDiffIgnoreZeroSign(out0, ref1);
1440*35238bceSAndroid Build Coastguard Worker 
1441*35238bceSAndroid Build Coastguard Worker                     if (ulpDiff0 > 0 && ulpDiff1 > 0)
1442*35238bceSAndroid Build Coastguard Worker                     {
1443*35238bceSAndroid Build Coastguard Worker                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " or " << HexFloat(ref1)
1444*35238bceSAndroid Build Coastguard Worker                                   << ", got ULP diff " << tcu::toHex(de::min(ulpDiff0, ulpDiff1));
1445*35238bceSAndroid Build Coastguard Worker                         return false;
1446*35238bceSAndroid Build Coastguard Worker                     }
1447*35238bceSAndroid Build Coastguard Worker                 }
1448*35238bceSAndroid Build Coastguard Worker                 else
1449*35238bceSAndroid Build Coastguard Worker                 {
1450*35238bceSAndroid Build Coastguard Worker                     // Require exact result
1451*35238bceSAndroid Build Coastguard Worker                     const float ref        = roundEven(in0);
1452*35238bceSAndroid Build Coastguard Worker                     const uint32_t ulpDiff = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1453*35238bceSAndroid Build Coastguard Worker 
1454*35238bceSAndroid Build Coastguard Worker                     if (ulpDiff > 0)
1455*35238bceSAndroid Build Coastguard Worker                     {
1456*35238bceSAndroid Build Coastguard Worker                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff "
1457*35238bceSAndroid Build Coastguard Worker                                   << tcu::toHex(ulpDiff);
1458*35238bceSAndroid Build Coastguard Worker                         return false;
1459*35238bceSAndroid Build Coastguard Worker                     }
1460*35238bceSAndroid Build Coastguard Worker                 }
1461*35238bceSAndroid Build Coastguard Worker             }
1462*35238bceSAndroid Build Coastguard Worker         }
1463*35238bceSAndroid Build Coastguard Worker         else
1464*35238bceSAndroid Build Coastguard Worker         {
1465*35238bceSAndroid Build Coastguard Worker             const int mantissaBits    = getMinMantissaBits(precision);
1466*35238bceSAndroid Build Coastguard Worker             const uint32_t maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value.
1467*35238bceSAndroid Build Coastguard Worker             const float eps           = getEpsFromBits(1.0f, mantissaBits);  // epsilon for rounding bounds
1468*35238bceSAndroid Build Coastguard Worker 
1469*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1470*35238bceSAndroid Build Coastguard Worker             {
1471*35238bceSAndroid Build Coastguard Worker                 const float in0  = ((const float *)inputs[0])[compNdx];
1472*35238bceSAndroid Build Coastguard Worker                 const float out0 = ((const float *)outputs[0])[compNdx];
1473*35238bceSAndroid Build Coastguard Worker                 const int minRes = int(roundEven(in0 - eps));
1474*35238bceSAndroid Build Coastguard Worker                 const int maxRes = int(roundEven(in0 + eps));
1475*35238bceSAndroid Build Coastguard Worker                 bool anyOk       = false;
1476*35238bceSAndroid Build Coastguard Worker 
1477*35238bceSAndroid Build Coastguard Worker                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1478*35238bceSAndroid Build Coastguard Worker                 {
1479*35238bceSAndroid Build Coastguard Worker                     const uint32_t ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1480*35238bceSAndroid Build Coastguard Worker 
1481*35238bceSAndroid Build Coastguard Worker                     if (ulpDiff <= maxUlpDiff)
1482*35238bceSAndroid Build Coastguard Worker                     {
1483*35238bceSAndroid Build Coastguard Worker                         anyOk = true;
1484*35238bceSAndroid Build Coastguard Worker                         break;
1485*35238bceSAndroid Build Coastguard Worker                     }
1486*35238bceSAndroid Build Coastguard Worker                 }
1487*35238bceSAndroid Build Coastguard Worker 
1488*35238bceSAndroid Build Coastguard Worker                 if (!anyOk)
1489*35238bceSAndroid Build Coastguard Worker                 {
1490*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes
1491*35238bceSAndroid Build Coastguard Worker                               << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1492*35238bceSAndroid Build Coastguard Worker                     return false;
1493*35238bceSAndroid Build Coastguard Worker                 }
1494*35238bceSAndroid Build Coastguard Worker             }
1495*35238bceSAndroid Build Coastguard Worker         }
1496*35238bceSAndroid Build Coastguard Worker 
1497*35238bceSAndroid Build Coastguard Worker         return true;
1498*35238bceSAndroid Build Coastguard Worker     }
1499*35238bceSAndroid Build Coastguard Worker };
1500*35238bceSAndroid Build Coastguard Worker 
1501*35238bceSAndroid Build Coastguard Worker class CeilCase : public CommonFunctionCase
1502*35238bceSAndroid Build Coastguard Worker {
1503*35238bceSAndroid Build Coastguard Worker public:
CeilCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1504*35238bceSAndroid Build Coastguard Worker     CeilCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1505*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ceil",
1506*35238bceSAndroid Build Coastguard Worker                              shaderType)
1507*35238bceSAndroid Build Coastguard Worker     {
1508*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1509*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1510*35238bceSAndroid Build Coastguard Worker         m_spec.source = "out0 = ceil(in0);";
1511*35238bceSAndroid Build Coastguard Worker     }
1512*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const1513*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
1514*35238bceSAndroid Build Coastguard Worker     {
1515*35238bceSAndroid Build Coastguard Worker         const Vec2 ranges[] = {
1516*35238bceSAndroid Build Coastguard Worker             Vec2(-2.0f, 2.0f), // lowp
1517*35238bceSAndroid Build Coastguard Worker             Vec2(-1e3f, 1e3f), // mediump
1518*35238bceSAndroid Build Coastguard Worker             Vec2(-1e7f, 1e7f)  // highp
1519*35238bceSAndroid Build Coastguard Worker         };
1520*35238bceSAndroid Build Coastguard Worker 
1521*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0xac23fu);
1522*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1523*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1524*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1525*35238bceSAndroid Build Coastguard Worker 
1526*35238bceSAndroid Build Coastguard Worker         // Random cases.
1527*35238bceSAndroid Build Coastguard Worker         fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float *)values[0],
1528*35238bceSAndroid Build Coastguard Worker                           numValues * scalarSize);
1529*35238bceSAndroid Build Coastguard Worker 
1530*35238bceSAndroid Build Coastguard Worker         // If precision is mediump, make sure values can be represented in fp16 exactly
1531*35238bceSAndroid Build Coastguard Worker         if (precision == glu::PRECISION_MEDIUMP)
1532*35238bceSAndroid Build Coastguard Worker         {
1533*35238bceSAndroid Build Coastguard Worker             for (int ndx = 0; ndx < numValues * scalarSize; ndx++)
1534*35238bceSAndroid Build Coastguard Worker                 ((float *)values[0])[ndx] = tcu::Float16(((float *)values[0])[ndx]).asFloat();
1535*35238bceSAndroid Build Coastguard Worker         }
1536*35238bceSAndroid Build Coastguard Worker     }
1537*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)1538*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
1539*35238bceSAndroid Build Coastguard Worker     {
1540*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1541*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1542*35238bceSAndroid Build Coastguard Worker         const bool hasZeroSign         = supportsSignedZero(precision);
1543*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1544*35238bceSAndroid Build Coastguard Worker 
1545*35238bceSAndroid Build Coastguard Worker         if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1546*35238bceSAndroid Build Coastguard Worker         {
1547*35238bceSAndroid Build Coastguard Worker             // Require exact result.
1548*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1549*35238bceSAndroid Build Coastguard Worker             {
1550*35238bceSAndroid Build Coastguard Worker                 const float in0  = ((const float *)inputs[0])[compNdx];
1551*35238bceSAndroid Build Coastguard Worker                 const float out0 = ((const float *)outputs[0])[compNdx];
1552*35238bceSAndroid Build Coastguard Worker                 const float ref  = deFloatCeil(in0);
1553*35238bceSAndroid Build Coastguard Worker 
1554*35238bceSAndroid Build Coastguard Worker                 const uint32_t ulpDiff = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1555*35238bceSAndroid Build Coastguard Worker 
1556*35238bceSAndroid Build Coastguard Worker                 if (ulpDiff > 0)
1557*35238bceSAndroid Build Coastguard Worker                 {
1558*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff "
1559*35238bceSAndroid Build Coastguard Worker                               << tcu::toHex(ulpDiff);
1560*35238bceSAndroid Build Coastguard Worker                     return false;
1561*35238bceSAndroid Build Coastguard Worker                 }
1562*35238bceSAndroid Build Coastguard Worker             }
1563*35238bceSAndroid Build Coastguard Worker         }
1564*35238bceSAndroid Build Coastguard Worker         else
1565*35238bceSAndroid Build Coastguard Worker         {
1566*35238bceSAndroid Build Coastguard Worker             const int mantissaBits    = getMinMantissaBits(precision);
1567*35238bceSAndroid Build Coastguard Worker             const uint32_t maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value.
1568*35238bceSAndroid Build Coastguard Worker             const float eps           = getEpsFromBits(1.0f, mantissaBits);  // epsilon for rounding bounds
1569*35238bceSAndroid Build Coastguard Worker 
1570*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1571*35238bceSAndroid Build Coastguard Worker             {
1572*35238bceSAndroid Build Coastguard Worker                 const float in0  = ((const float *)inputs[0])[compNdx];
1573*35238bceSAndroid Build Coastguard Worker                 const float out0 = ((const float *)outputs[0])[compNdx];
1574*35238bceSAndroid Build Coastguard Worker                 const int minRes = int(deFloatCeil(in0 - eps));
1575*35238bceSAndroid Build Coastguard Worker                 const int maxRes = int(deFloatCeil(in0 + eps));
1576*35238bceSAndroid Build Coastguard Worker                 bool anyOk       = false;
1577*35238bceSAndroid Build Coastguard Worker 
1578*35238bceSAndroid Build Coastguard Worker                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1579*35238bceSAndroid Build Coastguard Worker                 {
1580*35238bceSAndroid Build Coastguard Worker                     const uint32_t ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1581*35238bceSAndroid Build Coastguard Worker 
1582*35238bceSAndroid Build Coastguard Worker                     if (ulpDiff <= maxUlpDiff)
1583*35238bceSAndroid Build Coastguard Worker                     {
1584*35238bceSAndroid Build Coastguard Worker                         anyOk = true;
1585*35238bceSAndroid Build Coastguard Worker                         break;
1586*35238bceSAndroid Build Coastguard Worker                     }
1587*35238bceSAndroid Build Coastguard Worker                 }
1588*35238bceSAndroid Build Coastguard Worker 
1589*35238bceSAndroid Build Coastguard Worker                 if (!anyOk && de::inRange(0, minRes, maxRes))
1590*35238bceSAndroid Build Coastguard Worker                 {
1591*35238bceSAndroid Build Coastguard Worker                     // Allow -0 as well.
1592*35238bceSAndroid Build Coastguard Worker                     const int ulpDiff = de::abs((int)tcu::Float32(out0).bits() - (int)0x80000000u);
1593*35238bceSAndroid Build Coastguard Worker                     anyOk             = ((uint32_t)ulpDiff <= maxUlpDiff);
1594*35238bceSAndroid Build Coastguard Worker                 }
1595*35238bceSAndroid Build Coastguard Worker 
1596*35238bceSAndroid Build Coastguard Worker                 if (!anyOk)
1597*35238bceSAndroid Build Coastguard Worker                 {
1598*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes
1599*35238bceSAndroid Build Coastguard Worker                               << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1600*35238bceSAndroid Build Coastguard Worker                     return false;
1601*35238bceSAndroid Build Coastguard Worker                 }
1602*35238bceSAndroid Build Coastguard Worker             }
1603*35238bceSAndroid Build Coastguard Worker         }
1604*35238bceSAndroid Build Coastguard Worker 
1605*35238bceSAndroid Build Coastguard Worker         return true;
1606*35238bceSAndroid Build Coastguard Worker     }
1607*35238bceSAndroid Build Coastguard Worker };
1608*35238bceSAndroid Build Coastguard Worker 
1609*35238bceSAndroid Build Coastguard Worker class FractCase : public CommonFunctionCase
1610*35238bceSAndroid Build Coastguard Worker {
1611*35238bceSAndroid Build Coastguard Worker public:
FractCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1612*35238bceSAndroid Build Coastguard Worker     FractCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1613*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fract",
1614*35238bceSAndroid Build Coastguard Worker                              shaderType)
1615*35238bceSAndroid Build Coastguard Worker     {
1616*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1617*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1618*35238bceSAndroid Build Coastguard Worker         m_spec.source = "out0 = fract(in0);";
1619*35238bceSAndroid Build Coastguard Worker     }
1620*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const1621*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
1622*35238bceSAndroid Build Coastguard Worker     {
1623*35238bceSAndroid Build Coastguard Worker         const Vec2 ranges[] = {
1624*35238bceSAndroid Build Coastguard Worker             Vec2(-2.0f, 2.0f), // lowp
1625*35238bceSAndroid Build Coastguard Worker             Vec2(-1e3f, 1e3f), // mediump
1626*35238bceSAndroid Build Coastguard Worker             Vec2(-1e7f, 1e7f)  // highp
1627*35238bceSAndroid Build Coastguard Worker         };
1628*35238bceSAndroid Build Coastguard Worker 
1629*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0xac23fu);
1630*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1631*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1632*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1633*35238bceSAndroid Build Coastguard Worker         int numSpecialCases            = 0;
1634*35238bceSAndroid Build Coastguard Worker 
1635*35238bceSAndroid Build Coastguard Worker         // Special cases.
1636*35238bceSAndroid Build Coastguard Worker         if (precision != glu::PRECISION_LOWP)
1637*35238bceSAndroid Build Coastguard Worker         {
1638*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(numValues >= 10);
1639*35238bceSAndroid Build Coastguard Worker             for (int ndx = 0; ndx < 10; ndx++)
1640*35238bceSAndroid Build Coastguard Worker             {
1641*35238bceSAndroid Build Coastguard Worker                 const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y());
1642*35238bceSAndroid Build Coastguard Worker                 std::fill((float *)values[0], (float *)values[0] + scalarSize, v);
1643*35238bceSAndroid Build Coastguard Worker                 numSpecialCases += 1;
1644*35238bceSAndroid Build Coastguard Worker             }
1645*35238bceSAndroid Build Coastguard Worker         }
1646*35238bceSAndroid Build Coastguard Worker 
1647*35238bceSAndroid Build Coastguard Worker         // Random cases.
1648*35238bceSAndroid Build Coastguard Worker         fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(),
1649*35238bceSAndroid Build Coastguard Worker                           (float *)values[0] + numSpecialCases * scalarSize,
1650*35238bceSAndroid Build Coastguard Worker                           (numValues - numSpecialCases) * scalarSize);
1651*35238bceSAndroid Build Coastguard Worker 
1652*35238bceSAndroid Build Coastguard Worker         // If precision is mediump, make sure values can be represented in fp16 exactly
1653*35238bceSAndroid Build Coastguard Worker         if (precision == glu::PRECISION_MEDIUMP)
1654*35238bceSAndroid Build Coastguard Worker         {
1655*35238bceSAndroid Build Coastguard Worker             for (int ndx = 0; ndx < numValues * scalarSize; ndx++)
1656*35238bceSAndroid Build Coastguard Worker                 ((float *)values[0])[ndx] = tcu::Float16(((float *)values[0])[ndx]).asFloat();
1657*35238bceSAndroid Build Coastguard Worker         }
1658*35238bceSAndroid Build Coastguard Worker     }
1659*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)1660*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
1661*35238bceSAndroid Build Coastguard Worker     {
1662*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1663*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1664*35238bceSAndroid Build Coastguard Worker         const bool hasZeroSign         = supportsSignedZero(precision);
1665*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1666*35238bceSAndroid Build Coastguard Worker 
1667*35238bceSAndroid Build Coastguard Worker         if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1668*35238bceSAndroid Build Coastguard Worker         {
1669*35238bceSAndroid Build Coastguard Worker             // Require exact result.
1670*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1671*35238bceSAndroid Build Coastguard Worker             {
1672*35238bceSAndroid Build Coastguard Worker                 const float in0  = ((const float *)inputs[0])[compNdx];
1673*35238bceSAndroid Build Coastguard Worker                 const float out0 = ((const float *)outputs[0])[compNdx];
1674*35238bceSAndroid Build Coastguard Worker                 const float ref  = deFloatFrac(in0);
1675*35238bceSAndroid Build Coastguard Worker 
1676*35238bceSAndroid Build Coastguard Worker                 const uint32_t ulpDiff = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1677*35238bceSAndroid Build Coastguard Worker 
1678*35238bceSAndroid Build Coastguard Worker                 if (ulpDiff > 0)
1679*35238bceSAndroid Build Coastguard Worker                 {
1680*35238bceSAndroid Build Coastguard Worker                     m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff "
1681*35238bceSAndroid Build Coastguard Worker                               << tcu::toHex(ulpDiff);
1682*35238bceSAndroid Build Coastguard Worker                     return false;
1683*35238bceSAndroid Build Coastguard Worker                 }
1684*35238bceSAndroid Build Coastguard Worker             }
1685*35238bceSAndroid Build Coastguard Worker         }
1686*35238bceSAndroid Build Coastguard Worker         else
1687*35238bceSAndroid Build Coastguard Worker         {
1688*35238bceSAndroid Build Coastguard Worker             const int mantissaBits = getMinMantissaBits(precision);
1689*35238bceSAndroid Build Coastguard Worker             const float eps        = getEpsFromBits(1.0f, mantissaBits); // epsilon for rounding bounds
1690*35238bceSAndroid Build Coastguard Worker 
1691*35238bceSAndroid Build Coastguard Worker             for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1692*35238bceSAndroid Build Coastguard Worker             {
1693*35238bceSAndroid Build Coastguard Worker                 const float in0  = ((const float *)inputs[0])[compNdx];
1694*35238bceSAndroid Build Coastguard Worker                 const float out0 = ((const float *)outputs[0])[compNdx];
1695*35238bceSAndroid Build Coastguard Worker 
1696*35238bceSAndroid Build Coastguard Worker                 if (int(deFloatFloor(in0 - eps)) == int(deFloatFloor(in0 + eps)))
1697*35238bceSAndroid Build Coastguard Worker                 {
1698*35238bceSAndroid Build Coastguard Worker                     const float ref           = deFloatFrac(in0);
1699*35238bceSAndroid Build Coastguard Worker                     const int bitsLost        = numBitsLostInOp(in0, ref);
1700*35238bceSAndroid Build Coastguard Worker                     const uint32_t maxUlpDiff = getMaxUlpDiffFromBits(
1701*35238bceSAndroid Build Coastguard Worker                         de::max(0, mantissaBits - bitsLost)); // ULP diff for rounded integer value.
1702*35238bceSAndroid Build Coastguard Worker                     const uint32_t ulpDiff = getUlpDiffIgnoreZeroSign(out0, ref);
1703*35238bceSAndroid Build Coastguard Worker 
1704*35238bceSAndroid Build Coastguard Worker                     if (ulpDiff > maxUlpDiff)
1705*35238bceSAndroid Build Coastguard Worker                     {
1706*35238bceSAndroid Build Coastguard Worker                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << " with ULP threshold "
1707*35238bceSAndroid Build Coastguard Worker                                   << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
1708*35238bceSAndroid Build Coastguard Worker                         return false;
1709*35238bceSAndroid Build Coastguard Worker                     }
1710*35238bceSAndroid Build Coastguard Worker                 }
1711*35238bceSAndroid Build Coastguard Worker                 else
1712*35238bceSAndroid Build Coastguard Worker                 {
1713*35238bceSAndroid Build Coastguard Worker                     if (out0 >= 1.0f)
1714*35238bceSAndroid Build Coastguard Worker                     {
1715*35238bceSAndroid Build Coastguard Worker                         m_failMsg << "Expected [" << compNdx << "] < 1.0";
1716*35238bceSAndroid Build Coastguard Worker                         return false;
1717*35238bceSAndroid Build Coastguard Worker                     }
1718*35238bceSAndroid Build Coastguard Worker                 }
1719*35238bceSAndroid Build Coastguard Worker             }
1720*35238bceSAndroid Build Coastguard Worker         }
1721*35238bceSAndroid Build Coastguard Worker 
1722*35238bceSAndroid Build Coastguard Worker         return true;
1723*35238bceSAndroid Build Coastguard Worker     }
1724*35238bceSAndroid Build Coastguard Worker };
1725*35238bceSAndroid Build Coastguard Worker 
frexp(float in,float * significand,int * exponent)1726*35238bceSAndroid Build Coastguard Worker static inline void frexp(float in, float *significand, int *exponent)
1727*35238bceSAndroid Build Coastguard Worker {
1728*35238bceSAndroid Build Coastguard Worker     const tcu::Float32 fpValue(in);
1729*35238bceSAndroid Build Coastguard Worker 
1730*35238bceSAndroid Build Coastguard Worker     if (!fpValue.isZero())
1731*35238bceSAndroid Build Coastguard Worker     {
1732*35238bceSAndroid Build Coastguard Worker         // Construct float that has exactly the mantissa, and exponent of -1.
1733*35238bceSAndroid Build Coastguard Worker         *significand = tcu::Float32::construct(fpValue.sign(), -1, fpValue.mantissa()).asFloat();
1734*35238bceSAndroid Build Coastguard Worker         *exponent    = fpValue.exponent() + 1;
1735*35238bceSAndroid Build Coastguard Worker     }
1736*35238bceSAndroid Build Coastguard Worker     else
1737*35238bceSAndroid Build Coastguard Worker     {
1738*35238bceSAndroid Build Coastguard Worker         *significand = fpValue.sign() < 0 ? -0.0f : 0.0f;
1739*35238bceSAndroid Build Coastguard Worker         *exponent    = 0;
1740*35238bceSAndroid Build Coastguard Worker     }
1741*35238bceSAndroid Build Coastguard Worker }
1742*35238bceSAndroid Build Coastguard Worker 
ldexp(float significand,int exponent)1743*35238bceSAndroid Build Coastguard Worker static inline float ldexp(float significand, int exponent)
1744*35238bceSAndroid Build Coastguard Worker {
1745*35238bceSAndroid Build Coastguard Worker     const tcu::Float32 mant(significand);
1746*35238bceSAndroid Build Coastguard Worker 
1747*35238bceSAndroid Build Coastguard Worker     if (exponent == 0 && mant.isZero())
1748*35238bceSAndroid Build Coastguard Worker     {
1749*35238bceSAndroid Build Coastguard Worker         return mant.sign() < 0 ? -0.0f : 0.0f;
1750*35238bceSAndroid Build Coastguard Worker     }
1751*35238bceSAndroid Build Coastguard Worker     else
1752*35238bceSAndroid Build Coastguard Worker     {
1753*35238bceSAndroid Build Coastguard Worker         return tcu::Float32::construct(mant.sign(), exponent + mant.exponent(), mant.mantissa()).asFloat();
1754*35238bceSAndroid Build Coastguard Worker     }
1755*35238bceSAndroid Build Coastguard Worker }
1756*35238bceSAndroid Build Coastguard Worker 
1757*35238bceSAndroid Build Coastguard Worker class FrexpCase : public CommonFunctionCase
1758*35238bceSAndroid Build Coastguard Worker {
1759*35238bceSAndroid Build Coastguard Worker public:
FrexpCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1760*35238bceSAndroid Build Coastguard Worker     FrexpCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1761*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "frexp",
1762*35238bceSAndroid Build Coastguard Worker                              shaderType)
1763*35238bceSAndroid Build Coastguard Worker     {
1764*35238bceSAndroid Build Coastguard Worker         const int vecSize           = glu::getDataTypeScalarSize(baseType);
1765*35238bceSAndroid Build Coastguard Worker         const glu::DataType intType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
1766*35238bceSAndroid Build Coastguard Worker 
1767*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1768*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
1769*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out1", glu::VarType(intType, glu::PRECISION_HIGHP)));
1770*35238bceSAndroid Build Coastguard Worker         m_spec.source = "out0 = frexp(in0, out1);";
1771*35238bceSAndroid Build Coastguard Worker     }
1772*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const1773*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
1774*35238bceSAndroid Build Coastguard Worker     {
1775*35238bceSAndroid Build Coastguard Worker         const Vec2 ranges[] = {
1776*35238bceSAndroid Build Coastguard Worker             Vec2(-2.0f, 2.0f), // lowp
1777*35238bceSAndroid Build Coastguard Worker             Vec2(-1e3f, 1e3f), // mediump
1778*35238bceSAndroid Build Coastguard Worker             Vec2(-1e7f, 1e7f)  // highp
1779*35238bceSAndroid Build Coastguard Worker         };
1780*35238bceSAndroid Build Coastguard Worker 
1781*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0x2790au);
1782*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1783*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1784*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1785*35238bceSAndroid Build Coastguard Worker 
1786*35238bceSAndroid Build Coastguard Worker         // Special cases
1787*35238bceSAndroid Build Coastguard Worker         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1788*35238bceSAndroid Build Coastguard Worker         {
1789*35238bceSAndroid Build Coastguard Worker             ((float *)values[0])[scalarSize * 0 + compNdx] = 0.0f;
1790*35238bceSAndroid Build Coastguard Worker             ((float *)values[0])[scalarSize * 1 + compNdx] = -0.0f;
1791*35238bceSAndroid Build Coastguard Worker             ((float *)values[0])[scalarSize * 2 + compNdx] = 0.5f;
1792*35238bceSAndroid Build Coastguard Worker             ((float *)values[0])[scalarSize * 3 + compNdx] = -0.5f;
1793*35238bceSAndroid Build Coastguard Worker             ((float *)values[0])[scalarSize * 4 + compNdx] = 1.0f;
1794*35238bceSAndroid Build Coastguard Worker             ((float *)values[0])[scalarSize * 5 + compNdx] = -1.0f;
1795*35238bceSAndroid Build Coastguard Worker             ((float *)values[0])[scalarSize * 6 + compNdx] = 2.0f;
1796*35238bceSAndroid Build Coastguard Worker             ((float *)values[0])[scalarSize * 7 + compNdx] = -2.0f;
1797*35238bceSAndroid Build Coastguard Worker         }
1798*35238bceSAndroid Build Coastguard Worker 
1799*35238bceSAndroid Build Coastguard Worker         fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float *)values[0] + 8 * scalarSize,
1800*35238bceSAndroid Build Coastguard Worker                           (numValues - 8) * scalarSize);
1801*35238bceSAndroid Build Coastguard Worker 
1802*35238bceSAndroid Build Coastguard Worker         // Make sure the values are representable in the target format
1803*35238bceSAndroid Build Coastguard Worker         for (int caseNdx = 0; caseNdx < numValues; ++caseNdx)
1804*35238bceSAndroid Build Coastguard Worker         {
1805*35238bceSAndroid Build Coastguard Worker             for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1806*35238bceSAndroid Build Coastguard Worker             {
1807*35238bceSAndroid Build Coastguard Worker                 float *const valuePtr = &((float *)values[0])[caseNdx * scalarSize + scalarNdx];
1808*35238bceSAndroid Build Coastguard Worker 
1809*35238bceSAndroid Build Coastguard Worker                 *valuePtr = makeFloatRepresentable(*valuePtr, precision);
1810*35238bceSAndroid Build Coastguard Worker             }
1811*35238bceSAndroid Build Coastguard Worker         }
1812*35238bceSAndroid Build Coastguard Worker     }
1813*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)1814*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
1815*35238bceSAndroid Build Coastguard Worker     {
1816*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1817*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1818*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1819*35238bceSAndroid Build Coastguard Worker         const bool signedZero          = false;
1820*35238bceSAndroid Build Coastguard Worker 
1821*35238bceSAndroid Build Coastguard Worker         const int mantissaBits    = getMinMantissaBits(precision);
1822*35238bceSAndroid Build Coastguard Worker         const uint32_t maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits);
1823*35238bceSAndroid Build Coastguard Worker 
1824*35238bceSAndroid Build Coastguard Worker         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1825*35238bceSAndroid Build Coastguard Worker         {
1826*35238bceSAndroid Build Coastguard Worker             const float in0  = ((const float *)inputs[0])[compNdx];
1827*35238bceSAndroid Build Coastguard Worker             const float out0 = ((const float *)outputs[0])[compNdx];
1828*35238bceSAndroid Build Coastguard Worker             const int out1   = ((const int *)outputs[1])[compNdx];
1829*35238bceSAndroid Build Coastguard Worker 
1830*35238bceSAndroid Build Coastguard Worker             float refOut0;
1831*35238bceSAndroid Build Coastguard Worker             int refOut1;
1832*35238bceSAndroid Build Coastguard Worker 
1833*35238bceSAndroid Build Coastguard Worker             frexp(in0, &refOut0, &refOut1);
1834*35238bceSAndroid Build Coastguard Worker 
1835*35238bceSAndroid Build Coastguard Worker             const uint32_t ulpDiff0 = signedZero ? getUlpDiff(out0, refOut0) : getUlpDiffIgnoreZeroSign(out0, refOut0);
1836*35238bceSAndroid Build Coastguard Worker 
1837*35238bceSAndroid Build Coastguard Worker             if (ulpDiff0 > maxUlpDiff || out1 != refOut1)
1838*35238bceSAndroid Build Coastguard Worker             {
1839*35238bceSAndroid Build Coastguard Worker                 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(refOut0) << ", " << refOut1
1840*35238bceSAndroid Build Coastguard Worker                           << " with ULP threshold " << tcu::toHex(maxUlpDiff) << ", got ULP diff "
1841*35238bceSAndroid Build Coastguard Worker                           << tcu::toHex(ulpDiff0);
1842*35238bceSAndroid Build Coastguard Worker                 return false;
1843*35238bceSAndroid Build Coastguard Worker             }
1844*35238bceSAndroid Build Coastguard Worker         }
1845*35238bceSAndroid Build Coastguard Worker 
1846*35238bceSAndroid Build Coastguard Worker         return true;
1847*35238bceSAndroid Build Coastguard Worker     }
1848*35238bceSAndroid Build Coastguard Worker };
1849*35238bceSAndroid Build Coastguard Worker 
1850*35238bceSAndroid Build Coastguard Worker class LdexpCase : public CommonFunctionCase
1851*35238bceSAndroid Build Coastguard Worker {
1852*35238bceSAndroid Build Coastguard Worker public:
LdexpCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1853*35238bceSAndroid Build Coastguard Worker     LdexpCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1854*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ldexp",
1855*35238bceSAndroid Build Coastguard Worker                              shaderType)
1856*35238bceSAndroid Build Coastguard Worker     {
1857*35238bceSAndroid Build Coastguard Worker         const int vecSize           = glu::getDataTypeScalarSize(baseType);
1858*35238bceSAndroid Build Coastguard Worker         const glu::DataType intType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
1859*35238bceSAndroid Build Coastguard Worker 
1860*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1861*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("in1", glu::VarType(intType, glu::PRECISION_HIGHP)));
1862*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
1863*35238bceSAndroid Build Coastguard Worker         m_spec.source = "out0 = ldexp(in0, in1);";
1864*35238bceSAndroid Build Coastguard Worker     }
1865*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const1866*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
1867*35238bceSAndroid Build Coastguard Worker     {
1868*35238bceSAndroid Build Coastguard Worker         const Vec2 ranges[] = {
1869*35238bceSAndroid Build Coastguard Worker             Vec2(-2.0f, 2.0f), // lowp
1870*35238bceSAndroid Build Coastguard Worker             Vec2(-1e3f, 1e3f), // mediump
1871*35238bceSAndroid Build Coastguard Worker             Vec2(-1e7f, 1e7f)  // highp
1872*35238bceSAndroid Build Coastguard Worker         };
1873*35238bceSAndroid Build Coastguard Worker 
1874*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0x2790au);
1875*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1876*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1877*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1878*35238bceSAndroid Build Coastguard Worker         int valueNdx                   = 0;
1879*35238bceSAndroid Build Coastguard Worker 
1880*35238bceSAndroid Build Coastguard Worker         {
1881*35238bceSAndroid Build Coastguard Worker             const float easySpecialCases[] = {0.0f, -0.0f, 0.5f, -0.5f, 1.0f, -1.0f, 2.0f, -2.0f};
1882*35238bceSAndroid Build Coastguard Worker 
1883*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(valueNdx + DE_LENGTH_OF_ARRAY(easySpecialCases) <= numValues);
1884*35238bceSAndroid Build Coastguard Worker             for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(easySpecialCases); caseNdx++)
1885*35238bceSAndroid Build Coastguard Worker             {
1886*35238bceSAndroid Build Coastguard Worker                 float in0;
1887*35238bceSAndroid Build Coastguard Worker                 int in1;
1888*35238bceSAndroid Build Coastguard Worker 
1889*35238bceSAndroid Build Coastguard Worker                 frexp(easySpecialCases[caseNdx], &in0, &in1);
1890*35238bceSAndroid Build Coastguard Worker 
1891*35238bceSAndroid Build Coastguard Worker                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1892*35238bceSAndroid Build Coastguard Worker                 {
1893*35238bceSAndroid Build Coastguard Worker                     ((float *)values[0])[valueNdx * scalarSize + compNdx] = in0;
1894*35238bceSAndroid Build Coastguard Worker                     ((int *)values[1])[valueNdx * scalarSize + compNdx]   = in1;
1895*35238bceSAndroid Build Coastguard Worker                 }
1896*35238bceSAndroid Build Coastguard Worker 
1897*35238bceSAndroid Build Coastguard Worker                 valueNdx += 1;
1898*35238bceSAndroid Build Coastguard Worker             }
1899*35238bceSAndroid Build Coastguard Worker         }
1900*35238bceSAndroid Build Coastguard Worker 
1901*35238bceSAndroid Build Coastguard Worker         {
1902*35238bceSAndroid Build Coastguard Worker             // \note lowp and mediump can not necessarily fit the values in hard cases, so we'll use only easy ones.
1903*35238bceSAndroid Build Coastguard Worker             const int numEasyRandomCases = precision == glu::PRECISION_HIGHP ? 50 : (numValues - valueNdx);
1904*35238bceSAndroid Build Coastguard Worker 
1905*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(valueNdx + numEasyRandomCases <= numValues);
1906*35238bceSAndroid Build Coastguard Worker             for (int caseNdx = 0; caseNdx < numEasyRandomCases; caseNdx++)
1907*35238bceSAndroid Build Coastguard Worker             {
1908*35238bceSAndroid Build Coastguard Worker                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1909*35238bceSAndroid Build Coastguard Worker                 {
1910*35238bceSAndroid Build Coastguard Worker                     const float in = rnd.getFloat(ranges[precision].x(), ranges[precision].y());
1911*35238bceSAndroid Build Coastguard Worker                     float in0;
1912*35238bceSAndroid Build Coastguard Worker                     int in1;
1913*35238bceSAndroid Build Coastguard Worker 
1914*35238bceSAndroid Build Coastguard Worker                     frexp(in, &in0, &in1);
1915*35238bceSAndroid Build Coastguard Worker 
1916*35238bceSAndroid Build Coastguard Worker                     ((float *)values[0])[valueNdx * scalarSize + compNdx] = in0;
1917*35238bceSAndroid Build Coastguard Worker                     ((int *)values[1])[valueNdx * scalarSize + compNdx]   = in1;
1918*35238bceSAndroid Build Coastguard Worker                 }
1919*35238bceSAndroid Build Coastguard Worker 
1920*35238bceSAndroid Build Coastguard Worker                 valueNdx += 1;
1921*35238bceSAndroid Build Coastguard Worker             }
1922*35238bceSAndroid Build Coastguard Worker         }
1923*35238bceSAndroid Build Coastguard Worker 
1924*35238bceSAndroid Build Coastguard Worker         {
1925*35238bceSAndroid Build Coastguard Worker             const int numHardRandomCases = numValues - valueNdx;
1926*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(numHardRandomCases >= 0 && valueNdx + numHardRandomCases <= numValues);
1927*35238bceSAndroid Build Coastguard Worker 
1928*35238bceSAndroid Build Coastguard Worker             for (int caseNdx = 0; caseNdx < numHardRandomCases; caseNdx++)
1929*35238bceSAndroid Build Coastguard Worker             {
1930*35238bceSAndroid Build Coastguard Worker                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1931*35238bceSAndroid Build Coastguard Worker                 {
1932*35238bceSAndroid Build Coastguard Worker                     const int fpExp         = rnd.getInt(-126, 127);
1933*35238bceSAndroid Build Coastguard Worker                     const int sign          = rnd.getBool() ? -1 : +1;
1934*35238bceSAndroid Build Coastguard Worker                     const uint32_t mantissa = (1u << 23) | (rnd.getUint32() & ((1u << 23) - 1));
1935*35238bceSAndroid Build Coastguard Worker                     const int in1           = rnd.getInt(de::max(-126, -126 - fpExp), de::min(127, 127 - fpExp));
1936*35238bceSAndroid Build Coastguard Worker                     const float in0         = tcu::Float32::construct(sign, fpExp, mantissa).asFloat();
1937*35238bceSAndroid Build Coastguard Worker 
1938*35238bceSAndroid Build Coastguard Worker                     DE_ASSERT(de::inRange(in1, -126, 127)); // See Khronos bug 11180
1939*35238bceSAndroid Build Coastguard Worker                     DE_ASSERT(de::inRange(in1 + fpExp, -126, 127));
1940*35238bceSAndroid Build Coastguard Worker 
1941*35238bceSAndroid Build Coastguard Worker                     const float out = ldexp(in0, in1);
1942*35238bceSAndroid Build Coastguard Worker 
1943*35238bceSAndroid Build Coastguard Worker                     DE_ASSERT(!tcu::Float32(out).isInf() && !tcu::Float32(out).isDenorm());
1944*35238bceSAndroid Build Coastguard Worker                     DE_UNREF(out);
1945*35238bceSAndroid Build Coastguard Worker 
1946*35238bceSAndroid Build Coastguard Worker                     ((float *)values[0])[valueNdx * scalarSize + compNdx] = in0;
1947*35238bceSAndroid Build Coastguard Worker                     ((int *)values[1])[valueNdx * scalarSize + compNdx]   = in1;
1948*35238bceSAndroid Build Coastguard Worker                 }
1949*35238bceSAndroid Build Coastguard Worker 
1950*35238bceSAndroid Build Coastguard Worker                 valueNdx += 1;
1951*35238bceSAndroid Build Coastguard Worker             }
1952*35238bceSAndroid Build Coastguard Worker         }
1953*35238bceSAndroid Build Coastguard Worker     }
1954*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)1955*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
1956*35238bceSAndroid Build Coastguard Worker     {
1957*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
1958*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1959*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
1960*35238bceSAndroid Build Coastguard Worker 
1961*35238bceSAndroid Build Coastguard Worker         const int mantissaBits    = getMinMantissaBits(precision);
1962*35238bceSAndroid Build Coastguard Worker         const uint32_t maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits);
1963*35238bceSAndroid Build Coastguard Worker 
1964*35238bceSAndroid Build Coastguard Worker         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1965*35238bceSAndroid Build Coastguard Worker         {
1966*35238bceSAndroid Build Coastguard Worker             const float in0        = ((const float *)inputs[0])[compNdx];
1967*35238bceSAndroid Build Coastguard Worker             const int in1          = ((const int *)inputs[1])[compNdx];
1968*35238bceSAndroid Build Coastguard Worker             const float out0       = ((const float *)outputs[0])[compNdx];
1969*35238bceSAndroid Build Coastguard Worker             const float refOut0    = ldexp(in0, in1);
1970*35238bceSAndroid Build Coastguard Worker             const uint32_t ulpDiff = getUlpDiffIgnoreZeroSign(out0, refOut0);
1971*35238bceSAndroid Build Coastguard Worker 
1972*35238bceSAndroid Build Coastguard Worker             const int inExp = tcu::Float32(in0).exponent();
1973*35238bceSAndroid Build Coastguard Worker 
1974*35238bceSAndroid Build Coastguard Worker             if (ulpDiff > maxUlpDiff)
1975*35238bceSAndroid Build Coastguard Worker             {
1976*35238bceSAndroid Build Coastguard Worker                 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(refOut0) << ", (exp = " << inExp
1977*35238bceSAndroid Build Coastguard Worker                           << ") with ULP threshold " << tcu::toHex(maxUlpDiff) << ", got ULP diff "
1978*35238bceSAndroid Build Coastguard Worker                           << tcu::toHex(ulpDiff);
1979*35238bceSAndroid Build Coastguard Worker                 return false;
1980*35238bceSAndroid Build Coastguard Worker             }
1981*35238bceSAndroid Build Coastguard Worker         }
1982*35238bceSAndroid Build Coastguard Worker 
1983*35238bceSAndroid Build Coastguard Worker         return true;
1984*35238bceSAndroid Build Coastguard Worker     }
1985*35238bceSAndroid Build Coastguard Worker };
1986*35238bceSAndroid Build Coastguard Worker 
1987*35238bceSAndroid Build Coastguard Worker class FmaCase : public CommonFunctionCase
1988*35238bceSAndroid Build Coastguard Worker {
1989*35238bceSAndroid Build Coastguard Worker public:
FmaCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1990*35238bceSAndroid Build Coastguard Worker     FmaCase(Context &context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1991*35238bceSAndroid Build Coastguard Worker         : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fma", shaderType)
1992*35238bceSAndroid Build Coastguard Worker     {
1993*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("a", glu::VarType(baseType, precision)));
1994*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("b", glu::VarType(baseType, precision)));
1995*35238bceSAndroid Build Coastguard Worker         m_spec.inputs.push_back(Symbol("c", glu::VarType(baseType, precision)));
1996*35238bceSAndroid Build Coastguard Worker         m_spec.outputs.push_back(Symbol("res", glu::VarType(baseType, precision)));
1997*35238bceSAndroid Build Coastguard Worker         m_spec.source = "res = fma(a, b, c);";
1998*35238bceSAndroid Build Coastguard Worker 
1999*35238bceSAndroid Build Coastguard Worker         if (!glu::contextSupports(context.getRenderContext().getType(), glu::ApiType::es(3, 2)) &&
2000*35238bceSAndroid Build Coastguard Worker             !glu::contextSupports(context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
2001*35238bceSAndroid Build Coastguard Worker             m_spec.globalDeclarations = "#extension GL_EXT_gpu_shader5 : require\n";
2002*35238bceSAndroid Build Coastguard Worker     }
2003*35238bceSAndroid Build Coastguard Worker 
init(void)2004*35238bceSAndroid Build Coastguard Worker     void init(void)
2005*35238bceSAndroid Build Coastguard Worker     {
2006*35238bceSAndroid Build Coastguard Worker         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) &&
2007*35238bceSAndroid Build Coastguard Worker             !m_context.getContextInfo().isExtensionSupported("GL_EXT_gpu_shader5") &&
2008*35238bceSAndroid Build Coastguard Worker             !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
2009*35238bceSAndroid Build Coastguard Worker             throw tcu::NotSupportedError("OpenGL ES 3.2, GL_EXT_gpu_shader5 not supported and OpenGL 4.5");
2010*35238bceSAndroid Build Coastguard Worker 
2011*35238bceSAndroid Build Coastguard Worker         CommonFunctionCase::init();
2012*35238bceSAndroid Build Coastguard Worker     }
2013*35238bceSAndroid Build Coastguard Worker 
getInputValues(int numValues,void * const * values) const2014*35238bceSAndroid Build Coastguard Worker     void getInputValues(int numValues, void *const *values) const
2015*35238bceSAndroid Build Coastguard Worker     {
2016*35238bceSAndroid Build Coastguard Worker         const Vec2 ranges[] = {
2017*35238bceSAndroid Build Coastguard Worker             Vec2(-2.0f, 2.0f),   // lowp
2018*35238bceSAndroid Build Coastguard Worker             Vec2(-127.f, 127.f), // mediump
2019*35238bceSAndroid Build Coastguard Worker             Vec2(-1e7f, 1e7f)    // highp
2020*35238bceSAndroid Build Coastguard Worker         };
2021*35238bceSAndroid Build Coastguard Worker 
2022*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()) ^ 0xac23fu);
2023*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
2024*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
2025*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
2026*35238bceSAndroid Build Coastguard Worker         const float specialCases[][3]  = {
2027*35238bceSAndroid Build Coastguard Worker             // a        b        c
2028*35238bceSAndroid Build Coastguard Worker             {0.0f, 0.0f, 0.0f},  {0.0f, 1.0f, 0.0f},  {0.0f, 0.0f, -1.0f},  {1.0f, 1.0f, 0.0f},  {1.0f, 1.0f, 1.0f},
2029*35238bceSAndroid Build Coastguard Worker             {-1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f}, {-1.0f, -1.0f, 0.0f}, {-0.0f, 1.0f, 0.0f}, {1.0f, -0.0f, 0.0f}};
2030*35238bceSAndroid Build Coastguard Worker         const int numSpecialCases = DE_LENGTH_OF_ARRAY(specialCases);
2031*35238bceSAndroid Build Coastguard Worker 
2032*35238bceSAndroid Build Coastguard Worker         // Special cases
2033*35238bceSAndroid Build Coastguard Worker         for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++)
2034*35238bceSAndroid Build Coastguard Worker         {
2035*35238bceSAndroid Build Coastguard Worker             for (int inputNdx = 0; inputNdx < 3; inputNdx++)
2036*35238bceSAndroid Build Coastguard Worker             {
2037*35238bceSAndroid Build Coastguard Worker                 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
2038*35238bceSAndroid Build Coastguard Worker                     ((float *)values[inputNdx])[caseNdx * scalarSize + scalarNdx] = specialCases[caseNdx][inputNdx];
2039*35238bceSAndroid Build Coastguard Worker             }
2040*35238bceSAndroid Build Coastguard Worker         }
2041*35238bceSAndroid Build Coastguard Worker 
2042*35238bceSAndroid Build Coastguard Worker         // Random cases.
2043*35238bceSAndroid Build Coastguard Worker         {
2044*35238bceSAndroid Build Coastguard Worker             const int numScalars = (numValues - numSpecialCases) * scalarSize;
2045*35238bceSAndroid Build Coastguard Worker             const int offs       = scalarSize * numSpecialCases;
2046*35238bceSAndroid Build Coastguard Worker 
2047*35238bceSAndroid Build Coastguard Worker             for (int inputNdx = 0; inputNdx < 3; inputNdx++)
2048*35238bceSAndroid Build Coastguard Worker                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float *)values[inputNdx] + offs,
2049*35238bceSAndroid Build Coastguard Worker                                   numScalars);
2050*35238bceSAndroid Build Coastguard Worker         }
2051*35238bceSAndroid Build Coastguard Worker 
2052*35238bceSAndroid Build Coastguard Worker         // Make sure the values are representable in the target format
2053*35238bceSAndroid Build Coastguard Worker         for (int inputNdx = 0; inputNdx < 3; inputNdx++)
2054*35238bceSAndroid Build Coastguard Worker         {
2055*35238bceSAndroid Build Coastguard Worker             for (int caseNdx = 0; caseNdx < numValues; ++caseNdx)
2056*35238bceSAndroid Build Coastguard Worker             {
2057*35238bceSAndroid Build Coastguard Worker                 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
2058*35238bceSAndroid Build Coastguard Worker                 {
2059*35238bceSAndroid Build Coastguard Worker                     float *const valuePtr = &((float *)values[inputNdx])[caseNdx * scalarSize + scalarNdx];
2060*35238bceSAndroid Build Coastguard Worker 
2061*35238bceSAndroid Build Coastguard Worker                     *valuePtr = makeFloatRepresentable(*valuePtr, precision);
2062*35238bceSAndroid Build Coastguard Worker                 }
2063*35238bceSAndroid Build Coastguard Worker             }
2064*35238bceSAndroid Build Coastguard Worker         }
2065*35238bceSAndroid Build Coastguard Worker     }
2066*35238bceSAndroid Build Coastguard Worker 
fma(glu::Precision precision,float a,float b,float c)2067*35238bceSAndroid Build Coastguard Worker     static tcu::Interval fma(glu::Precision precision, float a, float b, float c)
2068*35238bceSAndroid Build Coastguard Worker     {
2069*35238bceSAndroid Build Coastguard Worker         const tcu::FloatFormat formats[] = {
2070*35238bceSAndroid Build Coastguard Worker             //                 minExp        maxExp        mantissa    exact, subnormals    infinities    NaN
2071*35238bceSAndroid Build Coastguard Worker             tcu::FloatFormat(0, 0, 7, false, tcu::YES, tcu::MAYBE, tcu::MAYBE),
2072*35238bceSAndroid Build Coastguard Worker             tcu::FloatFormat(-13, 13, 9, false, tcu::MAYBE, tcu::MAYBE, tcu::MAYBE),
2073*35238bceSAndroid Build Coastguard Worker             tcu::FloatFormat(-126, 127, 23, true, tcu::MAYBE, tcu::YES, tcu::MAYBE)};
2074*35238bceSAndroid Build Coastguard Worker         const tcu::FloatFormat &format = de::getSizedArrayElement<glu::PRECISION_LAST>(formats, precision);
2075*35238bceSAndroid Build Coastguard Worker         const tcu::Interval ia         = format.convert(a);
2076*35238bceSAndroid Build Coastguard Worker         const tcu::Interval ib         = format.convert(b);
2077*35238bceSAndroid Build Coastguard Worker         const tcu::Interval ic         = format.convert(c);
2078*35238bceSAndroid Build Coastguard Worker         tcu::Interval prod0;
2079*35238bceSAndroid Build Coastguard Worker         tcu::Interval prod1;
2080*35238bceSAndroid Build Coastguard Worker         tcu::Interval prod2;
2081*35238bceSAndroid Build Coastguard Worker         tcu::Interval prod3;
2082*35238bceSAndroid Build Coastguard Worker         tcu::Interval prod;
2083*35238bceSAndroid Build Coastguard Worker         tcu::Interval res;
2084*35238bceSAndroid Build Coastguard Worker 
2085*35238bceSAndroid Build Coastguard Worker         TCU_SET_INTERVAL(prod0, tmp, tmp = ia.lo() * ib.lo());
2086*35238bceSAndroid Build Coastguard Worker         TCU_SET_INTERVAL(prod1, tmp, tmp = ia.lo() * ib.hi());
2087*35238bceSAndroid Build Coastguard Worker         TCU_SET_INTERVAL(prod2, tmp, tmp = ia.hi() * ib.lo());
2088*35238bceSAndroid Build Coastguard Worker         TCU_SET_INTERVAL(prod3, tmp, tmp = ia.hi() * ib.hi());
2089*35238bceSAndroid Build Coastguard Worker 
2090*35238bceSAndroid Build Coastguard Worker         prod = format.convert(format.roundOut(prod0 | prod1 | prod2 | prod3,
2091*35238bceSAndroid Build Coastguard Worker                                               ia.isFinite(format.getMaxValue()) && ib.isFinite(format.getMaxValue())));
2092*35238bceSAndroid Build Coastguard Worker 
2093*35238bceSAndroid Build Coastguard Worker         TCU_SET_INTERVAL_BOUNDS(res, tmp, tmp = prod.lo() + ic.lo(), tmp = prod.hi() + ic.hi());
2094*35238bceSAndroid Build Coastguard Worker 
2095*35238bceSAndroid Build Coastguard Worker         return format.convert(
2096*35238bceSAndroid Build Coastguard Worker             format.roundOut(res, prod.isFinite(format.getMaxValue()) && ic.isFinite(format.getMaxValue())));
2097*35238bceSAndroid Build Coastguard Worker     }
2098*35238bceSAndroid Build Coastguard Worker 
compare(const void * const * inputs,const void * const * outputs)2099*35238bceSAndroid Build Coastguard Worker     bool compare(const void *const *inputs, const void *const *outputs)
2100*35238bceSAndroid Build Coastguard Worker     {
2101*35238bceSAndroid Build Coastguard Worker         const glu::DataType type       = m_spec.inputs[0].varType.getBasicType();
2102*35238bceSAndroid Build Coastguard Worker         const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
2103*35238bceSAndroid Build Coastguard Worker         const int scalarSize           = glu::getDataTypeScalarSize(type);
2104*35238bceSAndroid Build Coastguard Worker 
2105*35238bceSAndroid Build Coastguard Worker         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
2106*35238bceSAndroid Build Coastguard Worker         {
2107*35238bceSAndroid Build Coastguard Worker             const float a           = ((const float *)inputs[0])[compNdx];
2108*35238bceSAndroid Build Coastguard Worker             const float b           = ((const float *)inputs[1])[compNdx];
2109*35238bceSAndroid Build Coastguard Worker             const float c           = ((const float *)inputs[2])[compNdx];
2110*35238bceSAndroid Build Coastguard Worker             const float res         = ((const float *)outputs[0])[compNdx];
2111*35238bceSAndroid Build Coastguard Worker             const tcu::Interval ref = fma(precision, a, b, c);
2112*35238bceSAndroid Build Coastguard Worker 
2113*35238bceSAndroid Build Coastguard Worker             if (!ref.contains(res))
2114*35238bceSAndroid Build Coastguard Worker             {
2115*35238bceSAndroid Build Coastguard Worker                 m_failMsg << "Expected [" << compNdx << "] = " << ref;
2116*35238bceSAndroid Build Coastguard Worker                 return false;
2117*35238bceSAndroid Build Coastguard Worker             }
2118*35238bceSAndroid Build Coastguard Worker         }
2119*35238bceSAndroid Build Coastguard Worker 
2120*35238bceSAndroid Build Coastguard Worker         return true;
2121*35238bceSAndroid Build Coastguard Worker     }
2122*35238bceSAndroid Build Coastguard Worker };
2123*35238bceSAndroid Build Coastguard Worker 
ShaderCommonFunctionTests(Context & context)2124*35238bceSAndroid Build Coastguard Worker ShaderCommonFunctionTests::ShaderCommonFunctionTests(Context &context)
2125*35238bceSAndroid Build Coastguard Worker     : TestCaseGroup(context, "common", "Common function tests")
2126*35238bceSAndroid Build Coastguard Worker {
2127*35238bceSAndroid Build Coastguard Worker }
2128*35238bceSAndroid Build Coastguard Worker 
~ShaderCommonFunctionTests(void)2129*35238bceSAndroid Build Coastguard Worker ShaderCommonFunctionTests::~ShaderCommonFunctionTests(void)
2130*35238bceSAndroid Build Coastguard Worker {
2131*35238bceSAndroid Build Coastguard Worker }
2132*35238bceSAndroid Build Coastguard Worker 
2133*35238bceSAndroid Build Coastguard Worker template <class TestClass>
addFunctionCases(TestCaseGroup * parent,const char * functionName,bool floatTypes,bool intTypes,bool uintTypes,uint32_t shaderBits)2134*35238bceSAndroid Build Coastguard Worker static void addFunctionCases(TestCaseGroup *parent, const char *functionName, bool floatTypes, bool intTypes,
2135*35238bceSAndroid Build Coastguard Worker                              bool uintTypes, uint32_t shaderBits)
2136*35238bceSAndroid Build Coastguard Worker {
2137*35238bceSAndroid Build Coastguard Worker     tcu::TestCaseGroup *group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
2138*35238bceSAndroid Build Coastguard Worker     parent->addChild(group);
2139*35238bceSAndroid Build Coastguard Worker 
2140*35238bceSAndroid Build Coastguard Worker     const glu::DataType scalarTypes[] = {glu::TYPE_FLOAT, glu::TYPE_INT, glu::TYPE_UINT};
2141*35238bceSAndroid Build Coastguard Worker 
2142*35238bceSAndroid Build Coastguard Worker     for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++)
2143*35238bceSAndroid Build Coastguard Worker     {
2144*35238bceSAndroid Build Coastguard Worker         const glu::DataType scalarType = scalarTypes[scalarTypeNdx];
2145*35238bceSAndroid Build Coastguard Worker 
2146*35238bceSAndroid Build Coastguard Worker         if ((!floatTypes && scalarType == glu::TYPE_FLOAT) || (!intTypes && scalarType == glu::TYPE_INT) ||
2147*35238bceSAndroid Build Coastguard Worker             (!uintTypes && scalarType == glu::TYPE_UINT))
2148*35238bceSAndroid Build Coastguard Worker             continue;
2149*35238bceSAndroid Build Coastguard Worker 
2150*35238bceSAndroid Build Coastguard Worker         for (int vecSize = 1; vecSize <= 4; vecSize++)
2151*35238bceSAndroid Build Coastguard Worker         {
2152*35238bceSAndroid Build Coastguard Worker             for (int prec = glu::PRECISION_LOWP; prec <= glu::PRECISION_HIGHP; prec++)
2153*35238bceSAndroid Build Coastguard Worker             {
2154*35238bceSAndroid Build Coastguard Worker                 for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; shaderTypeNdx++)
2155*35238bceSAndroid Build Coastguard Worker                 {
2156*35238bceSAndroid Build Coastguard Worker                     if (shaderBits & (1 << shaderTypeNdx))
2157*35238bceSAndroid Build Coastguard Worker                         group->addChild(new TestClass(parent->getContext(), glu::DataType(scalarType + vecSize - 1),
2158*35238bceSAndroid Build Coastguard Worker                                                       glu::Precision(prec), glu::ShaderType(shaderTypeNdx)));
2159*35238bceSAndroid Build Coastguard Worker                 }
2160*35238bceSAndroid Build Coastguard Worker             }
2161*35238bceSAndroid Build Coastguard Worker         }
2162*35238bceSAndroid Build Coastguard Worker     }
2163*35238bceSAndroid Build Coastguard Worker }
2164*35238bceSAndroid Build Coastguard Worker 
init(void)2165*35238bceSAndroid Build Coastguard Worker void ShaderCommonFunctionTests::init(void)
2166*35238bceSAndroid Build Coastguard Worker {
2167*35238bceSAndroid Build Coastguard Worker     enum
2168*35238bceSAndroid Build Coastguard Worker     {
2169*35238bceSAndroid Build Coastguard Worker         VS = (1 << glu::SHADERTYPE_VERTEX),
2170*35238bceSAndroid Build Coastguard Worker         TC = (1 << glu::SHADERTYPE_TESSELLATION_CONTROL),
2171*35238bceSAndroid Build Coastguard Worker         TE = (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION),
2172*35238bceSAndroid Build Coastguard Worker         GS = (1 << glu::SHADERTYPE_GEOMETRY),
2173*35238bceSAndroid Build Coastguard Worker         FS = (1 << glu::SHADERTYPE_FRAGMENT),
2174*35238bceSAndroid Build Coastguard Worker         CS = (1 << glu::SHADERTYPE_COMPUTE),
2175*35238bceSAndroid Build Coastguard Worker 
2176*35238bceSAndroid Build Coastguard Worker         ALL_SHADERS = VS | TC | TE | GS | FS | CS,
2177*35238bceSAndroid Build Coastguard Worker         NEW_SHADERS = TC | TE | GS | CS,
2178*35238bceSAndroid Build Coastguard Worker     };
2179*35238bceSAndroid Build Coastguard Worker 
2180*35238bceSAndroid Build Coastguard Worker     //                                                                    Float?    Int?    Uint?    Shaders
2181*35238bceSAndroid Build Coastguard Worker     addFunctionCases<AbsCase>(this, "abs", true, true, false, NEW_SHADERS);
2182*35238bceSAndroid Build Coastguard Worker     addFunctionCases<SignCase>(this, "sign", true, true, false, NEW_SHADERS);
2183*35238bceSAndroid Build Coastguard Worker     addFunctionCases<FloorCase>(this, "floor", true, false, false, NEW_SHADERS);
2184*35238bceSAndroid Build Coastguard Worker     addFunctionCases<TruncCase>(this, "trunc", true, false, false, NEW_SHADERS);
2185*35238bceSAndroid Build Coastguard Worker     addFunctionCases<RoundCase>(this, "round", true, false, false, NEW_SHADERS);
2186*35238bceSAndroid Build Coastguard Worker     addFunctionCases<RoundEvenCase>(this, "roundeven", true, false, false, NEW_SHADERS);
2187*35238bceSAndroid Build Coastguard Worker     addFunctionCases<CeilCase>(this, "ceil", true, false, false, NEW_SHADERS);
2188*35238bceSAndroid Build Coastguard Worker     addFunctionCases<FractCase>(this, "fract", true, false, false, NEW_SHADERS);
2189*35238bceSAndroid Build Coastguard Worker     // mod
2190*35238bceSAndroid Build Coastguard Worker     addFunctionCases<ModfCase>(this, "modf", true, false, false, NEW_SHADERS);
2191*35238bceSAndroid Build Coastguard Worker     // min
2192*35238bceSAndroid Build Coastguard Worker     // max
2193*35238bceSAndroid Build Coastguard Worker     // clamp
2194*35238bceSAndroid Build Coastguard Worker     // mix
2195*35238bceSAndroid Build Coastguard Worker     // step
2196*35238bceSAndroid Build Coastguard Worker     // smoothstep
2197*35238bceSAndroid Build Coastguard Worker     addFunctionCases<IsnanCase>(this, "isnan", true, false, false, NEW_SHADERS);
2198*35238bceSAndroid Build Coastguard Worker     addFunctionCases<IsinfCase>(this, "isinf", true, false, false, NEW_SHADERS);
2199*35238bceSAndroid Build Coastguard Worker     addFunctionCases<FloatBitsToIntCase>(this, "floatbitstoint", true, false, false, NEW_SHADERS);
2200*35238bceSAndroid Build Coastguard Worker     addFunctionCases<FloatBitsToUintCase>(this, "floatbitstouint", true, false, false, NEW_SHADERS);
2201*35238bceSAndroid Build Coastguard Worker 
2202*35238bceSAndroid Build Coastguard Worker     addFunctionCases<FrexpCase>(this, "frexp", true, false, false, ALL_SHADERS);
2203*35238bceSAndroid Build Coastguard Worker     addFunctionCases<LdexpCase>(this, "ldexp", true, false, false, ALL_SHADERS);
2204*35238bceSAndroid Build Coastguard Worker     addFunctionCases<FmaCase>(this, "fma", true, false, false, ALL_SHADERS);
2205*35238bceSAndroid Build Coastguard Worker 
2206*35238bceSAndroid Build Coastguard Worker     // (u)intBitsToFloat()
2207*35238bceSAndroid Build Coastguard Worker     {
2208*35238bceSAndroid Build Coastguard Worker         const uint32_t shaderBits     = NEW_SHADERS;
2209*35238bceSAndroid Build Coastguard Worker         tcu::TestCaseGroup *intGroup  = new tcu::TestCaseGroup(m_testCtx, "intbitstofloat", "intBitsToFloat() Tests");
2210*35238bceSAndroid Build Coastguard Worker         tcu::TestCaseGroup *uintGroup = new tcu::TestCaseGroup(m_testCtx, "uintbitstofloat", "uintBitsToFloat() Tests");
2211*35238bceSAndroid Build Coastguard Worker 
2212*35238bceSAndroid Build Coastguard Worker         addChild(intGroup);
2213*35238bceSAndroid Build Coastguard Worker         addChild(uintGroup);
2214*35238bceSAndroid Build Coastguard Worker 
2215*35238bceSAndroid Build Coastguard Worker         for (int vecSize = 1; vecSize < 4; vecSize++)
2216*35238bceSAndroid Build Coastguard Worker         {
2217*35238bceSAndroid Build Coastguard Worker             const glu::DataType intType  = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
2218*35238bceSAndroid Build Coastguard Worker             const glu::DataType uintType = vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT;
2219*35238bceSAndroid Build Coastguard Worker 
2220*35238bceSAndroid Build Coastguard Worker             for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
2221*35238bceSAndroid Build Coastguard Worker             {
2222*35238bceSAndroid Build Coastguard Worker                 if (shaderBits & (1 << shaderType))
2223*35238bceSAndroid Build Coastguard Worker                 {
2224*35238bceSAndroid Build Coastguard Worker                     intGroup->addChild(new BitsToFloatCase(m_context, intType, glu::ShaderType(shaderType)));
2225*35238bceSAndroid Build Coastguard Worker                     uintGroup->addChild(new BitsToFloatCase(m_context, uintType, glu::ShaderType(shaderType)));
2226*35238bceSAndroid Build Coastguard Worker                 }
2227*35238bceSAndroid Build Coastguard Worker             }
2228*35238bceSAndroid Build Coastguard Worker         }
2229*35238bceSAndroid Build Coastguard Worker     }
2230*35238bceSAndroid Build Coastguard Worker }
2231*35238bceSAndroid Build Coastguard Worker 
2232*35238bceSAndroid Build Coastguard Worker } // namespace Functional
2233*35238bceSAndroid Build Coastguard Worker } // namespace gles31
2234*35238bceSAndroid Build Coastguard Worker } // namespace deqp
2235