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