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 ¶ms) : 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