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