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