1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.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 "es3fShaderBuiltinVarTests.hpp"
25 #include "glsShaderRenderCase.hpp"
26 #include "glsShaderExecUtil.hpp"
27 #include "deRandom.hpp"
28 #include "deString.h"
29 #include "deMath.h"
30 #include "deUniquePtr.hpp"
31 #include "deStringUtil.hpp"
32 #include "tcuTestLog.hpp"
33 #include "tcuTestCase.hpp"
34 #include "tcuTextureUtil.hpp"
35 #include "tcuRenderTarget.hpp"
36 #include "tcuImageCompare.hpp"
37 #include "gluPixelTransfer.hpp"
38 #include "gluDrawUtil.hpp"
39 #include "gluStrUtil.hpp"
40 #include "rrRenderer.hpp"
41 #include "rrFragmentOperations.hpp"
42
43 #include "glwEnums.hpp"
44 #include "glwFunctions.hpp"
45
46 using std::string;
47 using std::vector;
48 using tcu::TestLog;
49
50 namespace deqp
51 {
52 namespace gles3
53 {
54 namespace Functional
55 {
56
getInteger(const glw::Functions & gl,deUint32 pname)57 static int getInteger (const glw::Functions& gl, deUint32 pname)
58 {
59 int value = -1;
60 gl.getIntegerv(pname, &value);
61 GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegerv(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str());
62 return value;
63 }
64
65 template<deUint32 Pname>
getInteger(const glw::Functions & gl)66 static int getInteger (const glw::Functions& gl)
67 {
68 return getInteger(gl, Pname);
69 }
70
getVectorsFromComps(const glw::Functions & gl,deUint32 pname)71 static int getVectorsFromComps (const glw::Functions& gl, deUint32 pname)
72 {
73 int value = -1;
74 gl.getIntegerv(pname, &value);
75 GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegerv(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str());
76 // Accept truncated division. According to the spec, the number of vectors is number of components divided by four, plain and simple.
77 return value/4;
78 }
79
80 template<deUint32 Pname>
getVectorsFromComps(const glw::Functions & gl)81 static int getVectorsFromComps (const glw::Functions& gl)
82 {
83 return getVectorsFromComps(gl, Pname);
84 }
85
86 class ShaderBuiltinConstantCase : public TestCase
87 {
88 public:
89 typedef int (*GetConstantValueFunc) (const glw::Functions& gl);
90
91 ShaderBuiltinConstantCase (Context& context, const char* name, const char* desc, const char* varName, GetConstantValueFunc getValue, glu::ShaderType shaderType);
92 ~ShaderBuiltinConstantCase (void);
93
94 IterateResult iterate (void);
95
96 private:
97 const std::string m_varName;
98 const GetConstantValueFunc m_getValue;
99 const glu::ShaderType m_shaderType;
100 };
101
ShaderBuiltinConstantCase(Context & context,const char * name,const char * desc,const char * varName,GetConstantValueFunc getValue,glu::ShaderType shaderType)102 ShaderBuiltinConstantCase::ShaderBuiltinConstantCase (Context& context, const char* name, const char* desc, const char* varName, GetConstantValueFunc getValue, glu::ShaderType shaderType)
103 : TestCase (context, name, desc)
104 , m_varName (varName)
105 , m_getValue (getValue)
106 , m_shaderType (shaderType)
107 {
108 }
109
~ShaderBuiltinConstantCase(void)110 ShaderBuiltinConstantCase::~ShaderBuiltinConstantCase (void)
111 {
112 }
113
createGetConstantExecutor(const glu::RenderContext & renderCtx,glu::ShaderType shaderType,const std::string & varName)114 static gls::ShaderExecUtil::ShaderExecutor* createGetConstantExecutor (const glu::RenderContext& renderCtx, glu::ShaderType shaderType, const std::string& varName)
115 {
116 using namespace gls::ShaderExecUtil;
117
118 ShaderSpec shaderSpec;
119
120 shaderSpec.version = glu::GLSL_VERSION_300_ES;
121 shaderSpec.source = string("result = ") + varName + ";\n";
122 shaderSpec.outputs.push_back(Symbol("result", glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP)));
123
124 return createExecutor(renderCtx, shaderType, shaderSpec);
125 }
126
iterate(void)127 ShaderBuiltinConstantCase::IterateResult ShaderBuiltinConstantCase::iterate (void)
128 {
129 using namespace gls::ShaderExecUtil;
130
131 const de::UniquePtr<ShaderExecutor> shaderExecutor (createGetConstantExecutor(m_context.getRenderContext(), m_shaderType, m_varName));
132 const int reference = m_getValue(m_context.getRenderContext().getFunctions());
133 int result = -1;
134 void* const outputs = &result;
135
136 if (!shaderExecutor->isOk())
137 {
138 shaderExecutor->log(m_testCtx.getLog());
139 TCU_FAIL("Compile failed");
140 }
141
142 shaderExecutor->useProgram();
143 shaderExecutor->execute(1, DE_NULL, &outputs);
144
145 m_testCtx.getLog() << TestLog::Integer(m_varName, m_varName, "", QP_KEY_TAG_NONE, result);
146
147 if (result != reference)
148 {
149 m_testCtx.getLog() << TestLog::Message << "ERROR: Expected " << m_varName << " = " << reference << TestLog::EndMessage
150 << TestLog::Message << "Test shader:" << TestLog::EndMessage;
151 shaderExecutor->log(m_testCtx.getLog());
152 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid builtin constant value");
153 }
154 else
155 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
156
157 return STOP;
158 }
159
160 namespace
161 {
162
163 struct DepthRangeParams
164 {
DepthRangeParamsdeqp::gles3::Functional::__anon1eeffb4d0111::DepthRangeParams165 DepthRangeParams (void)
166 : zNear (0.0f)
167 , zFar (1.0f)
168 {
169 }
170
DepthRangeParamsdeqp::gles3::Functional::__anon1eeffb4d0111::DepthRangeParams171 DepthRangeParams (float zNear_, float zFar_)
172 : zNear (zNear_)
173 , zFar (zFar_)
174 {
175 }
176
177 float zNear;
178 float zFar;
179 };
180
181 class DepthRangeEvaluator : public gls::ShaderEvaluator
182 {
183 public:
DepthRangeEvaluator(const DepthRangeParams & params)184 DepthRangeEvaluator (const DepthRangeParams& params)
185 : m_params(params)
186 {
187 }
188
evaluate(gls::ShaderEvalContext & c)189 void evaluate (gls::ShaderEvalContext& c)
190 {
191 float zNear = deFloatClamp(m_params.zNear, 0.0f, 1.0f);
192 float zFar = deFloatClamp(m_params.zFar, 0.0f, 1.0f);
193 float diff = zFar - zNear;
194 c.color.xyz() = tcu::Vec3(zNear, zFar, diff*0.5f + 0.5f);
195 }
196
197 private:
198 const DepthRangeParams& m_params;
199 };
200
201 } // anonymous
202
203 class ShaderDepthRangeTest : public gls::ShaderRenderCase
204 {
205 public:
ShaderDepthRangeTest(Context & context,const char * name,const char * desc,bool isVertexCase)206 ShaderDepthRangeTest (Context& context, const char* name, const char* desc, bool isVertexCase)
207 : ShaderRenderCase (context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc, isVertexCase, m_evaluator)
208 , m_evaluator (m_depthRange)
209 , m_iterNdx (0)
210 {
211 }
212
init(void)213 void init (void)
214 {
215 static const char* defaultVertSrc =
216 "#version 300 es\n"
217 "in highp vec4 a_position;\n"
218 "void main (void)\n"
219 "{\n"
220 " gl_Position = a_position;\n"
221 "}\n";
222 static const char* defaultFragSrc =
223 "#version 300 es\n"
224 "in mediump vec4 v_color;\n"
225 "layout(location = 0) out mediump vec4 o_color;\n\n"
226 "void main (void)\n"
227 "{\n"
228 " o_color = v_color;\n"
229 "}\n";
230
231 // Construct shader.
232 std::ostringstream src;
233 src << "#version 300 es\n";
234 if (m_isVertexCase)
235 src << "in highp vec4 a_position;\n"
236 << "out mediump vec4 v_color;\n";
237 else
238 src << "layout(location = 0) out mediump vec4 o_color;\n";
239
240 src << "void main (void)\n{\n";
241 src << "\t" << (m_isVertexCase ? "v_color" : "o_color") << " = vec4(gl_DepthRange.near, gl_DepthRange.far, gl_DepthRange.diff*0.5 + 0.5, 1.0);\n";
242
243 if (m_isVertexCase)
244 src << "\tgl_Position = a_position;\n";
245
246 src << "}\n";
247
248 m_vertShaderSource = m_isVertexCase ? src.str() : defaultVertSrc;
249 m_fragShaderSource = m_isVertexCase ? defaultFragSrc : src.str();
250
251 gls::ShaderRenderCase::init();
252 }
253
iterate(void)254 IterateResult iterate (void)
255 {
256 const glw::Functions& gl = m_renderCtx.getFunctions();
257
258 const DepthRangeParams cases[] =
259 {
260 DepthRangeParams(0.0f, 1.0f),
261 DepthRangeParams(1.5f, -1.0f),
262 DepthRangeParams(0.7f, 0.3f)
263 };
264
265 m_depthRange = cases[m_iterNdx];
266 m_testCtx.getLog() << tcu::TestLog::Message << "glDepthRangef(" << m_depthRange.zNear << ", " << m_depthRange.zFar << ")" << tcu::TestLog::EndMessage;
267 gl.depthRangef(m_depthRange.zNear, m_depthRange.zFar);
268 GLU_EXPECT_NO_ERROR(gl.getError(), "glDepthRangef()");
269
270 gls::ShaderRenderCase::iterate();
271 m_iterNdx += 1;
272
273 if (m_iterNdx == DE_LENGTH_OF_ARRAY(cases) || m_testCtx.getTestResult() != QP_TEST_RESULT_PASS)
274 return STOP;
275 else
276 return CONTINUE;
277 }
278
279 private:
280 DepthRangeParams m_depthRange;
281 DepthRangeEvaluator m_evaluator;
282 int m_iterNdx;
283 };
284
285 class FragCoordXYZCase : public TestCase
286 {
287 public:
FragCoordXYZCase(Context & context)288 FragCoordXYZCase (Context& context)
289 : TestCase(context, "fragcoord_xyz", "gl_FragCoord.xyz Test")
290 {
291 }
292
iterate(void)293 IterateResult iterate (void)
294 {
295 TestLog& log = m_testCtx.getLog();
296 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
297 const int width = m_context.getRenderTarget().getWidth();
298 const int height = m_context.getRenderTarget().getHeight();
299 const tcu::RGBA threshold = tcu::RGBA(1,1,1,1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold();
300 const tcu::Vec3 scale (1.f / float(width), 1.f / float(height), 1.0f);
301
302 tcu::Surface testImg (width, height);
303 tcu::Surface refImg (width, height);
304
305 const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(
306 "#version 300 es\n"
307 "in highp vec4 a_position;\n"
308 "void main (void)\n"
309 "{\n"
310 " gl_Position = a_position;\n"
311 "}\n",
312
313 "#version 300 es\n"
314 "uniform highp vec3 u_scale;\n"
315 "layout(location = 0) out mediump vec4 o_color;\n"
316 "void main (void)\n"
317 "{\n"
318 " o_color = vec4(gl_FragCoord.xyz*u_scale, 1.0);\n"
319 "}\n"));
320
321 log << program;
322
323 if (!program.isOk())
324 throw tcu::TestError("Compile failed");
325
326 // Draw with GL.
327 {
328 const float positions[] =
329 {
330 -1.0f, 1.0f, -1.0f, 1.0f,
331 -1.0f, -1.0f, 0.0f, 1.0f,
332 1.0f, 1.0f, 0.0f, 1.0f,
333 1.0f, -1.0f, 1.0f, 1.0f
334 };
335 const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
336
337 const int scaleLoc = gl.getUniformLocation(program.getProgram(), "u_scale");
338 glu::VertexArrayBinding posBinding = glu::va::Float("a_position", 4, 4, 0, &positions[0]);
339
340 gl.useProgram(program.getProgram());
341 gl.uniform3fv(scaleLoc, 1, scale.getPtr());
342
343 glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
344 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
345
346 glu::readPixels(m_context.getRenderContext(), 0, 0, testImg.getAccess());
347 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
348 }
349
350 // Draw reference
351 for (int y = 0; y < refImg.getHeight(); y++)
352 {
353 for (int x = 0; x < refImg.getWidth(); x++)
354 {
355 const float xf = (float(x)+.5f) / float(refImg.getWidth());
356 const float yf = (float(refImg.getHeight()-y-1)+.5f) / float(refImg.getHeight());
357 const float z = (xf + yf) / 2.0f;
358 const tcu::Vec3 fragCoord (float(x)+.5f, float(y)+.5f, z);
359 const tcu::Vec3 scaledFC = fragCoord*scale;
360 const tcu::Vec4 color (scaledFC.x(), scaledFC.y(), scaledFC.z(), 1.0f);
361
362 refImg.setPixel(x, y, tcu::RGBA(color));
363 }
364 }
365
366 // Compare
367 {
368 bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT);
369 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
370 isOk ? "Pass" : "Image comparison failed");
371 }
372
373 return STOP;
374 }
375 };
376
projectedTriInterpolate(const tcu::Vec3 & s,const tcu::Vec3 & w,float nx,float ny)377 static inline float projectedTriInterpolate (const tcu::Vec3& s, const tcu::Vec3& w, float nx, float ny)
378 {
379 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]);
380 }
381
382 class FragCoordWCase : public TestCase
383 {
384 public:
FragCoordWCase(Context & context)385 FragCoordWCase (Context& context)
386 : TestCase(context, "fragcoord_w", "gl_FragCoord.w Test")
387 {
388 }
389
iterate(void)390 IterateResult iterate (void)
391 {
392 TestLog& log = m_testCtx.getLog();
393 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
394 const int width = m_context.getRenderTarget().getWidth();
395 const int height = m_context.getRenderTarget().getHeight();
396 const tcu::RGBA threshold = tcu::RGBA(1,1,1,1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold();
397
398 tcu::Surface testImg (width, height);
399 tcu::Surface refImg (width, height);
400
401 const float w[4] = { 1.7f, 2.0f, 1.2f, 1.0f };
402
403 const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(
404 "#version 300 es\n"
405 "in highp vec4 a_position;\n"
406 "void main (void)\n"
407 "{\n"
408 " gl_Position = a_position;\n"
409 "}\n",
410
411 "#version 300 es\n"
412 "layout(location = 0) out mediump vec4 o_color;\n"
413 "void main (void)\n"
414 "{\n"
415 " o_color = vec4(0.0, 1.0/gl_FragCoord.w - 1.0, 0.0, 1.0);\n"
416 "}\n"));
417
418 log << program;
419
420 if (!program.isOk())
421 throw tcu::TestError("Compile failed");
422
423 // Draw with GL.
424 {
425 const float positions[] =
426 {
427 -w[0], w[0], 0.0f, w[0],
428 -w[1], -w[1], 0.0f, w[1],
429 w[2], w[2], 0.0f, w[2],
430 w[3], -w[3], 0.0f, w[3]
431 };
432 const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
433
434 glu::VertexArrayBinding posBinding = glu::va::Float("a_position", 4, 4, 0, &positions[0]);
435
436 gl.useProgram(program.getProgram());
437
438 glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
439 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
440
441 glu::readPixels(m_context.getRenderContext(), 0, 0, testImg.getAccess());
442 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
443 }
444
445 // Draw reference
446 for (int y = 0; y < refImg.getHeight(); y++)
447 {
448 for (int x = 0; x < refImg.getWidth(); x++)
449 {
450 const float xf = (float(x)+.5f) / float(refImg.getWidth());
451 const float yf = (float(refImg.getHeight()-y-1)+.5f) / float(refImg.getHeight());
452 const float oow = ((xf + yf) < 1.0f)
453 ? projectedTriInterpolate(tcu::Vec3(w[0], w[1], w[2]), tcu::Vec3(w[0], w[1], w[2]), xf, yf)
454 : projectedTriInterpolate(tcu::Vec3(w[3], w[2], w[1]), tcu::Vec3(w[3], w[2], w[1]), 1.0f-xf, 1.0f-yf);
455 const tcu::Vec4 color (0.0f, oow - 1.0f, 0.0f, 1.0f);
456
457 refImg.setPixel(x, y, tcu::RGBA(color));
458 }
459 }
460
461 // Compare
462 {
463 bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT);
464 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
465 isOk ? "Pass" : "Image comparison failed");
466 }
467
468 return STOP;
469 }
470 };
471
472 class PointCoordCase : public TestCase
473 {
474 public:
PointCoordCase(Context & context)475 PointCoordCase (Context& context)
476 : TestCase(context, "pointcoord", "gl_PointCoord Test")
477 {
478 }
479
iterate(void)480 IterateResult iterate (void)
481 {
482 TestLog& log = m_testCtx.getLog();
483 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
484 const int width = de::min(256, m_context.getRenderTarget().getWidth());
485 const int height = de::min(256, m_context.getRenderTarget().getHeight());
486 const float threshold = 0.02f;
487
488 const int numPoints = 8;
489
490 vector<tcu::Vec3> coords (numPoints);
491 float pointSizeRange[2] = { 0.0f, 0.0f };
492
493 de::Random rnd (0x145fa);
494 tcu::Surface testImg (width, height);
495 tcu::Surface refImg (width, height);
496
497 gl.getFloatv(GL_ALIASED_POINT_SIZE_RANGE, &pointSizeRange[0]);
498 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE)");
499
500 if (pointSizeRange[0] <= 0.0f || pointSizeRange[1] <= 0.0f || pointSizeRange[1] < pointSizeRange[0])
501 throw tcu::TestError("Invalid GL_ALIASED_POINT_SIZE_RANGE");
502
503 // Compute coordinates.
504 {
505
506 for (vector<tcu::Vec3>::iterator coord = coords.begin(); coord != coords.end(); ++coord)
507 {
508 coord->x() = rnd.getFloat(-0.9f, 0.9f);
509 coord->y() = rnd.getFloat(-0.9f, 0.9f);
510 coord->z() = rnd.getFloat(pointSizeRange[0], pointSizeRange[1]);
511 }
512 }
513
514 const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(
515 "#version 300 es\n"
516 "in highp vec3 a_positionSize;\n"
517 "void main (void)\n"
518 "{\n"
519 " gl_Position = vec4(a_positionSize.xy, 0.0, 1.0);\n"
520 " gl_PointSize = a_positionSize.z;\n"
521 "}\n",
522
523 "#version 300 es\n"
524 "layout(location = 0) out mediump vec4 o_color;\n"
525 "void main (void)\n"
526 "{\n"
527 " o_color = vec4(gl_PointCoord, 0.0, 1.0);\n"
528 "}\n"));
529
530 log << program;
531
532 if (!program.isOk())
533 throw tcu::TestError("Compile failed");
534
535 // Draw with GL.
536 {
537 glu::VertexArrayBinding posBinding = glu::va::Float("a_positionSize", 3, (int)coords.size(), 0, (const float*)&coords[0]);
538 const int viewportX = rnd.getInt(0, m_context.getRenderTarget().getWidth()-width);
539 const int viewportY = rnd.getInt(0, m_context.getRenderTarget().getHeight()-height);
540
541 gl.viewport(viewportX, viewportY, width, height);
542 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
543 gl.clear(GL_COLOR_BUFFER_BIT);
544
545 gl.useProgram(program.getProgram());
546
547 glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
548 glu::pr::Points((int)coords.size()));
549
550 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
551 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
552 }
553
554 // Draw reference
555 tcu::clear(refImg.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
556 for (vector<tcu::Vec3>::const_iterator pointIter = coords.begin(); pointIter != coords.end(); ++pointIter)
557 {
558 const int x0 = deRoundFloatToInt32(float(width) *(pointIter->x()*0.5f + 0.5f) - pointIter->z()*0.5f);
559 const int y0 = deRoundFloatToInt32(float(height)*(pointIter->y()*0.5f + 0.5f) - pointIter->z()*0.5f);
560 const int x1 = deRoundFloatToInt32(float(width) *(pointIter->x()*0.5f + 0.5f) + pointIter->z()*0.5f);
561 const int y1 = deRoundFloatToInt32(float(height)*(pointIter->y()*0.5f + 0.5f) + pointIter->z()*0.5f);
562 const int w = x1-x0;
563 const int h = y1-y0;
564
565 for (int yo = 0; yo < h; yo++)
566 {
567 for (int xo = 0; xo < w; xo++)
568 {
569 const float xf = (float(xo)+0.5f) / float(w);
570 const float yf = (float(h-yo-1)+0.5f) / float(h);
571 const tcu::Vec4 color (xf, yf, 0.0f, 1.0f);
572 const int dx = x0+xo;
573 const int dy = y0+yo;
574
575 if (de::inBounds(dx, 0, refImg.getWidth()) && de::inBounds(dy, 0, refImg.getHeight()))
576 refImg.setPixel(dx, dy, tcu::RGBA(color));
577 }
578 }
579 }
580
581 // Compare
582 {
583 bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT);
584 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
585 isOk ? "Pass" : "Image comparison failed");
586 }
587
588 return STOP;
589 }
590 };
591
592 class FrontFacingCase : public TestCase
593 {
594 public:
FrontFacingCase(Context & context)595 FrontFacingCase (Context& context)
596 : TestCase(context, "frontfacing", "gl_FrontFacing Test")
597 {
598 }
599
iterate(void)600 IterateResult iterate (void)
601 {
602 // Test case renders two adjecent quads, where left is has front-facing
603 // triagles and right back-facing. Color is selected based on gl_FrontFacing
604 // value.
605
606 TestLog& log = m_testCtx.getLog();
607 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
608 de::Random rnd (0x89f2c);
609 const int width = de::min(64, m_context.getRenderTarget().getWidth());
610 const int height = de::min(64, m_context.getRenderTarget().getHeight());
611 const int viewportX = rnd.getInt(0, m_context.getRenderTarget().getWidth()-width);
612 const int viewportY = rnd.getInt(0, m_context.getRenderTarget().getHeight()-height);
613 const tcu::RGBA threshold = tcu::RGBA(1,1,1,1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold();
614
615 tcu::Surface testImg (width, height);
616 tcu::Surface refImg (width, height);
617
618 const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(
619 "#version 300 es\n"
620 "in highp vec4 a_position;\n"
621 "void main (void)\n"
622 "{\n"
623 " gl_Position = a_position;\n"
624 "}\n",
625
626 "#version 300 es\n"
627 "layout(location = 0) out mediump vec4 o_color;\n"
628 "void main (void)\n"
629 "{\n"
630 " if (gl_FrontFacing)\n"
631 " o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
632 " else\n"
633 " o_color = vec4(0.0, 0.0, 1.0, 1.0);\n"
634 "}\n"));
635
636 log << program;
637
638 if (!program.isOk())
639 throw tcu::TestError("Compile failed");
640
641 // Draw with GL.
642 {
643 const float positions[] =
644 {
645 -1.0f, 1.0f, 0.0f, 1.0f,
646 -1.0f, -1.0f, 0.0f, 1.0f,
647 1.0f, 1.0f, 0.0f, 1.0f,
648 1.0f, -1.0f, 0.0f, 1.0f
649 };
650 const deUint16 indicesCCW[] = { 0, 1, 2, 2, 1, 3 };
651 const deUint16 indicesCW[] = { 2, 1, 0, 3, 1, 2 };
652
653 glu::VertexArrayBinding posBinding = glu::va::Float("a_position", 4, 4, 0, &positions[0]);
654
655 gl.useProgram(program.getProgram());
656
657 gl.frontFace(GL_CCW);
658
659 gl.viewport(viewportX, viewportY, width/2, height/2);
660 glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
661 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCCW), &indicesCCW[0]));
662
663 gl.viewport(viewportX + width/2, viewportY, width-width/2, height/2);
664 glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
665 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCW), &indicesCW[0]));
666
667 gl.frontFace(GL_CW);
668
669 gl.viewport(viewportX, viewportY + height/2, width/2, height-height/2);
670 glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
671 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCCW), &indicesCCW[0]));
672
673 gl.viewport(viewportX + width/2, viewportY + height/2, width-width/2, height-height/2);
674 glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
675 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCW), &indicesCW[0]));
676
677 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
678 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
679 }
680
681 // Draw reference
682 {
683 for(int y = 0; y < refImg.getHeight() / 2; y++)
684 for(int x = 0; x < refImg.getWidth() / 2; x++)
685 refImg.setPixel(x, y, tcu::RGBA::green());
686
687 for(int y = 0; y < refImg.getHeight() / 2; y++)
688 for(int x = refImg.getWidth() / 2; x < refImg.getWidth(); x++)
689 refImg.setPixel(x, y, tcu::RGBA::blue());
690
691 for(int y = refImg.getHeight() / 2; y < refImg.getHeight(); y++)
692 for(int x = 0; x < refImg.getWidth() / 2; x++)
693 refImg.setPixel(x, y, tcu::RGBA::blue());
694
695 for(int y = refImg.getHeight() / 2; y < refImg.getHeight(); y++)
696 for(int x = refImg.getWidth() / 2; x < refImg.getWidth(); x++)
697 refImg.setPixel(x, y, tcu::RGBA::green());
698 }
699
700 // Compare
701 {
702 bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT);
703 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
704 isOk ? "Pass" : "Image comparison failed");
705 }
706
707 return STOP;
708 }
709 };
710
711 // VertexIDCase
712
713 class VertexIDCase : public TestCase
714 {
715 public:
716 VertexIDCase (Context& context);
717 ~VertexIDCase (void);
718
719 void init (void);
720 void deinit (void);
721 IterateResult iterate (void);
722
723 private:
724 enum
725 {
726 MAX_VERTICES = 8*3 //!< 8 triangles, totals 24 vertices
727 };
728
729 void renderReference (const tcu::PixelBufferAccess& dst, const int numVertices, const deUint16* const indices, const tcu::Vec4* const positions, const tcu::Vec4* const colors);
730
731 glu::ShaderProgram* m_program;
732 deUint32 m_positionBuffer;
733 deUint32 m_elementBuffer;
734
735 vector<tcu::Vec4> m_positions;
736 vector<tcu::Vec4> m_colors;
737 int m_viewportW;
738 int m_viewportH;
739
740 int m_iterNdx;
741 };
742
VertexIDCase(Context & context)743 VertexIDCase::VertexIDCase (Context& context)
744 : TestCase (context, "vertex_id", "gl_VertexID Test")
745 , m_program (DE_NULL)
746 , m_positionBuffer (0)
747 , m_elementBuffer (0)
748 , m_viewportW (0)
749 , m_viewportH (0)
750 , m_iterNdx (0)
751 {
752 }
753
~VertexIDCase(void)754 VertexIDCase::~VertexIDCase (void)
755 {
756 VertexIDCase::deinit();
757 }
758
init(void)759 void VertexIDCase::init (void)
760 {
761 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
762 const int width = m_context.getRenderTarget().getWidth();
763 const int height = m_context.getRenderTarget().getHeight();
764
765 const int quadWidth = 32;
766 const int quadHeight = 32;
767
768 if (width < quadWidth)
769 throw tcu::NotSupportedError("Too small render target");
770
771 const int maxQuadsX = width/quadWidth;
772 const int numVertices = MAX_VERTICES;
773
774 const int numQuads = numVertices/6 + (numVertices%6 != 0 ? 1 : 0);
775 const int viewportW = de::min(numQuads, maxQuadsX)*quadWidth;
776 const int viewportH = (numQuads/maxQuadsX + (numQuads%maxQuadsX != 0 ? 1 : 0))*quadHeight;
777
778 if (viewportH > height)
779 throw tcu::NotSupportedError("Too small render target");
780
781 DE_ASSERT(viewportW <= width && viewportH <= height);
782
783 DE_ASSERT(!m_program);
784 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(
785 "#version 300 es\n"
786 "in highp vec4 a_position;\n"
787 "out mediump vec4 v_color;\n"
788 "uniform highp vec4 u_colors[24];\n"
789 "void main (void)\n"
790 "{\n"
791 " gl_Position = a_position;\n"
792 " v_color = u_colors[gl_VertexID];\n"
793 "}\n",
794
795 "#version 300 es\n"
796 "in mediump vec4 v_color;\n"
797 "layout(location = 0) out mediump vec4 o_color;\n"
798 "void main (void)\n"
799 "{\n"
800 " o_color = v_color;\n"
801 "}\n"));
802
803 m_testCtx.getLog() << *m_program;
804
805 if (!m_program->isOk())
806 {
807 delete m_program;
808 m_program = DE_NULL;
809 throw tcu::TestError("Compile failed");
810 }
811
812 gl.genBuffers(1, &m_positionBuffer);
813 gl.genBuffers(1, &m_elementBuffer);
814
815 // Set colors (in dynamic memory to save static data space).
816 m_colors.resize(numVertices);
817 m_colors[ 0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
818 m_colors[ 1] = tcu::Vec4(0.5f, 1.0f, 0.5f, 1.0f);
819 m_colors[ 2] = tcu::Vec4(0.0f, 0.5f, 1.0f, 1.0f);
820 m_colors[ 3] = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
821 m_colors[ 4] = tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f);
822 m_colors[ 5] = tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f);
823 m_colors[ 6] = tcu::Vec4(0.5f, 0.0f, 1.0f, 1.0f);
824 m_colors[ 7] = tcu::Vec4(0.5f, 0.0f, 0.5f, 1.0f);
825 m_colors[ 8] = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
826 m_colors[ 9] = tcu::Vec4(0.5f, 1.0f, 0.0f, 1.0f);
827 m_colors[10] = tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f);
828 m_colors[11] = tcu::Vec4(0.5f, 1.0f, 1.0f, 1.0f);
829 m_colors[12] = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
830 m_colors[13] = tcu::Vec4(1.0f, 0.0f, 0.5f, 1.0f);
831 m_colors[14] = tcu::Vec4(0.0f, 0.5f, 0.5f, 1.0f);
832 m_colors[15] = tcu::Vec4(1.0f, 1.0f, 0.5f, 1.0f);
833 m_colors[16] = tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f);
834 m_colors[17] = tcu::Vec4(1.0f, 0.5f, 0.0f, 1.0f);
835 m_colors[18] = tcu::Vec4(0.0f, 1.0f, 0.5f, 1.0f);
836 m_colors[19] = tcu::Vec4(1.0f, 0.5f, 1.0f, 1.0f);
837 m_colors[20] = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
838 m_colors[21] = tcu::Vec4(1.0f, 0.5f, 0.5f, 1.0f);
839 m_colors[22] = tcu::Vec4(0.0f, 0.0f, 0.5f, 1.0f);
840 m_colors[23] = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
841
842 // Compute positions.
843 m_positions.resize(numVertices);
844 DE_ASSERT(numVertices%3 == 0);
845 for (int vtxNdx = 0; vtxNdx < numVertices; vtxNdx += 3)
846 {
847 const float h = 2.0f * float(quadHeight)/float(viewportH);
848 const float w = 2.0f * float(quadWidth)/float(viewportW);
849
850 const int triNdx = vtxNdx/3;
851 const int quadNdx = triNdx/2;
852 const int quadY = quadNdx/maxQuadsX;
853 const int quadX = quadNdx%maxQuadsX;
854
855 const float x0 = -1.0f + float(quadX)*w;
856 const float y0 = -1.0f + float(quadY)*h;
857
858 if (triNdx%2 == 0)
859 {
860 m_positions[vtxNdx+0] = tcu::Vec4(x0, y0, 0.0f, 1.0f);
861 m_positions[vtxNdx+1] = tcu::Vec4(x0+w, y0+h, 0.0f, 1.0f);
862 m_positions[vtxNdx+2] = tcu::Vec4(x0, y0+h, 0.0f, 1.0f);
863 }
864 else
865 {
866 m_positions[vtxNdx+0] = tcu::Vec4(x0+w, y0+h, 0.0f, 1.0f);
867 m_positions[vtxNdx+1] = tcu::Vec4(x0, y0, 0.0f, 1.0f);
868 m_positions[vtxNdx+2] = tcu::Vec4(x0+w, y0, 0.0f, 1.0f);
869 }
870 }
871
872 m_viewportW = viewportW;
873 m_viewportH = viewportH;
874 m_iterNdx = 0;
875
876 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
877 }
878
deinit(void)879 void VertexIDCase::deinit (void)
880 {
881 delete m_program;
882 m_program = DE_NULL;
883
884 if (m_positionBuffer)
885 {
886 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_positionBuffer);
887 m_positionBuffer = 0;
888 }
889
890 if (m_elementBuffer)
891 {
892 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_elementBuffer);
893 m_elementBuffer = 0;
894 }
895
896 m_positions.clear();
897 m_colors.clear();
898 }
899
900 class VertexIDReferenceShader : public rr::VertexShader, public rr::FragmentShader
901 {
902 public:
903 enum
904 {
905 VARYINGLOC_COLOR = 0
906 };
907
VertexIDReferenceShader()908 VertexIDReferenceShader ()
909 : rr::VertexShader (2, 1) // color and pos in => color out
910 , rr::FragmentShader(1, 1) // color in => color out
911 {
912 this->rr::VertexShader::m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
913 this->rr::VertexShader::m_inputs[1].type = rr::GENERICVECTYPE_FLOAT;
914
915 this->rr::VertexShader::m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
916 this->rr::VertexShader::m_outputs[0].flatshade = false;
917
918 this->rr::FragmentShader::m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
919 this->rr::FragmentShader::m_inputs[0].flatshade = false;
920
921 this->rr::FragmentShader::m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
922 }
923
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const924 void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
925 {
926 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
927 {
928 const int positionAttrLoc = 0;
929 const int colorAttrLoc = 1;
930
931 rr::VertexPacket& packet = *packets[packetNdx];
932
933 // Transform to position
934 packet.position = rr::readVertexAttribFloat(inputs[positionAttrLoc], packet.instanceNdx, packet.vertexNdx);
935
936 // Pass color to FS
937 packet.outputs[VARYINGLOC_COLOR] = rr::readVertexAttribFloat(inputs[colorAttrLoc], packet.instanceNdx, packet.vertexNdx);
938 }
939 }
940
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const941 void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
942 {
943 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
944 {
945 rr::FragmentPacket& packet = packets[packetNdx];
946
947 for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
948 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packet, context, VARYINGLOC_COLOR, fragNdx));
949 }
950 }
951 };
952
renderReference(const tcu::PixelBufferAccess & dst,const int numVertices,const deUint16 * const indices,const tcu::Vec4 * const positions,const tcu::Vec4 * const colors)953 void VertexIDCase::renderReference (const tcu::PixelBufferAccess& dst, const int numVertices, const deUint16* const indices, const tcu::Vec4* const positions, const tcu::Vec4* const colors)
954 {
955 const rr::Renderer referenceRenderer;
956 const rr::RenderState referenceState ((rr::ViewportState)(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(dst)));
957 const rr::RenderTarget referenceTarget (rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(dst));
958 const VertexIDReferenceShader referenceShader;
959 rr::VertexAttrib attribs[2];
960
961 attribs[0].type = rr::VERTEXATTRIBTYPE_FLOAT;
962 attribs[0].size = 4;
963 attribs[0].stride = 0;
964 attribs[0].instanceDivisor = 0;
965 attribs[0].pointer = positions;
966
967 attribs[1].type = rr::VERTEXATTRIBTYPE_FLOAT;
968 attribs[1].size = 4;
969 attribs[1].stride = 0;
970 attribs[1].instanceDivisor = 0;
971 attribs[1].pointer = colors;
972
973 referenceRenderer.draw(
974 rr::DrawCommand(
975 referenceState,
976 referenceTarget,
977 rr::Program(&referenceShader, &referenceShader),
978 2,
979 attribs,
980 rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, numVertices, rr::DrawIndices(indices))));
981 }
982
iterate(void)983 VertexIDCase::IterateResult VertexIDCase::iterate (void)
984 {
985 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
986 const int width = m_context.getRenderTarget().getWidth();
987 const int height = m_context.getRenderTarget().getHeight();
988 const int viewportW = m_viewportW;
989 const int viewportH = m_viewportH;
990
991 const float threshold = 0.02f;
992
993 de::Random rnd (0xcf23ab1 ^ deInt32Hash(m_iterNdx));
994 tcu::Surface refImg (viewportW, viewportH);
995 tcu::Surface testImg (viewportW, viewportH);
996
997 const int viewportX = rnd.getInt(0, width-viewportW);
998 const int viewportY = rnd.getInt(0, height-viewportH);
999
1000 const int posLoc = gl.getAttribLocation(m_program->getProgram(), "a_position");
1001 const int colorsLoc = gl.getUniformLocation(m_program->getProgram(), "u_colors[0]");
1002 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f);
1003
1004 // Setup common state.
1005 gl.viewport (viewportX, viewportY, viewportW, viewportH);
1006 gl.useProgram (m_program->getProgram());
1007 gl.bindBuffer (GL_ARRAY_BUFFER, m_positionBuffer);
1008 gl.enableVertexAttribArray (posLoc);
1009 gl.vertexAttribPointer (posLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1010 gl.uniform4fv (colorsLoc, (int)m_colors.size(), (const float*)&m_colors[0]);
1011
1012 // Clear render target to black.
1013 gl.clearColor (clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
1014 gl.clear (GL_COLOR_BUFFER_BIT);
1015
1016 tcu::clear(refImg.getAccess(), clearColor);
1017
1018 if (m_iterNdx == 0)
1019 {
1020 tcu::ScopedLogSection logSection (m_testCtx.getLog(), "Iter0", "glDrawArrays()");
1021 vector<deUint16> indices (m_positions.size());
1022
1023 gl.bufferData(GL_ARRAY_BUFFER, (int)(m_positions.size()*sizeof(tcu::Vec4)), &m_positions[0], GL_DYNAMIC_DRAW);
1024 gl.drawArrays(GL_TRIANGLES, 0, (int)m_positions.size());
1025
1026 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
1027 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
1028
1029 // Reference indices
1030 for (int ndx = 0; ndx < (int)indices.size(); ndx++)
1031 indices[ndx] = (deUint16)ndx;
1032
1033 renderReference(refImg.getAccess(), (int)m_positions.size(), &indices[0], &m_positions[0], &m_colors[0]);
1034 }
1035 else if (m_iterNdx == 1)
1036 {
1037 tcu::ScopedLogSection logSection (m_testCtx.getLog(), "Iter1", "glDrawElements(), indices in client-side array");
1038 vector<deUint16> indices (m_positions.size());
1039 vector<tcu::Vec4> mappedPos (m_positions.size());
1040
1041 // Compute initial indices and suffle
1042 for (int ndx = 0; ndx < (int)indices.size(); ndx++)
1043 indices[ndx] = (deUint16)ndx;
1044 rnd.shuffle(indices.begin(), indices.end());
1045
1046 // Use indices to re-map positions.
1047 for (int ndx = 0; ndx < (int)indices.size(); ndx++)
1048 mappedPos[indices[ndx]] = m_positions[ndx];
1049
1050 gl.bufferData(GL_ARRAY_BUFFER, (int)(m_positions.size()*sizeof(tcu::Vec4)), &mappedPos[0], GL_DYNAMIC_DRAW);
1051 gl.drawElements(GL_TRIANGLES, (int)indices.size(), GL_UNSIGNED_SHORT, &indices[0]);
1052
1053 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
1054 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
1055
1056 renderReference(refImg.getAccess(), (int)indices.size(), &indices[0], &mappedPos[0], &m_colors[0]);
1057 }
1058 else if (m_iterNdx == 2)
1059 {
1060 tcu::ScopedLogSection logSection (m_testCtx.getLog(), "Iter2", "glDrawElements(), indices in buffer");
1061 vector<deUint16> indices (m_positions.size());
1062 vector<tcu::Vec4> mappedPos (m_positions.size());
1063
1064 // Compute initial indices and suffle
1065 for (int ndx = 0; ndx < (int)indices.size(); ndx++)
1066 indices[ndx] = (deUint16)ndx;
1067 rnd.shuffle(indices.begin(), indices.end());
1068
1069 // Use indices to re-map positions.
1070 for (int ndx = 0; ndx < (int)indices.size(); ndx++)
1071 mappedPos[indices[ndx]] = m_positions[ndx];
1072
1073 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuffer);
1074 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (int)(indices.size()*sizeof(deUint16)), &indices[0], GL_DYNAMIC_DRAW);
1075
1076 gl.bufferData(GL_ARRAY_BUFFER, (int)(m_positions.size()*sizeof(tcu::Vec4)), &mappedPos[0], GL_DYNAMIC_DRAW);
1077 gl.drawElements(GL_TRIANGLES, (int)indices.size(), GL_UNSIGNED_SHORT, DE_NULL);
1078
1079 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
1080 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
1081
1082 tcu::clear(refImg.getAccess(), clearColor);
1083 renderReference(refImg.getAccess(), (int)indices.size(), &indices[0], &mappedPos[0], &m_colors[0]);
1084 }
1085 else
1086 DE_ASSERT(false);
1087
1088 if (!tcu::fuzzyCompare(m_testCtx.getLog(), "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT))
1089 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1090
1091 m_iterNdx += 1;
1092 return (m_iterNdx < 3) ? CONTINUE : STOP;
1093 }
1094
ShaderBuiltinVarTests(Context & context)1095 ShaderBuiltinVarTests::ShaderBuiltinVarTests (Context& context)
1096 : TestCaseGroup(context, "builtin_variable", "Built-in Variable Tests")
1097 {
1098 }
1099
~ShaderBuiltinVarTests(void)1100 ShaderBuiltinVarTests::~ShaderBuiltinVarTests (void)
1101 {
1102 }
1103
init(void)1104 void ShaderBuiltinVarTests::init (void)
1105 {
1106 // Builtin constants.
1107
1108 static const struct
1109 {
1110 const char* caseName;
1111 const char* varName;
1112 ShaderBuiltinConstantCase::GetConstantValueFunc getValue;
1113 } builtinConstants[] =
1114 {
1115 // GLES 2.
1116
1117 { "max_vertex_attribs", "gl_MaxVertexAttribs", getInteger<GL_MAX_VERTEX_ATTRIBS> },
1118 { "max_vertex_uniform_vectors", "gl_MaxVertexUniformVectors", getInteger<GL_MAX_VERTEX_UNIFORM_VECTORS> },
1119 { "max_fragment_uniform_vectors", "gl_MaxFragmentUniformVectors", getInteger<GL_MAX_FRAGMENT_UNIFORM_VECTORS> },
1120 { "max_texture_image_units", "gl_MaxTextureImageUnits", getInteger<GL_MAX_TEXTURE_IMAGE_UNITS> },
1121 { "max_vertex_texture_image_units", "gl_MaxVertexTextureImageUnits", getInteger<GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS> },
1122 { "max_combined_texture_image_units", "gl_MaxCombinedTextureImageUnits", getInteger<GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS> },
1123 { "max_draw_buffers", "gl_MaxDrawBuffers", getInteger<GL_MAX_DRAW_BUFFERS> },
1124
1125 // GLES 3.
1126
1127 { "max_vertex_output_vectors", "gl_MaxVertexOutputVectors", getVectorsFromComps<GL_MAX_VERTEX_OUTPUT_COMPONENTS> },
1128 { "max_fragment_input_vectors", "gl_MaxFragmentInputVectors", getVectorsFromComps<GL_MAX_FRAGMENT_INPUT_COMPONENTS> },
1129 { "min_program_texel_offset", "gl_MinProgramTexelOffset", getInteger<GL_MIN_PROGRAM_TEXEL_OFFSET> },
1130 { "max_program_texel_offset", "gl_MaxProgramTexelOffset", getInteger<GL_MAX_PROGRAM_TEXEL_OFFSET> }
1131 };
1132
1133 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtinConstants); ndx++)
1134 {
1135 const char* const caseName = builtinConstants[ndx].caseName;
1136 const char* const varName = builtinConstants[ndx].varName;
1137 const ShaderBuiltinConstantCase::GetConstantValueFunc getValue = builtinConstants[ndx].getValue;
1138
1139 addChild(new ShaderBuiltinConstantCase(m_context, (string(caseName) + "_vertex").c_str(), varName, varName, getValue, glu::SHADERTYPE_VERTEX));
1140 addChild(new ShaderBuiltinConstantCase(m_context, (string(caseName) + "_fragment").c_str(), varName, varName, getValue, glu::SHADERTYPE_FRAGMENT));
1141 }
1142
1143 addChild(new ShaderDepthRangeTest(m_context, "depth_range_vertex", "gl_DepthRange", true));
1144 addChild(new ShaderDepthRangeTest(m_context, "depth_range_fragment", "gl_DepthRange", false));
1145
1146 // Vertex shader builtin variables.
1147 addChild(new VertexIDCase (m_context));
1148 // \todo [2013-03-20 pyry] gl_InstanceID -- tested in instancing tests quite thoroughly.
1149
1150 // Fragment shader builtin variables.
1151
1152 addChild(new FragCoordXYZCase (m_context));
1153 addChild(new FragCoordWCase (m_context));
1154 addChild(new PointCoordCase (m_context));
1155 addChild(new FrontFacingCase (m_context));
1156 }
1157
1158 } // Functional
1159 } // gles3
1160 } // deqp
1161