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