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