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
44namespace deqp
45{
46namespace gles3
47{
48namespace Functional
49{
50namespace
51{
52
53using tcu::RasterizationArguments;
54using tcu::TriangleSceneSpec;
55using tcu::PointSceneSpec;
56using tcu::LineSceneSpec;
57using tcu::LineInterpolationMethod;
58
59static 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";
70static 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";
77enum InterpolationCaseFlags
78{
79	INTERPOLATIONFLAGS_NONE = 0,
80	INTERPOLATIONFLAGS_PROJECTED = (1 << 1),
81	INTERPOLATIONFLAGS_FLATSHADE = (1 << 2),
82};
83
84enum PrimitiveWideness
85{
86	PRIMITIVEWIDENESS_NARROW = 0,
87	PRIMITIVEWIDENESS_WIDE,
88
89	PRIMITIVEWIDENESS_LAST
90};
91
92static 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
98class BaseRenderingCase : public TestCase
99{
100public:
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
122protected:
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
136private:
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
148BaseRenderingCase::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
169BaseRenderingCase::~BaseRenderingCase (void)
170{
171	deinit();
172}
173
174void 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
312void 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
351void 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
359void 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
408float BaseRenderingCase::getLineWidth (void) const
409{
410	return 1.0f;
411}
412
413float BaseRenderingCase::getPointSize (void) const
414{
415	return 1.0f;
416}
417
418const tcu::PixelFormat& BaseRenderingCase::getPixelFormat (void) const
419{
420	return m_pixelFormat;
421}
422
423class BaseTriangleCase : public BaseRenderingCase
424{
425public:
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
430private:
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
439BaseTriangleCase::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
448BaseTriangleCase::~BaseTriangleCase (void)
449{
450}
451
452BaseTriangleCase::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
499class BaseLineCase : public BaseRenderingCase
500{
501public:
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
509private:
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
522BaseLineCase::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
535BaseLineCase::~BaseLineCase (void)
536{
537}
538
539void 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
572BaseLineCase::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
605			compareOk = verifyLineGroupRasterization(resultImage, scene, args, m_testCtx.getLog());
606
607			// multisampled wide lines might not be supported
608			if (scene.lineWidth != 1.0f && m_numSamples > 1 && !compareOk)
609			{
610				m_multisampleRelaxationRequired = true;
611				compareOk = true;
612			}
613
614			if (!compareOk)
615				m_allIterationsPassed = false;
616		}
617	}
618	else
619		m_testCtx.getLog() << tcu::TestLog::Message << "Line width " << lineWidth << " not supported, skipping iteration." << tcu::TestLog::EndMessage;
620
621	// result
622	if (++m_iteration == m_iterationCount)
623	{
624		if (m_allIterationsPassed && m_multisampleRelaxationRequired)
625			m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Rasterization of multisampled wide lines failed");
626		else if (m_allIterationsPassed)
627			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
628		else
629			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rasterization");
630
631		return STOP;
632	}
633	else
634		return CONTINUE;
635}
636
637float BaseLineCase::getLineWidth (void) const
638{
639	return m_lineWidths[m_iteration];
640}
641
642class PointCase : public BaseRenderingCase
643{
644public:
645							PointCase		(Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
646							~PointCase		(void);
647
648	void					init			(void);
649	IterateResult			iterate			(void);
650
651protected:
652	float					getPointSize	(void) const;
653
654private:
655	void					generatePoints	(int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& outPoints);
656
657	int						m_iteration;
658	const int				m_iterationCount;
659	const PrimitiveWideness	m_primitiveWideness;
660	bool					m_allIterationsPassed;
661
662	float					m_maxPointSize;
663	std::vector<float>		m_pointSizes;
664};
665
666PointCase::PointCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
667	: BaseRenderingCase		(context, name, desc, renderTarget, numSamples, DEFAULT_RENDER_SIZE)
668	, m_iteration			(0)
669	, m_iterationCount		(3)
670	, m_primitiveWideness	(wideness)
671	, m_allIterationsPassed	(true)
672	, m_maxPointSize		(1.0f)
673{
674}
675
676PointCase::~PointCase (void)
677{
678}
679
680void PointCase::init (void)
681{
682	// create point sizes
683	if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
684	{
685		m_pointSizes.resize(m_iterationCount, 1.0f);
686	}
687	else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
688	{
689		float range[2] = { 0.0f, 0.0f };
690		m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_POINT_SIZE_RANGE, range);
691
692		m_testCtx.getLog() << tcu::TestLog::Message << "GL_ALIASED_POINT_SIZE_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage;
693
694		// no wide line support
695		if (range[1] <= 1.0f)
696			throw tcu::NotSupportedError("wide point support required");
697
698		// set hand picked sizes
699		m_pointSizes.push_back(10.0f);
700		m_pointSizes.push_back(25.0f);
701		m_pointSizes.push_back(range[1]);
702		DE_ASSERT((int)m_pointSizes.size() == m_iterationCount);
703
704		m_maxPointSize = range[1];
705	}
706	else
707		DE_ASSERT(false);
708
709	// init parent
710	BaseRenderingCase::init();
711}
712
713PointCase::IterateResult PointCase::iterate (void)
714{
715	const std::string						iterationDescription	= "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
716	const tcu::ScopedLogSection				section					(m_testCtx.getLog(), iterationDescription, iterationDescription);
717	const float								pointSize				= getPointSize();
718	tcu::Surface							resultImage				(m_renderSize, m_renderSize);
719	std::vector<tcu::Vec4>					drawBuffer;
720	std::vector<PointSceneSpec::ScenePoint>	points;
721
722	// supported?
723	if (pointSize <= m_maxPointSize)
724	{
725		// gen data
726		generatePoints(m_iteration, drawBuffer, points);
727
728		// draw image
729		drawPrimitives(resultImage, drawBuffer, GL_POINTS);
730
731		// compare
732		{
733			bool					compareOk;
734			RasterizationArguments	args;
735			PointSceneSpec			scene;
736
737			args.numSamples		= m_numSamples;
738			args.subpixelBits	= m_subpixelBits;
739			args.redBits		= getPixelFormat().redBits;
740			args.greenBits		= getPixelFormat().greenBits;
741			args.blueBits		= getPixelFormat().blueBits;
742
743			scene.points.swap(points);
744
745			compareOk = verifyPointGroupRasterization(resultImage, scene, args, m_testCtx.getLog());
746
747			if (!compareOk)
748				m_allIterationsPassed = false;
749		}
750	}
751	else
752		m_testCtx.getLog() << tcu::TestLog::Message << "Point size " << pointSize << " not supported, skipping iteration." << tcu::TestLog::EndMessage;
753
754	// result
755	if (++m_iteration == m_iterationCount)
756	{
757		if (m_allIterationsPassed)
758			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
759		else
760			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rasterization");
761
762		return STOP;
763	}
764	else
765		return CONTINUE;
766}
767
768float PointCase::getPointSize (void) const
769{
770	return m_pointSizes[m_iteration];
771}
772
773void PointCase::generatePoints (int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& outPoints)
774{
775	outData.resize(6);
776
777	switch (iteration)
778	{
779		case 0:
780			// \note: these values are chosen arbitrarily
781			outData[0] = tcu::Vec4( 0.2f,  0.8f, 0.0f, 1.0f);
782			outData[1] = tcu::Vec4( 0.5f,  0.2f, 0.0f, 1.0f);
783			outData[2] = tcu::Vec4( 0.5f,  0.3f, 0.0f, 1.0f);
784			outData[3] = tcu::Vec4(-0.5f,  0.2f, 0.0f, 1.0f);
785			outData[4] = tcu::Vec4(-0.2f, -0.4f, 0.0f, 1.0f);
786			outData[5] = tcu::Vec4(-0.4f,  0.2f, 0.0f, 1.0f);
787			break;
788
789		case 1:
790			outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
791			outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
792			outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
793			outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
794			outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
795			outData[5] = tcu::Vec4(   0.4f,   1.2f, 0.0f, 1.0f);
796			break;
797
798		case 2:
799			outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
800			outData[1] = tcu::Vec4(  0.3f, -0.9f, 0.0f, 1.0f);
801			outData[2] = tcu::Vec4( -0.4f, -0.1f, 0.0f, 1.0f);
802			outData[3] = tcu::Vec4(-0.11f,  0.2f, 0.0f, 1.0f);
803			outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
804			outData[5] = tcu::Vec4( -0.4f,  0.4f, 0.0f, 1.0f);
805			break;
806	}
807
808	outPoints.resize(outData.size());
809	for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
810	{
811		outPoints[pointNdx].position = outData[pointNdx];
812		outPoints[pointNdx].pointSize = getPointSize();
813	}
814
815	// log
816	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outPoints.size() << " point(s): (point size = " << getPointSize() << ")" << tcu::TestLog::EndMessage;
817	for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
818		m_testCtx.getLog() << tcu::TestLog::Message << "Point " << (pointNdx+1) << ":\t" << outPoints[pointNdx].position << tcu::TestLog::EndMessage;
819}
820
821class TrianglesCase : public BaseTriangleCase
822{
823public:
824	TrianglesCase		(Context& context, const char* name, const char* desc, BaseRenderingCase::RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
825	~TrianglesCase		(void);
826
827	void	generateTriangles	(int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
828};
829
830TrianglesCase::TrianglesCase (Context& context, const char* name, const char* desc, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
831	: BaseTriangleCase(context, name, desc, GL_TRIANGLES, renderTarget, numSamples)
832{
833}
834
835TrianglesCase::~TrianglesCase (void)
836{
837
838}
839
840void TrianglesCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
841{
842	outData.resize(6);
843
844	switch (iteration)
845	{
846		case 0:
847			// \note: these values are chosen arbitrarily
848			outData[0] = tcu::Vec4( 0.2f,  0.8f, 0.0f, 1.0f);
849			outData[1] = tcu::Vec4( 0.5f,  0.2f, 0.0f, 1.0f);
850			outData[2] = tcu::Vec4( 0.5f,  0.3f, 0.0f, 1.0f);
851			outData[3] = tcu::Vec4(-0.5f,  0.2f, 0.0f, 1.0f);
852			outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f);
853			outData[5] = tcu::Vec4(-0.4f,  0.2f, 0.0f, 1.0f);
854			break;
855
856		case 1:
857			outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
858			outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
859			outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
860			outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
861			outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
862			outData[5] = tcu::Vec4(   0.4f,   1.2f, 0.0f, 1.0f);
863			break;
864
865		case 2:
866			outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
867			outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
868			outData[2] = tcu::Vec4( -1.1f, -0.1f, 0.0f, 1.0f);
869			outData[3] = tcu::Vec4(-0.11f,  0.2f, 0.0f, 1.0f);
870			outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
871			outData[5] = tcu::Vec4( -0.4f,  0.4f, 0.0f, 1.0f);
872			break;
873	}
874
875	outTriangles.resize(2);
876	outTriangles[0].positions[0] = outData[0];	outTriangles[0].sharedEdge[0] = false;
877	outTriangles[0].positions[1] = outData[1];	outTriangles[0].sharedEdge[1] = false;
878	outTriangles[0].positions[2] = outData[2];	outTriangles[0].sharedEdge[2] = false;
879
880	outTriangles[1].positions[0] = outData[3];	outTriangles[1].sharedEdge[0] = false;
881	outTriangles[1].positions[1] = outData[4];	outTriangles[1].sharedEdge[1] = false;
882	outTriangles[1].positions[2] = outData[5];	outTriangles[1].sharedEdge[2] = false;
883
884	// log
885	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outTriangles.size() << " triangle(s):" << tcu::TestLog::EndMessage;
886	for (int triangleNdx = 0; triangleNdx < (int)outTriangles.size(); ++triangleNdx)
887	{
888		m_testCtx.getLog()
889			<< tcu::TestLog::Message
890			<< "Triangle " << (triangleNdx+1) << ":"
891			<< "\n\t" << outTriangles[triangleNdx].positions[0]
892			<< "\n\t" << outTriangles[triangleNdx].positions[1]
893			<< "\n\t" << outTriangles[triangleNdx].positions[2]
894			<< tcu::TestLog::EndMessage;
895	}
896}
897
898class TriangleStripCase : public BaseTriangleCase
899{
900public:
901			TriangleStripCase	(Context& context, const char* name, const char* desc, BaseRenderingCase::RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
902
903	void	generateTriangles	(int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
904};
905
906TriangleStripCase::TriangleStripCase (Context& context, const char* name, const char* desc, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
907	: BaseTriangleCase(context, name, desc, GL_TRIANGLE_STRIP, renderTarget, numSamples)
908{
909}
910
911void TriangleStripCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
912{
913	outData.resize(5);
914
915	switch (iteration)
916	{
917		case 0:
918			// \note: these values are chosen arbitrarily
919			outData[0] = tcu::Vec4(-0.504f,  0.8f,   0.0f, 1.0f);
920			outData[1] = tcu::Vec4(-0.2f,   -0.2f,   0.0f, 1.0f);
921			outData[2] = tcu::Vec4(-0.2f,    0.199f, 0.0f, 1.0f);
922			outData[3] = tcu::Vec4( 0.5f,    0.201f, 0.0f, 1.0f);
923			outData[4] = tcu::Vec4( 1.5f,    0.4f,   0.0f, 1.0f);
924			break;
925
926		case 1:
927			outData[0] = tcu::Vec4(-0.499f, 0.129f,  0.0f, 1.0f);
928			outData[1] = tcu::Vec4(-0.501f,  -0.3f,  0.0f, 1.0f);
929			outData[2] = tcu::Vec4(  0.11f,  -0.2f,  0.0f, 1.0f);
930			outData[3] = tcu::Vec4(  0.11f,  -0.31f, 0.0f, 1.0f);
931			outData[4] = tcu::Vec4(  0.88f,   0.9f,  0.0f, 1.0f);
932			break;
933
934		case 2:
935			outData[0] = tcu::Vec4( -0.9f, -0.3f,  0.0f, 1.0f);
936			outData[1] = tcu::Vec4(  1.1f, -0.9f,  0.0f, 1.0f);
937			outData[2] = tcu::Vec4(-0.87f, -0.1f,  0.0f, 1.0f);
938			outData[3] = tcu::Vec4(-0.11f,  0.19f, 0.0f, 1.0f);
939			outData[4] = tcu::Vec4( 0.88f,  0.7f,  0.0f, 1.0f);
940			break;
941	}
942
943	outTriangles.resize(3);
944	outTriangles[0].positions[0] = outData[0];	outTriangles[0].sharedEdge[0] = false;
945	outTriangles[0].positions[1] = outData[1];	outTriangles[0].sharedEdge[1] = true;
946	outTriangles[0].positions[2] = outData[2];	outTriangles[0].sharedEdge[2] = false;
947
948	outTriangles[1].positions[0] = outData[2];	outTriangles[1].sharedEdge[0] = true;
949	outTriangles[1].positions[1] = outData[1];	outTriangles[1].sharedEdge[1] = false;
950	outTriangles[1].positions[2] = outData[3];	outTriangles[1].sharedEdge[2] = true;
951
952	outTriangles[2].positions[0] = outData[2];	outTriangles[2].sharedEdge[0] = true;
953	outTriangles[2].positions[1] = outData[3];	outTriangles[2].sharedEdge[1] = false;
954	outTriangles[2].positions[2] = outData[4];	outTriangles[2].sharedEdge[2] = false;
955
956	// log
957	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering triangle strip, " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
958	for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
959	{
960		m_testCtx.getLog()
961			<< tcu::TestLog::Message
962			<< "\t" << outData[vtxNdx]
963			<< tcu::TestLog::EndMessage;
964	}
965}
966
967class TriangleFanCase : public BaseTriangleCase
968{
969public:
970			TriangleFanCase		(Context& context, const char* name, const char* desc, BaseRenderingCase::RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
971
972	void	generateTriangles	(int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
973};
974
975TriangleFanCase::TriangleFanCase (Context& context, const char* name, const char* desc, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
976	: BaseTriangleCase(context, name, desc, GL_TRIANGLE_FAN, renderTarget, numSamples)
977{
978}
979
980void TriangleFanCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
981{
982	outData.resize(5);
983
984	switch (iteration)
985	{
986		case 0:
987			// \note: these values are chosen arbitrarily
988			outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
989			outData[1] = tcu::Vec4( 0.5f,   0.2f, 0.0f, 1.0f);
990			outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
991			outData[3] = tcu::Vec4(-0.5f,   0.2f, 0.0f, 1.0f);
992			outData[4] = tcu::Vec4(-1.5f,  -0.4f, 0.0f, 1.0f);
993			break;
994
995		case 1:
996			outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
997			outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
998			outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
999			outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
1000			outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
1001			break;
1002
1003		case 2:
1004			outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
1005			outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
1006			outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
1007			outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
1008			outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
1009			break;
1010	}
1011
1012	outTriangles.resize(3);
1013	outTriangles[0].positions[0] = outData[0];	outTriangles[0].sharedEdge[0] = false;
1014	outTriangles[0].positions[1] = outData[1];	outTriangles[0].sharedEdge[1] = false;
1015	outTriangles[0].positions[2] = outData[2];	outTriangles[0].sharedEdge[2] = true;
1016
1017	outTriangles[1].positions[0] = outData[0];	outTriangles[1].sharedEdge[0] = true;
1018	outTriangles[1].positions[1] = outData[2];	outTriangles[1].sharedEdge[1] = false;
1019	outTriangles[1].positions[2] = outData[3];	outTriangles[1].sharedEdge[2] = true;
1020
1021	outTriangles[2].positions[0] = outData[0];	outTriangles[2].sharedEdge[0] = true;
1022	outTriangles[2].positions[1] = outData[3];	outTriangles[2].sharedEdge[1] = false;
1023	outTriangles[2].positions[2] = outData[4];	outTriangles[2].sharedEdge[2] = false;
1024
1025	// log
1026	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering triangle fan, " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
1027	for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
1028	{
1029		m_testCtx.getLog()
1030			<< tcu::TestLog::Message
1031			<< "\t" << outData[vtxNdx]
1032			<< tcu::TestLog::EndMessage;
1033	}
1034}
1035
1036class LinesCase : public BaseLineCase
1037{
1038public:
1039			LinesCase		(Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
1040
1041	void	generateLines	(int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines);
1042};
1043
1044LinesCase::LinesCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
1045	: BaseLineCase(context, name, desc, GL_LINES, wideness, renderTarget, numSamples)
1046{
1047}
1048
1049void LinesCase::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
1050{
1051	outData.resize(6);
1052
1053	switch (iteration)
1054	{
1055		case 0:
1056			// \note: these values are chosen arbitrarily
1057			outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
1058			outData[1] = tcu::Vec4( 0.5f,   0.2f, 0.0f, 1.0f);
1059			outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
1060			outData[3] = tcu::Vec4(-0.3f,   0.2f, 0.0f, 1.0f);
1061			outData[4] = tcu::Vec4(-1.5f,  -0.4f, 0.0f, 1.0f);
1062			outData[5] = tcu::Vec4( 0.1f,   0.5f, 0.0f, 1.0f);
1063			break;
1064
1065		case 1:
1066			outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
1067			outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
1068			outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
1069			outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
1070			outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
1071			outData[5] = tcu::Vec4(  0.18f,  -0.2f, 0.0f, 1.0f);
1072			break;
1073
1074		case 2:
1075			outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
1076			outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
1077			outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
1078			outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
1079			outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
1080			outData[5] = tcu::Vec4(  0.8f, -0.7f, 0.0f, 1.0f);
1081			break;
1082	}
1083
1084	outLines.resize(3);
1085	outLines[0].positions[0] = outData[0];
1086	outLines[0].positions[1] = outData[1];
1087	outLines[1].positions[0] = outData[2];
1088	outLines[1].positions[1] = outData[3];
1089	outLines[2].positions[0] = outData[4];
1090	outLines[2].positions[1] = outData[5];
1091
1092	// log
1093	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outLines.size() << " lines(s): (width = " << getLineWidth() << ")" << tcu::TestLog::EndMessage;
1094	for (int lineNdx = 0; lineNdx < (int)outLines.size(); ++lineNdx)
1095	{
1096		m_testCtx.getLog()
1097			<< tcu::TestLog::Message
1098			<< "Line " << (lineNdx+1) << ":"
1099			<< "\n\t" << outLines[lineNdx].positions[0]
1100			<< "\n\t" << outLines[lineNdx].positions[1]
1101			<< tcu::TestLog::EndMessage;
1102	}
1103}
1104
1105class LineStripCase : public BaseLineCase
1106{
1107public:
1108			LineStripCase	(Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
1109
1110	void	generateLines	(int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines);
1111};
1112
1113LineStripCase::LineStripCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
1114	: BaseLineCase(context, name, desc, GL_LINE_STRIP, wideness, renderTarget, numSamples)
1115{
1116}
1117
1118void LineStripCase::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
1119{
1120	outData.resize(4);
1121
1122	switch (iteration)
1123	{
1124		case 0:
1125			// \note: these values are chosen arbitrarily
1126			outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
1127			outData[1] = tcu::Vec4( 0.5f,   0.2f, 0.0f, 1.0f);
1128			outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
1129			outData[3] = tcu::Vec4(-0.5f,   0.2f, 0.0f, 1.0f);
1130			break;
1131
1132		case 1:
1133			outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
1134			outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
1135			outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
1136			outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
1137			break;
1138
1139		case 2:
1140			outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
1141			outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
1142			outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
1143			outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
1144			break;
1145	}
1146
1147	outLines.resize(3);
1148	outLines[0].positions[0] = outData[0];
1149	outLines[0].positions[1] = outData[1];
1150	outLines[1].positions[0] = outData[1];
1151	outLines[1].positions[1] = outData[2];
1152	outLines[2].positions[0] = outData[2];
1153	outLines[2].positions[1] = outData[3];
1154
1155	// log
1156	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering line strip, width = " << getLineWidth() << ", " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
1157	for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
1158	{
1159		m_testCtx.getLog()
1160			<< tcu::TestLog::Message
1161			<< "\t" << outData[vtxNdx]
1162			<< tcu::TestLog::EndMessage;
1163	}
1164}
1165
1166class LineLoopCase : public BaseLineCase
1167{
1168public:
1169			LineLoopCase	(Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
1170
1171	void	generateLines	(int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines);
1172};
1173
1174LineLoopCase::LineLoopCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness, BaseRenderingCase::RenderTarget renderTarget, int numSamples)
1175	: BaseLineCase(context, name, desc, GL_LINE_LOOP, wideness, renderTarget, numSamples)
1176{
1177}
1178
1179void LineLoopCase::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
1180{
1181	outData.resize(4);
1182
1183	switch (iteration)
1184	{
1185		case 0:
1186			// \note: these values are chosen arbitrarily
1187			outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
1188			outData[1] = tcu::Vec4( 0.5f,   0.2f, 0.0f, 1.0f);
1189			outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
1190			outData[3] = tcu::Vec4(-0.5f,   0.2f, 0.0f, 1.0f);
1191			break;
1192
1193		case 1:
1194			outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
1195			outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
1196			outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
1197			outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
1198			break;
1199
1200		case 2:
1201			outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
1202			outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
1203			outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
1204			outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
1205			break;
1206	}
1207
1208	outLines.resize(4);
1209	outLines[0].positions[0] = outData[0];
1210	outLines[0].positions[1] = outData[1];
1211	outLines[1].positions[0] = outData[1];
1212	outLines[1].positions[1] = outData[2];
1213	outLines[2].positions[0] = outData[2];
1214	outLines[2].positions[1] = outData[3];
1215	outLines[3].positions[0] = outData[3];
1216	outLines[3].positions[1] = outData[0];
1217
1218	// log
1219	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering line loop, width = " << getLineWidth() << ", " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
1220	for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
1221	{
1222		m_testCtx.getLog()
1223			<< tcu::TestLog::Message
1224			<< "\t" << outData[vtxNdx]
1225			<< tcu::TestLog::EndMessage;
1226	}
1227}
1228
1229class FillRuleCase : public BaseRenderingCase
1230{
1231public:
1232	enum FillRuleCaseType
1233	{
1234		FILLRULECASE_BASIC = 0,
1235		FILLRULECASE_REVERSED,
1236		FILLRULECASE_CLIPPED_FULL,
1237		FILLRULECASE_CLIPPED_PARTIAL,
1238		FILLRULECASE_PROJECTED,
1239
1240		FILLRULECASE_LAST
1241	};
1242
1243							FillRuleCase		(Context& ctx, const char* name, const char* desc, FillRuleCaseType type, RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
1244							~FillRuleCase		(void);
1245	IterateResult			iterate				(void);
1246
1247private:
1248	int						getRenderSize		(FillRuleCase::FillRuleCaseType type) const;
1249	int						getNumIterations	(FillRuleCase::FillRuleCaseType type) const;
1250	void					generateTriangles	(int iteration, std::vector<tcu::Vec4>& outData) const;
1251
1252	const FillRuleCaseType	m_caseType;
1253	int						m_iteration;
1254	const int				m_iterationCount;
1255	bool					m_allIterationsPassed;
1256
1257};
1258
1259FillRuleCase::FillRuleCase (Context& ctx, const char* name, const char* desc, FillRuleCaseType type, RenderTarget renderTarget, int numSamples)
1260	: BaseRenderingCase		(ctx, name, desc, renderTarget, numSamples, getRenderSize(type))
1261	, m_caseType			(type)
1262	, m_iteration			(0)
1263	, m_iterationCount		(getNumIterations(type))
1264	, m_allIterationsPassed	(true)
1265{
1266	DE_ASSERT(type < FILLRULECASE_LAST);
1267}
1268
1269FillRuleCase::~FillRuleCase (void)
1270{
1271	deinit();
1272}
1273
1274FillRuleCase::IterateResult FillRuleCase::iterate (void)
1275{
1276	const std::string						iterationDescription	= "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
1277	const tcu::ScopedLogSection				section					(m_testCtx.getLog(), iterationDescription, iterationDescription);
1278	const int								thresholdRed			= 1 << (8 - getPixelFormat().redBits);
1279	const int								thresholdGreen			= 1 << (8 - getPixelFormat().greenBits);
1280	const int								thresholdBlue			= 1 << (8 - getPixelFormat().blueBits);
1281	tcu::Surface							resultImage				(m_renderSize, m_renderSize);
1282	std::vector<tcu::Vec4>					drawBuffer;
1283	bool									imageShown				= false;
1284
1285	generateTriangles(m_iteration, drawBuffer);
1286
1287	// draw image
1288	{
1289		const glw::Functions&			gl				= m_context.getRenderContext().getFunctions();
1290		const std::vector<tcu::Vec4>	colorBuffer		(drawBuffer.size(), tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f));
1291
1292		m_testCtx.getLog() << tcu::TestLog::Message << "Drawing gray triangles with shared edges.\nEnabling additive blending to detect overlapping fragments." << tcu::TestLog::EndMessage;
1293
1294		gl.enable(GL_BLEND);
1295		gl.blendEquation(GL_FUNC_ADD);
1296		gl.blendFunc(GL_ONE, GL_ONE);
1297		drawPrimitives(resultImage, drawBuffer, colorBuffer, GL_TRIANGLES);
1298	}
1299
1300	// verify no overdraw
1301	{
1302		const tcu::RGBA	triangleColor	= tcu::RGBA(127, 127, 127, 255);
1303		bool			overdraw		= false;
1304
1305		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying result." << tcu::TestLog::EndMessage;
1306
1307		for (int y = 0; y < resultImage.getHeight(); ++y)
1308		for (int x = 0; x < resultImage.getWidth();  ++x)
1309		{
1310			const tcu::RGBA color = resultImage.getPixel(x, y);
1311
1312			// color values are greater than triangle color? Allow lower values for multisampled edges and background.
1313			if ((color.getRed()   - triangleColor.getRed())   > thresholdRed   ||
1314				(color.getGreen() - triangleColor.getGreen()) > thresholdGreen ||
1315				(color.getBlue()  - triangleColor.getBlue())  > thresholdBlue)
1316				overdraw = true;
1317		}
1318
1319		// results
1320		if (!overdraw)
1321			m_testCtx.getLog() << tcu::TestLog::Message << "No overlapping fragments detected." << tcu::TestLog::EndMessage;
1322		else
1323		{
1324			m_testCtx.getLog()	<< tcu::TestLog::Message << "Overlapping fragments detected, image is not valid." << tcu::TestLog::EndMessage;
1325			m_testCtx.getLog()	<< tcu::TestLog::ImageSet("Result of rendering", "Result of rendering")
1326								<< tcu::TestLog::Image("Result", "Result", resultImage)
1327								<< tcu::TestLog::EndImageSet;
1328
1329			imageShown = true;
1330			m_allIterationsPassed = false;
1331		}
1332	}
1333
1334	// verify no missing fragments in the full viewport case
1335	if (m_caseType == FILLRULECASE_CLIPPED_FULL)
1336	{
1337		bool missingFragments = false;
1338
1339		m_testCtx.getLog() << tcu::TestLog::Message << "Searching missing fragments." << tcu::TestLog::EndMessage;
1340
1341		for (int y = 0; y < resultImage.getHeight(); ++y)
1342		for (int x = 0; x < resultImage.getWidth();  ++x)
1343		{
1344			const tcu::RGBA color = resultImage.getPixel(x, y);
1345
1346			// black? (background)
1347			if (color.getRed()   <= thresholdRed   ||
1348				color.getGreen() <= thresholdGreen ||
1349				color.getBlue()  <= thresholdBlue)
1350				missingFragments = true;
1351		}
1352
1353		// results
1354		if (!missingFragments)
1355			m_testCtx.getLog() << tcu::TestLog::Message << "No missing fragments detected." << tcu::TestLog::EndMessage;
1356		else
1357		{
1358			m_testCtx.getLog()	<< tcu::TestLog::Message << "Missing fragments detected, image is not valid." << tcu::TestLog::EndMessage;
1359
1360			if (!imageShown)
1361			{
1362				m_testCtx.getLog()	<< tcu::TestLog::ImageSet("Result of rendering", "Result of rendering")
1363									<< tcu::TestLog::Image("Result", "Result", resultImage)
1364									<< tcu::TestLog::EndImageSet;
1365			}
1366
1367			m_allIterationsPassed = false;
1368		}
1369	}
1370
1371	// result
1372	if (++m_iteration == m_iterationCount)
1373	{
1374		if (m_allIterationsPassed)
1375			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1376		else
1377			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Found invalid pixels");
1378
1379		return STOP;
1380	}
1381	else
1382		return CONTINUE;
1383}
1384
1385int FillRuleCase::getRenderSize (FillRuleCase::FillRuleCaseType type) const
1386{
1387	if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL)
1388		return DEFAULT_RENDER_SIZE / 4;
1389	else
1390		return DEFAULT_RENDER_SIZE;
1391}
1392
1393int FillRuleCase::getNumIterations (FillRuleCase::FillRuleCaseType type) const
1394{
1395	if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL)
1396		return 15;
1397	else
1398		return 2;
1399}
1400
1401void FillRuleCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData) const
1402{
1403	switch (m_caseType)
1404	{
1405		case FILLRULECASE_BASIC:
1406		case FILLRULECASE_REVERSED:
1407		case FILLRULECASE_PROJECTED:
1408		{
1409			const int	numRows		= 4;
1410			const int	numColumns	= 4;
1411			const float	quadSide	= 0.15f;
1412			de::Random	rnd			(0xabcd);
1413
1414			outData.resize(6 * numRows * numColumns);
1415
1416			for (int col = 0; col < numColumns; ++col)
1417			for (int row = 0; row < numRows;    ++row)
1418			{
1419				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);
1420				const float		rotation	= (float)(iteration * numColumns * numRows + col * numRows + row) / (float)(m_iterationCount * numColumns * numRows) * DE_PI / 2.0f;
1421				const tcu::Vec2 sideH		= quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation));
1422				const tcu::Vec2 sideV		= tcu::Vec2(sideH.y(), -sideH.x());
1423				const tcu::Vec2 quad[4]		=
1424				{
1425					center + sideH + sideV,
1426					center + sideH - sideV,
1427					center - sideH - sideV,
1428					center - sideH + sideV,
1429				};
1430
1431				if (m_caseType == FILLRULECASE_BASIC)
1432				{
1433					outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1434					outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
1435					outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1436					outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1437					outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1438					outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
1439				}
1440				else if (m_caseType == FILLRULECASE_REVERSED)
1441				{
1442					outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1443					outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
1444					outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1445					outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1446					outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1447					outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
1448				}
1449				else if (m_caseType == FILLRULECASE_PROJECTED)
1450				{
1451					const float w0 = rnd.getFloat(0.1f, 4.0f);
1452					const float w1 = rnd.getFloat(0.1f, 4.0f);
1453					const float w2 = rnd.getFloat(0.1f, 4.0f);
1454					const float w3 = rnd.getFloat(0.1f, 4.0f);
1455
1456					outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0);
1457					outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x() * w1, quad[1].y() * w1, 0.0f, w1);
1458					outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2);
1459					outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2);
1460					outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0);
1461					outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x() * w3, quad[3].y() * w3, 0.0f, w3);
1462				}
1463				else
1464					DE_ASSERT(DE_FALSE);
1465			}
1466
1467			break;
1468		}
1469
1470		case FILLRULECASE_CLIPPED_PARTIAL:
1471		case FILLRULECASE_CLIPPED_FULL:
1472		{
1473			const float		quadSide	= (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (1.0f) : (2.0f);
1474			const tcu::Vec2 center		= (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (tcu::Vec2(0.5f, 0.5f)) : (tcu::Vec2(0.0f, 0.0f));
1475			const float		rotation	= (float)(iteration) / (float)(m_iterationCount - 1) * DE_PI / 2.0f;
1476			const tcu::Vec2 sideH		= quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation));
1477			const tcu::Vec2 sideV		= tcu::Vec2(sideH.y(), -sideH.x());
1478			const tcu::Vec2 quad[4]		=
1479			{
1480				center + sideH + sideV,
1481				center + sideH - sideV,
1482				center - sideH - sideV,
1483				center - sideH + sideV,
1484			};
1485
1486			outData.resize(6);
1487			outData[0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1488			outData[1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
1489			outData[2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1490			outData[3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
1491			outData[4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
1492			outData[5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
1493			break;
1494		}
1495
1496		default:
1497			DE_ASSERT(DE_FALSE);
1498	}
1499}
1500
1501class CullingTest : public BaseRenderingCase
1502{
1503public:
1504						CullingTest			(Context& ctx, const char* name, const char* desc, glw::GLenum cullMode, glw::GLenum primitive, glw::GLenum faceOrder);
1505						~CullingTest		(void);
1506	IterateResult		iterate				(void);
1507
1508private:
1509	void				generateVertices	(std::vector<tcu::Vec4>& outData) const;
1510	void				extractTriangles	(std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const;
1511	bool				triangleOrder		(const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2) const;
1512
1513	const glw::GLenum	m_cullMode;
1514	const glw::GLenum	m_primitive;
1515	const glw::GLenum	m_faceOrder;
1516};
1517
1518CullingTest::CullingTest (Context& ctx, const char* name, const char* desc, glw::GLenum cullMode, glw::GLenum primitive, glw::GLenum faceOrder)
1519	: BaseRenderingCase	(ctx, name, desc, RENDERTARGET_DEFAULT, -1, DEFAULT_RENDER_SIZE)
1520	, m_cullMode		(cullMode)
1521	, m_primitive		(primitive)
1522	, m_faceOrder		(faceOrder)
1523{
1524}
1525
1526CullingTest::~CullingTest (void)
1527{
1528}
1529
1530CullingTest::IterateResult CullingTest::iterate (void)
1531{
1532	tcu::Surface									resultImage(m_renderSize, m_renderSize);
1533	std::vector<tcu::Vec4>							drawBuffer;
1534	std::vector<TriangleSceneSpec::SceneTriangle>	triangles;
1535
1536	// generate scene
1537	generateVertices(drawBuffer);
1538	extractTriangles(triangles, drawBuffer);
1539
1540	// draw image
1541	{
1542		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1543
1544		gl.enable(GL_CULL_FACE);
1545		gl.cullFace(m_cullMode);
1546		gl.frontFace(m_faceOrder);
1547
1548		m_testCtx.getLog() << tcu::TestLog::Message << "Setting front face to " << glu::getWindingName(m_faceOrder) << tcu::TestLog::EndMessage;
1549		m_testCtx.getLog() << tcu::TestLog::Message << "Setting cull face to " << glu::getFaceName(m_cullMode) << tcu::TestLog::EndMessage;
1550		m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test pattern (" << glu::getPrimitiveTypeName(m_primitive) << ")" << tcu::TestLog::EndMessage;
1551
1552		drawPrimitives(resultImage, drawBuffer, m_primitive);
1553	}
1554
1555	// compare
1556	{
1557		RasterizationArguments	args;
1558		TriangleSceneSpec		scene;
1559
1560		args.numSamples		= m_numSamples;
1561		args.subpixelBits	= m_subpixelBits;
1562		args.redBits		= getPixelFormat().redBits;
1563		args.greenBits		= getPixelFormat().greenBits;
1564		args.blueBits		= getPixelFormat().blueBits;
1565
1566		scene.triangles.swap(triangles);
1567
1568		if (verifyTriangleGroupRasterization(resultImage, scene, args, m_testCtx.getLog(), tcu::VERIFICATIONMODE_WEAK))
1569			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1570		else
1571			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rendering");
1572	}
1573
1574	return STOP;
1575}
1576
1577void CullingTest::generateVertices (std::vector<tcu::Vec4>& outData) const
1578{
1579	de::Random rnd(543210);
1580
1581	outData.resize(6);
1582	for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
1583	{
1584		outData[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
1585		outData[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
1586		outData[vtxNdx].z() = 0.0f;
1587		outData[vtxNdx].w() = 1.0f;
1588	}
1589}
1590
1591void CullingTest::extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const
1592{
1593	const bool cullDirection = (m_cullMode == GL_FRONT) ^ (m_faceOrder == GL_CCW);
1594
1595	// No triangles
1596	if (m_cullMode == GL_FRONT_AND_BACK)
1597		return;
1598
1599	switch (m_primitive)
1600	{
1601		case GL_TRIANGLES:
1602		{
1603			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
1604			{
1605				const tcu::Vec4& v0 = vertices[vtxNdx + 0];
1606				const tcu::Vec4& v1 = vertices[vtxNdx + 1];
1607				const tcu::Vec4& v2 = vertices[vtxNdx + 2];
1608
1609				if (triangleOrder(v0, v1, v2) != cullDirection)
1610				{
1611					TriangleSceneSpec::SceneTriangle tri;
1612					tri.positions[0] = v0;	tri.sharedEdge[0] = false;
1613					tri.positions[1] = v1;	tri.sharedEdge[1] = false;
1614					tri.positions[2] = v2;	tri.sharedEdge[2] = false;
1615
1616					outTriangles.push_back(tri);
1617				}
1618			}
1619			break;
1620		}
1621
1622		case GL_TRIANGLE_STRIP:
1623		{
1624			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
1625			{
1626				const tcu::Vec4& v0 = vertices[vtxNdx + 0];
1627				const tcu::Vec4& v1 = vertices[vtxNdx + 1];
1628				const tcu::Vec4& v2 = vertices[vtxNdx + 2];
1629
1630				if (triangleOrder(v0, v1, v2) != (cullDirection ^ (vtxNdx % 2 != 0)))
1631				{
1632					TriangleSceneSpec::SceneTriangle tri;
1633					tri.positions[0] = v0;	tri.sharedEdge[0] = false;
1634					tri.positions[1] = v1;	tri.sharedEdge[1] = false;
1635					tri.positions[2] = v2;	tri.sharedEdge[2] = false;
1636
1637					outTriangles.push_back(tri);
1638				}
1639			}
1640			break;
1641		}
1642
1643		case GL_TRIANGLE_FAN:
1644		{
1645			for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
1646			{
1647				const tcu::Vec4& v0 = vertices[0];
1648				const tcu::Vec4& v1 = vertices[vtxNdx + 0];
1649				const tcu::Vec4& v2 = vertices[vtxNdx + 1];
1650
1651				if (triangleOrder(v0, v1, v2) != cullDirection)
1652				{
1653					TriangleSceneSpec::SceneTriangle tri;
1654					tri.positions[0] = v0;	tri.sharedEdge[0] = false;
1655					tri.positions[1] = v1;	tri.sharedEdge[1] = false;
1656					tri.positions[2] = v2;	tri.sharedEdge[2] = false;
1657
1658					outTriangles.push_back(tri);
1659				}
1660			}
1661			break;
1662		}
1663
1664		default:
1665			DE_ASSERT(false);
1666	}
1667}
1668
1669bool CullingTest::triangleOrder (const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2) const
1670{
1671	const tcu::Vec2 s0 = v0.swizzle(0, 1) / v0.w();
1672	const tcu::Vec2 s1 = v1.swizzle(0, 1) / v1.w();
1673	const tcu::Vec2 s2 = v2.swizzle(0, 1) / v2.w();
1674
1675	// cross
1676	return ((s1.x() - s0.x()) * (s2.y() - s0.y()) - (s2.x() - s0.x()) * (s1.y() - s0.y())) < 0;
1677}
1678
1679class TriangleInterpolationTest : public BaseRenderingCase
1680{
1681public:
1682						TriangleInterpolationTest	(Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags, RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
1683						~TriangleInterpolationTest	(void);
1684	IterateResult		iterate						(void);
1685
1686private:
1687	void				generateVertices			(int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const;
1688	void				extractTriangles			(std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const;
1689
1690	const glw::GLenum	m_primitive;
1691	const bool			m_projective;
1692	const int			m_iterationCount;
1693
1694	int					m_iteration;
1695	bool				m_allIterationsPassed;
1696};
1697
1698TriangleInterpolationTest::TriangleInterpolationTest (Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags, RenderTarget renderTarget, int numSamples)
1699	: BaseRenderingCase		(ctx, name, desc, renderTarget, numSamples, DEFAULT_RENDER_SIZE)
1700	, m_primitive			(primitive)
1701	, m_projective			((flags & INTERPOLATIONFLAGS_PROJECTED) != 0)
1702	, m_iterationCount		(3)
1703	, m_iteration			(0)
1704	, m_allIterationsPassed	(true)
1705{
1706	m_flatshade = ((flags & INTERPOLATIONFLAGS_FLATSHADE) != 0);
1707}
1708
1709TriangleInterpolationTest::~TriangleInterpolationTest (void)
1710{
1711	deinit();
1712}
1713
1714TriangleInterpolationTest::IterateResult TriangleInterpolationTest::iterate (void)
1715{
1716	const std::string								iterationDescription	= "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
1717	const tcu::ScopedLogSection						section					(m_testCtx.getLog(), "Iteration" + de::toString(m_iteration+1), iterationDescription);
1718	tcu::Surface									resultImage				(m_renderSize, m_renderSize);
1719	std::vector<tcu::Vec4>							drawBuffer;
1720	std::vector<tcu::Vec4>							colorBuffer;
1721	std::vector<TriangleSceneSpec::SceneTriangle>	triangles;
1722
1723	// generate scene
1724	generateVertices(m_iteration, drawBuffer, colorBuffer);
1725	extractTriangles(triangles, drawBuffer, colorBuffer);
1726
1727	// log
1728	{
1729		m_testCtx.getLog() << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage;
1730		for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx)
1731			m_testCtx.getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx] << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage;
1732	}
1733
1734	// draw image
1735	drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitive);
1736
1737	// compare
1738	{
1739		RasterizationArguments	args;
1740		TriangleSceneSpec		scene;
1741
1742		args.numSamples		= m_numSamples;
1743		args.subpixelBits	= m_subpixelBits;
1744		args.redBits		= getPixelFormat().redBits;
1745		args.greenBits		= getPixelFormat().greenBits;
1746		args.blueBits		= getPixelFormat().blueBits;
1747
1748		scene.triangles.swap(triangles);
1749
1750		if (!verifyTriangleGroupInterpolation(resultImage, scene, args, m_testCtx.getLog()))
1751			m_allIterationsPassed = false;
1752	}
1753
1754	// result
1755	if (++m_iteration == m_iterationCount)
1756	{
1757		if (m_allIterationsPassed)
1758			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1759		else
1760			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Found invalid pixel values");
1761
1762		return STOP;
1763	}
1764	else
1765		return CONTINUE;
1766}
1767
1768void TriangleInterpolationTest::generateVertices (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const
1769{
1770	// use only red, green and blue
1771	const tcu::Vec4 colors[] =
1772	{
1773		tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
1774		tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
1775		tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
1776	};
1777
1778	de::Random rnd(123 + iteration * 1000 + (int)m_primitive);
1779
1780	outVertices.resize(6);
1781	outColors.resize(6);
1782
1783	for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx)
1784	{
1785		outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
1786		outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
1787		outVertices[vtxNdx].z() = 0.0f;
1788
1789		if (!m_projective)
1790			outVertices[vtxNdx].w() = 1.0f;
1791		else
1792		{
1793			const float w = rnd.getFloat(0.2f, 4.0f);
1794
1795			outVertices[vtxNdx].x() *= w;
1796			outVertices[vtxNdx].y() *= w;
1797			outVertices[vtxNdx].z() *= w;
1798			outVertices[vtxNdx].w() = w;
1799		}
1800
1801		outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)];
1802	}
1803}
1804
1805void TriangleInterpolationTest::extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const
1806{
1807	switch (m_primitive)
1808	{
1809		case GL_TRIANGLES:
1810		{
1811			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
1812			{
1813				TriangleSceneSpec::SceneTriangle tri;
1814				tri.positions[0]	= vertices[vtxNdx + 0];
1815				tri.positions[1]	= vertices[vtxNdx + 1];
1816				tri.positions[2]	= vertices[vtxNdx + 2];
1817				tri.sharedEdge[0]	= false;
1818				tri.sharedEdge[1]	= false;
1819				tri.sharedEdge[2]	= false;
1820
1821				if (m_flatshade)
1822				{
1823					tri.colors[0] = colors[vtxNdx + 2];
1824					tri.colors[1] = colors[vtxNdx + 2];
1825					tri.colors[2] = colors[vtxNdx + 2];
1826				}
1827				else
1828				{
1829					tri.colors[0] = colors[vtxNdx + 0];
1830					tri.colors[1] = colors[vtxNdx + 1];
1831					tri.colors[2] = colors[vtxNdx + 2];
1832				}
1833
1834				outTriangles.push_back(tri);
1835			}
1836			break;
1837		}
1838
1839		case GL_TRIANGLE_STRIP:
1840		{
1841			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
1842			{
1843				TriangleSceneSpec::SceneTriangle tri;
1844				tri.positions[0]	= vertices[vtxNdx + 0];
1845				tri.positions[1]	= vertices[vtxNdx + 1];
1846				tri.positions[2]	= vertices[vtxNdx + 2];
1847				tri.sharedEdge[0]	= false;
1848				tri.sharedEdge[1]	= false;
1849				tri.sharedEdge[2]	= false;
1850
1851				if (m_flatshade)
1852				{
1853					tri.colors[0] = colors[vtxNdx + 2];
1854					tri.colors[1] = colors[vtxNdx + 2];
1855					tri.colors[2] = colors[vtxNdx + 2];
1856				}
1857				else
1858				{
1859					tri.colors[0] = colors[vtxNdx + 0];
1860					tri.colors[1] = colors[vtxNdx + 1];
1861					tri.colors[2] = colors[vtxNdx + 2];
1862				}
1863
1864				outTriangles.push_back(tri);
1865			}
1866			break;
1867		}
1868
1869		case GL_TRIANGLE_FAN:
1870		{
1871			for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
1872			{
1873				TriangleSceneSpec::SceneTriangle tri;
1874				tri.positions[0]	= vertices[0];
1875				tri.positions[1]	= vertices[vtxNdx + 0];
1876				tri.positions[2]	= vertices[vtxNdx + 1];
1877				tri.sharedEdge[0]	= false;
1878				tri.sharedEdge[1]	= false;
1879				tri.sharedEdge[2]	= false;
1880
1881				if (m_flatshade)
1882				{
1883					tri.colors[0] = colors[vtxNdx + 1];
1884					tri.colors[1] = colors[vtxNdx + 1];
1885					tri.colors[2] = colors[vtxNdx + 1];
1886				}
1887				else
1888				{
1889					tri.colors[0] = colors[0];
1890					tri.colors[1] = colors[vtxNdx + 0];
1891					tri.colors[2] = colors[vtxNdx + 1];
1892				}
1893
1894				outTriangles.push_back(tri);
1895			}
1896			break;
1897		}
1898
1899		default:
1900			DE_ASSERT(false);
1901	}
1902}
1903
1904class LineInterpolationTest : public BaseRenderingCase
1905{
1906public:
1907							LineInterpolationTest	(Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags, PrimitiveWideness wideness, RenderTarget renderTarget = RENDERTARGET_DEFAULT, int numSamples = -1);
1908							~LineInterpolationTest	(void);
1909
1910	void					init					(void);
1911	IterateResult			iterate					(void);
1912
1913private:
1914	void					generateVertices		(int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const;
1915	void					extractLines			(std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const;
1916	float					getLineWidth			(void) const;
1917
1918	const glw::GLenum		m_primitive;
1919	const bool				m_projective;
1920	const int				m_iterationCount;
1921	const PrimitiveWideness	m_primitiveWideness;
1922
1923	int						m_iteration;
1924	tcu::ResultCollector	m_result;
1925	float					m_maxLineWidth;
1926	std::vector<float>		m_lineWidths;
1927};
1928
1929LineInterpolationTest::LineInterpolationTest (Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags, PrimitiveWideness wideness, RenderTarget renderTarget, int numSamples)
1930	: BaseRenderingCase		(ctx, name, desc, renderTarget, numSamples, DEFAULT_RENDER_SIZE)
1931	, m_primitive			(primitive)
1932	, m_projective			((flags & INTERPOLATIONFLAGS_PROJECTED) != 0)
1933	, m_iterationCount		(3)
1934	, m_primitiveWideness	(wideness)
1935	, m_iteration			(0)
1936	, m_maxLineWidth		(1.0f)
1937{
1938	m_flatshade = ((flags & INTERPOLATIONFLAGS_FLATSHADE) != 0);
1939}
1940
1941LineInterpolationTest::~LineInterpolationTest (void)
1942{
1943	deinit();
1944}
1945
1946void LineInterpolationTest::init (void)
1947{
1948	// create line widths
1949	if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
1950	{
1951		m_lineWidths.resize(m_iterationCount, 1.0f);
1952	}
1953	else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
1954	{
1955		float range[2] = { 0.0f, 0.0f };
1956		m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range);
1957
1958		m_testCtx.getLog() << tcu::TestLog::Message << "ALIASED_LINE_WIDTH_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage;
1959
1960		// no wide line support
1961		if (range[1] <= 1.0f)
1962			throw tcu::NotSupportedError("wide line support required");
1963
1964		// set hand picked sizes
1965		m_lineWidths.push_back(5.0f);
1966		m_lineWidths.push_back(10.0f);
1967		m_lineWidths.push_back(range[1]);
1968		DE_ASSERT((int)m_lineWidths.size() == m_iterationCount);
1969
1970		m_maxLineWidth = range[1];
1971	}
1972	else
1973		DE_ASSERT(false);
1974
1975	// init parent
1976	BaseRenderingCase::init();
1977}
1978
1979LineInterpolationTest::IterateResult LineInterpolationTest::iterate (void)
1980{
1981	const std::string						iterationDescription	= "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
1982	const tcu::ScopedLogSection				section					(m_testCtx.getLog(), "Iteration" + de::toString(m_iteration+1), iterationDescription);
1983	const float								lineWidth				= getLineWidth();
1984	tcu::Surface							resultImage				(m_renderSize, m_renderSize);
1985	std::vector<tcu::Vec4>					drawBuffer;
1986	std::vector<tcu::Vec4>					colorBuffer;
1987	std::vector<LineSceneSpec::SceneLine>	lines;
1988
1989	// supported?
1990	if (lineWidth <= m_maxLineWidth)
1991	{
1992		// generate scene
1993		generateVertices(m_iteration, drawBuffer, colorBuffer);
1994		extractLines(lines, drawBuffer, colorBuffer);
1995
1996		// log
1997		{
1998			m_testCtx.getLog() << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage;
1999			for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx)
2000				m_testCtx.getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx] << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage;
2001		}
2002
2003		// draw image
2004		drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitive);
2005
2006		// compare
2007		{
2008			RasterizationArguments	args;
2009			LineSceneSpec			scene;
2010			LineInterpolationMethod	iterationResult;
2011
2012			args.numSamples		= m_numSamples;
2013			args.subpixelBits	= m_subpixelBits;
2014			args.redBits		= getPixelFormat().redBits;
2015			args.greenBits		= getPixelFormat().greenBits;
2016			args.blueBits		= getPixelFormat().blueBits;
2017
2018			scene.lines.swap(lines);
2019			scene.lineWidth = getLineWidth();
2020
2021			iterationResult = verifyLineGroupInterpolation(resultImage, scene, args, m_testCtx.getLog());
2022			switch (iterationResult)
2023			{
2024				case tcu::LINEINTERPOLATION_STRICTLY_CORRECT:
2025					// line interpolation matches the specification
2026					m_result.addResult(QP_TEST_RESULT_PASS, "Pass");
2027					break;
2028
2029				case tcu::LINEINTERPOLATION_PROJECTED:
2030					// line interpolation weights are otherwise correct, but they are projected onto major axis
2031					m_testCtx.getLog()	<< tcu::TestLog::Message
2032										<< "Interpolation was calculated using coordinates projected onto major axis. "
2033										"This method does not produce the same values as the non-projecting method defined in the specification."
2034										<< tcu::TestLog::EndMessage;
2035					m_result.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Interpolation was calculated using projected coordinateds");
2036					break;
2037
2038				case tcu::LINEINTERPOLATION_INCORRECT:
2039					if (scene.lineWidth != 1.0f && m_numSamples > 1)
2040					{
2041						// multisampled wide lines might not be supported
2042						m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Interpolation of multisampled wide lines failed");
2043					}
2044					else
2045					{
2046						// line interpolation is incorrect
2047						m_result.addResult(QP_TEST_RESULT_FAIL, "Found invalid pixel values");
2048					}
2049					break;
2050
2051				default:
2052					DE_ASSERT(false);
2053					break;
2054			}
2055		}
2056	}
2057	else
2058		m_testCtx.getLog() << tcu::TestLog::Message << "Line width " << lineWidth << " not supported, skipping iteration." << tcu::TestLog::EndMessage;
2059
2060	// result
2061	if (++m_iteration == m_iterationCount)
2062	{
2063		m_result.setTestContextResult(m_testCtx);
2064		return STOP;
2065	}
2066	else
2067		return CONTINUE;
2068}
2069
2070void LineInterpolationTest::generateVertices (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const
2071{
2072	// use only red, green and blue
2073	const tcu::Vec4 colors[] =
2074	{
2075		tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
2076		tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
2077		tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
2078	};
2079
2080	de::Random rnd(123 + iteration * 1000 + (int)m_primitive);
2081
2082	outVertices.resize(6);
2083	outColors.resize(6);
2084
2085	for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx)
2086	{
2087		outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
2088		outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
2089		outVertices[vtxNdx].z() = 0.0f;
2090
2091		if (!m_projective)
2092			outVertices[vtxNdx].w() = 1.0f;
2093		else
2094		{
2095			const float w = rnd.getFloat(0.2f, 4.0f);
2096
2097			outVertices[vtxNdx].x() *= w;
2098			outVertices[vtxNdx].y() *= w;
2099			outVertices[vtxNdx].z() *= w;
2100			outVertices[vtxNdx].w() = w;
2101		}
2102
2103		outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)];
2104	}
2105}
2106
2107void LineInterpolationTest::extractLines (std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const
2108{
2109	switch (m_primitive)
2110	{
2111		case GL_LINES:
2112		{
2113			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; vtxNdx += 2)
2114			{
2115				LineSceneSpec::SceneLine line;
2116				line.positions[0] = vertices[vtxNdx + 0];
2117				line.positions[1] = vertices[vtxNdx + 1];
2118
2119				if (m_flatshade)
2120				{
2121					line.colors[0] = colors[vtxNdx + 1];
2122					line.colors[1] = colors[vtxNdx + 1];
2123				}
2124				else
2125				{
2126					line.colors[0] = colors[vtxNdx + 0];
2127					line.colors[1] = colors[vtxNdx + 1];
2128				}
2129
2130				outLines.push_back(line);
2131			}
2132			break;
2133		}
2134
2135		case GL_LINE_STRIP:
2136		{
2137			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
2138			{
2139				LineSceneSpec::SceneLine line;
2140				line.positions[0] = vertices[vtxNdx + 0];
2141				line.positions[1] = vertices[vtxNdx + 1];
2142
2143				if (m_flatshade)
2144				{
2145					line.colors[0] = colors[vtxNdx + 1];
2146					line.colors[1] = colors[vtxNdx + 1];
2147				}
2148				else
2149				{
2150					line.colors[0] = colors[vtxNdx + 0];
2151					line.colors[1] = colors[vtxNdx + 1];
2152				}
2153
2154				outLines.push_back(line);
2155			}
2156			break;
2157		}
2158
2159		case GL_LINE_LOOP:
2160		{
2161			for (int vtxNdx = 0; vtxNdx < (int)vertices.size(); ++vtxNdx)
2162			{
2163				LineSceneSpec::SceneLine line;
2164				line.positions[0] = vertices[(vtxNdx + 0) % (int)vertices.size()];
2165				line.positions[1] = vertices[(vtxNdx + 1) % (int)vertices.size()];
2166
2167				if (m_flatshade)
2168				{
2169					line.colors[0] = colors[(vtxNdx + 1) % (int)vertices.size()];
2170					line.colors[1] = colors[(vtxNdx + 1) % (int)vertices.size()];
2171				}
2172				else
2173				{
2174					line.colors[0] = colors[(vtxNdx + 0) % (int)vertices.size()];
2175					line.colors[1] = colors[(vtxNdx + 1) % (int)vertices.size()];
2176				}
2177
2178				outLines.push_back(line);
2179			}
2180			break;
2181		}
2182
2183		default:
2184			DE_ASSERT(false);
2185	}
2186}
2187
2188float LineInterpolationTest::getLineWidth (void) const
2189{
2190	return m_lineWidths[m_iteration];
2191}
2192
2193} // anonymous
2194
2195RasterizationTests::RasterizationTests (Context& context)
2196	: TestCaseGroup(context, "rasterization", "Rasterization Tests")
2197{
2198}
2199
2200RasterizationTests::~RasterizationTests (void)
2201{
2202}
2203
2204void RasterizationTests::init (void)
2205{
2206	// .primitives
2207	{
2208		tcu::TestCaseGroup* const primitives = new tcu::TestCaseGroup(m_testCtx, "primitives", "Primitive rasterization");
2209
2210		addChild(primitives);
2211
2212		primitives->addChild(new TrianglesCase		(m_context, "triangles",		"Render primitives as GL_TRIANGLES, verify rasterization result"));
2213		primitives->addChild(new TriangleStripCase	(m_context, "triangle_strip",	"Render primitives as GL_TRIANGLE_STRIP, verify rasterization result"));
2214		primitives->addChild(new TriangleFanCase	(m_context, "triangle_fan",		"Render primitives as GL_TRIANGLE_FAN, verify rasterization result"));
2215		primitives->addChild(new LinesCase			(m_context, "lines",			"Render primitives as GL_LINES, verify rasterization result",							PRIMITIVEWIDENESS_NARROW));
2216		primitives->addChild(new LineStripCase		(m_context, "line_strip",		"Render primitives as GL_LINE_STRIP, verify rasterization result",						PRIMITIVEWIDENESS_NARROW));
2217		primitives->addChild(new LineLoopCase		(m_context, "line_loop",		"Render primitives as GL_LINE_LOOP, verify rasterization result",						PRIMITIVEWIDENESS_NARROW));
2218		primitives->addChild(new LinesCase			(m_context, "lines_wide",		"Render primitives as GL_LINES with wide lines, verify rasterization result",			PRIMITIVEWIDENESS_WIDE));
2219		primitives->addChild(new LineStripCase		(m_context, "line_strip_wide",	"Render primitives as GL_LINE_STRIP with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE));
2220		primitives->addChild(new LineLoopCase		(m_context, "line_loop_wide",	"Render primitives as GL_LINE_LOOP with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE));
2221		primitives->addChild(new PointCase			(m_context, "points",			"Render primitives as GL_POINTS, verify rasterization result",							PRIMITIVEWIDENESS_WIDE));
2222	}
2223
2224	// .fill_rules
2225	{
2226		tcu::TestCaseGroup* const fillRules = new tcu::TestCaseGroup(m_testCtx, "fill_rules", "Primitive fill rules");
2227
2228		addChild(fillRules);
2229
2230		fillRules->addChild(new FillRuleCase(m_context,	"basic_quad",			"Verify fill rules",	FillRuleCase::FILLRULECASE_BASIC));
2231		fillRules->addChild(new FillRuleCase(m_context,	"basic_quad_reverse",	"Verify fill rules",	FillRuleCase::FILLRULECASE_REVERSED));
2232		fillRules->addChild(new FillRuleCase(m_context,	"clipped_full",			"Verify fill rules",	FillRuleCase::FILLRULECASE_CLIPPED_FULL));
2233		fillRules->addChild(new FillRuleCase(m_context,	"clipped_partly",		"Verify fill rules",	FillRuleCase::FILLRULECASE_CLIPPED_PARTIAL));
2234		fillRules->addChild(new FillRuleCase(m_context,	"projected",			"Verify fill rules",	FillRuleCase::FILLRULECASE_PROJECTED));
2235	}
2236
2237	// .culling
2238	{
2239		static const struct CullMode
2240		{
2241			glw::GLenum	mode;
2242			const char*	prefix;
2243		} cullModes[] =
2244		{
2245			{ GL_FRONT,				"front_"	},
2246			{ GL_BACK,				"back_"		},
2247			{ GL_FRONT_AND_BACK,	"both_"		},
2248		};
2249		static const struct PrimitiveType
2250		{
2251			glw::GLenum	type;
2252			const char*	name;
2253		} primitiveTypes[] =
2254		{
2255			{ GL_TRIANGLES,			"triangles"			},
2256			{ GL_TRIANGLE_STRIP,	"triangle_strip"	},
2257			{ GL_TRIANGLE_FAN,		"triangle_fan"		},
2258		};
2259		static const struct FrontFaceOrder
2260		{
2261			glw::GLenum	mode;
2262			const char*	postfix;
2263		} frontOrders[] =
2264		{
2265			{ GL_CCW,	""			},
2266			{ GL_CW,	"_reverse"	},
2267		};
2268
2269		tcu::TestCaseGroup* const culling = new tcu::TestCaseGroup(m_testCtx, "culling", "Culling");
2270
2271		addChild(culling);
2272
2273		for (int cullModeNdx   = 0; cullModeNdx   < DE_LENGTH_OF_ARRAY(cullModes);      ++cullModeNdx)
2274		for (int primitiveNdx  = 0; primitiveNdx  < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveNdx)
2275		for (int frontOrderNdx = 0; frontOrderNdx < DE_LENGTH_OF_ARRAY(frontOrders);    ++frontOrderNdx)
2276		{
2277			const std::string name = std::string(cullModes[cullModeNdx].prefix) + primitiveTypes[primitiveNdx].name + frontOrders[frontOrderNdx].postfix;
2278
2279			culling->addChild(new CullingTest(m_context, name.c_str(), "Test primitive culling.", cullModes[cullModeNdx].mode, primitiveTypes[primitiveNdx].type, frontOrders[frontOrderNdx].mode));
2280		}
2281	}
2282
2283	// .interpolation
2284	{
2285		tcu::TestCaseGroup* const interpolation = new tcu::TestCaseGroup(m_testCtx, "interpolation", "Test interpolation");
2286
2287		addChild(interpolation);
2288
2289		// .basic
2290		{
2291			tcu::TestCaseGroup* const basic = new tcu::TestCaseGroup(m_testCtx, "basic", "Non-projective interpolation");
2292
2293			interpolation->addChild(basic);
2294
2295			basic->addChild(new TriangleInterpolationTest		(m_context, "triangles",		"Verify triangle interpolation",		GL_TRIANGLES,		INTERPOLATIONFLAGS_NONE));
2296			basic->addChild(new TriangleInterpolationTest		(m_context, "triangle_strip",	"Verify triangle strip interpolation",	GL_TRIANGLE_STRIP,	INTERPOLATIONFLAGS_NONE));
2297			basic->addChild(new TriangleInterpolationTest		(m_context, "triangle_fan",		"Verify triangle fan interpolation",	GL_TRIANGLE_FAN,	INTERPOLATIONFLAGS_NONE));
2298			basic->addChild(new LineInterpolationTest			(m_context, "lines",			"Verify line interpolation",			GL_LINES,			INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_NARROW));
2299			basic->addChild(new LineInterpolationTest			(m_context, "line_strip",		"Verify line strip interpolation",		GL_LINE_STRIP,		INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_NARROW));
2300			basic->addChild(new LineInterpolationTest			(m_context, "line_loop",		"Verify line loop interpolation",		GL_LINE_LOOP,		INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_NARROW));
2301			basic->addChild(new LineInterpolationTest			(m_context, "lines_wide",		"Verify wide line interpolation",		GL_LINES,			INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_WIDE));
2302			basic->addChild(new LineInterpolationTest			(m_context, "line_strip_wide",	"Verify wide line strip interpolation",	GL_LINE_STRIP,		INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_WIDE));
2303			basic->addChild(new LineInterpolationTest			(m_context, "line_loop_wide",	"Verify wide line loop interpolation",	GL_LINE_LOOP,		INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_WIDE));
2304		}
2305
2306		// .projected
2307		{
2308			tcu::TestCaseGroup* const projected = new tcu::TestCaseGroup(m_testCtx, "projected", "Projective interpolation");
2309
2310			interpolation->addChild(projected);
2311
2312			projected->addChild(new TriangleInterpolationTest	(m_context, "triangles",		"Verify triangle interpolation",		GL_TRIANGLES,		INTERPOLATIONFLAGS_PROJECTED));
2313			projected->addChild(new TriangleInterpolationTest	(m_context, "triangle_strip",	"Verify triangle strip interpolation",	GL_TRIANGLE_STRIP,	INTERPOLATIONFLAGS_PROJECTED));
2314			projected->addChild(new TriangleInterpolationTest	(m_context, "triangle_fan",		"Verify triangle fan interpolation",	GL_TRIANGLE_FAN,	INTERPOLATIONFLAGS_PROJECTED));
2315			projected->addChild(new LineInterpolationTest		(m_context, "lines",			"Verify line interpolation",			GL_LINES,			INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_NARROW));
2316			projected->addChild(new LineInterpolationTest		(m_context, "line_strip",		"Verify line strip interpolation",		GL_LINE_STRIP,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_NARROW));
2317			projected->addChild(new LineInterpolationTest		(m_context, "line_loop",		"Verify line loop interpolation",		GL_LINE_LOOP,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_NARROW));
2318			projected->addChild(new LineInterpolationTest		(m_context, "lines_wide",		"Verify wide line interpolation",		GL_LINES,			INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_WIDE));
2319			projected->addChild(new LineInterpolationTest		(m_context, "line_strip_wide",	"Verify wide line strip interpolation",	GL_LINE_STRIP,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_WIDE));
2320			projected->addChild(new LineInterpolationTest		(m_context, "line_loop_wide",	"Verify wide line loop interpolation",	GL_LINE_LOOP,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_WIDE));
2321		}
2322	}
2323
2324	// .flatshading
2325	{
2326		tcu::TestCaseGroup* const flatshading = new tcu::TestCaseGroup(m_testCtx, "flatshading", "Test flatshading");
2327
2328		addChild(flatshading);
2329
2330		flatshading->addChild(new TriangleInterpolationTest		(m_context, "triangles",		"Verify triangle flatshading",			GL_TRIANGLES,		INTERPOLATIONFLAGS_FLATSHADE));
2331		flatshading->addChild(new TriangleInterpolationTest		(m_context, "triangle_strip",	"Verify triangle strip flatshading",	GL_TRIANGLE_STRIP,	INTERPOLATIONFLAGS_FLATSHADE));
2332		flatshading->addChild(new TriangleInterpolationTest		(m_context, "triangle_fan",		"Verify triangle fan flatshading",		GL_TRIANGLE_FAN,	INTERPOLATIONFLAGS_FLATSHADE));
2333		flatshading->addChild(new LineInterpolationTest			(m_context, "lines",			"Verify line flatshading",				GL_LINES,			INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_NARROW));
2334		flatshading->addChild(new LineInterpolationTest			(m_context, "line_strip",		"Verify line strip flatshading",		GL_LINE_STRIP,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_NARROW));
2335		flatshading->addChild(new LineInterpolationTest			(m_context, "line_loop",		"Verify line loop flatshading",			GL_LINE_LOOP,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_NARROW));
2336		flatshading->addChild(new LineInterpolationTest			(m_context, "lines_wide",		"Verify wide line flatshading",			GL_LINES,			INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_WIDE));
2337		flatshading->addChild(new LineInterpolationTest			(m_context, "line_strip_wide",	"Verify wide line strip flatshading",	GL_LINE_STRIP,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_WIDE));
2338		flatshading->addChild(new LineInterpolationTest			(m_context, "line_loop_wide",	"Verify wide line loop flatshading",	GL_LINE_LOOP,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_WIDE));
2339	}
2340
2341	// .fbo
2342	{
2343		static const struct
2344		{
2345			const char*						name;
2346			BaseRenderingCase::RenderTarget	target;
2347			int								numSamples;
2348		} renderTargets[] =
2349		{
2350			{ "texture_2d",				BaseRenderingCase::RENDERTARGET_TEXTURE_2D,			-1									},
2351			{ "rbo_singlesample",		BaseRenderingCase::RENDERTARGET_RBO_SINGLESAMPLE,	-1									},
2352			{ "rbo_multisample_4",		BaseRenderingCase::RENDERTARGET_RBO_MULTISAMPLE,	4									},
2353			{ "rbo_multisample_max",	BaseRenderingCase::RENDERTARGET_RBO_MULTISAMPLE,	BaseRenderingCase::SAMPLE_COUNT_MAX	},
2354		};
2355
2356		tcu::TestCaseGroup* const fboGroup = new tcu::TestCaseGroup(m_testCtx, "fbo", "Test using framebuffer objects");
2357		addChild(fboGroup);
2358
2359		// .texture_2d
2360		// .rbo_singlesample
2361		// .rbo_multisample_4
2362		// .rbo_multisample_max
2363		for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(renderTargets); ++targetNdx)
2364		{
2365			tcu::TestCaseGroup* const colorAttachmentGroup = new tcu::TestCaseGroup(m_testCtx, renderTargets[targetNdx].name, ("Test using " + std::string(renderTargets[targetNdx].name) + " color attachment").c_str());
2366			fboGroup->addChild(colorAttachmentGroup);
2367
2368			// .primitives
2369			{
2370				tcu::TestCaseGroup* const primitiveGroup = new tcu::TestCaseGroup(m_testCtx, "primitives", "Primitive rasterization");
2371				colorAttachmentGroup->addChild(primitiveGroup);
2372
2373				primitiveGroup->addChild(new TrianglesCase	(m_context, "triangles",	"Render primitives as GL_TRIANGLES, verify rasterization result",											renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2374				primitiveGroup->addChild(new LinesCase		(m_context, "lines",		"Render primitives as GL_LINES, verify rasterization result",					PRIMITIVEWIDENESS_NARROW,	renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2375				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));
2376				primitiveGroup->addChild(new PointCase		(m_context, "points",		"Render primitives as GL_POINTS, verify rasterization result",					PRIMITIVEWIDENESS_WIDE,		renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2377			}
2378
2379			// .fill_rules
2380			{
2381				tcu::TestCaseGroup* const fillRules = new tcu::TestCaseGroup(m_testCtx, "fill_rules", "Primitive fill rules");
2382
2383				colorAttachmentGroup->addChild(fillRules);
2384
2385				fillRules->addChild(new FillRuleCase(m_context,	"basic_quad",			"Verify fill rules",	FillRuleCase::FILLRULECASE_BASIC,			renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2386				fillRules->addChild(new FillRuleCase(m_context,	"basic_quad_reverse",	"Verify fill rules",	FillRuleCase::FILLRULECASE_REVERSED,		renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2387				fillRules->addChild(new FillRuleCase(m_context,	"clipped_full",			"Verify fill rules",	FillRuleCase::FILLRULECASE_CLIPPED_FULL,	renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2388				fillRules->addChild(new FillRuleCase(m_context,	"clipped_partly",		"Verify fill rules",	FillRuleCase::FILLRULECASE_CLIPPED_PARTIAL,	renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2389				fillRules->addChild(new FillRuleCase(m_context,	"projected",			"Verify fill rules",	FillRuleCase::FILLRULECASE_PROJECTED,		renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2390			}
2391
2392			// .interpolation
2393			{
2394				tcu::TestCaseGroup* const interpolation = new tcu::TestCaseGroup(m_testCtx, "interpolation", "Non-projective interpolation");
2395
2396				colorAttachmentGroup->addChild(interpolation);
2397
2398				interpolation->addChild(new TriangleInterpolationTest		(m_context, "triangles",		"Verify triangle interpolation",		GL_TRIANGLES,		INTERPOLATIONFLAGS_NONE,								renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2399				interpolation->addChild(new LineInterpolationTest			(m_context, "lines",			"Verify line interpolation",			GL_LINES,			INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_NARROW,	renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2400				interpolation->addChild(new LineInterpolationTest			(m_context, "lines_wide",		"Verify wide line interpolation",		GL_LINES,			INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_WIDE,		renderTargets[targetNdx].target, renderTargets[targetNdx].numSamples));
2401			}
2402		}
2403	}
2404}
2405
2406} // Functional
2407} // gles3
2408} // deqp
2409