1/*-------------------------------------------------------------------------
2* OpenGL Conformance Test Suite
3* -----------------------------
4*
5* Copyright (c) 2017 The Khronos Group Inc.
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  glcPolygonOffsetClampTests.cpp
21* \brief Conformance tests for the EXT_polygon_offset_clamp functionality.
22*/ /*-------------------------------------------------------------------*/
23
24#include "glcPolygonOffsetClampTests.hpp"
25#include "gluContextInfo.hpp"
26#include "gluShaderProgram.hpp"
27#include "glwEnums.hpp"
28#include "tcuRenderTarget.hpp"
29#include "tcuTestLog.hpp"
30
31#include <stdio.h>
32
33using namespace glw;
34using namespace glu;
35
36namespace glcts
37{
38
39const char* poc_shader_version_450core = "#version 450 core\n\n";
40const char* poc_shader_version_310es   = "#version 310 es\n\n";
41
42const char* poc_vertexColor = "in highp vec3 vertex;\n"
43							  "\n"
44							  "void main()\n"
45							  "{\n"
46							  "    gl_Position = vec4(vertex, 1);\n"
47							  "}\n";
48
49const char* poc_fragmentColor = "out highp vec4 fragColor;\n"
50								"\n"
51								"void main()\n"
52								"{\n"
53								"    fragColor = vec4(1, 1, 1, 1);\n"
54								"}\n";
55
56const char* poc_vertexTexture = "in highp vec3 vertex;\n"
57								"in highp vec2 texCoord;\n"
58								"out highp vec2 varyingtexCoord;\n"
59								"\n"
60								"void main()\n"
61								"{\n"
62								"    gl_Position = vec4(vertex, 1);\n"
63								"    varyingtexCoord = texCoord;\n"
64								"}\n";
65
66const char* poc_fragmentTexture = "in highp vec2 varyingtexCoord;\n"
67								  "out highp vec4 fragColor;\n"
68								  "\n"
69								  "layout (location = 0) uniform highp sampler2D tex;\n"
70								  "\n"
71								  "void main()\n"
72								  "{\n"
73								  "    highp vec4 v = texture(tex, varyingtexCoord);\n"
74								  "    highp int d = int(texture(tex, varyingtexCoord).r * 16777215.0);\n"
75								  "    highp int r = d % 256;\n"
76								  "    highp int g = (d % 65536) / 256;\n"
77								  "    highp int b = d / 65536;\n"
78								  "    fragColor = vec4(r, g, b, 255) / 255.0;\n"
79								  "}\n";
80
81/** Constructor.
82*
83*  @param context Rendering context
84*  @param name Test name
85*  @param description Test description
86*/
87PolygonOffsetClampTestCaseBase::PolygonOffsetClampTestCaseBase(deqp::Context& context, const char* name,
88															   const char* description)
89	: TestCase(context, name, description)
90{
91	glu::ContextType contextType = m_context.getRenderContext().getType();
92	m_extensionSupported		 = glu::contextSupports(contextType, glu::ApiType::core(4, 6));
93	m_extensionSupported |= context.getContextInfo().isExtensionSupported("GL_EXT_polygon_offset_clamp");
94	m_extensionSupported |= context.getContextInfo().isExtensionSupported("GL_ARB_polygon_offset_clamp");
95}
96
97tcu::TestNode::IterateResult PolygonOffsetClampTestCaseBase::iterate()
98{
99	if (!m_extensionSupported)
100	{
101		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
102		return STOP;
103	}
104
105	test(m_context.getRenderContext().getFunctions());
106
107	return STOP;
108}
109
110/** Constructor.
111*
112*  @param context Rendering context
113*/
114PolygonOffsetClampAvailabilityTestCase::PolygonOffsetClampAvailabilityTestCase(deqp::Context& context)
115	: PolygonOffsetClampTestCaseBase(context, "PolygonOffsetClampAvailability",
116									 "Verifies if queries for GL_EXT_polygon_offset_clamp extension works properly")
117{
118}
119
120void PolygonOffsetClampAvailabilityTestCase::test(const glw::Functions& gl)
121{
122	{
123		glw::GLboolean data;
124		gl.getBooleanv(GL_POLYGON_OFFSET_CLAMP_EXT, &data);
125		GLU_EXPECT_NO_ERROR(gl.getError(), "getBooleanv error occurred");
126	}
127	{
128		glw::GLint data;
129		gl.getIntegerv(GL_POLYGON_OFFSET_CLAMP_EXT, &data);
130		GLU_EXPECT_NO_ERROR(gl.getError(), "getBooleanv error occurred");
131	}
132	{
133		glw::GLint64 data;
134		gl.getInteger64v(GL_POLYGON_OFFSET_CLAMP_EXT, &data);
135		GLU_EXPECT_NO_ERROR(gl.getError(), "getBooleanv error occurred");
136	}
137	{
138		glw::GLfloat data;
139		gl.getFloatv(GL_POLYGON_OFFSET_CLAMP_EXT, &data);
140		GLU_EXPECT_NO_ERROR(gl.getError(), "getBooleanv error occurred");
141	}
142
143	// OpenGL ES does not support getDoublev query
144	if (glu::isContextTypeGLCore(m_context.getRenderContext().getType()))
145	{
146		glw::GLdouble data;
147		gl.getDoublev(GL_POLYGON_OFFSET_CLAMP_EXT, &data);
148		GLU_EXPECT_NO_ERROR(gl.getError(), "getBooleanv error occurred");
149	}
150
151	gl.polygonOffsetClamp(1.0f, 1.0f, 0.5f);
152	GLU_EXPECT_NO_ERROR(gl.getError(), "polygonOffsetClamp error occurred");
153
154	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
155}
156
157/** Constructor.
158*
159*  @param context Rendering context
160*/
161PolygonOffsetClampValueTestCaseBase::PolygonOffsetClampValueTestCaseBase(deqp::Context& context, const char* name,
162																		 const char* description)
163	: PolygonOffsetClampTestCaseBase(context, name, description)
164	, m_fbo(0)
165	, m_depthBuf(0)
166	, m_colorBuf(0)
167	, m_fboReadback(0)
168	, m_colorBufReadback(0)
169{
170}
171
172/** Initialization method that creates framebuffer with depth attachment
173 */
174void PolygonOffsetClampValueTestCaseBase::init()
175{
176	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
177
178	gl.genTextures(1, &m_depthBuf);
179	GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures");
180	gl.bindTexture(GL_TEXTURE_2D, m_depthBuf);
181	GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture");
182	gl.texStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT16, 64, 64);
183	GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D");
184	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
185	GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri");
186	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
187	GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri");
188
189	gl.genTextures(1, &m_colorBuf);
190	GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures");
191	gl.bindTexture(GL_TEXTURE_2D, m_colorBuf);
192	GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture");
193	gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 64, 64);
194	GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D");
195	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
196	GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri");
197	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
198	GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri");
199
200	gl.genFramebuffers(1, &m_fbo);
201	GLU_EXPECT_NO_ERROR(gl.getError(), "genFramebuffers");
202	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
203	GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer");
204	gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthBuf, 0);
205	GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D");
206	gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuf, 0);
207	GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D");
208
209	if (!glu::isContextTypeGLCore(m_context.getRenderContext().getType()))
210	{
211		gl.genTextures(1, &m_colorBufReadback);
212		GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures");
213		gl.bindTexture(GL_TEXTURE_2D, m_colorBufReadback);
214		GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture");
215		gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 64, 64);
216		GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D");
217		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
218		GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri");
219		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
220		GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri");
221
222		gl.genFramebuffers(1, &m_fboReadback);
223		GLU_EXPECT_NO_ERROR(gl.getError(), "genFramebuffers");
224		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboReadback);
225		GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer");
226		gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBufReadback, 0);
227		GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D");
228	}
229
230	gl.viewport(0, 0, 64, 64);
231}
232
233/** De-Initialization method that releases
234 */
235void PolygonOffsetClampValueTestCaseBase::deinit()
236{
237	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
238
239	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
240	GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer");
241
242	if (m_fbo)
243		gl.deleteFramebuffers(1, &m_fbo);
244	if (m_depthBuf)
245		gl.deleteTextures(1, &m_depthBuf);
246	if (m_colorBuf)
247		gl.deleteTextures(1, &m_colorBuf);
248
249	if (!glu::isContextTypeGLCore(m_context.getRenderContext().getType()))
250	{
251		if (m_colorBufReadback)
252			gl.deleteTextures(1, &m_colorBufReadback);
253		if (m_fboReadback)
254			gl.deleteFramebuffers(1, &m_fboReadback);
255	}
256}
257
258/** Testing method that verifies if depth values generated after polygon offset clamp are as expected.
259 *
260 *  @param gl   Function bindings
261 */
262void PolygonOffsetClampValueTestCaseBase::test(const glw::Functions& gl)
263{
264	const GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f };
265
266	// Prepare shader program
267	std::string vertexColor;
268	std::string fragmentColor;
269	if (glu::isContextTypeGLCore(m_context.getRenderContext().getType()))
270		vertexColor = std::string(poc_shader_version_450core);
271	else
272		vertexColor = std::string(poc_shader_version_310es);
273	fragmentColor   = vertexColor;
274
275	vertexColor   = vertexColor + poc_vertexColor;
276	fragmentColor = fragmentColor + poc_fragmentColor;
277
278	ProgramSources testSources = makeVtxFragSources(vertexColor, fragmentColor);
279	ShaderProgram  testProgram(gl, testSources);
280
281	if (!testProgram.isOk())
282	{
283		m_testCtx.getLog() << tcu::TestLog::Message << "TestProgram build failed.\n"
284						   << "Vertex: " << testProgram.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n"
285						   << "Fragment: " << testProgram.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n"
286						   << "Program: " << testProgram.getProgramInfo().infoLog << tcu::TestLog::EndMessage;
287
288		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
289		return;
290	}
291
292	GLuint testProgramId = testProgram.getProgram();
293
294	ShaderProgram* readDepthProgram   = DE_NULL;
295	GLuint		   readDepthProgramId = 0;
296
297	// Prepare shader program for reading depth buffer indirectly
298	if (!glu::isContextTypeGLCore(m_context.getRenderContext().getType()))
299	{
300		std::string vertexTexture   = std::string(poc_shader_version_310es) + poc_vertexTexture;
301		std::string fragmentTexture = std::string(poc_shader_version_310es) + poc_fragmentTexture;
302
303		ProgramSources readDepthSources = makeVtxFragSources(vertexTexture, fragmentTexture);
304
305		readDepthProgram = new ShaderProgram(gl, readDepthSources);
306
307		if (!readDepthProgram->isOk())
308		{
309			m_testCtx.getLog() << tcu::TestLog::Message << "ReadDepthProgram build failed.\n"
310							   << "Vertex: " << readDepthProgram->getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n"
311							   << "Fragment: " << readDepthProgram->getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n"
312							   << "Program: " << readDepthProgram->getProgramInfo().infoLog << tcu::TestLog::EndMessage;
313
314			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
315			return;
316		}
317
318		readDepthProgramId = readDepthProgram->getProgram();
319	}
320
321	gl.useProgram(testProgramId);
322	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
323
324	GLuint vao;
325	GLuint arrayBuffer;
326
327	// Setup depth testing
328	gl.enable(GL_DEPTH_TEST);
329	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable");
330
331	gl.depthFunc(GL_ALWAYS);
332	GLU_EXPECT_NO_ERROR(gl.getError(), "glDepthFunc");
333
334	// Generate vertex array object
335	gl.genVertexArrays(1, &vao);
336	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays");
337
338	gl.bindVertexArray(vao);
339	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray");
340
341	// Setup vertex array buffer
342	gl.genBuffers(1, &arrayBuffer);
343	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
344
345	gl.bindBuffer(GL_ARRAY_BUFFER, arrayBuffer);
346	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
347
348	gl.bufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
349	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
350
351	// Setup vertex attrib pointer
352	gl.enableVertexAttribArray(0);
353	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray");
354
355	gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
356	GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer");
357
358	// Bind framebuffer for drawing
359	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
360	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer");
361
362	bool result = true;
363	for (GLuint i = 0; i < m_testValues.size(); ++i)
364	{
365		// Prepare verification variables
366		GLfloat depthValue			  = 0.0f;
367		GLfloat depthValueOffset	  = 0.0f;
368		GLfloat depthValueOffsetClamp = 0.0f;
369
370		// Draw reference polygon
371		gl.disable(GL_POLYGON_OFFSET_FILL);
372		GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable");
373
374		gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
375		GLU_EXPECT_NO_ERROR(gl.getError(), "glClear");
376
377		gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
378		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays");
379
380		// Get reference depth value
381		depthValue = readDepthValue(gl, readDepthProgramId, testProgramId);
382
383		// Draw polygon with depth offset
384		gl.enable(GL_POLYGON_OFFSET_FILL);
385		GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable");
386
387		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
388		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer");
389
390		gl.polygonOffset(m_testValues[i].factor, m_testValues[i].units);
391		GLU_EXPECT_NO_ERROR(gl.getError(), "glPolygonOffset");
392
393		gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
394		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays");
395
396		depthValueOffset = readDepthValue(gl, readDepthProgramId, testProgramId);
397
398		// Draw reference polygon
399		gl.disable(GL_POLYGON_OFFSET_FILL);
400		GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable");
401
402		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
403		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer");
404
405		gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
406		GLU_EXPECT_NO_ERROR(gl.getError(), "glClear");
407
408		gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
409		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays");
410
411		// Draw polygon with depth offset
412		gl.enable(GL_POLYGON_OFFSET_FILL);
413		GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable");
414
415		gl.polygonOffsetClamp(m_testValues[i].factor, m_testValues[i].units, m_testValues[i].clamp);
416		GLU_EXPECT_NO_ERROR(gl.getError(), "glPolygonOffsetClamp");
417
418		gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
419		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays");
420
421		depthValueOffsetClamp = readDepthValue(gl, readDepthProgramId, testProgramId);
422
423		// Verify results
424		result = result && verify(i, depthValue, depthValueOffset, depthValueOffsetClamp);
425	}
426
427	// Cleanup
428	gl.disableVertexAttribArray(0);
429	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray");
430
431	gl.deleteVertexArrays(1, &arrayBuffer);
432	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteVertexArrays");
433
434	gl.deleteVertexArrays(1, &vao);
435	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteVertexArrays");
436
437	gl.disable(GL_POLYGON_OFFSET_FILL);
438	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable");
439
440	if (readDepthProgram)
441		delete readDepthProgram;
442
443	if (result)
444		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
445	else
446		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
447}
448
449/** Method .
450 *
451 *  @param gl   Function bindings
452 */
453float PolygonOffsetClampValueTestCaseBase::readDepthValue(const glw::Functions& gl, const GLuint readDepthProgramId, const GLuint testProgramId)
454{
455	GLfloat depthValue = 0.0f;
456
457	if (glu::isContextTypeGLCore(m_context.getRenderContext().getType()))
458	{
459		gl.readPixels(0, 0, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depthValue);
460		GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels");
461	}
462	// OpenGL ES does not support reading pixels directly from depth buffer
463	else
464	{
465		// Bind framebuffer for readback
466		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboReadback);
467		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer");
468
469		gl.disable(GL_DEPTH_TEST);
470		GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable");
471
472		gl.useProgram(readDepthProgramId);
473		GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
474
475		gl.activeTexture(GL_TEXTURE0);
476		GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveTexture");
477		gl.bindTexture(GL_TEXTURE_2D, m_depthBuf);
478		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture");
479		gl.uniform1i(0, 0);
480		GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i");
481
482		gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
483		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays");
484
485		GLubyte pixels[4];
486		gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
487		GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels");
488
489		gl.enable(GL_DEPTH_TEST);
490		GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable");
491
492		// Convert read depth value to GLfloat normalized
493		depthValue = (GLfloat)(pixels[0] + pixels[1] * 256 + pixels[2] * 65536) / 0xFFFFFF;
494
495		// Bind framebuffer for drawing
496		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
497		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer");
498
499		gl.useProgram(testProgramId);
500		GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
501	}
502
503	return depthValue;
504}
505
506/** Constructor.
507*
508*  @param context Rendering context
509*/
510PolygonOffsetClampMinMaxTestCase::PolygonOffsetClampMinMaxTestCase(deqp::Context& context)
511	: PolygonOffsetClampValueTestCaseBase(
512		  context, "PolygonOffsetClampMinMax",
513		  "Verifies if polygon offset clamp works as expected for non-zero, finite clamp values")
514{
515}
516
517/** Initialization method that fills polygonOffset* testing values
518 */
519void PolygonOffsetClampMinMaxTestCase::init()
520{
521	PolygonOffsetClampValueTestCaseBase::init();
522
523	m_testValues.clear();
524	m_testValues.push_back(PolygonOffsetClampValues(0.0f, -5000.0f, -0.0001f)); // Min offset case
525	m_testValues.push_back(PolygonOffsetClampValues(0.0f, 5000.0f, 0.0001f));   // Max offset case
526}
527
528/** Verification method that determines if depth values are as expected
529 *
530 *  @param caseNo           Case iteration number
531 *  @param depth            Reference depth value
532 *  @param offsetDepth      Case iteration number
533 *  @param offsetClampDepth Case iteration number
534 */
535bool PolygonOffsetClampMinMaxTestCase::verify(GLuint caseNo, GLfloat depth, GLfloat offsetDepth,
536											  GLfloat offsetClampDepth)
537{
538	// Min offset case
539	if (caseNo == 0)
540	{
541		if (depth <= offsetDepth || depth <= offsetClampDepth || offsetDepth >= offsetClampDepth)
542		{
543			m_testCtx.getLog() << tcu::TestLog::Message << "PolygonOffsetClampEXT failed at MIN offset test.\n"
544							   << "Expected result: "
545							   << "refDepth[" << depth << "] > "
546							   << "offsetClampDepth[" << offsetClampDepth << "] > "
547							   << "offsetDepth[" << offsetDepth << "]" << tcu::TestLog::EndMessage;
548
549			return false;
550		}
551	}
552	// Max offset case
553	else if (caseNo == 1)
554	{
555		if (depth >= offsetDepth || depth >= offsetClampDepth || offsetDepth <= offsetClampDepth)
556		{
557			m_testCtx.getLog() << tcu::TestLog::Message << "PolygonOffsetClampEXT failed at MAX offset test.\n"
558							   << "Expected result: "
559							   << "refDepth[" << depth << "] < "
560							   << "offsetClampDepth[" << offsetClampDepth << "] < "
561							   << "offsetDepth[" << offsetDepth << "]" << tcu::TestLog::EndMessage;
562
563			return false;
564		}
565	}
566	// Undefined case
567	else
568		return false;
569
570	return true;
571}
572
573/** Constructor.
574*
575*  @param context Rendering context
576*/
577PolygonOffsetClampZeroInfinityTestCase::PolygonOffsetClampZeroInfinityTestCase(deqp::Context& context)
578	: PolygonOffsetClampValueTestCaseBase(
579		  context, "PolygonOffsetClampZeroInfinity",
580		  "Verifies if polygon offset clamp works as expected for zero and infinite clamp values")
581{
582}
583
584/** Initialization method that fills polygonOffset* testing values
585 */
586void PolygonOffsetClampZeroInfinityTestCase::init()
587{
588	PolygonOffsetClampValueTestCaseBase::init();
589
590	m_testValues.clear();
591	m_testValues.push_back(PolygonOffsetClampValues(0.0f, -1000.0f, 0.0f));		 // Min offset, zero clamp case
592	m_testValues.push_back(PolygonOffsetClampValues(0.0f, -1000.0f, -INFINITY)); // Min Offset, infinity clamp case
593	m_testValues.push_back(PolygonOffsetClampValues(0.0f, 1000.0f, 0.0f));		 // Max offset, zero clamp case
594	m_testValues.push_back(PolygonOffsetClampValues(0.0f, 1000.0f, INFINITY));   // Max Offset, infinity clamp case
595}
596
597bool PolygonOffsetClampZeroInfinityTestCase::verify(GLuint caseNo, GLfloat depth, GLfloat offsetDepth,
598													GLfloat offsetClampDepth)
599{
600	DE_UNREF(caseNo);
601
602	if (depth == offsetDepth || depth == offsetClampDepth || offsetDepth != offsetClampDepth)
603	{
604		m_testCtx.getLog() << tcu::TestLog::Message
605						   << "PolygonOffsetClampEXT failed at Zero/Infinity offset clamp test.\n"
606						   << "Expected result: "
607						   << "refDepth[" << depth << "] != "
608						   << "(offsetClampDepth[" << offsetClampDepth << "] == "
609						   << "offsetDepth[" << offsetDepth << "])" << tcu::TestLog::EndMessage;
610
611		return false;
612	}
613
614	return true;
615}
616
617/** Constructor.
618*
619*  @param context Rendering context.
620*/
621PolygonOffsetClamp::PolygonOffsetClamp(deqp::Context& context)
622	: TestCaseGroup(context, "polygon_offset_clamp",
623					"Verify conformance of CTS_EXT_polygon_offset_clamp implementation")
624{
625}
626
627/** Initializes the test group contents. */
628void PolygonOffsetClamp::init()
629{
630	addChild(new PolygonOffsetClampAvailabilityTestCase(m_context));
631	addChild(new PolygonOffsetClampMinMaxTestCase(m_context));
632	addChild(new PolygonOffsetClampZeroInfinityTestCase(m_context));
633}
634} /* glcts namespace */
635