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