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