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