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