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