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