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