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