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