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 Polygon offset tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es2fPolygonOffsetTests.hpp"
25#include "deStringUtil.hpp"
26#include "deRandom.hpp"
27#include "gluContextInfo.hpp"
28#include "gluRenderContext.hpp"
29#include "gluShaderProgram.hpp"
30#include "gluPixelTransfer.hpp"
31#include "gluStrUtil.hpp"
32#include "glwEnums.hpp"
33#include "glwDefs.hpp"
34#include "glwFunctions.hpp"
35#include "tcuTestContext.hpp"
36#include "tcuTestLog.hpp"
37#include "tcuTextureUtil.hpp"
38#include "tcuRenderTarget.hpp"
39#include "tcuVectorUtil.hpp"
40#include "rrRenderer.hpp"
41#include "rrFragmentOperations.hpp"
42
43#include "sglrReferenceContext.hpp"
44
45#include <string>
46#include <limits>
47
48using namespace glw; // GLint and other GL types
49
50namespace deqp
51{
52namespace gles2
53{
54namespace Functional
55{
56namespace
57{
58
59const char* s_shaderSourceVertex	= "attribute highp vec4 a_position;\n"
60									  "attribute highp vec4 a_color;\n"
61									  "varying mediump vec4 v_color;\n"
62									  "void main (void)\n"
63									  "{\n"
64									  "	gl_Position = a_position;\n"
65									  "	v_color = a_color;\n"
66									  "}\n";
67const char* s_shaderSourceFragment	= "varying mediump vec4 v_color;\n"
68									  "void main (void)\n"
69									  "{\n"
70									  "	gl_FragColor = v_color;\n"
71									  "}\n";
72
73static const tcu::Vec4	MASK_COLOR_OK	= tcu::Vec4(0.0f, 0.1f, 0.0f, 1.0f);
74static const tcu::Vec4	MASK_COLOR_DEV	= tcu::Vec4(0.8f, 0.5f, 0.0f, 1.0f);
75static const tcu::Vec4	MASK_COLOR_FAIL	= tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f);
76
77inline bool compareThreshold (const tcu::IVec4& a, const tcu::IVec4& b, const tcu::IVec4& threshold)
78{
79	return tcu::boolAll(tcu::lessThanEqual(tcu::abs(a - b), threshold));
80}
81
82/*--------------------------------------------------------------------*//*!
83* \brief Pixelwise comparison of two images.
84* \note copied & modified from glsRasterizationTests
85*
86* Kernel radius defines maximum allowed distance. If radius is 0, only
87* perfect match is allowed. Radius of 1 gives a 3x3 kernel.
88*
89* Return values: -1 = Perfect match
90* 0 = Deviation within kernel
91* >0 = Number of faulty pixels
92*//*--------------------------------------------------------------------*/
93int compareImages (tcu::TestLog& log, glu::RenderContext& renderCtx, const tcu::ConstPixelBufferAccess& test, const tcu::ConstPixelBufferAccess& ref, const tcu::PixelBufferAccess& diffMask, int radius)
94{
95	const int			height			= test.getHeight();
96	const int			width			= test.getWidth();
97	const int			colorThreshold	= 128;
98	const tcu::RGBA		formatThreshold	= renderCtx.getRenderTarget().getPixelFormat().getColorThreshold();
99	const tcu::IVec4	threshold		= tcu::IVec4(colorThreshold, colorThreshold, colorThreshold, formatThreshold.getAlpha() > 0 ? colorThreshold : 0)
100										+ tcu::IVec4(formatThreshold.getRed(), formatThreshold.getGreen(), formatThreshold.getBlue(), formatThreshold.getAlpha());
101
102	int			deviatingPixels = 0;
103	int			faultyPixels	= 0;
104	int			compareFailed	= -1;
105
106	tcu::clear(diffMask, MASK_COLOR_OK);
107
108	for (int y = 0; y < height; y++)
109	{
110		for (int x = 0; x < width; x++)
111		{
112			const tcu::IVec4 cRef = ref.getPixelInt(x, y);
113
114			// Pixelwise match, no deviation or fault
115			{
116				const tcu::IVec4 cTest = test.getPixelInt(x, y);
117				if (compareThreshold(cRef, cTest, threshold))
118					continue;
119			}
120
121			// If not, search within kernel radius
122			{
123				const int kYmin = deMax32(y - radius, 0);
124				const int kYmax = deMin32(y + radius, height-1);
125				const int kXmin = deMax32(x - radius, 0);
126				const int kXmax = deMin32(x + radius, width-1);
127				bool found = false;
128
129				for (int kY = kYmin; kY <= kYmax; kY++)
130				for (int kX = kXmin; kX <= kXmax; kX++)
131				{
132					const tcu::IVec4 cTest = test.getPixelInt(kX, kY);
133					if (compareThreshold(cRef, cTest, threshold))
134						found = true;
135				}
136
137				if (found)	// The pixel is deviating if the color is found inside the kernel
138				{
139					diffMask.setPixel(MASK_COLOR_DEV, x, y);
140					if (compareFailed == -1)
141						compareFailed = 0;
142					deviatingPixels++;
143					continue;
144				}
145			}
146
147			diffMask.setPixel(MASK_COLOR_FAIL, x, y);
148			faultyPixels++;										// The pixel is faulty if the color is not found
149			compareFailed = 1;
150		}
151	}
152
153	log << tcu::TestLog::Message << faultyPixels << " faulty pixel(s) found." << tcu::TestLog::EndMessage;
154
155	return (compareFailed == 1 ? faultyPixels : compareFailed);
156}
157
158void verifyImages (tcu::TestLog& log, tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const tcu::ConstPixelBufferAccess& testImage, const tcu::ConstPixelBufferAccess& referenceImage)
159{
160	using tcu::TestLog;
161
162	const int			kernelRadius		= 1;
163	const int			faultyPixelLimit	= 20;
164	int					faultyPixels;
165	tcu::Surface		diffMask			(testImage.getWidth(), testImage.getHeight());
166
167	faultyPixels = compareImages(log, renderCtx, referenceImage, testImage, diffMask.getAccess(), kernelRadius);
168
169	if (faultyPixels > faultyPixelLimit)
170	{
171		log << TestLog::ImageSet("Images", "Image comparison");
172		log << TestLog::Image("Test image", "Test image", testImage);
173		log << TestLog::Image("Reference image", "Reference image", referenceImage);
174		log << TestLog::Image("Difference mask", "Difference mask", diffMask.getAccess());
175		log << TestLog::EndImageSet;
176
177		log << tcu::TestLog::Message << "Got " << faultyPixels << " faulty pixel(s)." << tcu::TestLog::EndMessage;
178		testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got faulty pixels");
179	}
180}
181
182void verifyError (tcu::TestContext& testCtx, const glw::Functions& gl, GLenum expected)
183{
184	deUint32 got = gl.getError();
185	if (got != expected)
186	{
187		testCtx.getLog() << tcu::TestLog::Message << "// ERROR: expected " << glu::getErrorStr(expected) << "; got " << glu::getErrorStr(got) << tcu::TestLog::EndMessage;
188		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
189			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid error");
190	}
191}
192
193void checkCanvasSize (int width, int height, int minWidth, int minHeight)
194{
195	if (width < minWidth || height < minHeight)
196		throw tcu::NotSupportedError(std::string("Render context size must be at least ") + de::toString(minWidth) + "x" + de::toString(minWidth));
197}
198
199class PositionColorShader : public sglr::ShaderProgram
200{
201public:
202	enum
203	{
204		VARYINGLOC_COLOR = 0
205	};
206
207			PositionColorShader (void);
208	void	shadeVertices		(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
209	void	shadeFragments		(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
210};
211
212PositionColorShader::PositionColorShader (void)
213	: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
214							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
215							<< sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
216							<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
217							<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
218							<< sglr::pdec::VertexSource(s_shaderSourceVertex)
219							<< sglr::pdec::FragmentSource(s_shaderSourceFragment))
220{
221}
222
223void PositionColorShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
224{
225	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
226	{
227		const int positionAttrLoc = 0;
228		const int colorAttrLoc = 1;
229
230		rr::VertexPacket& packet = *packets[packetNdx];
231
232		// Transform to position
233		packet.position = rr::readVertexAttribFloat(inputs[positionAttrLoc], packet.instanceNdx, packet.vertexNdx);
234
235		// Pass color to FS
236		packet.outputs[VARYINGLOC_COLOR] = rr::readVertexAttribFloat(inputs[colorAttrLoc], packet.instanceNdx, packet.vertexNdx);
237	}
238}
239
240void PositionColorShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
241{
242	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
243	{
244		rr::FragmentPacket& packet = packets[packetNdx];
245
246		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
247			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readTriangleVarying<float>(packet, context, VARYINGLOC_COLOR, fragNdx));
248	}
249}
250
251// PolygonOffsetTestCase
252
253class PolygonOffsetTestCase : public TestCase
254{
255public:
256					PolygonOffsetTestCase	(Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName, int canvasSize);
257
258	virtual void	testPolygonOffset		(void) = DE_NULL;
259	IterateResult	iterate					(void);
260
261protected:
262	const GLenum	m_internalFormat;
263	const char*		m_internalFormatName;
264	const int		m_targetSize;
265};
266
267PolygonOffsetTestCase::PolygonOffsetTestCase (Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName, int canvasSize)
268	: TestCase				(context, name, description)
269	, m_internalFormat		(internalFormat)
270	, m_internalFormatName	(internalFormatName)
271	, m_targetSize			(canvasSize)
272{
273}
274
275PolygonOffsetTestCase::IterateResult PolygonOffsetTestCase::iterate (void)
276{
277	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
278	m_testCtx.getLog() << tcu::TestLog::Message << "Testing PolygonOffset with " << m_internalFormatName << " depth buffer." << tcu::TestLog::EndMessage;
279
280	if (m_internalFormat == 0)
281	{
282		// default framebuffer
283		const int width		= m_context.getRenderTarget().getWidth();
284		const int height	= m_context.getRenderTarget().getHeight();
285
286		checkCanvasSize(width, height, m_targetSize, m_targetSize);
287
288		if (m_context.getRenderTarget().getDepthBits() == 0)
289			throw tcu::NotSupportedError("polygon offset tests require depth buffer");
290
291		testPolygonOffset();
292	}
293	else
294	{
295		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
296
297		// framebuffer object
298		GLuint	colorRboId	= 0;
299		GLuint	depthRboId	= 0;
300		GLuint	fboId		= 0;
301		bool	fboComplete;
302
303		gl.genRenderbuffers(1, &colorRboId);
304		gl.bindRenderbuffer(GL_RENDERBUFFER, colorRboId);
305		gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, m_targetSize, m_targetSize);
306		verifyError(m_testCtx, gl, GL_NO_ERROR);
307
308		gl.genRenderbuffers(1, &depthRboId);
309		gl.bindRenderbuffer(GL_RENDERBUFFER, depthRboId);
310		gl.renderbufferStorage(GL_RENDERBUFFER, m_internalFormat, m_targetSize, m_targetSize);
311		verifyError(m_testCtx, gl, GL_NO_ERROR);
312
313		gl.genFramebuffers(1, &fboId);
314		gl.bindFramebuffer(GL_FRAMEBUFFER, fboId);
315		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRboId);
316		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,	GL_RENDERBUFFER, depthRboId);
317		verifyError(m_testCtx, gl, GL_NO_ERROR);
318
319		fboComplete = gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
320
321		if (fboComplete)
322			testPolygonOffset();
323
324		gl.deleteFramebuffers(1, &fboId);
325		gl.deleteRenderbuffers(1, &depthRboId);
326		gl.deleteRenderbuffers(1, &colorRboId);
327
328		if (!fboComplete)
329			throw tcu::NotSupportedError("could not create fbo for testing.");
330	}
331
332	return STOP;
333}
334
335// UsageTestCase
336
337class UsageTestCase : public PolygonOffsetTestCase
338{
339public:
340			UsageTestCase		(Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName);
341
342	void	testPolygonOffset	(void);
343};
344
345UsageTestCase::UsageTestCase (Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName)
346	: PolygonOffsetTestCase(context, name, description, internalFormat, internalFormatName, 200)
347{
348}
349
350void UsageTestCase::testPolygonOffset (void)
351{
352	using tcu::TestLog;
353
354	const tcu::Vec4 triangle[] =
355	{
356		tcu::Vec4(-1,  1,  0,  1),
357		tcu::Vec4( 1,  1,  0,  1),
358		tcu::Vec4( 1, -1,  0,  1),
359	};
360
361	tcu::TestLog&		log				= m_testCtx.getLog();
362	tcu::Surface		testImage		(m_targetSize, m_targetSize);
363	tcu::Surface		referenceImage	(m_targetSize, m_targetSize);
364
365	// render test image
366	{
367		const glw::Functions&		gl			= m_context.getRenderContext().getFunctions();
368		const glu::ShaderProgram	program		(m_context.getRenderContext(), glu::makeVtxFragSources(s_shaderSourceVertex, s_shaderSourceFragment));
369		const GLint					positionLoc = gl.getAttribLocation(program.getProgram(), "a_position");
370		const GLint					colorLoc	= gl.getAttribLocation(program.getProgram(), "a_color");
371
372		if (!program.isOk())
373		{
374			log << program;
375			TCU_FAIL("Shader compile failed.");
376		}
377
378		gl.clearColor				(0, 0, 0, 1);
379		gl.clearDepthf				(1.0f);
380		gl.clear					(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
381		gl.viewport					(0, 0, m_targetSize, m_targetSize);
382		gl.useProgram				(program.getProgram());
383		gl.enable					(GL_DEPTH_TEST);
384		gl.depthFunc				(GL_LEQUAL);	// make test pass if polygon offset doesn't do anything. It has its own test case. This test is only for to detect always-on cases.
385
386		log << TestLog::Message << "DepthFunc = GL_LEQUAL" << TestLog::EndMessage;
387
388		gl.enableVertexAttribArray	(positionLoc);
389		gl.vertexAttribPointer		(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangle);
390
391		//draw back (offset disabled)
392
393		log << TestLog::Message << "Draw bottom-right. Color = White.\tState: PolygonOffset(0, -2), POLYGON_OFFSET_FILL disabled." << TestLog::EndMessage;
394
395		gl.polygonOffset			(0, -2);
396		gl.disable					(GL_POLYGON_OFFSET_FILL);
397		gl.vertexAttrib4f			(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
398		gl.drawArrays				(GL_TRIANGLES, 0, 3);
399
400		//draw front
401
402		log << TestLog::Message << "Draw bottom-right. Color = Red.\tState: PolygonOffset(0, -1), POLYGON_OFFSET_FILL enabled." << TestLog::EndMessage;
403
404		gl.polygonOffset			(0, -1);
405		gl.enable					(GL_POLYGON_OFFSET_FILL);
406		gl.vertexAttrib4f			(colorLoc, 1.0f, 0.0f, 0.0f, 1.0f);
407		gl.drawArrays				(GL_TRIANGLES, 0, 3);
408
409		gl.disableVertexAttribArray	(positionLoc);
410		gl.useProgram				(0);
411		gl.finish					();
412
413		glu::readPixels(m_context.getRenderContext(), 0, 0, testImage.getAccess());
414	}
415
416	// render reference image
417	{
418		rr::Renderer		referenceRenderer;
419		rr::VertexAttrib	attribs[2];
420		rr::RenderState		state((rr::ViewportState)(rr::WindowRectangle(0, 0, m_targetSize, m_targetSize)));
421
422		PositionColorShader program;
423
424		attribs[0].type				= rr::VERTEXATTRIBTYPE_FLOAT;
425		attribs[0].size				= 4;
426		attribs[0].stride			= 0;
427		attribs[0].instanceDivisor	= 0;
428		attribs[0].pointer			= triangle;
429
430		attribs[1].type				= rr::VERTEXATTRIBTYPE_DONT_CARE;
431		attribs[1].generic			= tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
432
433		tcu::clear(referenceImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
434
435		log << TestLog::Message << "Expecting: Bottom-right = Red." << TestLog::EndMessage;
436
437		referenceRenderer.draw(
438			rr::DrawCommand(
439				state,
440				rr::RenderTarget(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(referenceImage.getAccess())),
441				rr::Program(program.getVertexShader(), program.getFragmentShader()),
442				2,
443				attribs,
444				rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, 3, 0)));
445	}
446
447	// compare
448	verifyImages(log, m_testCtx, m_context.getRenderContext(), testImage.getAccess(), referenceImage.getAccess());
449}
450
451// UsageDisplacementTestCase
452
453class UsageDisplacementTestCase : public PolygonOffsetTestCase
454{
455public:
456				UsageDisplacementTestCase	(Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName);
457
458private:
459	tcu::Vec4	genRandomVec4				(de::Random& rnd) const;
460	void		testPolygonOffset			(void);
461};
462
463UsageDisplacementTestCase::UsageDisplacementTestCase (Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName)
464	: PolygonOffsetTestCase(context, name, description, internalFormat, internalFormatName, 200)
465{
466}
467
468tcu::Vec4 UsageDisplacementTestCase::genRandomVec4 (de::Random& rnd) const
469{
470	// generater triangle endpoint with following properties
471	//	1) it will not be clipped
472	//	2) it is not near either far or near plane to prevent possible problems related to depth clamping
473	// => w >= 1.0 and z in (-0.9, 0.9) range
474	tcu::Vec4 retVal;
475
476	retVal.x() = rnd.getFloat(-1, 1);
477	retVal.y() = rnd.getFloat(-1, 1);
478	retVal.z() = rnd.getFloat(-0.9f, 0.9f);
479	retVal.w() = 1.0f + rnd.getFloat();
480
481	return retVal;
482}
483
484void UsageDisplacementTestCase::testPolygonOffset (void)
485{
486	using tcu::TestLog;
487
488	de::Random			rnd				(0xdec0de);
489	tcu::TestLog&		log				= m_testCtx.getLog();
490	tcu::Surface		testImage		(m_targetSize, m_targetSize);
491	tcu::Surface		referenceImage	(m_targetSize, m_targetSize);
492
493	// render test image
494	{
495		const glw::Functions&		gl				= m_context.getRenderContext().getFunctions();
496		const glu::ShaderProgram	program			(m_context.getRenderContext(), glu::makeVtxFragSources(s_shaderSourceVertex, s_shaderSourceFragment));
497		const GLint					positionLoc		= gl.getAttribLocation(program.getProgram(), "a_position");
498		const GLint					colorLoc		= gl.getAttribLocation(program.getProgram(), "a_color");
499		const int					numIterations	= 40;
500
501		if (!program.isOk())
502		{
503			log << program;
504			TCU_FAIL("Shader compile failed.");
505		}
506
507		gl.clearColor				(0, 0, 0, 1);
508		gl.clearDepthf				(1.0f);
509		gl.clear					(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
510		gl.viewport					(0, 0, m_targetSize, m_targetSize);
511		gl.useProgram				(program.getProgram());
512		gl.enable					(GL_DEPTH_TEST);
513		gl.enable					(GL_POLYGON_OFFSET_FILL);
514		gl.enableVertexAttribArray	(positionLoc);
515		gl.vertexAttrib4f			(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
516
517		log << TestLog::Message << "Framebuffer cleared, clear color = Black." << TestLog::EndMessage;
518		log << TestLog::Message << "POLYGON_OFFSET_FILL enabled." << TestLog::EndMessage;
519
520		// draw colorless (mask = 0,0,0) triangle at random* location, set offset and render green triangle with depthfunc = equal
521		// *) w >= 1.0 and z in (-1, 1) range
522		for (int iterationNdx = 0; iterationNdx < numIterations; ++iterationNdx)
523		{
524			const bool		offsetDirection = rnd.getBool();
525			const float		offset = offsetDirection ? -1.0f : 1.0f;
526			tcu::Vec4		triangle[3];
527
528			for (int vertexNdx = 0; vertexNdx < DE_LENGTH_OF_ARRAY(triangle); ++vertexNdx)
529				triangle[vertexNdx] = genRandomVec4(rnd);
530
531			gl.vertexAttribPointer		(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangle);
532
533			log << TestLog::Message << "Setup triangle with random coordinates:" << TestLog::EndMessage;
534			for (size_t ndx = 0; ndx < DE_LENGTH_OF_ARRAY(triangle); ++ndx)
535				log << TestLog::Message
536						<< "\tx=" << triangle[ndx].x()
537						<< "\ty=" << triangle[ndx].y()
538						<< "\tz=" << triangle[ndx].z()
539						<< "\tw=" << triangle[ndx].w()
540						<< TestLog::EndMessage;
541
542			log << TestLog::Message << "Draw colorless triangle.\tState: DepthFunc = GL_ALWAYS, PolygonOffset(0, 0)." << TestLog::EndMessage;
543
544			gl.depthFunc				(GL_ALWAYS);
545			gl.polygonOffset			(0, 0);
546			gl.colorMask				(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
547			gl.drawArrays				(GL_TRIANGLES, 0, 3);
548
549			// all fragments should have different Z => DepthFunc == GL_EQUAL fails with every fragment
550
551			log << TestLog::Message << "Draw green triangle.\tState: DepthFunc = GL_EQUAL, PolygonOffset(0, " << offset << ")." << TestLog::EndMessage;
552
553			gl.depthFunc				(GL_EQUAL);
554			gl.polygonOffset			(0, offset);
555			gl.colorMask				(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
556			gl.drawArrays				(GL_TRIANGLES, 0, 3);
557
558			log << TestLog::Message << TestLog::EndMessage; // empty line for clarity
559		}
560
561		gl.disableVertexAttribArray	(positionLoc);
562		gl.useProgram				(0);
563		gl.finish					();
564
565		glu::readPixels(m_context.getRenderContext(), 0, 0, testImage.getAccess());
566	}
567
568	// render reference image
569	log << TestLog::Message << "Expecting black framebuffer." << TestLog::EndMessage;
570	tcu::clear(referenceImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
571
572	// compare
573	verifyImages(log, m_testCtx, m_context.getRenderContext(), testImage.getAccess(), referenceImage.getAccess());
574}
575
576// UsagePositiveNegativeTestCase
577
578class UsagePositiveNegativeTestCase : public PolygonOffsetTestCase
579{
580public:
581			UsagePositiveNegativeTestCase	(Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName);
582
583	void	testPolygonOffset				(void);
584};
585
586UsagePositiveNegativeTestCase::UsagePositiveNegativeTestCase (Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName)
587	: PolygonOffsetTestCase(context, name, description, internalFormat, internalFormatName, 200)
588{
589}
590
591void UsagePositiveNegativeTestCase::testPolygonOffset (void)
592{
593	using tcu::TestLog;
594
595	const tcu::Vec4 triangleBottomRight[] =
596	{
597		tcu::Vec4(-1,  1,  0,  1),
598		tcu::Vec4( 1,  1,  0,  1),
599		tcu::Vec4( 1, -1,  0,  1),
600	};
601	const tcu::Vec4 triangleTopLeft[] =
602	{
603		tcu::Vec4(-1, -1,  0,  1),
604		tcu::Vec4(-1,  1,  0,  1),
605		tcu::Vec4( 1, -1,  0,  1),
606	};
607
608	tcu::TestLog&		log				= m_testCtx.getLog();
609	tcu::Surface		testImage		(m_targetSize, m_targetSize);
610	tcu::Surface		referenceImage	(m_targetSize, m_targetSize);
611
612	// render test image
613	{
614		const glw::Functions&		gl				= m_context.getRenderContext().getFunctions();
615		const glu::ShaderProgram	program			(m_context.getRenderContext(), glu::makeVtxFragSources(s_shaderSourceVertex, s_shaderSourceFragment));
616		const GLint					positionLoc		= gl.getAttribLocation(program.getProgram(), "a_position");
617		const GLint					colorLoc		= gl.getAttribLocation(program.getProgram(), "a_color");
618
619		if (!program.isOk())
620		{
621			log << program;
622			TCU_FAIL("Shader compile failed.");
623		}
624
625		gl.clearColor				(0, 0, 0, 1);
626		gl.clearDepthf				(1.0f);
627		gl.clear					(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
628		gl.viewport					(0, 0, m_targetSize, m_targetSize);
629		gl.depthFunc				(GL_LESS);
630		gl.useProgram				(program.getProgram());
631		gl.enable					(GL_DEPTH_TEST);
632		gl.enable					(GL_POLYGON_OFFSET_FILL);
633		gl.enableVertexAttribArray	(positionLoc);
634
635		log << TestLog::Message << "DepthFunc = GL_LESS." << TestLog::EndMessage;
636		log << TestLog::Message << "POLYGON_OFFSET_FILL enabled." << TestLog::EndMessage;
637
638		//draw top left (negative offset test)
639		{
640			gl.vertexAttribPointer		(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangleTopLeft);
641
642			log << TestLog::Message << "Draw top-left. Color = White.\tState: PolygonOffset(0, 0)." << TestLog::EndMessage;
643
644			gl.polygonOffset			(0, 0);
645			gl.vertexAttrib4f			(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
646			gl.drawArrays				(GL_TRIANGLES, 0, 3);
647
648			log << TestLog::Message << "Draw top-left. Color = Green.\tState: PolygonOffset(0, -1)." << TestLog::EndMessage;
649
650			gl.polygonOffset			(0, -1);
651			gl.vertexAttrib4f			(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
652			gl.drawArrays				(GL_TRIANGLES, 0, 3);
653		}
654
655		//draw bottom right (positive offset test)
656		{
657			gl.vertexAttribPointer		(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangleBottomRight);
658
659			log << TestLog::Message << "Draw bottom-right. Color = White.\tState: PolygonOffset(0, 1)." << TestLog::EndMessage;
660
661			gl.polygonOffset			(0, 1);
662			gl.vertexAttrib4f			(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
663			gl.drawArrays				(GL_TRIANGLES, 0, 3);
664
665			log << TestLog::Message << "Draw bottom-right. Color = Yellow.\tState: PolygonOffset(0, 0)." << TestLog::EndMessage;
666
667			gl.polygonOffset			(0, 0);
668			gl.vertexAttrib4f			(colorLoc, 1.0f, 1.0f, 0.0f, 1.0f);
669			gl.drawArrays				(GL_TRIANGLES, 0, 3);
670		}
671
672		gl.disableVertexAttribArray	(positionLoc);
673		gl.useProgram				(0);
674		gl.finish					();
675
676		glu::readPixels(m_context.getRenderContext(), 0, 0, testImage.getAccess());
677	}
678
679	// render reference image
680	{
681		rr::Renderer		referenceRenderer;
682		rr::VertexAttrib	attribs[2];
683		rr::RenderState		state((rr::ViewportState)(rr::WindowRectangle(0, 0, m_targetSize, m_targetSize)));
684
685		PositionColorShader program;
686
687		attribs[0].type				= rr::VERTEXATTRIBTYPE_FLOAT;
688		attribs[0].size				= 4;
689		attribs[0].stride			= 0;
690		attribs[0].instanceDivisor	= 0;
691		attribs[0].pointer			= triangleTopLeft;
692
693		attribs[1].type				= rr::VERTEXATTRIBTYPE_DONT_CARE;
694		attribs[1].generic			= tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
695
696		tcu::clear(referenceImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
697
698		log << TestLog::Message << "Expecting: Top-left = Green, Bottom-right = Yellow." << TestLog::EndMessage;
699
700		referenceRenderer.draw(
701			rr::DrawCommand(
702				state,
703				rr::RenderTarget(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(referenceImage.getAccess())),
704				rr::Program(program.getVertexShader(), program.getFragmentShader()),
705				2,
706				attribs,
707				rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, 3, 0)));
708
709		attribs[0].pointer = triangleBottomRight;
710		attribs[1].generic = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
711
712		referenceRenderer.draw(
713			rr::DrawCommand(
714				state,
715				rr::RenderTarget(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(referenceImage.getAccess())),
716				rr::Program(program.getVertexShader(), program.getFragmentShader()),
717				2,
718				attribs,
719				rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, 3, 0)));
720	}
721
722	// compare
723	verifyImages(log, m_testCtx, m_context.getRenderContext(), testImage.getAccess(), referenceImage.getAccess());
724}
725
726// ResultClampingTestCase
727
728class ResultClampingTestCase : public PolygonOffsetTestCase
729{
730public:
731			ResultClampingTestCase	(Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName);
732
733	void	testPolygonOffset		(void);
734};
735
736ResultClampingTestCase::ResultClampingTestCase (Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName)
737	: PolygonOffsetTestCase(context, name, description, internalFormat, internalFormatName, 200)
738{
739}
740
741void ResultClampingTestCase::testPolygonOffset (void)
742{
743	using tcu::TestLog;
744
745	const tcu::Vec4 triangleBottomRight[] =
746	{
747		tcu::Vec4(-1,  1,  1,  1),
748		tcu::Vec4( 1,  1,  1,  1),
749		tcu::Vec4( 1, -1,  1,  1),
750	};
751	const tcu::Vec4 triangleTopLeft[] =
752	{
753		tcu::Vec4(-1, -1, -1,  1),
754		tcu::Vec4(-1,  1, -1,  1),
755		tcu::Vec4( 1, -1, -1,  1),
756	};
757
758	tcu::TestLog&		log				= m_testCtx.getLog();
759	tcu::Surface		testImage		(m_targetSize, m_targetSize);
760	tcu::Surface		referenceImage	(m_targetSize, m_targetSize);
761
762	// render test image
763	{
764		const glw::Functions&		gl			= m_context.getRenderContext().getFunctions();
765		const glu::ShaderProgram	program		(m_context.getRenderContext(), glu::makeVtxFragSources(s_shaderSourceVertex, s_shaderSourceFragment));
766		const GLint					positionLoc = gl.getAttribLocation(program.getProgram(), "a_position");
767		const GLint					colorLoc	= gl.getAttribLocation(program.getProgram(), "a_color");
768
769		if (!program.isOk())
770		{
771			log << program;
772			TCU_FAIL("Shader compile failed.");
773		}
774
775		gl.clearColor				(0, 0, 0, 1);
776		gl.clearDepthf				(1.0f);
777		gl.clear					(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
778		gl.viewport					(0, 0, m_targetSize, m_targetSize);
779		gl.useProgram				(program.getProgram());
780		gl.enable					(GL_DEPTH_TEST);
781		gl.enable					(GL_POLYGON_OFFSET_FILL);
782		gl.enableVertexAttribArray	(positionLoc);
783
784		log << TestLog::Message << "POLYGON_OFFSET_FILL enabled." << TestLog::EndMessage;
785
786		//draw bottom right (far)
787		{
788			gl.vertexAttribPointer		(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangleBottomRight);
789
790			log << TestLog::Message << "Draw bottom-right. Color = White.\tState: DepthFunc = ALWAYS, PolygonOffset(0, 8), Polygon Z = 1.0. (Result depth should clamp to 1.0)." << TestLog::EndMessage;
791
792			gl.depthFunc				(GL_ALWAYS);
793			gl.polygonOffset			(0, 8);
794			gl.vertexAttrib4f			(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
795			gl.drawArrays				(GL_TRIANGLES, 0, 3);
796
797			log << TestLog::Message << "Draw bottom-right. Color = Red.\tState: DepthFunc = GREATER, PolygonOffset(0, 9), Polygon Z = 1.0. (Result depth should clamp to 1.0 too)" << TestLog::EndMessage;
798
799			gl.depthFunc				(GL_GREATER);
800			gl.polygonOffset			(0, 9);
801			gl.vertexAttrib4f			(colorLoc, 1.0f, 0.0f, 0.0f, 1.0f);
802			gl.drawArrays				(GL_TRIANGLES, 0, 3);
803		}
804
805		//draw top left (near)
806		{
807			gl.vertexAttribPointer		(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangleTopLeft);
808
809			log << TestLog::Message << "Draw top-left. Color = White.\tState: DepthFunc = ALWAYS, PolygonOffset(0, -8), Polygon Z = -1.0. (Result depth should clamp to -1.0)" << TestLog::EndMessage;
810
811			gl.depthFunc				(GL_ALWAYS);
812			gl.polygonOffset			(0, -8);
813			gl.vertexAttrib4f			(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
814			gl.drawArrays				(GL_TRIANGLES, 0, 3);
815
816			log << TestLog::Message << "Draw top-left. Color = Yellow.\tState: DepthFunc = LESS, PolygonOffset(0, -9), Polygon Z = -1.0. (Result depth should clamp to -1.0 too)." << TestLog::EndMessage;
817
818			gl.depthFunc				(GL_LESS);
819			gl.polygonOffset			(0, -9);
820			gl.vertexAttrib4f			(colorLoc, 1.0f, 1.0f, 0.0f, 1.0f);
821			gl.drawArrays				(GL_TRIANGLES, 0, 3);
822		}
823
824		gl.disableVertexAttribArray	(positionLoc);
825		gl.useProgram				(0);
826		gl.finish					();
827
828		glu::readPixels(m_context.getRenderContext(), 0, 0, testImage.getAccess());
829	}
830
831	// render reference image
832	log << TestLog::Message << "Expecting: Top-left = White, Bottom-right = White." << TestLog::EndMessage;
833	tcu::clear(referenceImage.getAccess(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
834
835	// compare
836	verifyImages(log, m_testCtx, m_context.getRenderContext(), testImage.getAccess(), referenceImage.getAccess());
837}
838
839// UsageSlopeTestCase
840
841class UsageSlopeTestCase  : public PolygonOffsetTestCase
842{
843public:
844			UsageSlopeTestCase	(Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName);
845
846	void	testPolygonOffset	(void);
847};
848
849UsageSlopeTestCase::UsageSlopeTestCase (Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName)
850	: PolygonOffsetTestCase(context, name, description, internalFormat, internalFormatName, 200)
851{
852}
853
854void UsageSlopeTestCase::testPolygonOffset (void)
855{
856	using tcu::TestLog;
857
858	const tcu::Vec4 triangleBottomRight[] =
859	{
860		tcu::Vec4(-1,  1,  0.0f,  1),
861		tcu::Vec4( 1,  1,  0.9f,  1),
862		tcu::Vec4( 1, -1,  0.9f,  1),
863	};
864	const tcu::Vec4 triangleTopLeft[] =
865	{
866		tcu::Vec4(-1, -1,  -0.9f,  1),
867		tcu::Vec4(-1,  1,   0.9f,  1),
868		tcu::Vec4( 1, -1,   0.0f,  1),
869	};
870
871	tcu::TestLog&		log				= m_testCtx.getLog();
872	tcu::Surface		testImage		(m_targetSize, m_targetSize);
873	tcu::Surface		referenceImage	(m_targetSize, m_targetSize);
874
875	// render test image
876	{
877		const glw::Functions&		gl			= m_context.getRenderContext().getFunctions();
878		const glu::ShaderProgram	program		(m_context.getRenderContext(), glu::makeVtxFragSources(s_shaderSourceVertex, s_shaderSourceFragment));
879		const GLint					positionLoc = gl.getAttribLocation(program.getProgram(), "a_position");
880		const GLint					colorLoc	= gl.getAttribLocation(program.getProgram(), "a_color");
881
882		if (!program.isOk())
883		{
884			log << program;
885			TCU_FAIL("Shader compile failed.");
886		}
887
888		gl.clearColor				(0, 0, 0, 1);
889		gl.clearDepthf				(1.0f);
890		gl.clear					(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
891		gl.viewport					(0, 0, m_targetSize, m_targetSize);
892		gl.useProgram				(program.getProgram());
893		gl.enable					(GL_DEPTH_TEST);
894		gl.enable					(GL_POLYGON_OFFSET_FILL);
895		gl.enableVertexAttribArray	(positionLoc);
896
897		log << TestLog::Message << "POLYGON_OFFSET_FILL enabled." << TestLog::EndMessage;
898
899		//draw top left (negative offset test)
900		{
901			gl.vertexAttribPointer		(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangleTopLeft);
902
903			log << TestLog::Message << "Draw top-left. Color = White.\tState: DepthFunc = ALWAYS, PolygonOffset(0, 0)." << TestLog::EndMessage;
904
905			gl.depthFunc				(GL_ALWAYS);
906			gl.polygonOffset			(0, 0);
907			gl.vertexAttrib4f			(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
908			gl.drawArrays				(GL_TRIANGLES, 0, 3);
909
910			log << TestLog::Message << "Draw top-left. Color = Green.\tState: DepthFunc = LESS, PolygonOffset(-1, 0)." << TestLog::EndMessage;
911
912			gl.depthFunc				(GL_LESS);
913			gl.polygonOffset			(-1, 0);
914			gl.vertexAttrib4f			(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
915			gl.drawArrays				(GL_TRIANGLES, 0, 3);
916		}
917
918		//draw bottom right (positive offset test)
919		{
920			gl.vertexAttribPointer		(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangleBottomRight);
921
922			log << TestLog::Message << "Draw bottom-right. Color = White.\tState: DepthFunc = ALWAYS, PolygonOffset(0, 0)." << TestLog::EndMessage;
923
924			gl.depthFunc				(GL_ALWAYS);
925			gl.polygonOffset			(0, 0);
926			gl.vertexAttrib4f			(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
927			gl.drawArrays				(GL_TRIANGLES, 0, 3);
928
929			log << TestLog::Message << "Draw bottom-right. Color = Green.\tState: DepthFunc = GREATER, PolygonOffset(1, 0)." << TestLog::EndMessage;
930
931			gl.depthFunc				(GL_GREATER);
932			gl.polygonOffset			(1, 0);
933			gl.vertexAttrib4f			(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
934			gl.drawArrays				(GL_TRIANGLES, 0, 3);
935		}
936
937		gl.disableVertexAttribArray	(positionLoc);
938		gl.useProgram				(0);
939		gl.finish					();
940
941		glu::readPixels(m_context.getRenderContext(), 0, 0, testImage.getAccess());
942	}
943
944	// render reference image
945	log << TestLog::Message << "Expecting: Top-left = Green, Bottom-right = Green." << TestLog::EndMessage;
946	tcu::clear(referenceImage.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
947
948	// compare
949	verifyImages(log, m_testCtx, m_context.getRenderContext(), testImage.getAccess(), referenceImage.getAccess());
950}
951
952// ZeroSlopeTestCase
953
954class ZeroSlopeTestCase : public PolygonOffsetTestCase
955{
956public:
957			ZeroSlopeTestCase	(Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName);
958
959	void	testPolygonOffset	(void);
960};
961
962ZeroSlopeTestCase::ZeroSlopeTestCase (Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName)
963	: PolygonOffsetTestCase(context, name, description, internalFormat, internalFormatName, 200)
964{
965}
966
967void ZeroSlopeTestCase::testPolygonOffset (void)
968{
969	using tcu::TestLog;
970
971	const tcu::Vec4 triangle[] =
972	{
973		tcu::Vec4(-0.4f,  0.4f, 0.0f, 1.0f),
974		tcu::Vec4(-0.8f, -0.5f, 0.0f, 1.0f),
975		tcu::Vec4( 0.7f,  0.2f, 0.0f, 1.0f),
976	};
977
978	tcu::TestLog&		log				= m_testCtx.getLog();
979	tcu::Surface		testImage		(m_targetSize, m_targetSize);
980	tcu::Surface		referenceImage	(m_targetSize, m_targetSize);
981
982	// log the triangle
983	log << TestLog::Message << "Setup triangle with coordinates:" << TestLog::EndMessage;
984	for (size_t ndx = 0; ndx < DE_LENGTH_OF_ARRAY(triangle); ++ndx)
985		log << TestLog::Message
986				<< "\tx=" << triangle[ndx].x()
987				<< "\ty=" << triangle[ndx].y()
988				<< "\tz=" << triangle[ndx].z()
989				<< "\tw=" << triangle[ndx].w()
990				<< TestLog::EndMessage;
991
992	// render test image
993	{
994		const glw::Functions&		gl			= m_context.getRenderContext().getFunctions();
995		const glu::ShaderProgram	program		(m_context.getRenderContext(), glu::makeVtxFragSources(s_shaderSourceVertex, s_shaderSourceFragment));
996		const GLint					positionLoc = gl.getAttribLocation(program.getProgram(), "a_position");
997		const GLint					colorLoc	= gl.getAttribLocation(program.getProgram(), "a_color");
998
999		if (!program.isOk())
1000		{
1001			log << program;
1002			TCU_FAIL("Shader compile failed.");
1003		}
1004
1005		gl.clearColor				(0, 0, 0, 1);
1006		gl.clearDepthf				(1.0f);
1007		gl.clear					(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1008		gl.viewport					(0, 0, m_targetSize, m_targetSize);
1009		gl.useProgram				(program.getProgram());
1010		gl.enable					(GL_DEPTH_TEST);
1011		gl.enable					(GL_POLYGON_OFFSET_FILL);
1012		gl.enableVertexAttribArray	(positionLoc);
1013
1014		log << TestLog::Message << "POLYGON_OFFSET_FILL enabled." << TestLog::EndMessage;
1015
1016		{
1017			gl.vertexAttribPointer		(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangle);
1018
1019			log << TestLog::Message << "Draw triangle. Color = Red.\tState: DepthFunc = ALWAYS, PolygonOffset(0, 0)." << TestLog::EndMessage;
1020
1021			gl.depthFunc				(GL_ALWAYS);
1022			gl.polygonOffset			(0, 0);
1023			gl.vertexAttrib4f			(colorLoc, 1.0f, 0.0f, 0.0f, 1.0f);
1024			gl.drawArrays				(GL_TRIANGLES, 0, 3);
1025
1026			log << TestLog::Message << "Draw triangle. Color = Black.\tState: DepthFunc = EQUAL, PolygonOffset(4, 0)." << TestLog::EndMessage;
1027
1028			gl.depthFunc				(GL_EQUAL);
1029			gl.polygonOffset			(4, 0);	// triangle slope == 0
1030			gl.vertexAttrib4f			(colorLoc, 0.0f, 0.0f, 0.0f, 1.0f);
1031			gl.drawArrays				(GL_TRIANGLES, 0, 3);
1032		}
1033
1034		gl.disableVertexAttribArray	(positionLoc);
1035		gl.useProgram				(0);
1036		gl.finish					();
1037
1038		glu::readPixels(m_context.getRenderContext(), 0, 0, testImage.getAccess());
1039	}
1040
1041	// render reference image
1042	log << TestLog::Message << "Expecting black triangle." << TestLog::EndMessage;
1043	tcu::clear(referenceImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1044
1045	// compare
1046	verifyImages(log, m_testCtx, m_context.getRenderContext(), testImage.getAccess(), referenceImage.getAccess());
1047}
1048
1049// OneSlopeTestCase
1050
1051class OneSlopeTestCase : public PolygonOffsetTestCase
1052{
1053public:
1054			OneSlopeTestCase	(Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName);
1055
1056	void	testPolygonOffset	(void);
1057};
1058
1059OneSlopeTestCase::OneSlopeTestCase (Context& context, const char* name, const char* description, GLenum internalFormat, const char* internalFormatName)
1060	: PolygonOffsetTestCase(context, name, description, internalFormat, internalFormatName, 200)
1061{
1062}
1063
1064void OneSlopeTestCase::testPolygonOffset (void)
1065{
1066	using tcu::TestLog;
1067
1068	/*
1069		* setup vertices subject to following properties
1070		*   dz_w / dx_w == 1
1071		*   dz_w / dy_w == 0
1072		* or
1073		*   dz_w / dx_w == 0
1074		*   dz_w / dy_w == 1
1075		* ==> m == 1
1076		*/
1077	const float cornerDepth = float(m_targetSize);
1078	const tcu::Vec4 triangles[2][3] =
1079	{
1080		{
1081			tcu::Vec4(-1, -1, -cornerDepth, 1),
1082			tcu::Vec4(-1,  1, -cornerDepth, 1),
1083			tcu::Vec4( 1, -1,  cornerDepth, 1),
1084		},
1085		{
1086			tcu::Vec4(-1,  1,  cornerDepth, 1),
1087			tcu::Vec4( 1,  1,  cornerDepth, 1),
1088			tcu::Vec4( 1, -1, -cornerDepth, 1),
1089		},
1090	};
1091
1092	tcu::TestLog&		log				= m_testCtx.getLog();
1093	tcu::Surface		testImage		(m_targetSize, m_targetSize);
1094	tcu::Surface		referenceImage	(m_targetSize, m_targetSize);
1095
1096	// log triangle info
1097	log << TestLog::Message << "Setup triangle0 coordinates: (slope in window coordinates = 1.0)" << TestLog::EndMessage;
1098	for (size_t ndx = 0; ndx < DE_LENGTH_OF_ARRAY(triangles[0]); ++ndx)
1099		log << TestLog::Message
1100				<< "\tx=" << triangles[0][ndx].x()
1101				<< "\ty=" << triangles[0][ndx].y()
1102				<< "\tz=" << triangles[0][ndx].z()
1103				<< "\tw=" << triangles[0][ndx].w()
1104				<< TestLog::EndMessage;
1105	log << TestLog::Message << "Setup triangle1 coordinates: (slope in window coordinates = 1.0)" << TestLog::EndMessage;
1106	for (size_t ndx = 0; ndx < DE_LENGTH_OF_ARRAY(triangles[1]); ++ndx)
1107		log << TestLog::Message
1108				<< "\tx=" << triangles[1][ndx].x()
1109				<< "\ty=" << triangles[1][ndx].y()
1110				<< "\tz=" << triangles[1][ndx].z()
1111				<< "\tw=" << triangles[1][ndx].w()
1112				<< TestLog::EndMessage;
1113
1114	// render test image
1115	{
1116		const glw::Functions&		gl			= m_context.getRenderContext().getFunctions();
1117		const glu::ShaderProgram	program		(m_context.getRenderContext(), glu::makeVtxFragSources(s_shaderSourceVertex, s_shaderSourceFragment));
1118		const GLint					positionLoc = gl.getAttribLocation(program.getProgram(), "a_position");
1119		const GLint					colorLoc	= gl.getAttribLocation(program.getProgram(), "a_color");
1120
1121		if (!program.isOk())
1122		{
1123			log << program;
1124			TCU_FAIL("Shader compile failed.");
1125		}
1126
1127		gl.clearColor				(0, 0, 0, 1);
1128		gl.clear					(GL_COLOR_BUFFER_BIT);
1129		gl.viewport					(0, 0, m_targetSize, m_targetSize);
1130		gl.useProgram				(program.getProgram());
1131		gl.enable					(GL_DEPTH_TEST);
1132		gl.enable					(GL_POLYGON_OFFSET_FILL);
1133		gl.enableVertexAttribArray	(positionLoc);
1134
1135		log << TestLog::Message << "Framebuffer cleared, clear color = Black." << TestLog::EndMessage;
1136		log << TestLog::Message << "POLYGON_OFFSET_FILL enabled." << TestLog::EndMessage;
1137
1138		// top left (positive offset)
1139		{
1140			log << TestLog::Message << "Clear depth to 1.0." << TestLog::EndMessage;
1141
1142			gl.clearDepthf			(1.0f); // far
1143			gl.clear				(GL_DEPTH_BUFFER_BIT);
1144
1145			gl.vertexAttribPointer	(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangles[0]);
1146
1147			log << TestLog::Message << "Draw triangle0. Color = Red.\tState: DepthFunc = NOTEQUAL, PolygonOffset(10, 0). (Result depth should clamp to 1.0)." << TestLog::EndMessage;
1148
1149			gl.polygonOffset		(10, 0);		// clamps any depth on the triangle to 1
1150			gl.depthFunc			(GL_NOTEQUAL);
1151			gl.vertexAttrib4f		(colorLoc, 1.0f, 0.0f, 0.0f, 1.0f);
1152			gl.drawArrays			(GL_TRIANGLES, 0, 3);
1153		}
1154		// bottom right (negative offset)
1155		{
1156			log << TestLog::Message << "Clear depth to 0.0." << TestLog::EndMessage;
1157
1158			gl.clearDepthf			(0.0f); // far
1159			gl.clear				(GL_DEPTH_BUFFER_BIT);
1160
1161			gl.vertexAttribPointer	(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangles[1]);
1162
1163			log << TestLog::Message << "Draw triangle1. Color = Green.\tState: DepthFunc = NOTEQUAL, PolygonOffset(-10, 0). (Result depth should clamp to 0.0)." << TestLog::EndMessage;
1164
1165			gl.polygonOffset		(-10, 0); // clamps depth to 0
1166			gl.depthFunc			(GL_NOTEQUAL);
1167			gl.vertexAttrib4f		(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
1168			gl.drawArrays			(GL_TRIANGLES, 0, 3);
1169		}
1170
1171		gl.disableVertexAttribArray	(positionLoc);
1172		gl.useProgram				(0);
1173		gl.finish					();
1174
1175		glu::readPixels(m_context.getRenderContext(), 0, 0, testImage.getAccess());
1176	}
1177
1178	// render reference image
1179	log << TestLog::Message << "Expecting black framebuffer." << TestLog::EndMessage;
1180	tcu::clear(referenceImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1181
1182	// compare
1183	verifyImages(log, m_testCtx, m_context.getRenderContext(), testImage.getAccess(), referenceImage.getAccess());
1184}
1185
1186} // anonymous
1187
1188PolygonOffsetTests::PolygonOffsetTests (Context& context)
1189	: TestCaseGroup(context, "polygon_offset", "Polygon offset tests")
1190{
1191}
1192
1193PolygonOffsetTests::~PolygonOffsetTests (void)
1194{
1195}
1196
1197void PolygonOffsetTests::init (void)
1198{
1199	const struct DepthBufferFormat
1200	{
1201		enum BufferType
1202		{
1203			TYPE_FIXED_POINT,
1204			TYPE_FLOATING_POINT,
1205			TYPE_UNKNOWN
1206		};
1207
1208		GLenum		internalFormat;
1209		int			bits;
1210		BufferType	floatingPoint;
1211		const char* name;
1212	} depthFormats[]=
1213	{
1214		{ 0,						0,		DepthBufferFormat::TYPE_UNKNOWN,		"default" },
1215		{ GL_DEPTH_COMPONENT16,		16,		DepthBufferFormat::TYPE_FIXED_POINT,	"fixed16" },
1216	};
1217
1218	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(depthFormats); ++ndx)
1219	{
1220		const DepthBufferFormat& format = depthFormats[ndx];
1221
1222		// enable works?
1223		addChild(new UsageTestCase(m_context, (std::string(format.name) + "_enable").c_str(), "test enable GL_POLYGON_OFFSET_FILL", format.internalFormat, format.name));
1224
1225		// Really moves the polygons ?
1226		addChild(new UsageDisplacementTestCase(m_context, (std::string(format.name) + "_displacement_with_units").c_str(), "test polygon offset", format.internalFormat, format.name));
1227
1228		// Really moves the polygons to right direction ?
1229		addChild(new UsagePositiveNegativeTestCase(m_context, (std::string(format.name) + "_render_with_units").c_str(), "test polygon offset", format.internalFormat, format.name));
1230
1231		// Is total result clamped to [0,1] like promised?
1232		addChild(new ResultClampingTestCase(m_context, (std::string(format.name) + "_result_depth_clamp").c_str(), "test polygon offset clamping", format.internalFormat, format.name));
1233
1234		// Slope really moves the polygon?
1235		addChild(new UsageSlopeTestCase(m_context, (std::string(format.name) + "_render_with_factor").c_str(), "test polygon offset factor", format.internalFormat, format.name));
1236
1237		// Factor with zero slope
1238		addChild(new ZeroSlopeTestCase(m_context, (std::string(format.name) + "_factor_0_slope").c_str(), "test polygon offset factor", format.internalFormat, format.name));
1239
1240		// Factor with 1.0 slope
1241		addChild(new OneSlopeTestCase(m_context, (std::string(format.name) + "_factor_1_slope").c_str(), "test polygon offset factor", format.internalFormat, format.name));
1242	}
1243}
1244
1245} // Functional
1246} // gles2
1247} // deqp
1248