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