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