xref: /aosp_15_r20/external/deqp/modules/gles2/functional/es2fShaderBuiltinVarTests.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 Shader built-in variable tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es2fShaderBuiltinVarTests.hpp"
25 #include "glsShaderRenderCase.hpp"
26 #include "deRandom.hpp"
27 #include "deString.h"
28 #include "deMath.h"
29 #include "deStringUtil.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuTestCase.hpp"
32 #include "tcuTextureUtil.hpp"
33 #include "tcuRenderTarget.hpp"
34 #include "tcuImageCompare.hpp"
35 #include "gluPixelTransfer.hpp"
36 #include "gluDrawUtil.hpp"
37 
38 #include "glwEnums.hpp"
39 #include "glwFunctions.hpp"
40 
41 using std::string;
42 using std::vector;
43 using tcu::TestLog;
44 
45 namespace deqp
46 {
47 namespace gles2
48 {
49 namespace Functional
50 {
51 
52 const float builtinConstScale = 4.0f;
53 
evalBuiltinConstant(gls::ShaderEvalContext & c)54 void evalBuiltinConstant(gls::ShaderEvalContext &c)
55 {
56     bool isOk = 0 == (int)(deFloatFloor(c.coords.x() * builtinConstScale) + 0.05f);
57     c.color   = isOk ? tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f) : tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
58 }
59 
60 class ShaderBuiltinConstantCase : public gls::ShaderRenderCase
61 {
62 public:
63     ShaderBuiltinConstantCase(Context &context, const char *name, const char *desc, const char *varName,
64                               uint32_t paramName, bool isVertexCase);
65     ~ShaderBuiltinConstantCase(void);
66 
67     int getRefValue(void);
68     void init(void);
69 
70 private:
71     const std::string m_varName;
72     const uint32_t m_paramName;
73 };
74 
ShaderBuiltinConstantCase(Context & context,const char * name,const char * desc,const char * varName,uint32_t paramName,bool isVertexCase)75 ShaderBuiltinConstantCase::ShaderBuiltinConstantCase(Context &context, const char *name, const char *desc,
76                                                      const char *varName, uint32_t paramName, bool isVertexCase)
77     : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc,
78                        isVertexCase, evalBuiltinConstant)
79     , m_varName(varName)
80     , m_paramName(paramName)
81 {
82 }
83 
~ShaderBuiltinConstantCase(void)84 ShaderBuiltinConstantCase::~ShaderBuiltinConstantCase(void)
85 {
86 }
87 
getRefValue(void)88 int ShaderBuiltinConstantCase::getRefValue(void)
89 {
90     if (m_varName == "gl_MaxDrawBuffers")
91     {
92         if (m_ctxInfo.isExtensionSupported("GL_EXT_draw_buffers") ||
93             m_ctxInfo.isExtensionSupported("GL_NV_draw_buffers") || m_ctxInfo.isES3Compatible())
94             return m_ctxInfo.getInt(GL_MAX_DRAW_BUFFERS);
95         else
96             return 1;
97     }
98     else
99     {
100         DE_ASSERT(m_paramName != GL_NONE);
101         return m_ctxInfo.getInt(m_paramName);
102     }
103 }
104 
init(void)105 void ShaderBuiltinConstantCase::init(void)
106 {
107     const int refValue = getRefValue();
108     m_testCtx.getLog() << tcu::TestLog::Message << m_varName << " = " << refValue << tcu::TestLog::EndMessage;
109 
110     static const char *defaultVertSrc = "attribute highp vec4 a_position;\n"
111                                         "attribute highp vec4 a_coords;\n"
112                                         "varying mediump vec4 v_coords;\n\n"
113                                         "void main (void)\n"
114                                         "{\n"
115                                         "    v_coords = a_coords;\n"
116                                         "    gl_Position = a_position;\n"
117                                         "}\n";
118     static const char *defaultFragSrc = "varying mediump vec4 v_color;\n\n"
119                                         "void main (void)\n"
120                                         "{\n"
121                                         "    gl_FragColor = v_color;\n"
122                                         "}\n";
123 
124     // Construct shader.
125     std::ostringstream src;
126     if (m_isVertexCase)
127     {
128         src << "attribute highp vec4 a_position;\n"
129             << "attribute highp vec4 a_coords;\n"
130             << "varying mediump vec4 v_color;\n";
131     }
132     else
133         src << "varying mediump vec4 v_coords;\n";
134 
135     src << "void main (void)\n{\n";
136 
137     src << "\tbool isOk = " << m_varName << " == (" << refValue << " + int(floor("
138         << (m_isVertexCase ? "a_coords" : "v_coords") << ".x * " << de::floatToString(builtinConstScale, 1)
139         << ") + 0.05));\n";
140     src << "\t" << (m_isVertexCase ? "v_color" : "gl_FragColor")
141         << " = isOk ? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);\n";
142 
143     if (m_isVertexCase)
144         src << "\tgl_Position = a_position;\n";
145 
146     src << "}\n";
147 
148     m_vertShaderSource = m_isVertexCase ? src.str() : defaultVertSrc;
149     m_fragShaderSource = m_isVertexCase ? defaultFragSrc : src.str();
150 
151     gls::ShaderRenderCase::init();
152 }
153 
154 namespace
155 {
156 
157 struct DepthRangeParams
158 {
DepthRangeParamsdeqp::gles2::Functional::__anonac2a45210111::DepthRangeParams159     DepthRangeParams(void) : zNear(0.0f), zFar(1.0f)
160     {
161     }
162 
DepthRangeParamsdeqp::gles2::Functional::__anonac2a45210111::DepthRangeParams163     DepthRangeParams(float zNear_, float zFar_) : zNear(zNear_), zFar(zFar_)
164     {
165     }
166 
167     float zNear;
168     float zFar;
169 };
170 
171 class DepthRangeEvaluator : public gls::ShaderEvaluator
172 {
173 public:
DepthRangeEvaluator(const DepthRangeParams & params)174     DepthRangeEvaluator(const DepthRangeParams &params) : m_params(params)
175     {
176     }
177 
evaluate(gls::ShaderEvalContext & c)178     void evaluate(gls::ShaderEvalContext &c)
179     {
180         float zNear   = deFloatClamp(m_params.zNear, 0.0f, 1.0f);
181         float zFar    = deFloatClamp(m_params.zFar, 0.0f, 1.0f);
182         float diff    = zFar - zNear;
183         c.color.xyz() = tcu::Vec3(zNear, zFar, diff * 0.5f + 0.5f);
184     }
185 
186 private:
187     const DepthRangeParams &m_params;
188 };
189 
190 } // namespace
191 
192 class ShaderDepthRangeTest : public gls::ShaderRenderCase
193 {
194 public:
ShaderDepthRangeTest(Context & context,const char * name,const char * desc,bool isVertexCase)195     ShaderDepthRangeTest(Context &context, const char *name, const char *desc, bool isVertexCase)
196         : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc,
197                            isVertexCase, m_evaluator)
198         , m_evaluator(m_depthRange)
199         , m_iterNdx(0)
200     {
201     }
202 
init(void)203     void init(void)
204     {
205         static const char *defaultVertSrc = "attribute highp vec4 a_position;\n"
206                                             "void main (void)\n"
207                                             "{\n"
208                                             "    gl_Position = a_position;\n"
209                                             "}\n";
210         static const char *defaultFragSrc = "varying mediump vec4 v_color;\n\n"
211                                             "void main (void)\n"
212                                             "{\n"
213                                             "    gl_FragColor = v_color;\n"
214                                             "}\n";
215 
216         // Construct shader.
217         std::ostringstream src;
218         if (m_isVertexCase)
219             src << "attribute highp vec4 a_position;\n"
220                 << "varying mediump vec4 v_color;\n";
221 
222         src << "void main (void)\n{\n";
223         src << "\t" << (m_isVertexCase ? "v_color" : "gl_FragColor")
224             << " = vec4(gl_DepthRange.near, gl_DepthRange.far, gl_DepthRange.diff*0.5 + 0.5, 1.0);\n";
225 
226         if (m_isVertexCase)
227             src << "\tgl_Position = a_position;\n";
228 
229         src << "}\n";
230 
231         m_vertShaderSource = m_isVertexCase ? src.str() : defaultVertSrc;
232         m_fragShaderSource = m_isVertexCase ? defaultFragSrc : src.str();
233 
234         gls::ShaderRenderCase::init();
235     }
236 
iterate(void)237     IterateResult iterate(void)
238     {
239         const glw::Functions &gl = m_renderCtx.getFunctions();
240 
241         const DepthRangeParams cases[] = {DepthRangeParams(0.0f, 1.0f), DepthRangeParams(1.5f, -1.0f),
242                                           DepthRangeParams(0.7f, 0.3f)};
243 
244         m_depthRange = cases[m_iterNdx];
245         m_testCtx.getLog() << tcu::TestLog::Message << "glDepthRangef(" << m_depthRange.zNear << ", "
246                            << m_depthRange.zFar << ")" << tcu::TestLog::EndMessage;
247         gl.depthRangef(m_depthRange.zNear, m_depthRange.zFar);
248         GLU_EXPECT_NO_ERROR(gl.getError(), "glDepthRangef()");
249 
250         gls::ShaderRenderCase::iterate();
251         m_iterNdx += 1;
252 
253         if (m_iterNdx == DE_LENGTH_OF_ARRAY(cases) || m_testCtx.getTestResult() != QP_TEST_RESULT_PASS)
254             return STOP;
255         else
256             return CONTINUE;
257     }
258 
259 private:
260     DepthRangeParams m_depthRange;
261     DepthRangeEvaluator m_evaluator;
262     int m_iterNdx;
263 };
264 
265 class FragCoordXYZCase : public TestCase
266 {
267 public:
FragCoordXYZCase(Context & context)268     FragCoordXYZCase(Context &context) : TestCase(context, "fragcoord_xyz", "gl_FragCoord.xyz Test")
269     {
270     }
271 
iterate(void)272     IterateResult iterate(void)
273     {
274         TestLog &log             = m_testCtx.getLog();
275         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
276         const int width          = m_context.getRenderTarget().getWidth();
277         const int height         = m_context.getRenderTarget().getHeight();
278         const tcu::RGBA threshold =
279             tcu::RGBA(1, 1, 1, 1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold();
280         const tcu::Vec3 scale(1.f / float(width), 1.f / float(height), 1.0f);
281 
282         tcu::Surface testImg(width, height);
283         tcu::Surface refImg(width, height);
284 
285         const glu::ShaderProgram program(
286             m_context.getRenderContext(),
287             glu::makeVtxFragSources("attribute highp vec4 a_position;\n"
288                                     "void main (void)\n"
289                                     "{\n"
290                                     "    gl_Position = a_position;\n"
291                                     "}\n",
292 
293                                     "uniform mediump vec3 u_scale;\n"
294                                     "void main (void)\n"
295                                     "{\n"
296                                     "    gl_FragColor = vec4(gl_FragCoord.xyz*u_scale, 1.0);\n"
297                                     "}\n"));
298 
299         log << program;
300 
301         if (!program.isOk())
302             throw tcu::TestError("Compile failed");
303 
304         // Draw with GL.
305         {
306             const float positions[]  = {-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f,
307                                         1.0f,  1.0f, 0.0f,  1.0f, 1.0f,  -1.0f, 1.0f, 1.0f};
308             const uint16_t indices[] = {0, 1, 2, 2, 1, 3};
309 
310             const int scaleLoc                 = gl.getUniformLocation(program.getProgram(), "u_scale");
311             glu::VertexArrayBinding posBinding = glu::va::Float("a_position", 4, 4, 0, &positions[0]);
312 
313             gl.useProgram(program.getProgram());
314             gl.uniform3fv(scaleLoc, 1, scale.getPtr());
315 
316             glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
317                       glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
318 
319             glu::readPixels(m_context.getRenderContext(), 0, 0, testImg.getAccess());
320             GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
321         }
322 
323         // Draw reference
324         for (int y = 0; y < refImg.getHeight(); y++)
325         {
326             for (int x = 0; x < refImg.getWidth(); x++)
327             {
328                 const float xf = (float(x) + .5f) / float(refImg.getWidth());
329                 const float yf = (float(refImg.getHeight() - y - 1) + .5f) / float(refImg.getHeight());
330                 const float z  = (xf + yf) / 2.0f;
331                 const tcu::Vec3 fragCoord(float(x) + .5f, float(y) + .5f, z);
332                 const tcu::Vec3 scaledFC = fragCoord * scale;
333                 const tcu::Vec4 color(scaledFC.x(), scaledFC.y(), scaledFC.z(), 1.0f);
334 
335                 refImg.setPixel(x, y, tcu::RGBA(color));
336             }
337         }
338 
339         // Compare
340         {
341             bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold,
342                                                    tcu::COMPARE_LOG_RESULT);
343             m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
344                                     isOk ? "Pass" : "Image comparison failed");
345         }
346 
347         return STOP;
348     }
349 };
350 
projectedTriInterpolate(const tcu::Vec3 & s,const tcu::Vec3 & w,float nx,float ny)351 static inline float projectedTriInterpolate(const tcu::Vec3 &s, const tcu::Vec3 &w, float nx, float ny)
352 {
353     return (s[0] * (1.0f - nx - ny) / w[0] + s[1] * ny / w[1] + s[2] * nx / w[2]) /
354            ((1.0f - nx - ny) / w[0] + ny / w[1] + nx / w[2]);
355 }
356 
357 class FragCoordWCase : public TestCase
358 {
359 public:
FragCoordWCase(Context & context)360     FragCoordWCase(Context &context) : TestCase(context, "fragcoord_w", "gl_FragCoord.w Test")
361     {
362     }
363 
iterate(void)364     IterateResult iterate(void)
365     {
366         TestLog &log             = m_testCtx.getLog();
367         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
368         const int width          = m_context.getRenderTarget().getWidth();
369         const int height         = m_context.getRenderTarget().getHeight();
370         const tcu::RGBA threshold =
371             tcu::RGBA(1, 1, 1, 1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold();
372 
373         tcu::Surface testImg(width, height);
374         tcu::Surface refImg(width, height);
375 
376         const float w[4] = {1.7f, 2.0f, 1.2f, 1.0f};
377 
378         const glu::ShaderProgram program(
379             m_context.getRenderContext(),
380             glu::makeVtxFragSources("attribute highp vec4 a_position;\n"
381                                     "void main (void)\n"
382                                     "{\n"
383                                     "    gl_Position = a_position;\n"
384                                     "}\n",
385 
386                                     "void main (void)\n"
387                                     "{\n"
388                                     "    gl_FragColor = vec4(0.0, 1.0/gl_FragCoord.w - 1.0, 0.0, 1.0);\n"
389                                     "}\n"));
390 
391         log << program;
392 
393         if (!program.isOk())
394             throw tcu::TestError("Compile failed");
395 
396         // Draw with GL.
397         {
398             const float positions[]  = {-w[0], w[0], 0.0f, w[0], -w[1], -w[1], 0.0f, w[1],
399                                         w[2],  w[2], 0.0f, w[2], w[3],  -w[3], 0.0f, w[3]};
400             const uint16_t indices[] = {0, 1, 2, 2, 1, 3};
401 
402             glu::VertexArrayBinding posBinding = glu::va::Float("a_position", 4, 4, 0, &positions[0]);
403 
404             gl.useProgram(program.getProgram());
405 
406             glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
407                       glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
408 
409             glu::readPixels(m_context.getRenderContext(), 0, 0, testImg.getAccess());
410             GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
411         }
412 
413         // Draw reference
414         for (int y = 0; y < refImg.getHeight(); y++)
415         {
416             for (int x = 0; x < refImg.getWidth(); x++)
417             {
418                 const float xf = (float(x) + .5f) / float(refImg.getWidth());
419                 const float yf = (float(refImg.getHeight() - y - 1) + .5f) / float(refImg.getHeight());
420                 const float oow =
421                     ((xf + yf) < 1.0f) ?
422                         projectedTriInterpolate(tcu::Vec3(w[0], w[1], w[2]), tcu::Vec3(w[0], w[1], w[2]), xf, yf) :
423                         projectedTriInterpolate(tcu::Vec3(w[3], w[2], w[1]), tcu::Vec3(w[3], w[2], w[1]), 1.0f - xf,
424                                                 1.0f - yf);
425                 const tcu::Vec4 color(0.0f, oow - 1.0f, 0.0f, 1.0f);
426 
427                 refImg.setPixel(x, y, tcu::RGBA(color));
428             }
429         }
430 
431         // Compare
432         {
433             bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold,
434                                                    tcu::COMPARE_LOG_RESULT);
435             m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
436                                     isOk ? "Pass" : "Image comparison failed");
437         }
438 
439         return STOP;
440     }
441 };
442 
443 class PointCoordCase : public TestCase
444 {
445 public:
PointCoordCase(Context & context)446     PointCoordCase(Context &context) : TestCase(context, "pointcoord", "gl_PointCoord Test")
447     {
448     }
449 
iterate(void)450     IterateResult iterate(void)
451     {
452         TestLog &log             = m_testCtx.getLog();
453         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
454         const int width          = de::min(256, m_context.getRenderTarget().getWidth());
455         const int height         = de::min(256, m_context.getRenderTarget().getHeight());
456         const float threshold    = 0.02f;
457 
458         const int numPoints = 8;
459 
460         vector<tcu::Vec3> coords(numPoints);
461         float pointSizeRange[2] = {0.0f, 0.0f};
462 
463         de::Random rnd(0x145fa);
464         tcu::Surface testImg(width, height);
465         tcu::Surface refImg(width, height);
466 
467         gl.getFloatv(GL_ALIASED_POINT_SIZE_RANGE, &pointSizeRange[0]);
468         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE)");
469 
470         if (pointSizeRange[0] <= 0.0f || pointSizeRange[1] <= 0.0f || pointSizeRange[1] < pointSizeRange[0])
471             throw tcu::TestError("Invalid GL_ALIASED_POINT_SIZE_RANGE");
472 
473         // Compute coordinates.
474         {
475 
476             for (vector<tcu::Vec3>::iterator coord = coords.begin(); coord != coords.end(); ++coord)
477             {
478                 coord->x() = rnd.getFloat(-0.9f, 0.9f);
479                 coord->y() = rnd.getFloat(-0.9f, 0.9f);
480                 coord->z() = rnd.getFloat(pointSizeRange[0], pointSizeRange[1]);
481             }
482         }
483 
484         const glu::ShaderProgram program(
485             m_context.getRenderContext(),
486             glu::makeVtxFragSources("attribute highp vec3 a_positionSize;\n"
487                                     "void main (void)\n"
488                                     "{\n"
489                                     "    gl_Position = vec4(a_positionSize.xy, 0.0, 1.0);\n"
490                                     "    gl_PointSize = a_positionSize.z;\n"
491                                     "}\n",
492 
493                                     "void main (void)\n"
494                                     "{\n"
495                                     "    gl_FragColor = vec4(gl_PointCoord, 0.0, 1.0);\n"
496                                     "}\n"));
497 
498         log << program;
499 
500         if (!program.isOk())
501             throw tcu::TestError("Compile failed");
502 
503         // Draw with GL.
504         {
505             glu::VertexArrayBinding posBinding =
506                 glu::va::Float("a_positionSize", 3, (int)coords.size(), 0, (const float *)&coords[0]);
507             const int viewportX = rnd.getInt(0, m_context.getRenderTarget().getWidth() - width);
508             const int viewportY = rnd.getInt(0, m_context.getRenderTarget().getHeight() - height);
509 
510             gl.viewport(viewportX, viewportY, width, height);
511             gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
512             gl.clear(GL_COLOR_BUFFER_BIT);
513 
514             gl.useProgram(program.getProgram());
515 
516             glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
517                       glu::pr::Points((int)coords.size()));
518 
519             glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
520             GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
521         }
522 
523         // Draw reference
524         tcu::clear(refImg.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
525         for (vector<tcu::Vec3>::const_iterator pointIter = coords.begin(); pointIter != coords.end(); ++pointIter)
526         {
527             const int x0 = deRoundFloatToInt32(float(width) * (pointIter->x() * 0.5f + 0.5f) - pointIter->z() * 0.5f);
528             const int y0 = deRoundFloatToInt32(float(height) * (pointIter->y() * 0.5f + 0.5f) - pointIter->z() * 0.5f);
529             const int x1 = deRoundFloatToInt32(float(width) * (pointIter->x() * 0.5f + 0.5f) + pointIter->z() * 0.5f);
530             const int y1 = deRoundFloatToInt32(float(height) * (pointIter->y() * 0.5f + 0.5f) + pointIter->z() * 0.5f);
531             const int w  = x1 - x0;
532             const int h  = y1 - y0;
533 
534             for (int yo = 0; yo < h; yo++)
535             {
536                 for (int xo = 0; xo < w; xo++)
537                 {
538                     const float xf = (float(xo) + 0.5f) / float(w);
539                     const float yf = (float(h - yo - 1) + 0.5f) / float(h);
540                     const tcu::Vec4 color(xf, yf, 0.0f, 1.0f);
541                     const int dx = x0 + xo;
542                     const int dy = y0 + yo;
543 
544                     if (de::inBounds(dx, 0, refImg.getWidth()) && de::inBounds(dy, 0, refImg.getHeight()))
545                         refImg.setPixel(dx, dy, tcu::RGBA(color));
546                 }
547             }
548         }
549 
550         // Compare
551         {
552             bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", refImg, testImg, threshold,
553                                           tcu::COMPARE_LOG_RESULT);
554             m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
555                                     isOk ? "Pass" : "Image comparison failed");
556         }
557 
558         return STOP;
559     }
560 };
561 
562 class FrontFacingCase : public TestCase
563 {
564 public:
FrontFacingCase(Context & context)565     FrontFacingCase(Context &context) : TestCase(context, "frontfacing", "gl_FrontFacing Test")
566     {
567     }
568 
iterate(void)569     IterateResult iterate(void)
570     {
571         // Test case renders two adjecent quads, where left is has front-facing
572         // triagles and right back-facing. Color is selected based on gl_FrontFacing
573         // value.
574 
575         TestLog &log             = m_testCtx.getLog();
576         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
577         de::Random rnd(0x89f2c);
578         const int width     = de::min(64, m_context.getRenderTarget().getWidth());
579         const int height    = de::min(64, m_context.getRenderTarget().getHeight());
580         const int viewportX = rnd.getInt(0, m_context.getRenderTarget().getWidth() - width);
581         const int viewportY = rnd.getInt(0, m_context.getRenderTarget().getHeight() - height);
582         const tcu::RGBA threshold =
583             tcu::RGBA(1, 1, 1, 1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold();
584 
585         tcu::Surface testImg(width, height);
586         tcu::Surface refImg(width, height);
587 
588         const glu::ShaderProgram program(m_context.getRenderContext(),
589                                          glu::makeVtxFragSources("attribute highp vec4 a_position;\n"
590                                                                  "void main (void)\n"
591                                                                  "{\n"
592                                                                  "    gl_Position = a_position;\n"
593                                                                  "}\n",
594 
595                                                                  "void main (void)\n"
596                                                                  "{\n"
597                                                                  "    if (gl_FrontFacing)\n"
598                                                                  "        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
599                                                                  "    else\n"
600                                                                  "        gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
601                                                                  "}\n"));
602 
603         log << program;
604 
605         if (!program.isOk())
606             throw tcu::TestError("Compile failed");
607 
608         // Draw with GL.
609         {
610             const float positions[]     = {-1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f,
611                                            1.0f,  1.0f, 0.0f, 1.0f, 1.0f,  -1.0f, 0.0f, 1.0f};
612             const uint16_t indicesCCW[] = {0, 1, 2, 2, 1, 3};
613             const uint16_t indicesCW[]  = {2, 1, 0, 3, 1, 2};
614 
615             glu::VertexArrayBinding posBinding = glu::va::Float("a_position", 4, 4, 0, &positions[0]);
616 
617             gl.useProgram(program.getProgram());
618 
619             gl.frontFace(GL_CCW);
620 
621             gl.viewport(viewportX, viewportY, width / 2, height / 2);
622             glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
623                       glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCCW), &indicesCCW[0]));
624 
625             gl.viewport(viewportX + width / 2, viewportY, width - width / 2, height / 2);
626             glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
627                       glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCW), &indicesCW[0]));
628 
629             gl.frontFace(GL_CW);
630 
631             gl.viewport(viewportX, viewportY + height / 2, width / 2, height - height / 2);
632             glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
633                       glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCCW), &indicesCCW[0]));
634 
635             gl.viewport(viewportX + width / 2, viewportY + height / 2, width - width / 2, height - height / 2);
636             glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
637                       glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCW), &indicesCW[0]));
638 
639             glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
640             GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
641         }
642 
643         // Draw reference
644         {
645             for (int y = 0; y < refImg.getHeight() / 2; y++)
646                 for (int x = 0; x < refImg.getWidth() / 2; x++)
647                     refImg.setPixel(x, y, tcu::RGBA::green());
648 
649             for (int y = 0; y < refImg.getHeight() / 2; y++)
650                 for (int x = refImg.getWidth() / 2; x < refImg.getWidth(); x++)
651                     refImg.setPixel(x, y, tcu::RGBA::blue());
652 
653             for (int y = refImg.getHeight() / 2; y < refImg.getHeight(); y++)
654                 for (int x = 0; x < refImg.getWidth() / 2; x++)
655                     refImg.setPixel(x, y, tcu::RGBA::blue());
656 
657             for (int y = refImg.getHeight() / 2; y < refImg.getHeight(); y++)
658                 for (int x = refImg.getWidth() / 2; x < refImg.getWidth(); x++)
659                     refImg.setPixel(x, y, tcu::RGBA::green());
660         }
661 
662         // Compare
663         {
664             bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold,
665                                                    tcu::COMPARE_LOG_RESULT);
666             m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
667                                     isOk ? "Pass" : "Image comparison failed");
668         }
669 
670         return STOP;
671     }
672 };
673 
ShaderBuiltinVarTests(Context & context)674 ShaderBuiltinVarTests::ShaderBuiltinVarTests(Context &context)
675     : TestCaseGroup(context, "builtin_variable", "Built-in Variable Tests")
676 {
677 }
678 
~ShaderBuiltinVarTests(void)679 ShaderBuiltinVarTests::~ShaderBuiltinVarTests(void)
680 {
681 }
682 
init(void)683 void ShaderBuiltinVarTests::init(void)
684 {
685     // Builtin constants.
686 
687     static const struct
688     {
689         const char *caseName;
690         const char *varName;
691         uint32_t paramName;
692     } builtinConstants[] = {
693         {"max_vertex_attribs", "gl_MaxVertexAttribs", GL_MAX_VERTEX_ATTRIBS},
694         {"max_vertex_uniform_vectors", "gl_MaxVertexUniformVectors", GL_MAX_VERTEX_UNIFORM_VECTORS},
695         {"max_fragment_uniform_vectors", "gl_MaxFragmentUniformVectors", GL_MAX_FRAGMENT_UNIFORM_VECTORS},
696         {"max_varying_vectors", "gl_MaxVaryingVectors", GL_MAX_VARYING_VECTORS},
697         {"max_texture_image_units", "gl_MaxTextureImageUnits", GL_MAX_TEXTURE_IMAGE_UNITS},
698         {"max_vertex_texture_image_units", "gl_MaxVertexTextureImageUnits", GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS},
699         {"max_combined_texture_image_units", "gl_MaxCombinedTextureImageUnits", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS},
700         {"max_draw_buffers", "gl_MaxDrawBuffers", GL_NONE}};
701 
702     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtinConstants); ndx++)
703     {
704         const char *caseName = builtinConstants[ndx].caseName;
705         const char *varName  = builtinConstants[ndx].varName;
706         uint32_t paramName   = builtinConstants[ndx].paramName;
707 
708         addChild(new ShaderBuiltinConstantCase(m_context, (string(caseName) + "_vertex").c_str(), varName, varName,
709                                                paramName, true));
710         addChild(new ShaderBuiltinConstantCase(m_context, (string(caseName) + "_fragment").c_str(), varName, varName,
711                                                paramName, false));
712     }
713 
714     addChild(new ShaderDepthRangeTest(m_context, "depth_range_vertex", "gl_DepthRange", true));
715     addChild(new ShaderDepthRangeTest(m_context, "depth_range_fragment", "gl_DepthRange", false));
716 
717     // Fragment shader builtin variables.
718 
719     addChild(new FragCoordXYZCase(m_context));
720     addChild(new FragCoordWCase(m_context));
721     addChild(new PointCoordCase(m_context));
722     addChild(new FrontFacingCase(m_context));
723 }
724 
725 } // namespace Functional
726 } // namespace gles2
727 } // namespace deqp
728