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