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 Functional rasterization tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es2fRasterizationTests.hpp"
25 #include "tcuRasterizationVerifier.hpp"
26 #include "tcuSurface.hpp"
27 #include "tcuRenderTarget.hpp"
28 #include "tcuVectorUtil.hpp"
29 #include "tcuStringTemplate.hpp"
30 #include "tcuResultCollector.hpp"
31 #include "gluShaderProgram.hpp"
32 #include "gluRenderContext.hpp"
33 #include "gluPixelTransfer.hpp"
34 #include "gluStrUtil.hpp"
35 #include "deStringUtil.hpp"
36 #include "deRandom.hpp"
37 #include "glwFunctions.hpp"
38 #include "glwEnums.hpp"
39
40 #include <vector>
41
42 namespace deqp
43 {
44 namespace gles2
45 {
46 namespace Functional
47 {
48 namespace
49 {
50
51 using tcu::LineInterpolationMethod;
52 using tcu::LineSceneSpec;
53 using tcu::PointSceneSpec;
54 using tcu::RasterizationArguments;
55 using tcu::TriangleSceneSpec;
56
57 static const char *const s_shaderVertexTemplate = "attribute highp vec4 a_position;\n"
58 "attribute highp vec4 a_color;\n"
59 "varying highp vec4 v_color;\n"
60 "uniform highp float u_pointSize;\n"
61 "void main ()\n"
62 "{\n"
63 " gl_Position = a_position;\n"
64 " gl_PointSize = u_pointSize;\n"
65 " v_color = a_color;\n"
66 "}\n";
67 static const char *const s_shaderFragmentTemplate = "varying mediump vec4 v_color;\n"
68 "void main ()\n"
69 "{\n"
70 " gl_FragColor = v_color;\n"
71 "}\n";
72 enum InterpolationCaseFlags
73 {
74 INTERPOLATIONFLAGS_NONE = 0,
75 INTERPOLATIONFLAGS_PROJECTED = (1 << 1),
76 };
77
78 enum PrimitiveWideness
79 {
80 PRIMITIVEWIDENESS_NARROW = 0,
81 PRIMITIVEWIDENESS_WIDE,
82
83 PRIMITIVEWIDENESS_LAST
84 };
85
86 class BaseRenderingCase : public TestCase
87 {
88 public:
89 BaseRenderingCase(Context &context, const char *name, const char *desc, int renderSize = 256);
90 ~BaseRenderingCase(void);
91 virtual void init(void);
92 void deinit(void);
93
94 protected:
95 void drawPrimitives(tcu::Surface &result, const std::vector<tcu::Vec4> &vertexData, glw::GLenum primitiveType);
96 void drawPrimitives(tcu::Surface &result, const std::vector<tcu::Vec4> &vertexData,
97 const std::vector<tcu::Vec4> &coloDrata, glw::GLenum primitiveType);
98
99 const int m_renderSize;
100 int m_numSamples;
101 int m_subpixelBits;
102 float m_pointSize;
103 float m_lineWidth;
104
105 glu::ShaderProgram *m_shader;
106 };
107
BaseRenderingCase(Context & context,const char * name,const char * desc,int renderSize)108 BaseRenderingCase::BaseRenderingCase(Context &context, const char *name, const char *desc, int renderSize)
109 : TestCase(context, name, desc)
110 , m_renderSize(renderSize)
111 , m_numSamples(-1)
112 , m_subpixelBits(-1)
113 , m_pointSize(1.0f)
114 , m_lineWidth(1.0f)
115 , m_shader(DE_NULL)
116 {
117 }
118
~BaseRenderingCase(void)119 BaseRenderingCase::~BaseRenderingCase(void)
120 {
121 deinit();
122 }
123
init(void)124 void BaseRenderingCase::init(void)
125 {
126 const int width = m_context.getRenderTarget().getWidth();
127 const int height = m_context.getRenderTarget().getHeight();
128
129 // Requirements
130
131 if (width < m_renderSize || height < m_renderSize)
132 throw tcu::NotSupportedError(std::string("Render target size must be at least ") + de::toString(m_renderSize) +
133 "x" + de::toString(m_renderSize));
134
135 if (m_lineWidth != 1.0f)
136 {
137 float range[2] = {0.0f, 0.0f};
138 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range);
139
140 if (m_lineWidth < range[0] || m_lineWidth > range[1])
141 throw tcu::NotSupportedError(std::string("Support for line width ") + de::toString(m_lineWidth) +
142 " is required.");
143
144 m_testCtx.getLog() << tcu::TestLog::Message << "ALIASED_LINE_WIDTH_RANGE = [" << range[0] << ", " << range[1]
145 << "]" << tcu::TestLog::EndMessage;
146 }
147
148 if (m_pointSize != 1.0f)
149 {
150 float range[2] = {0.0f, 0.0f};
151 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_POINT_SIZE_RANGE, range);
152
153 if (m_pointSize < range[0] || m_pointSize > range[1])
154 throw tcu::NotSupportedError(std::string("Support for point size ") + de::toString(m_pointSize) +
155 " is required.");
156
157 m_testCtx.getLog() << tcu::TestLog::Message << "ALIASED_POINT_SIZE_RANGE = [" << range[0] << ", " << range[1]
158 << "]" << tcu::TestLog::EndMessage;
159 }
160
161 // Query info
162
163 m_numSamples = m_context.getRenderTarget().getNumSamples();
164 m_context.getRenderContext().getFunctions().getIntegerv(GL_SUBPIXEL_BITS, &m_subpixelBits);
165
166 m_testCtx.getLog() << tcu::TestLog::Message << "Sample count = " << m_numSamples << tcu::TestLog::EndMessage;
167 m_testCtx.getLog() << tcu::TestLog::Message << "SUBPIXEL_BITS = " << m_subpixelBits << tcu::TestLog::EndMessage;
168
169 // Gen shader
170
171 {
172 tcu::StringTemplate vertexSource(s_shaderVertexTemplate);
173 tcu::StringTemplate fragmentSource(s_shaderFragmentTemplate);
174 std::map<std::string, std::string> params;
175
176 m_shader =
177 new glu::ShaderProgram(m_context.getRenderContext(),
178 glu::ProgramSources() << glu::VertexSource(vertexSource.specialize(params))
179 << glu::FragmentSource(fragmentSource.specialize(params)));
180 if (!m_shader->isOk())
181 throw tcu::TestError("could not create shader");
182 }
183 }
184
deinit(void)185 void BaseRenderingCase::deinit(void)
186 {
187 if (m_shader)
188 {
189 delete m_shader;
190 m_shader = DE_NULL;
191 }
192 }
193
drawPrimitives(tcu::Surface & result,const std::vector<tcu::Vec4> & vertexData,glw::GLenum primitiveType)194 void BaseRenderingCase::drawPrimitives(tcu::Surface &result, const std::vector<tcu::Vec4> &vertexData,
195 glw::GLenum primitiveType)
196 {
197 // default to color white
198 const std::vector<tcu::Vec4> colorData(vertexData.size(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
199
200 drawPrimitives(result, vertexData, colorData, primitiveType);
201 }
202
drawPrimitives(tcu::Surface & result,const std::vector<tcu::Vec4> & vertexData,const std::vector<tcu::Vec4> & colorData,glw::GLenum primitiveType)203 void BaseRenderingCase::drawPrimitives(tcu::Surface &result, const std::vector<tcu::Vec4> &vertexData,
204 const std::vector<tcu::Vec4> &colorData, glw::GLenum primitiveType)
205 {
206 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
207 const glw::GLint positionLoc = gl.getAttribLocation(m_shader->getProgram(), "a_position");
208 const glw::GLint colorLoc = gl.getAttribLocation(m_shader->getProgram(), "a_color");
209 const glw::GLint pointSizeLoc = gl.getUniformLocation(m_shader->getProgram(), "u_pointSize");
210
211 gl.clearColor(0, 0, 0, 1);
212 gl.clear(GL_COLOR_BUFFER_BIT);
213 gl.viewport(0, 0, m_renderSize, m_renderSize);
214 gl.useProgram(m_shader->getProgram());
215 gl.enableVertexAttribArray(positionLoc);
216 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &vertexData[0]);
217 gl.enableVertexAttribArray(colorLoc);
218 gl.vertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 0, &colorData[0]);
219 gl.uniform1f(pointSizeLoc, m_pointSize);
220 gl.lineWidth(m_lineWidth);
221 gl.drawArrays(primitiveType, 0, (glw::GLsizei)vertexData.size());
222 gl.disableVertexAttribArray(colorLoc);
223 gl.disableVertexAttribArray(positionLoc);
224 gl.useProgram(0);
225 gl.finish();
226 GLU_EXPECT_NO_ERROR(gl.getError(), "draw primitives");
227
228 glu::readPixels(m_context.getRenderContext(), 0, 0, result.getAccess());
229 }
230
231 class BaseTriangleCase : public BaseRenderingCase
232 {
233 public:
234 BaseTriangleCase(Context &context, const char *name, const char *desc, glw::GLenum primitiveDrawType);
235 ~BaseTriangleCase(void);
236 IterateResult iterate(void);
237
238 private:
239 virtual void generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
240 std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles) = DE_NULL;
241
242 int m_iteration;
243 const int m_iterationCount;
244 const glw::GLenum m_primitiveDrawType;
245 bool m_allIterationsPassed;
246 };
247
BaseTriangleCase(Context & context,const char * name,const char * desc,glw::GLenum primitiveDrawType)248 BaseTriangleCase::BaseTriangleCase(Context &context, const char *name, const char *desc, glw::GLenum primitiveDrawType)
249 : BaseRenderingCase(context, name, desc)
250 , m_iteration(0)
251 , m_iterationCount(3)
252 , m_primitiveDrawType(primitiveDrawType)
253 , m_allIterationsPassed(true)
254 {
255 }
256
~BaseTriangleCase(void)257 BaseTriangleCase::~BaseTriangleCase(void)
258 {
259 }
260
iterate(void)261 BaseTriangleCase::IterateResult BaseTriangleCase::iterate(void)
262 {
263 const std::string iterationDescription =
264 "Test iteration " + de::toString(m_iteration + 1) + " / " + de::toString(m_iterationCount);
265 const tcu::ScopedLogSection section(m_testCtx.getLog(), iterationDescription, iterationDescription);
266 tcu::Surface resultImage(m_renderSize, m_renderSize);
267 std::vector<tcu::Vec4> drawBuffer;
268 std::vector<TriangleSceneSpec::SceneTriangle> triangles;
269
270 generateTriangles(m_iteration, drawBuffer, triangles);
271
272 // draw image
273 drawPrimitives(resultImage, drawBuffer, m_primitiveDrawType);
274
275 // compare
276 {
277 bool compareOk;
278 RasterizationArguments args;
279 TriangleSceneSpec scene;
280
281 args.numSamples = m_numSamples;
282 args.subpixelBits = m_subpixelBits;
283 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits;
284 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits;
285 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits;
286
287 scene.triangles.swap(triangles);
288
289 compareOk = verifyTriangleGroupRasterization(resultImage, scene, args, m_testCtx.getLog());
290
291 if (!compareOk)
292 m_allIterationsPassed = false;
293 }
294
295 // result
296 if (++m_iteration == m_iterationCount)
297 {
298 if (m_allIterationsPassed)
299 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
300 else
301 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rasterization");
302
303 return STOP;
304 }
305 else
306 return CONTINUE;
307 }
308
309 class BaseLineCase : public BaseRenderingCase
310 {
311 public:
312 BaseLineCase(Context &context, const char *name, const char *desc, glw::GLenum primitiveDrawType,
313 PrimitiveWideness wideness);
314 ~BaseLineCase(void);
315 IterateResult iterate(void);
316
317 private:
318 virtual void generateLines(int iteration, std::vector<tcu::Vec4> &outData,
319 std::vector<LineSceneSpec::SceneLine> &outLines) = DE_NULL;
320
321 int m_iteration;
322 const int m_iterationCount;
323 const glw::GLenum m_primitiveDrawType;
324 const PrimitiveWideness m_primitiveWideness;
325 bool m_allIterationsPassed;
326 bool m_multisampleRelaxationRequired;
327
328 static const float s_wideSize;
329 };
330
331 const float BaseLineCase::s_wideSize = 5.0f;
332
BaseLineCase(Context & context,const char * name,const char * desc,glw::GLenum primitiveDrawType,PrimitiveWideness wideness)333 BaseLineCase::BaseLineCase(Context &context, const char *name, const char *desc, glw::GLenum primitiveDrawType,
334 PrimitiveWideness wideness)
335 : BaseRenderingCase(context, name, desc)
336 , m_iteration(0)
337 , m_iterationCount(3)
338 , m_primitiveDrawType(primitiveDrawType)
339 , m_primitiveWideness(wideness)
340 , m_allIterationsPassed(true)
341 , m_multisampleRelaxationRequired(false)
342 {
343 DE_ASSERT(m_primitiveWideness < PRIMITIVEWIDENESS_LAST);
344 m_lineWidth = (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE) ? (s_wideSize) : (1.0f);
345 }
346
~BaseLineCase(void)347 BaseLineCase::~BaseLineCase(void)
348 {
349 }
350
iterate(void)351 BaseLineCase::IterateResult BaseLineCase::iterate(void)
352 {
353 const std::string iterationDescription =
354 "Test iteration " + de::toString(m_iteration + 1) + " / " + de::toString(m_iterationCount);
355 const tcu::ScopedLogSection section(m_testCtx.getLog(), iterationDescription, iterationDescription);
356 tcu::Surface resultImage(m_renderSize, m_renderSize);
357 std::vector<tcu::Vec4> drawBuffer;
358 std::vector<LineSceneSpec::SceneLine> lines;
359
360 // last iteration, max out size
361 if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE && m_iteration + 1 == m_iterationCount)
362 {
363 float range[2] = {0.0f, 0.0f};
364 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range);
365
366 m_lineWidth = range[1];
367 }
368
369 // gen data
370 generateLines(m_iteration, drawBuffer, lines);
371
372 // draw image
373 drawPrimitives(resultImage, drawBuffer, m_primitiveDrawType);
374
375 // compare
376 {
377 bool compareOk;
378 RasterizationArguments args;
379 LineSceneSpec scene;
380
381 args.numSamples = m_numSamples;
382 args.subpixelBits = m_subpixelBits;
383 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits;
384 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits;
385 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits;
386
387 scene.lines.swap(lines);
388 scene.lineWidth = m_lineWidth;
389 scene.stippleFactor = 1;
390 scene.stipplePattern = 0xFFFF;
391 scene.allowNonProjectedInterpolation = true;
392
393 compareOk = verifyLineGroupRasterization(resultImage, scene, args, m_testCtx.getLog());
394
395 // multisampled wide lines might not be supported
396 if (scene.lineWidth != 1.0f && m_numSamples > 1 && !compareOk)
397 {
398 m_multisampleRelaxationRequired = true;
399 compareOk = true;
400 }
401
402 if (!compareOk)
403 m_allIterationsPassed = false;
404 }
405
406 // result
407 if (++m_iteration == m_iterationCount)
408 {
409 if (m_allIterationsPassed && m_multisampleRelaxationRequired)
410 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING,
411 "Rasterization of multisampled wide lines failed");
412 else if (m_allIterationsPassed)
413 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
414 else
415 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rasterization");
416
417 return STOP;
418 }
419 else
420 return CONTINUE;
421 }
422
423 class PointCase : public BaseRenderingCase
424 {
425 public:
426 PointCase(Context &context, const char *name, const char *desc, PrimitiveWideness wideness);
427 ~PointCase(void);
428 IterateResult iterate(void);
429
430 private:
431 void generatePoints(int iteration, std::vector<tcu::Vec4> &outData,
432 std::vector<PointSceneSpec::ScenePoint> &outPoints);
433
434 int m_iteration;
435 const int m_iterationCount;
436 const PrimitiveWideness m_primitiveWideness;
437 bool m_allIterationsPassed;
438
439 static const float s_wideSize;
440 };
441
442 const float PointCase::s_wideSize = 10.0f;
443
PointCase(Context & context,const char * name,const char * desc,PrimitiveWideness wideness)444 PointCase::PointCase(Context &context, const char *name, const char *desc, PrimitiveWideness wideness)
445 : BaseRenderingCase(context, name, desc)
446 , m_iteration(0)
447 , m_iterationCount(3)
448 , m_primitiveWideness(wideness)
449 , m_allIterationsPassed(true)
450 {
451 m_pointSize = (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE) ? (s_wideSize) : (1.0f);
452 }
453
~PointCase(void)454 PointCase::~PointCase(void)
455 {
456 }
457
iterate(void)458 PointCase::IterateResult PointCase::iterate(void)
459 {
460 const std::string iterationDescription =
461 "Test iteration " + de::toString(m_iteration + 1) + " / " + de::toString(m_iterationCount);
462 const tcu::ScopedLogSection section(m_testCtx.getLog(), iterationDescription, iterationDescription);
463 tcu::Surface resultImage(m_renderSize, m_renderSize);
464 std::vector<tcu::Vec4> drawBuffer;
465 std::vector<PointSceneSpec::ScenePoint> points;
466
467 // last iteration, max out size
468 if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE && m_iteration + 1 == m_iterationCount)
469 {
470 float range[2] = {0.0f, 0.0f};
471 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_POINT_SIZE_RANGE, range);
472
473 m_pointSize = range[1];
474 }
475
476 // gen data
477 generatePoints(m_iteration, drawBuffer, points);
478
479 // draw image
480 drawPrimitives(resultImage, drawBuffer, GL_POINTS);
481
482 // compare
483 {
484 bool compareOk;
485 RasterizationArguments args;
486 PointSceneSpec scene;
487
488 args.numSamples = m_numSamples;
489 args.subpixelBits = m_subpixelBits;
490 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits;
491 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits;
492 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits;
493
494 scene.points.swap(points);
495
496 compareOk = verifyPointGroupRasterization(resultImage, scene, args, m_testCtx.getLog());
497
498 if (!compareOk)
499 m_allIterationsPassed = false;
500 }
501
502 // result
503 if (++m_iteration == m_iterationCount)
504 {
505 if (m_allIterationsPassed)
506 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
507 else
508 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rasterization");
509
510 return STOP;
511 }
512 else
513 return CONTINUE;
514 }
515
generatePoints(int iteration,std::vector<tcu::Vec4> & outData,std::vector<PointSceneSpec::ScenePoint> & outPoints)516 void PointCase::generatePoints(int iteration, std::vector<tcu::Vec4> &outData,
517 std::vector<PointSceneSpec::ScenePoint> &outPoints)
518 {
519 outData.resize(6);
520
521 switch (iteration)
522 {
523 case 0:
524 // \note: these values are chosen arbitrarily
525 outData[0] = tcu::Vec4(0.2f, 0.8f, 0.0f, 1.0f);
526 outData[1] = tcu::Vec4(0.5f, 0.2f, 0.0f, 1.0f);
527 outData[2] = tcu::Vec4(0.5f, 0.3f, 0.0f, 1.0f);
528 outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f);
529 outData[4] = tcu::Vec4(-0.2f, -0.4f, 0.0f, 1.0f);
530 outData[5] = tcu::Vec4(-0.4f, 0.2f, 0.0f, 1.0f);
531 break;
532
533 case 1:
534 outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
535 outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f);
536 outData[2] = tcu::Vec4(0.11f, -0.2f, 0.0f, 1.0f);
537 outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
538 outData[4] = tcu::Vec4(0.88f, 0.9f, 0.0f, 1.0f);
539 outData[5] = tcu::Vec4(0.4f, 1.2f, 0.0f, 1.0f);
540 break;
541
542 case 2:
543 outData[0] = tcu::Vec4(-0.9f, -0.3f, 0.0f, 1.0f);
544 outData[1] = tcu::Vec4(0.3f, -0.9f, 0.0f, 1.0f);
545 outData[2] = tcu::Vec4(-0.4f, -0.1f, 0.0f, 1.0f);
546 outData[3] = tcu::Vec4(-0.11f, 0.2f, 0.0f, 1.0f);
547 outData[4] = tcu::Vec4(0.88f, 0.7f, 0.0f, 1.0f);
548 outData[5] = tcu::Vec4(-0.4f, 0.4f, 0.0f, 1.0f);
549 break;
550 }
551
552 outPoints.resize(outData.size());
553 for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
554 {
555 outPoints[pointNdx].position = outData[pointNdx];
556 outPoints[pointNdx].pointSize = m_pointSize;
557 }
558
559 // log
560 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outPoints.size()
561 << " point(s): (point size = " << m_pointSize << ")" << tcu::TestLog::EndMessage;
562 for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
563 m_testCtx.getLog() << tcu::TestLog::Message << "Point " << (pointNdx + 1) << ":\t"
564 << outPoints[pointNdx].position << tcu::TestLog::EndMessage;
565 }
566
567 class PointSizeClampedTest : public BaseRenderingCase
568 {
569 public:
PointSizeClampedTest(Context & context,const char * name,const char * desc)570 PointSizeClampedTest(Context &context, const char *name, const char *desc) : BaseRenderingCase(context, name, desc)
571 {
572 }
573
iterate()574 IterateResult iterate()
575 {
576 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
577 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
578
579 // Tests that point sizes (written to gl_PointSize) are clamped,
580 // before rasterization, to the ALIASED_POINT_SIZE_RANGE
581 // given by the implementation.
582 static const int fboHeight = 4;
583 static const int testAreaWidth = 4;
584 static const int testAreaWidthWithMargin = testAreaWidth + 4;
585 static const float pointRadiusOverage = 8;
586 int fboWidth = 0;
587 int maxPointDiameter = 0;
588 {
589 int maxRenderbufferSize = 0;
590 int maxViewportDims[2] = {};
591 gl.getIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxRenderbufferSize);
592 gl.getIntegerv(GL_MAX_VIEWPORT_DIMS, maxViewportDims);
593 int maxFboWidth = std::min(maxRenderbufferSize, maxViewportDims[0]);
594
595 float pointSizeRange[2] = {};
596 gl.getFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
597 m_testCtx.getLog() << tcu::TestLog::Message << "GL_ALIASED_POINT_SIZE_RANGE is [" << pointSizeRange[0]
598 << ", " << pointSizeRange[1] << "]" << tcu::TestLog::EndMessage;
599 // Typically (in the correct case), maxPointDiameter is an odd integer.
600 maxPointDiameter = (int)pointSizeRange[1];
601 // maxPointRadius is inclusive of the center point.
602 int maxPointRadius = (maxPointDiameter + 1) / 2;
603 if (maxPointRadius > maxFboWidth - testAreaWidthWithMargin)
604 {
605 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING,
606 "max framebuffer size isn't large enough to test max point size");
607 return STOP;
608 }
609 fboWidth = maxPointRadius + testAreaWidthWithMargin;
610 // Round up to the nearest multiple of 2:
611 fboWidth = ((fboWidth + 1) / 2) * 2;
612 }
613 float pointSize = ((float)maxPointDiameter) + pointRadiusOverage * 2;
614 TCU_CHECK(gl.getError() == GL_NO_ERROR);
615
616 m_testCtx.getLog() << tcu::TestLog::Message << "Testing with pointSize = " << pointSize
617 << ", fboWidth = " << fboWidth << tcu::TestLog::EndMessage;
618
619 // Create a framebuffer that is (fboWidth)x(fboHeight), cleared to green:
620 // +---------------------------+
621 // |ggggggggggggggggggggggggggg|
622 // +---------------------------+
623 gl.viewport(0, 0, fboWidth, fboHeight);
624 uint32_t fbo = 0;
625 gl.genFramebuffers(1, &fbo);
626 gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
627 uint32_t rbo = 0;
628 gl.genRenderbuffers(1, &rbo);
629 gl.bindRenderbuffer(GL_RENDERBUFFER, rbo);
630 gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, fboWidth, fboHeight);
631 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
632 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
633 {
634 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING,
635 "couldn't complete a framebuffer suitable to test max point size");
636 return STOP;
637 }
638 gl.clearColor(0.0f, 1.0f, 0.0f, 1.0f);
639 gl.clear(GL_COLOR_BUFFER_BIT);
640 TCU_CHECK(gl.getError() == GL_NO_ERROR);
641
642 // (Framebuffer is still bound.)
643
644 // Draw a red point, with size pointSize, at the far right:
645 // +---------------------------+
646 // |ggggggggRRRRRRRRRRRRRRRRRRR|
647 // +---------------------------+
648 // x point center
649 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ fboWidth
650 // ^^^^ testAreaWidth = 4 (this is the area that's tested)
651 // ^^^^^^^^ testAreaWidthWithMargin = 8 (extra 4 pixels for tolerance)
652 // ^^^^^^^^^^^^^^^^^^x^^^^^^^^^^^^^^^^^^ maxPointDiameter = 37
653 // ^^^^^^^^ ^^^^^^^^ pointRadiusOverage = 8 * 2
654 // ^^^^^^^^^^^^^^^^^^^^^^^^^^x^^^^^^^^^^^^^^^^^^^^^^^^^^ pointSize = 53
655 // ^^^^^^^^^^^^^^^^^^^ area of resulting draw, if the size is clamped properly = 19
656 {
657 const glw::GLint positionLoc = gl.getAttribLocation(m_shader->getProgram(), "a_position");
658 const glw::GLint colorLoc = gl.getAttribLocation(m_shader->getProgram(), "a_color");
659 const glw::GLint pointSizeLoc = gl.getUniformLocation(m_shader->getProgram(), "u_pointSize");
660 static const float position[] = {1.0f, 0.0f, 0.0f, 1.0f};
661 static const float color[] = {1.0f, 0.0f, 0.0f, 1.0f};
662 gl.useProgram(m_shader->getProgram());
663 gl.enableVertexAttribArray(positionLoc);
664 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, position);
665 gl.enableVertexAttribArray(colorLoc);
666 gl.vertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 0, color);
667 gl.uniform1f(pointSizeLoc, pointSize);
668 gl.drawArrays(GL_POINTS, 0, 1);
669 gl.disableVertexAttribArray(colorLoc);
670 gl.disableVertexAttribArray(positionLoc);
671 gl.useProgram(0);
672 TCU_CHECK(gl.getError() == GL_NO_ERROR);
673 }
674
675 // And test the resulting draw (the test area should still be green).
676 uint32_t pixels[testAreaWidth * fboHeight] = {};
677 gl.readPixels(0, 0, testAreaWidth, fboHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
678 TCU_CHECK(gl.getError() == GL_NO_ERROR);
679
680 const tcu::RGBA threshold(12, 12, 12, 12);
681 for (uint32_t y = 0; y < fboHeight; ++y)
682 {
683 for (uint32_t x = 0; x < testAreaWidth; ++x)
684 {
685 tcu::RGBA color(pixels[y * testAreaWidth + x]);
686 TCU_CHECK(compareThreshold(color, tcu::RGBA::green(), threshold));
687 }
688 }
689
690 return STOP;
691 }
692 };
693
694 class TrianglesCase : public BaseTriangleCase
695 {
696 public:
697 TrianglesCase(Context &context, const char *name, const char *desc);
698 ~TrianglesCase(void);
699
700 void generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
701 std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles);
702 };
703
TrianglesCase(Context & context,const char * name,const char * desc)704 TrianglesCase::TrianglesCase(Context &context, const char *name, const char *desc)
705 : BaseTriangleCase(context, name, desc, GL_TRIANGLES)
706 {
707 }
708
~TrianglesCase(void)709 TrianglesCase::~TrianglesCase(void)
710 {
711 }
712
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)713 void TrianglesCase::generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
714 std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles)
715 {
716 outData.resize(6);
717
718 switch (iteration)
719 {
720 case 0:
721 // \note: these values are chosen arbitrarily
722 outData[0] = tcu::Vec4(0.2f, 0.8f, 0.0f, 1.0f);
723 outData[1] = tcu::Vec4(0.5f, 0.2f, 0.0f, 1.0f);
724 outData[2] = tcu::Vec4(0.5f, 0.3f, 0.0f, 1.0f);
725 outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f);
726 outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f);
727 outData[5] = tcu::Vec4(-0.4f, 0.2f, 0.0f, 1.0f);
728 break;
729
730 case 1:
731 outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
732 outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f);
733 outData[2] = tcu::Vec4(0.11f, -0.2f, 0.0f, 1.0f);
734 outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
735 outData[4] = tcu::Vec4(0.88f, 0.9f, 0.0f, 1.0f);
736 outData[5] = tcu::Vec4(0.4f, 1.2f, 0.0f, 1.0f);
737 break;
738
739 case 2:
740 outData[0] = tcu::Vec4(-0.9f, -0.3f, 0.0f, 1.0f);
741 outData[1] = tcu::Vec4(1.1f, -0.9f, 0.0f, 1.0f);
742 outData[2] = tcu::Vec4(-1.1f, -0.1f, 0.0f, 1.0f);
743 outData[3] = tcu::Vec4(-0.11f, 0.2f, 0.0f, 1.0f);
744 outData[4] = tcu::Vec4(0.88f, 0.7f, 0.0f, 1.0f);
745 outData[5] = tcu::Vec4(-0.4f, 0.4f, 0.0f, 1.0f);
746 break;
747 }
748
749 outTriangles.resize(2);
750 outTriangles[0].positions[0] = outData[0];
751 outTriangles[0].sharedEdge[0] = false;
752 outTriangles[0].positions[1] = outData[1];
753 outTriangles[0].sharedEdge[1] = false;
754 outTriangles[0].positions[2] = outData[2];
755 outTriangles[0].sharedEdge[2] = false;
756
757 outTriangles[1].positions[0] = outData[3];
758 outTriangles[1].sharedEdge[0] = false;
759 outTriangles[1].positions[1] = outData[4];
760 outTriangles[1].sharedEdge[1] = false;
761 outTriangles[1].positions[2] = outData[5];
762 outTriangles[1].sharedEdge[2] = false;
763
764 // log
765 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outTriangles.size()
766 << " triangle(s):" << tcu::TestLog::EndMessage;
767 for (int triangleNdx = 0; triangleNdx < (int)outTriangles.size(); ++triangleNdx)
768 {
769 m_testCtx.getLog() << tcu::TestLog::Message << "Triangle " << (triangleNdx + 1) << ":"
770 << "\n\t" << outTriangles[triangleNdx].positions[0] << "\n\t"
771 << outTriangles[triangleNdx].positions[1] << "\n\t" << outTriangles[triangleNdx].positions[2]
772 << tcu::TestLog::EndMessage;
773 }
774 }
775
776 class TriangleStripCase : public BaseTriangleCase
777 {
778 public:
779 TriangleStripCase(Context &context, const char *name, const char *desc);
780
781 void generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
782 std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles);
783 };
784
TriangleStripCase(Context & context,const char * name,const char * desc)785 TriangleStripCase::TriangleStripCase(Context &context, const char *name, const char *desc)
786 : BaseTriangleCase(context, name, desc, GL_TRIANGLE_STRIP)
787 {
788 }
789
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)790 void TriangleStripCase::generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
791 std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles)
792 {
793 outData.resize(5);
794
795 switch (iteration)
796 {
797 case 0:
798 // \note: these values are chosen arbitrarily
799 outData[0] = tcu::Vec4(-0.504f, 0.8f, 0.0f, 1.0f);
800 outData[1] = tcu::Vec4(-0.2f, -0.2f, 0.0f, 1.0f);
801 outData[2] = tcu::Vec4(-0.2f, 0.199f, 0.0f, 1.0f);
802 outData[3] = tcu::Vec4(0.5f, 0.201f, 0.0f, 1.0f);
803 outData[4] = tcu::Vec4(1.5f, 0.4f, 0.0f, 1.0f);
804 break;
805
806 case 1:
807 outData[0] = tcu::Vec4(-0.499f, 0.129f, 0.0f, 1.0f);
808 outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f);
809 outData[2] = tcu::Vec4(0.11f, -0.2f, 0.0f, 1.0f);
810 outData[3] = tcu::Vec4(0.11f, -0.31f, 0.0f, 1.0f);
811 outData[4] = tcu::Vec4(0.88f, 0.9f, 0.0f, 1.0f);
812 break;
813
814 case 2:
815 outData[0] = tcu::Vec4(-0.9f, -0.3f, 0.0f, 1.0f);
816 outData[1] = tcu::Vec4(1.1f, -0.9f, 0.0f, 1.0f);
817 outData[2] = tcu::Vec4(-0.87f, -0.1f, 0.0f, 1.0f);
818 outData[3] = tcu::Vec4(-0.11f, 0.19f, 0.0f, 1.0f);
819 outData[4] = tcu::Vec4(0.88f, 0.7f, 0.0f, 1.0f);
820 break;
821 }
822
823 outTriangles.resize(3);
824 outTriangles[0].positions[0] = outData[0];
825 outTriangles[0].sharedEdge[0] = false;
826 outTriangles[0].positions[1] = outData[1];
827 outTriangles[0].sharedEdge[1] = true;
828 outTriangles[0].positions[2] = outData[2];
829 outTriangles[0].sharedEdge[2] = false;
830
831 outTriangles[1].positions[0] = outData[2];
832 outTriangles[1].sharedEdge[0] = true;
833 outTriangles[1].positions[1] = outData[1];
834 outTriangles[1].sharedEdge[1] = false;
835 outTriangles[1].positions[2] = outData[3];
836 outTriangles[1].sharedEdge[2] = true;
837
838 outTriangles[2].positions[0] = outData[2];
839 outTriangles[2].sharedEdge[0] = true;
840 outTriangles[2].positions[1] = outData[3];
841 outTriangles[2].sharedEdge[1] = false;
842 outTriangles[2].positions[2] = outData[4];
843 outTriangles[2].sharedEdge[2] = false;
844
845 // log
846 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering triangle strip, " << outData.size() << " vertices."
847 << tcu::TestLog::EndMessage;
848 for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
849 {
850 m_testCtx.getLog() << tcu::TestLog::Message << "\t" << outData[vtxNdx] << tcu::TestLog::EndMessage;
851 }
852 }
853
854 class TriangleFanCase : public BaseTriangleCase
855 {
856 public:
857 TriangleFanCase(Context &context, const char *name, const char *desc);
858
859 void generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
860 std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles);
861 };
862
TriangleFanCase(Context & context,const char * name,const char * desc)863 TriangleFanCase::TriangleFanCase(Context &context, const char *name, const char *desc)
864 : BaseTriangleCase(context, name, desc, GL_TRIANGLE_FAN)
865 {
866 }
867
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)868 void TriangleFanCase::generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
869 std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles)
870 {
871 outData.resize(5);
872
873 switch (iteration)
874 {
875 case 0:
876 // \note: these values are chosen arbitrarily
877 outData[0] = tcu::Vec4(0.01f, 0.0f, 0.0f, 1.0f);
878 outData[1] = tcu::Vec4(0.5f, 0.2f, 0.0f, 1.0f);
879 outData[2] = tcu::Vec4(0.46f, 0.3f, 0.0f, 1.0f);
880 outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f);
881 outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f);
882 break;
883
884 case 1:
885 outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
886 outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f);
887 outData[2] = tcu::Vec4(0.11f, -0.2f, 0.0f, 1.0f);
888 outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
889 outData[4] = tcu::Vec4(0.88f, 0.9f, 0.0f, 1.0f);
890 break;
891
892 case 2:
893 outData[0] = tcu::Vec4(-0.9f, -0.3f, 0.0f, 1.0f);
894 outData[1] = tcu::Vec4(1.1f, -0.9f, 0.0f, 1.0f);
895 outData[2] = tcu::Vec4(0.7f, -0.1f, 0.0f, 1.0f);
896 outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
897 outData[4] = tcu::Vec4(0.88f, 0.7f, 0.0f, 1.0f);
898 break;
899 }
900
901 outTriangles.resize(3);
902 outTriangles[0].positions[0] = outData[0];
903 outTriangles[0].sharedEdge[0] = false;
904 outTriangles[0].positions[1] = outData[1];
905 outTriangles[0].sharedEdge[1] = false;
906 outTriangles[0].positions[2] = outData[2];
907 outTriangles[0].sharedEdge[2] = true;
908
909 outTriangles[1].positions[0] = outData[0];
910 outTriangles[1].sharedEdge[0] = true;
911 outTriangles[1].positions[1] = outData[2];
912 outTriangles[1].sharedEdge[1] = false;
913 outTriangles[1].positions[2] = outData[3];
914 outTriangles[1].sharedEdge[2] = true;
915
916 outTriangles[2].positions[0] = outData[0];
917 outTriangles[2].sharedEdge[0] = true;
918 outTriangles[2].positions[1] = outData[3];
919 outTriangles[2].sharedEdge[1] = false;
920 outTriangles[2].positions[2] = outData[4];
921 outTriangles[2].sharedEdge[2] = false;
922
923 // log
924 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering triangle fan, " << outData.size() << " vertices."
925 << tcu::TestLog::EndMessage;
926 for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
927 {
928 m_testCtx.getLog() << tcu::TestLog::Message << "\t" << outData[vtxNdx] << tcu::TestLog::EndMessage;
929 }
930 }
931
932 class LinesCase : public BaseLineCase
933 {
934 public:
935 LinesCase(Context &context, const char *name, const char *desc, PrimitiveWideness wideness);
936
937 void generateLines(int iteration, std::vector<tcu::Vec4> &outData, std::vector<LineSceneSpec::SceneLine> &outLines);
938 };
939
LinesCase(Context & context,const char * name,const char * desc,PrimitiveWideness wideness)940 LinesCase::LinesCase(Context &context, const char *name, const char *desc, PrimitiveWideness wideness)
941 : BaseLineCase(context, name, desc, GL_LINES, wideness)
942 {
943 }
944
generateLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)945 void LinesCase::generateLines(int iteration, std::vector<tcu::Vec4> &outData,
946 std::vector<LineSceneSpec::SceneLine> &outLines)
947 {
948 outData.resize(6);
949
950 switch (iteration)
951 {
952 case 0:
953 // \note: these values are chosen arbitrarily
954 outData[0] = tcu::Vec4(0.01f, 0.0f, 0.0f, 1.0f);
955 outData[1] = tcu::Vec4(0.5f, 0.2f, 0.0f, 1.0f);
956 outData[2] = tcu::Vec4(0.46f, 0.3f, 0.0f, 1.0f);
957 outData[3] = tcu::Vec4(-0.3f, 0.2f, 0.0f, 1.0f);
958 outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f);
959 outData[5] = tcu::Vec4(0.1f, 0.5f, 0.0f, 1.0f);
960 break;
961
962 case 1:
963 outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
964 outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f);
965 outData[2] = tcu::Vec4(0.11f, -0.2f, 0.0f, 1.0f);
966 outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
967 outData[4] = tcu::Vec4(0.88f, 0.9f, 0.0f, 1.0f);
968 outData[5] = tcu::Vec4(0.18f, -0.2f, 0.0f, 1.0f);
969 break;
970
971 case 2:
972 outData[0] = tcu::Vec4(-0.9f, -0.3f, 0.0f, 1.0f);
973 outData[1] = tcu::Vec4(1.1f, -0.9f, 0.0f, 1.0f);
974 outData[2] = tcu::Vec4(0.7f, -0.1f, 0.0f, 1.0f);
975 outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
976 outData[4] = tcu::Vec4(0.88f, 0.7f, 0.0f, 1.0f);
977 outData[5] = tcu::Vec4(0.8f, -0.7f, 0.0f, 1.0f);
978 break;
979 }
980
981 outLines.resize(3);
982 outLines[0].positions[0] = outData[0];
983 outLines[0].positions[1] = outData[1];
984 outLines[1].positions[0] = outData[2];
985 outLines[1].positions[1] = outData[3];
986 outLines[2].positions[0] = outData[4];
987 outLines[2].positions[1] = outData[5];
988
989 // log
990 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outLines.size()
991 << " lines(s): (width = " << m_lineWidth << ")" << tcu::TestLog::EndMessage;
992 for (int lineNdx = 0; lineNdx < (int)outLines.size(); ++lineNdx)
993 {
994 m_testCtx.getLog() << tcu::TestLog::Message << "Line " << (lineNdx + 1) << ":"
995 << "\n\t" << outLines[lineNdx].positions[0] << "\n\t" << outLines[lineNdx].positions[1]
996 << tcu::TestLog::EndMessage;
997 }
998 }
999
1000 class LineStripCase : public BaseLineCase
1001 {
1002 public:
1003 LineStripCase(Context &context, const char *name, const char *desc, PrimitiveWideness wideness);
1004
1005 void generateLines(int iteration, std::vector<tcu::Vec4> &outData, std::vector<LineSceneSpec::SceneLine> &outLines);
1006 };
1007
LineStripCase(Context & context,const char * name,const char * desc,PrimitiveWideness wideness)1008 LineStripCase::LineStripCase(Context &context, const char *name, const char *desc, PrimitiveWideness wideness)
1009 : BaseLineCase(context, name, desc, GL_LINE_STRIP, wideness)
1010 {
1011 }
1012
generateLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)1013 void LineStripCase::generateLines(int iteration, std::vector<tcu::Vec4> &outData,
1014 std::vector<LineSceneSpec::SceneLine> &outLines)
1015 {
1016 outData.resize(4);
1017
1018 switch (iteration)
1019 {
1020 case 0:
1021 // \note: these values are chosen arbitrarily
1022 outData[0] = tcu::Vec4(0.01f, 0.0f, 0.0f, 1.0f);
1023 outData[1] = tcu::Vec4(0.5f, 0.2f, 0.0f, 1.0f);
1024 outData[2] = tcu::Vec4(0.46f, 0.3f, 0.0f, 1.0f);
1025 outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f);
1026 break;
1027
1028 case 1:
1029 outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
1030 outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f);
1031 outData[2] = tcu::Vec4(0.11f, -0.2f, 0.0f, 1.0f);
1032 outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
1033 break;
1034
1035 case 2:
1036 outData[0] = tcu::Vec4(-0.9f, -0.3f, 0.0f, 1.0f);
1037 outData[1] = tcu::Vec4(1.1f, -0.9f, 0.0f, 1.0f);
1038 outData[2] = tcu::Vec4(0.7f, -0.1f, 0.0f, 1.0f);
1039 outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
1040 break;
1041 }
1042
1043 outLines.resize(3);
1044 outLines[0].positions[0] = outData[0];
1045 outLines[0].positions[1] = outData[1];
1046 outLines[1].positions[0] = outData[1];
1047 outLines[1].positions[1] = outData[2];
1048 outLines[2].positions[0] = outData[2];
1049 outLines[2].positions[1] = outData[3];
1050
1051 // log
1052 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering line strip, width = " << m_lineWidth << ", "
1053 << outData.size() << " vertices." << tcu::TestLog::EndMessage;
1054 for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
1055 {
1056 m_testCtx.getLog() << tcu::TestLog::Message << "\t" << outData[vtxNdx] << tcu::TestLog::EndMessage;
1057 }
1058 }
1059
1060 class LineLoopCase : public BaseLineCase
1061 {
1062 public:
1063 LineLoopCase(Context &context, const char *name, const char *desc, PrimitiveWideness wideness);
1064
1065 void generateLines(int iteration, std::vector<tcu::Vec4> &outData, std::vector<LineSceneSpec::SceneLine> &outLines);
1066 };
1067
LineLoopCase(Context & context,const char * name,const char * desc,PrimitiveWideness wideness)1068 LineLoopCase::LineLoopCase(Context &context, const char *name, const char *desc, PrimitiveWideness wideness)
1069 : BaseLineCase(context, name, desc, GL_LINE_LOOP, wideness)
1070 {
1071 }
1072
generateLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)1073 void LineLoopCase::generateLines(int iteration, std::vector<tcu::Vec4> &outData,
1074 std::vector<LineSceneSpec::SceneLine> &outLines)
1075 {
1076 outData.resize(4);
1077
1078 switch (iteration)
1079 {
1080 case 0:
1081 // \note: these values are chosen arbitrarily
1082 outData[0] = tcu::Vec4(0.01f, 0.0f, 0.0f, 1.0f);
1083 outData[1] = tcu::Vec4(0.5f, 0.2f, 0.0f, 1.0f);
1084 outData[2] = tcu::Vec4(0.46f, 0.3f, 0.0f, 1.0f);
1085 outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f);
1086 break;
1087
1088 case 1:
1089 outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
1090 outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f);
1091 outData[2] = tcu::Vec4(0.11f, -0.2f, 0.0f, 1.0f);
1092 outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
1093 break;
1094
1095 case 2:
1096 outData[0] = tcu::Vec4(-0.9f, -0.3f, 0.0f, 1.0f);
1097 outData[1] = tcu::Vec4(1.1f, -0.9f, 0.0f, 1.0f);
1098 outData[2] = tcu::Vec4(0.7f, -0.1f, 0.0f, 1.0f);
1099 outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
1100 break;
1101 }
1102
1103 outLines.resize(4);
1104 outLines[0].positions[0] = outData[0];
1105 outLines[0].positions[1] = outData[1];
1106 outLines[1].positions[0] = outData[1];
1107 outLines[1].positions[1] = outData[2];
1108 outLines[2].positions[0] = outData[2];
1109 outLines[2].positions[1] = outData[3];
1110 outLines[3].positions[0] = outData[3];
1111 outLines[3].positions[1] = outData[0];
1112
1113 // log
1114 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering line loop, width = " << m_lineWidth << ", "
1115 << outData.size() << " vertices." << tcu::TestLog::EndMessage;
1116 for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
1117 {
1118 m_testCtx.getLog() << tcu::TestLog::Message << "\t" << outData[vtxNdx] << tcu::TestLog::EndMessage;
1119 }
1120 }
1121
1122 class FillRuleCase : public BaseRenderingCase
1123 {
1124 public:
1125 enum FillRuleCaseType
1126 {
1127 FILLRULECASE_BASIC = 0,
1128 FILLRULECASE_REVERSED,
1129 FILLRULECASE_CLIPPED_FULL,
1130 FILLRULECASE_CLIPPED_PARTIAL,
1131 FILLRULECASE_PROJECTED,
1132
1133 FILLRULECASE_LAST
1134 };
1135
1136 FillRuleCase(Context &ctx, const char *name, const char *desc, FillRuleCaseType type);
1137 ~FillRuleCase(void);
1138 IterateResult iterate(void);
1139
1140 private:
1141 int getRenderSize(FillRuleCase::FillRuleCaseType type) const;
1142 int getNumIterations(FillRuleCase::FillRuleCaseType type) const;
1143 void generateTriangles(int iteration, std::vector<tcu::Vec4> &outData) const;
1144
1145 const FillRuleCaseType m_caseType;
1146 int m_iteration;
1147 const int m_iterationCount;
1148 bool m_allIterationsPassed;
1149 };
1150
FillRuleCase(Context & ctx,const char * name,const char * desc,FillRuleCaseType type)1151 FillRuleCase::FillRuleCase(Context &ctx, const char *name, const char *desc, FillRuleCaseType type)
1152 : BaseRenderingCase(ctx, name, desc, getRenderSize(type))
1153 , m_caseType(type)
1154 , m_iteration(0)
1155 , m_iterationCount(getNumIterations(type))
1156 , m_allIterationsPassed(true)
1157 {
1158 DE_ASSERT(type < FILLRULECASE_LAST);
1159 }
1160
~FillRuleCase(void)1161 FillRuleCase::~FillRuleCase(void)
1162 {
1163 deinit();
1164 }
1165
iterate(void)1166 FillRuleCase::IterateResult FillRuleCase::iterate(void)
1167 {
1168 const std::string iterationDescription =
1169 "Test iteration " + de::toString(m_iteration + 1) + " / " + de::toString(m_iterationCount);
1170 const tcu::ScopedLogSection section(m_testCtx.getLog(), iterationDescription, iterationDescription);
1171 const int thresholdRed = 1 << (8 - m_context.getRenderTarget().getPixelFormat().redBits);
1172 const int thresholdGreen = 1 << (8 - m_context.getRenderTarget().getPixelFormat().greenBits);
1173 const int thresholdBlue = 1 << (8 - m_context.getRenderTarget().getPixelFormat().blueBits);
1174 tcu::Surface resultImage(m_renderSize, m_renderSize);
1175 std::vector<tcu::Vec4> drawBuffer;
1176 bool imageShown = false;
1177
1178 generateTriangles(m_iteration, drawBuffer);
1179
1180 // draw image
1181 {
1182 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1183 const std::vector<tcu::Vec4> colorBuffer(drawBuffer.size(), tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f));
1184
1185 m_testCtx.getLog()
1186 << tcu::TestLog::Message
1187 << "Drawing gray triangles with shared edges.\nEnabling additive blending to detect overlapping fragments."
1188 << tcu::TestLog::EndMessage;
1189
1190 gl.enable(GL_BLEND);
1191 gl.blendEquation(GL_FUNC_ADD);
1192 gl.blendFunc(GL_ONE, GL_ONE);
1193 drawPrimitives(resultImage, drawBuffer, colorBuffer, GL_TRIANGLES);
1194 }
1195
1196 // verify no overdraw
1197 {
1198 const tcu::RGBA triangleColor = tcu::RGBA(127, 127, 127, 255);
1199 bool overdraw = false;
1200
1201 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying result." << tcu::TestLog::EndMessage;
1202
1203 for (int y = 0; y < resultImage.getHeight(); ++y)
1204 for (int x = 0; x < resultImage.getWidth(); ++x)
1205 {
1206 const tcu::RGBA color = resultImage.getPixel(x, y);
1207
1208 // color values are greater than triangle color? Allow lower values for multisampled edges and background.
1209 if ((color.getRed() - triangleColor.getRed()) > thresholdRed ||
1210 (color.getGreen() - triangleColor.getGreen()) > thresholdGreen ||
1211 (color.getBlue() - triangleColor.getBlue()) > thresholdBlue)
1212 overdraw = true;
1213 }
1214
1215 // results
1216 if (!overdraw)
1217 m_testCtx.getLog() << tcu::TestLog::Message << "No overlapping fragments detected."
1218 << tcu::TestLog::EndMessage;
1219 else
1220 {
1221 m_testCtx.getLog() << tcu::TestLog::Message << "Overlapping fragments detected, image is not valid."
1222 << tcu::TestLog::EndMessage;
1223 m_testCtx.getLog() << tcu::TestLog::ImageSet("Result of rendering", "Result of rendering")
1224 << tcu::TestLog::Image("Result", "Result", resultImage) << tcu::TestLog::EndImageSet;
1225
1226 imageShown = true;
1227 m_allIterationsPassed = false;
1228 }
1229 }
1230
1231 // verify no missing fragments in the full viewport case
1232 if (m_caseType == FILLRULECASE_CLIPPED_FULL)
1233 {
1234 bool missingFragments = false;
1235
1236 m_testCtx.getLog() << tcu::TestLog::Message << "Searching missing fragments." << tcu::TestLog::EndMessage;
1237
1238 for (int y = 0; y < resultImage.getHeight(); ++y)
1239 for (int x = 0; x < resultImage.getWidth(); ++x)
1240 {
1241 const tcu::RGBA color = resultImage.getPixel(x, y);
1242
1243 // black? (background)
1244 if (color.getRed() <= thresholdRed || color.getGreen() <= thresholdGreen ||
1245 color.getBlue() <= thresholdBlue)
1246 missingFragments = true;
1247 }
1248
1249 // results
1250 if (!missingFragments)
1251 m_testCtx.getLog() << tcu::TestLog::Message << "No missing fragments detected." << tcu::TestLog::EndMessage;
1252 else
1253 {
1254 m_testCtx.getLog() << tcu::TestLog::Message << "Missing fragments detected, image is not valid."
1255 << tcu::TestLog::EndMessage;
1256
1257 if (!imageShown)
1258 {
1259 m_testCtx.getLog() << tcu::TestLog::ImageSet("Result of rendering", "Result of rendering")
1260 << tcu::TestLog::Image("Result", "Result", resultImage) << tcu::TestLog::EndImageSet;
1261 }
1262
1263 m_allIterationsPassed = false;
1264 }
1265 }
1266
1267 // result
1268 if (++m_iteration == m_iterationCount)
1269 {
1270 if (m_allIterationsPassed)
1271 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1272 else
1273 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Found invalid pixels");
1274
1275 return STOP;
1276 }
1277 else
1278 return CONTINUE;
1279 }
1280
getRenderSize(FillRuleCase::FillRuleCaseType type) const1281 int FillRuleCase::getRenderSize(FillRuleCase::FillRuleCaseType type) const
1282 {
1283 if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL)
1284 return 64;
1285 else
1286 return 256;
1287 }
1288
getNumIterations(FillRuleCase::FillRuleCaseType type) const1289 int FillRuleCase::getNumIterations(FillRuleCase::FillRuleCaseType type) const
1290 {
1291 if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL)
1292 return 15;
1293 else
1294 return 2;
1295 }
1296
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData) const1297 void FillRuleCase::generateTriangles(int iteration, std::vector<tcu::Vec4> &outData) const
1298 {
1299 switch (m_caseType)
1300 {
1301 case FILLRULECASE_BASIC:
1302 case FILLRULECASE_REVERSED:
1303 case FILLRULECASE_PROJECTED:
1304 {
1305 const int numRows = 4;
1306 const int numColumns = 4;
1307 const float quadSide = 0.15f;
1308 de::Random rnd(0xabcd);
1309
1310 outData.resize(6 * numRows * numColumns);
1311
1312 for (int col = 0; col < numColumns; ++col)
1313 for (int row = 0; row < numRows; ++row)
1314 {
1315 const tcu::Vec2 center = tcu::Vec2(((float)row + 0.5f) / (float)numRows * 2.0f - 1.0f,
1316 ((float)col + 0.5f) / (float)numColumns * 2.0f - 1.0f);
1317 const float rotation = float(iteration * numColumns * numRows + col * numRows + row) /
1318 (float)(m_iterationCount * numColumns * numRows) * DE_PI / 2.0f;
1319 const tcu::Vec2 sideH = quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation));
1320 const tcu::Vec2 sideV = tcu::Vec2(sideH.y(), -sideH.x());
1321 const tcu::Vec2 quad[4] = {
1322 center + sideH + sideV,
1323 center + sideH - sideV,
1324 center - sideH - sideV,
1325 center - sideH + sideV,
1326 };
1327
1328 if (m_caseType == FILLRULECASE_BASIC)
1329 {
1330 outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1331 outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
1332 outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1333 outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1334 outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1335 outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
1336 }
1337 else if (m_caseType == FILLRULECASE_REVERSED)
1338 {
1339 outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1340 outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
1341 outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1342 outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1343 outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1344 outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
1345 }
1346 else if (m_caseType == FILLRULECASE_PROJECTED)
1347 {
1348 const float w0 = rnd.getFloat(0.1f, 4.0f);
1349 const float w1 = rnd.getFloat(0.1f, 4.0f);
1350 const float w2 = rnd.getFloat(0.1f, 4.0f);
1351 const float w3 = rnd.getFloat(0.1f, 4.0f);
1352
1353 outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0);
1354 outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x() * w1, quad[1].y() * w1, 0.0f, w1);
1355 outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2);
1356 outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2);
1357 outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0);
1358 outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x() * w3, quad[3].y() * w3, 0.0f, w3);
1359 }
1360 else
1361 DE_ASSERT(false);
1362 }
1363
1364 break;
1365 }
1366
1367 case FILLRULECASE_CLIPPED_PARTIAL:
1368 case FILLRULECASE_CLIPPED_FULL:
1369 {
1370 const float quadSide = (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (1.0f) : (2.0f);
1371 const tcu::Vec2 center =
1372 (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (tcu::Vec2(0.5f, 0.5f)) : (tcu::Vec2(0.0f, 0.0f));
1373 const float rotation = (float)(iteration) / (float)(m_iterationCount - 1) * DE_PI / 2.0f;
1374 const tcu::Vec2 sideH = quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation));
1375 const tcu::Vec2 sideV = tcu::Vec2(sideH.y(), -sideH.x());
1376 const tcu::Vec2 quad[4] = {
1377 center + sideH + sideV,
1378 center + sideH - sideV,
1379 center - sideH - sideV,
1380 center - sideH + sideV,
1381 };
1382
1383 outData.resize(6);
1384 outData[0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1385 outData[1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
1386 outData[2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1387 outData[3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1388 outData[4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1389 outData[5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
1390 break;
1391 }
1392
1393 default:
1394 DE_ASSERT(false);
1395 }
1396 }
1397
1398 class CullingTest : public BaseRenderingCase
1399 {
1400 public:
1401 CullingTest(Context &ctx, const char *name, const char *desc, glw::GLenum cullMode, glw::GLenum primitive,
1402 glw::GLenum faceOrder);
1403 ~CullingTest(void);
1404 IterateResult iterate(void);
1405
1406 private:
1407 void generateVertices(std::vector<tcu::Vec4> &outData) const;
1408 void extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
1409 const std::vector<tcu::Vec4> &vertices) const;
1410 bool triangleOrder(const tcu::Vec4 &v0, const tcu::Vec4 &v1, const tcu::Vec4 &v2) const;
1411
1412 const glw::GLenum m_cullMode;
1413 const glw::GLenum m_primitive;
1414 const glw::GLenum m_faceOrder;
1415 };
1416
CullingTest(Context & ctx,const char * name,const char * desc,glw::GLenum cullMode,glw::GLenum primitive,glw::GLenum faceOrder)1417 CullingTest::CullingTest(Context &ctx, const char *name, const char *desc, glw::GLenum cullMode, glw::GLenum primitive,
1418 glw::GLenum faceOrder)
1419 : BaseRenderingCase(ctx, name, desc)
1420 , m_cullMode(cullMode)
1421 , m_primitive(primitive)
1422 , m_faceOrder(faceOrder)
1423 {
1424 }
1425
~CullingTest(void)1426 CullingTest::~CullingTest(void)
1427 {
1428 }
1429
iterate(void)1430 CullingTest::IterateResult CullingTest::iterate(void)
1431 {
1432 tcu::Surface resultImage(m_renderSize, m_renderSize);
1433 std::vector<tcu::Vec4> drawBuffer;
1434 std::vector<TriangleSceneSpec::SceneTriangle> triangles;
1435
1436 // generate scene
1437 generateVertices(drawBuffer);
1438 extractTriangles(triangles, drawBuffer);
1439
1440 // draw image
1441 {
1442 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1443
1444 gl.enable(GL_CULL_FACE);
1445 gl.cullFace(m_cullMode);
1446 gl.frontFace(m_faceOrder);
1447
1448 m_testCtx.getLog() << tcu::TestLog::Message << "Setting front face to " << glu::getWindingName(m_faceOrder)
1449 << tcu::TestLog::EndMessage;
1450 m_testCtx.getLog() << tcu::TestLog::Message << "Setting cull face to " << glu::getFaceName(m_cullMode)
1451 << tcu::TestLog::EndMessage;
1452 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test pattern ("
1453 << glu::getPrimitiveTypeName(m_primitive) << ")" << tcu::TestLog::EndMessage;
1454
1455 drawPrimitives(resultImage, drawBuffer, m_primitive);
1456 }
1457
1458 // compare
1459 {
1460 RasterizationArguments args;
1461 TriangleSceneSpec scene;
1462
1463 args.numSamples = m_numSamples;
1464 args.subpixelBits = m_subpixelBits;
1465 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits;
1466 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits;
1467 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits;
1468
1469 scene.triangles.swap(triangles);
1470
1471 if (verifyTriangleGroupRasterization(resultImage, scene, args, m_testCtx.getLog(), tcu::VERIFICATIONMODE_WEAK))
1472 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1473 else
1474 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rendering");
1475 }
1476
1477 return STOP;
1478 }
1479
generateVertices(std::vector<tcu::Vec4> & outData) const1480 void CullingTest::generateVertices(std::vector<tcu::Vec4> &outData) const
1481 {
1482 de::Random rnd(543210);
1483
1484 outData.resize(6);
1485 for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
1486 {
1487 outData[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
1488 outData[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
1489 outData[vtxNdx].z() = 0.0f;
1490 outData[vtxNdx].w() = 1.0f;
1491 }
1492 }
1493
extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles,const std::vector<tcu::Vec4> & vertices) const1494 void CullingTest::extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
1495 const std::vector<tcu::Vec4> &vertices) const
1496 {
1497 const bool cullDirection = (m_cullMode == GL_FRONT) ^ (m_faceOrder == GL_CCW);
1498
1499 // No triangles
1500 if (m_cullMode == GL_FRONT_AND_BACK)
1501 return;
1502
1503 switch (m_primitive)
1504 {
1505 case GL_TRIANGLES:
1506 {
1507 for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
1508 {
1509 const tcu::Vec4 &v0 = vertices[vtxNdx + 0];
1510 const tcu::Vec4 &v1 = vertices[vtxNdx + 1];
1511 const tcu::Vec4 &v2 = vertices[vtxNdx + 2];
1512
1513 if (triangleOrder(v0, v1, v2) != cullDirection)
1514 {
1515 TriangleSceneSpec::SceneTriangle tri;
1516 tri.positions[0] = v0;
1517 tri.sharedEdge[0] = false;
1518 tri.positions[1] = v1;
1519 tri.sharedEdge[1] = false;
1520 tri.positions[2] = v2;
1521 tri.sharedEdge[2] = false;
1522
1523 outTriangles.push_back(tri);
1524 }
1525 }
1526 break;
1527 }
1528
1529 case GL_TRIANGLE_STRIP:
1530 {
1531 for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
1532 {
1533 const tcu::Vec4 &v0 = vertices[vtxNdx + 0];
1534 const tcu::Vec4 &v1 = vertices[vtxNdx + 1];
1535 const tcu::Vec4 &v2 = vertices[vtxNdx + 2];
1536
1537 if (triangleOrder(v0, v1, v2) != (cullDirection ^ (vtxNdx % 2 != 0)))
1538 {
1539 TriangleSceneSpec::SceneTriangle tri;
1540 tri.positions[0] = v0;
1541 tri.sharedEdge[0] = false;
1542 tri.positions[1] = v1;
1543 tri.sharedEdge[1] = false;
1544 tri.positions[2] = v2;
1545 tri.sharedEdge[2] = false;
1546
1547 outTriangles.push_back(tri);
1548 }
1549 }
1550 break;
1551 }
1552
1553 case GL_TRIANGLE_FAN:
1554 {
1555 for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
1556 {
1557 const tcu::Vec4 &v0 = vertices[0];
1558 const tcu::Vec4 &v1 = vertices[vtxNdx + 0];
1559 const tcu::Vec4 &v2 = vertices[vtxNdx + 1];
1560
1561 if (triangleOrder(v0, v1, v2) != cullDirection)
1562 {
1563 TriangleSceneSpec::SceneTriangle tri;
1564 tri.positions[0] = v0;
1565 tri.sharedEdge[0] = false;
1566 tri.positions[1] = v1;
1567 tri.sharedEdge[1] = false;
1568 tri.positions[2] = v2;
1569 tri.sharedEdge[2] = false;
1570
1571 outTriangles.push_back(tri);
1572 }
1573 }
1574 break;
1575 }
1576
1577 default:
1578 DE_ASSERT(false);
1579 }
1580 }
1581
triangleOrder(const tcu::Vec4 & v0,const tcu::Vec4 & v1,const tcu::Vec4 & v2) const1582 bool CullingTest::triangleOrder(const tcu::Vec4 &v0, const tcu::Vec4 &v1, const tcu::Vec4 &v2) const
1583 {
1584 const tcu::Vec2 s0 = v0.swizzle(0, 1) / v0.w();
1585 const tcu::Vec2 s1 = v1.swizzle(0, 1) / v1.w();
1586 const tcu::Vec2 s2 = v2.swizzle(0, 1) / v2.w();
1587
1588 // cross
1589 return ((s1.x() - s0.x()) * (s2.y() - s0.y()) - (s2.x() - s0.x()) * (s1.y() - s0.y())) < 0;
1590 }
1591
1592 class TriangleInterpolationTest : public BaseRenderingCase
1593 {
1594 public:
1595 TriangleInterpolationTest(Context &ctx, const char *name, const char *desc, glw::GLenum primitive, int flags);
1596 ~TriangleInterpolationTest(void);
1597 IterateResult iterate(void);
1598
1599 private:
1600 void generateVertices(int iteration, std::vector<tcu::Vec4> &outVertices, std::vector<tcu::Vec4> &outColors) const;
1601 void extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
1602 const std::vector<tcu::Vec4> &vertices, const std::vector<tcu::Vec4> &colors) const;
1603
1604 const glw::GLenum m_primitive;
1605 const bool m_projective;
1606 const int m_iterationCount;
1607
1608 int m_iteration;
1609 bool m_allIterationsPassed;
1610 };
1611
TriangleInterpolationTest(Context & ctx,const char * name,const char * desc,glw::GLenum primitive,int flags)1612 TriangleInterpolationTest::TriangleInterpolationTest(Context &ctx, const char *name, const char *desc,
1613 glw::GLenum primitive, int flags)
1614 : BaseRenderingCase(ctx, name, desc)
1615 , m_primitive(primitive)
1616 , m_projective((flags & INTERPOLATIONFLAGS_PROJECTED) != 0)
1617 , m_iterationCount(3)
1618 , m_iteration(0)
1619 , m_allIterationsPassed(true)
1620 {
1621 }
1622
~TriangleInterpolationTest(void)1623 TriangleInterpolationTest::~TriangleInterpolationTest(void)
1624 {
1625 deinit();
1626 }
1627
iterate(void)1628 TriangleInterpolationTest::IterateResult TriangleInterpolationTest::iterate(void)
1629 {
1630 const std::string iterationDescription =
1631 "Test iteration " + de::toString(m_iteration + 1) + " / " + de::toString(m_iterationCount);
1632 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Iteration" + de::toString(m_iteration + 1),
1633 iterationDescription);
1634 tcu::Surface resultImage(m_renderSize, m_renderSize);
1635 std::vector<tcu::Vec4> drawBuffer;
1636 std::vector<tcu::Vec4> colorBuffer;
1637 std::vector<TriangleSceneSpec::SceneTriangle> triangles;
1638
1639 // generate scene
1640 generateVertices(m_iteration, drawBuffer, colorBuffer);
1641 extractTriangles(triangles, drawBuffer, colorBuffer);
1642
1643 // log
1644 {
1645 m_testCtx.getLog() << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage;
1646 for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx)
1647 m_testCtx.getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx]
1648 << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage;
1649 }
1650
1651 // draw image
1652 drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitive);
1653
1654 // compare
1655 {
1656 RasterizationArguments args;
1657 TriangleSceneSpec scene;
1658
1659 args.numSamples = m_numSamples;
1660 args.subpixelBits = m_subpixelBits;
1661 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits;
1662 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits;
1663 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits;
1664
1665 scene.triangles.swap(triangles);
1666
1667 if (!verifyTriangleGroupInterpolation(resultImage, scene, args, m_testCtx.getLog()))
1668 m_allIterationsPassed = false;
1669 }
1670
1671 // result
1672 if (++m_iteration == m_iterationCount)
1673 {
1674 if (m_allIterationsPassed)
1675 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1676 else
1677 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Found invalid pixel values");
1678
1679 return STOP;
1680 }
1681 else
1682 return CONTINUE;
1683 }
1684
generateVertices(int iteration,std::vector<tcu::Vec4> & outVertices,std::vector<tcu::Vec4> & outColors) const1685 void TriangleInterpolationTest::generateVertices(int iteration, std::vector<tcu::Vec4> &outVertices,
1686 std::vector<tcu::Vec4> &outColors) const
1687 {
1688 // use only red, green and blue
1689 const tcu::Vec4 colors[] = {
1690 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
1691 tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
1692 tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
1693 };
1694
1695 de::Random rnd(123 + iteration * 1000 + (int)m_primitive);
1696
1697 outVertices.resize(6);
1698 outColors.resize(6);
1699
1700 for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx)
1701 {
1702 outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
1703 outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
1704 outVertices[vtxNdx].z() = 0.0f;
1705
1706 if (!m_projective)
1707 outVertices[vtxNdx].w() = 1.0f;
1708 else
1709 {
1710 const float w = rnd.getFloat(0.2f, 4.0f);
1711
1712 outVertices[vtxNdx].x() *= w;
1713 outVertices[vtxNdx].y() *= w;
1714 outVertices[vtxNdx].z() *= w;
1715 outVertices[vtxNdx].w() = w;
1716 }
1717
1718 outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)];
1719 }
1720 }
1721
extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles,const std::vector<tcu::Vec4> & vertices,const std::vector<tcu::Vec4> & colors) const1722 void TriangleInterpolationTest::extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
1723 const std::vector<tcu::Vec4> &vertices,
1724 const std::vector<tcu::Vec4> &colors) const
1725 {
1726 switch (m_primitive)
1727 {
1728 case GL_TRIANGLES:
1729 {
1730 for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
1731 {
1732 TriangleSceneSpec::SceneTriangle tri;
1733 tri.positions[0] = vertices[vtxNdx + 0];
1734 tri.positions[1] = vertices[vtxNdx + 1];
1735 tri.positions[2] = vertices[vtxNdx + 2];
1736 tri.sharedEdge[0] = false;
1737 tri.sharedEdge[1] = false;
1738 tri.sharedEdge[2] = false;
1739
1740 tri.colors[0] = colors[vtxNdx + 0];
1741 tri.colors[1] = colors[vtxNdx + 1];
1742 tri.colors[2] = colors[vtxNdx + 2];
1743
1744 outTriangles.push_back(tri);
1745 }
1746 break;
1747 }
1748
1749 case GL_TRIANGLE_STRIP:
1750 {
1751 for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
1752 {
1753 TriangleSceneSpec::SceneTriangle tri;
1754 tri.positions[0] = vertices[vtxNdx + 0];
1755 tri.positions[1] = vertices[vtxNdx + 1];
1756 tri.positions[2] = vertices[vtxNdx + 2];
1757 tri.sharedEdge[0] = false;
1758 tri.sharedEdge[1] = false;
1759 tri.sharedEdge[2] = false;
1760
1761 tri.colors[0] = colors[vtxNdx + 0];
1762 tri.colors[1] = colors[vtxNdx + 1];
1763 tri.colors[2] = colors[vtxNdx + 2];
1764
1765 outTriangles.push_back(tri);
1766 }
1767 break;
1768 }
1769
1770 case GL_TRIANGLE_FAN:
1771 {
1772 for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
1773 {
1774 TriangleSceneSpec::SceneTriangle tri;
1775 tri.positions[0] = vertices[0];
1776 tri.positions[1] = vertices[vtxNdx + 0];
1777 tri.positions[2] = vertices[vtxNdx + 1];
1778 tri.sharedEdge[0] = false;
1779 tri.sharedEdge[1] = false;
1780 tri.sharedEdge[2] = false;
1781
1782 tri.colors[0] = colors[0];
1783 tri.colors[1] = colors[vtxNdx + 0];
1784 tri.colors[2] = colors[vtxNdx + 1];
1785
1786 outTriangles.push_back(tri);
1787 }
1788 break;
1789 }
1790
1791 default:
1792 DE_ASSERT(false);
1793 }
1794 }
1795
1796 class LineInterpolationTest : public BaseRenderingCase
1797 {
1798 public:
1799 LineInterpolationTest(Context &ctx, const char *name, const char *desc, glw::GLenum primitive, int flags,
1800 float lineWidth);
1801 ~LineInterpolationTest(void);
1802 IterateResult iterate(void);
1803
1804 private:
1805 void generateVertices(int iteration, std::vector<tcu::Vec4> &outVertices, std::vector<tcu::Vec4> &outColors) const;
1806 void extractLines(std::vector<LineSceneSpec::SceneLine> &outLines, const std::vector<tcu::Vec4> &vertices,
1807 const std::vector<tcu::Vec4> &colors) const;
1808
1809 const glw::GLenum m_primitive;
1810 const bool m_projective;
1811 const int m_iterationCount;
1812
1813 int m_iteration;
1814 tcu::ResultCollector m_result;
1815 };
1816
LineInterpolationTest(Context & ctx,const char * name,const char * desc,glw::GLenum primitive,int flags,float lineWidth)1817 LineInterpolationTest::LineInterpolationTest(Context &ctx, const char *name, const char *desc, glw::GLenum primitive,
1818 int flags, float lineWidth)
1819 : BaseRenderingCase(ctx, name, desc)
1820 , m_primitive(primitive)
1821 , m_projective((flags & INTERPOLATIONFLAGS_PROJECTED) != 0)
1822 , m_iterationCount(3)
1823 , m_iteration(0)
1824 {
1825 m_lineWidth = lineWidth;
1826 }
1827
~LineInterpolationTest(void)1828 LineInterpolationTest::~LineInterpolationTest(void)
1829 {
1830 deinit();
1831 }
1832
iterate(void)1833 LineInterpolationTest::IterateResult LineInterpolationTest::iterate(void)
1834 {
1835 const std::string iterationDescription =
1836 "Test iteration " + de::toString(m_iteration + 1) + " / " + de::toString(m_iterationCount);
1837 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Iteration" + de::toString(m_iteration + 1),
1838 iterationDescription);
1839 tcu::Surface resultImage(m_renderSize, m_renderSize);
1840 std::vector<tcu::Vec4> drawBuffer;
1841 std::vector<tcu::Vec4> colorBuffer;
1842 std::vector<LineSceneSpec::SceneLine> lines;
1843
1844 // generate scene
1845 generateVertices(m_iteration, drawBuffer, colorBuffer);
1846 extractLines(lines, drawBuffer, colorBuffer);
1847
1848 // log
1849 {
1850 m_testCtx.getLog() << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage;
1851 for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx)
1852 m_testCtx.getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx]
1853 << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage;
1854 }
1855
1856 // draw image
1857 drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitive);
1858
1859 // compare
1860 {
1861 RasterizationArguments args;
1862 LineSceneSpec scene;
1863 LineInterpolationMethod iterationResult;
1864
1865 args.numSamples = m_numSamples;
1866 args.subpixelBits = m_subpixelBits;
1867 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits;
1868 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits;
1869 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits;
1870
1871 scene.lines.swap(lines);
1872 scene.lineWidth = m_lineWidth;
1873 scene.stippleFactor = 1;
1874 scene.stipplePattern = 0xFFFF;
1875 scene.allowNonProjectedInterpolation = true;
1876
1877 iterationResult = verifyLineGroupInterpolation(resultImage, scene, args, m_testCtx.getLog());
1878 switch (iterationResult)
1879 {
1880 case tcu::LINEINTERPOLATION_STRICTLY_CORRECT:
1881 // line interpolation matches the specification
1882 m_result.addResult(QP_TEST_RESULT_PASS, "Pass");
1883 break;
1884
1885 case tcu::LINEINTERPOLATION_PROJECTED:
1886 // line interpolation weights are otherwise correct, but they are projected onto major axis
1887 m_testCtx.getLog() << tcu::TestLog::Message
1888 << "Interpolation was calculated using coordinates projected onto major axis. "
1889 "This method does not produce the same values as the non-projecting method defined "
1890 "in the specification."
1891 << tcu::TestLog::EndMessage;
1892 m_result.addResult(QP_TEST_RESULT_QUALITY_WARNING,
1893 "Interpolation was calculated using projected coordinateds");
1894 break;
1895
1896 case tcu::LINEINTERPOLATION_INCORRECT:
1897 if (scene.lineWidth != 1.0f && m_numSamples > 1)
1898 {
1899 // multisampled wide lines might not be supported
1900 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING,
1901 "Interpolation of multisampled wide lines failed");
1902 }
1903 else
1904 {
1905 // line interpolation is incorrect
1906 m_result.addResult(QP_TEST_RESULT_FAIL, "Found invalid pixel values");
1907 }
1908 break;
1909
1910 default:
1911 DE_ASSERT(false);
1912 break;
1913 }
1914 }
1915
1916 // result
1917 if (++m_iteration == m_iterationCount)
1918 {
1919 m_result.setTestContextResult(m_testCtx);
1920 return STOP;
1921 }
1922 else
1923 return CONTINUE;
1924 }
1925
generateVertices(int iteration,std::vector<tcu::Vec4> & outVertices,std::vector<tcu::Vec4> & outColors) const1926 void LineInterpolationTest::generateVertices(int iteration, std::vector<tcu::Vec4> &outVertices,
1927 std::vector<tcu::Vec4> &outColors) const
1928 {
1929 // use only red, green and blue
1930 const tcu::Vec4 colors[] = {
1931 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
1932 tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
1933 tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
1934 };
1935
1936 de::Random rnd(123 + iteration * 1000 + (int)m_primitive);
1937
1938 outVertices.resize(6);
1939 outColors.resize(6);
1940
1941 for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx)
1942 {
1943 outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
1944 outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
1945 outVertices[vtxNdx].z() = 0.0f;
1946
1947 if (!m_projective)
1948 outVertices[vtxNdx].w() = 1.0f;
1949 else
1950 {
1951 const float w = rnd.getFloat(0.2f, 4.0f);
1952
1953 outVertices[vtxNdx].x() *= w;
1954 outVertices[vtxNdx].y() *= w;
1955 outVertices[vtxNdx].z() *= w;
1956 outVertices[vtxNdx].w() = w;
1957 }
1958
1959 outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)];
1960 }
1961 }
1962
extractLines(std::vector<LineSceneSpec::SceneLine> & outLines,const std::vector<tcu::Vec4> & vertices,const std::vector<tcu::Vec4> & colors) const1963 void LineInterpolationTest::extractLines(std::vector<LineSceneSpec::SceneLine> &outLines,
1964 const std::vector<tcu::Vec4> &vertices,
1965 const std::vector<tcu::Vec4> &colors) const
1966 {
1967 switch (m_primitive)
1968 {
1969 case GL_LINES:
1970 {
1971 for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; vtxNdx += 2)
1972 {
1973 LineSceneSpec::SceneLine line;
1974 line.positions[0] = vertices[vtxNdx + 0];
1975 line.positions[1] = vertices[vtxNdx + 1];
1976
1977 line.colors[0] = colors[vtxNdx + 0];
1978 line.colors[1] = colors[vtxNdx + 1];
1979
1980 outLines.push_back(line);
1981 }
1982 break;
1983 }
1984
1985 case GL_LINE_STRIP:
1986 {
1987 for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
1988 {
1989 LineSceneSpec::SceneLine line;
1990 line.positions[0] = vertices[vtxNdx + 0];
1991 line.positions[1] = vertices[vtxNdx + 1];
1992
1993 line.colors[0] = colors[vtxNdx + 0];
1994 line.colors[1] = colors[vtxNdx + 1];
1995
1996 outLines.push_back(line);
1997 }
1998 break;
1999 }
2000
2001 case GL_LINE_LOOP:
2002 {
2003 for (int vtxNdx = 0; vtxNdx < (int)vertices.size(); ++vtxNdx)
2004 {
2005 LineSceneSpec::SceneLine line;
2006 line.positions[0] = vertices[(vtxNdx + 0) % (int)vertices.size()];
2007 line.positions[1] = vertices[(vtxNdx + 1) % (int)vertices.size()];
2008
2009 line.colors[0] = colors[(vtxNdx + 0) % (int)vertices.size()];
2010 line.colors[1] = colors[(vtxNdx + 1) % (int)vertices.size()];
2011
2012 outLines.push_back(line);
2013 }
2014 break;
2015 }
2016
2017 default:
2018 DE_ASSERT(false);
2019 }
2020 }
2021
2022 } // namespace
2023
RasterizationTests(Context & context)2024 RasterizationTests::RasterizationTests(Context &context)
2025 : TestCaseGroup(context, "rasterization", "Rasterization Tests")
2026 {
2027 }
2028
~RasterizationTests(void)2029 RasterizationTests::~RasterizationTests(void)
2030 {
2031 }
2032
init(void)2033 void RasterizationTests::init(void)
2034 {
2035 // .primitives
2036 {
2037 tcu::TestCaseGroup *const primitives =
2038 new tcu::TestCaseGroup(m_testCtx, "primitives", "Primitive rasterization");
2039
2040 addChild(primitives);
2041
2042 primitives->addChild(new TrianglesCase(m_context, "triangles",
2043 "Render primitives as GL_TRIANGLES, verify rasterization result"));
2044 primitives->addChild(new TriangleStripCase(
2045 m_context, "triangle_strip", "Render primitives as GL_TRIANGLE_STRIP, verify rasterization result"));
2046 primitives->addChild(new TriangleFanCase(m_context, "triangle_fan",
2047 "Render primitives as GL_TRIANGLE_FAN, verify rasterization result"));
2048 primitives->addChild(new LinesCase(m_context, "lines",
2049 "Render primitives as GL_LINES, verify rasterization result",
2050 PRIMITIVEWIDENESS_NARROW));
2051 primitives->addChild(new LineStripCase(m_context, "line_strip",
2052 "Render primitives as GL_LINE_STRIP, verify rasterization result",
2053 PRIMITIVEWIDENESS_NARROW));
2054 primitives->addChild(new LineLoopCase(m_context, "line_loop",
2055 "Render primitives as GL_LINE_LOOP, verify rasterization result",
2056 PRIMITIVEWIDENESS_NARROW));
2057 primitives->addChild(new LinesCase(m_context, "lines_wide",
2058 "Render primitives as GL_LINES with wide lines, verify rasterization result",
2059 PRIMITIVEWIDENESS_WIDE));
2060 primitives->addChild(new LineStripCase(
2061 m_context, "line_strip_wide",
2062 "Render primitives as GL_LINE_STRIP with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE));
2063 primitives->addChild(new LineLoopCase(
2064 m_context, "line_loop_wide",
2065 "Render primitives as GL_LINE_LOOP with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE));
2066 primitives->addChild(new PointCase(m_context, "points",
2067 "Render primitives as GL_POINTS, verify rasterization result",
2068 PRIMITIVEWIDENESS_WIDE));
2069 }
2070
2071 // .limits
2072 {
2073 tcu::TestCaseGroup *const limits = new tcu::TestCaseGroup(m_testCtx, "limits", "Primitive width limits");
2074
2075 addChild(limits);
2076
2077 limits->addChild(
2078 new PointSizeClampedTest(m_context, "points", "gl_PointSize is clamped to ALIASED_POINT_SIZE_RANGE"));
2079 }
2080
2081 // .fill_rules
2082 {
2083 tcu::TestCaseGroup *const fillRules = new tcu::TestCaseGroup(m_testCtx, "fill_rules", "Primitive fill rules");
2084
2085 addChild(fillRules);
2086
2087 fillRules->addChild(
2088 new FillRuleCase(m_context, "basic_quad", "Verify fill rules", FillRuleCase::FILLRULECASE_BASIC));
2089 fillRules->addChild(new FillRuleCase(m_context, "basic_quad_reverse", "Verify fill rules",
2090 FillRuleCase::FILLRULECASE_REVERSED));
2091 fillRules->addChild(
2092 new FillRuleCase(m_context, "clipped_full", "Verify fill rules", FillRuleCase::FILLRULECASE_CLIPPED_FULL));
2093 fillRules->addChild(new FillRuleCase(m_context, "clipped_partly", "Verify fill rules",
2094 FillRuleCase::FILLRULECASE_CLIPPED_PARTIAL));
2095 fillRules->addChild(
2096 new FillRuleCase(m_context, "projected", "Verify fill rules", FillRuleCase::FILLRULECASE_PROJECTED));
2097 }
2098
2099 // .culling
2100 {
2101 static const struct CullMode
2102 {
2103 glw::GLenum mode;
2104 const char *prefix;
2105 } cullModes[] = {
2106 {GL_FRONT, "front_"},
2107 {GL_BACK, "back_"},
2108 {GL_FRONT_AND_BACK, "both_"},
2109 };
2110 static const struct PrimitiveType
2111 {
2112 glw::GLenum type;
2113 const char *name;
2114 } primitiveTypes[] = {
2115 {GL_TRIANGLES, "triangles"},
2116 {GL_TRIANGLE_STRIP, "triangle_strip"},
2117 {GL_TRIANGLE_FAN, "triangle_fan"},
2118 };
2119 static const struct FrontFaceOrder
2120 {
2121 glw::GLenum mode;
2122 const char *postfix;
2123 } frontOrders[] = {
2124 {GL_CCW, ""},
2125 {GL_CW, "_reverse"},
2126 };
2127
2128 tcu::TestCaseGroup *const culling = new tcu::TestCaseGroup(m_testCtx, "culling", "Culling");
2129
2130 addChild(culling);
2131
2132 for (int cullModeNdx = 0; cullModeNdx < DE_LENGTH_OF_ARRAY(cullModes); ++cullModeNdx)
2133 for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveNdx)
2134 for (int frontOrderNdx = 0; frontOrderNdx < DE_LENGTH_OF_ARRAY(frontOrders); ++frontOrderNdx)
2135 {
2136 const std::string name = std::string(cullModes[cullModeNdx].prefix) +
2137 primitiveTypes[primitiveNdx].name + frontOrders[frontOrderNdx].postfix;
2138
2139 culling->addChild(new CullingTest(m_context, name.c_str(), "Test primitive culling.",
2140 cullModes[cullModeNdx].mode, primitiveTypes[primitiveNdx].type,
2141 frontOrders[frontOrderNdx].mode));
2142 }
2143 }
2144
2145 // .interpolation
2146 {
2147 tcu::TestCaseGroup *const interpolation =
2148 new tcu::TestCaseGroup(m_testCtx, "interpolation", "Test interpolation");
2149
2150 addChild(interpolation);
2151
2152 // .basic
2153 {
2154 tcu::TestCaseGroup *const basic =
2155 new tcu::TestCaseGroup(m_testCtx, "basic", "Non-projective interpolation");
2156
2157 interpolation->addChild(basic);
2158
2159 basic->addChild(new TriangleInterpolationTest(m_context, "triangles", "Verify triangle interpolation",
2160 GL_TRIANGLES, INTERPOLATIONFLAGS_NONE));
2161 basic->addChild(new TriangleInterpolationTest(m_context, "triangle_strip",
2162 "Verify triangle strip interpolation", GL_TRIANGLE_STRIP,
2163 INTERPOLATIONFLAGS_NONE));
2164 basic->addChild(new TriangleInterpolationTest(m_context, "triangle_fan",
2165 "Verify triangle fan interpolation", GL_TRIANGLE_FAN,
2166 INTERPOLATIONFLAGS_NONE));
2167 basic->addChild(new LineInterpolationTest(m_context, "lines", "Verify line interpolation", GL_LINES,
2168 INTERPOLATIONFLAGS_NONE, 1.0f));
2169 basic->addChild(new LineInterpolationTest(m_context, "line_strip", "Verify line strip interpolation",
2170 GL_LINE_STRIP, INTERPOLATIONFLAGS_NONE, 1.0f));
2171 basic->addChild(new LineInterpolationTest(m_context, "line_loop", "Verify line loop interpolation",
2172 GL_LINE_LOOP, INTERPOLATIONFLAGS_NONE, 1.0f));
2173 basic->addChild(new LineInterpolationTest(m_context, "lines_wide", "Verify wide line interpolation",
2174 GL_LINES, INTERPOLATIONFLAGS_NONE, 5.0f));
2175 basic->addChild(new LineInterpolationTest(m_context, "line_strip_wide",
2176 "Verify wide line strip interpolation", GL_LINE_STRIP,
2177 INTERPOLATIONFLAGS_NONE, 5.0f));
2178 basic->addChild(new LineInterpolationTest(m_context, "line_loop_wide",
2179 "Verify wide line loop interpolation", GL_LINE_LOOP,
2180 INTERPOLATIONFLAGS_NONE, 5.0f));
2181 }
2182
2183 // .projected
2184 {
2185 tcu::TestCaseGroup *const projected =
2186 new tcu::TestCaseGroup(m_testCtx, "projected", "Projective interpolation");
2187
2188 interpolation->addChild(projected);
2189
2190 projected->addChild(new TriangleInterpolationTest(m_context, "triangles", "Verify triangle interpolation",
2191 GL_TRIANGLES, INTERPOLATIONFLAGS_PROJECTED));
2192 projected->addChild(new TriangleInterpolationTest(m_context, "triangle_strip",
2193 "Verify triangle strip interpolation", GL_TRIANGLE_STRIP,
2194 INTERPOLATIONFLAGS_PROJECTED));
2195 projected->addChild(new TriangleInterpolationTest(m_context, "triangle_fan",
2196 "Verify triangle fan interpolation", GL_TRIANGLE_FAN,
2197 INTERPOLATIONFLAGS_PROJECTED));
2198 projected->addChild(new LineInterpolationTest(m_context, "lines", "Verify line interpolation", GL_LINES,
2199 INTERPOLATIONFLAGS_PROJECTED, 1.0f));
2200 projected->addChild(new LineInterpolationTest(m_context, "line_strip", "Verify line strip interpolation",
2201 GL_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED, 1.0f));
2202 projected->addChild(new LineInterpolationTest(m_context, "line_loop", "Verify line loop interpolation",
2203 GL_LINE_LOOP, INTERPOLATIONFLAGS_PROJECTED, 1.0f));
2204 projected->addChild(new LineInterpolationTest(m_context, "lines_wide", "Verify wide line interpolation",
2205 GL_LINES, INTERPOLATIONFLAGS_PROJECTED, 5.0f));
2206 projected->addChild(new LineInterpolationTest(m_context, "line_strip_wide",
2207 "Verify wide line strip interpolation", GL_LINE_STRIP,
2208 INTERPOLATIONFLAGS_PROJECTED, 5.0f));
2209 projected->addChild(new LineInterpolationTest(m_context, "line_loop_wide",
2210 "Verify wide line loop interpolation", GL_LINE_LOOP,
2211 INTERPOLATIONFLAGS_PROJECTED, 5.0f));
2212 }
2213 }
2214 }
2215
2216 } // namespace Functional
2217 } // namespace gles2
2218 } // namespace deqp
2219