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