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