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