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