• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
getInternalFormatPixelFormat(glw::GLenum internalFormat)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 
BaseRenderingCase(Context & context,const char * name,const char * desc,RenderTarget target,int numSamples,int renderSize)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 
~BaseRenderingCase(void)169 BaseRenderingCase::~BaseRenderingCase (void)
170 {
171 	deinit();
172 }
173 
init(void)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 
deinit(void)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 
drawPrimitives(tcu::Surface & result,const std::vector<tcu::Vec4> & vertexData,glw::GLenum primitiveType)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 
drawPrimitives(tcu::Surface & result,const std::vector<tcu::Vec4> & vertexData,const std::vector<tcu::Vec4> & colorData,glw::GLenum primitiveType)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 
getLineWidth(void) const408 float BaseRenderingCase::getLineWidth (void) const
409 {
410 	return 1.0f;
411 }
412 
getPointSize(void) const413 float BaseRenderingCase::getPointSize (void) const
414 {
415 	return 1.0f;
416 }
417 
getPixelFormat(void) const418 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 
BaseTriangleCase(Context & context,const char * name,const char * desc,glw::GLenum primitiveDrawType,BaseRenderingCase::RenderTarget renderTarget,int numSamples)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 
~BaseTriangleCase(void)448 BaseTriangleCase::~BaseTriangleCase (void)
449 {
450 }
451 
iterate(void)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 
BaseLineCase(Context & context,const char * name,const char * desc,glw::GLenum primitiveDrawType,PrimitiveWideness wideness,BaseRenderingCase::RenderTarget renderTarget,int numSamples)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 
~BaseLineCase(void)535 BaseLineCase::~BaseLineCase (void)
536 {
537 }
538 
init(void)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 
iterate(void)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 
getLineWidth(void) const637 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 
PointCase(Context & context,const char * name,const char * desc,PrimitiveWideness wideness,BaseRenderingCase::RenderTarget renderTarget,int numSamples)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 
~PointCase(void)676 PointCase::~PointCase (void)
677 {
678 }
679 
init(void)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 
iterate(void)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 
getPointSize(void) const768 float PointCase::getPointSize (void) const
769 {
770 	return m_pointSizes[m_iteration];
771 }
772 
generatePoints(int iteration,std::vector<tcu::Vec4> & outData,std::vector<PointSceneSpec::ScenePoint> & outPoints)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 
TrianglesCase(Context & context,const char * name,const char * desc,BaseRenderingCase::RenderTarget renderTarget,int numSamples)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 
~TrianglesCase(void)835 TrianglesCase::~TrianglesCase (void)
836 {
837 
838 }
839 
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)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 
TriangleStripCase(Context & context,const char * name,const char * desc,BaseRenderingCase::RenderTarget renderTarget,int numSamples)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 
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)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 
TriangleFanCase(Context & context,const char * name,const char * desc,BaseRenderingCase::RenderTarget renderTarget,int numSamples)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 
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)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 
LinesCase(Context & context,const char * name,const char * desc,PrimitiveWideness wideness,BaseRenderingCase::RenderTarget renderTarget,int numSamples)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 
generateLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)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 
LineStripCase(Context & context,const char * name,const char * desc,PrimitiveWideness wideness,BaseRenderingCase::RenderTarget renderTarget,int numSamples)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 
generateLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)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 
LineLoopCase(Context & context,const char * name,const char * desc,PrimitiveWideness wideness,BaseRenderingCase::RenderTarget renderTarget,int numSamples)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 
generateLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)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 
FillRuleCase(Context & ctx,const char * name,const char * desc,FillRuleCaseType type,RenderTarget renderTarget,int numSamples)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 
~FillRuleCase(void)1269 FillRuleCase::~FillRuleCase (void)
1270 {
1271 	deinit();
1272 }
1273 
iterate(void)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 
getRenderSize(FillRuleCase::FillRuleCaseType type) const1385 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 
getNumIterations(FillRuleCase::FillRuleCaseType type) const1393 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 
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData) const1401 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 
CullingTest(Context & ctx,const char * name,const char * desc,glw::GLenum cullMode,glw::GLenum primitive,glw::GLenum faceOrder)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 
~CullingTest(void)1526 CullingTest::~CullingTest (void)
1527 {
1528 }
1529 
iterate(void)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 
generateVertices(std::vector<tcu::Vec4> & outData) const1577 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 
extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles,const std::vector<tcu::Vec4> & vertices) const1591 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 
triangleOrder(const tcu::Vec4 & v0,const tcu::Vec4 & v1,const tcu::Vec4 & v2) const1669 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 
TriangleInterpolationTest(Context & ctx,const char * name,const char * desc,glw::GLenum primitive,int flags,RenderTarget renderTarget,int numSamples)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 
~TriangleInterpolationTest(void)1709 TriangleInterpolationTest::~TriangleInterpolationTest (void)
1710 {
1711 	deinit();
1712 }
1713 
iterate(void)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 
generateVertices(int iteration,std::vector<tcu::Vec4> & outVertices,std::vector<tcu::Vec4> & outColors) const1768 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 
extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles,const std::vector<tcu::Vec4> & vertices,const std::vector<tcu::Vec4> & colors) const1805 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 
LineInterpolationTest(Context & ctx,const char * name,const char * desc,glw::GLenum primitive,int flags,PrimitiveWideness wideness,RenderTarget renderTarget,int numSamples)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 
~LineInterpolationTest(void)1941 LineInterpolationTest::~LineInterpolationTest (void)
1942 {
1943 	deinit();
1944 }
1945 
init(void)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 
iterate(void)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 
generateVertices(int iteration,std::vector<tcu::Vec4> & outVertices,std::vector<tcu::Vec4> & outColors) const2070 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 
extractLines(std::vector<LineSceneSpec::SceneLine> & outLines,const std::vector<tcu::Vec4> & vertices,const std::vector<tcu::Vec4> & colors) const2107 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 
getLineWidth(void) const2188 float LineInterpolationTest::getLineWidth (void) const
2189 {
2190 	return m_lineWidths[m_iteration];
2191 }
2192 
2193 } // anonymous
2194 
RasterizationTests(Context & context)2195 RasterizationTests::RasterizationTests (Context& context)
2196 	: TestCaseGroup(context, "rasterization", "Rasterization Tests")
2197 {
2198 }
2199 
~RasterizationTests(void)2200 RasterizationTests::~RasterizationTests (void)
2201 {
2202 }
2203 
init(void)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