Home | History | Annotate | Download | only in functional
      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 
    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 
    119 BaseRenderingCase::~BaseRenderingCase (void)
    120 {
    121 	deinit();
    122 }
    123 
    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 
    177 void BaseRenderingCase::deinit (void)
    178 {
    179 	if (m_shader)
    180 	{
    181 		delete m_shader;
    182 		m_shader = DE_NULL;
    183 	}
    184 }
    185 
    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 
    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 
    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 
    246 BaseTriangleCase::~BaseTriangleCase (void)
    247 {
    248 }
    249 
    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 
    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 
    332 BaseLineCase::~BaseLineCase (void)
    333 {
    334 }
    335 
    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 
    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 
    434 PointCase::~PointCase (void)
    435 {
    436 }
    437 
    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 
    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 
    553 TrianglesCase::TrianglesCase (Context& context, const char* name, const char* desc)
    554 	: BaseTriangleCase(context, name, desc, GL_TRIANGLES)
    555 {
    556 }
    557 
    558 TrianglesCase::~TrianglesCase (void)
    559 {
    560 
    561 }
    562 
    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 
    629 TriangleStripCase::TriangleStripCase (Context& context, const char* name, const char* desc)
    630 	: BaseTriangleCase(context, name, desc, GL_TRIANGLE_STRIP)
    631 {
    632 }
    633 
    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 
    698 TriangleFanCase::TriangleFanCase (Context& context, const char* name, const char* desc)
    699 	: BaseTriangleCase(context, name, desc, GL_TRIANGLE_FAN)
    700 {
    701 }
    702 
    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 
    767 LinesCase::LinesCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness)
    768 	: BaseLineCase(context, name, desc, GL_LINES, wideness)
    769 {
    770 }
    771 
    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 
    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 
    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 
    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 
    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 
    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 
    992 FillRuleCase::~FillRuleCase (void)
    993 {
    994 	deinit();
    995 }
    996 
    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 
   1108 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 
   1116 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 
   1124 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 
   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 
   1249 CullingTest::~CullingTest (void)
   1250 {
   1251 }
   1252 
   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 
   1300 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 
   1314 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 
   1392 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 
   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 
   1431 TriangleInterpolationTest::~TriangleInterpolationTest (void)
   1432 {
   1433 	deinit();
   1434 }
   1435 
   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 
   1490 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 
   1527 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 
   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 
   1628 LineInterpolationTest::~LineInterpolationTest (void)
   1629 {
   1630 	deinit();
   1631 }
   1632 
   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 
   1717 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 
   1754 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 
   1813 RasterizationTests::RasterizationTests (Context& context)
   1814 	: TestCaseGroup(context, "rasterization", "Rasterization Tests")
   1815 {
   1816 }
   1817 
   1818 RasterizationTests::~RasterizationTests (void)
   1819 {
   1820 }
   1821 
   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