xref: /aosp_15_r20/external/deqp/modules/gles2/accuracy/es2aVaryingInterpolationTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 2.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 
24 #include "es2aVaryingInterpolationTests.hpp"
25 #include "gluPixelTransfer.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "gluShaderUtil.hpp"
28 #include "tcuStringTemplate.hpp"
29 #include "gluContextInfo.hpp"
30 #include "glsTextureTestUtil.hpp"
31 #include "tcuVector.hpp"
32 #include "tcuVectorUtil.hpp"
33 #include "tcuTestLog.hpp"
34 #include "tcuFloat.hpp"
35 #include "tcuImageCompare.hpp"
36 #include "tcuRenderTarget.hpp"
37 #include "tcuSurfaceAccess.hpp"
38 #include "deRandom.hpp"
39 #include "deStringUtil.hpp"
40 #include "deString.h"
41 
42 #include "glw.h"
43 
44 using std::map;
45 using std::string;
46 using std::vector;
47 using tcu::SurfaceAccess;
48 using tcu::TestLog;
49 using tcu::Vec3;
50 using tcu::Vec4;
51 
52 namespace deqp
53 {
54 namespace gles2
55 {
56 namespace Accuracy
57 {
58 
projectedTriInterpolate(const tcu::Vec3 & s,const tcu::Vec3 & w,float nx,float ny)59 static inline float projectedTriInterpolate(const tcu::Vec3 &s, const tcu::Vec3 &w, float nx, float ny)
60 {
61     return (s[0] * (1.0f - nx - ny) / w[0] + s[1] * ny / w[1] + s[2] * nx / w[2]) /
62            ((1.0f - nx - ny) / w[0] + ny / w[1] + nx / w[2]);
63 }
64 
renderReference(const SurfaceAccess & dst,const float coords[4* 3],const Vec4 & wCoord,const Vec3 & scale,const Vec3 & bias)65 static void renderReference(const SurfaceAccess &dst, const float coords[4 * 3], const Vec4 &wCoord, const Vec3 &scale,
66                             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]),
72                          Vec3(coords[3 * 3 + 0], coords[2 * 3 + 0], coords[1 * 3 + 0])};
73     Vec3 triG[2]      = {Vec3(coords[0 * 3 + 1], coords[1 * 3 + 1], coords[2 * 3 + 1]),
74                          Vec3(coords[3 * 3 + 1], coords[2 * 3 + 1], coords[1 * 3 + 1])};
75     Vec3 triB[2]      = {Vec3(coords[0 * 3 + 2], coords[1 * 3 + 2], coords[2 * 3 + 2]),
76                          Vec3(coords[3 * 3 + 2], coords[2 * 3 + 2], coords[1 * 3 + 2])};
77     tcu::Vec3 triW[2] = {wCoord.swizzle(0, 1, 2), wCoord.swizzle(3, 2, 1)};
78 
79     for (int py = 0; py < dst.getHeight(); py++)
80     {
81         for (int px = 0; px < dst.getWidth(); px++)
82         {
83             float wx = (float)px + 0.5f;
84             float wy = (float)py + 0.5f;
85             float nx = wx / dstW;
86             float ny = wy / dstH;
87 
88             int triNdx  = nx + ny >= 1.0f ? 1 : 0;
89             float triNx = triNdx ? 1.0f - nx : nx;
90             float triNy = triNdx ? 1.0f - ny : ny;
91 
92             float r = projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy) * scale[0] + bias[0];
93             float g = projectedTriInterpolate(triG[triNdx], triW[triNdx], triNx, triNy) * scale[1] + bias[1];
94             float b = projectedTriInterpolate(triB[triNdx], triW[triNdx], triNx, triNy) * scale[2] + bias[2];
95 
96             Vec4 color = Vec4(r, g, b, 1.0f);
97 
98             dst.setPixel(color, px, py);
99         }
100     }
101 }
102 
103 class InterpolationCase : public TestCase
104 {
105 public:
106     InterpolationCase(Context &context, const char *name, const char *desc, glu::Precision precision,
107                       const tcu::Vec3 &minVal, const tcu::Vec3 &maxVal, bool projective);
108     ~InterpolationCase(void);
109 
110     IterateResult iterate(void);
111 
112 private:
113     glu::Precision m_precision;
114     tcu::Vec3 m_min;
115     tcu::Vec3 m_max;
116     bool m_projective;
117 };
118 
InterpolationCase(Context & context,const char * name,const char * desc,glu::Precision precision,const tcu::Vec3 & minVal,const tcu::Vec3 & maxVal,bool projective)119 InterpolationCase::InterpolationCase(Context &context, const char *name, const char *desc, glu::Precision precision,
120                                      const tcu::Vec3 &minVal, const tcu::Vec3 &maxVal, bool projective)
121     : TestCase(context, tcu::NODETYPE_ACCURACY, name, desc)
122     , m_precision(precision)
123     , m_min(minVal)
124     , m_max(maxVal)
125     , m_projective(projective)
126 {
127 }
128 
~InterpolationCase(void)129 InterpolationCase::~InterpolationCase(void)
130 {
131 }
132 
isValidFloat(glu::Precision precision,float val)133 static bool isValidFloat(glu::Precision precision, float val)
134 {
135     if (precision == glu::PRECISION_MEDIUMP)
136     {
137         tcu::Float16 fp16(val);
138         return !fp16.isDenorm() && !fp16.isInf() && !fp16.isNaN();
139     }
140     else
141     {
142         tcu::Float32 fp32(val);
143         return !fp32.isDenorm() && !fp32.isInf() && !fp32.isNaN();
144     }
145 }
146 
147 template <int Size>
isValidFloatVec(glu::Precision precision,const tcu::Vector<float,Size> & vec)148 static bool isValidFloatVec(glu::Precision precision, const tcu::Vector<float, Size> &vec)
149 {
150     for (int ndx = 0; ndx < Size; ndx++)
151     {
152         if (!isValidFloat(precision, vec[ndx]))
153             return false;
154     }
155     return true;
156 }
157 
iterate(void)158 InterpolationCase::IterateResult InterpolationCase::iterate(void)
159 {
160     TestLog &log = m_testCtx.getLog();
161     de::Random rnd(deStringHash(getName()));
162     int viewportWidth  = 128;
163     int viewportHeight = 128;
164 
165     if (m_context.getRenderTarget().getWidth() < viewportWidth ||
166         m_context.getRenderTarget().getHeight() < viewportHeight)
167         throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
168 
169     int viewportX = rnd.getInt(0, m_context.getRenderTarget().getWidth() - viewportWidth);
170     int viewportY = rnd.getInt(0, m_context.getRenderTarget().getHeight() - viewportHeight);
171 
172     static const char *s_vertShaderTemplate = "attribute highp vec4 a_position;\n"
173                                               "attribute ${PRECISION} vec3 a_coords;\n"
174                                               "varying ${PRECISION} vec3 v_coords;\n"
175                                               "\n"
176                                               "void main (void)\n"
177                                               "{\n"
178                                               "    gl_Position = a_position;\n"
179                                               "    v_coords = a_coords;\n"
180                                               "}\n";
181     static const char *s_fragShaderTemplate = "varying ${PRECISION} vec3 v_coords;\n"
182                                               "uniform ${PRECISION} vec3 u_scale;\n"
183                                               "uniform ${PRECISION} vec3 u_bias;\n"
184                                               "\n"
185                                               "void main (void)\n"
186                                               "{\n"
187                                               "    gl_FragColor = vec4(v_coords * u_scale + u_bias, 1.0);\n"
188                                               "}\n";
189 
190     map<string, string> templateParams;
191     templateParams["PRECISION"] = glu::getPrecisionName(m_precision);
192 
193     glu::ShaderProgram program(
194         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[] = {-1.0f * wCoord.x(), -1.0f * wCoord.x(), 0.0f, wCoord.x(),
210                          -1.0f * wCoord.y(), +1.0f * wCoord.y(), 0.0f, wCoord.y(),
211                          +1.0f * wCoord.z(), -1.0f * wCoord.z(), 0.0f, wCoord.z(),
212                          +1.0f * wCoord.w(), +1.0f * wCoord.w(), 0.0f, wCoord.w()};
213 
214     // Coordinates for interpolation.
215     tcu::Vec3 scale = 1.0f / (m_max - m_min);
216     tcu::Vec3 bias  = -1.0f * m_min * scale;
217     float coords[]  = {(0.0f - bias[0]) / scale[0], (0.5f - bias[1]) / scale[1], (1.0f - bias[2]) / scale[2],
218                        (0.5f - bias[0]) / scale[0], (1.0f - bias[1]) / scale[1], (0.5f - bias[2]) / scale[2],
219                        (0.5f - bias[0]) / scale[0], (0.0f - bias[1]) / scale[1], (0.5f - bias[2]) / scale[2],
220                        (1.0f - bias[0]) / scale[0], (0.5f - bias[1]) / scale[1], (0.0f - bias[2]) / scale[2]};
221 
222     log << TestLog::Message << "a_coords = " << ((tcu::Vec3(0.0f) - bias) / scale) << " -> "
223         << ((tcu::Vec3(1.0f) - bias) / scale) << TestLog::EndMessage;
224     log << TestLog::Message << "u_scale = " << scale << TestLog::EndMessage;
225     log << TestLog::Message << "u_bias = " << bias << TestLog::EndMessage;
226 
227     // Verify that none of the inputs are denormalized / inf / nan.
228     TCU_CHECK(isValidFloatVec(m_precision, scale));
229     TCU_CHECK(isValidFloatVec(m_precision, bias));
230     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(coords); ndx++)
231     {
232         TCU_CHECK(isValidFloat(m_precision, coords[ndx]));
233         TCU_CHECK(isValidFloat(m_precision, coords[ndx] * scale[ndx % 3] + bias[ndx % 3]));
234     }
235 
236     // Indices.
237     static const uint16_t indices[] = {0, 1, 2, 2, 1, 3};
238 
239     {
240         const int posLoc   = glGetAttribLocation(program.getProgram(), "a_position");
241         const int coordLoc = glGetAttribLocation(program.getProgram(), "a_coords");
242 
243         glEnableVertexAttribArray(posLoc);
244         glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &positions[0]);
245 
246         glEnableVertexAttribArray(coordLoc);
247         glVertexAttribPointer(coordLoc, 3, GL_FLOAT, GL_FALSE, 0, &coords[0]);
248     }
249 
250     glUseProgram(program.getProgram());
251     glUniform3f(glGetUniformLocation(program.getProgram(), "u_scale"), scale.x(), scale.y(), scale.z());
252     glUniform3f(glGetUniformLocation(program.getProgram(), "u_bias"), bias.x(), bias.y(), bias.z());
253 
254     GLU_CHECK_MSG("After program setup");
255 
256     // Frames.
257     tcu::Surface rendered(viewportWidth, viewportHeight);
258     tcu::Surface reference(viewportWidth, viewportHeight);
259 
260     // Render with GL.
261     glViewport(viewportX, viewportY, viewportWidth, viewportHeight);
262     glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
263 
264     // Render reference \note While GPU is hopefully doing our draw call.
265     renderReference(SurfaceAccess(reference, m_context.getRenderTarget().getPixelFormat()), coords, wCoord, scale,
266                     bias);
267 
268     glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, rendered.getAccess());
269 
270     // Compute difference.
271     const int bestScoreDiff  = 16;
272     const int worstScoreDiff = 300;
273     int score = tcu::measurePixelDiffAccuracy(log, "Result", "Image comparison result", reference, rendered,
274                                               bestScoreDiff, worstScoreDiff, tcu::COMPARE_LOG_EVERYTHING);
275 
276     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
277     return STOP;
278 }
279 
VaryingInterpolationTests(Context & context)280 VaryingInterpolationTests::VaryingInterpolationTests(Context &context)
281     : TestCaseGroup(context, "interpolation", "Varying Interpolation Accuracy Tests")
282 {
283 }
284 
~VaryingInterpolationTests(void)285 VaryingInterpolationTests::~VaryingInterpolationTests(void)
286 {
287 }
288 
init(void)289 void VaryingInterpolationTests::init(void)
290 {
291     DE_STATIC_ASSERT(glu::PRECISION_LOWP + 1 == glu::PRECISION_MEDIUMP);
292     DE_STATIC_ASSERT(glu::PRECISION_MEDIUMP + 1 == glu::PRECISION_HIGHP);
293 
294     // Exp = Emax-3, Mantissa = 0
295     float minF32 = tcu::Float32((0u << 31) | (0xfcu << 23) | 0x0u).asFloat();
296     float maxF32 = tcu::Float32((1u << 31) | (0xfcu << 23) | 0x0u).asFloat();
297     float minF16 = tcu::Float16((uint16_t)((0u << 15) | (0x1cu << 10) | 0x0u)).asFloat();
298     float maxF16 = tcu::Float16((uint16_t)((1u << 15) | (0x1cu << 10) | 0x0u)).asFloat();
299 
300     static const struct
301     {
302         const char *name;
303         Vec3 minVal;
304         Vec3 maxVal;
305         glu::Precision minPrecision;
306     } coordRanges[] = {
307         {"zero_to_one", Vec3(0.0f, 0.0f, 0.0f), Vec3(1.0f, 1.0f, 1.0f), glu::PRECISION_LOWP},
308         {"zero_to_minus_one", Vec3(0.0f, 0.0f, 0.0f), Vec3(-1.0f, -1.0f, -1.0f), glu::PRECISION_LOWP},
309         {"minus_one_to_one", Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f), glu::PRECISION_LOWP},
310         {"minus_ten_to_ten", Vec3(-10.0f, -10.0f, -10.0f), Vec3(10.0f, 10.0f, 10.0f), glu::PRECISION_MEDIUMP},
311         {"thousands", Vec3(-5e3f, 1e3f, 1e3f), Vec3(3e3f, -1e3f, 7e3f), glu::PRECISION_MEDIUMP},
312         {"full_mediump", Vec3(minF16, minF16, minF16), Vec3(maxF16, maxF16, maxF16), glu::PRECISION_MEDIUMP},
313         {"full_highp", Vec3(minF32, minF32, minF32), Vec3(maxF32, maxF32, maxF32), glu::PRECISION_HIGHP},
314     };
315 
316     for (int precision = glu::PRECISION_LOWP; precision <= glu::PRECISION_HIGHP; precision++)
317     {
318         for (int coordNdx = 0; coordNdx < DE_LENGTH_OF_ARRAY(coordRanges); coordNdx++)
319         {
320             if (precision < (int)coordRanges[coordNdx].minPrecision)
321                 continue;
322 
323             string baseName =
324                 string(glu::getPrecisionName((glu::Precision)precision)) + "_" + coordRanges[coordNdx].name;
325 
326             addChild(new InterpolationCase(m_context, baseName.c_str(), "", (glu::Precision)precision,
327                                            coordRanges[coordNdx].minVal, coordRanges[coordNdx].maxVal, false));
328             addChild(new InterpolationCase(m_context, (baseName + "_proj").c_str(), "", (glu::Precision)precision,
329                                            coordRanges[coordNdx].minVal, coordRanges[coordNdx].maxVal, true));
330         }
331     }
332 }
333 
334 } // namespace Accuracy
335 } // namespace gles2
336 } // namespace deqp
337