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