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