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