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