Merge "Fix color change verification in dithering tests" into nougat-cts-dev am:...
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / accuracy / es3aVaryingInterpolationTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Varying interpolation accuracy tests.
22  *
23  * \todo [2012-07-03 pyry] On GLES3 we could use floating-point render target
24  *                                                 for better accuracy evaluation.
25  *//*--------------------------------------------------------------------*/
26
27 #include "es3aVaryingInterpolationTests.hpp"
28 #include "gluPixelTransfer.hpp"
29 #include "gluShaderProgram.hpp"
30 #include "gluShaderUtil.hpp"
31 #include "tcuStringTemplate.hpp"
32 #include "gluContextInfo.hpp"
33 #include "glsTextureTestUtil.hpp"
34 #include "tcuVector.hpp"
35 #include "tcuVectorUtil.hpp"
36 #include "tcuTestLog.hpp"
37 #include "tcuFloat.hpp"
38 #include "tcuImageCompare.hpp"
39 #include "tcuRenderTarget.hpp"
40 #include "deRandom.hpp"
41 #include "deStringUtil.hpp"
42 #include "deString.h"
43
44 #include "glw.h"
45
46 using tcu::TestLog;
47 using tcu::Vec3;
48 using tcu::Vec4;
49 using std::string;
50 using std::vector;
51 using std::map;
52 using deqp::gls::TextureTestUtil::SurfaceAccess;
53
54 namespace deqp
55 {
56 namespace gles3
57 {
58 namespace Accuracy
59 {
60
61 static inline float projectedTriInterpolate (const tcu::Vec3& s, const tcu::Vec3& w, float nx, float ny)
62 {
63         return (s[0]*(1.0f-nx-ny)/w[0] + s[1]*ny/w[1] + s[2]*nx/w[2]) / ((1.0f-nx-ny)/w[0] + ny/w[1] + nx/w[2]);
64 }
65
66 static void renderReference (const SurfaceAccess& dst, const float coords[4*3], const Vec4& wCoord, const Vec3& scale, const Vec3& bias)
67 {
68         float           dstW            = (float)dst.getWidth();
69         float           dstH            = (float)dst.getHeight();
70
71         Vec3            triR[2]         = { Vec3(coords[0*3+0], coords[1*3+0], coords[2*3+0]), Vec3(coords[3*3+0], coords[2*3+0], coords[1*3+0]) };
72         Vec3            triG[2]         = { Vec3(coords[0*3+1], coords[1*3+1], coords[2*3+1]), Vec3(coords[3*3+1], coords[2*3+1], coords[1*3+1]) };
73         Vec3            triB[2]         = { Vec3(coords[0*3+2], coords[1*3+2], coords[2*3+2]), Vec3(coords[3*3+2], coords[2*3+2], coords[1*3+2]) };
74         tcu::Vec3       triW[2]         = { wCoord.swizzle(0, 1, 2), wCoord.swizzle(3, 2, 1) };
75
76         for (int py = 0; py < dst.getHeight(); py++)
77         {
78                 for (int px = 0; px < dst.getWidth(); px++)
79                 {
80                         float   wx              = (float)px + 0.5f;
81                         float   wy              = (float)py + 0.5f;
82                         float   nx              = wx / dstW;
83                         float   ny              = wy / dstH;
84
85                         int             triNdx  = nx + ny >= 1.0f ? 1 : 0;
86                         float   triNx   = triNdx ? 1.0f - nx : nx;
87                         float   triNy   = triNdx ? 1.0f - ny : ny;
88
89                         float   r               = projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy) * scale[0] + bias[0];
90                         float   g               = projectedTriInterpolate(triG[triNdx], triW[triNdx], triNx, triNy) * scale[1] + bias[1];
91                         float   b               = projectedTriInterpolate(triB[triNdx], triW[triNdx], triNx, triNy) * scale[2] + bias[2];
92
93                         Vec4    color   = Vec4(r, g, b, 1.0f);
94
95                         dst.setPixel(color, px, py);
96                 }
97         }
98 }
99
100 class InterpolationCase : public TestCase
101 {
102 public:
103                                         InterpolationCase                       (Context& context, const char* name, const char* desc, glu::Precision precision, const tcu::Vec3& minVal, const tcu::Vec3& maxVal, bool projective);
104                                         ~InterpolationCase                      (void);
105
106         IterateResult   iterate                                         (void);
107
108 private:
109         glu::Precision  m_precision;
110         tcu::Vec3               m_min;
111         tcu::Vec3               m_max;
112         bool                    m_projective;
113 };
114
115 InterpolationCase::InterpolationCase (Context& context, const char* name, const char* desc, glu::Precision precision, const tcu::Vec3& minVal, const tcu::Vec3& maxVal, bool projective)
116         : TestCase              (context, tcu::NODETYPE_ACCURACY, name, desc)
117         , m_precision   (precision)
118         , m_min                 (minVal)
119         , m_max                 (maxVal)
120         , m_projective  (projective)
121 {
122 }
123
124 InterpolationCase::~InterpolationCase (void)
125 {
126 }
127
128 static bool isValidFloat (glu::Precision precision, float val)
129 {
130         if (precision == glu::PRECISION_MEDIUMP)
131         {
132                 tcu::Float16 fp16(val);
133                 return !fp16.isDenorm() && !fp16.isInf() && !fp16.isNaN();
134         }
135         else
136         {
137                 tcu::Float32 fp32(val);
138                 return !fp32.isDenorm() && !fp32.isInf() && !fp32.isNaN();
139         }
140 }
141
142 template <int Size>
143 static bool isValidFloatVec (glu::Precision precision, const tcu::Vector<float, Size>& vec)
144 {
145         for (int ndx = 0; ndx < Size; ndx++)
146         {
147                 if (!isValidFloat(precision, vec[ndx]))
148                         return false;
149         }
150         return true;
151 }
152
153 InterpolationCase::IterateResult InterpolationCase::iterate (void)
154 {
155         TestLog&                                        log                             = m_testCtx.getLog();
156         de::Random                                      rnd                             (deStringHash(getName()));
157         const tcu::RenderTarget&        renderTarget    = m_context.getRenderTarget();
158         int                                                     viewportWidth   = 128;
159         int                                                     viewportHeight  = 128;
160
161         if (renderTarget.getWidth() < viewportWidth ||
162                 renderTarget.getHeight() < viewportHeight)
163                 throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
164
165         int                                                     viewportX               = rnd.getInt(0, renderTarget.getWidth()         - viewportWidth);
166         int                                                     viewportY               = rnd.getInt(0, renderTarget.getHeight()        - viewportHeight);
167
168         static const char* s_vertShaderTemplate =
169                 "#version 300 es\n"
170                 "in highp vec4 a_position;\n"
171                 "in ${PRECISION} vec3 a_coords;\n"
172                 "out ${PRECISION} vec3 v_coords;\n"
173                 "\n"
174                 "void main (void)\n"
175                 "{\n"
176                 "       gl_Position = a_position;\n"
177                 "       v_coords = a_coords;\n"
178                 "}\n";
179         static const char* s_fragShaderTemplate =
180                 "#version 300 es\n"
181                 "in ${PRECISION} vec3 v_coords;\n"
182                 "uniform ${PRECISION} vec3 u_scale;\n"
183                 "uniform ${PRECISION} vec3 u_bias;\n"
184                 "layout(location = 0) out ${PRECISION} vec4 o_color;\n"
185                 "\n"
186                 "void main (void)\n"
187                 "{\n"
188                 "       o_color = vec4(v_coords * u_scale + u_bias, 1.0);\n"
189                 "}\n";
190
191         map<string, string> templateParams;
192         templateParams["PRECISION"] = glu::getPrecisionName(m_precision);
193
194         glu::ShaderProgram program(m_context.getRenderContext(),
195                                                            glu::makeVtxFragSources(tcu::StringTemplate(s_vertShaderTemplate).specialize(templateParams),
196                                                                                                            tcu::StringTemplate(s_fragShaderTemplate).specialize(templateParams)));
197         log << program;
198         if (!program.isOk())
199         {
200                 if (m_precision == glu::PRECISION_HIGHP && !m_context.getContextInfo().isFragmentHighPrecisionSupported())
201                         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Fragment highp not supported");
202                 else
203                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
204                 return STOP;
205         }
206
207         // Position coordinates.
208         Vec4 wCoord = m_projective ? Vec4(1.3f, 0.8f, 0.6f, 2.0f) : Vec4(1.0f, 1.0f, 1.0f, 1.0f);
209         float positions[] =
210         {
211                 -1.0f*wCoord.x(), -1.0f*wCoord.x(), 0.0f, wCoord.x(),
212                 -1.0f*wCoord.y(), +1.0f*wCoord.y(), 0.0f, wCoord.y(),
213                 +1.0f*wCoord.z(), -1.0f*wCoord.z(), 0.0f, wCoord.z(),
214                 +1.0f*wCoord.w(), +1.0f*wCoord.w(), 0.0f, wCoord.w()
215         };
216
217         // Coordinates for interpolation.
218         tcu::Vec3 scale = 1.0f / (m_max - m_min);
219         tcu::Vec3 bias  = -1.0f*m_min*scale;
220         float coords[] =
221         {
222                 (0.0f - bias[0])/scale[0], (0.5f - bias[1])/scale[1], (1.0f - bias[2])/scale[2],
223                 (0.5f - bias[0])/scale[0], (1.0f - bias[1])/scale[1], (0.5f - bias[2])/scale[2],
224                 (0.5f - bias[0])/scale[0], (0.0f - bias[1])/scale[1], (0.5f - bias[2])/scale[2],
225                 (1.0f - bias[0])/scale[0], (0.5f - bias[1])/scale[1], (0.0f - bias[2])/scale[2]
226         };
227
228         log << TestLog::Message << "a_coords = " << ((tcu::Vec3(0.0f) - bias)/scale) << " -> " << ((tcu::Vec3(1.0f) - bias)/scale) << TestLog::EndMessage;
229         log << TestLog::Message << "u_scale = " << scale << TestLog::EndMessage;
230         log << TestLog::Message << "u_bias = " << bias << TestLog::EndMessage;
231
232         // Verify that none of the inputs are denormalized / inf / nan.
233         TCU_CHECK(isValidFloatVec(m_precision, scale));
234         TCU_CHECK(isValidFloatVec(m_precision, bias));
235         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(coords); ndx++)
236         {
237                 TCU_CHECK(isValidFloat(m_precision, coords[ndx]));
238                 TCU_CHECK(isValidFloat(m_precision, coords[ndx] * scale[ndx % 3] + bias[ndx % 3]));
239         }
240
241         // Indices.
242         static const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
243
244         {
245                 const int       posLoc          = glGetAttribLocation(program.getProgram(), "a_position");
246                 const int       coordLoc        = glGetAttribLocation(program.getProgram(), "a_coords");
247
248                 glEnableVertexAttribArray(posLoc);
249                 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &positions[0]);
250
251                 glEnableVertexAttribArray(coordLoc);
252                 glVertexAttribPointer(coordLoc, 3, GL_FLOAT, GL_FALSE, 0, &coords[0]);
253         }
254
255         glUseProgram(program.getProgram());
256         glUniform3f(glGetUniformLocation(program.getProgram(), "u_scale"), scale.x(), scale.y(), scale.z());
257         glUniform3f(glGetUniformLocation(program.getProgram(), "u_bias"), bias.x(), bias.y(), bias.z());
258
259         GLU_CHECK_MSG("After program setup");
260
261         // Frames.
262         tcu::Surface    rendered                (viewportWidth, viewportHeight);
263         tcu::Surface    reference               (viewportWidth, viewportHeight);
264
265         // Render with GL.
266         glViewport(viewportX, viewportY, viewportWidth, viewportHeight);
267         glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
268
269         // Render reference \note While GPU is hopefully doing our draw call.
270         renderReference(SurfaceAccess(reference, m_context.getRenderTarget().getPixelFormat()), coords, wCoord, scale, bias);
271
272         glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, rendered.getAccess());
273
274         // Compute difference.
275         const int               bestScoreDiff   = 16;
276         const int               worstScoreDiff  = 300;
277         int                             score                   = tcu::measurePixelDiffAccuracy(log, "Result", "Image comparison result", reference, rendered, bestScoreDiff, worstScoreDiff, tcu::COMPARE_LOG_EVERYTHING);
278
279         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
280         return STOP;
281 }
282
283 VaryingInterpolationTests::VaryingInterpolationTests (Context& context)
284         : TestCaseGroup(context, "interpolation", "Varying Interpolation Accuracy Tests")
285 {
286 }
287
288 VaryingInterpolationTests::~VaryingInterpolationTests (void)
289 {
290 }
291
292 void VaryingInterpolationTests::init (void)
293 {
294         DE_STATIC_ASSERT(glu::PRECISION_LOWP+1          == glu::PRECISION_MEDIUMP);
295         DE_STATIC_ASSERT(glu::PRECISION_MEDIUMP+1       == glu::PRECISION_HIGHP);
296
297         // Exp = Emax-3, Mantissa = 0
298         float minF32 = tcu::Float32((0u<<31) | (0xfcu<<23) | 0x0u).asFloat();
299         float maxF32 = tcu::Float32((1u<<31) | (0xfcu<<23) | 0x0u).asFloat();
300         float minF16 = tcu::Float16((deUint16)((0u<<15) | (0x1cu<<10) | 0x0u)).asFloat();
301         float maxF16 = tcu::Float16((deUint16)((1u<<15) | (0x1cu<<10) | 0x0u)).asFloat();
302
303         static const struct
304         {
305                 const char*             name;
306                 Vec3                    minVal;
307                 Vec3                    maxVal;
308                 glu::Precision  minPrecision;
309         } coordRanges[] =
310         {
311                 { "zero_to_one",                Vec3(  0.0f,   0.0f,   0.0f), Vec3(  1.0f,   1.0f,   1.0f), glu::PRECISION_LOWP         },
312                 { "zero_to_minus_one",  Vec3(  0.0f,   0.0f,   0.0f), Vec3( -1.0f,  -1.0f,  -1.0f), glu::PRECISION_LOWP         },
313                 { "minus_one_to_one",   Vec3( -1.0f,  -1.0f,  -1.0f), Vec3(  1.0f,   1.0f,   1.0f), glu::PRECISION_LOWP         },
314                 { "minus_ten_to_ten",   Vec3(-10.0f, -10.0f, -10.0f), Vec3( 10.0f,  10.0f,  10.0f), glu::PRECISION_MEDIUMP      },
315                 { "thousands",                  Vec3( -5e3f,   1e3f,   1e3f), Vec3(  3e3f,  -1e3f,   7e3f), glu::PRECISION_MEDIUMP      },
316                 { "full_mediump",               Vec3(minF16, minF16, minF16), Vec3(maxF16, maxF16, maxF16), glu::PRECISION_MEDIUMP      },
317                 { "full_highp",                 Vec3(minF32, minF32, minF32), Vec3(maxF32, maxF32, maxF32), glu::PRECISION_HIGHP        },
318         };
319
320         for (int precision = glu::PRECISION_LOWP; precision <= glu::PRECISION_HIGHP; precision++)
321         {
322                 for (int coordNdx = 0; coordNdx < DE_LENGTH_OF_ARRAY(coordRanges); coordNdx++)
323                 {
324                         if (precision < (int)coordRanges[coordNdx].minPrecision)
325                                 continue;
326
327                         string baseName = string(glu::getPrecisionName((glu::Precision)precision)) + "_" + coordRanges[coordNdx].name;
328
329                         addChild(new InterpolationCase(m_context, baseName.c_str(),                             "",     (glu::Precision)precision, coordRanges[coordNdx].minVal, coordRanges[coordNdx].maxVal, false));
330                         addChild(new InterpolationCase(m_context, (baseName + "_proj").c_str(), "",     (glu::Precision)precision, coordRanges[coordNdx].minVal, coordRanges[coordNdx].maxVal, true));
331                 }
332         }
333 }
334
335 } // Accuracy
336 } // gles3
337 } // deqp