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